yoruba-tts / cache.py
Yurikks's picture
Deploy Yoruba TTS API with facebook/mms-tts-yor
a3fa620
"""
TTS Cache using Redis or in-memory fallback
"""
import hashlib
import logging
import os
from typing import Optional
logger = logging.getLogger(__name__)
# Try to import redis, fallback to in-memory cache
try:
import redis.asyncio as redis
REDIS_AVAILABLE = True
except ImportError:
REDIS_AVAILABLE = False
logger.warning("Redis not available, using in-memory cache")
class TTSCache:
def __init__(self):
self.ttl = 86400 * 7 # 7 days
self.redis_client = None
self.memory_cache: dict[str, str] = {}
self.max_memory_items = 1000
# Try to connect to Redis
redis_url = os.environ.get("REDIS_URL", "redis://localhost:6379")
if REDIS_AVAILABLE:
try:
self.redis_client = redis.from_url(redis_url, decode_responses=True)
logger.info(f"Redis cache initialized: {redis_url}")
except Exception as e:
logger.warning(f"Redis connection failed, using memory cache: {e}")
self.redis_client = None
def _key(self, text: str) -> str:
"""Generate cache key from text hash"""
return f"tts:{hashlib.md5(text.encode()).hexdigest()}"
async def get(self, text: str) -> Optional[str]:
"""Get cached audio (base64) for text"""
key = self._key(text)
# Try Redis first
if self.redis_client:
try:
result = await self.redis_client.get(key)
if result:
logger.debug(f"Redis cache hit for key: {key}")
return result
except Exception as e:
logger.warning(f"Redis get failed: {e}")
# Fallback to memory cache
result = self.memory_cache.get(key)
if result:
logger.debug(f"Memory cache hit for key: {key}")
return result
async def set(self, text: str, audio_b64: str):
"""Cache audio (base64) for text"""
key = self._key(text)
# Try Redis first
if self.redis_client:
try:
await self.redis_client.setex(key, self.ttl, audio_b64)
logger.debug(f"Cached to Redis: {key}")
return
except Exception as e:
logger.warning(f"Redis set failed: {e}")
# Fallback to memory cache with LRU eviction
if len(self.memory_cache) >= self.max_memory_items:
# Remove oldest item (simple FIFO, not true LRU)
oldest_key = next(iter(self.memory_cache))
del self.memory_cache[oldest_key]
logger.debug(f"Evicted from memory cache: {oldest_key}")
self.memory_cache[key] = audio_b64
logger.debug(f"Cached to memory: {key}")
async def clear(self):
"""Clear all cached items"""
self.memory_cache.clear()
if self.redis_client:
try:
# Clear only TTS keys
async for key in self.redis_client.scan_iter("tts:*"):
await self.redis_client.delete(key)
except Exception as e:
logger.warning(f"Redis clear failed: {e}")