15 KiB
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
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
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
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:
class ProviderFactory:
def get_provider(self, provider_type: str = "auto") -> BaseProvider: ...
Proveedores disponibles:
claude: Claude via Z.ai APIgemini: Google Gemini APIgemini_cli: Gemini CLI localauto: 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
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 archivosPOST /api/reprocess- Reprocesar archivoPOST /api/mark-unprocessed- Resetear estadoGET /api/refresh- Sincronizar con NextcloudGET /health- Health check
Patrones de Diseno Utilizados
1. Repository Pattern
# 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
# services/ai/provider_factory.py
class ProviderFactory:
def get_provider(self, provider_type: str = "auto") -> BaseProvider: ...
3. Strategy Pattern
# services/vram_manager.py
class VRAMManager:
def cleanup(self) -> None: ...
def should_cleanup(self) -> bool: ...
def lazy_cleanup(self) -> None: ...
4. Service Layer Pattern
# 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:
# services/webdav_service.py
webdav_service = WebDAVService()
# services/vram_manager.py
vram_manager = VRAMManager()
6. Result Pattern
# 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
- Crear archivo en
processors/:
from processors.base_processor import FileProcessor
class NuevoProcessor(FileProcessor):
def process(self, file_path: str) -> None:
# Implementar procesamiento
pass
- Registrar en
processors/__init__.py:
from processors.nuevo_processor import NuevoProcessor
__all__ = ['NuevoProcessor', ...]
- Integrar en
main.py:
from processors.nuevo_processor import NuevoProcessor
nuevo_processor = NuevoProcessor()
Agregar Nuevo AI Provider
- Crear clase en
services/ai/:
from services.ai.base_provider import BaseProvider
class NuevoProvider(BaseProvider):
def summarize(self, text: str) -> str:
# Implementar
pass
- Registrar en
provider_factory.py:
PROVIDERS = {
'nuevo': NuevoProvider,
...
}
- Usar:
provider = factory.get_provider('nuevo')
Agregar Nuevo Servicio
- Crear archivo en
services/:
from core.base_service import BaseService
class NuevoService(BaseService):
def initialize(self) -> None:
pass
nuevo_service = NuevoService()
- Inicializar en
main.py:
from services.nuevo_service import nuevo_service
nuevo_service.initialize()
Agregar Nuevo Endpoint API
- Editar
api/routes.py:
@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
- Mantenibilidad: Cada responsabilidad en su propio modulo
- Testabilidad: Servicios independientes y testeables
- Escalabilidad: Facil agregar nuevos procesadores/servicios
- Reutilizacion: Componentes desacoplados
- Legibilidad: Codigo organizado y documentado
- Seguridad: Configuracion centralizada sin hardcoding
Licencia
MIT License - Ver LICENSE para detalles.