CBCFacil v8.0 - Refactored with AMD GPU support

This commit is contained in:
2026-01-09 13:05:46 -03:00
parent cb17136f21
commit b017504c52
54 changed files with 7251 additions and 3670 deletions

501
ARCHITECTURE.md Normal file
View File

@@ -0,0 +1,501 @@
# Arquitectura CBCFacil v9
## Resumen Ejecutivo
CBCFacil es un servicio de IA modular para procesamiento de documentos (audio, PDF, texto) con integracion a Nextcloud. Este documento describe la arquitectura actual, patrones de diseno utilizados y guia de extension del sistema.
## Evucion Arquitectonica
### Problema Original (v7)
El proyecto sufria de un archivo monolitico de 3167 lineas (`main.py`) que contenia todas las responsabilidades en un solo archivo.
### Solucion Actual (v9)
Arquitectura modular con separacion clara de responsabilidades en capas independientes.
```
FLUJO DE DATOS
=============
1. MONITOREO 2. DESCARGA 3. PROCESAMIENTO
+---------------+ +---------------+ +---------------+
| Nextcloud |-------->| Downloads/ |------>| Processors |
| (WebDAV) | | Local | | (Audio/PDF) |
+---------------+ +---------------+ +---------------+
| |
v v
+---------------+ +---------------+
| WebDAV | | AI Services |
| Service | | (Claude/ |
+---------------+ | Gemini) |
+---------------+
|
v
4. GENERACION 5. REGISTRO 6. NOTIFICACION
+---------------+ +---------------+ +---------------+
| Document |-------->| Processed |------>| Telegram |
| Generators | | Registry | | Service |
+---------------+ +---------------+ +---------------+
| |
v v
+---------------+ +---------------+
| Nextcloud | | Dashboard |
| (Upload) | | (Flask) |
+---------------+ +---------------+
```
## Estructura de Directorios
```
cbcfacil/
├── main.py # Orquestador principal (149 lineas)
├── run.py # Script de ejecucion alternativo
├── config/ # Configuracion centralizada
│ ├── __init__.py # Exports: settings, validate_environment
│ ├── settings.py # Configuracion desde variables de entorno
│ └── validators.py # Validadores de configuracion
├── core/ # Nucleo compartido
│ ├── __init__.py # Exports: excepciones, Result
│ ├── exceptions.py # Excepciones personalizadas
│ ├── result.py # Patron Result/Error handling
│ └── base_service.py # Clase base BaseService
├── services/ # Servicios externos
│ ├── __init__.py # Exports de servicios
│ ├── webdav_service.py # WebDAV/Nextcloud operaciones
│ ├── vram_manager.py # GPU memory management
│ ├── telegram_service.py # Telegram notificaciones
│ ├── metrics_collector.py # Metricas y estadisticas
│ ├── ai_service.py # Servicio AI unificado
│ └── ai/ # AI Providers
│ ├── __init__.py
│ ├── base_provider.py # Interfaz BaseProvider
│ ├── claude_provider.py # Claude (Z.ai) implementation
│ ├── gemini_provider.py # Gemini API/CLI implementation
│ └── provider_factory.py # Factory para proveedores
├── processors/ # Procesadores de archivos
│ ├── __init__.py # Exports de procesadores
│ ├── base_processor.py # Clase base FileProcessor
│ ├── audio_processor.py # Whisper transcription
│ ├── pdf_processor.py # PDF OCR processing
│ └── text_processor.py # Text summarization
├── document/ # Generacion de documentos
│ ├── __init__.py
│ └── generators.py # DOCX/PDF/Markdown generation
├── storage/ # Persistencia y cache
│ ├── __init__.py
│ └── processed_registry.py # Registro de archivos procesados
├── api/ # API REST
│ ├── __init__.py
│ └── routes.py # Flask routes y endpoints
├── tests/ # Tests unitarios e integracion
│ ├── conftest.py # Fixtures pytest
│ ├── test_config.py # Tests de configuracion
│ ├── test_storage.py # Tests de almacenamiento
│ ├── test_webdav.py # Tests de WebDAV
│ ├── test_processors.py # Tests de procesadores
│ ├── test_ai_providers.py # Tests de AI providers
│ ├── test_vram_manager.py # Tests de VRAM manager
│ └── test_main_integration.py # Tests de integracion main
├── docs/ # Documentacion
│ ├── archive/ # Documentacion historica
│ ├── SETUP.md # Guia de configuracion
│ ├── TESTING.md # Guia de testing
│ └── DEPLOYMENT.md # Guia de despliegue
├── requirements.txt # Dependencias produccion
├── requirements-dev.txt # Dependencias desarrollo
├── .env.example # Template de configuracion
├── .env.secrets # Configuracion local (no versionar)
└── Dockerfile # Container Docker
```
## Componentes Principales
### 1. Servicios (services/)
#### WebDAVService
**Archivo**: `services/webdav_service.py`
Responsabilidades:
- Conexion y operaciones con Nextcloud via WebDAV
- Download/upload de archivos
- Listado y creacion de directorios remotos
- Manejo de errores con reintentos configurables
```python
class WebDAVService:
def initialize(self) -> None: ...
def list(self, remote_path: str) -> List[str]: ...
def download(self, remote_path: str, local_path: Path) -> None: ...
def upload(self, local_path: Path, remote_path: str) -> None: ...
def mkdir(self, remote_path: str) -> None: ...
```
#### VRAMManager
**Archivo**: `services/vram_manager.py`
Responsabilidades:
- Gestion de memoria GPU
- Carga/descarga de modelos (Whisper, OCR, TrOCR)
- Limpieza automatica de VRAM ociosa
- Fallback a CPU cuando GPU no disponible
```python
class VRAMManager:
def initialize(self) -> None: ...
def cleanup(self) -> None: ...
def should_cleanup(self) -> bool: ...
def lazy_cleanup(self) -> None: ...
```
#### TelegramService
**Archivo**: `services/telegram_service.py`
Responsabilidades:
- Envio de notificaciones a Telegram
- Throttling de errores para evitar spam
- Notificaciones de inicio/parada del servicio
```python
class TelegramService:
def configure(self, token: str, chat_id: str) -> None: ...
def send_message(self, message: str) -> None: ...
def send_error_notification(self, context: str, error: str) -> None: ...
def send_start_notification(self) -> None: ...
```
### 2. Procesadores (processors/)
#### AudioProcessor
**Archivo**: `processors/audio_processor.py`
Responsabilidades:
- Transcripcion de audio usando Whisper
- Modelo: medium (optimizado para espanol)
- Soporte GPU/CPU automatico
- Post-procesamiento de texto transcrito
#### PDFProcessor
**Archivo**: `processors/pdf_processor.py`
Responsabilidades:
- Extraccion de texto de PDFs
- OCR con EasyOCR + Tesseract + TrOCR en paralelo
- Correccion de texto con IA
- Generacion de documentos DOCX
#### TextProcessor
**Archivo**: `processors/text_processor.py`
Responsabilidades:
- Resumenes usando IA (Claude/Gemini)
- Clasificacion de contenido
- Generacion de quizzes opcionales
### 3. AI Services (services/ai/)
#### ProviderFactory
**Archivo**: `services/ai/provider_factory.py`
Patron Factory para seleccion dinamica de proveedor de IA:
```python
class ProviderFactory:
def get_provider(self, provider_type: str = "auto") -> BaseProvider: ...
```
Proveedores disponibles:
- `claude`: Claude via Z.ai API
- `gemini`: Google Gemini API
- `gemini_cli`: Gemini CLI local
- `auto`: Seleccion automatica basada en disponibilidad
### 4. Document Generation (document/)
#### DocumentGenerator
**Archivo**: `document/generators.py`
Responsabilidades:
- Creacion de documentos DOCX
- Conversion a PDF
- Formateo Markdown
- Plantillas de documentos
### 5. Storage (storage/)
#### ProcessedRegistry
**Archivo**: `storage/processed_registry.py`
Responsabilidades:
- Registro persistente de archivos procesados
- Cache en memoria con TTL
- File locking para thread-safety
```python
class ProcessedRegistry:
def initialize(self) -> None: ...
def load(self) -> Set[str]: ...
def save(self, file_path: str) -> None: ...
def is_processed(self, file_path: str) -> bool: ...
def mark_for_reprocess(self, file_path: str) -> None: ...
```
### 6. API (api/)
#### Flask Routes
**Archivo**: `api/routes.py`
Endpoints REST disponibles:
- `GET /api/files` - Listado de archivos
- `POST /api/reprocess` - Reprocesar archivo
- `POST /api/mark-unprocessed` - Resetear estado
- `GET /api/refresh` - Sincronizar con Nextcloud
- `GET /health` - Health check
## Patrones de Diseno Utilizados
### 1. Repository Pattern
```python
# storage/processed_registry.py
class ProcessedRegistry:
def save(self, file_path: str) -> None: ...
def load(self) -> Set[str]: ...
def is_processed(self, file_path: str) -> bool: ...
```
### 2. Factory Pattern
```python
# services/ai/provider_factory.py
class ProviderFactory:
def get_provider(self, provider_type: str = "auto") -> BaseProvider: ...
```
### 3. Strategy Pattern
```python
# services/vram_manager.py
class VRAMManager:
def cleanup(self) -> None: ...
def should_cleanup(self) -> bool: ...
def lazy_cleanup(self) -> None: ...
```
### 4. Service Layer Pattern
```python
# services/webdav_service.py
class WebDAVService:
def list(self, remote_path: str) -> List[str]: ...
def download(self, remote_path: str, local_path: Path) -> None: ...
def upload(self, local_path: Path, remote_path: str) -> None: ...
```
### 5. Singleton Pattern
Servicios implementados como singletons para compartir estado:
```python
# services/webdav_service.py
webdav_service = WebDAVService()
# services/vram_manager.py
vram_manager = VRAMManager()
```
### 6. Result Pattern
```python
# core/result.py
class Result:
@staticmethod
def success(value): ...
@staticmethod
def failure(error): ...
```
## Decisiones Arquitectonicas (ADR)
### ADR-001: Arquitectura Modular
**Decision**: Separar el monolito en modulos independientes.
**Contexto**: El archivo main.py de 3167 lineas era dificil de mantener y testar.
**Decision**: Separar en capas: config/, core/, services/, processors/, document/, storage/, api/.
**Consecuencias**:
- Positivo: Codigo mas mantenible y testeable
- Positivo: Reutilizacion de componentes
- Negativo: Mayor complejidad inicial
### ADR-002: Configuracion Centralizada
**Decision**: Usar clase Settings con variables de entorno.
**Contexto**: Credenciales hardcodeadas representan riesgo de seguridad.
**Decision**: Todas las configuraciones via variables de entorno con .env.secrets.
**Consecuencias**:
- Positivo: Seguridad mejorada
- Positivo: Facil despliegue en diferentes entornos
- Negativo: Requiere documentacion de variables
### ADR-003: GPU-First con CPU Fallback
**Decision**: Optimizar para GPU pero soportar CPU.
**Contexto**: No todos los usuarios tienen GPU disponible.
**Decision**: VRAMManager con lazy loading y cleanup automatico.
**Consecuencias**:
- Positivo: Performance optimo en GPU
- Positivo: Funciona sin GPU
- Negativo: Complejidad adicional en gestion de memoria
### ADR-004: Factory para AI Providers
**Decision**: Abstraer proveedores de IA detras de interfaz comun.
**Contexto**: Multiples proveedores (Claude, Gemini) con diferentes APIs.
**Decision**: BaseProvider con implementaciones concretas y ProviderFactory.
**Consecuencias**:
- Positivo: Facilidad para agregar nuevos proveedores
- Positivo: Fallback entre proveedores
- Negativo: Sobrecarga de abstraccion
## Guia de Extension del Sistema
### Agregar Nuevo Procesador
1. Crear archivo en `processors/`:
```python
from processors.base_processor import FileProcessor
class NuevoProcessor(FileProcessor):
def process(self, file_path: str) -> None:
# Implementar procesamiento
pass
```
2. Registrar en `processors/__init__.py`:
```python
from processors.nuevo_processor import NuevoProcessor
__all__ = ['NuevoProcessor', ...]
```
3. Integrar en `main.py`:
```python
from processors.nuevo_processor import NuevoProcessor
nuevo_processor = NuevoProcessor()
```
### Agregar Nuevo AI Provider
1. Crear clase en `services/ai/`:
```python
from services.ai.base_provider import BaseProvider
class NuevoProvider(BaseProvider):
def summarize(self, text: str) -> str:
# Implementar
pass
```
2. Registrar en `provider_factory.py`:
```python
PROVIDERS = {
'nuevo': NuevoProvider,
...
}
```
3. Usar:
```python
provider = factory.get_provider('nuevo')
```
### Agregar Nuevo Servicio
1. Crear archivo en `services/`:
```python
from core.base_service import BaseService
class NuevoService(BaseService):
def initialize(self) -> None:
pass
nuevo_service = NuevoService()
```
2. Inicializar en `main.py`:
```python
from services.nuevo_service import nuevo_service
nuevo_service.initialize()
```
### Agregar Nuevo Endpoint API
1. Editar `api/routes.py`:
```python
@app.route('/api/nuevo', methods=['GET'])
def nuevo_endpoint():
return {'status': 'ok'}, 200
```
## Configuracion Detallada
### Variables de Entorno Principales
| Variable | Requerido | Default | Descripcion |
|----------|-----------|---------|-------------|
| NEXTCLOUD_URL | Si | - | URL de Nextcloud WebDAV |
| NEXTCLOUD_USER | Si | - | Usuario Nextcloud |
| NEXTCLOUD_PASSWORD | Si | - | Contrasena Nextcloud |
| ANTHROPIC_AUTH_TOKEN | No | - | Token Claude/Z.ai |
| GEMINI_API_KEY | No | - | API Key Gemini |
| TELEGRAM_TOKEN | No | - | Token Bot Telegram |
| TELEGRAM_CHAT_ID | No | - | Chat ID Telegram |
| CUDA_VISIBLE_DEVICES | No | "all" | GPU a usar |
| POLL_INTERVAL | No | 5 | Segundos entre polls |
| LOG_LEVEL | No | "INFO" | Nivel de logging |
## Metricas y Benchmarks
| Metrica | Valor |
|---------|-------|
| Lineas main.py | 149 (antes 3167) |
| Modulos independientes | 8+ |
| Cobertura tests | ~60%+ |
| Tiempo inicio | 5-10s |
| Transcripcion Whisper | ~1x tiempo audio (GPU) |
| OCR PDF | 0.5-2s/pagina |
## Beneficios de la Arquitectura
1. **Mantenibilidad**: Cada responsabilidad en su propio modulo
2. **Testabilidad**: Servicios independientes y testeables
3. **Escalabilidad**: Facil agregar nuevos procesadores/servicios
4. **Reutilizacion**: Componentes desacoplados
5. **Legibilidad**: Codigo organizado y documentado
6. **Seguridad**: Configuracion centralizada sin hardcoding
## Licencia
MIT License - Ver LICENSE para detalles.