Ë
    ðæj¾B  ã            	      ó¢  — U d Z ddlmZ ddlZddlZddlZddlZddlmZ ddl	m
Z
mZmZmZ ddlmZ ddlmZ i dd	“d
d“dd“dd“dd“dd“dd“dd“dd“dd“dd“dd“d d!“d"d#“d$d%“d&d'“d(d)“d*d+d,d-d.d/d0d1œ¥Zd2ed3<   d4Z G d5„ d6e«      Zda ej0                  «       Zd7„ ZdZd8„Zd[d9„Z ed:¬;«      	 	 	 	 	 	 d\d<„«       Z	 	 d]	 	 	 	 	 d^d=„Zd>Zd_d?„Z d@ddAdBdCdDœ	 	 	 	 	 	 	 	 	 	 	 	 	 d`dE„Z!ddAdFœ	 	 	 dadG„Z"ddHœdbdI„Z#ddHœdcdJ„Z$dddK„Z%ddHœdedL„Z&ddCdMœ	 	 	 dfdN„Z'dgdO„Z(dgdP„Z)dddQœ	 	 	 dhdR„Z*didjdS„Z+dTdddCdUdVœ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dkdW„Z,dldX„Z-dmdY„Z.y)nu  
GOLS - OpenAI Language & Voice Intelligence
===========================================
Single integration point for all OpenAI usage across the platform.

Capabilities
------------
  â€¢ Script generation (role-play, interview, coaching, assessment, learning, custom)
  â€¢ Script rewrite / improve / summarize / translate / personalize
  â€¢ Language detection
  â€¢ Avatar-optimized rewriting (clean spoken text for TTS + facial delivery)
  â€¢ Gendered, multilingual Text-to-Speech (OpenAI TTS)

Design notes
------------
  â€¢ Lazy, cached singleton client â€” created once, reused.
  â€¢ Graceful degradation: if no OPENAI_API_KEY is configured, text helpers fall
    back to deterministic local transforms and TTS callers fall back to gTTS in
    the pipeline. Nothing crashes when the key is missing.
  â€¢ Response caching: identical (model, prompt) text requests are cached in-memory
    (LRU) to cut token spend on repeated calls (e.g. polling / re-renders).
  â€¢ All errors are wrapped in OpenAIServiceError with a clean message.
é    )ÚannotationsN)Ú	lru_cache)ÚOptionalÚListÚDictÚAny)Úcfg)ÚlogÚenÚEnglishÚhiÚHindiÚmrÚMarathiÚtaÚTamilÚteÚTeluguÚknÚKannadaÚmlÚ	MalayalamÚguÚGujaratiÚbnÚBengaliÚpaÚPunjabiÚurÚUrduÚesÚSpanishÚfrÚFrenchÚdeÚGermanÚjaÚJapaneseÚzhÚChineseÚarÚArabicÚ
PortugueseÚRussianÚItalianÚKoreanÚ
IndonesianÚDutchÚTurkish)ÚptÚruÚitÚkoÚidÚnlÚtrzDict[str, str]ÚSUPPORTED_LANGUAGES©	ÚgeneralÚroleplayÚ	interviewÚcoachingÚ
assessmentÚlearningÚsalesÚ
onboardingÚannouncementc                  ó   — e Zd ZdZy)ÚOpenAIServiceErrorzGRaised for any recoverable OpenAI failure (clean, user-facing message).N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__© ó    ús/Users/priyanka/Documents/AI_Agent_Assessment/ai-video-generator-gols-v2-new/backend/app/services/openai_service.pyrG   rG   7   s   „ ÚQrM   rG   c                 óü  — t         �t         S t        j                  syt        5  t         €†	 ddlm}  t        j                  t        j                  dœ}t        j                  rt        j                  |d<    | di |¤Ža t        j                  dt        j                  t        j                  «       ddd«       t         S # t        $ r"}t        j                  d|«       da Y d}~Œ4d}~ww xY w# 1 sw Y   t         S xY w)	zEReturn a cached OpenAI client, or None if no key / SDK not installed.Nr   )ÚOpenAI)Úapi_keyÚtimeoutÚbase_urlz.[openai] client initialised (model=%s, tts=%s)z"[openai] failed to init client: %srL   )Ú_clientr	   ÚOPENAI_API_KEYÚ_client_lockÚopenairP   ÚOPENAI_TIMEOUTÚOPENAI_BASE_URLr
   ÚinfoÚOPENAI_TEXT_MODELÚOPENAI_TTS_MODELÚ	ExceptionÚerror)rP   ÚkwargsÚes      rN   Ú_get_clientra   @   sÌ   € ô ÐÜˆÜ×ÒØÞ	Üˆ?ðÝ)ä"×1Ñ1Ü"×1Ñ1ñ*�ô ×&Ò&Ü),×)<Ñ)<�F˜:Ñ&Ù Ñ* 6Ñ*�Ü—‘ÐIÜ×.Ñ.´×0DÑ0DôF÷ 
ô  €Nøô ò Ü—	‘	Ð>ÀÔBØ•ûðú÷ 
ô  €Nús/   ¤C-¬BB?Â?	C*ÃC%Ã C-Ã%C*Ã*C-Ã-C;c                 ó   — t        «       duS )z*True when OpenAI is configured and usable.N)ra   rL   rM   rN   Ú
is_enabledrc   Z   s   € ä‹= Ð$Ð$rM   c                óR   — t         j                  | xs dj                  «       d«      S )Nr   r   )r;   ÚgetÚlower)Úcodes    rN   Ú	lang_namerh   _   s"   € Ü×"Ñ" D¢L¨D×#7Ñ#7Ó#9¸9ÓEÐErM   é   )Úmaxsizec                óh  — t        «       }|€t        d«      ‚	 |j                  j                  j	                  | d|dœd|dœg||¬«      }|j
                  d   j                  j                  xs dj                  «       S # t        $ r)}t        j                  d	|«       t        d
|› �«      ‚d}~ww xY w)zBLRU-cached chat call. Args must be hashable (all strings/numbers).Nú.OpenAI is not configured (set OPENAI_API_KEY).Úsystem©ÚroleÚcontentÚuser©ÚmodelÚmessagesÚtemperatureÚ
max_tokensr   Ú z#[openai] chat completion failed: %súOpenAI request failed: )ra   rG   ÚchatÚcompletionsÚcreateÚchoicesÚmessagerp   Ústripr]   r
   r^   )rs   rm   rq   ru   rv   ÚclientÚrespr`   s           rN   Ú_cached_chatr�   d   s¿   € ô ‹]€FØ€~Ü Ð!QÓRÐRð@Ø�{‰{×&Ñ&×-Ñ-Øà!¨fÑ5Ø¨DÑ1ðð $Ø!ð .ó 
ˆð —‘˜Q‘×'Ñ'×/Ñ/Ò5°2×<Ñ<Ó>Ð>øÜò @Ü�	‰	Ð7¸Ô;Ü Ð#:¸1¸#Ð!>Ó?Ð?ûð@ús   ™A%A? Á?	B1Â$B,Â,B1c                óÄ   — t        t        j                  | j                  «       |j                  «       |€t        j                  n||€t        j
                  «      S |«      S ©N)r�   r	   r[   r~   ÚOPENAI_TEMPERATUREÚOPENAI_MAX_TOKENS)rm   rq   ru   rv   s       rN   Ú_chatr†   {   sZ   € ô Ü×ÑØ�‰‹Ø�
‰
‹Ø"-Ð"5Œ×Ò¸;Ø!+Ð!3Œ×Ñóð ð
 :Dóð rM   uß  You are a professional scriptwriter for AI talking-avatar videos used on a platform similar to HeyGen and Tavus. You write natural, human-sounding spoken dialogue meant to be read aloud by a realistic avatar. Rules: write ONLY the words the avatar will speak â€” no stage directions, no headings, no markdown, no bullet symbols, no speaker labels unless a dialogue is explicitly requested. Use short, breathable sentences and natural punctuation that helps text-to-speech pacing.c           
     óD   — ddddddddd	d
œ	}|j                  | |d   «      S )Nz'Write a clear, engaging spoken message.zRWrite a realistic role-play scene the avatar performs, staying fully in character.zIWrite interview questions and natural framing the avatar asks one by one.zOWrite a warm, motivating coaching session with practical, encouraging guidance.z>Write assessment questions with brief spoken framing for each.zQWrite a concise, easy-to-follow micro-lesson that teaches the topic step by step.zCWrite a persuasive but trustworthy sales pitch focused on benefits.zFWrite a friendly onboarding/welcome message that orients a new person.z&Write a crisp, confident announcement.r<   r=   )re   )Úcontent_typeÚbriefss     rN   Ú_content_briefrŠ   •   s<   € à?ØjØaØgØVØiØ[Ø^Ø@ñ
€Fð �:‰:�l F¨9Ñ$5Ó6Ð6rM   r=   ÚprofessionalÚmediumÚnatural)rˆ   ÚlanguageÚtoneÚlengthÚemotionc               ó¤   — ddddœ}|j                  ||d   «      }t        › dt        |«      › dt        |«      › d|› d	|› d
|› d�}t	        || «      S )z:Generate an avatar-ready spoken script from a topic/brief.zabout 40-70 wordszabout 90-150 wordszabout 200-300 words)ÚshortrŒ   ÚlongrŒ   Ú
z
Write the entire output in z. Tone: z. Emotional delivery: z. Target length: Ú.)re   Ú_SYSTEM_BASErŠ   rh   r†   )	Úpromptrˆ   rŽ   r�   r�   r‘   Ú
length_mapÚwordsrm   s	            rN   Úgenerate_scriptr›   ¤   s~   € ð /Ð:NØ/ñ1€Jà�N‰N˜6 :¨hÑ#7Ó8€Eäˆ.˜œ>¨,Ó7Ð8ð 9&Ü&/°Ó&9Ð%:ð ;Ø�Ð,¨W¨IÐ5FÀuÀgÈQð	Pð ô
 �˜Ó Ð rM   )rŽ   r�   c               óJ   — t         › dt        |«      › d|› d�}t        || «      S )z<Improve clarity, flow and naturalness while keeping meaning.z�
Improve the following script for a talking-avatar video: fix grammar, improve flow and naturalness, keep the original meaning and length similar. Output in z, tone z'. Return only the improved spoken text.©r—   rh   r†   )ÚscriptrŽ   r�   rm   s       rN   Úimprove_scriptrŸ   ¹   s>   € ô ˆ.ð %ä%.¨xÓ%8Ð$9¸ÀÀð G0ð	1ð ô �˜Ó Ð rM   )rŽ   c               óP   — t         › dt        |«      › d�}t        |d|› d| › �«      S )z3Rewrite a script following a free-form instruction.zY
Rewrite the script according to the user's instruction. Output the spoken text only, in r–   zINSTRUCTION: z


SCRIPT:
r�   )rž   ÚinstructionrŽ   rm   s       rN   Úrewrite_scriptr¢   Å   sB   € ô ˆ.ð +Ü+4°XÓ+>Ð*?¸qð	Bð ô �˜=¨¨°]À6À(ÐKÓLÐLrM   c               óH   — t         › dt        |«      › d�}t        || d¬«      S )Nzk
Summarize the following into a short spoken version that keeps the key points. Output only spoken text in r–   ç333333Ó?©ru   r�   )rž   rŽ   rm   s      rN   Úsummarize_scriptr¦   Î   s7   € äˆ.ð AÜAJÈ8ÓATÐ@UÐUVð	Xð ô �˜¨SÔ1Ð1rM   c                óH   — t         › dt        |«      › d�}t        || d¬«      S )z@Translate to a target language, preserving spoken/natural style.z
Translate the script into zw. Keep it natural and idiomatic for a spoken avatar, not a literal translation. Return only the translated spoken text.r¤   r¥   r�   )rž   Útarget_languagerm   s      rN   Útranslate_scriptr©   Ö   s7   € ô ˆ.Ð4´Y¸Ó5OÐ4Pð Q2ð 	3ð ô
 �˜¨SÔ1Ð1rM   c               óJ   — t         › d|› dt        |«      › d�}t        || «      S )Nz+
Personalize the script for this audience: zO. Adjust examples, vocabulary and tone accordingly. Output only spoken text in r–   r�   )rž   ÚaudiencerŽ   rm   s       rN   Úpersonalize_scriptr¬   à   s:   € äˆ.ÐDÀXÀJð O&ä&/°Ó&9Ð%:¸!ð	=ð ô
 �˜Ó Ð rM   )rŽ   r‘   c               óN   — t         › d|› dt        |«      › d�}t        || d¬«      S )zÙ
    Clean a raw script into avatar/TTS-optimized spoken text:
    expand abbreviations, add natural pauses (commas), remove markup/emoji.
    Used automatically by the pipeline before TTS when OpenAI is enabled.
    z[
Rewrite the text so it is optimal for text-to-speech and realistic avatar delivery with a z´ emotional tone: expand abbreviations and numbers into spoken words, add natural commas for breathing, remove any emojis, markdown, URLs or symbols. Keep the meaning and language (z'). Return only the cleaned spoken text.gš™™™™™É?r¥   r�   )rž   rŽ   r‘   rm   s       rN   Úoptimize_for_speechr®   é   sD   € ô ˆ.ð ,Ø,3¨9ð 5ô # 8Ó,Ð-Ð-Tð		Vð ô �˜¨SÔ1Ð1rM   c                óä   — t        «       st        | «      S d}	 t        || dd dd¬«      j                  «       j	                  «       }|dd }|t
        v r|S dS # t        $ r t        | «      cY S w xY w)	z<Return a best-effort ISO 639-1 code for the text's language.zˆDetect the language of the user's text. Respond with ONLY the lowercase ISO 639-1 two-letter code (e.g. en, hi, mr, ta). No other words.NiX  r   é   )ru   rv   é   r   )rc   Ú_heuristic_detectr†   r~   rf   r;   rG   )Útextrm   rg   s      rN   Údetect_languager´   ú   s‚   € äŒ<Ü  Ó&Ð&ð	Kð ð'Ü�V˜T $ 3˜Z°QÀ1ÔE×KÑKÓM×SÑSÓUˆØ�B�QˆxˆØÔ2Ñ2ˆtÐ<¸Ð<øÜò 'Ü  Ó&Ò&ð'ús   ™<A ÁA ÁA/Á.A/c                ó¦   — ddddddddd	d	d
dddœ}| D ]<  }t        |«      }|j                  «       D ]  \  }\  }}||cxk  r|k  sŒn Œ|c c S  Œ> y)z?Offline fallback: detect a few Indian scripts by Unicode range.)i 	  i	  )i€	  iÿ	  )i 
  i
  )i€
  iÿ
  )i€  iÿ  )i   i  )i€  iÿ  )i   i  )i   iÿ  )i N  iÿŸ  )i@0  iÿ0  )i ¬  i¯×  )r   r   r   r   r   r   r   r   r   r+   r)   r'   r7   r   )ÚordÚitems)r³   ÚrangesÚchÚorg   Úlor   s          rN   r²   r²   
  st   € ð ØØØØØØØØØØØØñ€Fó ˆÜ�‹GˆØ$Ÿl™lžn‰NˆD‘(�2�rØ�QŒ}˜"Ž}Ø”ñ -ð ð
 rM   )rŽ   rm   c               óê  — t        «       }|€t        d«      ‚|xs t        › dt        |«      › d�}	 |j                  j
                  j                  t        j                  d|dœg| ¢t        j                  t        j                  ¬«      }|j                  d   j                  j                  xs d	j                  «       S # t        $ r)}t!        j"                  d
|«       t        d|› �«      ‚d}~ww xY w)zv
    Maintain conversational context. `messages` is a list of
    {"role": "user"|"assistant", "content": "..."}.
    Nrl   zR
You are having a natural conversation that will be spoken by an avatar. Reply in z with spoken text only.rm   rn   rr   r   rw   z[openai] converse failed: %srx   )ra   rG   r—   rh   ry   rz   r{   r	   r[   r„   r…   r|   r}   rp   r~   r]   r
   r^   )rt   rŽ   rm   r   Úsysr€   r`   s          rN   Úconverser¾   &  sõ   € ô ‹]€FØ€~Ü Ð!QÓRÐRØ
ò Üˆ.ð "Ü"+¨HÓ"5Ð!6Ð6Mð	Oð ð
@Ø�{‰{×&Ñ&×-Ñ-Ü×'Ñ'Ø'°CÑ8ÐD¸8ÐDÜ×.Ñ.Ü×,Ñ,ð	 .ó 
ˆð —‘˜Q‘×'Ñ'×/Ñ/Ò5°2×<Ñ<Ó>Ð>øÜò @Ü�	‰	Ð0°!Ô4Ü Ð#:¸1¸#Ð!>Ó?Ð?ûð@ús   ²BC  Ã 	C2Ã	$C-Ã-C2c                óx   — |r|S | xs dj                  «       dk(  rt        j                  S t        j                  S )z9Map a gender ('male'/'female') to an OpenAI TTS voice id.rw   Úmale)rf   r	   ÚOPENAI_VOICE_MALEÚOPENAI_VOICE_FEMALE)ÚgenderÚoverrides     rN   Úvoice_for_genderrÅ   C  s:   € áØˆØ%+¢\¨r×$8Ñ$8Ó$:¸fÒ$DŒ3× Ñ ð %Ü×$Ñ$ð%rM   Úfemaleç      ð?)rÃ   ÚvoicerŽ   r‘   Úspeedc          	     ó  — t        «       }|€yt        ||«      }dt        |«      › d|› d�}		 t        dt	        dt        |«      «      «      }
g }t        j                  d	fD ]  }|sŒ||vsŒ|j                  |«       Œ d}|D ]£  }	 t        ||| d
|
¬«      }d|v r|	|d<    |j                  j                  j                  j                  di |¤Ž5 }|j                  |«       ddd«       t         j"                  j%                  |«      dkD  rt'        j(                  d||||«        yŒ¥ t'        j,                  d|«       y# t        $ r d}
Y �Œw xY w# 1 sw Y   ŒqxY w# t        $ r$}|}t'        j*                  d||«       Y d}~�Œd}~ww xY w)zÓ
    Generate speech audio (mp3) with OpenAI TTS. Returns True on success,
    False if OpenAI is unavailable (so the pipeline can fall back to gTTS).
    Raises OpenAIServiceError only on a hard API error.
    NFz	Speak in z with a z„, natural human tone suitable for a realistic talking-avatar video. Clear articulation, appropriate emotional inflection and pacing.g      à?g       @rÇ   ztts-1Úmp3)rs   rÈ   ÚinputÚresponse_formatrÉ   zgpt-4oÚinstructionsiè  z3[openai] TTS ok (model=%s, voice=%s, lang=%s) -> %sTu3   [openai] TTS model '%s' failed (%s) â€” trying nextuL   [openai] All OpenAI TTS attempts failed (%s) â€” pipeline falls back to gTTSrL   )ra   rÅ   rh   ÚmaxÚminÚfloatr]   r	   r\   ÚappendÚdictÚaudioÚspeechÚwith_streaming_responser{   Ústream_to_fileÚosÚpathÚgetsizer
   rZ   Úwarningr^   )r³   Úout_pathrÃ   rÈ   rŽ   r‘   rÉ   r   ÚchosenrÎ   ÚspdÚmodels_to_tryÚmÚlast_errrs   r_   r€   r`   s                     rN   Úsynthesize_speechrâ   K  s¥  € ô ‹]€FØ€~Øä˜f eÓ,€Fà
”I˜hÓ'Ð(¨°°	ð :7ð 	8ð ð
Ü�#”s˜3¤ e£Ó-Ó.ˆð €MÜ×"Ñ" GÓ,ˆÚ�˜-Ò'Ø× Ñ  Õ#ð -ð €HÛˆð	YÜ%)Ø 6°Ø %¨Sô&ˆFð ˜5Ñ Ø)5��~Ñ&ØC�—‘×$Ñ$×<Ñ<×CÑCÑMÀfÒMÐQUØ×#Ñ# HÔ-÷ Nä�w‰w�‰˜xÓ(¨4Ò/Ü—‘ÐNØ ¨°(ô<áð 0ð ô$ ‡I�IÐ\Øôàøô? ò Ø‹ðú÷& NÐMûô ò 	YØˆHÜ�K‰KÐMÈuÐVW×XÒXûð	YúsC   ­D? ÂA	EÃEÃ!AEÄ?EÅEÅE	ÅEÅ	F
Å&FÆF
c                 ó,   — t         j                  «        y rƒ   )r�   Úcache_clearrL   rM   rN   Úclear_cacherå   ‰  s   € Ü×ÑÕrM   c                 óˆ   — t         j                  «       } | j                  | j                  | j                  | j
                  dœS )N)ÚhitsÚmissesÚsizerj   )r�   Ú
cache_inforç   rè   Úcurrsizerj   )rZ   s    rN   Úcache_statsrì   �  s4   € Ü×"Ñ"Ó$€DØ—I‘I¨¯©Ø—M‘M¨d¯l©lñ<ð <rM   )ÚreturnÚbool)rg   Ústrrí   rï   )rs   rï   rm   rï   rq   rï   ru   rÑ   rv   Úintrí   rï   )NN)
rm   rï   rq   rï   ru   zOptional[float]rv   zOptional[int]rí   rï   )rˆ   rï   rí   rï   )r˜   rï   rˆ   rï   rŽ   rï   r�   rï   r�   rï   r‘   rï   rí   rï   )rž   rï   rŽ   rï   r�   rï   rí   rï   )rž   rï   r¡   rï   rŽ   rï   rí   rï   )rž   rï   rŽ   rï   rí   rï   )rž   rï   r¨   rï   rí   rï   )rž   rï   r«   rï   rŽ   rï   rí   rï   )rž   rï   rŽ   rï   r‘   rï   rí   rï   )r³   rï   rí   rï   )rt   zList[Dict[str, str]]rŽ   rï   rm   úOptional[str]rí   rï   rƒ   )rÃ   rï   rÄ   rñ   rí   rï   )r³   rï   rÜ   rï   rÃ   rï   rÈ   rñ   rŽ   rï   r‘   rï   rÉ   rÑ   rí   rî   )rí   ÚNone)rí   zDict[str, Any])/rK   Ú
__future__r   ÚhashlibÚjsonrØ   Ú	threadingÚ	functoolsr   Útypingr   r   r   r   Ú
app.configr	   Úapp.utils.loggerr
   r;   Ú__annotations__ÚCONTENT_TYPESr]   rG   rT   ÚLockrV   ra   rc   rh   r�   r†   r—   rŠ   r›   rŸ   r¢   r¦   r©   r¬   r®   r´   r²   r¾   rÅ   râ   rå   rì   rL   rM   rN   Ú<module>rþ      s  ðòõ0 #ã Û Û 	Û Ý ß ,Ó ,å Ý  ð'Øˆ)ð'Ø˜Wð'Ø*.°	ð'Ø=AÀ7ð'àˆ(ð'à˜Yð'à*.°ð'à=AÀ:ð'ð 	ˆ)ð'ð ˜Yð'ð +/°ð'ð >BÀ9ð'ð 	ˆ(ð	'ð ˜Xð	'ð +/°
ð	'ð >BÀ9ð	'ð
 	ˆ(ð'ð
 *°	À9Ø
˜\°À9ò'Ð �^ó ð€ôR˜ô Rð
 €Øˆy�~‰~Ó€òó4%ó
Fñ
 �3Ôð@Ø#ð@Ø14ð@Ø9<ò@ó ð@ð. *.Ø&*ð	Ø&ð	à#ð	à/2ó	ð <ð ó7ð$ "ØØØØñ!Øð!ð ð!ð ð	!ð
 ð!ð ð!ð ð!ð 	ó!ð* 48Ø-ñ	!Øð	!Ø25ó	!ð FJõ Mð 6:õ 2ó2ð GKõ !ð 9=Ø'0ñ2Ø!$ð2Ø58ó2ó"'ó ð8 AEØ%)ñ@Ø"ð@Ø.1ó@ô:%ð ØØØØñ:Ø
ð:àð:ð ð	:ð
 ð:ð ð:ð ð:ð ð:ð 
ó:ó|ô<rM   