diff --git a/.github/workflows/validate-scripts.yml b/.github/workflows/validate-scripts.yml new file mode 100644 index 0000000..9e25f69 --- /dev/null +++ b/.github/workflows/validate-scripts.yml @@ -0,0 +1,43 @@ +name: Validate Shell Scripts + +on: + pull_request: + paths: + - 'Servicio/Instalacion-Base-VibeVoice/**/*.sh' + push: + branches: + - main + - 'feat/**' + paths: + - 'Servicio/Instalacion-Base-VibeVoice/**/*.sh' + +jobs: + shellcheck: + name: ShellCheck + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Run ShellCheck + uses: ludeeus/action-shellcheck@master + with: + scandir: './Servicio/Instalacion-Base-VibeVoice' + severity: warning + ignore_paths: 'node_modules .git' + + - name: Check script permissions + run: | + echo "Verificando permisos ejecutables en scripts..." + find Servicio/Instalacion-Base-VibeVoice -name "*.sh" -type f ! -perm -u+x -print | while read script; do + echo "ADVERTENCIA: $script no tiene permisos ejecutables" + done + + # Contar scripts sin permisos ejecutables + count=$(find Servicio/Instalacion-Base-VibeVoice -name "*.sh" -type f ! -perm -u+x | wc -l) + if [ "$count" -gt 0 ]; then + echo "ERROR: $count script(s) no tienen permisos ejecutables" + exit 1 + fi + + echo "✓ Todos los scripts tienen permisos ejecutables correctos" diff --git a/README.md b/README.md index 81080d5..051d8aa 100644 --- a/README.md +++ b/README.md @@ -120,4 +120,19 @@ We do not recommend using VibeVoice in commercial or real-world applications wit ## Star History -![Star History Chart](https://api.star-history.com/svg?repos=Microsoft/vibevoice&type=date&legend=top-left) \ No newline at end of file +![Star History Chart](https://api.star-history.com/svg?repos=Microsoft/vibevoice&type=date&legend=top-left) + +--- + +### ⚠️ Nota para Usuarios con NVIDIA GTX 1060 (y GPUs con arquitectura sm_61) + +Esta instalación (documentada también en Servicio/Instalacion-Base-VibeVoice/LEEME.md) se puede ejecutar en **modo host** (entorno virtual Python) en vez de Docker para mejorar compatibilidad y rendimiento en GPUs antiguas como la NVIDIA GeForce GTX 1060. + +Motivación: las builds precompiladas recientes de PyTorch pueden no incluir soporte para la arquitectura CUDA `sm_61`. En nuestras pruebas, la combinación estable fue usar PyTorch `2.6.0+cu118` y ejecutar la API en el `venv` del host. + +Configuración recomendada: +- `VIBE_API_MODE=host` en `.env` +- `MODEL_DEVICE=cuda` +- `MODEL_PATH=/opt/vibevoice/models/VibeVoice-Realtime-0.5B/snapshots/` + +Para más detalles y pasos de reversión, ver `Servicio/Instalacion-Base-VibeVoice/LEEME.md`. \ No newline at end of file diff --git a/Servicio/Instalacion-Base-VibeVoice/GLOSARIO.md b/Servicio/Instalacion-Base-VibeVoice/GLOSARIO.md new file mode 100644 index 0000000..343a112 --- /dev/null +++ b/Servicio/Instalacion-Base-VibeVoice/GLOSARIO.md @@ -0,0 +1,360 @@ +# GLOSARIO - Servicio de Instalación VibeVoice + +## Términos Técnicos y Definiciones + +Este glosario proporciona definiciones técnicas empresariales de los términos utilizados en el servicio de instalación de VibeVoice. + +--- + +### A + +**API (Application Programming Interface)** +Interfaz de Programación de Aplicaciones. Conjunto de definiciones y protocolos que permite la comunicación entre diferentes componentes de software. + +**AOF (Append-Only File)** +Mecanismo de persistencia de Redis que registra cada operación de escritura, permitiendo la recuperación de datos en caso de fallo. + +**Auditoría** +Registro sistemático de eventos críticos del sistema para fines de trazabilidad, seguridad y cumplimiento. + +--- + +### B + +**Backup (Respaldo)** +Copia de seguridad de datos que permite la recuperación ante pérdida o corrupción de información. + +**Bitácora (Log)** +Registro cronológico de eventos, operaciones y errores del sistema. + +**Bash** +Shell de comandos y lenguaje de scripting utilizado en sistemas Unix/Linux. + +--- + +### C + +**Caché** +Almacenamiento temporal de datos de acceso frecuente para mejorar el rendimiento del sistema. + +**Contenedor** +Unidad estándar de software que empaqueta código y todas sus dependencias para ejecutarse de manera consistente en diferentes entornos. + +**CORS (Cross-Origin Resource Sharing)** +Mecanismo de seguridad que permite o restringe recursos solicitados desde otro dominio fuera del dominio de origen. + +**CPU (Central Processing Unit)** +Unidad Central de Procesamiento. Componente principal del hardware que ejecuta instrucciones del software. + +--- + +### D + +**Daemon** +Proceso que se ejecuta en segundo plano, generalmente iniciado al arrancar el sistema. + +**Docker** +Plataforma de contenedorización que permite empaquetar aplicaciones y sus dependencias en contenedores ligeros y portables. + +**Docker Compose** +Herramienta para definir y ejecutar aplicaciones multi-contenedor usando archivos YAML. + +**Docker Network** +Red virtual que permite la comunicación entre contenedores Docker. + +--- + +### E + +**Entorno Virtual (Virtual Environment)** +Espacio aislado de Python que contiene una instalación independiente de paquetes y dependencias. + +**Escalabilidad** +Capacidad del sistema para manejar cargas de trabajo crecientes mediante la adición de recursos. + +--- + +### F + +**Failover** +Capacidad de un sistema para transferir automáticamente operaciones a un sistema de respaldo en caso de fallo. + +**Firewall** +Sistema de seguridad de red que monitorea y controla el tráfico entrante y saliente. + +--- + +### G + +**GB (Gigabyte)** +Unidad de medida de almacenamiento digital equivalente a 1,024 megabytes. + +--- + +### H + +**Health Check** +Verificación periódica del estado de salud de un servicio o aplicación. + +**HTTPS (Hypertext Transfer Protocol Secure)** +Protocolo de comunicación seguro para transferencia de datos en la web. + +--- + +### I + +**Idempotencia** +Propiedad de una operación que puede ejecutarse múltiples veces sin cambiar el resultado después de la primera aplicación. + +**IA (Inteligencia Artificial)** +Tecnología que permite a las máquinas realizar tareas que normalmente requieren inteligencia humana. + +--- + +### J + +**JSON (JavaScript Object Notation)** +Formato ligero de intercambio de datos legible por humanos y máquinas. + +**JWT (JSON Web Token)** +Estándar abierto para crear tokens de acceso que permiten la autenticación y autorización. + +--- + +### K + +**Kafka** +Plataforma de transmisión distribuida utilizada para construir pipelines de datos en tiempo real. + +--- + +### L + +**Load Balancer** +Distribuidor de carga que reparte el tráfico entre múltiples servidores. + +**LTS (Long-Term Support)** +Soporte a largo plazo. Versión de software con actualizaciones de seguridad y mantenimiento extendidas. + +--- + +### M + +**Microservicio** +Arquitectura de software que estructura una aplicación como colección de servicios pequeños e independientes. + +**Módulo** +Componente independiente y reutilizable de un sistema más grande. + +--- + +### N + +**NFS (Network File System)** +Sistema de archivos distribuido que permite acceder a archivos a través de una red. + +--- + +### O + +**Orquestación** +Coordinación automatizada de múltiples servicios o componentes de software. + +--- + +### P + +**PID (Process IDentifier)** +Identificador único asignado a cada proceso en ejecución en un sistema Unix/Linux. + +**PostgreSQL** +Sistema de gestión de bases de datos relacional de código abierto. + +**PPA (Personal Package Archive)** +Repositorio de software para Ubuntu que permite a desarrolladores distribuir paquetes. + +**Puerto (Port)** +Punto de comunicación específico en una red que identifica un servicio o proceso. + +--- + +### Q + +**Query** +Consulta a una base de datos para recuperar o manipular información. + +--- + +### R + +**RAM (Random Access Memory)** +Memoria de acceso aleatorio utilizada para almacenamiento temporal de datos en uso. + +**Redis** +Base de datos en memoria de código abierto utilizada como caché, broker de mensajes y base de datos. + +**Replicación** +Proceso de copiar y mantener datos en múltiples ubicaciones para redundancia. + +**RESTful API** +API que sigue los principios de la arquitectura REST (Representational State Transfer). + +--- + +### S + +**Script** +Conjunto de instrucciones o comandos escritos en un lenguaje interpretado. + +**Secret Manager** +Sistema para almacenar y gestionar credenciales y secretos de manera segura. + +**Servicio** +Programa que se ejecuta en segundo plano proporcionando funcionalidades específicas. + +**SSL/TLS (Secure Sockets Layer / Transport Layer Security)** +Protocolos de seguridad para establecer comunicaciones cifradas. + +**Subnet** +Sub-red. División lógica de una red IP. + +**Systemd** +Sistema de inicialización y gestor de servicios para Linux. + +--- + +### T + +**TCP/IP (Transmission Control Protocol / Internet Protocol)** +Suite de protocolos de comunicación utilizados en Internet. + +**Timeout** +Tiempo máximo de espera para que se complete una operación. + +**Topic (Kafka)** +Canal lógico en Kafka donde se publican y consumen mensajes. + +**Trazabilidad** +Capacidad de seguir y registrar el historial de eventos y operaciones del sistema. + +--- + +### U + +**Ubuntu** +Distribución de Linux basada en Debian, orientada a la facilidad de uso. + +**UUID (Universally Unique Identifier)** +Identificador único universal de 128 bits. + +--- + +### V + +**Validación** +Proceso de verificar que datos o configuraciones cumplen con requisitos específicos. + +**Variable de Entorno** +Valor dinámico que puede afectar el comportamiento de procesos en ejecución. + +**venv (Virtual Environment)** +Herramienta de Python para crear entornos virtuales aislados. + +**Volumen (Docker)** +Mecanismo de persistencia de datos en Docker que existe independientemente del ciclo de vida del contenedor. + +--- + +### W + +**WebSocket** +Protocolo de comunicación bidireccional en tiempo real sobre una conexión TCP. + +--- + +### Y + +**YAML (YAML Ain't Markup Language)** +Formato de serialización de datos legible por humanos, comúnmente usado en archivos de configuración. + +--- + +### Z + +**Zookeeper** +Servicio centralizado para mantener información de configuración y sincronización en sistemas distribuidos. + +--- + +## Acrónimos Comunes + +| Acrónimo | Significado | Contexto | +|----------|-------------|----------| +| API | Application Programming Interface | Comunicación entre servicios | +| AOF | Append-Only File | Persistencia de Redis | +| CPU | Central Processing Unit | Recursos de hardware | +| CORS | Cross-Origin Resource Sharing | Seguridad web | +| GB | Gigabyte | Almacenamiento | +| JWT | JSON Web Token | Autenticación | +| LTS | Long-Term Support | Versiones de Ubuntu | +| PID | Process Identifier | Gestión de procesos | +| RAM | Random Access Memory | Memoria del sistema | +| SSL | Secure Sockets Layer | Seguridad | +| TLS | Transport Layer Security | Seguridad | +| UUID | Universally Unique Identifier | Identificadores únicos | + +--- + +## Convenciones de Nomenclatura + +### Archivos de Configuración +- **stack-vibe.conf**: Configuración principal (única fuente de verdad) +- **.env**: Variables de entorno para Docker Compose + +### Scripts +- **instalador.sh**: Script principal de instalación +- **XX-nombre-modulo.sh**: Módulos numerados secuencialmente +- **registrador.sh**: Biblioteca para bitácoras +- **ayudante.sh**: Biblioteca de funciones auxiliares +- **validador.sh**: Biblioteca de validaciones + +### Directorios +- **/opt/vibevoice**: Directorio base de instalación +- **/opt/vibevoice/datos**: Datos de servicios +- **/opt/vibevoice/logs**: Bitácoras del sistema +- **/opt/vibevoice/config**: Configuraciones +- **/opt/vibevoice/backups**: Respaldos + +### Servicios Docker +- **vibevoice-postgres**: Contenedor PostgreSQL +- **vibevoice-redis**: Contenedor Redis +- **vibevoice-kafka**: Contenedor Kafka +- **vibevoice-zookeeper**: Contenedor Zookeeper +- **vibevoice-network**: Red Docker + +--- + +## Referencias Técnicas + +### Versiones de Software +- **Ubuntu**: 22.04 LTS (Jammy), 24.04 LTS (Noble) +- **Python**: 3.11+ +- **Docker**: 24.0+ +- **Docker Compose**: 2.20+ +- **PostgreSQL**: 15 +- **Redis**: 7 +- **Kafka**: 3.5 + +### Puertos Estándar +- **PostgreSQL**: 5432 +- **Redis**: 6379 +- **Kafka**: 9092 +- **Zookeeper**: 2181 +- **API VibeVoice**: 8000 +- **WebSocket**: 8001 +- **Admin**: 8080 + +--- + +**Última actualización**: Diciembre 2024 +**Versión del documento**: 1.0.0 diff --git a/Servicio/Instalacion-Base-VibeVoice/LEEME.md b/Servicio/Instalacion-Base-VibeVoice/LEEME.md new file mode 100644 index 0000000..0267730 --- /dev/null +++ b/Servicio/Instalacion-Base-VibeVoice/LEEME.md @@ -0,0 +1,445 @@ +# LEEME - Servicio de Instalación VibeVoice + +## Descripción General + +Este es el **Servicio de Instalación Base para VibeVoice**, un sistema completo, modular e idempotente diseñado para preparar y desplegar VibeVoice en sistemas Ubuntu 22.04 y 24.04. + +## Características Principales + +- ✅ **Modular**: Instalación dividida en 6 módulos independientes +- ✅ **Idempotente**: Puede ejecutarse múltiples veces sin efectos adversos +- ✅ **Trazabilidad**: Sistema completo de bitácoras y auditoría +- ✅ **Validación**: Pruebas automáticas pre y post-instalación +- ✅ **Documentación**: Documentación técnica en español empresarial +- ✅ **Automatización**: Servicio systemd para gestión del ciclo de vida + +## Requisitos del Sistema + +### Sistema Operativo +- Ubuntu 22.04 LTS (Jammy Jellyfish) +- Ubuntu 24.04 LTS (Noble Numbat) + +### Recursos Mínimos +- **RAM**: 8 GB (recomendado: 16 GB) +- **CPU**: 4 núcleos (recomendado: 8 núcleos) +- **Disco**: 50 GB de espacio libre (recomendado: 100 GB) +- **Red**: Conexión a Internet estable + +### Privilegios +- Acceso root o sudo + +**Nota:** El instalador intentará crear el usuario de sistema `vibevoice` durante la fase de verificación inicial. Asegúrese de ejecutar el instalador con privilegios `root` (sudo) para que la creación del usuario y la asignación de propietarios (`chown`) funcionen correctamente. Si no es posible crear el usuario, el instalador continuará pero omitirá operaciones `chown` cuando el propietario no exista. + +## Estructura del Proyecto + +``` +Servicio/Instalacion-Base-VibeVoice/ +├── instalador.sh # Script principal de instalación +├── configuracion/ +│ └── stack-vibe.conf # Única fuente de verdad (configuración) +├── librerias/ +│ ├── registrador.sh # Sistema de bitácoras +│ ├── ayudante.sh # Funciones auxiliares +│ └── validador.sh # Validaciones del sistema +├── modulos/ +│ ├── 01-verificacion-sistema.sh # Verificación de requisitos +│ ├── 02-python.sh # Instalación de Python +│ ├── 03-docker.sh # Instalación de Docker +│ ├── 04-servicios-datos.sh # PostgreSQL, Redis, Kafka +│ ├── 05-docker-compose.sh # Orquestación de contenedores +│ └── 06-systemd-service.sh # Servicio de sistema +├── pruebas/ +│ ├── validar-instalacion.sh # Validación post-instalación +│ └── probar-modulo.sh # Pruebas de módulos individuales +├── bitacoras/ # Logs de instalación (generado) +├── LEEME.md # Este archivo +├── GLOSARIO.md # Glosario de términos técnicos +└── arbol.md # Estructura detallada del proyecto +``` + +## Instalación Rápida + +### Paso 1: Clonar el Repositorio + +```bash +git clone https://github.com/jhoavera/VibeVoice.git +cd VibeVoice/Servicio/Instalacion-Base-VibeVoice +``` + +### Paso 2: Hacer Ejecutables los Scripts + +```bash +chmod +x instalador.sh +chmod +x librerias/*.sh +chmod +x modulos/*.sh +chmod +x pruebas/*.sh +``` + +### Paso 3: Verificar Requisitos (Opcional) + +```bash +sudo ./instalador.sh --check +``` + +### Paso 4: Ejecutar Instalación + +```bash +sudo ./instalador.sh +``` + +La instalación tardará aproximadamente 15-30 minutos dependiendo de la velocidad de su conexión a Internet y los recursos del sistema. + +## Componentes Instalados + +### 1. Python (Módulo 02) +- Python 3.11 o superior +- pip, virtualenv, pipenv +- Entorno virtual en `/opt/vibevoice/venv` +- Paquetes: numpy, scipy, pandas, fastapi, uvicorn, psycopg2, redis, pydantic + +### 2. Docker (Módulo 03) +- Docker Engine 24.0+ +- Docker Compose 2.20+ +- Red Docker: `vibevoice-network` + +### 3. Servicios de Datos (Módulo 04) + +#### PostgreSQL +- Versión: 15-alpine +- Puerto: 5432 +- Base de datos: `vibevoice_db` +- Usuario: `vibe_admin` +- **⚠️ ADVERTENCIA**: Cambiar contraseña por defecto en producción + +#### Redis +- Versión: 7-alpine +- Puerto: 6379 +- Política de memoria: allkeys-lru +- Persistencia: AOF habilitado + +#### Kafka + Zookeeper +- Kafka 3.5 (puerto 9092) +- Zookeeper (puerto 2181) +- Topics: audio-input, transcription-output, analysis-results + +### 4. Docker Compose (Módulo 05) +- Archivo de orquestación: `/opt/vibevoice/config/docker-compose.yml` +- Variables de entorno: `/opt/vibevoice/config/.env` + +### 5. Servicio Systemd (Módulo 06) +- Servicio: `vibevoice.service` +- Usuario del sistema: `vibevoice` +- Inicio automático configurado + +## Uso Post-Instalación + +### Iniciar Servicios + +```bash +sudo systemctl start vibevoice +``` + +### Detener Servicios + +```bash +sudo systemctl stop vibevoice +``` + +### Reiniciar Servicios + +```bash +sudo systemctl restart vibevoice +``` + +### Ver Estado + +```bash +sudo systemctl status vibevoice +``` + +### Ver Logs en Tiempo Real + +```bash +sudo journalctl -u vibevoice -f +``` + +### Validar Instalación + +```bash +cd /path/to/Servicio/Instalacion-Base-VibeVoice +sudo ./pruebas/validar-instalacion.sh +``` + +### Modo Ultra-Ligero (Desarrollo Local Rápido) + +Para ejecutar VibeVoice en modo ultra-ligero con mínimo consumo de recursos (ideal para desarrollo local): + +```bash +# 1. Activar entorno virtual de Python +source /opt/vibevoice/venv/bin/activate + +# 2. Configurar variables de optimización +export OMP_NUM_THREADS=1 +export MKL_NUM_THREADS=1 +export TRANSCRIBE_MODEL=whisper-tiny + +# 3. Iniciar servidor Uvicorn en modo ligero +python -m uvicorn demo.web.app:app \ + --host 0.0.0.0 \ + --port 8000 \ + --workers 1 \ + --limit-concurrency 1 +``` + +**Explicación:** +- `OMP_NUM_THREADS=1` y `MKL_NUM_THREADS=1`: Limitan threads de NumPy/MKL para reducir uso de CPU +- `TRANSCRIBE_MODEL=whisper-tiny`: Usa el modelo más ligero de Whisper +- `--workers 1` y `--limit-concurrency 1`: Minimizan procesos worker y conexiones concurrentes + +**Acceso:** +- Aplicación: http://localhost:8000 +- Documentación API: http://localhost:8000/docs + +### Modo GPU ligero (super liviano) + +Para ejecutar VibeVoice en modo **GPU** pero con consumo reducido de recursos (útil en máquinas con GPUs antiguas o para montar servicios MCP ligeros): + +- Ajustes recomendados en `/opt/vibevoice/config/.env`: + - **MODEL_PATH**: ruta o identificador HuggingFace del modelo (ej. `microsoft/VibeVoice-Realtime-0.5B`) + - **MODEL_DEVICE=cuda**: forzar uso de GPU + - **OMP_NUM_THREADS=1** y **MKL_NUM_THREADS=1**: limitar threads de BLAS/NumPy + - **UVICORN_WORKERS=1** y **UVICORN_LIMIT_CONCURRENCY=1**: minimizar workers y concurrencia + - **VIBE_API_WORKERS=1**: configuración interna para procesos + - **TRANSCRIBE_MODEL=whisper-tiny**: modelo de transcripción ligero + - **PYTORCH_CUDA_ALLOC_CONF=max_split_size_mb:64**: reducir fragmentación de memoria GPU + +Ejemplo de arranque (systemd, recomendado): + +```bash +# (1) Editar y confirmar /opt/vibevoice/config/.env con las variables anteriores +sudo nano /opt/vibevoice/config/.env + +# (2) Reiniciar el servicio de la API para aplicar cambios +sudo systemctl daemon-reload +sudo systemctl restart vibevoice-api + +# (3) Verificar estado y logs +sudo systemctl status vibevoice-api -l +sudo journalctl -u vibevoice-api -f + +# (4) Verificar uso GPU +/usr/bin/nvidia-smi +``` + +Arranque manual (útil para desarrollo, no necesario si usas systemd): + +```bash +source /opt/vibevoice/venv/bin/activate +export MODEL_PATH=microsoft/VibeVoice-Realtime-0.5B +export MODEL_DEVICE=cuda +export OMP_NUM_THREADS=1 MKL_NUM_THREADS=1 TRANSCRIBE_MODEL=whisper-tiny +/opt/vibevoice/venv/bin/uvicorn demo.web.app:app --host 0.0.0.0 --port 8000 --workers 1 --limit-concurrency 1 +``` + +Notas: +- Con `MODEL_DEVICE=cuda` la aplicación cargará el modelo en GPU si PyTorch detecta CUDA; comprobar `nvidia-smi` confirmará uso GPU. +- Si tu GPU tiene poca memoria o sigue habiendo advertencias de compatibilidad (`sm_61`), puedes forzar `MODEL_DEVICE=cpu` temporalmente para estabilidad. + +Nota: Si ejecuta la API en el `venv` del host (modo ultra-ligero), asegúrese de instalar las dependencias de modelos antes de iniciar el servicio: + +```bash +/opt/vibevoice/venv/bin/pip install diffusers huggingface-hub safetensors +``` + +## Configuración + +### Archivo Principal de Configuración + +El archivo `configuracion/stack-vibe.conf` es la **única fuente de verdad** para todos los parámetros de instalación. Edite este archivo antes de la instalación para personalizar: + +- Rutas de directorios +- Versiones de software +- Puertos de servicios +- Credenciales (⚠️ cambiar en producción) +- Recursos del sistema +- Políticas de logs y backups + +### Variables de Entorno + +Después de la instalación, el archivo `/opt/vibevoice/config/.env` contiene las variables de entorno para Docker Compose. Este archivo contiene credenciales sensibles y debe protegerse adecuadamente. + +**Nota importante:** Para que la API pueda inicializarse correctamente, debe definirse la variable `MODEL_PATH` en `/opt/vibevoice/config/.env` (o exportarla en el entorno del servicio host). `MODEL_PATH` puede ser un identificador de repositorio de Hugging Face (por ejemplo `microsoft/VibeVoice-Realtime-0.5B`) o la ruta a un directorio local que contenga el modelo. +## Pruebas y Validación + +### Validación Completa + +```bash +sudo ./pruebas/validar-instalacion.sh +``` + +Ejecuta una batería completa de pruebas que verifican: +- Comandos del sistema instalados +- Versiones de software correctas +- Directorios creados +- Servicios Docker funcionando +- Archivos de configuración presentes +- Servicio systemd configurado +- Puertos en uso + +### Prueba de Módulos Individuales + +```bash +# Listar módulos disponibles +./pruebas/probar-modulo.sh --list + +# Probar un módulo específico +sudo ./pruebas/probar-modulo.sh 02 # Ejemplo: módulo de Python +``` + +## Bitácoras y Auditoría + +### Ubicación de Logs + +- **Logs de instalación**: `/opt/vibevoice/logs/` o `./bitacoras/` +- **Log principal**: `instalacion-YYYYMMDD-HHMMSS.log` +- **Log de errores**: `errores-YYYYMMDD-HHMMSS.log` +- **Log de auditoría**: `auditoria-YYYYMMDD-HHMMSS.log` + +### Niveles de Log + +- **INFO**: Información general del proceso +- **SUCCESS**: Operaciones completadas exitosamente +- **WARN**: Advertencias que no impiden la instalación +- **ERROR**: Errores que pueden afectar la instalación +- **DEBUG**: Información detallada (cuando `VIBE_LOG_LEVEL=DEBUG`) +- **AUDIT**: Registro de auditoría de operaciones críticas + +## Seguridad + +### ⚠️ Consideraciones Críticas de Seguridad + +1. **Cambiar Contraseñas por Defecto** + - PostgreSQL: `VIBE_POSTGRES_PASSWORD` + - Redis: `VIBE_REDIS_PASSWORD` + - Secret Key: `VIBE_SECRET_KEY` + +2. **Proteger Archivo .env** + ```bash + chmod 600 /opt/vibevoice/config/.env + ``` + +3. **Firewall** + - Configurar UFW o iptables para limitar acceso a puertos + - Solo exponer puertos necesarios + +4. **SSL/TLS** + - Habilitar SSL para PostgreSQL + - Configurar HTTPS para API + - Usar certificados válidos en producción + +5. **Secret Manager** + - Usar AWS Secrets Manager, HashiCorp Vault, o similar en producción + - No almacenar credenciales en archivos de configuración + +6. **Backups** + - Configurar backups automáticos de bases de datos + - Almacenar backups en ubicación segura y cifrada + +## Solución de Problemas + +### Error: "Sistema operativo no soportado" +**Solución**: Verificar que esté usando Ubuntu 22.04 o 24.04 +```bash +lsb_release -a +``` + +### Error: "Recursos del sistema insuficientes" +**Solución**: Verificar RAM, CPU y disco disponible +```bash +free -h +nproc +df -h +``` + +### Error: "Puerto ya está en uso" +**Solución**: Identificar y detener el servicio que usa el puerto +```bash +sudo netstat -tulpn | grep :5432 +sudo systemctl stop +``` + +### Error: "Docker no funciona correctamente" +**Solución**: Reiniciar servicio Docker +```bash +sudo systemctl restart docker +sudo systemctl status docker +``` + +### Error: "Permisos insuficientes" +**Solución**: Ejecutar con sudo +```bash +sudo ./instalador.sh +``` + +## Desinstalación + +Para desinstalar VibeVoice: + +```bash +# Detener servicios +sudo systemctl stop vibevoice +sudo systemctl disable vibevoice + +# Eliminar contenedores Docker +docker-compose -f /opt/vibevoice/config/docker-compose.yml down -v + +# Eliminar servicio systemd +sudo rm /etc/systemd/system/vibevoice.service +sudo systemctl daemon-reload + +# Eliminar directorios (ADVERTENCIA: elimina datos) +sudo rm -rf /opt/vibevoice + +# Eliminar usuario de servicio +sudo userdel -r vibevoice +``` + +## Opciones de Línea de Comandos + +```bash +# Mostrar ayuda +./instalador.sh --help + +# Mostrar versión +./instalador.sh --version + +# Solo verificar requisitos +sudo ./instalador.sh --check + +# Instalación sin confirmación (modo automatizado) +sudo ./instalador.sh --skip-confirmation +``` + +## Soporte y Contribuciones + +### Reportar Problemas +- GitHub Issues: https://github.com/jhoavera/VibeVoice/issues + +### Documentación Adicional +- `GLOSARIO.md`: Glosario de términos técnicos +- `arbol.md`: Estructura detallada del proyecto +- Repositorio principal: https://github.com/jhoavera/VibeVoice + +### Licencia +Ver archivo `LICENSE` en la raíz del repositorio. + +## Contacto + +Para más información sobre VibeVoice, visite: +- https://github.com/jhoavera/VibeVoice + +--- + +**Última actualización**: Diciembre 2024 +**Versión del instalador**: 1.0.0 +**Autor**: jhoavera diff --git a/Servicio/Instalacion-Base-VibeVoice/arbol.md b/Servicio/Instalacion-Base-VibeVoice/arbol.md new file mode 100644 index 0000000..33753c3 --- /dev/null +++ b/Servicio/Instalacion-Base-VibeVoice/arbol.md @@ -0,0 +1,416 @@ +# Estructura del Proyecto - Servicio de Instalación VibeVoice + +## Árbol de Directorios Completo + +``` +Servicio/Instalacion-Base-VibeVoice/ +│ +├── instalador.sh # Script principal de instalación +│ │ +│ ├─> Orquesta la ejecución de todos los módulos +│ ├─> Maneja argumentos de línea de comandos +│ ├─> Gestiona el flujo de instalación +│ └─> Genera reportes y estadísticas finales +│ +├── configuracion/ +│ └── stack-vibe.conf # Única fuente de verdad +│ │ +│ ├─> Configuración de rutas del sistema +│ ├─> Versiones de software a instalar +│ ├─> Credenciales de servicios (cambiar en producción) +│ ├─> Parámetros de recursos y límites +│ └─> Configuración de logs y backups +│ +├── librerias/ +│ │ +│ ├── registrador.sh # Sistema de bitácoras +│ │ │ +│ │ ├─> inicializar_bitacoras(): Configuración inicial +│ │ ├─> registrar_info(): Mensajes informativos +│ │ ├─> registrar_exito(): Operaciones exitosas +│ │ ├─> registrar_advertencia(): Advertencias +│ │ ├─> registrar_error(): Errores +│ │ ├─> registrar_debug(): Información de depuración +│ │ ├─> registrar_auditoria(): Registro de auditoría +│ │ ├─> registrar_comando(): Log de comandos ejecutados +│ │ ├─> registrar_error_fatal(): Errores críticos (termina) +│ │ └─> obtener_estadisticas_bitacoras(): Resumen final +│ │ +│ ├── ayudante.sh # Funciones auxiliares +│ │ │ +│ │ ├─> verificar_root(): Validar privilegios +│ │ ├─> solicitar_confirmacion(): Interacción con usuario +│ │ ├─> ejecutar_comando(): Ejecución con logging +│ │ ├─> verificar_comando_existe(): Verificar disponibilidad +│ │ ├─> instalar_paquete_apt(): Instalación de paquetes +│ │ ├─> actualizar_apt(): Actualizar repositorios +│ │ ├─> crear_directorio(): Crear con permisos +│ │ ├─> crear_usuario_sistema(): Crear usuario de servicio +│ │ ├─> obtener_memoria_total_gb(): Info de RAM +│ │ ├─> obtener_espacio_disco_gb(): Info de disco +│ │ ├─> obtener_numero_cpus(): Info de CPUs +│ │ ├─> verificar_conectividad_internet(): Test de red +│ │ ├─> esperar_servicio(): Esperar servicio activo +│ │ ├─> comparar_versiones(): Comparar versiones semánticas +│ │ ├─> generar_password_seguro(): Generar contraseñas +│ │ ├─> crear_respaldo(): Crear backups +│ │ └─> mostrar_barra_progreso(): UI de progreso +│ │ +│ └── validador.sh # Validaciones del sistema +│ │ +│ ├─> validar_ubuntu_version(): Verificar SO compatible +│ ├─> validar_recursos_sistema(): RAM, CPU, disco +│ ├─> validar_conectividad(): Internet y repos +│ ├─> validar_python_version(): Versión de Python +│ ├─> validar_docker_version(): Versión de Docker +│ ├─> validar_docker_compose_version(): Versión de Compose +│ ├─> validar_puertos_disponibles(): Puertos libres +│ ├─> validar_privilegios(): Permisos root +│ ├─> validar_configuracion(): Archivo de config +│ ├─> validar_servicio_activo(): Estado de servicio +│ ├─> validar_docker_funcionando(): Docker operativo +│ └─> validar_instalacion_completa(): Validación total +│ +├── modulos/ +│ │ +│ ├── 01-verificacion-sistema.sh # Módulo 1: Verificaciones +│ │ │ +│ │ ├─> Validar privilegios de root +│ │ ├─> Validar versión de Ubuntu (22.04/24.04) +│ │ ├─> Verificar recursos mínimos (RAM, CPU, disco) +│ │ ├─> Verificar conectividad a Internet +│ │ ├─> Validar archivo de configuración +│ │ ├─> Verificar puertos disponibles +│ │ └─> Mostrar resumen del sistema +│ │ +│ ├── 02-python.sh # Módulo 2: Python +│ │ │ +│ │ ├─> Actualizar repositorios apt +│ │ ├─> Instalar dependencias de compilación +│ │ ├─> Agregar PPA deadsnakes (si necesario) +│ │ ├─> Instalar Python 3.11+ +│ │ ├─> Instalar pip, virtualenv, pipenv +│ │ ├─> Crear entorno virtual en /opt/vibevoice/venv +│ │ ├─> Instalar paquetes esenciales en venv +│ │ └─> Validar instalación de Python +│ │ +│ ├── 03-docker.sh # Módulo 3: Docker +│ │ │ +│ │ ├─> Verificar instalación previa +│ │ ├─> Instalar dependencias previas +│ │ ├─> Agregar clave GPG de Docker +│ │ ├─> Configurar repositorio de Docker +│ │ ├─> Instalar Docker Engine y plugins +│ │ ├─> Instalar Docker Compose standalone +│ │ ├─> Iniciar y habilitar servicio Docker +│ │ ├─> Configurar daemon.json +│ │ ├─> Crear red vibevoice-network +│ │ ├─> Agregar usuarios al grupo docker +│ │ └─> Validar funcionamiento de Docker +│ │ +│ ├── 04-servicios-datos.sh # Módulo 4: Servicios de Datos +│ │ │ +│ │ ├─> Crear directorios de datos +│ │ │ +│ │ ├─> PostgreSQL: +│ │ │ ├─> Detener contenedor existente +│ │ │ ├─> Crear contenedor PostgreSQL 15-alpine +│ │ │ ├─> Configurar variables de entorno +│ │ │ ├─> Montar volumen de datos +│ │ │ ├─> Exponer puerto 5432 +│ │ │ ├─> Esperar disponibilidad +│ │ │ └─> Crear extensiones (uuid-ossp, pg_trgm) +│ │ │ +│ │ ├─> Redis: +│ │ │ ├─> Detener contenedor existente +│ │ │ ├─> Crear contenedor Redis 7-alpine +│ │ │ ├─> Configurar autenticación y memoria +│ │ │ ├─> Habilitar persistencia AOF +│ │ │ ├─> Exponer puerto 6379 +│ │ │ └─> Validar con PING +│ │ │ +│ │ └─> Kafka + Zookeeper: +│ │ ├─> Crear contenedor Zookeeper +│ │ ├─> Exponer puerto 2181 +│ │ ├─> Crear contenedor Kafka +│ │ ├─> Configurar conexión a Zookeeper +│ │ ├─> Exponer puerto 9092 +│ │ └─> Crear topics predefinidos +│ │ +│ ├── 05-docker-compose.sh # Módulo 5: Docker Compose +│ │ │ +│ │ ├─> Crear directorio de configuración +│ │ ├─> Generar docker-compose.yml: +│ │ │ ├─> Definir servicios (postgres, redis, kafka, etc.) +│ │ │ ├─> Configurar redes +│ │ │ ├─> Configurar volúmenes +│ │ │ ├─> Configurar health checks +│ │ │ └─> Configurar políticas de reinicio +│ │ ├─> Generar archivo .env: +│ │ │ ├─> Variables de PostgreSQL +│ │ │ ├─> Variables de Redis +│ │ │ ├─> Variables de Kafka +│ │ │ ├─> Variables de API +│ │ │ ├─> Variables de seguridad +│ │ │ └─> Establecer permisos restrictivos (600) +│ │ └─> Validar sintaxis de docker-compose.yml +│ │ +│ └── 06-systemd-service.sh # Módulo 6: Servicio Systemd +│ │ +│ ├─> Crear usuario de sistema 'vibevoice' +│ ├─> Configurar permisos de directorios +│ ├─> Generar archivo vibevoice.service: +│ │ ├─> Configurar dependencias (After, Requires) +│ │ ├─> Configurar usuario y grupo +│ │ ├─> Definir comandos (ExecStart, ExecStop) +│ │ ├─> Configurar reinicio automático +│ │ ├─> Establecer límites de recursos +│ │ └─> Aplicar sandboxing de seguridad +│ ├─> Recargar daemon de systemd +│ ├─> Habilitar servicio para inicio automático +│ └─> Mostrar comandos de gestión +│ +├── pruebas/ +│ │ +│ ├── validar-instalacion.sh # Validación post-instalación +│ │ │ +│ │ ├─> Sección 1: Comandos del Sistema +│ │ │ └─> Verificar python3, pip3, docker, docker-compose +│ │ │ +│ │ ├─> Sección 2: Versiones de Software +│ │ │ └─> Mostrar versiones instaladas +│ │ │ +│ │ ├─> Sección 3: Directorios +│ │ │ └─> Verificar existencia de directorios clave +│ │ │ +│ │ ├─> Sección 4: Servicios Docker +│ │ │ ├─> Verificar servicio Docker activo +│ │ │ ├─> Verificar red Docker +│ │ │ └─> Verificar contenedores (si existen) +│ │ │ +│ │ ├─> Sección 5: Archivos de Configuración +│ │ │ └─> Verificar existencia de configs +│ │ │ +│ │ ├─> Sección 6: Servicio Systemd +│ │ │ └─> Verificar servicio creado y habilitado +│ │ │ +│ │ ├─> Sección 7: Conectividad de Puertos +│ │ │ └─> Verificar puertos en uso +│ │ │ +│ │ └─> Resumen Final +│ │ ├─> Contador de pruebas +│ │ ├─> Pruebas exitosas vs fallidas +│ │ └─> Porcentaje de éxito +│ │ +│ └── probar-modulo.sh # Prueba de módulos individuales +│ │ +│ ├─> Listar módulos disponibles +│ ├─> Ejecutar módulo específico +│ ├─> Medir tiempo de ejecución +│ └─> Reportar resultado +│ +├── bitacoras/ # Directorio de logs (generado) +│ │ +│ ├── instalacion-YYYYMMDD-HHMMSS.log # Log principal +│ ├── errores-YYYYMMDD-HHMMSS.log # Log de errores +│ └── auditoria-YYYYMMDD-HHMMSS.log # Log de auditoría +│ +├── LEEME.md # Documentación principal +│ │ +│ ├─> Descripción general +│ ├─> Características principales +│ ├─> Requisitos del sistema +│ ├─> Guía de instalación +│ ├─> Componentes instalados +│ ├─> Uso post-instalación +│ ├─> Configuración +│ ├─> Pruebas y validación +│ ├─> Bitácoras y auditoría +│ ├─> Seguridad +│ ├─> Solución de problemas +│ └─> Soporte y contribuciones +│ +├── GLOSARIO.md # Glosario técnico +│ │ +│ ├─> Términos técnicos (A-Z) +│ ├─> Acrónimos comunes +│ ├─> Convenciones de nomenclatura +│ └─> Referencias técnicas +│ +└── arbol.md # Este archivo + │ + ├─> Estructura completa del proyecto + ├─> Descripción de cada componente + ├─> Flujo de ejecución + └─> Dependencias entre módulos + +``` + +## Directorios Creados en el Sistema (Post-Instalación) + +``` +/opt/vibevoice/ # Directorio base +│ +├── venv/ # Entorno virtual Python +│ ├── bin/ # Ejecutables +│ ├── lib/ # Bibliotecas Python +│ └── include/ # Headers +│ +├── datos/ # Datos de servicios +│ ├── postgresql/ # Datos PostgreSQL +│ ├── redis/ # Datos Redis +│ ├── kafka/ # Datos Kafka +│ └── zookeeper/ # Datos Zookeeper +│ +├── logs/ # Bitácoras del sistema +│ ├── instalacion-*.log # Logs de instalación +│ ├── errores-*.log # Logs de errores +│ └── auditoria-*.log # Logs de auditoría +│ +├── config/ # Configuraciones +│ ├── docker-compose.yml # Orquestación de servicios +│ └── .env # Variables de entorno +│ +├── backups/ # Respaldos automáticos +│ └── (archivos de backup) +│ +├── temp/ # Archivos temporales +│ └── (archivos temporales) +│ +└── app/ # Aplicación VibeVoice + └── (código de la aplicación) +``` + +## Archivos de Systemd + +``` +/etc/systemd/system/ +└── vibevoice.service # Servicio de VibeVoice +``` + +## Flujo de Ejecución del Instalador + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ INICIO DE INSTALACIÓN │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Cargar Configuración (stack-vibe.conf) │ +│ Cargar Librerías (registrador, ayudante, validador) │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Inicializar Sistema de Bitácoras │ +│ Crear archivos de log │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Mostrar Banner y Resumen │ +│ Solicitar Confirmación del Usuario │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ MÓDULO 01: Verificación del Sistema │ +│ ├─ Validar privilegios root │ +│ ├─ Validar versión Ubuntu │ +│ ├─ Validar recursos (RAM, CPU, disco) │ +│ ├─ Validar conectividad │ +│ └─ Validar puertos disponibles │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ MÓDULO 02: Instalación de Python │ +│ ├─ Instalar dependencias │ +│ ├─ Instalar Python 3.11+ │ +│ ├─ Crear entorno virtual │ +│ └─ Instalar paquetes Python │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ MÓDULO 03: Instalación de Docker │ +│ ├─ Agregar repositorio Docker │ +│ ├─ Instalar Docker Engine │ +│ ├─ Instalar Docker Compose │ +│ ├─ Configurar daemon │ +│ └─ Crear red Docker │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ MÓDULO 04: Configuración de Servicios de Datos │ +│ ├─ Desplegar PostgreSQL │ +│ ├─ Desplegar Redis │ +│ └─ Desplegar Kafka + Zookeeper │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ MÓDULO 05: Configuración de Docker Compose │ +│ ├─ Generar docker-compose.yml │ +│ ├─ Generar archivo .env │ +│ └─ Validar sintaxis │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ MÓDULO 06: Configuración de Servicio Systemd │ +│ ├─ Crear usuario de sistema │ +│ ├─ Configurar permisos │ +│ ├─ Generar archivo de servicio │ +│ └─ Habilitar servicio │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Mostrar Resultado Final │ +│ Mostrar Instrucciones Post-Instalación │ +│ Mostrar Estadísticas de Bitácoras │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ INSTALACIÓN COMPLETADA │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## Dependencias Entre Módulos + +``` +Módulo 01 (Verificación) + │ + ├──> Módulo 02 (Python) + │ │ + │ └──> Módulo 03 (Docker) + │ │ + │ ├──> Módulo 04 (Servicios de Datos) + │ │ │ + │ │ └──> Módulo 05 (Docker Compose) + │ │ │ + │ └───────────────┴──> Módulo 06 (Systemd) +``` + +## Tamaños Aproximados de Componentes + +| Componente | Tamaño Aproximado | +|------------|-------------------| +| Scripts de instalación | ~150 KB | +| Python + venv + paquetes | ~2-3 GB | +| Docker Engine | ~500 MB | +| PostgreSQL (imagen) | ~200 MB | +| Redis (imagen) | ~30 MB | +| Kafka + Zookeeper (imágenes) | ~600 MB | +| Datos de servicios | Variable (crece con uso) | +| Logs | Variable (configurable) | +| **Total inicial** | **~4-5 GB** | + +--- + +**Última actualización**: Diciembre 2024 +**Versión del documento**: 1.0.0 diff --git a/Servicio/Instalacion-Base-VibeVoice/configuracion/stack-vibe.conf b/Servicio/Instalacion-Base-VibeVoice/configuracion/stack-vibe.conf new file mode 100644 index 0000000..98157ba --- /dev/null +++ b/Servicio/Instalacion-Base-VibeVoice/configuracion/stack-vibe.conf @@ -0,0 +1,166 @@ +#!/bin/bash +# ============================================================================ +# Archivo: stack-vibe.conf +# Propósito: Configuración centralizada para el servicio de instalación VibeVoice +# Versión: 1.0.0 +# Descripción: Única fuente de verdad para todos los parámetros de instalación +# ============================================================================ + +# ============================================================================ +# INFORMACIÓN DEL SISTEMA +# ============================================================================ +export VIBE_VERSION="1.0.0" +export VIBE_NOMBRE_PROYECTO="VibeVoice" +export VIBE_DESCRIPCION="Sistema de transcripción y análisis de voz con IA" + +# ============================================================================ +# CONFIGURACIÓN DE RUTAS +# ============================================================================ +export VIBE_DIR_BASE="/opt/vibevoice" +export VIBE_DIR_DATOS="${VIBE_DIR_BASE}/datos" +export VIBE_DIR_LOGS="${VIBE_DIR_BASE}/logs" +export VIBE_DIR_CONFIG="${VIBE_DIR_BASE}/config" +export VIBE_DIR_BACKUPS="${VIBE_DIR_BASE}/backups" +export VIBE_DIR_TEMP="${VIBE_DIR_BASE}/temp" + +# ============================================================================ +# CONFIGURACIÓN DE PYTHON +# ============================================================================ +export VIBE_PYTHON_VERSION="3.11" +export VIBE_PYTHON_MIN_VERSION="3.10" +export VIBE_VENV_DIR="${VIBE_DIR_BASE}/venv" +export VIBE_PYTHON_PACKAGES="torch torchaudio transformers fastapi uvicorn pydantic sqlalchemy redis kafka-python" + +# ============================================================================ +# CONFIGURACIÓN DE DOCKER +# ============================================================================ +export VIBE_DOCKER_MIN_VERSION="24.0" +export VIBE_DOCKER_COMPOSE_MIN_VERSION="2.20" +export VIBE_DOCKER_NETWORK="vibevoice-network" +export VIBE_DOCKER_SUBNET="172.28.0.0/16" + +# ============================================================================ +# CONFIGURACIÓN DE POSTGRESQL +# ============================================================================ +# ADVERTENCIA: Estas credenciales son solo para DESARROLLO/DEMO +# En producción, usar variables de entorno seguras o secret manager +export VIBE_POSTGRES_VERSION="15-alpine" +export VIBE_POSTGRES_HOST="localhost" +export VIBE_POSTGRES_PORT="5432" +export VIBE_POSTGRES_DB="vibevoice_db" +export VIBE_POSTGRES_USER="vibe_admin" +export VIBE_POSTGRES_PASSWORD="Cambiar_En_Produccion_123!" +export VIBE_POSTGRES_MAX_CONNECTIONS="200" +export VIBE_POSTGRES_SHARED_BUFFERS="256MB" + +# ============================================================================ +# CONFIGURACIÓN DE REDIS +# ============================================================================ +export VIBE_REDIS_VERSION="7-alpine" +export VIBE_REDIS_HOST="localhost" +export VIBE_REDIS_PORT="6379" +export VIBE_REDIS_PASSWORD="Cambiar_En_Produccion_Redis456!" +export VIBE_REDIS_MAX_MEMORY="2gb" +export VIBE_REDIS_EVICTION_POLICY="allkeys-lru" + +# ============================================================================ +# CONFIGURACIÓN DE KAFKA +# ============================================================================ +export VIBE_KAFKA_VERSION="3.5" +export VIBE_KAFKA_HOST="localhost" +export VIBE_KAFKA_PORT="9092" +export VIBE_KAFKA_ZOOKEEPER_PORT="2181" +export VIBE_KAFKA_HEAP_OPTS="-Xmx1G -Xms1G" +export VIBE_KAFKA_TOPICS="audio-input,transcription-output,analysis-results" + +# ============================================================================ +# CONFIGURACIÓN DE SERVICIOS VibeVoice +# ============================================================================ +export VIBE_API_PORT="8000" +export VIBE_API_WORKERS="4" +export VIBE_API_TIMEOUT="300" +export VIBE_WEBSOCKET_PORT="8001" +export VIBE_ADMIN_PORT="8080" + +# Punto de entrada ASGI para Uvicorn (se detecta automáticamente si no está configurado) +export VIBE_UVICORN_APP="${VIBE_UVICORN_APP:-demo.web.app:app}" + +# ============================================================================ +# CONFIGURACIÓN DE RENDIMIENTO Y MODELOS +# ============================================================================ +# Modelo de transcripción (whisper-tiny es el más ligero para desarrollo local) +export TRANSCRIBE_MODEL="${TRANSCRIBE_MODEL:-whisper-tiny}" + +# Optimización de threads para ahorro de recursos en desarrollo local +export OMP_NUM_THREADS="${OMP_NUM_THREADS:-1}" +export MKL_NUM_THREADS="${MKL_NUM_THREADS:-1}" + +# Configuración de Uvicorn para modo ligero +export UVICORN_WORKERS="${UVICORN_WORKERS:-1}" +export UVICORN_LIMIT_CONCURRENCY="${UVICORN_LIMIT_CONCURRENCY:-1}" + +# Límites de recursos para contenedores Docker (opcional, para desarrollo local) +export POSTGRES_MEM="${POSTGRES_MEM:-512m}" +export POSTGRES_CPUS="${POSTGRES_CPUS:-0.5}" +export REDIS_MEM="${REDIS_MEM:-256m}" +export REDIS_CPUS="${REDIS_CPUS:-0.5}" + +# ============================================================================ +# CONFIGURACIÓN DE SEGURIDAD +# ============================================================================ +export VIBE_SECRET_KEY="CAMBIAR_ESTE_SECRET_KEY_EN_PRODUCCION_abc123xyz" +export VIBE_JWT_ALGORITHM="HS256" +export VIBE_JWT_EXPIRATION="3600" +export VIBE_CORS_ORIGINS="http://localhost:3000,http://localhost:8080" +export VIBE_ALLOWED_HOSTS="localhost,127.0.0.1" + +# ============================================================================ +# CONFIGURACIÓN DE RECURSOS DEL SISTEMA +# ============================================================================ +export VIBE_MIN_RAM_GB="8" +export VIBE_MIN_DISK_GB="50" +export VIBE_MIN_CPU_CORES="4" + +# ============================================================================ +# CONFIGURACIÓN DE BITÁCORAS +# ============================================================================ +export VIBE_LOG_LEVEL="INFO" +export VIBE_LOG_FORMAT="json" +export VIBE_LOG_RETENTION_DAYS="30" +export VIBE_LOG_MAX_SIZE="100M" +export VIBE_LOG_ROTATIONS="10" + +# ============================================================================ +# CONFIGURACIÓN DE RESPALDOS +# ============================================================================ +export VIBE_BACKUP_ENABLED="true" +export VIBE_BACKUP_SCHEDULE="0 2 * * *" # 2 AM diariamente +export VIBE_BACKUP_RETENTION_DAYS="7" +export VIBE_BACKUP_COMPRESSION="gzip" + +# ============================================================================ +# CONFIGURACIÓN DE SYSTEMD +# ============================================================================ +export VIBE_SERVICE_NAME="vibevoice" +export VIBE_SERVICE_USER="vibevoice" +export VIBE_SERVICE_GROUP="vibevoice" +export VIBE_SERVICE_RESTART="always" +export VIBE_SERVICE_RESTART_SEC="10" + +# ============================================================================ +# CONFIGURACIÓN DE MONITOREO +# ============================================================================ +export VIBE_HEALTH_CHECK_INTERVAL="30" +export VIBE_HEALTH_CHECK_TIMEOUT="10" +export VIBE_METRICS_ENABLED="true" +export VIBE_METRICS_PORT="9090" + +# ============================================================================ +# CONFIGURACIÓN DE UBUNTU +# ============================================================================ +export VIBE_UBUNTU_VERSIONS="22.04 24.04" +export VIBE_REQUIRED_PACKAGES="curl wget git build-essential libssl-dev libffi-dev software-properties-common" + +# ============================================================================ +# FIN DE CONFIGURACIÓN +# ============================================================================ diff --git a/Servicio/Instalacion-Base-VibeVoice/instalador.sh b/Servicio/Instalacion-Base-VibeVoice/instalador.sh new file mode 100755 index 0000000..78d7fa5 --- /dev/null +++ b/Servicio/Instalacion-Base-VibeVoice/instalador.sh @@ -0,0 +1,362 @@ +#!/bin/bash +# ============================================================================ +# Instalador Principal: VibeVoice +# Propósito: Orquestar la instalación completa de VibeVoice en Ubuntu 22.04/24.04 +# Versión: 1.0.0 +# Descripción: Instalador modular, idempotente y con trazabilidad completa +# ============================================================================ + +set -euo pipefail + +# ============================================================================ +# CONFIGURACIÓN INICIAL +# ============================================================================ +INSTALLER_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +INSTALLER_VERSION="1.0.0" + +# Modo no interactivo por defecto (puede sobrescribirse con NONINTERACTIVE=0) +export NONINTERACTIVE="${NONINTERACTIVE:-1}" + +# Configurar bitácora central +# shellcheck disable=SC2155 +export BITACORA="${INSTALLER_DIR}/bitacoras/instalacion-$(date +%Y%m%d-%H%M%S).log" +mkdir -p "${INSTALLER_DIR}/bitacoras" + +# Redirigir toda salida a bitácora y terminal +exec > >(tee -a "${BITACORA}") 2>&1 + +# Trap para capturar errores +# shellcheck disable=SC2064,SC2154 +trap "ret=\$?; echo '[ERROR] Fallo en instalador (código=\$ret). Revisa ${BITACORA}' >&2; exit \$ret" ERR + +# Cargar configuración y librerías +source "${INSTALLER_DIR}/configuracion/stack-vibe.conf" +source "${INSTALLER_DIR}/librerias/registrador.sh" +source "${INSTALLER_DIR}/librerias/ayudante.sh" +source "${INSTALLER_DIR}/librerias/validador.sh" + +# ============================================================================ +# FUNCIONES DE BANNER +# ============================================================================ +mostrar_banner() { + clear + echo "" + echo "╔══════════════════════════════════════════════════════════════════════╗" + echo "║ ║" + echo "║ INSTALADOR VIBEVOICE v${INSTALLER_VERSION} ║" + echo "║ ║" + echo "║ Sistema de Transcripción y Análisis de Voz con IA ║" + echo "║ ║" + echo "╚══════════════════════════════════════════════════════════════════════╝" + echo "" + echo " Versión del Sistema: ${VIBE_VERSION}" + echo " Plataforma: Ubuntu 22.04 / 24.04" + echo " Tipo de Instalación: Completa (Base + Servicios + Systemd)" + echo "" + echo "════════════════════════════════════════════════════════════════════════" + echo "" +} + +mostrar_resumen_instalacion() { + echo "" + registrar_info "╔══════════════════════════════════════════════════════════════╗" + registrar_info "║ RESUMEN DE COMPONENTES A INSTALAR ║" + registrar_info "╚══════════════════════════════════════════════════════════════╝" + echo "" + registrar_info "Módulos de instalación:" + registrar_info " 1. Verificación del sistema (Ubuntu, recursos, conectividad)" + registrar_info " 2. Python ${VIBE_PYTHON_VERSION} + pip + virtualenv + dependencias" + registrar_info " 3. Docker Engine + Docker Compose" + registrar_info " 4. Servicios de datos:" + registrar_info " • PostgreSQL ${VIBE_POSTGRES_VERSION} (Base de datos)" + registrar_info " • Redis ${VIBE_REDIS_VERSION} (Caché y colas)" + registrar_info " • Kafka ${VIBE_KAFKA_VERSION} + Zookeeper (Mensajería)" + registrar_info " 5. Docker Compose (Orquestación de servicios)" + registrar_info " 6. Servicio Systemd (Inicio automático)" + echo "" + registrar_info "Directorios de instalación:" + registrar_info " • Base: ${VIBE_DIR_BASE}" + registrar_info " • Datos: ${VIBE_DIR_DATOS}" + registrar_info " • Logs: ${VIBE_DIR_LOGS}" + registrar_info " • Config: ${VIBE_DIR_CONFIG}" + registrar_info " • Backups: ${VIBE_DIR_BACKUPS}" + echo "" + registrar_info "═══════════════════════════════════════════════════════════════" + echo "" +} + +# ============================================================================ +# FUNCIÓN: ejecutar_modulo +# Propósito: Ejecutar un módulo de instalación con manejo de errores +# Parámetros: +# $1: Número del módulo +# $2: Nombre del script del módulo +# $3: Descripción del módulo +# ============================================================================ +ejecutar_modulo() { + local numero="$1" + local script="$2" + local descripcion="$3" + local script_path="${INSTALLER_DIR}/modulos/${script}" + + echo "" + registrar_info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + registrar_info "MÓDULO ${numero}: ${descripcion}" + registrar_info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + if [[ ! -f "${script_path}" ]]; then + registrar_error_fatal "No se encontró el módulo: ${script_path}" 10 + fi + + # Ejecutar módulo + if bash "${script_path}"; then + registrar_exito "✓ Módulo ${numero} completado exitosamente" + return 0 + else + local codigo=$? + registrar_error "✗ Error en módulo ${numero}: ${descripcion}" + registrar_error_fatal "Instalación abortada en módulo ${numero}" ${codigo} + return ${codigo} + fi +} + +# ============================================================================ +# FUNCIÓN: verificar_prerequisitos +# ============================================================================ +verificar_prerequisitos() { + registrar_info "Verificando prerequisitos de instalación..." + + # Verificar que se ejecuta como root + if [[ $EUID -ne 0 ]]; then + echo "" + echo "ERROR: Este instalador debe ejecutarse con privilegios de root" + echo "Por favor, ejecute: sudo $0" + echo "" + exit 1 + fi + + # Verificar que todos los módulos existen + local modulos=( + "01-verificacion-sistema.sh" + "02-python.sh" + "03-docker.sh" + "04-servicios-datos.sh" + "05-docker-compose.sh" + "06-systemd-service.sh" + ) + + for modulo in "${modulos[@]}"; do + if [[ ! -f "${INSTALLER_DIR}/modulos/${modulo}" ]]; then + echo "ERROR: Falta el módulo: ${modulo}" + exit 1 + fi + done + + registrar_debug "Prerequisitos verificados correctamente" +} + +# ============================================================================ +# FUNCIÓN: instalacion_principal +# ============================================================================ +instalacion_principal() { + local inicio + inicio=$(date +%s) + + # Inicializar sistema de bitácoras + inicializar_bitacoras + + # Mostrar banner + mostrar_banner + + # Mostrar resumen + mostrar_resumen_instalacion + + # Solicitar confirmación + if ! solicitar_confirmacion "¿Desea continuar con la instalación?"; then + registrar_info "Instalación cancelada por el usuario" + exit 0 + fi + + # Ejecutar módulos en orden + ejecutar_modulo "01" "01-verificacion-sistema.sh" "Verificación del Sistema" + ejecutar_modulo "02" "02-python.sh" "Instalación de Python" + ejecutar_modulo "03" "03-docker.sh" "Instalación de Docker" + ejecutar_modulo "04" "04-servicios-datos.sh" "Configuración de Servicios de Datos" + ejecutar_modulo "05" "05-docker-compose.sh" "Configuración de Docker Compose" + ejecutar_modulo "06" "06-systemd-service.sh" "Configuración de Servicio Systemd" + + # Calcular tiempo de instalación + local fin + fin=$(date +%s) + local duracion=$((fin - inicio)) + local minutos=$((duracion / 60)) + local segundos=$((duracion % 60)) + + # Mostrar resultado final + echo "" + echo "╔══════════════════════════════════════════════════════════════════════╗" + echo "║ ║" + echo "║ ✓ INSTALACIÓN COMPLETADA EXITOSAMENTE ║" + echo "║ ║" + echo "╚══════════════════════════════════════════════════════════════════════╝" + echo "" + registrar_exito "Instalación de VibeVoice completada exitosamente" + registrar_info "Tiempo total de instalación: ${minutos} minutos ${segundos} segundos" + echo "" + + # Mostrar instrucciones post-instalación + mostrar_instrucciones_postinstalacion + + # Mostrar estadísticas de bitácoras + obtener_estadisticas_bitacoras +} + +# ============================================================================ +# FUNCIÓN: mostrar_instrucciones_postinstalacion +# ============================================================================ +mostrar_instrucciones_postinstalacion() { + echo "" + registrar_info "╔══════════════════════════════════════════════════════════════╗" + registrar_info "║ INSTRUCCIONES POST-INSTALACIÓN ║" + registrar_info "╚══════════════════════════════════════════════════════════════╝" + echo "" + registrar_info "1. Iniciar servicios de VibeVoice:" + registrar_info " sudo systemctl start ${VIBE_SERVICE_NAME}" + echo "" + registrar_info "2. Verificar estado del servicio:" + registrar_info " sudo systemctl status ${VIBE_SERVICE_NAME}" + echo "" + registrar_info "3. Ver logs en tiempo real:" + registrar_info " sudo journalctl -u ${VIBE_SERVICE_NAME} -f" + echo "" + registrar_info "4. Validar instalación:" + registrar_info " cd ${INSTALLER_DIR}" + registrar_info " sudo ./pruebas/validar-instalacion.sh" + echo "" + registrar_info "5. Acceder a los servicios:" + registrar_info " • API: http://localhost:${VIBE_API_PORT}" + registrar_info " • PostgreSQL: localhost:${VIBE_POSTGRES_PORT}" + registrar_info " • Redis: localhost:${VIBE_REDIS_PORT}" + registrar_info " • Kafka: localhost:${VIBE_KAFKA_PORT}" + echo "" + registrar_advertencia "═══════════════════════════════════════════════════════════════" + registrar_advertencia "IMPORTANTE - SEGURIDAD:" + registrar_advertencia "═══════════════════════════════════════════════════════════════" + registrar_advertencia "1. Cambiar contraseñas por defecto en: ${VIBE_DIR_CONFIG}/.env" + registrar_advertencia "2. Configurar firewall para limitar acceso a puertos" + registrar_advertencia "3. Habilitar SSL/TLS para conexiones remotas" + registrar_advertencia "4. Implementar secret manager en producción" + registrar_advertencia "5. Configurar backups automáticos de datos" + registrar_advertencia "═══════════════════════════════════════════════════════════════" + echo "" + registrar_info "Para más información, consulte:" + registrar_info " • ${INSTALLER_DIR}/LEEME.md" + registrar_info " • ${INSTALLER_DIR}/GLOSARIO.md" + registrar_info " • https://github.com/jhoavera/VibeVoice" + echo "" +} + +# ============================================================================ +# FUNCIÓN: mostrar_ayuda +# ============================================================================ +mostrar_ayuda() { + cat </dev/null || true +source "${SCRIPT_DIR}/registrador.sh" 2>/dev/null || true + +# ============================================================================ +# FUNCIÓN: verificar_root +# Propósito: Verificar si el script se ejecuta con privilegios de root +# Retorno: 0 si es root, 1 si no lo es +# ============================================================================ +verificar_root() { + if [[ $EUID -ne 0 ]]; then + registrar_error "Este script debe ejecutarse con privilegios de root (sudo)" + return 1 + fi + registrar_debug "Verificación de privilegios root: OK" + return 0 +} + +# ============================================================================ +# FUNCIÓN: solicitar_confirmacion +# Propósito: Solicitar confirmación del usuario antes de continuar +# Parámetros: +# $1: Mensaje de confirmación +# Retorno: 0 si confirma (o si NONINTERACTIVE=1), 1 si rechaza +# ============================================================================ +solicitar_confirmacion() { + local mensaje="${1:-¿Desea continuar?}" + local respuesta + + # En modo NONINTERACTIVE, asumir 'sí' automáticamente + if [[ "${NONINTERACTIVE:-0}" == "1" ]]; then + registrar_info "Modo NONINTERACTIVE: auto-confirmando: ${mensaje}" + return 0 + fi + + echo "" + echo -e "${COLOR_AMARILLO}${mensaje} (s/N)${COLOR_RESET}" + read -r respuesta + + if [[ "${respuesta}" =~ ^[Ss]$ ]]; then + registrar_auditoria "Usuario confirmó: ${mensaje}" + return 0 + else + registrar_advertencia "Usuario rechazó: ${mensaje}" + return 1 + fi +} + +# ============================================================================ +# FUNCIÓN: ejecutar_comando +# Propósito: Ejecutar comando con registro automático +# Parámetros: +# $1: Comando a ejecutar +# $2: Mensaje descriptivo (opcional) +# Retorno: Código de salida del comando +# ============================================================================ +ejecutar_comando() { + local comando="$1" + local descripcion="${2:-Ejecutando comando}" + + registrar_info "${descripcion}..." + registrar_debug "Comando: ${comando}" + + local salida + salida=$(eval "${comando}" 2>&1) + local codigo=$? + + registrar_comando "${comando}" "${codigo}" "${salida}" + + if [[ ${codigo} -ne 0 ]]; then + registrar_error "Falló: ${descripcion}" + return ${codigo} + fi + + registrar_exito "${descripcion} completado" + return 0 +} + +# ============================================================================ +# FUNCIÓN: verificar_comando_existe +# Propósito: Verificar si un comando está disponible en el sistema +# Parámetros: +# $1: Nombre del comando +# Retorno: 0 si existe, 1 si no existe +# ============================================================================ +verificar_comando_existe() { + local comando="$1" + + if command -v "${comando}" &> /dev/null; then + registrar_debug "Comando encontrado: ${comando}" + return 0 + else + registrar_advertencia "Comando no encontrado: ${comando}" + return 1 + fi +} + +# ============================================================================ +# FUNCIÓN: instalar_paquete_apt +# Propósito: Instalar paquete usando apt con verificación +# Parámetros: +# $1: Nombre del paquete +# Retorno: 0 si se instaló correctamente, 1 si falló +# ============================================================================ +instalar_paquete_apt() { + local paquete="$1" + + registrar_info "Instalando paquete: ${paquete}" + + if dpkg -l | grep -q "^ii ${paquete} "; then + registrar_info "Paquete ${paquete} ya está instalado" + return 0 + fi + + DEBIAN_FRONTEND=noninteractive apt-get install -y "${paquete}" &>/dev/null + local codigo=$? + + if [[ ${codigo} -eq 0 ]]; then + registrar_exito "Paquete instalado: ${paquete}" + return 0 + else + registrar_error "Error al instalar paquete: ${paquete}" + return 1 + fi +} + +# ============================================================================ +# FUNCIÓN: actualizar_apt +# Propósito: Actualizar índice de paquetes apt +# Retorno: 0 si se actualizó correctamente, 1 si falló +# ============================================================================ +actualizar_apt() { + registrar_info "Actualizando índice de paquetes apt..." + + apt-get update -qq &>/dev/null + local codigo=$? + + if [[ ${codigo} -eq 0 ]]; then + registrar_exito "Índice de paquetes actualizado" + return 0 + else + registrar_error "Error al actualizar índice de paquetes" + return 1 + fi +} + +# ============================================================================ +# FUNCIÓN: crear_directorio +# Propósito: Crear directorio con permisos y propietario +# Parámetros: +# $1: Ruta del directorio +# $2: Propietario (opcional) +# $3: Permisos (opcional, por defecto 755) +# Retorno: 0 si se creó correctamente, 1 si falló +# ============================================================================ +crear_directorio() { + local ruta="$1" + local propietario="${2:-}" + local permisos="${3:-755}" + + if [[ -d "${ruta}" ]]; then + registrar_debug "Directorio ya existe: ${ruta}" + return 0 + fi + + registrar_info "Creando directorio: ${ruta}" + mkdir -p "${ruta}" + chmod "${permisos}" "${ruta}" + + if [[ -n "${propietario}" ]]; then + chown -R "${propietario}:${propietario}" "${ruta}" + fi + + registrar_exito "Directorio creado: ${ruta}" + return 0 +} + +# ============================================================================ +# FUNCIÓN: crear_usuario_sistema +# Propósito: Crear usuario de sistema para el servicio +# Parámetros: +# $1: Nombre de usuario +# $2: Directorio home (opcional) +# Retorno: 0 si se creó correctamente, 1 si falló +# ============================================================================ +crear_usuario_sistema() { + local usuario="$1" + local home_dir="${2:-/opt/${usuario}}" + + if id "${usuario}" &>/dev/null; then + registrar_info "Usuario ${usuario} ya existe" + return 0 + fi + + registrar_info "Creando usuario de sistema: ${usuario}" + useradd --system --home-dir "${home_dir}" --shell /bin/bash --create-home "${usuario}" + local codigo=$? + + if [[ ${codigo} -eq 0 ]]; then + registrar_exito "Usuario creado: ${usuario}" + registrar_auditoria "Usuario de sistema creado: ${usuario} (home: ${home_dir})" + return 0 + else + registrar_error "Error al crear usuario: ${usuario}" + return 1 + fi +} + +# ============================================================================ +# FUNCIÓN: obtener_memoria_total_gb +# Propósito: Obtener memoria RAM total del sistema en GB +# Retorno: Memoria total en GB +# ============================================================================ +obtener_memoria_total_gb() { + local mem_kb=$(grep MemTotal /proc/meminfo | awk '{print $2}') + local mem_gb=$((mem_kb / 1024 / 1024)) + echo "${mem_gb}" +} + +# ============================================================================ +# FUNCIÓN: obtener_espacio_disco_gb +# Propósito: Obtener espacio disponible en disco en GB +# Parámetros: +# $1: Ruta del punto de montaje (por defecto /) +# Retorno: Espacio disponible en GB +# ============================================================================ +obtener_espacio_disco_gb() { + local ruta="${1:-/}" + local espacio=$(df -BG "${ruta}" | tail -1 | awk '{print $4}' | sed 's/G//') + echo "${espacio}" +} + +# ============================================================================ +# FUNCIÓN: obtener_numero_cpus +# Propósito: Obtener número de CPUs del sistema +# Retorno: Número de CPUs +# ============================================================================ +obtener_numero_cpus() { + nproc +} + +# ============================================================================ +# FUNCIÓN: verificar_conectividad_internet +# Propósito: Verificar si hay conexión a Internet +# Retorno: 0 si hay conexión, 1 si no la hay +# ============================================================================ +verificar_conectividad_internet() { + registrar_debug "Verificando conectividad a Internet..." + + if ping -c 1 -W 2 8.8.8.8 &>/dev/null; then + registrar_debug "Conectividad a Internet: OK" + return 0 + else + registrar_advertencia "No se detectó conexión a Internet" + return 1 + fi +} + +# ============================================================================ +# FUNCIÓN: esperar_servicio +# Propósito: Esperar a que un servicio esté activo +# Parámetros: +# $1: Nombre del servicio +# $2: Timeout en segundos (opcional, por defecto 30) +# Retorno: 0 si el servicio está activo, 1 si timeout +# ============================================================================ +esperar_servicio() { + local servicio="$1" + local timeout="${2:-30}" + local contador=0 + + registrar_info "Esperando a que el servicio ${servicio} esté activo..." + + while [[ ${contador} -lt ${timeout} ]]; do + if systemctl is-active --quiet "${servicio}"; then + registrar_exito "Servicio ${servicio} está activo" + return 0 + fi + sleep 1 + ((contador++)) + done + + registrar_error "Timeout esperando al servicio ${servicio}" + return 1 +} + +# ============================================================================ +# FUNCIÓN: wait_for_postgres +# Propósito: Esperar a que PostgreSQL esté listo para aceptar conexiones +# Parámetros: +# $1: Nombre del contenedor (opcional, por defecto vibevoice-postgres) +# $2: Timeout en segundos (opcional, por defecto 60) +# Retorno: 0 si PostgreSQL está listo, 1 si timeout +# ============================================================================ +wait_for_postgres() { + local container_name="${1:-vibevoice-postgres}" + local timeout="${2:-60}" + local contador=0 + + registrar_info "Esperando a que PostgreSQL (${container_name}) esté listo..." + + while [[ ${contador} -lt ${timeout} ]]; do + if docker exec "${container_name}" pg_isready -U "${VIBE_POSTGRES_USER:-postgres}" &>/dev/null; then + registrar_exito "PostgreSQL está listo y aceptando conexiones" + return 0 + fi + sleep 2 + ((contador+=2)) + done + + registrar_error "Timeout esperando a PostgreSQL (${timeout}s). El contenedor puede no estar funcionando correctamente." + registrar_error "Revisa los logs con: docker logs ${container_name}" + return 1 +} + +# ============================================================================ +# FUNCIÓN: wait_for_redis +# Propósito: Esperar a que Redis esté listo para aceptar conexiones +# Parámetros: +# $1: Nombre del contenedor (opcional, por defecto vibevoice-redis) +# $2: Timeout en segundos (opcional, por defecto 30) +# Retorno: 0 si Redis está listo, 1 si timeout +# ============================================================================ +wait_for_redis() { + local container_name="${1:-vibevoice-redis}" + local timeout="${2:-30}" + local contador=0 + + registrar_info "Esperando a que Redis (${container_name}) esté listo..." + + while [[ ${contador} -lt ${timeout} ]]; do + if docker exec "${container_name}" redis-cli -a "${VIBE_REDIS_PASSWORD:-}" ping 2>/dev/null | grep -q "PONG"; then + registrar_exito "Redis está listo y respondiendo a PING" + return 0 + fi + sleep 1 + ((contador++)) + done + + registrar_error "Timeout esperando a Redis (${timeout}s). El contenedor puede no estar funcionando correctamente." + registrar_error "Revisa los logs con: docker logs ${container_name}" + return 1 +} + +# ============================================================================ +# FUNCIÓN: comparar_versiones +# Propósito: Comparar dos versiones en formato semántico +# Parámetros: +# $1: Versión 1 +# $2: Versión 2 +# Retorno: 0 si v1 >= v2, 1 si v1 < v2 +# ============================================================================ +comparar_versiones() { + local v1="$1" + local v2="$2" + + if [[ "${v1}" == "${v2}" ]]; then + return 0 + fi + + local IFS=. + local i ver1=($v1) ver2=($v2) + + for ((i=0; i<${#ver1[@]} || i<${#ver2[@]}; i++)); do + local num1=${ver1[i]:-0} + local num2=${ver2[i]:-0} + + if ((10#$num1 > 10#$num2)); then + return 0 + elif ((10#$num1 < 10#$num2)); then + return 1 + fi + done + + return 0 +} + +# ============================================================================ +# FUNCIÓN: generar_password_seguro +# Propósito: Generar contraseña aleatoria segura +# Parámetros: +# $1: Longitud (opcional, por defecto 32) +# Retorno: Contraseña generada +# ============================================================================ +generar_password_seguro() { + local longitud="${1:-32}" + openssl rand -base64 48 | tr -d "=+/" | cut -c1-${longitud} +} + +# ============================================================================ +# FUNCIÓN: crear_respaldo +# Propósito: Crear respaldo de un archivo o directorio +# Parámetros: +# $1: Ruta del archivo/directorio a respaldar +# Retorno: 0 si se creó el respaldo, 1 si falló +# ============================================================================ +crear_respaldo() { + local origen="$1" + local timestamp=$(date +%Y%m%d-%H%M%S) + local respaldo="${origen}.backup-${timestamp}" + + if [[ ! -e "${origen}" ]]; then + registrar_advertencia "No existe el archivo/directorio a respaldar: ${origen}" + return 1 + fi + + registrar_info "Creando respaldo: ${respaldo}" + cp -r "${origen}" "${respaldo}" + + if [[ $? -eq 0 ]]; then + registrar_exito "Respaldo creado: ${respaldo}" + return 0 + else + registrar_error "Error al crear respaldo de: ${origen}" + return 1 + fi +} + +# ============================================================================ +# FUNCIÓN: mostrar_barra_progreso +# Propósito: Mostrar barra de progreso simple +# Parámetros: +# $1: Progreso actual (0-100) +# $2: Mensaje (opcional) +# ============================================================================ +mostrar_barra_progreso() { + local progreso="$1" + local mensaje="${2:-Procesando}" + local ancho=50 + local completado=$((progreso * ancho / 100)) + local restante=$((ancho - completado)) + + printf "\r%s [" "${mensaje}" + printf "%${completado}s" | tr ' ' '=' + printf "%${restante}s" | tr ' ' '-' + printf "] %3d%%" "${progreso}" + + if [[ ${progreso} -eq 100 ]]; then + echo "" + fi +} + +# ============================================================================ +# EXPORTAR FUNCIONES +# ============================================================================ +export -f verificar_root +export -f solicitar_confirmacion +export -f ejecutar_comando +export -f verificar_comando_existe +export -f instalar_paquete_apt +export -f actualizar_apt +export -f crear_directorio +export -f crear_usuario_sistema +export -f obtener_memoria_total_gb +export -f obtener_espacio_disco_gb +export -f obtener_numero_cpus +export -f verificar_conectividad_internet +export -f esperar_servicio +export -f wait_for_postgres +export -f wait_for_redis +export -f comparar_versiones +export -f generar_password_seguro +export -f crear_respaldo +export -f mostrar_barra_progreso diff --git a/Servicio/Instalacion-Base-VibeVoice/librerias/registrador.sh b/Servicio/Instalacion-Base-VibeVoice/librerias/registrador.sh new file mode 100755 index 0000000..116f026 --- /dev/null +++ b/Servicio/Instalacion-Base-VibeVoice/librerias/registrador.sh @@ -0,0 +1,248 @@ +#!/bin/bash +# ============================================================================ +# Archivo: registrador.sh +# Propósito: Sistema de bitácoras centralizado para trazabilidad completa +# Versión: 1.0.0 +# Descripción: Proporciona funciones para registro de eventos, errores y auditoría +# ============================================================================ + +# Cargar configuración +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/../configuracion/stack-vibe.conf" 2>/dev/null || true + +# ============================================================================ +# VARIABLES GLOBALES DE BITÁCORA +# ============================================================================ +# Usar BITACORA si está definida desde el instalador, sino usar default +VIBE_LOG_DIR="${VIBE_LOG_DIR:-${VIBE_DIR_BASE}/logs}" +if [[ -n "${BITACORA:-}" ]]; then + # Si BITACORA está definida externamente, usar esa + VIBE_LOG_FILE="${BITACORA}" + VIBE_ERROR_LOG="$(dirname "${BITACORA}")/errores-$(basename "${BITACORA}")" + VIBE_AUDIT_LOG="$(dirname "${BITACORA}")/auditoria-$(basename "${BITACORA}")" +else + # Sino, crear archivos de log con timestamp + VIBE_LOG_FILE="${VIBE_LOG_DIR}/instalacion-$(date +%Y%m%d-%H%M%S).log" + VIBE_ERROR_LOG="${VIBE_LOG_DIR}/errores-$(date +%Y%m%d-%H%M%S).log" + VIBE_AUDIT_LOG="${VIBE_LOG_DIR}/auditoria-$(date +%Y%m%d-%H%M%S).log" + export BITACORA="${VIBE_LOG_FILE}" +fi + +# Colores para salida en terminal +COLOR_RESET='\033[0m' +COLOR_ROJO='\033[0;31m' +COLOR_VERDE='\033[0;32m' +COLOR_AMARILLO='\033[0;33m' +COLOR_AZUL='\033[0;34m' +COLOR_MORADO='\033[0;35m' +COLOR_CYAN='\033[0;36m' + +# ============================================================================ +# FUNCIÓN: inicializar_bitacoras +# Propósito: Crear directorios de bitácoras y archivos iniciales +# ============================================================================ +inicializar_bitacoras() { + mkdir -p "${VIBE_LOG_DIR}" 2>/dev/null || { + echo "ADVERTENCIA: No se pudo crear directorio de bitácoras en ${VIBE_LOG_DIR}" + VIBE_LOG_DIR="./bitacoras" + mkdir -p "${VIBE_LOG_DIR}" + VIBE_LOG_FILE="${VIBE_LOG_DIR}/instalacion-$(date +%Y%m%d-%H%M%S).log" + VIBE_ERROR_LOG="${VIBE_LOG_DIR}/errores-$(date +%Y%m%d-%H%M%S).log" + VIBE_AUDIT_LOG="${VIBE_LOG_DIR}/auditoria-$(date +%Y%m%d-%H%M%S).log" + } + + touch "${VIBE_LOG_FILE}" "${VIBE_ERROR_LOG}" "${VIBE_AUDIT_LOG}" + + registrar_info "====================================================" + registrar_info "INICIO DE INSTALACIÓN: VibeVoice ${VIBE_VERSION}" + registrar_info "Fecha: $(date '+%Y-%m-%d %H:%M:%S')" + registrar_info "Usuario: $(whoami)" + registrar_info "Hostname: $(hostname)" + registrar_info "Sistema: $(uname -a)" + registrar_info "====================================================" +} + +# ============================================================================ +# FUNCIÓN: registrar_mensaje +# Propósito: Función base para registro de mensajes +# Parámetros: +# $1: Nivel (INFO, WARN, ERROR, DEBUG, SUCCESS) +# $2: Mensaje +# $3: Archivo de log (opcional) +# ============================================================================ +registrar_mensaje() { + local nivel="$1" + local mensaje="$2" + local archivo_log="${3:-${VIBE_LOG_FILE}}" + local timestamp + timestamp="$(date '+%Y-%m-%d %H:%M:%S')" + local log_entry="[${timestamp}] [${nivel}] ${mensaje}" + + # Escribir a archivo de log + echo "${log_entry}" >> "${archivo_log}" + + # Determinar color para terminal + local color="${COLOR_RESET}" + case "${nivel}" in + ERROR) color="${COLOR_ROJO}" ;; + WARN) color="${COLOR_AMARILLO}" ;; + SUCCESS) color="${COLOR_VERDE}" ;; + INFO) color="${COLOR_AZUL}" ;; + DEBUG) color="${COLOR_CYAN}" ;; + AUDIT) color="${COLOR_MORADO}" ;; + esac + + # Escribir a terminal con color + echo -e "${color}[${nivel}]${COLOR_RESET} ${mensaje}" +} + +# ============================================================================ +# FUNCIONES DE REGISTRO POR NIVEL +# ============================================================================ + +registrar_info() { + registrar_mensaje "INFO" "$1" "${VIBE_LOG_FILE}" +} + +registrar_exito() { + registrar_mensaje "SUCCESS" "$1" "${VIBE_LOG_FILE}" +} + +registrar_advertencia() { + registrar_mensaje "WARN" "$1" "${VIBE_LOG_FILE}" +} + +registrar_error() { + registrar_mensaje "ERROR" "$1" "${VIBE_ERROR_LOG}" + registrar_mensaje "ERROR" "$1" "${VIBE_LOG_FILE}" +} + +registrar_debug() { + if [[ "${VIBE_LOG_LEVEL}" == "DEBUG" ]]; then + registrar_mensaje "DEBUG" "$1" "${VIBE_LOG_FILE}" + fi +} + +registrar_auditoria() { + registrar_mensaje "AUDIT" "$1" "${VIBE_AUDIT_LOG}" + registrar_mensaje "AUDIT" "$1" "${VIBE_LOG_FILE}" +} + +# ============================================================================ +# FUNCIÓN: registrar_comando +# Propósito: Registrar ejecución de comandos y sus resultados +# Parámetros: +# $1: Comando ejecutado +# $2: Código de salida +# $3: Salida del comando (opcional) +# ============================================================================ +registrar_comando() { + local comando="$1" + local codigo_salida="$2" + local salida="${3:-}" + + registrar_auditoria "Comando ejecutado: ${comando}" + registrar_auditoria "Código de salida: ${codigo_salida}" + + if [[ ${codigo_salida} -eq 0 ]]; then + registrar_exito "Comando exitoso: ${comando}" + else + registrar_error "Comando falló (código ${codigo_salida}): ${comando}" + if [[ -n "${salida}" ]]; then + registrar_error "Salida: ${salida}" + fi + fi +} + +# ============================================================================ +# FUNCIÓN: registrar_inicio_modulo +# Propósito: Marcar inicio de un módulo de instalación +# Parámetros: +# $1: Nombre del módulo +# ============================================================================ +registrar_inicio_modulo() { + local modulo="$1" + echo "" + registrar_info "╔══════════════════════════════════════════════════════════════╗" + registrar_info "║ INICIANDO MÓDULO: ${modulo}" + registrar_info "╚══════════════════════════════════════════════════════════════╝" + registrar_auditoria "Inicio de módulo: ${modulo}" +} + +# ============================================================================ +# FUNCIÓN: registrar_fin_modulo +# Propósito: Marcar finalización exitosa de un módulo +# Parámetros: +# $1: Nombre del módulo +# ============================================================================ +registrar_fin_modulo() { + local modulo="$1" + registrar_exito "Módulo completado exitosamente: ${modulo}" + registrar_auditoria "Fin de módulo: ${modulo}" + echo "" +} + +# ============================================================================ +# FUNCIÓN: registrar_error_fatal +# Propósito: Registrar error fatal y terminar instalación +# Parámetros: +# $1: Mensaje de error +# $2: Código de salida (opcional, por defecto 1) +# ============================================================================ +registrar_error_fatal() { + local mensaje="$1" + local codigo="${2:-1}" + + echo "" + registrar_error "╔══════════════════════════════════════════════════════════════╗" + registrar_error "║ ERROR FATAL: ${mensaje}" + registrar_error "╚══════════════════════════════════════════════════════════════╝" + registrar_auditoria "Error fatal: ${mensaje} (código: ${codigo})" + registrar_info "Instalación abortada. Revise los logs en: ${VIBE_LOG_DIR}" + exit "${codigo}" +} + +# ============================================================================ +# FUNCIÓN: obtener_estadisticas_bitacoras +# Propósito: Generar resumen de bitácoras +# ============================================================================ +obtener_estadisticas_bitacoras() { + echo "" + registrar_info "═══════════════════════════════════════════════════════════════" + registrar_info "ESTADÍSTICAS DE INSTALACIÓN" + registrar_info "═══════════════════════════════════════════════════════════════" + + if [[ -f "${VIBE_LOG_FILE}" ]]; then + local total_info=$(grep -c "\[INFO\]" "${VIBE_LOG_FILE}" 2>/dev/null || echo "0") + local total_success=$(grep -c "\[SUCCESS\]" "${VIBE_LOG_FILE}" 2>/dev/null || echo "0") + local total_warn=$(grep -c "\[WARN\]" "${VIBE_LOG_FILE}" 2>/dev/null || echo "0") + local total_error=$(grep -c "\[ERROR\]" "${VIBE_LOG_FILE}" 2>/dev/null || echo "0") + + registrar_info "Mensajes informativos: ${total_info}" + registrar_info "Operaciones exitosas: ${total_success}" + registrar_info "Advertencias: ${total_warn}" + registrar_info "Errores: ${total_error}" + registrar_info "Archivo de log principal: ${VIBE_LOG_FILE}" + registrar_info "Archivo de errores: ${VIBE_ERROR_LOG}" + registrar_info "Archivo de auditoría: ${VIBE_AUDIT_LOG}" + fi + + registrar_info "═══════════════════════════════════════════════════════════════" +} + +# ============================================================================ +# EXPORTAR FUNCIONES +# ============================================================================ +export -f inicializar_bitacoras +export -f registrar_mensaje +export -f registrar_info +export -f registrar_exito +export -f registrar_advertencia +export -f registrar_error +export -f registrar_debug +export -f registrar_auditoria +export -f registrar_comando +export -f registrar_inicio_modulo +export -f registrar_fin_modulo +export -f registrar_error_fatal +export -f obtener_estadisticas_bitacoras diff --git a/Servicio/Instalacion-Base-VibeVoice/librerias/validador.sh b/Servicio/Instalacion-Base-VibeVoice/librerias/validador.sh new file mode 100755 index 0000000..7176a81 --- /dev/null +++ b/Servicio/Instalacion-Base-VibeVoice/librerias/validador.sh @@ -0,0 +1,419 @@ +#!/bin/bash +# ============================================================================ +# Archivo: validador.sh +# Propósito: Funciones de validación de requisitos y configuración +# Versión: 1.0.0 +# Descripción: Valida requisitos del sistema, versiones y configuraciones +# ============================================================================ + +# Cargar dependencias +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/../configuracion/stack-vibe.conf" 2>/dev/null || true +source "${SCRIPT_DIR}/registrador.sh" 2>/dev/null || true +source "${SCRIPT_DIR}/ayudante.sh" 2>/dev/null || true + +# ============================================================================ +# FUNCIÓN: validar_ubuntu_version +# Propósito: Validar que se esté ejecutando en Ubuntu 22.04 o 24.04 +# Retorno: 0 si la versión es válida, 1 si no lo es +# ============================================================================ +validar_ubuntu_version() { + registrar_info "Validando versión de Ubuntu..." + + if [[ ! -f /etc/os-release ]]; then + registrar_error "No se pudo detectar el sistema operativo" + return 1 + fi + + source /etc/os-release + + if [[ "${ID}" != "ubuntu" ]]; then + registrar_error "Este instalador solo funciona en Ubuntu. Detectado: ${ID}" + return 1 + fi + + local version_valida=false + for version in ${VIBE_UBUNTU_VERSIONS}; do + if [[ "${VERSION_ID}" == "${version}" ]]; then + version_valida=true + break + fi + done + + if [[ "${version_valida}" == "true" ]]; then + registrar_exito "Versión de Ubuntu válida: ${VERSION_ID} (${PRETTY_NAME})" + return 0 + else + registrar_error "Versión de Ubuntu no soportada: ${VERSION_ID}" + registrar_error "Versiones soportadas: ${VIBE_UBUNTU_VERSIONS}" + return 1 + fi +} + +# ============================================================================ +# FUNCIÓN: validar_recursos_sistema +# Propósito: Validar que el sistema cumpla con los requisitos mínimos +# Retorno: 0 si cumple los requisitos, 1 si no los cumple +# ============================================================================ +validar_recursos_sistema() { + registrar_info "Validando recursos del sistema..." + local errores=0 + + # Validar RAM + local ram_gb=$(obtener_memoria_total_gb) + registrar_info "RAM detectada: ${ram_gb} GB" + + if [[ ${ram_gb} -lt ${VIBE_MIN_RAM_GB} ]]; then + registrar_error "RAM insuficiente: ${ram_gb} GB (mínimo: ${VIBE_MIN_RAM_GB} GB)" + ((errores++)) + else + registrar_exito "RAM suficiente: ${ram_gb} GB" + fi + + # Validar espacio en disco + local disco_gb=$(obtener_espacio_disco_gb "/") + registrar_info "Espacio en disco disponible: ${disco_gb} GB" + + if [[ ${disco_gb} -lt ${VIBE_MIN_DISK_GB} ]]; then + registrar_error "Espacio en disco insuficiente: ${disco_gb} GB (mínimo: ${VIBE_MIN_DISK_GB} GB)" + ((errores++)) + else + registrar_exito "Espacio en disco suficiente: ${disco_gb} GB" + fi + + # Validar CPUs + local cpus=$(obtener_numero_cpus) + registrar_info "CPUs detectadas: ${cpus}" + + if [[ ${cpus} -lt ${VIBE_MIN_CPU_CORES} ]]; then + registrar_advertencia "CPUs por debajo del mínimo recomendado: ${cpus} (mínimo: ${VIBE_MIN_CPU_CORES})" + else + registrar_exito "CPUs suficientes: ${cpus}" + fi + + if [[ ${errores} -gt 0 ]]; then + registrar_error "El sistema NO cumple con los requisitos mínimos" + return 1 + fi + + registrar_exito "El sistema cumple con los requisitos mínimos" + return 0 +} + +# ============================================================================ +# FUNCIÓN: validar_conectividad +# Propósito: Validar conectividad a Internet y repositorios +# Retorno: 0 si hay conectividad, 1 si no la hay +# ============================================================================ +validar_conectividad() { + registrar_info "Validando conectividad..." + + if ! verificar_conectividad_internet; then + registrar_error "Se requiere conexión a Internet para la instalación" + return 1 + fi + + # Verificar acceso a repositorios comunes + local repos=("archive.ubuntu.com" "github.com" "pypi.org" "hub.docker.com") + local errores=0 + + for repo in "${repos[@]}"; do + if ping -c 1 -W 2 "${repo}" &>/dev/null; then + registrar_debug "Acceso a ${repo}: OK" + else + registrar_advertencia "No se pudo acceder a: ${repo}" + ((errores++)) + fi + done + + if [[ ${errores} -gt 2 ]]; then + registrar_error "Problemas de conectividad detectados. Verifique su conexión." + return 1 + fi + + registrar_exito "Conectividad verificada" + return 0 +} + +# ============================================================================ +# FUNCIÓN: validar_python_version +# Propósito: Validar versión de Python instalada +# Retorno: 0 si la versión es válida, 1 si no lo es +# ============================================================================ +validar_python_version() { + registrar_info "Validando versión de Python..." + + if ! verificar_comando_existe python3; then + registrar_error "Python3 no está instalado" + return 1 + fi + + local version_python=$(python3 --version 2>&1 | awk '{print $2}') + registrar_info "Versión de Python detectada: ${version_python}" + + if comparar_versiones "${version_python}" "${VIBE_PYTHON_MIN_VERSION}"; then + registrar_exito "Versión de Python válida: ${version_python}" + return 0 + else + registrar_error "Versión de Python insuficiente: ${version_python} (mínimo: ${VIBE_PYTHON_MIN_VERSION})" + return 1 + fi +} + +# ============================================================================ +# FUNCIÓN: validar_docker_version +# Propósito: Validar versión de Docker instalada +# Retorno: 0 si la versión es válida, 1 si no lo es +# ============================================================================ +validar_docker_version() { + registrar_info "Validando versión de Docker..." + + if ! verificar_comando_existe docker; then + registrar_advertencia "Docker no está instalado" + return 1 + fi + + local version_docker=$(docker --version 2>&1 | grep -oP '(\d+\.\d+\.\d+)' | head -1) + registrar_info "Versión de Docker detectada: ${version_docker}" + + if comparar_versiones "${version_docker}" "${VIBE_DOCKER_MIN_VERSION}"; then + registrar_exito "Versión de Docker válida: ${version_docker}" + return 0 + else + registrar_error "Versión de Docker insuficiente: ${version_docker} (mínimo: ${VIBE_DOCKER_MIN_VERSION})" + return 1 + fi +} + +# ============================================================================ +# FUNCIÓN: validar_docker_compose_version +# Propósito: Validar versión de Docker Compose instalada +# Retorno: 0 si la versión es válida, 1 si no lo es +# ============================================================================ +validar_docker_compose_version() { + registrar_info "Validando versión de Docker Compose..." + + if ! verificar_comando_existe docker-compose; then + if ! docker compose version &>/dev/null; then + registrar_advertencia "Docker Compose no está instalado" + return 1 + fi + local version_compose=$(docker compose version 2>&1 | grep -oP '(\d+\.\d+\.\d+)' | head -1) + else + local version_compose=$(docker-compose --version 2>&1 | grep -oP '(\d+\.\d+\.\d+)' | head -1) + fi + + registrar_info "Versión de Docker Compose detectada: ${version_compose}" + + if comparar_versiones "${version_compose}" "${VIBE_DOCKER_COMPOSE_MIN_VERSION}"; then + registrar_exito "Versión de Docker Compose válida: ${version_compose}" + return 0 + else + registrar_error "Versión de Docker Compose insuficiente: ${version_compose} (mínimo: ${VIBE_DOCKER_COMPOSE_MIN_VERSION})" + return 1 + fi +} + +# ============================================================================ +# FUNCIÓN: validar_puertos_disponibles +# Propósito: Validar que los puertos necesarios estén disponibles +# Retorno: 0 si todos los puertos están disponibles, 1 si alguno está ocupado +# ============================================================================ +validar_puertos_disponibles() { + registrar_info "Validando disponibilidad de puertos..." + + local puertos=( + "${VIBE_POSTGRES_PORT}" + "${VIBE_REDIS_PORT}" + "${VIBE_KAFKA_PORT}" + "${VIBE_KAFKA_ZOOKEEPER_PORT}" + "${VIBE_API_PORT}" + "${VIBE_WEBSOCKET_PORT}" + "${VIBE_ADMIN_PORT}" + ) + + local errores=0 + + for puerto in "${puertos[@]}"; do + if netstat -tuln 2>/dev/null | grep -q ":${puerto} " || \ + ss -tuln 2>/dev/null | grep -q ":${puerto} "; then + registrar_error "Puerto ${puerto} ya está en uso" + ((errores++)) + else + registrar_debug "Puerto ${puerto} disponible" + fi + done + + if [[ ${errores} -gt 0 ]]; then + registrar_error "Hay puertos ocupados. Libere los puertos o modifique la configuración." + return 1 + fi + + registrar_exito "Todos los puertos están disponibles" + return 0 +} + +# ============================================================================ +# FUNCIÓN: validar_privilegios +# Propósito: Validar que se tengan privilegios de root +# Retorno: 0 si tiene privilegios, 1 si no los tiene +# ============================================================================ +validar_privilegios() { + registrar_info "Validando privilegios de ejecución..." + + if verificar_root; then + registrar_exito "Ejecutando con privilegios de root" + return 0 + else + registrar_error "Se requieren privilegios de root. Ejecute con sudo." + return 1 + fi +} + +# ============================================================================ +# FUNCIÓN: validar_configuracion +# Propósito: Validar que el archivo de configuración sea válido +# Retorno: 0 si la configuración es válida, 1 si no lo es +# ============================================================================ +validar_configuracion() { + registrar_info "Validando archivo de configuración..." + + local config_file="${SCRIPT_DIR}/../configuracion/stack-vibe.conf" + + if [[ ! -f "${config_file}" ]]; then + registrar_error "No se encontró el archivo de configuración: ${config_file}" + return 1 + fi + + # Verificar variables críticas + local vars_criticas=( + "VIBE_DIR_BASE" + "VIBE_POSTGRES_DB" + "VIBE_POSTGRES_USER" + "VIBE_REDIS_PORT" + "VIBE_API_PORT" + ) + + local errores=0 + + for var in "${vars_criticas[@]}"; do + if [[ -z "${!var}" ]]; then + registrar_error "Variable crítica no definida: ${var}" + ((errores++)) + else + registrar_debug "Variable ${var} = ${!var}" + fi + done + + if [[ ${errores} -gt 0 ]]; then + registrar_error "Configuración incompleta o inválida" + return 1 + fi + + registrar_exito "Configuración validada correctamente" + return 0 +} + +# ============================================================================ +# FUNCIÓN: validar_servicio_activo +# Propósito: Validar que un servicio esté activo y funcionando +# Parámetros: +# $1: Nombre del servicio +# Retorno: 0 si el servicio está activo, 1 si no lo está +# ============================================================================ +validar_servicio_activo() { + local servicio="$1" + + if systemctl is-active --quiet "${servicio}"; then + registrar_exito "Servicio activo: ${servicio}" + return 0 + else + registrar_error "Servicio no activo: ${servicio}" + return 1 + fi +} + +# ============================================================================ +# FUNCIÓN: validar_docker_funcionando +# Propósito: Validar que Docker esté funcionando correctamente +# Retorno: 0 si Docker funciona, 1 si no funciona +# ============================================================================ +validar_docker_funcionando() { + registrar_info "Validando funcionamiento de Docker..." + + if ! systemctl is-active --quiet docker; then + registrar_error "El servicio Docker no está activo" + return 1 + fi + + if docker ps &>/dev/null; then + registrar_exito "Docker está funcionando correctamente" + return 0 + else + registrar_error "Docker no está funcionando correctamente" + return 1 + fi +} + +# ============================================================================ +# FUNCIÓN: validar_instalacion_completa +# Propósito: Validar que todos los componentes estén instalados +# Retorno: 0 si todo está instalado, 1 si falta algo +# ============================================================================ +validar_instalacion_completa() { + registrar_info "Validando instalación completa de VibeVoice..." + local errores=0 + + # Validar directorios + local dirs=( + "${VIBE_DIR_BASE}" + "${VIBE_DIR_DATOS}" + "${VIBE_DIR_LOGS}" + "${VIBE_DIR_CONFIG}" + ) + + for dir in "${dirs[@]}"; do + if [[ -d "${dir}" ]]; then + registrar_debug "Directorio existe: ${dir}" + else + registrar_error "Directorio faltante: ${dir}" + ((errores++)) + fi + done + + # Validar comandos + local comandos=("python3" "docker" "docker-compose") + + for cmd in "${comandos[@]}"; do + if verificar_comando_existe "${cmd}"; then + registrar_debug "Comando disponible: ${cmd}" + else + registrar_error "Comando faltante: ${cmd}" + ((errores++)) + fi + done + + if [[ ${errores} -gt 0 ]]; then + registrar_error "Instalación incompleta. Faltan ${errores} componente(s)" + return 1 + fi + + registrar_exito "Instalación completa validada" + return 0 +} + +# ============================================================================ +# EXPORTAR FUNCIONES +# ============================================================================ +export -f validar_ubuntu_version +export -f validar_recursos_sistema +export -f validar_conectividad +export -f validar_python_version +export -f validar_docker_version +export -f validar_docker_compose_version +export -f validar_puertos_disponibles +export -f validar_privilegios +export -f validar_configuracion +export -f validar_servicio_activo +export -f validar_docker_funcionando +export -f validar_instalacion_completa diff --git a/Servicio/Instalacion-Base-VibeVoice/modulos/01-verificacion-sistema.sh b/Servicio/Instalacion-Base-VibeVoice/modulos/01-verificacion-sistema.sh new file mode 100755 index 0000000..f461516 --- /dev/null +++ b/Servicio/Instalacion-Base-VibeVoice/modulos/01-verificacion-sistema.sh @@ -0,0 +1,91 @@ +#!/bin/bash +# ============================================================================ +# Módulo: 01-verificacion-sistema.sh +# Propósito: Verificar requisitos del sistema antes de la instalación +# Versión: 1.0.0 +# Descripción: Valida Ubuntu, recursos, conectividad y privilegios +# ============================================================================ + +set -euo pipefail + +# Cargar dependencias +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/../configuracion/stack-vibe.conf" +source "${SCRIPT_DIR}/../librerias/registrador.sh" +source "${SCRIPT_DIR}/../librerias/ayudante.sh" +source "${SCRIPT_DIR}/../librerias/validador.sh" + +# ============================================================================ +# FUNCIÓN PRINCIPAL: verificar_sistema +# ============================================================================ +verificar_sistema() { + registrar_inicio_modulo "Verificación de Sistema" + + local errores=0 + + # Validar privilegios de root + if ! validar_privilegios; then + registrar_error_fatal "Se requieren privilegios de root para ejecutar este instalador" 2 + fi + + # Validar versión de Ubuntu + if ! validar_ubuntu_version; then + registrar_error_fatal "Sistema operativo no soportado" 3 + fi + + # Validar recursos del sistema + if ! validar_recursos_sistema; then + registrar_error "Recursos del sistema insuficientes" + ((errores++)) + fi + + # Validar conectividad + if ! validar_conectividad; then + registrar_error "Problemas de conectividad detectados" + ((errores++)) + fi + + # Validar configuración + if ! validar_configuracion; then + registrar_error_fatal "Configuración inválida" 4 + fi + + # Validar puertos disponibles + if ! validar_puertos_disponibles; then + registrar_advertencia "Algunos puertos están ocupados. Esto puede causar conflictos." + if ! solicitar_confirmacion "¿Desea continuar de todos modos?"; then + registrar_error_fatal "Instalación cancelada por el usuario" 5 + fi + fi + + # Mostrar resumen del sistema + echo "" + registrar_info "═══════════════════════════════════════════════════════════════" + registrar_info "RESUMEN DEL SISTEMA" + registrar_info "═══════════════════════════════════════════════════════════════" + registrar_info "Sistema Operativo: $(lsb_release -d | cut -f2)" + registrar_info "Kernel: $(uname -r)" + registrar_info "RAM: $(obtener_memoria_total_gb) GB" + registrar_info "CPUs: $(obtener_numero_cpus)" + registrar_info "Espacio en Disco: $(obtener_espacio_disco_gb /) GB" + registrar_info "Usuario: $(whoami)" + registrar_info "Hostname: $(hostname)" + registrar_info "═══════════════════════════════════════════════════════════════" + echo "" + + if [[ ${errores} -gt 0 ]]; then + if ! solicitar_confirmacion "Se detectaron ${errores} advertencia(s). ¿Desea continuar?"; then + registrar_error_fatal "Instalación cancelada por el usuario" 6 + fi + fi + + registrar_fin_modulo "Verificación de Sistema" + return 0 +} + +# ============================================================================ +# EJECUCIÓN +# ============================================================================ +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + verificar_sistema +fi diff --git a/Servicio/Instalacion-Base-VibeVoice/modulos/02-python.sh b/Servicio/Instalacion-Base-VibeVoice/modulos/02-python.sh new file mode 100755 index 0000000..392fdf6 --- /dev/null +++ b/Servicio/Instalacion-Base-VibeVoice/modulos/02-python.sh @@ -0,0 +1,241 @@ +#!/bin/bash +# ============================================================================ +# Módulo: 02-python.sh +# Propósito: Instalar y configurar Python para VibeVoice +# Versión: 1.0.0 +# Descripción: Instala Python 3.11+, pip, venv y dependencias necesarias +# ============================================================================ + +set -euo pipefail + +# Cargar dependencias +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/../configuracion/stack-vibe.conf" +source "${SCRIPT_DIR}/../librerias/registrador.sh" +source "${SCRIPT_DIR}/../librerias/ayudante.sh" +source "${SCRIPT_DIR}/../librerias/validador.sh" + +# ============================================================================ +# FUNCIÓN: instalar_python +# ============================================================================ +instalar_python() { + registrar_inicio_modulo "Instalación de Python ${VIBE_PYTHON_VERSION}" + + # Actualizar repositorios + actualizar_apt || registrar_error_fatal "Error al actualizar repositorios apt" + + # Instalar dependencias de Python + registrar_info "Instalando dependencias de Python..." + local dependencias=( + "software-properties-common" + "build-essential" + "libssl-dev" + "libffi-dev" + "python3-dev" + "python3-pip" + "python3-venv" + "python3-setuptools" + "python3-wheel" + ) + + for paquete in "${dependencias[@]}"; do + instalar_paquete_apt "${paquete}" || { + registrar_error "Error al instalar ${paquete}" + return 1 + } + done + + # Verificar versión de Python + if validar_python_version; then + registrar_exito "Python ya está instalado en versión adecuada" + else + # Intentar instalar versión específica desde deadsnakes PPA + registrar_info "Agregando repositorio deadsnakes para Python ${VIBE_PYTHON_VERSION}..." + + if ! grep -q "deadsnakes/ppa" /etc/apt/sources.list.d/*.list 2>/dev/null; then + ejecutar_comando \ + "add-apt-repository -y ppa:deadsnakes/ppa" \ + "Agregando repositorio PPA deadsnakes" + + actualizar_apt + fi + + local python_pkg="python${VIBE_PYTHON_VERSION}" + instalar_paquete_apt "${python_pkg}" || { + registrar_advertencia "No se pudo instalar ${python_pkg}. Usando versión del sistema." + } + + instalar_paquete_apt "${python_pkg}-dev" 2>/dev/null || true + instalar_paquete_apt "${python_pkg}-venv" 2>/dev/null || true + fi + + # Crear enlace simbólico si no existe + if [[ ! -L /usr/bin/python ]]; then + registrar_info "Creando enlace simbólico para python..." + ln -sf /usr/bin/python3 /usr/bin/python + fi + + # Actualizar pip + registrar_info "Actualizando pip..." + python3 -m pip install --upgrade pip setuptools wheel --quiet || { + registrar_advertencia "No se pudo actualizar pip" + } + + # Instalar herramientas de Python + registrar_info "Instalando herramientas de Python..." + local herramientas=("virtualenv" "pipenv") + + for herramienta in "${herramientas[@]}"; do + python3 -m pip install "${herramienta}" --quiet || { + registrar_advertencia "No se pudo instalar ${herramienta}" + } + done + + # Crear entorno virtual para VibeVoice + registrar_info "Creando entorno virtual en ${VIBE_VENV_DIR}..." + crear_directorio "$(dirname "${VIBE_VENV_DIR}")" + + if [[ ! -d "${VIBE_VENV_DIR}" ]]; then + python3 -m venv "${VIBE_VENV_DIR}" || { + registrar_error_fatal "Error al crear entorno virtual" + } + registrar_exito "Entorno virtual creado exitosamente" + else + # Verificar si el venv está corrupto + if [[ ! -f "${VIBE_VENV_DIR}/bin/python" ]] || [[ ! -f "${VIBE_VENV_DIR}/bin/activate" ]]; then + registrar_advertencia "Entorno virtual corrupto detectado. Eliminando y recreando..." + rm -rf "${VIBE_VENV_DIR}" + python3 -m venv "${VIBE_VENV_DIR}" || { + registrar_error_fatal "Error al recrear entorno virtual" + } + registrar_exito "Entorno virtual recreado exitosamente" + else + registrar_info "Entorno virtual ya existe y es válido" + fi + fi + + # Activar entorno virtual e instalar paquetes base + registrar_info "Instalando paquetes Python en entorno virtual..." + source "${VIBE_VENV_DIR}/bin/activate" + + # Actualizar pip en el venv + pip install --upgrade pip setuptools wheel --quiet + + # Instalar paquetes esenciales + local paquetes_esenciales=( + "numpy" + "scipy" + "pandas" + "requests" + "pyyaml" + "python-dotenv" + "psycopg2-binary" + "redis" + "pydantic" + "fastapi" + "uvicorn[standard]" + ) + + for paquete in "${paquetes_esenciales[@]}"; do + registrar_info "Instalando ${paquete}..." + pip install "${paquete}" --quiet || { + registrar_advertencia "Error al instalar ${paquete}" + } + done + + # Instalar dependencias de VibeVoice si existe requirements.txt + if [[ -f "${VIBE_DIR_BASE}/../vibevoice/requirements.txt" ]]; then + registrar_info "Instalando dependencias desde requirements.txt..." + pip install -r "${VIBE_DIR_BASE}/../vibevoice/requirements.txt" --quiet || { + registrar_advertencia "Error al instalar dependencias desde requirements.txt" + } + fi + + deactivate + + # Validar y autocorregir punto ASGI + validar_asgi_entrypoint + + # Verificar instalación + registrar_info "Verificando instalación de Python..." + python3 --version + pip3 --version + + # Mostrar resumen + echo "" + registrar_info "═══════════════════════════════════════════════════════════════" + registrar_info "RESUMEN DE INSTALACIÓN DE PYTHON" + registrar_info "═══════════════════════════════════════════════════════════════" + registrar_info "Versión de Python: $(python3 --version | awk '{print $2}')" + registrar_info "Versión de pip: $(pip3 --version | awk '{print $2}')" + registrar_info "Entorno virtual: ${VIBE_VENV_DIR}" + registrar_info "═══════════════════════════════════════════════════════════════" + echo "" + + registrar_fin_modulo "Instalación de Python" + return 0 +} + +# ============================================================================ +# FUNCIÓN: validar_asgi_entrypoint +# Propósito: Validar y autocorregir el punto de entrada ASGI +# ============================================================================ +validar_asgi_entrypoint() { + registrar_info "Validando punto de entrada ASGI..." + + # Candidatos comunes para el entrypoint ASGI + local candidatos=( + "demo.web.app:app" + "app.main:app" + "main:app" + "app:app" + "vibevoice.app:app" + ) + + # Punto configurado (si existe) + local asgi_app="${VIBE_UVICORN_APP:-demo.web.app:app}" + + # Activar entorno virtual para la prueba + source "${VIBE_VENV_DIR}/bin/activate" + + # Probar el punto configurado + registrar_info "Probando punto ASGI: ${asgi_app}" + if python3 -c "import sys; mod, obj = '${asgi_app}'.split(':'); __import__(mod.replace('.', '/')); getattr(sys.modules[mod], obj)" 2>/dev/null; then + registrar_exito "Punto ASGI válido: ${asgi_app}" + export VIBE_UVICORN_APP="${asgi_app}" + deactivate + return 0 + fi + + # Si falla, probar candidatos comunes + registrar_advertencia "El punto ASGI configurado '${asgi_app}' no es válido. Probando alternativas..." + + for candidato in "${candidatos[@]}"; do + registrar_debug "Probando: ${candidato}" + if python3 -c "import sys; mod, obj = '${candidato}'.split(':'); __import__(mod); getattr(sys.modules[mod], obj)" 2>/dev/null; then + registrar_exito "Punto ASGI encontrado y configurado: ${candidato}" + export VIBE_UVICORN_APP="${candidato}" + registrar_auditoria "Auto-corregido VIBE_UVICORN_APP a: ${candidato}" + deactivate + return 0 + fi + done + + # Si no se encuentra ninguno válido + deactivate + registrar_advertencia "No se pudo detectar automáticamente un punto ASGI válido." + registrar_advertencia "Ajusta manualmente VIBE_UVICORN_APP en configuracion/stack-vibe.conf" + registrar_advertencia "Formato: 'modulo.submodulo:objeto_app' (ej: 'demo.web.app:app')" + + # No es fatal, continuar con el valor por defecto + export VIBE_UVICORN_APP="demo.web.app:app" + registrar_info "Usando punto ASGI por defecto: ${VIBE_UVICORN_APP}" + return 0 +} + +# ============================================================================ +# EJECUCIÓN +# ============================================================================ +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + instalar_python +fi diff --git a/Servicio/Instalacion-Base-VibeVoice/modulos/03-docker.sh b/Servicio/Instalacion-Base-VibeVoice/modulos/03-docker.sh new file mode 100755 index 0000000..4402c27 --- /dev/null +++ b/Servicio/Instalacion-Base-VibeVoice/modulos/03-docker.sh @@ -0,0 +1,228 @@ +#!/bin/bash +# ============================================================================ +# Módulo: 03-docker.sh +# Propósito: Instalar y configurar Docker y Docker Compose +# Versión: 1.0.0 +# Descripción: Instala Docker Engine y Docker Compose para contenedorización +# ============================================================================ + +set -euo pipefail + +# Cargar dependencias +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/../configuracion/stack-vibe.conf" +source "${SCRIPT_DIR}/../librerias/registrador.sh" +source "${SCRIPT_DIR}/../librerias/ayudante.sh" +source "${SCRIPT_DIR}/../librerias/validador.sh" + +# ============================================================================ +# FUNCIÓN: instalar_docker +# ============================================================================ +instalar_docker() { + registrar_inicio_modulo "Instalación de Docker" + + # Verificar si Docker ya está instalado + if verificar_comando_existe docker; then + if validar_docker_version; then + registrar_info "Docker ya está instalado en versión adecuada" + if validar_docker_funcionando; then + registrar_fin_modulo "Instalación de Docker (ya instalado)" + return 0 + fi + else + registrar_advertencia "Docker está instalado pero en versión antigua. Actualizando..." + fi + fi + + # Actualizar repositorios + actualizar_apt || registrar_error_fatal "Error al actualizar repositorios" + + # Instalar dependencias previas + registrar_info "Instalando dependencias de Docker..." + local dependencias=( + "ca-certificates" + "curl" + "gnupg" + "lsb-release" + "apt-transport-https" + ) + + for paquete in "${dependencias[@]}"; do + instalar_paquete_apt "${paquete}" || { + registrar_error "Error al instalar ${paquete}" + return 1 + } + done + + # Agregar clave GPG oficial de Docker + registrar_info "Agregando clave GPG de Docker..." + crear_directorio "/etc/apt/keyrings" + + if [[ ! -f /etc/apt/keyrings/docker.gpg ]]; then + ejecutar_comando \ + "curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg" \ + "Descargando clave GPG de Docker" + + chmod a+r /etc/apt/keyrings/docker.gpg + else + registrar_info "Clave GPG de Docker ya existe" + fi + + # Configurar repositorio de Docker + registrar_info "Configurando repositorio de Docker..." + local docker_repo_file="/etc/apt/sources.list.d/docker.list" + + if [[ ! -f "${docker_repo_file}" ]]; then + echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ + $(lsb_release -cs) stable" | tee "${docker_repo_file}" > /dev/null + + registrar_exito "Repositorio de Docker configurado" + else + registrar_info "Repositorio de Docker ya existe" + fi + + # Actualizar índice de paquetes + actualizar_apt + + # Instalar Docker Engine + registrar_info "Instalando Docker Engine..." + local paquetes_docker=( + "docker-ce" + "docker-ce-cli" + "containerd.io" + "docker-buildx-plugin" + "docker-compose-plugin" + ) + + for paquete in "${paquetes_docker[@]}"; do + instalar_paquete_apt "${paquete}" || { + registrar_error "Error al instalar ${paquete}" + return 1 + } + done + + # Iniciar y habilitar servicio Docker + registrar_info "Iniciando servicio Docker..." + ejecutar_comando "systemctl start docker" "Iniciando Docker" + ejecutar_comando "systemctl enable docker" "Habilitando Docker al inicio" + + # Esperar a que Docker esté listo + esperar_servicio "docker" 30 || { + registrar_error_fatal "Docker no se inició correctamente" + } + + # Configurar Docker para usuario de servicio + if [[ -n "${VIBE_SERVICE_USER:-}" ]]; then + registrar_info "Agregando usuario ${VIBE_SERVICE_USER} al grupo docker..." + usermod -aG docker "${VIBE_SERVICE_USER}" 2>/dev/null || true + fi + + # Agregar usuario actual al grupo docker si no es root + if [[ $(whoami) != "root" ]]; then + usermod -aG docker "$(whoami)" + registrar_info "Usuario $(whoami) agregado al grupo docker" + fi + + # Configurar daemon de Docker + registrar_info "Configurando daemon de Docker..." + local daemon_json="/etc/docker/daemon.json" + + if [[ ! -f "${daemon_json}" ]]; then + cat > "${daemon_json}" </dev/null || echo "unknown") + + if [[ "${estado}" == "running" ]]; then + registrar_info "Contenedor PostgreSQL ya está en ejecución" + # Verificar si está saludable + if wait_for_postgres "vibevoice-postgres" 10; then + registrar_exito "PostgreSQL ya está configurado y funcionando" + return 0 + else + registrar_advertencia "PostgreSQL está corriendo pero no responde. Recreando..." + docker stop vibevoice-postgres 2>/dev/null || true + docker rm vibevoice-postgres 2>/dev/null || true + fi + elif [[ "${estado}" == "exited" ]]; then + registrar_advertencia "Contenedor PostgreSQL existe pero está detenido. Eliminando y recreando..." + docker rm vibevoice-postgres 2>/dev/null || true + else + registrar_info "Eliminando contenedor PostgreSQL en estado: ${estado}" + docker stop vibevoice-postgres 2>/dev/null || true + docker rm vibevoice-postgres 2>/dev/null || true + fi + fi + + # Crear contenedor PostgreSQL + registrar_info "Creando contenedor PostgreSQL ${VIBE_POSTGRES_VERSION}..." + registrar_info "Límites de recursos: Memoria=${POSTGRES_MEM}, CPUs=${POSTGRES_CPUS}" + + docker run -d \ + --name vibevoice-postgres \ + --network "${VIBE_DOCKER_NETWORK}" \ + --memory="${POSTGRES_MEM}" \ + --cpus="${POSTGRES_CPUS}" \ + -e POSTGRES_DB="${VIBE_POSTGRES_DB}" \ + -e POSTGRES_USER="${VIBE_POSTGRES_USER}" \ + -e POSTGRES_PASSWORD="${VIBE_POSTGRES_PASSWORD}" \ + -e POSTGRES_MAX_CONNECTIONS="${VIBE_POSTGRES_MAX_CONNECTIONS}" \ + -e POSTGRES_SHARED_BUFFERS="${VIBE_POSTGRES_SHARED_BUFFERS}" \ + -p "${VIBE_POSTGRES_PORT}:5432" \ + -v "${VIBE_DIR_DATOS}/postgresql:/var/lib/postgresql/data" \ + --restart unless-stopped \ + "postgres:${VIBE_POSTGRES_VERSION}" || { + registrar_error "Error al crear contenedor PostgreSQL" + return 1 + } + + registrar_exito "Contenedor PostgreSQL creado" + + # Usar la función wait_for_postgres + if ! wait_for_postgres "vibevoice-postgres" 60; then + registrar_error "PostgreSQL no está listo después de 60 segundos" + return 1 + fi + + # Crear base de datos y extensiones + registrar_info "Configurando base de datos..." + docker exec vibevoice-postgres psql -U "${VIBE_POSTGRES_USER}" -d "${VIBE_POSTGRES_DB}" -c "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";" 2>/dev/null || true + docker exec vibevoice-postgres psql -U "${VIBE_POSTGRES_USER}" -d "${VIBE_POSTGRES_DB}" -c "CREATE EXTENSION IF NOT EXISTS \"pg_trgm\";" 2>/dev/null || true + + registrar_exito "PostgreSQL configurado correctamente" + registrar_auditoria "PostgreSQL desplegado en puerto ${VIBE_POSTGRES_PORT}" + + return 0 +} + +# ============================================================================ +# FUNCIÓN: configurar_redis +# ============================================================================ +configurar_redis() { + registrar_info "Configurando Redis..." + + # Verificar si el contenedor existe + if docker ps -a | grep -q "vibevoice-redis"; then + local estado=$(docker inspect -f '{{.State.Status}}' vibevoice-redis 2>/dev/null || echo "unknown") + + if [[ "${estado}" == "running" ]]; then + registrar_info "Contenedor Redis ya está en ejecución" + # Verificar si está saludable + if wait_for_redis "vibevoice-redis" 10; then + registrar_exito "Redis ya está configurado y funcionando" + return 0 + else + registrar_advertencia "Redis está corriendo pero no responde. Recreando..." + docker stop vibevoice-redis 2>/dev/null || true + docker rm vibevoice-redis 2>/dev/null || true + fi + elif [[ "${estado}" == "exited" ]]; then + registrar_advertencia "Contenedor Redis existe pero está detenido. Eliminando y recreando..." + docker rm vibevoice-redis 2>/dev/null || true + else + registrar_info "Eliminando contenedor Redis en estado: ${estado}" + docker stop vibevoice-redis 2>/dev/null || true + docker rm vibevoice-redis 2>/dev/null || true + fi + fi + + # Crear contenedor Redis + registrar_info "Creando contenedor Redis ${VIBE_REDIS_VERSION}..." + registrar_info "Límites de recursos: Memoria=${REDIS_MEM}, CPUs=${REDIS_CPUS}" + + docker run -d \ + --name vibevoice-redis \ + --network "${VIBE_DOCKER_NETWORK}" \ + --memory="${REDIS_MEM}" \ + --cpus="${REDIS_CPUS}" \ + -p "${VIBE_REDIS_PORT}:6379" \ + -v "${VIBE_DIR_DATOS}/redis:/data" \ + --restart unless-stopped \ + "redis:${VIBE_REDIS_VERSION}" \ + redis-server \ + --requirepass "${VIBE_REDIS_PASSWORD}" \ + --maxmemory "${VIBE_REDIS_MAX_MEMORY}" \ + --maxmemory-policy "${VIBE_REDIS_EVICTION_POLICY}" \ + --appendonly yes \ + --appendfsync everysec || { + registrar_error "Error al crear contenedor Redis" + return 1 + } + + registrar_exito "Contenedor Redis creado" + + # Esperar a que Redis esté listo + registrar_info "Esperando a que Redis esté listo..." + local intentos=0 + local max_intentos=30 + + # Usar la función wait_for_redis + if ! wait_for_redis "vibevoice-redis" 30; then + registrar_error "Redis no está listo después de 30 segundos" + return 1 + fi + + registrar_exito "Redis configurado correctamente" + registrar_auditoria "Redis desplegado en puerto ${VIBE_REDIS_PORT}" + + return 0 +} + +# ============================================================================ +# FUNCIÓN: configurar_kafka +# ============================================================================ +configurar_kafka() { + registrar_info "Configurando Kafka y Zookeeper..." + + # Detener contenedores existentes + for container in vibevoice-zookeeper vibevoice-kafka; do + if docker ps -a | grep -q "${container}"; then + registrar_info "Deteniendo contenedor ${container}..." + docker stop "${container}" 2>/dev/null || true + docker rm "${container}" 2>/dev/null || true + fi + done + + # Crear contenedor Zookeeper + registrar_info "Creando contenedor Zookeeper..." + + docker run -d \ + --name vibevoice-zookeeper \ + --network "${VIBE_DOCKER_NETWORK}" \ + -e ZOOKEEPER_CLIENT_PORT="${VIBE_KAFKA_ZOOKEEPER_PORT}" \ + -e ZOOKEEPER_TICK_TIME=2000 \ + -p "${VIBE_KAFKA_ZOOKEEPER_PORT}:${VIBE_KAFKA_ZOOKEEPER_PORT}" \ + -v "${VIBE_DIR_DATOS}/zookeeper:/var/lib/zookeeper/data" \ + --restart unless-stopped \ + "confluentinc/cp-zookeeper:7.5.0" || { + registrar_error "Error al crear contenedor Zookeeper" + return 1 + } + + registrar_exito "Contenedor Zookeeper creado" + + # Esperar a que Zookeeper esté listo + sleep 10 + + # Crear contenedor Kafka + registrar_info "Creando contenedor Kafka ${VIBE_KAFKA_VERSION}..." + + docker run -d \ + --name vibevoice-kafka \ + --network "${VIBE_DOCKER_NETWORK}" \ + -e KAFKA_BROKER_ID=1 \ + -e KAFKA_ZOOKEEPER_CONNECT="vibevoice-zookeeper:${VIBE_KAFKA_ZOOKEEPER_PORT}" \ + -e KAFKA_ADVERTISED_LISTENERS="PLAINTEXT://localhost:${VIBE_KAFKA_PORT}" \ + -e KAFKA_LISTENER_SECURITY_PROTOCOL_MAP="PLAINTEXT:PLAINTEXT" \ + -e KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT \ + -e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 \ + -e KAFKA_HEAP_OPTS="${VIBE_KAFKA_HEAP_OPTS}" \ + -e KAFKA_AUTO_CREATE_TOPICS_ENABLE=true \ + -p "${VIBE_KAFKA_PORT}:${VIBE_KAFKA_PORT}" \ + -v "${VIBE_DIR_DATOS}/kafka:/var/lib/kafka/data" \ + --restart unless-stopped \ + "confluentinc/cp-kafka:7.5.0" || { + registrar_error "Error al crear contenedor Kafka" + return 1 + } + + registrar_exito "Contenedor Kafka creado" + + # Esperar a que Kafka esté listo + registrar_info "Esperando a que Kafka esté listo..." + sleep 15 + + # Crear topics de Kafka + registrar_info "Creando topics de Kafka..." + IFS=',' read -ra TOPICS <<< "${VIBE_KAFKA_TOPICS}" + + for topic in "${TOPICS[@]}"; do + docker exec vibevoice-kafka kafka-topics \ + --create \ + --if-not-exists \ + --bootstrap-server localhost:${VIBE_KAFKA_PORT} \ + --topic "${topic}" \ + --partitions 3 \ + --replication-factor 1 2>/dev/null || { + registrar_advertencia "No se pudo crear topic: ${topic}" + } + registrar_info "Topic creado: ${topic}" + done + + registrar_exito "Kafka configurado correctamente" + registrar_auditoria "Kafka desplegado en puerto ${VIBE_KAFKA_PORT}" + + return 0 +} + +# ============================================================================ +# EJECUCIÓN +# ============================================================================ +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + configurar_servicios_datos +fi diff --git a/Servicio/Instalacion-Base-VibeVoice/modulos/05-docker-compose.sh b/Servicio/Instalacion-Base-VibeVoice/modulos/05-docker-compose.sh new file mode 100755 index 0000000..19d4ec8 --- /dev/null +++ b/Servicio/Instalacion-Base-VibeVoice/modulos/05-docker-compose.sh @@ -0,0 +1,424 @@ +#!/bin/bash +# ============================================================================ +# Módulo: 05-docker-compose.sh +# Propósito: Generar y configurar docker-compose.yml para VibeVoice +# Versión: 1.0.0 +# Descripción: Crea archivo docker-compose completo con todos los servicios +# ============================================================================ + +set -euo pipefail + +# Cargar dependencias +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/../configuracion/stack-vibe.conf" +source "${SCRIPT_DIR}/../librerias/registrador.sh" +source "${SCRIPT_DIR}/../librerias/ayudante.sh" +source "${SCRIPT_DIR}/../librerias/validador.sh" + +# ============================================================================ +# FUNCIÓN: configurar_docker_compose +# ============================================================================ +configurar_docker_compose() { + registrar_inicio_modulo "Configuración de Docker Compose" + + # Crear directorio de configuración + crear_directorio "${VIBE_DIR_CONFIG}" + + # Generar archivo docker-compose.yml + generar_docker_compose_file + + # Generar archivo .env + generar_env_file + + # Validar archivo docker-compose + validar_docker_compose_file + + registrar_fin_modulo "Configuración de Docker Compose" + return 0 +} + +# ============================================================================ +# FUNCIÓN: generar_docker_compose_file +# ============================================================================ +generar_docker_compose_file() { + local compose_file="${VIBE_DIR_CONFIG}/docker-compose.yml" + + registrar_info "Generando archivo docker-compose.yml..." + + cat > "${compose_file}" <<'EOF' +version: '3.8' + +networks: + vibevoice-network: + external: true + +volumes: + postgres-data: + redis-data: + kafka-data: + zookeeper-data: + +services: + # ============================================================================ + # PostgreSQL - Base de datos principal + # ============================================================================ + postgres: + image: postgres:${POSTGRES_VERSION:-15-alpine} + container_name: vibevoice-postgres + environment: + POSTGRES_DB: ${POSTGRES_DB} + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_MAX_CONNECTIONS: ${POSTGRES_MAX_CONNECTIONS:-200} + POSTGRES_SHARED_BUFFERS: ${POSTGRES_SHARED_BUFFERS:-256MB} + ports: + - "${POSTGRES_PORT}:5432" + volumes: + - postgres-data:/var/lib/postgresql/data + networks: + - vibevoice-network + restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"] + interval: 10s + timeout: 5s + retries: 5 + + # ============================================================================ + # Redis - Caché y cola de mensajes + # ============================================================================ + redis: + image: redis:${REDIS_VERSION:-7-alpine} + container_name: vibevoice-redis + command: > + redis-server + --requirepass ${REDIS_PASSWORD} + --maxmemory ${REDIS_MAX_MEMORY:-2gb} + --maxmemory-policy ${REDIS_EVICTION_POLICY:-allkeys-lru} + --appendonly yes + --appendfsync everysec + ports: + - "${REDIS_PORT}:6379" + volumes: + - redis-data:/data + networks: + - vibevoice-network + restart: unless-stopped + healthcheck: + test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"] + interval: 10s + timeout: 3s + retries: 5 + + # ============================================================================ + # Zookeeper - Coordinación para Kafka + # ============================================================================ + zookeeper: + image: confluentinc/cp-zookeeper:7.5.0 + container_name: vibevoice-zookeeper + environment: + ZOOKEEPER_CLIENT_PORT: ${KAFKA_ZOOKEEPER_PORT:-2181} + ZOOKEEPER_TICK_TIME: 2000 + ports: + - "${KAFKA_ZOOKEEPER_PORT:-2181}:${KAFKA_ZOOKEEPER_PORT:-2181}" + volumes: + - zookeeper-data:/var/lib/zookeeper/data + networks: + - vibevoice-network + restart: unless-stopped + + # ============================================================================ + # Kafka - Sistema de mensajería + # ============================================================================ + kafka: + image: confluentinc/cp-kafka:7.5.0 + container_name: vibevoice-kafka + depends_on: + - zookeeper + environment: + KAFKA_BROKER_ID: 1 + KAFKA_ZOOKEEPER_CONNECT: zookeeper:${KAFKA_ZOOKEEPER_PORT:-2181} + KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:${KAFKA_PORT} + KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT + KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT + KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 + KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true" + KAFKA_HEAP_OPTS: ${KAFKA_HEAP_OPTS:--Xmx1G -Xms1G} + ports: + - "${KAFKA_PORT}:${KAFKA_PORT}" + volumes: + - kafka-data:/var/lib/kafka/data + networks: + - vibevoice-network + restart: unless-stopped + + # ============================================================================ + # VibeVoice API - Servicio principal + # ============================================================================ + vibevoice-api: + build: + context: ${VIBE_DIR_BASE}/app + dockerfile: Dockerfile + image: vibevoice:latest + container_name: vibevoice-api + profiles: + - host-api + depends_on: + - postgres + - redis + - kafka + environment: + # Base de datos + DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB} + + # Redis + REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379/0 + + # Kafka + KAFKA_BOOTSTRAP_SERVERS: kafka:${KAFKA_PORT} + + # Configuración de la API + API_HOST: 0.0.0.0 + API_PORT: ${API_PORT:-8000} + API_WORKERS: ${API_WORKERS:-4} + API_TIMEOUT: ${API_TIMEOUT:-300} + # Modelo de inferencia + MODEL_PATH: ${MODEL_PATH:-} + MODEL_DEVICE: ${MODEL_DEVICE:-cuda} + VOICE_PRESET: ${VOICE_PRESET:-} + + # Seguridad + SECRET_KEY: ${SECRET_KEY} + JWT_ALGORITHM: ${JWT_ALGORITHM:-HS256} + JWT_EXPIRATION: ${JWT_EXPIRATION:-3600} + + # CORS + CORS_ORIGINS: ${CORS_ORIGINS} + + # Logs + LOG_LEVEL: ${LOG_LEVEL:-INFO} + ports: + - "${API_PORT:-8000}:${API_PORT:-8000}" + volumes: + - ${VIBE_DIR_BASE}/app:/app + - ${VIBE_DIR_LOGS}:/app/logs + networks: + - vibevoice-network + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:${API_PORT:-8000}/health"] + interval: 30s + timeout: 10s + retries: 3 +EOF + + registrar_exito "Archivo docker-compose.yml generado: ${compose_file}" + registrar_auditoria "Docker Compose configurado en: ${compose_file}" + + return 0 +} + +# ============================================================================ +# FUNCIÓN: generar_env_file +# ============================================================================ +generar_env_file() { + local env_file="${VIBE_DIR_CONFIG}/.env" + + registrar_info "Generando archivo .env..." + + cat > "${env_file}" < "${env_example}" <<'ENVEXAMPLE' +# ============================================================================ +# Ejemplo de Configuración de Entorno para VibeVoice +# IMPORTANTE: Copiar a .env y ajustar valores según entorno +# ============================================================================ + +# PostgreSQL +POSTGRES_VERSION=15-alpine +POSTGRES_DB=vibevoice_db +POSTGRES_USER=vibe_admin +POSTGRES_PASSWORD=CHANGE_ME_POSTGRES_PASSWORD +POSTGRES_PORT=5432 +POSTGRES_MAX_CONNECTIONS=200 +POSTGRES_SHARED_BUFFERS=256MB + +# Redis +REDIS_VERSION=7-alpine +REDIS_PORT=6379 +REDIS_PASSWORD=CHANGE_ME_REDIS_PASSWORD +REDIS_MAX_MEMORY=2gb +REDIS_EVICTION_POLICY=allkeys-lru + +# Kafka +KAFKA_PORT=9092 +KAFKA_ZOOKEEPER_PORT=2181 +KAFKA_HEAP_OPTS=-Xmx1G -Xms1G + +# API +API_PORT=8000 +API_WORKERS=1 +API_TIMEOUT=300 + +# Seguridad +SECRET_KEY=CHANGE_ME_SECRET_KEY_FOR_PRODUCTION +JWT_ALGORITHM=HS256 +JWT_EXPIRATION=3600 + +# CORS +CORS_ORIGINS=http://localhost:3000,http://localhost:8080 + +# Logs +LOG_LEVEL=INFO + +# Directorios +VIBE_DIR_BASE=/opt/vibevoice +VIBE_DIR_LOGS=/opt/vibevoice/logs + +# Performance (para modo desarrollo local ligero) +TRANSCRIBE_MODEL=whisper-tiny +OMP_NUM_THREADS=1 +MKL_NUM_THREADS=1 +UVICORN_WORKERS=1 +UVICORN_LIMIT_CONCURRENCY=1 +# Modelo de inferencia (ajustar a su modelo preferido o ruta local) +# Puede usar un repositorio Hugging Face público, por ejemplo: +# MODEL_PATH=microsoft/VibeVoice-Realtime-0.5B +# O una ruta local: MODEL_PATH=/opt/vibevoice/models/VibeVoice-Realtime-0.5B +# Dispositivo: cuda, mps, cpu +MODEL_PATH= +MODEL_DEVICE=cuda +VOICE_PRESET= +ENVEXAMPLE + + chmod 644 "${env_example}" + registrar_exito "Archivo .env.example generado: ${env_example}" + + return 0 +} + +# ============================================================================ +# FUNCIÓN: validar_docker_compose_file +# ============================================================================ +validar_docker_compose_file() { + local compose_file="${VIBE_DIR_CONFIG}/docker-compose.yml" + + registrar_info "Validando archivo docker-compose.yml..." + + cd "${VIBE_DIR_CONFIG}" + + if docker-compose config --quiet 2>/dev/null || docker compose config --quiet 2>/dev/null; then + registrar_exito "Archivo docker-compose.yml validado correctamente" + return 0 + else + registrar_error "Error en la validación de docker-compose.yml" + return 1 + fi +} + + +# ============================================================================ +# FUNCIÓN: generar_dockerfile_api +# ============================================================================ +generar_dockerfile_api() { + local app_dir="${VIBE_DIR_BASE}/app" + crear_directorio "${app_dir}" "${VIBE_SERVICE_USER}" "755" + + local dockerfile="${app_dir}/Dockerfile" + if [[ -f "${dockerfile}" ]]; then + registrar_info "Dockerfile ya existe en ${app_dir}, no se sobrescribe" + return 0 + fi + + registrar_info "Generando Dockerfile mínimo en: ${dockerfile}" + cat > "${dockerfile}" <<'DOCKERFILE' +FROM python:3.12-slim +ENV DEBIAN_FRONTEND=noninteractive +WORKDIR /app +COPY . /app + RUN apt-get update && apt-get install -y --no-install-recommends build-essential gcc git libpq-dev && rm -rf /var/lib/apt/lists/* +RUN python -m pip install --upgrade pip setuptools wheel +RUN python -m pip install --no-cache-dir "uvicorn[standard]" fastapi +RUN if [ -n "${VIBE_PYTHON_PACKAGES:-}" ]; then python -m pip install --no-cache-dir ${VIBE_PYTHON_PACKAGES}; fi +RUN python -m pip install --no-cache-dir . || true +ENV PYTHONUNBUFFERED=1 +CMD ["uvicorn", "demo.web.app:app", "--host", "0.0.0.0", "--port", "8000"] +DOCKERFILE + + registrar_exito "Dockerfile generado: ${dockerfile}" + return 0 +} + +# ============================================================================ +# EJECUCIÓN +# ============================================================================ +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + configurar_docker_compose +fi diff --git a/Servicio/Instalacion-Base-VibeVoice/modulos/06-systemd-service.sh b/Servicio/Instalacion-Base-VibeVoice/modulos/06-systemd-service.sh new file mode 100755 index 0000000..6c69be7 --- /dev/null +++ b/Servicio/Instalacion-Base-VibeVoice/modulos/06-systemd-service.sh @@ -0,0 +1,231 @@ +#!/bin/bash +# ============================================================================ +# Módulo: 06-systemd-service.sh +# Propósito: Configurar servicio systemd para VibeVoice +# Versión: 1.0.0 +# Descripción: Crea y configura servicio systemd para inicio automático +# ============================================================================ + +set -euo pipefail + +# Cargar dependencias +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/../configuracion/stack-vibe.conf" +source "${SCRIPT_DIR}/../librerias/registrador.sh" +source "${SCRIPT_DIR}/../librerias/ayudante.sh" +source "${SCRIPT_DIR}/../librerias/validador.sh" + +# ============================================================================ +# FUNCIÓN: configurar_servicio_systemd +# ============================================================================ +configurar_servicio_systemd() { + registrar_inicio_modulo "Configuración de Servicio Systemd" + + # Crear usuario de servicio + crear_usuario_servicio + + # Configurar permisos de directorios + configurar_permisos + + # Generar archivo de servicio systemd + generar_servicio_systemd + + # Habilitar servicio + habilitar_servicio + + registrar_fin_modulo "Configuración de Servicio Systemd" + return 0 +} + +# ============================================================================ +# FUNCIÓN: crear_usuario_servicio +# ============================================================================ +crear_usuario_servicio() { + registrar_info "Creando usuario de servicio..." + + if crear_usuario_sistema "${VIBE_SERVICE_USER}" "${VIBE_DIR_BASE}"; then + registrar_exito "Usuario de servicio configurado: ${VIBE_SERVICE_USER}" + + # Agregar usuario al grupo docker + if verificar_comando_existe docker; then + usermod -aG docker "${VIBE_SERVICE_USER}" 2>/dev/null || true + registrar_info "Usuario ${VIBE_SERVICE_USER} agregado al grupo docker" + fi + + return 0 + else + registrar_advertencia "El usuario ${VIBE_SERVICE_USER} ya existe" + return 0 + fi +} + +# ============================================================================ +# FUNCIÓN: configurar_permisos +# ============================================================================ +configurar_permisos() { + registrar_info "Configurando permisos de directorios..." + + local directorios=( + "${VIBE_DIR_BASE}" + "${VIBE_DIR_DATOS}" + "${VIBE_DIR_LOGS}" + "${VIBE_DIR_CONFIG}" + "${VIBE_DIR_BACKUPS}" + "${VIBE_DIR_TEMP}" + ) + + for dir in "${directorios[@]}"; do + if [[ -d "${dir}" ]]; then + chown -R "${VIBE_SERVICE_USER}:${VIBE_SERVICE_GROUP}" "${dir}" + registrar_debug "Permisos configurados: ${dir}" + else + crear_directorio "${dir}" "${VIBE_SERVICE_USER}" "755" + fi + done + + registrar_exito "Permisos configurados correctamente" + return 0 +} + +# ============================================================================ +# FUNCIÓN: generar_servicio_systemd +# ============================================================================ +generar_servicio_systemd() { + local service_file="/etc/systemd/system/${VIBE_SERVICE_NAME}.service" + + registrar_info "Generando archivo de servicio systemd..." + + cat > "${service_file}" < "${service_file}" <&2; exit 1; fi' +ExecStart=${VIBE_VENV_DIR}/bin/uvicorn demo.web.app:app --host 0.0.0.0 --port ${VIBE_API_PORT:-8000} --workers 1 +Restart=on-failure +RestartSec=5 +PrivateTmp=true +ProtectSystem=strict +ReadWritePaths=${VIBE_DIR_BASE} ${VIBE_DIR_LOGS} + +[Install] +WantedBy=multi-user.target +EOF + + chmod 0644 "${service_file}" + ejecutar_comando "systemctl daemon-reload" "Recargando daemon de systemd" + ejecutar_comando "systemctl enable ${VIBE_SERVICE_NAME}-api" "Habilitando servicio ${VIBE_SERVICE_NAME}-api" + + registrar_exito "Servicio ${VIBE_SERVICE_NAME}-api creado y habilitado" + return 0 +} + +# ============================================================================ +# EJECUCIÓN +# ============================================================================ +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + configurar_servicio_systemd +fi diff --git a/Servicio/Instalacion-Base-VibeVoice/pruebas/probar-modulo.sh b/Servicio/Instalacion-Base-VibeVoice/pruebas/probar-modulo.sh new file mode 100755 index 0000000..e0d9106 --- /dev/null +++ b/Servicio/Instalacion-Base-VibeVoice/pruebas/probar-modulo.sh @@ -0,0 +1,225 @@ +#!/bin/bash +# ============================================================================ +# Script: probar-modulo.sh +# Propósito: Probar módulos de instalación individualmente +# Versión: 1.0.0 +# Descripción: Permite ejecutar y probar módulos de instalación por separado +# ============================================================================ + +set -euo pipefail + +# Cargar dependencias +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/../configuracion/stack-vibe.conf" +source "${SCRIPT_DIR}/../librerias/registrador.sh" +source "${SCRIPT_DIR}/../librerias/ayudante.sh" +source "${SCRIPT_DIR}/../librerias/validador.sh" + +# ============================================================================ +# FUNCIÓN: mostrar_ayuda +# ============================================================================ +mostrar_ayuda() { + cat < /dev/null; then + registrar_error "No se encontró el módulo: ${numero}" + echo "" + echo "Use './probar-modulo.sh --list' para ver los módulos disponibles" + echo "" + return 1 + fi + + # Obtener nombre exacto del archivo + modulo_script=$(compgen -G "${modulo_script}" | head -1) + + if [[ ! -f "${modulo_script}" ]]; then + registrar_error "El módulo no existe: ${modulo_script}" + return 1 + fi + + # Verificar privilegios de root + if [[ $EUID -ne 0 ]]; then + echo "" + echo "ERROR: Este script debe ejecutarse con privilegios de root" + echo "Por favor, ejecute: sudo $0 ${numero}" + echo "" + return 1 + fi + + # Inicializar bitácoras + inicializar_bitacoras + + echo "" + echo "╔══════════════════════════════════════════════════════════════════════╗" + echo "║ ║" + echo "║ PRUEBA DE MÓDULO DE INSTALACIÓN ║" + echo "║ ║" + echo "╚══════════════════════════════════════════════════════════════════════╝" + echo "" + + local nombre_modulo=$(basename "${modulo_script}") + registrar_info "Módulo a ejecutar: ${nombre_modulo}" + + # Obtener descripción del módulo + local descripcion=$(grep -m 1 "^# Propósito:" "${modulo_script}" | cut -d':' -f2- | xargs) + if [[ -n "${descripcion}" ]]; then + registrar_info "Descripción: ${descripcion}" + fi + + echo "" + + if ! solicitar_confirmacion "¿Desea ejecutar este módulo?"; then + registrar_info "Ejecución cancelada por el usuario" + return 0 + fi + + # Ejecutar módulo + local inicio=$(date +%s) + + echo "" + registrar_info "════════════════════════════════════════════════════════════════" + registrar_info "INICIANDO EJECUCIÓN DEL MÓDULO" + registrar_info "════════════════════════════════════════════════════════════════" + echo "" + + if bash "${modulo_script}"; then + local fin=$(date +%s) + local duracion=$((fin - inicio)) + + echo "" + echo "╔══════════════════════════════════════════════════════════════════════╗" + echo "║ ║" + echo "║ ✓ MÓDULO EJECUTADO EXITOSAMENTE ║" + echo "║ ║" + echo "╚══════════════════════════════════════════════════════════════════════╝" + echo "" + registrar_exito "Módulo completado en ${duracion} segundos" + return 0 + else + local codigo=$? + local fin=$(date +%s) + local duracion=$((fin - inicio)) + + echo "" + echo "╔══════════════════════════════════════════════════════════════════════╗" + echo "║ ║" + echo "║ ✗ ERROR EN LA EJECUCIÓN DEL MÓDULO ║" + echo "║ ║" + echo "╚══════════════════════════════════════════════════════════════════════╝" + echo "" + registrar_error "Módulo falló después de ${duracion} segundos (código: ${codigo})" + registrar_info "Revise los logs para más detalles" + return ${codigo} + fi +} + +# ============================================================================ +# FUNCIÓN: main +# ============================================================================ +main() { + # Procesar argumentos + if [[ $# -eq 0 ]]; then + mostrar_ayuda + return 1 + fi + + case "$1" in + -h|--help) + mostrar_ayuda + return 0 + ;; + -l|--list) + listar_modulos + return 0 + ;; + [0-9]|[0-9][0-9]) + probar_modulo "$1" + return $? + ;; + *) + echo "Argumento inválido: $1" + mostrar_ayuda + return 1 + ;; + esac +} + +# ============================================================================ +# EJECUCIÓN +# ============================================================================ +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + main "$@" +fi diff --git a/Servicio/Instalacion-Base-VibeVoice/pruebas/validar-instalacion.sh b/Servicio/Instalacion-Base-VibeVoice/pruebas/validar-instalacion.sh new file mode 100755 index 0000000..9c9d824 --- /dev/null +++ b/Servicio/Instalacion-Base-VibeVoice/pruebas/validar-instalacion.sh @@ -0,0 +1,240 @@ +#!/bin/bash +# ============================================================================ +# Script: validar-instalacion.sh +# Propósito: Validar que la instalación de VibeVoice sea correcta +# Versión: 1.0.0 +# Descripción: Ejecuta pruebas de validación post-instalación +# ============================================================================ + +set -euo pipefail + +# Cargar dependencias +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/../configuracion/stack-vibe.conf" +source "${SCRIPT_DIR}/../librerias/registrador.sh" +source "${SCRIPT_DIR}/../librerias/ayudante.sh" +source "${SCRIPT_DIR}/../librerias/validador.sh" + +# ============================================================================ +# VARIABLES GLOBALES +# ============================================================================ +TOTAL_PRUEBAS=0 +PRUEBAS_EXITOSAS=0 +PRUEBAS_FALLIDAS=0 + +# ============================================================================ +# FUNCIÓN: ejecutar_prueba +# ============================================================================ +ejecutar_prueba() { + local nombre="$1" + local comando="$2" + + ((TOTAL_PRUEBAS++)) + + echo -n " [${TOTAL_PRUEBAS}] ${nombre}... " + + if eval "${comando}" &>/dev/null; then + echo -e "${COLOR_VERDE}✓ OK${COLOR_RESET}" + ((PRUEBAS_EXITOSAS++)) + return 0 + else + echo -e "${COLOR_ROJO}✗ FALLO${COLOR_RESET}" + ((PRUEBAS_FALLIDAS++)) + return 1 + fi +} + +# ============================================================================ +# FUNCIÓN: validar_instalacion_completa +# ============================================================================ +validar_instalacion_completa() { + inicializar_bitacoras + + echo "" + echo "╔══════════════════════════════════════════════════════════════════════╗" + echo "║ ║" + echo "║ VALIDACIÓN DE INSTALACIÓN - VIBEVOICE ║" + echo "║ ║" + echo "╚══════════════════════════════════════════════════════════════════════╝" + echo "" + + registrar_info "Iniciando validación de instalación..." + echo "" + + # ======================================================================== + # SECCIÓN 1: Comandos del Sistema + # ======================================================================== + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "1. COMANDOS DEL SISTEMA" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + ejecutar_prueba "Python 3 instalado" "command -v python3" + ejecutar_prueba "pip instalado" "command -v pip3" + ejecutar_prueba "Docker instalado" "command -v docker" + ejecutar_prueba "Docker Compose instalado" "command -v docker-compose" + ejecutar_prueba "curl instalado" "command -v curl" + ejecutar_prueba "git instalado" "command -v git" + + echo "" + + # ======================================================================== + # SECCIÓN 2: Versiones + # ======================================================================== + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "2. VERSIONES DE SOFTWARE" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + echo " Python: $(python3 --version 2>&1 | awk '{print $2}')" + echo " pip: $(pip3 --version 2>&1 | awk '{print $2}')" + echo " Docker: $(docker --version 2>&1 | awk '{print $3}' | sed 's/,//')" + echo " Docker Compose: $(docker-compose --version 2>&1 | awk '{print $4}')" + + echo "" + + # ======================================================================== + # SECCIÓN 3: Directorios + # ======================================================================== + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "3. DIRECTORIOS DE INSTALACIÓN" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + ejecutar_prueba "Directorio base existe" "test -d ${VIBE_DIR_BASE}" + ejecutar_prueba "Directorio de datos existe" "test -d ${VIBE_DIR_DATOS}" + ejecutar_prueba "Directorio de logs existe" "test -d ${VIBE_DIR_LOGS}" + ejecutar_prueba "Directorio de config existe" "test -d ${VIBE_DIR_CONFIG}" + ejecutar_prueba "Directorio de backups existe" "test -d ${VIBE_DIR_BACKUPS}" + + echo "" + + # ======================================================================== + # SECCIÓN 4: Servicios Docker + # ======================================================================== + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "4. SERVICIOS DOCKER" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + ejecutar_prueba "Servicio Docker activo" "systemctl is-active docker" + ejecutar_prueba "Red Docker existe" "docker network ls | grep -q ${VIBE_DOCKER_NETWORK}" + + # Verificar contenedores si están corriendo + if docker ps &>/dev/null; then + ejecutar_prueba "Docker funcional" "docker ps" + + # Opcional: verificar contenedores específicos si existen + if docker ps -a | grep -q "vibevoice-postgres"; then + ejecutar_prueba "Contenedor PostgreSQL existe" "docker ps -a | grep -q vibevoice-postgres" + fi + + if docker ps -a | grep -q "vibevoice-redis"; then + ejecutar_prueba "Contenedor Redis existe" "docker ps -a | grep -q vibevoice-redis" + fi + + if docker ps -a | grep -q "vibevoice-kafka"; then + ejecutar_prueba "Contenedor Kafka existe" "docker ps -a | grep -q vibevoice-kafka" + fi + fi + + echo "" + + # ======================================================================== + # SECCIÓN 5: Archivos de Configuración + # ======================================================================== + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "5. ARCHIVOS DE CONFIGURACIÓN" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + ejecutar_prueba "stack-vibe.conf existe" "test -f ${SCRIPT_DIR}/../configuracion/stack-vibe.conf" + + if [[ -f "${VIBE_DIR_CONFIG}/docker-compose.yml" ]]; then + ejecutar_prueba "docker-compose.yml existe" "test -f ${VIBE_DIR_CONFIG}/docker-compose.yml" + fi + + if [[ -f "${VIBE_DIR_CONFIG}/.env" ]]; then + ejecutar_prueba ".env existe" "test -f ${VIBE_DIR_CONFIG}/.env" + fi + + echo "" + + # ======================================================================== + # SECCIÓN 6: Servicio Systemd + # ======================================================================== + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "6. SERVICIO SYSTEMD" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + if [[ -f "/etc/systemd/system/${VIBE_SERVICE_NAME}.service" ]]; then + ejecutar_prueba "Archivo de servicio existe" "test -f /etc/systemd/system/${VIBE_SERVICE_NAME}.service" + ejecutar_prueba "Servicio habilitado" "systemctl is-enabled ${VIBE_SERVICE_NAME}" + else + echo " Servicio systemd no configurado (opcional)" + fi + + echo "" + + # ======================================================================== + # SECCIÓN 7: Conectividad de Puertos + # ======================================================================== + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "7. CONECTIVIDAD DE PUERTOS" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + # Verificar si los puertos están en uso (si los servicios están corriendo) + for puerto in ${VIBE_POSTGRES_PORT} ${VIBE_REDIS_PORT} ${VIBE_KAFKA_PORT}; do + if netstat -tuln 2>/dev/null | grep -q ":${puerto} " || ss -tuln 2>/dev/null | grep -q ":${puerto} "; then + echo -e " Puerto ${puerto}: ${COLOR_VERDE}✓ EN USO${COLOR_RESET}" + else + echo -e " Puerto ${puerto}: ${COLOR_AMARILLO}○ Disponible (servicio no iniciado)${COLOR_RESET}" + fi + done + + echo "" + + # ======================================================================== + # RESUMEN FINAL + # ======================================================================== + echo "╔══════════════════════════════════════════════════════════════════════╗" + echo "║ RESUMEN DE VALIDACIÓN ║" + echo "╚══════════════════════════════════════════════════════════════════════╝" + echo "" + echo " Total de pruebas: ${TOTAL_PRUEBAS}" + echo -e " Pruebas exitosas: ${COLOR_VERDE}${PRUEBAS_EXITOSAS}${COLOR_RESET}" + + if [[ ${PRUEBAS_FALLIDAS} -gt 0 ]]; then + echo -e " Pruebas fallidas: ${COLOR_ROJO}${PRUEBAS_FALLIDAS}${COLOR_RESET}" + else + echo -e " Pruebas fallidas: ${COLOR_VERDE}${PRUEBAS_FALLIDAS}${COLOR_RESET}" + fi + + local porcentaje=$((PRUEBAS_EXITOSAS * 100 / TOTAL_PRUEBAS)) + echo " Porcentaje de éxito: ${porcentaje}%" + echo "" + + if [[ ${PRUEBAS_FALLIDAS} -eq 0 ]]; then + echo -e "${COLOR_VERDE}╔══════════════════════════════════════════════════════════════════════╗${COLOR_RESET}" + echo -e "${COLOR_VERDE}║ ║${COLOR_RESET}" + echo -e "${COLOR_VERDE}║ ✓ INSTALACIÓN VALIDADA EXITOSAMENTE ║${COLOR_RESET}" + echo -e "${COLOR_VERDE}║ ║${COLOR_RESET}" + echo -e "${COLOR_VERDE}╚══════════════════════════════════════════════════════════════════════╝${COLOR_RESET}" + echo "" + registrar_exito "Validación completada: Todas las pruebas pasaron" + return 0 + else + echo -e "${COLOR_AMARILLO}╔══════════════════════════════════════════════════════════════════════╗${COLOR_RESET}" + echo -e "${COLOR_AMARILLO}║ ║${COLOR_RESET}" + echo -e "${COLOR_AMARILLO}║ ⚠ INSTALACIÓN PARCIALMENTE VALIDADA ║${COLOR_RESET}" + echo -e "${COLOR_AMARILLO}║ ║${COLOR_RESET}" + echo -e "${COLOR_AMARILLO}╚══════════════════════════════════════════════════════════════════════╝${COLOR_RESET}" + echo "" + registrar_advertencia "Validación completada: ${PRUEBAS_FALLIDAS} prueba(s) fallaron" + echo " Revise los componentes que fallaron e intente reinstalarlos." + echo "" + return 1 + fi +} + +# ============================================================================ +# EJECUCIÓN +# ============================================================================ +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + validar_instalacion_completa +fi diff --git a/Servicio/Instalacion-Base-VibeVoice/run-vibevoice.sh b/Servicio/Instalacion-Base-VibeVoice/run-vibevoice.sh new file mode 100755 index 0000000..47cb8a7 --- /dev/null +++ b/Servicio/Instalacion-Base-VibeVoice/run-vibevoice.sh @@ -0,0 +1,168 @@ +#!/bin/bash +# ============================================================================ +# Script: run-vibevoice.sh +# Propósito: Arranque manual inmediato de VibeVoice en modo desarrollo local +# Versión: 1.0.0 +# ============================================================================ + +set -euo pipefail + +# ============================================================================ +# CONFIGURACIÓN +# ============================================================================ +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "${SCRIPT_DIR}/configuracion/stack-vibe.conf" + +# Directorio del proyecto principal +REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" + +# ============================================================================ +# FUNCIÓN: mostrar_ayuda +# ============================================================================ +mostrar_ayuda() { + cat </dev/null; then + echo "ADVERTENCIA: No se pudo verificar el punto ASGI ${ASGI_APP}" + echo "Intentando con puntos alternativos..." + + # Probar alternativas comunes + for candidato in "demo.web.app:app" "app.main:app" "main:app"; do + echo " Probando: ${candidato}" + if python -c "import sys; mod, obj = '${candidato}'.split(':'); __import__(mod); getattr(sys.modules[mod], obj)" 2>/dev/null; then + ASGI_APP="${candidato}" + echo " ✓ Punto ASGI encontrado: ${ASGI_APP}" + break + fi + done +fi + +echo "" +echo "════════════════════════════════════════════════════════════════════════" +echo "" +echo "Iniciando servidor Uvicorn..." +echo "Acceso: http://${HOST}:${PORT}" +echo "Documentación API: http://${HOST}:${PORT}/docs" +echo "" +echo "Presiona Ctrl+C para detener el servidor" +echo "" +echo "════════════════════════════════════════════════════════════════════════" +echo "" + +# ============================================================================ +# INICIAR SERVIDOR +# ============================================================================ +# shellcheck disable=SC2086 +python -m uvicorn "${ASGI_APP}" \ + --host "${HOST}" \ + --port "${PORT}" \ + --workers "${WORKERS}" \ + --limit-concurrency "${UVICORN_LIMIT_CONCURRENCY:-1}" \ + ${RELOAD_FLAG} diff --git a/demo/web/app.py b/demo/web/app.py index 887d62b..83f3064 100644 --- a/demo/web/app.py +++ b/demo/web/app.py @@ -339,7 +339,7 @@ def chunk_to_pcm16(self, chunk: np.ndarray) -> bytes: async def _startup() -> None: model_path = os.environ.get("MODEL_PATH") if not model_path: - raise RuntimeError("MODEL_PATH not set in environment") + raise RuntimeError("MODEL_PATH not set in environment. Set MODEL_PATH in /opt/vibevoice/config/.env or export MODEL_PATH before starting the service.") device = os.environ.get("MODEL_DEVICE", "cuda") @@ -483,8 +483,14 @@ async def flush_logs() -> None: log_queue.get_nowait() except Empty: break - if ws.client_state == WebSocketState.CONNECTED: - await ws.close() + try: + if ws.client_state == WebSocketState.CONNECTED: + await ws.close() + except RuntimeError: + # Ignore if a close message was already sent (race-condition) + pass + except Exception as exc: # pragma: no cover - defensive logging + print(f"Error while closing websocket: {exc}") print("WS handler exit") finally: if acquired: