
    fi'i                     `    S SK r S SKrS SKJrJrJrJr  S SKJrJ	r	J
r
JrJrJr   " S S5      rg)    N)DictListAnyOptional)SCENARIO_GENERATION_PROMPTCHARACTER_ROLEPLAY_PROMPTCHARACTER_CONCLUSION_PROMPT CHARACTER_GUIDED_ROLEPLAY_PROMPTSKILL_ANALYSIS_PROMPTget_skill_analysis_templatec                   &   \ rS rSrS$S\4S jjrS\S\4S jrS\S\\\	4   4S	 jr
S\\\	4   4S
 jrS rS%S\S\S\S\S\\\   \\\\	4      4   4
S jjrS\\\	4   S\\\\	4      4S jrS\\\\4      S\\\\4      S\4S jrS&S\\\	4   S\\\\4      S\S\S\\\\4      S\\   4S jjrS'S\\\	4   S\\\\4      S\S\\\\	4      4S jjrS\S\\   4S jrS\S\4S jrS\S\\\\	4      4S  jrS\\\	4   4S! jrS\4S" jrS#rg)(OllamaService   base_urlc                 L    Xl         SU l        SSSS.SSSS.SSSS.S.U l        g )Nz
gemma3:12br   inputoutputtotal)previewconversation
assessmentr   modeltoken_counts)selfr   s     I/var/www/eduai.edurigo.com/roleplay/production/services/ollama_service.py__init__OllamaService.__init__   s8     !
 "#a!<&'1qA$%Q?
    textreturnc                 2    [        S[        U5      S-  5      $ )uM   Estimate token count for text (rough approximation: 1 token ≈ 4 characters)      )maxlen)r   r!   s     r   _estimate_tokensOllamaService._estimate_tokens   s    1c$i1n%%r    operation_typeusage_statsc           
         U(       a  UR                  SS5      nUR                  SS5      nUR                  SX4-   5      nUS:  a  X4-   nU R                  U   S==   U-  ss'   U R                  U   S==   U-  ss'   U R                  U   S==   U-  ss'   [        S	U S
U SU SU 35        g[        SU S35        g)zDUpdate token counts for specific operation using actual Ollama statsprompt_eval_countr   
eval_counttotal_durationi r   r   r   zOLLAMA Token count for z: Input=z	, Output=z, Total=z%OLLAMA: No usage stats available for z, skipping token countN)getr   print)r   r*   r+   input_tokensoutput_tokenstotal_tokenss         r   _update_token_count!OllamaService._update_token_count   s    &??+>BL'OOL!<M&??+;\=YZL f$+;n-g6,F6n-h7=H7n-g6,F6+N+;8L>QZ[hZiiqr~q  A  B9.9II_`ar    c                 6    U R                   R                  5       $ )z+Get current token counts for all operations)r   copyr   s    r   get_token_countsOllamaService.get_token_counts0   s      %%''r    c                 P    U R                    H  nSSSS.U R                   U'   M     g)zReset all token countersr   r   N)r   )r   	operations     r   reset_token_counts OllamaService.reset_token_counts4   s)    **I56!a+PDi( +r    promptsystem_prompttemperature
max_tokensc                   #     U R                    S3n[        SU 35        [        SU R                   35        UnU(       a  SU SU 3nU R                  USUUS.S.n[        S	US
    35        [        R                  " SS9 ISh  vN nUR                  XWS9I Sh  vN n	SSS5      ISh  vN   [        SW	R                   35        U	R                  S:X  a  [        SU R                   S35        gU	R                  5         U	R                  5       n
U
R                  SS5      R                  5       nU
R                  SS5      U
R                  SS5      U
R                  SS5      U
R                  SS5      U
R                  SS5      S.n[        S[        U5       35        [        SU 35        X4$  GN. GN GN! , ISh  vN  (       d  f       GN#= f! [        R                   a0  n[        SU 35        [        S U R                    35         SnAgSnAf[        R                   a  n[        S!U 35         SnAgSnAf[        R                   aG  n[        S!U 35        UR                  b"  [        S"UR                  R                    35         SnAgSnAf["         a  n[        S#U 35         SnAgSnAff = f7f)$zEMake a request to Ollama API and return response text and usage statsz/api/generatez!DEBUG: Making Ollama request to: zDEBUG: Using model: zSystem: z

User: F)rB   num_predict)r   r@   streamoptionszDEBUG: Payload model: r   g      ^@timeoutN)jsonzDEBUG: Response status: i  zERROR: 404 - Model 'z>' not found. Available models can be checked with: ollama list)NNresponse r-   r   r.   r/   prompt_eval_durationeval_duration)r-   r.   r/   rM   rN   zDEBUG: Ollama response length: zDEBUG: Ollama usage stats: z#Error connecting to Ollama server: zMake sure Ollama is running on zError making Ollama request: zResponse content: z$Unexpected error in Ollama request: )r   r1   r   httpxAsyncClientpoststatus_coderaise_for_statusrJ   r0   stripr'   ConnectErrorRequestErrorHTTPStatusErrorrK   r!   	Exception)r   r@   rA   rB   rC   urlfull_promptpayloadclientrK   resultresponse_textr+   es                 r   _make_requestOllamaService._make_request9   s    =	]]O=1C5cU;<(56 !K (z&J %#.#-	G *77+;*<=>((776!'S!?? 87 ,X-A-A,BCD##s*,TZZL8vwx!%%']]_F"JJz26<<>M%+ZZ0CQ%G$jjq9"(**-=q"A(.

3I1(M!'OQ!?K 3C4F3GHI/}=> --/ 8? 87772 !! 	7s;<3DMM?CD!! 	1!56$$ 	21#67

&*1::??*;<= 	8<=	s   KBG F5G F>F8F>#G .F;/AG 4K5B?G 4K5G 8F>;G >GGGG K -&HKK /I=KK =JKK (J;6K;K  Kadmin_inputc           	      z  #     SnUS   R                  5        H  u  p4X# SU S3-  nM     SnUR                  S5      nU(       a1  Sn[        US5       H  u  pxXW SUR                  S	S5       S3-  nM!     [        R                  " US
   US   X%-   SR                  US   5      S9n	Sn
U R                  U	U
SSS9I Sh  vN u  pU(       d  gU R                  SU5         UR                  S5      (       a  USS nOUR                  S5      (       a  USS nUR                  S5      (       a  USS n[        R                  " UR                  5       5      $  N! [        R                   a&  n[        SU 35        [        SU 35         SnAgSnAff = f! [         a  n[        SU 35         SnAgSnAff = f7f)z-Generate structured scenario from admin inputrL   details: 
roleplay_questionszO
GUIDED CONVERSATION QUESTIONS (The scenario should accommodate THESE topics):
r$   . questioncategory	objective, skills_to_assess)rj   rk   rd   skillszHYou are a training scenario expert. Always respond with valid JSON only.ffffff?   r@   rA   rB   rC   Nr   ```json   ```   zJSON parsing error: Response text: z'Error generating scenario with Ollama: )itemsr0   	enumerater   formatjoinr`   r5   
startswithendswithrJ   loadsrT   JSONDecodeErrorr1   rX   )r   rb   details_textkeyvaluequestions_textrg   idxqr@   rA   r^   r+   r_   s                 r   generate_scenarioOllamaService.generate_scenarioz   s    6	L))4::<
%r% 33 =  N!,1E!F!!t'(:A>FC"Rj"0E/Fb&IIN ? 066$Z0%k2$5yy-?!@A	F gM/3/A/A+	 0B 0 *&M ! $$Y< ++I66$1!"$5M"--e44$1!"$5M ))%00$1#2$6Mzz-"5"5"788/*0 '' ,QC0178
  	;A3?@	sx   F;B;F ?E F F;F !A5E F;F F-F	F F;FF 
F8 F3.F;3F88F;rg   conversation_historyc           
        ^ U(       d  gSR                  U Vs/ s H  o3R                  SS5      PM     sn5      R                  5       m/ n[        US5       H  u  pVUR                  SS5      R                  5       nUR	                  5       SS n[        U4S	 jU 5       5      n	U	(       a  S
OSn
UR                  SU SUR                  SS5       SU
 35        M     [        U5       H  u  pVUR                  SS5      R                  5       nUR	                  5       SS n[        U4S jU 5       5      n	U	(       a  MV  UR                  SUS-    SUR                  SS5       35          O   SR                  U5      $ s  snf )z
Analyze conversation history to determine which guided questions have been addressed.
Returns a formatted string explaining the progression status.
z&No guided questions for this roleplay. messagerL   r$   ri   Nru   c              3   P   >#    U  H  n[        U5      S :  d  M  UT;   v   M     g7fru   Nr'   .0keywordconversation_texts     r   	<genexpr>>OllamaService._analyze_question_progression.<locals>.<genexpr>   )     eWTWX_T`cdTd8G'88   &&u   ✓ ADDRESSEDu   ⚠ NOT YET ADDRESSEDz	Question re    - c              3   P   >#    U  H  n[        U5      S :  d  M  UT;   v   M     g7fr   r   r   s     r   r   r      r   r   z
**NEXT FOCUS**: Question rf   )r{   r0   lowerry   splitanyappend)r   rg   r   turnprogression_linesr   r   question_textkeywords	addressedstatusr   s              @r   _analyze_question_progression+OllamaService._analyze_question_progression   st   
 ";  HHJ^%_J^$hhy"&=J^%_`ffh 2A6FCEE*b1779M$**,Ra0HeeeI(1_7NF$$yRj"8M7NcRXQY%Z[ 7   23FCEE*b1779M$**,Ra0HeeeI9!((+FsQwisSTSXSXYcegShRi)jk 4 yy*+++ &`s   E=Nscenariouser_messageis_conclusionc                   #     SnU H#  nUS   S:X  a  SOUS   S   nXh SUS    S	3-  nM%     [        U V	s/ s H  oR                  S5      S:X  d  M  U	PM     sn	5      S
-   n
UR                  SS5      nUR                  SS5      nUR                  SS5      nUR                  SS5      nUR                  SS5      nU(       aR  [        nUS   S   US   S   US   S   US   S   US   R                  SS5      US   S   US   S   US   S   UUS.
nGOU(       a  [        nSn[	        US
5       H!  u  nnUU SUR                  SS5       S	3-  nM#     U R                  XR5      n0 S US   S   _SUS   S   _SUS   S   _SUS   S   _SUS   R                  SS5      _SUS   S   _SUS   S   _S!UR                  S!S5      _S"UR                  S#0 5      R                  SS5      _SUS   S   _S$U_S%U_S&U_S'U_SU_S(U_SU_UUU
S).EnO[        n0 S US   S   _SUS   S   _SUS   S   _SUS   S   _SUS   R                  SS5      _SUS   S   _SUS   S   _S!UR                  S!S5      _S"UR                  S#0 5      R                  SS5      _SUS   S   _S&U_S'U_SU_S(U_SU_SU_SU_S*U
0EnUR                  " S30 UD6nS+nU R                  UUS,S-S.9I S/h  vN u  nnU(       a  U R                  S0U5        U(       a  U$ S1$ s  sn	f  N0! [         a  n[        S2U 35         S/nAg1S/nAff = f7f)4z&AI character responses during roleplayrL   speakerlearnerLearnerai_characternamere   r   rf   r$   roleplay_namezRoleplay Sessionai_role	Characterlearner_role
difficultymediumdurationi,  personalitygoals
backgroundemotional_stateneutralscenario_setupcontextenvironmentconstraints)
character_namer   r   r   r   r   r   r   r   r   rh   ri   r   rk   additional_inford   guided_questionsquestion_progress_analysisr   r   character_role)r   r   current_turnr   a"  You are a world-class roleplay AI. You MUST stay strictly in character as a human-like counterpart (client, customer, etc.). You NEVER break character. You MUST follow the provided 'MANDATORY GUIDED QUESTIONS' if they exist. Respond professionally, naturally, and concisely (1-3 sentences).g?i   rq   Nr   z:I'm having trouble responding right now. Please try again.z)Error in character roleplay with Ollama:  )r'   r0   r	   r
   ry   r   r   rz   r`   r5   rX   r1   )r   r   r   r   r   rg   history_textr   r   tr   r   r   r   r   r   prompt_templateprompt_kwargsr   r   r   question_progressr@   rA   rK   r+   r_   s                              r   play_characterOllamaService.play_character   s!    i	PL,'+I)'C)R`IabhIi)2d9o->b AA -
 +?a+?a55CSW`C`+?abeffL %LL:LMM%\\)[AN#<<	BL!lH=J||J4H"=&.~&>v&F#+N#;M#J%n5g>"*>":<"H'/'?'C'CDUW`'a'(89)D#+,<#=m#L#+,<#=m#L,8$0! $"B!#'(:A>FC"Rj"0E/Fb&IIN ? %)$F$FGY$p!!$h~&>v&F!!8N#;M#J! Xn5g>! !(>":<"H	!
 &x'?'C'CDUW`'a! x(89)D! "8,<#=m#L!  k2!>! &x||Ir'B'F'F|UW'X! "8,<#=m#L! '! 12C! +L! #L! $]!  %n!!" #L#!$ #- ($0)!. #<!$h~&>v&F!!8N#;M#J! Xn5g>! !(>":<"H	!
 &x'?'C'CDUW`'a! x(89)D! "8,<#=m#L!  k2!>! &x||Ir'B'F'F|UW'X! "8,<#=m#L! +L! #L! $]! %n! #L!  !*!!" #!$ #L%!* %++<m<F AM*.*<*<+	 += + %!Hk ((E'8i-ii{  bd%  	P=aSABO	Ps^   L>4L LLJL &L'(L L>L L>L 
L;#L61L>6L;;L>conversation_turnsengagement_metadatac                   ^#     SnU H  nUS   S:X  a  SOSnXF SUS    S3-  nM     S	US
    SUS    SUS   S    SUS    SUS   S    SUS   S    S3nUS   n[        U5      n	[        R                  " SR                  U5      UUUU	S9n
SnU R	                  U
USSS9I Sh  vN u  pU(       d  gU R                  SU5         UR                  S 5      (       a  US!S nOUR                  S"5      (       a  US#S nUR                  S"5      (       a  USS$ nUR                  5       nU R                  U5      n[        R                  " U5      m[        U4S% jS& 5       5      (       d  [        S'5        gT$  N! [        R                   a7  n[        S(U 35        [        S)U 35        U R                  U5      s SnA$ SnAff = f! [          a  n[        S*U 35         SnAgSnAff = f7f)+z:Comprehensive skill analysis with engagement-aware scoringrL   r   r   r   zAI Characterre   r   rf   z
Category: rj   z
Objective: rk   z

Context: r   r   z
Success Criteria: success_criteriaz
AI Character: r   r   r   r   rm   rl   )rn   scenario_contextr   r   skill_analysis_templatezYou are an expert skill assessor. Provide STRICT, ACCURATE analysis in valid JSON format only. Do NOT inflate scores. Follow the engagement-based score ceilings exactly.g333333?i  rq   Nr   rr   rs   rt   ru   rv   c              3   ,   >#    U  H	  oT;   v   M     g 7f)Nr   )r   r   analysiss     r   r   /OllamaService.analyze_skills.<locals>.<genexpr>  s       M  7Ls(?  7Ls   skill_analysisoverall_performanceconversation_analysisrecommendationszAnalysis missing required keysz JSON parsing error in analysis: rw   z$Error analyzing skills with Ollama: )r   r   rz   r{   r`   r5   r|   r}   rT   _sanitize_json_textrJ   r~   allr1   r   _try_json_fallbacksrX   )r   r   r   r   r   r   r   r   rn   skill_templater@   rA   r^   r+   r_   r   s                  @r   analyze_skillsOllamaService.analyze_skillsA  s    K	 "*'+I)'C)!y4	?2C2%FF! +
$J
  ![!" #

#
$Y
/	0 1./0 1'/0H^4L\4Z3[ \  01F8@N*11yy(!1$7.(6F HM/3/A/A+	 0B 0 *&M ! $$\;?? ++I66$1!"$5M"--e44$1!"$5M ))%00$1#2$6M - 3 3 5 !% 8 8 G::m4   M  7L  M  M  M:;G*J '' ?8<=78 //>>?  	8<=	s   G0B#G (E;)G 6G07G 
B.E= 8G09E= :G0;G =G,G=G>G G0GG 
G-G(#G0(G--G0c                    #     SnU R                  UUSSS9I Sh  vN u  p4U(       a  U R                  SU5        U$  N!! [         a  n[        SU 35         SnAgSnAff = f7f)z(Get a simple text completion from Ollamaz]You are a helpful assistant. Provide clear, natural responses without any formatting symbols.ro   i  rq   Nr   z&Error getting completion from Ollama: )r`   r5   rX   r1   )r   r@   rA   rK   r+   r_   s         r   get_completionOllamaService.get_completion  s{     	{M*.*<*<+	 += + %!H ((K@O%  	:1#>?	s7   A$? = ? A$? 
A!	AA$A!!A$c                 0    UnSSK nUR                  SSU5      nUR                  SSU5      nUR                  SS5      R                  SS5      nUR                  SS	5      nUR                  S
SU5      nUR                  SSU5      nUR                  SSU5      nUR                  S5      n[	        U5       H  u  pVSU;   d  M  UR                  5       R                  S5      (       d  M3  UR                  SS5      n[        U5      S:X  d  MV  US   R                  5       nUR                  S5      S-  S:w  d  M  UR                  SSU5      nUS   S-   U-   XE'   M     SR                  U5      nU$ ! [         a  n	[        SU	 35        Us Sn	A	$ Sn	A	ff = f)z6Sanitize JSON text to fix common issues before parsingr   Nz
(\w+)n's\bz\1n'tz	(\w+)'s\bz\1's"z, "'").replace('z,(\s*[}\]])z\1z}\s*{z},{z]\s*\[z],[rf   :r$      z+(?<!^")(?<!: ")(?<![\[\{] ")"(?!"[\s,\]\}])z\"re   zError sanitizing JSON: )resubreplacer   ry   rT   r}   r'   countr{   rX   r1   )
r   r!   	sanitizedr   linesilinekey_val
value_partr_   s
             r   r   !OllamaService._sanitize_json_text  s   ,	I  }h	BI|Wi@I "))#s3;;CEI!))*?EI ~ui@I x;Iy&)<I OOD)E$U+$;4::<#8#8#=#="jja0G7|q(%,QZ%5%5%7
%++C0149)+0^`egq)rJ'.qzD'8:'EEH , 		%(I 	+A3/0K	s6   B>E1 "E1 *E1 )E1 :6E1 1
F;F
FFc                    SSK n UR                  SXR                  5      nU(       aD  UR                  5       nU R	                  U5      n[
        R                  " U5      n[        S5        U$   [        S5        UR                  SXR                  5      nUR                  SXR                  5      n	UR                  S	XR                  5      n
UR                  S
XR                  5      n[        XX/5      (       a  SnXR                  5       S-   -  nXR                  5       S-   -  nXR                  5       S-   -  nXR                  5       -  nUS-  nU R	                  U5      n[
        R                  " U5      n[        S5        U$  [        S5        U R                  5       $ ! [         a  n[        SU 35         SnAGNTSnAff = f! [         a  n[        SU 35         SnAN^SnAff = f)z3Try multiple fallback methods to extract valid JSONr   Nz\{.*\}zBSuccessfully extracted JSON using regex fallback with sanitizationz)Regex fallback with sanitization failed: z+Attempting to reconstruct JSON structure...z$"skill_analysis":\s*\{.*?\}(?=,\s*")z)"overall_performance":\s*\{.*?\}(?=,\s*")z+"conversation_analysis":\s*\{.*?\}(?=,\s*")z"recommendations":\s*\{.*?\}{,}z-Successfully reconstructed JSON from sectionszJSON reconstruction failed: zDAll JSON parsing attempts failed, creating minimal fallback response)r   searchDOTALLgroupr   rJ   r~   r1   rX   r   _create_fallback_assessment)r   r!   r   
json_matchextracted_jsonsanitized_jsonr   r_   skill_analysis_matchoverall_performance_matchconversation_analysis_matchrecommendations_matchreconstructeds                r   r   !OllamaService._try_json_fallbacks  s   		C9dII>J!+!1!1!3!%!9!9.!I::n5Z[ 	6?@ $&99-TVZ\e\e#f (*		2^`dfofo(p%*,))4bdhjsjs*t'$&II.MtU^U^$_!(E`xyy #!;!;!=!CC!@!@!BS!HH!B!B!Ds!JJ!<!<!>>$ $ 8 8 G::m4EF z" 	TU//11A  	C=aSABB	C6  	60455	6s1   A&F$ /DG
 $
G.GG

G,G''G,c                 J    SSS/S/S/S.0SSSSS	.S
/S/S/S.S/S/S/S.S.$ )z<Create a basic assessment when JSON parsing completely failszOverall Performance   z9Assessment could not be completed due to technical issueszSession completed successfullyz;Unable to provide detailed feedback due to technical issues)scoreevidence	strengthsimprovement_areaszAssessment Unavailabler$   )weighted_scoreperformance_leveltotal_turnsconversation_qualityzSession completedzAssessment unavailablez)Unable to analyze due to technical issues)r  critical_momentsmissed_opportunitiesz.Please retry the session for detailed feedbackz,Technical issues prevented detailed analysisz'Retry recommended for proper assessment)immediate_focuspractice_suggestionsadvanced_skillsr   r   r9   s    r   r   )OllamaService._create_fallback_assessment  sv     &!\ ]"B!C*g)h	( #$%= (c	$ 22%=$>)T(U& %U#U)W(X$M#N )
 	
r    c                   #     U R                    S3n[        SU 35        [        R                  " SS9 ISh  vN nUR	                  U5      I Sh  vN nSSS5      ISh  vN   [        SWR
                   35        UR
                  S:X  a  UR                  5       R	                  S/ 5      nU Vs/ s H  oUR	                  S	S
5      PM     nn[        SU 35        U R                  U;  a(  [        SU R                   S35        [        SU 35        ggg N N N! , ISh  vN  (       d  f       N= fs  snf ! [         a  n[        SU 35         SnAgSnAff = f7f)z$Check if Ollama service is availablez	/api/tagsz"DEBUG: Checking Ollama health at: g      @rH   Nz%DEBUG: Health check response status:    modelsr   rL   zDEBUG: Available models: zWARNING: Model 'z' not found in available modelszAvailable models: FTzDEBUG: Health check failed: )	r   r1   rO   rP   r0   rR   rJ   r   rX   )r   rY   r\   rK   r  r   model_namesr_   s           r   health_checkOllamaService.health_check"  s=    	]]O9-C6se<=((55!'C0 65 9(:N:N9OPQ##s*!,,Xr:BHI&yy4&I1+?@::[0,TZZL8WXY.{m<= # 60 6555 J  	045	s   E"5D= DD= DDDD= "D#AD= 3D8AD= E"D= DD= D5$D'%D51D= =
EEE"EE"r   )zhttp://127.0.0.1:11434)rL   ro   rp   )FN)rL   )__name__
__module____qualname____firstlineno__strr   intr(   r   r   r5   r:   r>   floattupler   r`   r   r   r   boolr   r   r   r   r   r   r  __static_attributes__r   r    r   r   r      s   	
 	
&S &S &b# bDcN b&($sCx. (Q
?# ?c ?UZ ?nq ?  ~C  DL  MP  DQ  S[  \`  ad  fi  ai  \j  Sk  Dk  ~l ?B84S> 8htTWY\T\~F^ 8t,T#s(^@T ,lpquvy{~v~q  mA ,  FI ,@kPT#s(^ kPSWX\]`be]eXfSg kPwz kP  LP kP  nr  sw  x{  }@  x@  sA  nB kP  NV  WZ  N[ kPZMT#s(^ MQUVZ[^`c[cVdQe M| M  JR  SW  X[  ]`  X`  Sa  Jb M^3 8C= ,. . .`-2 -2c3h0H -2^
T#s(^ 
:D r    r   )rJ   rO   typingr   r   r   r   config.promptsr   r   r	   r
   r   r   r   r   r    r   <module>r&     s'      , , o or    