1111
1212## Características
1313
14- ** Orquestación multi-proveedor** con fallback automático (Groq → OpenRouter)
14+ ** Orquestación multi-proveedor** con fallback automático (Groq → OpenRouter → Ollama)
15+ ** Soporte para Ollama** (modelos locales) además de proveedores cloud
1516 ** Streaming SSE** (Server-Sent Events) para respuestas en tiempo real
1617 ** Arquitectura por capas** (Controllers → Orchestrator → Router → Adapters)
1718 ** Rate limiting** y control de concurrencia con Redis
3334 │
3435┌─────────────────────▼───────────────────────────────────────┐
3536│ Controllers │
36- │ • Validación de entrada (Pydantic) │
37- │ • Autorización (API Key) │
38- │ • Manejo de SSE │
37+ │ • Validación de entrada (Pydantic) │
38+ │ • Autorización (API Key) │
39+ │ • Manejo de SSE │
3940└─────────────────────┬───────────────────────────────────────┘
4041 │
4142┌─────────────────────▼───────────────────────────────────────┐
4243│ Orchestrator │
43- │ • Timeout global de operación │
44- │ • Coordinación de streaming │
45- │ • Manejo de cancelación │
44+ │ • Timeout global de operación │
45+ │ • Coordinación de streaming │
46+ │ • Manejo de cancelación │
4647└─────────────────────┬───────────────────────────────────────┘
4748 │
4849┌─────────────────────▼───────────────────────────────────────┐
4950│ Router │
50- │ • Selección de proveedor │
51- │ • Fallback automático │
52- │ • Blacklist + backoff exponencial │
53- │ • Estado en Redis │
51+ │ • Selección de proveedor │
52+ │ • Fallback automático │
53+ │ • Blacklist + backoff exponencial │
54+ │ • Estado en Redis │
5455└─────────────────────┬───────────────────────────────────────┘
5556 │
56- ┌─────────────┴─────────────┐
57- │ │
58- ┌───────▼────────┐ ┌────────▼───────┐
59- │ GroqAdapter │ │ OpenRouter │
60- │ │ │ Adapter │
61- │ • Traducción │ │ • Traducción │
62- │ de request │ │ de request │
63- │ • Stream SSE │ │ • Stream SSE │
64- └───────┬────────┘ └────────┬───────┘
65- │ │
66- └─────────────┬─────────────┘
57+ ┌─────────────┴─────────────┬───────────────── ┐
58+ │ │ │
59+ ┌───────▼────────┐ ┌────────▼───────┐ ┌────▼────────┐
60+ │ GroqAdapter │ │ OpenRouter │ │ Ollama │
61+ │ │ │ Adapter │ │ Adapter │
62+ │ • Traducción │ │ • Traducción │ │ • Modelos │
63+ │ de request │ │ de request │ │ locales │
64+ │ • Stream SSE │ │ • Stream SSE │ │ • Stream │
65+ └───────┬────────┘ └────────┬───────┘ └─────┬───────┘
66+ │ │ │
67+ └─────────────┬─────────────┴────────────────── ┘
6768 │
6869 ┌───────▼────────┐
6970 │ HTTPClient │
7273
7374┌──────────────────────────────────────────────────┐
7475│ Infraestructura │
75- │ • Redis: blacklist, rate limits, locks │
76+ │ • Redis: blacklist, rate limits, locks │
7677│ • Prometheus: métricas │
7778│ • Logs: JSON estructurado │
7879└──────────────────────────────────────────────────┘
8889- ** Docker** y ** Docker Compose**
8990- ** Redis** (incluido en docker-compose)
9091- Claves API de ** Groq** y/o ** OpenRouter**
92+ - ** Ollama** instalado localmente (opcional, para usar modelos locales)
9193
9294### 1. Clonar repositorio
9395
@@ -107,6 +109,7 @@ Edita [.env](.env) y añade tus claves API:
107109``` env
108110GROQ_API_KEY=tu_clave_groq
109111OPENROUTER_API_KEY=tu_clave_openrouter
112+ OLLAMA_API_KEY=tu_clave_ollama
110113API_KEY=tu_clave_para_clientes
111114```
112115
@@ -325,6 +328,8 @@ Todas las configuraciones están en [app/config.py](app/config.py) y se pueden s
325328| ----------------------------------| --------------------------------------| ------------------------------|
326329| ` GROQ_API_KEY ` | Clave API de Groq | - |
327330| ` OPENROUTER_API_KEY ` | Clave API de OpenRouter | - |
331+ | ` OLLAMA_API_KEY ` | Clave API de Ollama (opcional) | - |
332+ | ` OLLAMA_BASE_URL ` | URL de Ollama | ` http://localhost:11434 ` |
328333| ` API_KEY ` | Clave para autenticar clientes | - |
329334| ` REDIS_URL ` | URL de conexión Redis | ` redis://localhost:6379/0 ` |
330335| ` PROVIDER_TIMEOUT ` | Timeout por proveedor (s) | ` 30.0 ` |
@@ -333,7 +338,9 @@ Todas las configuraciones están en [app/config.py](app/config.py) y se pueden s
333338| ` BACKOFF_BASE_SECONDS ` | Backoff base exponencial | ` 5 ` |
334339| ` BACKOFF_MAX_SECONDS ` | Backoff máximo | ` 300 ` |
335340| ` RATE_LIMIT_REQUESTS_PER_MINUTE ` | Rate limit global por minuto | ` 60 ` |
336- | ` GROQ_RATE_LIMIT ` | Rate limit específico Groq (req/min) | Usa límite global |
341+ | ` GROQ_RATE_LIMIT ` | Rate limit específico Groq (req/min) | ` 30 ` |
342+ | ` OPENROUTER_RATE_LIMIT ` | Rate limit OpenRouter (req/min) | ` 20 ` |
343+ | ` OLLAMA_RATE_LIMIT ` | Rate limit Ollama (req/min) | ` 100 ` |
337344| ` OPENROUTER_RATE_LIMIT ` | Rate limit OpenRouter (req/min) | Usa límite global |
338345| ` MAX_CONCURRENT_STREAMS ` | Streams concurrentes máx. | ` 10 ` |
339346
@@ -442,7 +449,7 @@ ModelRouter/
442449### Completado
443450
444451- [x] Scaffold proyecto + Docker
445- - [x] Adapters Groq y OpenRouter
452+ - [x] Adapters Groq, OpenRouter y Ollama
446453- [x] Router con fallback
447454- [x] Orchestrator
448455- [x] Endpoints /chat y /stream
@@ -453,9 +460,10 @@ ModelRouter/
453460
454461### Próximos pasos
455462
463+ - [ ] Permitir especificar de forma opcional un proveedor en la request
464+ - [ ] Selección Explícita de Modelo por Proveedor
456465- [ ] Persistencia de historiales (PostgreSQL)
457466- [ ] Soporte para más proveedores (Anthropic, OpenAI)
458- - [ ] WebSockets como alternativa a SSE
459467- [ ] Cacheo de respuestas frecuentes
460468- [ ] Dashboard Grafana pre-configurado
461469
0 commit comments