1+ import hashlib
2+ import base64
3+ import os
14from io import BytesIO
25
6+ import redis
7+ from django .conf import settings
38from django .http import FileResponse
49from drf_yasg .utils import swagger_auto_schema
510from gtts import gTTS
1015from apps .api .utils import serializer_to_manual_parameters
1116from apps .speech .serializers import TextToSpeechSerializer
1217
18+ # Redis connection setup
19+ try :
20+ redis_url = os .getenv ('REDIS_URL' ) or getattr (settings , 'REDIS_URL' , None )
21+ if redis_url :
22+ redis_client = redis .from_url (redis_url , decode_responses = False ) # Keep as False for binary data
23+ redis_client .ping () # Test connection
24+ REDIS_AVAILABLE = True
25+ else :
26+ redis_client = None
27+ REDIS_AVAILABLE = False
28+ except (redis .ConnectionError , AttributeError ):
29+ redis_client = None
30+ REDIS_AVAILABLE = False
31+
1332
1433class TextToSpeechAPIView (APIView ):
1534 @swagger_auto_schema (manual_parameters = serializer_to_manual_parameters (TextToSpeechSerializer ))
@@ -23,18 +42,57 @@ def get(self, request, *args, **kwargs):
2342 if not input_text :
2443 return Response ({"error" : "The text parameter is missing." }, status = status .HTTP_400_BAD_REQUEST )
2544
45+ # Create cache key from text, language, and slow parameter
2646 slow = False if language == "bn" else True
47+ cache_data = f"{ input_text } _{ language } _{ slow } "
48+ cache_key = f"tts:{ hashlib .md5 (cache_data .encode ('utf-8' )).hexdigest ()} "
49+
50+ # Try to get from Redis cache first
51+ if REDIS_AVAILABLE and redis_client :
52+ try :
53+ cached_audio = redis_client .get (cache_key )
54+ if cached_audio :
55+ # Convert base64 back to bytes
56+ audio_data = base64 .b64decode (cached_audio )
57+ output_file = BytesIO (audio_data )
2758
59+ response = FileResponse (output_file , content_type = "audio/mpeg" )
60+ response ["Content-Disposition" ] = 'attachment; filename="output.mp3"'
61+ response ["X-Cache-Status" ] = "HIT"
62+ return response
63+ except redis .RedisError :
64+ # If Redis fails, continue without caching
65+ pass
66+
67+ # Generate TTS if not in cache
2868 try :
2969 tts = gTTS (text = input_text , lang = language , slow = slow )
3070
3171 output_file = BytesIO ()
3272 tts .write_to_fp (output_file )
3373 output_file .seek (0 )
3474
75+ # Read audio data for caching
76+ audio_data = output_file .read ()
77+ output_file .seek (0 ) # Reset for response
78+
79+ # Cache the audio data in Redis permanently
80+ if REDIS_AVAILABLE and redis_client :
81+ try :
82+ # Encode binary data as base64 for Redis storage
83+ encoded_audio = base64 .b64encode (audio_data ).decode ('utf-8' )
84+
85+ # Cache forever - TTS results never change
86+ redis_client .set (cache_key , encoded_audio )
87+ except redis .RedisError :
88+ # If caching fails, continue serving the response
89+ pass
90+
3591 response = FileResponse (output_file , content_type = "audio/mpeg" )
3692 response ["Content-Disposition" ] = 'attachment; filename="output.mp3"'
93+ response ["X-Cache-Status" ] = "MISS"
3794 return response
95+
3896 except Exception as e :
3997 return Response (
4098 {"error" : f"Error generating audio: { str (e )} " }, status = status .HTTP_500_INTERNAL_SERVER_ERROR
0 commit comments