Ë
    I»j”4  ã                   ó   — d Z ddlmZ ddlmZ ddlmZ ddlmZm	Z	m
Z
mZmZmZmZmZmZmZmZmZmZmZmZmZmZ ddlmZ ddlmZmZ  G d„ d	«      Z G d
„ d«      Z G d„ d«      Z  G d„ d«      Z! G d„ d«      Z" G d„ d«      Z# G d„ d«      Z$y)zƒFinal SOW AI helpers: inclusive JD rewrite, next-question, TTS, scenarios, lock validate,
follow-up logic, merge custom questions.
é    )Úuuid4)Ú	JobStatus)ÚQuestionType)ÚFollowUpLogicRequestÚFollowUpLogicResponseÚFollowUpRuleÚInterviewValidateLockRequestÚInterviewValidateLockResponseÚJdInclusivityRewriteRequestÚJdInclusivityRewriteResponseÚMergeCustomQuestionsRequestÚMergeCustomQuestionsResponseÚNextQuestionRequestÚNextQuestionResponseÚScenarioGenerateRequestÚScenarioGenerateResponseÚScenarioGradeRequestÚScenarioGradeResponseÚTtsSynthesizeRequestÚTtsSynthesizeResponse)Úgenerate_json)Ú_local_questionsÚ_parse_questionsc                   ó   — e Zd Zdedefd„Zy)ÚJdInclusivityServiceÚpayloadÚreturnc              ƒ   ó–  ‡K  — d}d‰j                   › d‰j                  › �}dt        fˆfd„}t        |||¬«      ƒ d {  –—† \  }}}t	        ‰j
                  t        j                  |d|› �‰j                  |j                  d«      t        |j                  d	«      xs g «      t        |j                  d
«      xs g «      ¬«      S 7 Œ‡­w)NzrRewrite JD to be inclusive and bias-free. Return JSON: {"rewritten_markdown","removed_bias_phrases":[],"notes":[]}zTitle: z
JD:
r   c                  ó  •— g d¢} | D �cg c]!  }|‰j                   j                  «       v sŒ |‘Œ# }}‰j                   }|D ]4  }|j                  |d«      }|j                  |j                  «       d«      }Œ6 ||dgdœS c c}w )N)zyoung bloodznative speakerÚguyszrockstar ninjazskilled professionalzSkilled professionalz6Prefer skill/outcome language over demographic proxies)Úrewritten_markdownÚremoved_bias_phrasesÚnotes)Újob_descriptionÚlowerÚreplaceÚtitle)ÚriskyÚpÚfoundÚtextr   s       €ú./var/www/html/TJ-AI/tj/app/services/helpers.pyÚlocalz+JdInclusivityService.rewrite.<locals>.local*   s�   ø€ ÚOˆEÙ %ÓN¡˜1¨¨g×.EÑ.E×.KÑ.KÓ.MÒ)M’Q ˆEÐNØ×*Ñ*ˆDÛ�Ø—|‘| AÐ'=Ó>�Ø—|‘| A§G¡G£IÐ/EÓF‘ð ð '+Ø(-ØRÐSñð ùò Os
   Š!A>¬A>©ÚsystemÚuserÚlocal_factoryzInclusivity rewrite via r!   r"   r#   )Úcorrelation_idÚstatusÚstubÚmessageÚoriginalr!   r"   r#   )
Ú
role_titler$   Údictr   r   r2   r   Ú	SUCCEEDEDÚgetÚlist©Úselfr   r/   r0   r-   Údatar4   Úproviders    `      r,   ÚrewritezJdInclusivityService.rewrite!   sÕ   øè ø€ ðPð 	ð ˜×+Ñ+Ð,¨G°G×4KÑ4KÐ3LÐMˆð	”tõ 	ô &3Ø °Eô&
÷  
Ñˆˆd�Hô ,Ø"×1Ñ1Ü×&Ñ&ØØ.¨x¨jÐ9Ø×,Ñ,Ø#Ÿx™xÐ(<Ó=Ü!% d§h¡hÐ/EÓ&FÒ&LÈ"Ó!MÜ�t—x‘x Ó(Ò.¨BÓ/ô	
ð 		
ð 
ús   ƒ<C	¿CÁ BC	N)Ú__name__Ú
__module__Ú__qualname__r   r   r@   © ó    r,   r   r       s   „ ð"
Ø2ð"
à	%ô"
rE   r   c                   ó   — e Zd Zdedefd„Zy)ÚNextQuestionServicer   r   c              ƒ   ó  ‡K  — d}d‰j                   › d‰j                  › d‰j                  › d‰j                  › d‰j                  › d‰j
                  dd  › �}d	t        fˆfd
„}t        |||¬«      ƒ d {  –—† \  }}}t        ‰j                  ‰j                  t        j                  |d|› �|j                  d«      |j                  d«      |j                  d«      t        |j                  d«      «      ¬«	      S 7 Œ†­w)NzkPick the best next interview question. Return JSON: {"question_id","question_text","rationale","done":bool}úRole: ú
JD: z

Planned: z
Asked: z
Last score: z
Transcript: éûÿÿÿr   c                  ó®  •— t        ‰j                  «      D � �cg c])  \  } }d| dz   › �‰j                  vr|‰j                  vr|‘Œ+ }} }|s!‰j                  sdd‰j                  › d�dddœS |sd d d	d
dœS d}‰j                  �‰j                  dk  rt        |«      dkD  rd}||   }d‰j                  j                  |«      dz   › �}||dddœS c c}} w )Núq-é   znq-1z(What recent impact did you deliver as a Ú?u+   No planned list â€” generate adaptive probeF)Úquestion_idÚquestion_textÚ	rationaleÚdonezAll planned questions askedTr   g333333ã?z Next unanswered planned question)Ú	enumerateÚplanned_questionsÚasked_question_idsr7   Ú
last_scoreÚlenÚindex)ÚiÚqÚ	remainingÚidxÚqtextÚqidr   s         €r,   r-   z)NextQuestionService.choose.<locals>.localR   s"  ø€ ô & g×&?Ñ&?Ô@ôá@‘D�A�qØ˜˜A™�w�< w×'AÑ'AÑAØ˜W×7Ñ7Ñ7ò Ø@ð ñ ñ  W×%>Ò%>à#)àBÀ7×CUÑCUÐBVÐVWÐXà!NØ!ñð ñ à#'Ø%)Ø!>Ø ñ	ð ð ˆCØ×!Ñ!Ð-°'×2DÑ2DÀsÒ2JÌsÐS\Ë~Ð`aÒOaØ�Ø˜c‘NˆEØ�w×0Ñ0×6Ñ6°uÓ=ÀÑAÐBÐCˆCà"Ø!&Ø?Øñ	ð ùó7s   š.Cr.   zNext question via rP   rQ   rR   rS   )	r2   Úinterview_idr3   r4   r5   rP   rQ   rR   rS   )r7   r$   rU   rV   rW   Ú
transcriptr8   r   r   r2   r`   r   r9   r:   Úboolr<   s    `      r,   ÚchoosezNextQuestionService.chooseG   s  øè ø€ ðNð 	ð
 �W×'Ñ'Ð(¨¨w×/FÑ/FÐ.Gð HØ×1Ñ1Ð2°)¸G×<VÑ<VÐ;Wð XØ"×-Ñ-Ð.¨n¸W×=OÑ=OÐPRÐPSÐ=TÐ<UðWð 	ð!	”tõ !	ôF &3Ø °Eô&
÷  
Ñˆˆd�Hô $Ø"×1Ñ1Ø ×-Ñ-Ü×&Ñ&ØØ(¨¨
Ð3ØŸ™ Ó/ØŸ(™( ?Ó3Ø—h‘h˜{Ó+Ü�d—h‘h˜vÓ&Ó'ô

ð 
	
ð 
ús   ƒA3C?Á6C=Á7BC?N)rA   rB   rC   r   r   rc   rD   rE   r,   rG   rG   F   s   „ ð;
Ð$7ð ;
Ð<Pô ;
rE   rG   c                   ó   — e Zd Zdedefd„Zy)Ú
TtsServicer   r   c           
   ƒ   ó˜   K  — t        |j                  t        j                  ddd d|j                  xs |j
                  xs dd¬«      S ­w)NTu4   TTS local stub â€” live audio provider not wired yetz
audio/mpegÚdefaultr-   )r2   r3   r4   r5   Úaudio_base64Ú	mime_typeÚvoice_idr?   )r   r2   r   r9   rj   Ú
voice_name)r=   r   s     r,   Ú
synthesizezTtsService.synthesize†   sM   è ø€ Ü$Ø"×1Ñ1Ü×&Ñ&ØØJØØ"Ø×%Ñ%ÒH¨×);Ñ);ÒH¸yØô	
ð 		
ùs   ‚AA
N)rA   rB   rC   r   r   rl   rD   rE   r,   re   re   …   s   „ ð

Ð(<ð 

ÐAVô 

rE   re   c                   ó,   — e Zd Zdedefd„Zdedefd„Zy)ÚScenariosServicer   r   c              ƒ   óÄ  ‡K  — d}d‰j                   › d‰j                  › d‰j                  j                  › d‰j                  › �}dt
        fˆfd„}t        |||¬«      ƒ d {  –—† \  }}}t        |j                  d	g «      t        j                  ‰j                  «      }t        ‰j                  t        t        «       «      t        j                   |d
|› �|¬«      S 7 Œz­w)NzHGenerate role-based scenario questions. Return JSON: {"scenarios":[...]}rI   rJ   z
Difficulty: z
Count: r   c                  ó„   •— dt        ‰ j                  t        j                  ‰ j                  d‰ j
                  › �¬«      iS )NÚ	scenarioszscenario / )ÚcountÚqtypeÚ
difficultyÚtopic)r   rr   r   ÚLONG_ANSWERrt   r7   )r   s   €r,   r-   z(ScenariosService.generate.<locals>.local�   sB   ø€ àÔ-Ø!Ÿ-™-Ü&×2Ñ2Ø&×1Ñ1Ø'¨×(:Ñ(:Ð';Ð<ô	ðð rE   r.   rq   zScenarios via )r2   Úscenario_set_idr3   r4   r5   rq   )r7   r$   rt   Úvaluerr   r8   r   r   r:   r   rv   r   r2   Ústrr   r   r9   )	r=   r   r/   r0   r-   r>   r4   r?   rq   s	    `       r,   ÚgeneratezScenariosService.generate”   së   øè ø€ ð ^ˆà�W×'Ñ'Ð(¨¨w×/FÑ/FÐ.Gð HØ"×-Ñ-×3Ñ3Ð4°I¸g¿m¹m¸_ðNð 	ð
	”tõ 	ô &3Ø °Eô&
÷  
Ñˆˆd�Hô %Ø�H‰H�[ "Ó%¤|×'?Ñ'?À×ASÑASó
ˆ	ô (Ø"×1Ñ1Ü¤£›LÜ×&Ñ&ØØ$ X JÐ/Øô
ð 	
ð 
ús   ƒA C Á#CÁ$A;C c              ƒ   ó   ‡K  — d}d‰j                   › d‰j                  › �}dt        fˆfd„}t        |||¬«      ƒ d {  –—† \  }}}t	        ‰j
                  t        j                  |d|› �t        |j                  d«      xs d	«      t        |j                  d
«      xs d«      |j                  d«      |j                  d«      ¬«      S 7 ŒŒ­w)NzgGrade scenario answers. Return JSON: {"total_score","max_total_score":100,"passed","feedback_markdown"}rI   z

Answers: r   c                  óf   •— t        ‰j                  «      } t        ddd| z  z   «      }|d|dk\  ddœS )Ng     ÀW@g      I@g      $@g      Y@éF   z;Scenarios show structured thinking; add trade-off analysis.)Útotal_scoreÚmax_total_scoreÚpassedÚfeedback_markdown)rX   ÚanswersÚmin)ÚnÚscorer   s     €r,   r-   z%ScenariosService.grade.<locals>.local½   s?   ø€ Ü�G—O‘OÓ$ˆAÜ˜˜d T¨A¡X™oÓ.ˆEà$Ø#(Ø 2™+Ø%bñ	ð rE   r.   zScenario graded via r~   r   r   éd   r€   r�   )r2   r3   r4   r5   r~   r   r€   r�   )
r7   r‚   r8   r   r   r2   r   r9   Úfloatr:   r<   s    `      r,   ÚgradezScenariosService.grade¶   sÖ   øè ø€ ðYð 	ð ˜×*Ñ*Ð+¨;°w·±Ð6GÐHˆð	”tõ 	ô &3Ø °Eô&
÷  
Ñˆˆd�Hô %Ø"×1Ñ1Ü×&Ñ&ØØ*¨8¨*Ð5Ü˜dŸh™h }Ó5Ò:¸Ó;Ü! $§(¡(Ð+<Ó"=Ò"DÀÓEØ—8‘8˜HÓ%Ø"Ÿh™hÐ':Ó;ô	
ð 		
ð 
ús   ƒ<C¿CÁ BCN)	rA   rB   rC   r   r   rz   r   r   rˆ   rD   rE   r,   rn   rn   “   s-   „ ð 
Ø.ð 
à	!ó 
ðD
Ð#7ð 
Ð<Qô 
rE   rn   c                   ó   — e Zd Zdedefd„Zy)ÚInterviewLockValidateServicer   r   c           	   ƒ   ój  K  — g }g }t        |j                  «      dk  r|j                  d«       t        |j                  «      D ��cg c]U  \  }}t	        |t
        «      r@|j                  d«      s/|j                  d«      st        |j                  d«      xs |«      ‘ŒW }}}|r&|j                  ddj                  |d d «      › �«       |j                  D ]m  }|j                  D �ch c]=  }t	        |t
        «      r+|j                  d«      rt        |j                  d«      «      ’Œ? }}||vsŒZ|j                  d	|› �«       Œo t        |j                  «      d
kD  r|j                  d«       t        |j                  t        j                  ddt        |«      dk(  ||¬«      S c c}}w c c}w ­w)Né   z%Need at least 3 questions before lockÚstemr+   ÚidzEmpty question stems: z, é   zMandatory question missing: é   z1Large question set may increase interview fatigueTz"Interview lock validation completer   )r2   r3   r4   r5   Úready_to_lockÚissuesÚwarnings)rX   Ú	questionsÚappendrT   Ú
isinstancer8   r:   ry   ÚjoinÚmandatory_question_idsr
   r2   r   r9   )	r=   r   r’   r“   rZ   r[   ÚemptyÚmidÚidss	            r,   Úvalidatez%InterviewLockValidateService.validate×   s•  è ø€ ð ˆØ ˆÜˆw× Ñ Ó! AÒ%Ø�M‰MÐAÔBô " '×"3Ñ"3Ô4ô
á4‘��1Ü˜!œTÔ"¨A¯E©E°&¬M¸Q¿U¹UÀ6¼]ô �—‘�d“Ò ˜qÕ!Ø4ð 	ñ 
ñ
 Ø�M‰MÐ2°4·9±9¸UÀ2ÀA¸YÓ3GÐ2HÐIÔJØ×1Ô1ˆCð !×*Ò*óá*�AÜ˜a¤Ô&¨1¯5©5°¬;ô �A—E‘E˜$“KÕ Ø*ð ð ð
 ˜#Š~Ø—‘Ð <¸S¸EÐBÕCð 2ô ˆw× Ñ Ó! BÒ&Ø�O‰OÐOÔPÜ,Ø"×1Ñ1Ü×&Ñ&ØØ8Ü˜f›+¨Ñ*ØØô
ð 	
ùó#
ùòùs(   ‚AF3ÁAF(Â"AF3Ã*AF.Ä,F3Ä3B F3N)rA   rB   rC   r	   r
   rœ   rD   rE   r,   rŠ   rŠ   Ö   s   „ ð 
Ø3ð 
à	&ô 
rE   rŠ   c                   ó   — e Zd Zdedefd„Zy)ÚFollowUpLogicServicer   r   c              ƒ   óâ  ‡K  — d}d‰j                   › d‰j                  j                  › d‰j                  › �}dt        fˆfd„}t        |||¬«      ƒ d {  –—† \  }}}|j                  d«      xs g D �cg c]¯  }t        |t        «      r�|j                  d	«      rŒ|j                  d
«      r{t        t        |j                  d	«      «      t        |j                  d«      xs d«      t        |j                  d
«      xs d«      t        |j                  d«      xs d«      ¬«      ‘Œ± }	}t        ‰j                  t        j                  |d|› �|	|j                  d«      ¬«      S 7 �Œc c}w ­w)Nz™Define adaptive follow-up logic for an interview pack. Return JSON: {"rules":[{"question_id","trigger","follow_up_prompt","max_depth"}],"logic_markdown"}rI   z

Persona: z
Questions: r   c            	      óR  •— g } t        ‰j                  «      D ]ˆ  \  }}t        |t        «      sŒt	        |j                  d«      xs d|dz   › �«      }t	        |j                  d«      xs |j                  d«      xs d«      }| j                  |dd|d d	 › d
�ddœ«       ŒŠ | ddœS )NrŽ   rM   rN   r�   r+   z
this topiczscore_below_0.6_or_vague_answerzProbe deeper on: éx   z6. Ask for a concrete example, metrics, and trade-offs.é   ©rP   ÚtriggerÚfollow_up_promptÚ	max_depthu�   # Follow-up logic

- If answer score < 0.6 â†’ ask clarifying example follow-up
- If answer is strong â†’ optional stretch follow-up (depth 1)
)ÚrulesÚlogic_markdown)rT   r”   r–   r8   ry   r:   r•   )r§   rZ   r[   r_   r�   r   s        €r,   r-   z*FollowUpLogicService.define.<locals>.local  s»   ø€ ØˆEÜ! '×"3Ñ"3Ö4‘��1Ü! !¤TÔ*ØÜ˜!Ÿ%™% ›+Ò5¨2¨a°!©e¨W¨Ó6�Ü˜1Ÿ5™5 ›=ÒI¨A¯E©E°&«MÒI¸\ÓJ�Ø—‘à'*Ø#Dà/°°T°c°
¨|ð <7ð 7ð &'ñõ
ð 5ð" ðWñð rE   r.   r§   rP   r¥   r¤   zscore_below_0.6Ú r¦   rN   r£   zFollow-up logic via r¨   )r2   r3   r4   r5   r§   r¨   )r7   Úpersonarx   r”   r8   r   r:   r–   r   ry   Úintr   r2   r   r9   )
r=   r   r/   r0   r-   r>   r4   r?   Úrr§   s
    `        r,   ÚdefinezFollowUpLogicService.defineû   ss  øè ø€ ð"ð 	ð �W×'Ñ'Ð(¨°G·O±O×4IÑ4IÐ3Jð KØ!×+Ñ+Ð,ð.ð 	ð
	”tõ 	ô6 &3Ø °Eô&
÷  
Ñˆˆd�Hð —X‘X˜gÓ&Ò,¨"Ð,ó	
ñ -�Ü˜!œTÔ" q§u¡u¨]Ô';ÀÇÁÐFXÔ@Yô Ü §¡ mÓ 4Ó5Ü˜AŸE™E )Ó,ÒAÐ0AÓBÜ!$ Q§U¡UÐ+=Ó%>Ò%DÀ"Ó!EÜ˜aŸe™e KÓ0Ò5°AÓ6ö	ð -ð 	ð 	
ô %Ø"×1Ñ1Ü×&Ñ&ØØ*¨8¨*Ð5ØØŸ8™8Ð$4Ó5ô
ð 	
ð 
ûò	
ùs%   ƒAE/ÁE'ÁE/Á6B4E*Ä*>E/Å*E/N)rA   rB   rC   r   r   r­   rD   rE   r,   rž   rž   ú   s   „ ð:
Ð$8ð :
Ð=Rô :
rE   rž   c                   ó   — e Zd Zdedefd„Zy)ÚMergeCustomQuestionsServicer   r   c              ƒ   óZ  K  — g }t        «       }t        |j                  «      t        |j                  «      z   D ]²  }t	        |t
        «      sŒt        |j                  d«      xs dt        |«      dz   › �«      }||v rŒF|j                  |«       t        |«      }||d<   ||j                  v r-|j                  d«      }t	        |t
        «      si }d|d<   ||d<   |j                  |«       Œ´ t        |j                  «      }|j                  D ][  }t	        |t
        «      sŒ|j                  d«      sŒ&|j                  d«      sŒ8t        |d   «      }	|	|vsŒK|j                  |	«       Œ] t        |j                  t        j                  dd	||t        |j                  «      ¬
«      S ­w)NrŽ   zcq-rN   ÚmetadataÚcompany_customÚsourceÚ	mandatoryTz3Custom company questions merged into interview pack)r2   r3   r4   r5   r”   r˜   Úadded_count)Úsetr;   Úexisting_questionsÚcustom_questionsr–   r8   ry   r:   rX   Úaddr•   r˜   r   r2   r   r9   )
r=   r   ÚmergedÚseenr[   r_   ÚrowÚmetar´   rš   s
             r,   Úmergez!MergeCustomQuestionsService.merge9  s}  è ø€ ð  ˆÜ›ˆÜ�g×0Ñ0Ó1´D¸×9QÑ9QÓ4RÔRˆAÜ˜a¤Ô&ØÜ�a—e‘e˜D“kÒ< s¬3¨v«;¸©?Ð*;Ð%<Ó=ˆCØ�d‰{ØØ�H‰H�SŒMÜ�q“'ˆCØˆC�‰IØ�G×,Ñ,Ñ,Ø—w‘w˜zÓ*�Ü! $¬Ô-Ø�DØ!1��X‘Ø"&��J‘Ø�M‰M˜#Õð Sô  ˜×7Ñ7Ó8ˆ	Ø×)Ô)ˆAÜ˜!œTÕ" q§u¡u¨[Õ'9¸a¿e¹eÀD½kÜ˜!˜D™'“l�Ø˜iÒ'Ø×$Ñ$ SÕ)ð	 *ô
 ,Ø"×1Ñ1Ü×&Ñ&ØØIØØ#,Ü˜G×4Ñ4Ó5ô
ð 	
ùs   ‚D!F+Ä$F+Ä6F+ÅF+ÅAF+N)rA   rB   rC   r   r   r¾   rD   rE   r,   r¯   r¯   8  s   „ ð#
Ø2ð#
à	%ô#
rE   r¯   N)%Ú__doc__Úuuidr   Úapp.schemas.commonr   Úapp.schemas.questionsr   Úapp.schemas.helpersr   r   r   r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   Úapp.services.ai_generater   Úapp.services.questionsr   r   r   rG   re   rn   rŠ   rž   r¯   rD   rE   r,   Ú<module>rÆ      sƒ   ðñõ å (Ý .÷÷ ÷ ÷ õ õ& 3ß E÷#
ñ #
÷L<
ñ <
÷~
ñ 
÷@
ñ @
÷F!
ñ !
÷H;
ñ ;
÷|$
ò $
rE   