Compare commits
2 Commits
4b451aa7a6
...
8acbe84b15
| Author | SHA1 | Date | |
|---|---|---|---|
| 8acbe84b15 | |||
| 4e9e3c4159 |
747
CLAUDE.md
747
CLAUDE.md
@@ -1,747 +0,0 @@
|
||||
# CLAUDE.md - TranscriptorIO
|
||||
|
||||
## ¿Qué es TranscriptorIO?
|
||||
|
||||
TranscriptorIO es un sistema completo de generación automática de subtítulos para contenido multimedia usando IA (Whisper + modelos de traducción). Es un **hard fork** de [SubGen](https://github.com/McCloudS/subgen) con una arquitectura completamente rediseñada inspirada en Tdarr.
|
||||
|
||||
## Motivación
|
||||
|
||||
SubGen es funcional pero tiene limitaciones fundamentales de diseño:
|
||||
|
||||
### Problemas de SubGen
|
||||
- **Procesamiento síncrono**: Bloquea threads mientras transcribe
|
||||
- **Sin cola persistente**: Los trabajos se pierden al reiniciar
|
||||
- **Sin WebUI**: Removida en marzo 2024, solo tiene Swagger docs
|
||||
- **Sin visibilidad**: No sabes progreso, ETA, o estado de trabajos
|
||||
- **Sin priorización**: No puedes reordenar trabajos
|
||||
- **Timeouts en Bazarr**: Si un episodio tarda >5min, throttle de 24 horas
|
||||
- **Configuración compleja**: 40+ variables ENV sin validación
|
||||
|
||||
### Visión de TranscriptorIO
|
||||
|
||||
Un sistema tipo **Tdarr pero para subtítulos**, con:
|
||||
- ✅ Sistema de cola asíncrona persistente (SQLite)
|
||||
- ✅ Workers configurables (múltiples GPUs/CPUs)
|
||||
- ✅ WebUI moderna con progreso en tiempo real
|
||||
- ✅ Múltiples pipelines de calidad (Fast/Balanced/Best)
|
||||
- ✅ Integración asíncrona con Bazarr
|
||||
- ✅ Procesamiento batch (temporadas completas)
|
||||
- ✅ API REST completa
|
||||
- ✅ WebSocket para updates en vivo
|
||||
|
||||
## Casos de uso
|
||||
|
||||
### Caso principal: Anime japonés → Subtítulos español
|
||||
|
||||
**Problema**: Anime sin fansubs en español, solo tiene audio japonés.
|
||||
|
||||
**Pipeline**:
|
||||
```
|
||||
Audio japonés
|
||||
↓
|
||||
Whisper (task="translate") → Texto inglés
|
||||
↓
|
||||
Helsinki-NLP (en→es) → Texto español
|
||||
↓
|
||||
Generar .srt con timestamps
|
||||
```
|
||||
|
||||
**Alternativas configurables**:
|
||||
- **Fast** (4GB VRAM): ja→en→es con Helsinki-NLP
|
||||
- **Balanced** (6GB VRAM): ja→ja→es con M2M100
|
||||
- **Best** (10GB+ VRAM): ja→es directo con SeamlessM4T
|
||||
|
||||
### Integración con stack existente
|
||||
```
|
||||
Sonarr descarga episodio
|
||||
↓
|
||||
Bazarr detecta: faltan subtítulos español
|
||||
↓
|
||||
Bazarr → TranscriptorIO (provider asíncrono)
|
||||
↓
|
||||
TranscriptorIO encola trabajo
|
||||
↓
|
||||
Worker procesa cuando está libre
|
||||
↓
|
||||
Callback a Bazarr con .srt generado
|
||||
↓
|
||||
Jellyfin detecta nuevo subtítulo
|
||||
```
|
||||
|
||||
## Modos de Operación
|
||||
|
||||
TranscriptorIO soporta dos modos de operación distintos que se configuran vía environment variables:
|
||||
|
||||
### Modo Standalone (Tdarr-like)
|
||||
|
||||
**Descripción**: TranscriptorIO escanea automáticamente tu biblioteca de medios y genera subtítulos según reglas configurables.
|
||||
|
||||
**Casos de uso**:
|
||||
- Procesamiento batch de biblioteca existente
|
||||
- Monitoreo automático de nuevos archivos
|
||||
- Control total sobre qué se transcribe sin depender de Bazarr
|
||||
|
||||
**Funcionamiento**:
|
||||
```
|
||||
1. Escaneo periódico con ffprobe
|
||||
└─> Detecta archivos que cumplen criterios
|
||||
(Ej: audio japonés + sin subs español)
|
||||
|
||||
2. Encolado automático
|
||||
└─> Añade a cola con prioridad configurada
|
||||
|
||||
3. Procesamiento batch
|
||||
└─> Workers procesan según disponibilidad
|
||||
|
||||
4. Escritura directa
|
||||
└─> Guarda .srt junto al archivo origen
|
||||
```
|
||||
|
||||
**Configuración**:
|
||||
```env
|
||||
# Habilitar modo standalone
|
||||
TRANSCRIPTARR_MODE=standalone
|
||||
|
||||
# Carpetas a escanear (separadas por |)
|
||||
LIBRARY_PATHS=/media/anime|/media/movies
|
||||
|
||||
# Reglas de filtrado
|
||||
REQUIRED_AUDIO_LANGUAGE=ja
|
||||
REQUIRED_MISSING_SUBTITLE=spa
|
||||
SKIP_IF_SUBTITLE_EXISTS=true
|
||||
|
||||
# Escaneo automático
|
||||
AUTO_SCAN_ENABLED=true
|
||||
SCAN_INTERVAL_MINUTES=30
|
||||
```
|
||||
|
||||
**Ventajas**:
|
||||
- ✅ No depende de integraciones externas
|
||||
- ✅ Procesamiento batch eficiente
|
||||
- ✅ Monitoreo automático de nueva media
|
||||
- ✅ Control granular con reglas de filtrado
|
||||
|
||||
### Modo Provider (Bazarr-slave)
|
||||
|
||||
**Descripción**: TranscriptorIO actúa como provider de subtítulos para Bazarr mediante una API asíncrona mejorada.
|
||||
|
||||
**Casos de uso**:
|
||||
- Integración con stack *arr existente
|
||||
- Gestión centralizada de subtítulos en Bazarr
|
||||
- Fallback cuando no hay subtítulos pre-hechos
|
||||
|
||||
**Funcionamiento**:
|
||||
```
|
||||
1. Bazarr solicita subtítulo (API call)
|
||||
└─> POST /api/provider/request
|
||||
|
||||
2. TranscriptorIO encola trabajo
|
||||
└─> Retorna job_id inmediatamente
|
||||
└─> No bloquea thread de Bazarr
|
||||
|
||||
3. Procesamiento asíncrono
|
||||
└─> Worker transcribe cuando hay capacidad
|
||||
|
||||
4. Callback a Bazarr
|
||||
└─> POST {bazarr_callback_url} con .srt
|
||||
└─> O polling de Bazarr cada 30s
|
||||
```
|
||||
|
||||
**Configuración**:
|
||||
```env
|
||||
# Habilitar modo provider
|
||||
TRANSCRIPTARR_MODE=provider
|
||||
|
||||
# API de Bazarr para callbacks
|
||||
BAZARR_URL=http://bazarr:6767
|
||||
BAZARR_API_KEY=your_api_key_here
|
||||
|
||||
# Configuración del provider
|
||||
PROVIDER_TIMEOUT_SECONDS=600
|
||||
PROVIDER_CALLBACK_ENABLED=true
|
||||
PROVIDER_POLLING_INTERVAL=30
|
||||
```
|
||||
|
||||
**Ventajas vs SubGen original**:
|
||||
- ✅ **No bloquea**: Retorna inmediatamente con job_id
|
||||
- ✅ **Sin timeouts**: Bazarr no throttle por trabajos lentos
|
||||
- ✅ **Visibilidad**: Bazarr puede consultar progreso
|
||||
- ✅ **Reintentos**: Manejo automático de errores
|
||||
- ✅ **Priorización**: Trabajos manuales tienen mayor prioridad
|
||||
|
||||
### Modo Híbrido (Recomendado)
|
||||
|
||||
Puedes habilitar ambos modos simultáneamente:
|
||||
|
||||
```env
|
||||
TRANSCRIPTARR_MODE=standalone,provider
|
||||
```
|
||||
|
||||
**Beneficios**:
|
||||
- Bazarr maneja media nueva automáticamente
|
||||
- Standalone procesa biblioteca existente
|
||||
- Cola unificada con priorización inteligente
|
||||
- Mejor aprovechamiento de recursos
|
||||
|
||||
## Arquitectura técnica
|
||||
|
||||
### Stack tecnológico
|
||||
|
||||
**Backend**:
|
||||
- FastAPI (API REST + WebSocket)
|
||||
- SQLAlchemy (ORM multi-backend)
|
||||
- SQLite / PostgreSQL / MariaDB (queue persistente)
|
||||
- faster-whisper (transcripción optimizada)
|
||||
- Helsinki-NLP/opus-mt-en-es (traducción ligera)
|
||||
- stable-ts (mejora de timestamps)
|
||||
|
||||
**Frontend**:
|
||||
- Vue 3 + Vite
|
||||
- Tailwind CSS
|
||||
- Chart.js (estadísticas)
|
||||
- Socket.io-client (updates en tiempo real)
|
||||
|
||||
**Infraestructura**:
|
||||
- Docker + Docker Compose
|
||||
- NVIDIA GPU support (opcional, también CPU)
|
||||
- Multi-container: backend + workers + frontend
|
||||
|
||||
### Componentes principales
|
||||
```
|
||||
transcriptorio/
|
||||
├── backend/
|
||||
│ ├── core/
|
||||
│ │ ├── pipelines/
|
||||
│ │ │ ├── whisper_fast.py # ja→en→es (Helsinki)
|
||||
│ │ │ ├── whisper_balanced.py # ja→ja→es (M2M100)
|
||||
│ │ │ └── seamless.py # ja→es directo
|
||||
│ │ ├── queue_manager.py # Cola SQLite
|
||||
│ │ ├── worker_pool.py # Gestión de workers
|
||||
│ │ └── transcriber.py # Core Whisper
|
||||
│ ├── api/
|
||||
│ │ ├── legacy.py # /asr (compat SubGen/Bazarr)
|
||||
│ │ ├── queue.py # /api/queue/*
|
||||
│ │ ├── jobs.py # /api/jobs/*
|
||||
│ │ └── websocket.py # /ws (real-time)
|
||||
│ └── main.py
|
||||
├── frontend/
|
||||
│ ├── src/
|
||||
│ │ ├── components/
|
||||
│ │ │ ├── Dashboard.vue # Stats + current job
|
||||
│ │ │ ├── QueueManager.vue # Lista de trabajos
|
||||
│ │ │ ├── JobDetails.vue # Detalles + logs
|
||||
│ │ │ └── Settings.vue # Configuración
|
||||
│ │ ├── App.vue
|
||||
│ │ └── main.js
|
||||
│ └── package.json
|
||||
├── bazarr-integration/
|
||||
│ └── transcriptorio_provider.py # Custom provider asíncrono
|
||||
└── docker-compose.yml
|
||||
```
|
||||
|
||||
### Base de datos (SQLite)
|
||||
```sql
|
||||
CREATE TABLE jobs (
|
||||
id TEXT PRIMARY KEY,
|
||||
file_path TEXT NOT NULL,
|
||||
file_name TEXT NOT NULL,
|
||||
status TEXT DEFAULT 'queued', -- queued, processing, completed, failed
|
||||
priority INTEGER DEFAULT 0,
|
||||
|
||||
-- Config
|
||||
source_lang TEXT,
|
||||
target_lang TEXT,
|
||||
quality_preset TEXT DEFAULT 'fast',
|
||||
|
||||
-- Progress
|
||||
progress REAL DEFAULT 0,
|
||||
current_stage TEXT, -- transcribing, translating, generating
|
||||
eta_seconds INTEGER,
|
||||
|
||||
-- Timestamps
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
started_at TIMESTAMP,
|
||||
completed_at TIMESTAMP,
|
||||
|
||||
-- Results
|
||||
output_path TEXT,
|
||||
srt_content TEXT,
|
||||
segments_count INTEGER,
|
||||
|
||||
-- Error handling
|
||||
error TEXT,
|
||||
retry_count INTEGER DEFAULT 0,
|
||||
|
||||
-- Metadata
|
||||
worker_id TEXT,
|
||||
vram_used_mb INTEGER,
|
||||
processing_time_seconds REAL
|
||||
);
|
||||
|
||||
CREATE INDEX idx_status ON jobs(status);
|
||||
CREATE INDEX idx_priority ON jobs(priority DESC, created_at ASC);
|
||||
CREATE INDEX idx_created ON jobs(created_at DESC);
|
||||
```
|
||||
|
||||
### API Endpoints
|
||||
|
||||
#### Legacy (compatibilidad SubGen/Bazarr)
|
||||
```http
|
||||
POST /asr?task=translate&language=ja&output=srt
|
||||
Content-Type: multipart/form-data
|
||||
|
||||
→ Respuesta síncrona con .srt
|
||||
```
|
||||
|
||||
#### Modernos (TranscriptorIO)
|
||||
```http
|
||||
# Añadir trabajo a cola
|
||||
POST /api/queue/add
|
||||
{
|
||||
"files": ["/media/anime/episode.mkv"],
|
||||
"source_lang": "ja",
|
||||
"target_lang": "es",
|
||||
"quality_preset": "fast",
|
||||
"priority": 0
|
||||
}
|
||||
→ { "job_ids": ["uuid-1234"], "queued": 1 }
|
||||
|
||||
# Estado de la cola
|
||||
GET /api/queue/status
|
||||
→ {
|
||||
"pending": 3,
|
||||
"processing": 1,
|
||||
"completed_today": 12,
|
||||
"failed_today": 0,
|
||||
"vram_available": "1.5GB/4GB"
|
||||
}
|
||||
|
||||
# Detalles de trabajo
|
||||
GET /api/jobs/{job_id}
|
||||
→ {
|
||||
"id": "uuid-1234",
|
||||
"status": "processing",
|
||||
"progress": 45.2,
|
||||
"current_stage": "translating",
|
||||
"eta_seconds": 120,
|
||||
"file_name": "anime_ep01.mkv"
|
||||
}
|
||||
|
||||
# Historial
|
||||
GET /api/jobs/history?limit=50
|
||||
→ [ { job }, { job }, ... ]
|
||||
|
||||
# WebSocket updates
|
||||
WS /ws
|
||||
→ Stream continuo de updates
|
||||
```
|
||||
|
||||
### WebUI
|
||||
|
||||
#### Dashboard
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ TranscriptorIO 🟢 │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 📊 Stats │
|
||||
│ ┌─────────┬──────────┬──────────┬─────────────────┐ │
|
||||
│ │ Queue: 3│Processing│Completed │ VRAM: 2.8/4.0GB │ │
|
||||
│ │ │ 1 │ Today │ │ │
|
||||
│ │ │ │ 12 │ │ │
|
||||
│ └─────────┴──────────┴──────────┴─────────────────┘ │
|
||||
│ │
|
||||
│ 🎬 Current Job │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ File: Anime_S01E05.mkv │ │
|
||||
│ │ Stage: Translating segments │ │
|
||||
│ │ Progress: ████████████░░░░░░ 65% │ │
|
||||
│ │ ETA: 2m 15s │ │
|
||||
│ │ Model: whisper-medium + helsinki-nlp │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ 📋 Queue (3 pending) │
|
||||
│ ┌──┬─────────────────────┬────────┬──────────────┐ │
|
||||
│ │#1│Anime_S01E06.mkv │ Fast │ Priority: 0 │ │
|
||||
│ │#2│Movie_2024.mkv │ Best │ Priority: 0 │ │
|
||||
│ │#3│Show_S02E01.mkv │ Fast │ Priority: -1 │ │
|
||||
│ └──┴─────────────────────┴────────┴──────────────┘ │
|
||||
│ │
|
||||
│ [+ Add Files] [⚙️ Settings] [📊 Stats] [📖 Logs] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### Settings
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Settings │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 🎯 Default Quality Preset │
|
||||
│ ○ Fast (4GB VRAM, ~3min/episode) │
|
||||
│ Whisper medium + Helsinki-NLP │
|
||||
│ Best for: GTX 1650, RTX 3050 │
|
||||
│ │
|
||||
│ ● Balanced (6GB VRAM, ~5min/episode) │
|
||||
│ Whisper medium + M2M100 │
|
||||
│ Best for: RTX 3060, RTX 4060 │
|
||||
│ │
|
||||
│ ○ Best (10GB+ VRAM, ~10min/episode) │
|
||||
│ SeamlessM4T direct translation │
|
||||
│ Best for: RTX 4070+, professional GPUs │
|
||||
│ │
|
||||
│ ⚡ Workers Configuration │
|
||||
│ GPU Workers: [2] ▾ │
|
||||
│ CPU Workers: [1] ▾ │
|
||||
│ Concurrent jobs per worker: [1] ▾ │
|
||||
│ │
|
||||
│ 🌐 Default Languages │
|
||||
│ Source: [Japanese ▾] Target: [Spanish ▾] │
|
||||
│ │
|
||||
│ 📁 Paths │
|
||||
│ Watch folders: /media/anime │
|
||||
│ /media/movies │
|
||||
│ Output format: {filename}.{lang}.srt │
|
||||
│ │
|
||||
│ 🔔 Notifications │
|
||||
│ ☑ Discord webhook on completion │
|
||||
│ ☑ Email on failure │
|
||||
│ │
|
||||
│ [Save Changes] [Reset Defaults] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Pipeline de transcripción detallado
|
||||
|
||||
### Flujo Fast Preset (ja→en→es)
|
||||
```python
|
||||
# 1. Extracción de audio (si es video)
|
||||
ffprobe detecta pistas de audio
|
||||
→ Selecciona pista japonesa
|
||||
→ Extrae con ffmpeg (opcional, Whisper acepta video directo)
|
||||
|
||||
# 2. Whisper transcripción
|
||||
WhisperModel("medium", compute_type="int8")
|
||||
→ transcribe(audio, language="ja", task="translate")
|
||||
→ Output: Segmentos con timestamps en INGLÉS
|
||||
|
||||
Ejemplo:
|
||||
[0.00s -> 3.50s] "Hello, welcome to today's episode"
|
||||
[3.50s -> 7.80s] "We're going to see something interesting"
|
||||
|
||||
# 3. Traducción en→es (batch)
|
||||
Helsinki-NLP/opus-mt-en-es
|
||||
→ Batch de 32 segmentos a la vez
|
||||
→ Mantiene timestamps originales
|
||||
|
||||
Ejemplo:
|
||||
[0.00s -> 3.50s] "Hola, bienvenido al episodio de hoy"
|
||||
[3.50s -> 7.80s] "Vamos a ver algo interesante"
|
||||
|
||||
# 4. Generación SRT
|
||||
Formato timestamps + texto
|
||||
→ Guarda archivo.es.srt
|
||||
|
||||
# 5. Post-processing (opcional)
|
||||
- Aeneas re-sync (ajuste fino de timestamps)
|
||||
- Subtitle styling (ASS format)
|
||||
- Quality check (detección de errores)
|
||||
```
|
||||
|
||||
### Uso de VRAM esperado
|
||||
|
||||
**GTX 1650 (4GB VRAM)**:
|
||||
```
|
||||
Fast preset:
|
||||
- Whisper medium INT8: ~2.5GB
|
||||
- Helsinki-NLP: ~1GB
|
||||
- Overhead sistema: ~0.5GB
|
||||
Total: ~4GB ✅ Cabe perfecto
|
||||
Tiempo: ~3-5 min por episodio 24min
|
||||
```
|
||||
|
||||
**RTX 3060 (12GB VRAM)**:
|
||||
```
|
||||
Balanced preset:
|
||||
- Whisper large-v3 INT8: ~5GB
|
||||
- M2M100: ~2GB
|
||||
- Overhead: ~1GB
|
||||
Total: ~8GB ✅ Sobra espacio
|
||||
Tiempo: ~4-7 min por episodio 24min
|
||||
```
|
||||
|
||||
## Integración con Bazarr
|
||||
|
||||
### Custom Provider (asíncrono)
|
||||
```python
|
||||
# bazarr/libs/subliminal_patch/providers/transcriptorio.py
|
||||
|
||||
class TranscriptorIOProvider(Provider):
|
||||
"""
|
||||
Provider asíncrono para TranscriptorIO
|
||||
A diferencia del provider Whisper original, NO bloquea
|
||||
"""
|
||||
|
||||
provider_name = 'transcriptorio'
|
||||
|
||||
def download_subtitle(self, subtitle):
|
||||
# Si es búsqueda automática → async (no bloquea)
|
||||
if not subtitle.manual_search:
|
||||
job_id = self._queue_job(subtitle)
|
||||
raise SubtitlePending(
|
||||
job_id=job_id,
|
||||
eta=self._estimate_time(subtitle)
|
||||
)
|
||||
|
||||
# Si es búsqueda manual → sync con long polling
|
||||
return self._process_sync(subtitle, timeout=600)
|
||||
|
||||
def _queue_job(self, subtitle):
|
||||
"""Encola trabajo sin esperar"""
|
||||
response = requests.post(
|
||||
f"{self.endpoint}/api/queue/add",
|
||||
json={
|
||||
"file": subtitle.video.name,
|
||||
"source_lang": "ja",
|
||||
"target_lang": "es",
|
||||
"quality_preset": self.quality_preset,
|
||||
"callback_url": self._get_callback_url(subtitle.id)
|
||||
},
|
||||
headers={"X-API-Key": self.api_key}
|
||||
)
|
||||
return response.json()["job_ids"][0]
|
||||
|
||||
# Background task en Bazarr (cada 30s)
|
||||
@scheduler.scheduled_job('interval', seconds=30)
|
||||
def poll_transcriptorio_jobs():
|
||||
"""Revisar trabajos completados"""
|
||||
pending = db.get_pending_transcriptorio_jobs()
|
||||
|
||||
for job in pending:
|
||||
status = get_job_status(job.provider_job_id)
|
||||
|
||||
if status['status'] == 'completed':
|
||||
save_subtitle(job.subtitle_id, status['srt_content'])
|
||||
db.mark_completed(job.id)
|
||||
```
|
||||
|
||||
### Ventajas vs provider Whisper original
|
||||
|
||||
| Feature | Whisper (original) | TranscriptorIO |
|
||||
|---------|-------------------|----------------|
|
||||
| Bloquea thread Bazarr | ✅ Sí (3-10min) | ❌ No (async) |
|
||||
| Timeout 24h si tarda | ✅ Sí | ❌ No |
|
||||
| Cola visible | ❌ No | ✅ Sí (WebUI) |
|
||||
| Retry automático | ❌ No | ✅ Sí |
|
||||
| Priorización | ❌ No | ✅ Sí |
|
||||
| Múltiples GPUs | ❌ No | ✅ Sí |
|
||||
| WebUI | ❌ No | ✅ Sí |
|
||||
|
||||
## Roadmap de desarrollo
|
||||
|
||||
### Fase 1: MVP Backend (2-3 semanas)
|
||||
|
||||
**Objetivos**:
|
||||
- [ ] Queue manager con SQLite
|
||||
- [ ] Worker pool básico
|
||||
- [ ] Pipeline Fast (Whisper + Helsinki-NLP)
|
||||
- [ ] API REST completa
|
||||
- [ ] Endpoint legacy `/asr` compatible
|
||||
|
||||
**Entregables**:
|
||||
- Backend funcional headless
|
||||
- Docker Compose para testing
|
||||
- Documentación API
|
||||
|
||||
### Fase 2: WebUI (2-3 semanas)
|
||||
|
||||
**Objetivos**:
|
||||
- [ ] Dashboard con stats
|
||||
- [ ] Queue viewer con drag&drop
|
||||
- [ ] Job details con logs
|
||||
- [ ] Settings page
|
||||
- [ ] WebSocket integration
|
||||
|
||||
**Entregables**:
|
||||
- WebUI completa y funcional
|
||||
- Mobile responsive
|
||||
- Tema dark/light
|
||||
|
||||
### Fase 3: Bazarr Integration (1-2 semanas)
|
||||
|
||||
**Objetivos**:
|
||||
- [ ] Custom provider asíncrono
|
||||
- [ ] Background polling task
|
||||
- [ ] Callback webhook support
|
||||
- [ ] Testing con Bazarr real
|
||||
|
||||
**Entregables**:
|
||||
- Provider plugin para Bazarr
|
||||
- Documentación integración
|
||||
- PR al repo de Bazarr (si aceptan)
|
||||
|
||||
### Fase 4: Features Avanzados (3-4 semanas)
|
||||
|
||||
**Objetivos**:
|
||||
- [ ] Pipeline Balanced (M2M100)
|
||||
- [ ] Pipeline Best (SeamlessM4T)
|
||||
- [ ] Batch operations (temporadas)
|
||||
- [ ] Scanner automático (inotify)
|
||||
- [ ] Post-processing (Aeneas sync)
|
||||
- [ ] Notificaciones (Discord, email)
|
||||
|
||||
**Entregables**:
|
||||
- Sistema completo production-ready
|
||||
- Docs completas
|
||||
- Tests automatizados
|
||||
|
||||
### Fase 5: Release & Community (ongoing)
|
||||
|
||||
**Objetivos**:
|
||||
- [ ] Docker Hub releases
|
||||
- [ ] GitHub Actions CI/CD
|
||||
- [ ] Documentación completa
|
||||
- [ ] Video tutoriales
|
||||
- [ ] Anuncio en comunidades
|
||||
|
||||
**Canales**:
|
||||
- /r/selfhosted
|
||||
- /r/homelab
|
||||
- Discord de Bazarr
|
||||
- LinuxServer.io
|
||||
|
||||
## Métricas de éxito
|
||||
|
||||
**Técnicas**:
|
||||
- ✅ Procesa episodio 24min en <5min (GTX 1650)
|
||||
- ✅ Uso VRAM <4GB total
|
||||
- ✅ Queue persiste entre reinicios
|
||||
- ✅ API response time <100ms
|
||||
- ✅ WebUI load time <2s
|
||||
|
||||
**UX**:
|
||||
- ✅ Setup en <15min para usuario promedio
|
||||
- ✅ Zero-config con defaults razonables
|
||||
- ✅ WebUI intuitiva (no necesita docs)
|
||||
|
||||
**Comunidad**:
|
||||
- 🎯 100 stars en primer mes
|
||||
- 🎯 500 stars en 6 meses
|
||||
- 🎯 10+ contributors
|
||||
- 🎯 Featured en LinuxServer.io
|
||||
|
||||
## Diferenciadores clave
|
||||
|
||||
### vs SubGen
|
||||
- ✅ WebUI moderna vs ❌ Sin UI
|
||||
- ✅ Cola asíncrona vs ❌ Queue simple
|
||||
- ✅ Múltiples presets vs ❌ Config manual
|
||||
- ✅ Worker pool vs ❌ Single process
|
||||
|
||||
### vs Tdarr
|
||||
- ✅ Específico para subtítulos vs 🔧 General transcoding
|
||||
- ✅ Integración Bazarr nativa vs ⚠️ Solo webhooks
|
||||
- ✅ Traducción multilingüe vs ❌ No traduce
|
||||
|
||||
### vs Whisper-ASR-Webservice
|
||||
- ✅ Cola persistente vs ❌ Stateless
|
||||
- ✅ WebUI vs ❌ Solo API
|
||||
- ✅ Múltiples pipelines vs ⚠️ Solo Whisper
|
||||
|
||||
## Consideraciones técnicas
|
||||
|
||||
### Limitaciones conocidas
|
||||
|
||||
**Whisper**:
|
||||
- Solo traduce a inglés (limitación del modelo)
|
||||
- Necesita audio limpio (música de fondo degrada calidad)
|
||||
- Nombres propios se traducen mal
|
||||
- Honoríficos japoneses se pierden
|
||||
|
||||
**Traducción**:
|
||||
- Helsinki-NLP a veces muy literal
|
||||
- Expresiones idiomáticas se pierden
|
||||
- Sin contexto entre segmentos
|
||||
|
||||
**Hardware**:
|
||||
- GPU mínima: GTX 1050 Ti (4GB VRAM)
|
||||
- Recomendada: RTX 3060 (12GB VRAM)
|
||||
- CPU funciona pero 10x más lento
|
||||
|
||||
### Mitigaciones
|
||||
|
||||
**Mejorar calidad**:
|
||||
- Usar Balanced/Best presets si hay VRAM
|
||||
- Post-processing con Aeneas para mejor sync
|
||||
- Manual review de nombres propios
|
||||
- Context prompting en Whisper
|
||||
|
||||
**Optimizar velocidad**:
|
||||
- Batch translation (32 segments)
|
||||
- Cache de modelos en VRAM
|
||||
- Pipeline paralelo (transcribe + traduce simultáneo)
|
||||
|
||||
## Stack de desarrollo
|
||||
|
||||
### Backend
|
||||
```
|
||||
Python 3.11+
|
||||
FastAPI 0.100+
|
||||
SQLite 3.40+
|
||||
faster-whisper 1.0+
|
||||
transformers 4.35+
|
||||
torch 2.1+ (CUDA 12.x)
|
||||
```
|
||||
|
||||
### Frontend
|
||||
```
|
||||
Node 20+
|
||||
Vue 3.4+
|
||||
Vite 5+
|
||||
Tailwind CSS 3.4+
|
||||
Socket.io-client 4.7+
|
||||
Chart.js 4.4+
|
||||
```
|
||||
|
||||
### DevOps
|
||||
```
|
||||
Docker 24+
|
||||
Docker Compose 2.20+
|
||||
GitHub Actions
|
||||
Docker Hub
|
||||
```
|
||||
|
||||
## Licencia
|
||||
|
||||
**Apache 2.0** (misma que SubGen)
|
||||
|
||||
Permite:
|
||||
- ✅ Uso comercial
|
||||
- ✅ Modificación
|
||||
- ✅ Distribución
|
||||
- ✅ Uso privado
|
||||
|
||||
Requiere:
|
||||
- ⚠️ Incluir licencia y copyright
|
||||
- ⚠️ Documentar cambios
|
||||
|
||||
## Contacto
|
||||
|
||||
- **GitHub**: `github.com/[tu-usuario]/transcriptorio`
|
||||
- **Discord**: [crear servidor]
|
||||
- **Email**: [configurar]
|
||||
|
||||
## Referencias
|
||||
|
||||
- SubGen original: https://github.com/McCloudS/subgen
|
||||
- Bazarr: https://github.com/morpheus65535/bazarr
|
||||
- Whisper: https://github.com/openai/whisper
|
||||
- faster-whisper: https://github.com/guillaumekln/faster-whisper
|
||||
- stable-ts: https://github.com/jianfch/stable-ts
|
||||
- Tdarr: https://github.com/HaveAGitGat/Tdarr
|
||||
|
||||
---
|
||||
|
||||
**Última actualización**: 2026-01-11
|
||||
**Versión**: 0.1.0-planning
|
||||
**Estado**: En diseño
|
||||
Reference in New Issue
Block a user