o
    .i]M                     @   sv   d dl Z d dlZd dlZd dlZd dlmZmZmZmZ d dl	m
Z
 d dlmZmZmZmZmZmZ G dd dZdS )    N)DictListAnyOptional)	AsyncGroq)SCENARIO_GENERATION_PROMPTCHARACTER_ROLEPLAY_PROMPTCHARACTER_CONCLUSION_PROMPT CHARACTER_GUIDED_ROLEPLAY_PROMPTSKILL_ANALYSIS_PROMPTget_skill_analysis_templatec                   @   sD  e Zd Zdd ZdefddZdeeef fddZd	d
 Z	deeef de
eeef  fddZdeeeef  deeeef  defddZd$deeef deeeef  dededeeeef  de
e fddZd%deeef deeeef  dede
eeef  fddZdede
e fdd Zd!ede
e fd"d#ZdS )&GroqServicec                 C   s   ddl m} |  td}|s#td td td d | _d| _n	t|d| _d	| _d
| _ddddddddddddd| _	d S )Nr   )load_dotenvGROQ_API_KEYu@   ⚠️  WARNING: GROQ_API_KEY not found in environment variablesuL       ℹ️  Groq service will not be available. System will use Ollama only.uJ       ℹ️  To use Groq, set GROQ_API_KEY in your .env file or environmentF)api_keyTzopenai/gpt-oss-20binputoutputtotal)previewconversation
assessment)
dotenvr   osgetenvprintclient	availabler   modeltoken_counts)selfr   r    r!   G/var/www/eduai.edurigo.com/roleplay/production/services/groq_service.py__init__   s    



zGroqService.__init__operation_typec              	   C   s   |rHt |drJt |drL|j}|j}|j}| j| d  |7  < | j| d  |7  < | j| d  |7  < td| d| d| d	|  d
S d
S d
S d
S )z*Update token counts for specific operationprompt_tokenscompletion_tokensr   r   r   zGROQ Token count for z: Input=z	, Output=z, Total=N)hasattrr%   r&   total_tokensr   r   )r    r$   usage_statsinput_tokensoutput_tokensr(   r!   r!   r"   _update_token_count(   s   $zGroqService._update_token_countreturnc                 C   s
   | j  S )z+Get current token counts for all operations)r   copy)r    r!   r!   r"   get_token_counts5   s   
zGroqService.get_token_countsc                 C   s"   | j D ]}dddd| j |< qdS )zReset all token countersr   r   N)r   )r    	operationr!   r!   r"   reset_token_counts9   s   
zGroqService.reset_token_countsadmin_inputc              
      s  zd}|d   D ]\}}|| d| d7 }q
d}|d}|r<d}t|dD ]\}}|| d|d	d d7 }q)tj|d
 |d |d |d || d|d d}	| jjjj	dddd|	dg| j
dddI dH }
| d|
j |
jd jj }z|dr|dd }|dr|dd }t|W W S  tjy } ztd|  td |  W Y d}~W dS d}~ww  ty } ztd!|  W Y d}~dS d}~ww )"z-Generate structured scenario from admin input details: 
roleplay_questionszO
GUIDED CONVERSATION QUESTIONS (The scenario should accommodate THESE topics):
   . questioncategory	objectivelearner_roleai_role, skills_to_assess)r;   r<   r=   r>   r4   skillssystemzHYou are a training scenario expert. Always respond with valid JSON only.rolecontentuserffffff?i   messagesr   temperature
max_tokensNr   r   ```json   ```zJSON parsing error: Response text: zError generating scenario: )itemsget	enumerater   formatjoinr   chatcompletionscreater   r,   usagechoicesmessagerE   strip
startswithendswithjsonloadsJSONDecodeErrorr   	Exception)r    r2   details_textkeyvaluequestions_textr7   idxqpromptresponseresponse_texter!   r!   r"   generate_scenario>   sd   

	


zGroqService.generate_scenarior7   conversation_historyc           
   
      s  |sdS d dd |D   g }t|dD ]7\}}|dd }| dd	 }t fd
d|D }|r:dnd}	|d| d|dd d|	  qt|D ]4\}}|dd }| dd	 }t fdd|D }|s|d|d  d|dd   nqSd |S )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. c                 S   s   g | ]}| d dqS )r[   r3   rR   ).0turnr!   r!   r"   
<listcomp>   s    z=GroqService._analyze_question_progression.<locals>.<listcomp>r8   r:   r3   N   c                 3   $    | ]}t |d kr| v V  qdS rt   Nlenrq   keywordconversation_textr!   r"   	<genexpr>      " z<GroqService._analyze_question_progression.<locals>.<genexpr>u   ✓ ADDRESSEDu   ⚠ NOT YET ADDRESSEDz	Question r5    - c                 3   ru   rv   rw   ry   r{   r!   r"   r}      r~   z
**NEXT FOCUS**: Question r6   )rU   lowerrS   rR   splitanyappend)
r    r7   rn   progression_linesrg   rh   question_textkeywords	addressedstatusr!   r{   r"   _analyze_question_progression~   s&   &"
z)GroqService._analyze_question_progressionFNscenariouser_messageis_conclusionc                    s  zd}|D ]}|d dkrdn|d d }|| d|d  d	7 }qt d
d |D d }	|dd}
|dd}|dd}|dd}|dd}|rt}|d d |d d |d d |d d |d dd|d d |d d |d d ||d
}n|rt}d}t|dD ]\}}|| d |d!d d	7 }q| ||}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%i ddd|d d d&|d'|d(|d)|d|
d*|d||||	d+}nit}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%i ddd|d d d(|d)|d|
d*|d|d|d|d,|	i}|jd9i |}| jj	j
jd-d.d/d0|d/g| jd1d2d3I d4H }| d5|j |jd6 jj W S  ty } ztd7|  W Y d4}~d8S d4}~ww ):z&AI character responses during roleplayr3   speakerlearnerLearnerai_characternamer5   r[   r6   c                 S   s   g | ]}| d dkr|qS )r   r   rp   )rq   tr!   r!   r"   rs      s    z.GroqService.play_character.<locals>.<listcomp>r8   roleplay_namezRoleplay Sessionr>   	Characterr=   
difficultymediumdurationi,  personalitygoals
backgroundemotional_stateneutralscenario_setupcontextenvironmentconstraints)
character_namer   r   r   r   r   r   r   rn   r   r9   r:   r   r<   additional_infor4   guided_questionsquestion_progress_analysisrn   r   character_role)r   r   current_turnr   rB   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).rC   rF   g?i   rH   Nr   r   zError in character roleplay: z:I'm having trouble responding right now. Please try again.r!   )rx   rR   r	   r
   rS   r   r   rT   r   rV   rW   rX   r   r,   rY   rZ   r[   rE   r\   rb   r   )r    r   rn   r   r   r7   history_textrr   r   r   r   r   r=   r   r   prompt_templateprompt_kwargsrf   rg   rh   question_progressri   rj   rl   r!   r!   r"   play_character   s   






	

	


zGroqService.play_characterr3   conversation_turnsengagement_metadatac                    st  zd}|D ]}|d dkrdnd}|| d|d  d7 }qd	|d
  d|d  d|d d  d|d  d|d d  d|d d  d}|d }t |}	tjd|||||	d}
| jjjjdddd|
dg| jddd I d!H }| 	d"|j
 |jd# jj }zB|d$r|d%d! }n|d&r|d'd! }|d&r|d!d( }| }t| t fd)d*d+D std, W W d!S  W W S  tjy } zJtd-|  td.|  d#d!l}|d/||j}|rzt|  td0  W W  Y d!}~W S  tjy   td1 Y nw W Y d!}~W d!S d!}~ww  ty9 } ztd2|  W Y d!}~d!S d!}~ww )3z:Comprehensive skill analysis with engagement-aware scoringr3   r   r   r   zAI Characterr5   r[   r6   z
Category: r;   z
Objective: r<   z

Context: r   r   z
Success Criteria: success_criteriaz
AI Character: r   r   r   r   r@   r?   )rA   scenario_contextr   r   skill_analysis_templaterB   zYou 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.rC   rF   g333333?i  rH   Nr   r   rL   rM   rN   rt   rO   c                 3   s    | ]}| v V  qd S )Nr!   )rq   rd   analysisr!   r"   r}   Q  s    z-GroqService.analyze_skills.<locals>.<genexpr>)skill_analysisoverall_performanceconversation_analysisrecommendationszAnalysis missing required keysz JSON parsing error in analysis: rP   z\{.*\}z0Successfully extracted JSON using regex fallbackzRegex fallback also failedzError analyzing skills: )r   r   rT   rU   r   rV   rW   rX   r   r,   rY   rZ   r[   rE   r\   r]   r^   r_   r`   allr   ra   researchDOTALLgrouprb   )r    r   r   r   r|   rr   r   r   rA   skill_templateri   rj   rk   rl   r   
json_matchr!   r   r"   analyze_skills  s   








zGroqService.analyze_skillsri   c              
      s   z)| j jjjdddd|dg| jdddI dH }| d	|j |jd
 jj	
 W S  tyD } ztd|  W Y d}~dS d}~ww )z)Get a simple text completion from the LLMrB   z]You are a helpful assistant. Provide clear, natural responses without any formatting symbols.rC   rF   rG   i  rH   Nr   r   zError getting completion: )r   rV   rW   rX   r   r,   rY   rZ   r[   rE   r\   rb   r   )r    ri   rj   rl   r!   r!   r"   get_completionl  s*   

zGroqService.get_completiontextc              
      sf  | j sdS |rt| dkrdS |dd }z~td}d}d| dd}d	d
|dd}td|dd  d tjdd4 I dH }|j|||dI dH }W d  I dH  n1 I dH saw   Y  |j	dkr|j
}|rt|d}	tdt|	 d |	W S W dS td|j	 d|j  W dS  ty }
 ztdt|
  W Y d}
~
dS d}
~
ww )z
        Generate human-like voice using Groq's TTS model.
        Uses direct HTTP request to avoid SDK version conflicts.
        Returns base64 encoded audio string.
        Nr   i  r   z+https://api.groq.com/openai/v1/audio/speechzBearer zapplication/json)AuthorizationzContent-Typezcanopylabs/orpheus-v1-englishtaramp3)r   voicer   response_formatz*INFO: Requesting TTS from Groq for text: '   z...'g      >@)timeout)headersr_      zutf-8z'SUCCESS: Generated TTS base64 (length: )zERROR: Groq TTS API returned r5   zEXCEPTION in generate_tts: )r   rx   r\   r   r   r   httpxAsyncClientpoststatus_coderE   base64	b64encodedecoder   rb   str)r    r   r   urlr   payloadr   rj   
audio_data	b64_audiorl   r!   r!   r"   generate_tts  sF   
(
zGroqService.generate_tts)FN)r3   )__name__
__module____qualname__r#   r   r,   r   r   r/   r1   r   rm   r   r   boolr   r   r   r   r!   r!   r!   r"   r      s    &.@H <s[r   )r   r_   r   r   typingr   r   r   r   groqr   config.promptsr   r   r	   r
   r   r   r   r!   r!   r!   r"   <module>   s     	