o
    Rûif.  ã                
   @   s¸  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 ejejdd e d¡Ze d¡ e j d	e j e j e j e¡¡d
¡¡Ze jedd e j dd¡Ze j dd¡Zee j dd¡ƒZG dd„ deeƒZde defdd„Z!de defdd„Z"d6dededede	e fdd „Z#d!e$de$fd"d#„Z%d$d%„ Z&de d&ede$fd'd(„Z'd)d*„ Z(d+d,„ Z)d-d.„ Z*de de$fd/d0„Z+de d1ee$ de$fd2d3„Z,de de$fd4d5„Z-dS )7é    N)ÚEnum)ÚDictÚListÚOptionalÚAny)Údatetimez4%(asctime)s | %(levelname)s | %(name)s | %(message)s)ÚlevelÚformatÚassessment_report_processorzDInitializing Question Bank Training Processor [Version 3.0.0-LIGHT].ÚTRAINED_DATA_DIRÚtrained_dataT©Úexist_okÚ
OLLAMA_URLz#http://localhost:11434/api/generateÚOLLAMA_MODELz	gemma3:4bÚOLLAMA_TIMEOUTg      >@c                   @   s   e Zd ZdZdZdZdZdS )ÚTrainingStatusÚqueuedÚ
processingÚ	completedÚfailedN)Ú__name__Ú
__module__Ú__qualname__ÚQUEUEDÚ
PROCESSINGÚ	COMPLETEDÚFAILED© r   r   úk/var/www/eduai.edurigo.com/assessment_competency_evaluation/testing/assessment_report_analysis_processor.pyr      s
    r   Ú	client_idÚreturnc                 C   s   t j tt| ƒ¡S )N)ÚosÚpathÚjoinÚ	DATA_ROOTÚstr)r    r   r   r   Ú_client_dir   s   r'   c                 C   s   t | ƒ}tj|dd |S )NTr   )r'   r"   Úmakedirs)r    r#   r   r   r   Ú_ensure_client_dir    s   r)   Ú Úquestion_textÚcategory_hintÚoptionsc              
   C   s  | sdS d| › d|› d|› d}z_t jtt|dddd	œd
œtd}|jdkrm| ¡  dd¡ ¡ }| 	d¡d  ¡ }| 
d¡ ¡ }ddddddddddœ	}| ¡ |v rY|| ¡  W S t| 	¡ ƒdkre| ¡ }|rj|W S dW S W dS  tyŠ } zt d|› ¡ W Y d}~dS d}~ww )zNUses Ollama gemma3:4b to classify the question into a professional competency.Nap  
    Act as a Senior Academic Consultant and Competency Mapping Expert.
    Your task is to identify the single most accurate 'Professional Competency' for the question provided.

    STANDARDIZATION GUIDELINES:
    1. Use FORMAL, FULL NAMES (e.g., use 'Mathematics' instead of 'Math').
    2. Use BROAD PROFESSIONAL DOMAINS (e.g., use 'English Language' instead of 'Grammar' or 'English Grammar').
    3. Use TITLE CASE (e.g., 'General Knowledge' instead of 'general knowledge').
    4. NO ABBREVIATIONS (e.g., 'General Knowledge' instead of 'GK').
    5. Prioritize the Question Text and Options; use the Category Hint only for context.
    6. Return ONLY the competency name. No prefixes, no punctuation, no extra words.

    EXAMPLES OF PREFERRED TERMS:
    - Arithmetic/Algebra/Calculus -> Mathematics
    - Grammar/Vocabulary/Verbal -> English Language
    - Logic/Aptitude -> Logical Reasoning
    - Programming/Code -> Software Development
    - Physics/Chemistry/Biology -> [Subject Name]
    - Historical Events/Dates -> History
    - Geography/Maps -> Geography
    - Sports/Athletes -> General Knowledge

    Question Text: z
    Options: z
    Category Hint: z

    Professional Competency:Fg        gÍÌÌÌÌÌì?)ÚtemperatureÚtop_p)ÚmodelÚpromptÚstreamr-   )ÚjsonÚtimeoutéÈ   Úresponser*   Ú
r   z.:!ÚMathematicszEnglish LanguageúGeneral KnowledgezLogical ReasoningÚHistory)	ÚmathÚmathsÚgrammarzenglish grammarÚgkÚlogicÚaptitudezhistorical awarenessÚ
historicalé   zOllama classification failed: )ÚhttpxÚpostr   r   r   Ústatus_coder3   ÚgetÚstripÚsplitÚrstripÚlowerÚlenÚtitleÚ	ExceptionÚloggerÚwarning)r+   r,   r-   r1   r6   ÚresultÚnormalization_mapÚer   r   r   Ú_classify_with_ollama%   s^   êéèþü	õ
÷æý€ýrS   Úqc                 C   sÞ   t |  dd¡ƒ}t |  d¡pdƒ ¡ }t |  d¡pdƒ ¡ }t |  d¡p%dƒ ¡ }t|||ƒ}|sV| d¡d  d	¡d  ¡ }|rG| ¡ d
v rJd}n| ¡ }| ¡ dkrVd}|||t|ƒdkrg|dd… d n||  d¡dœS )zVExtracts competency and other metadata from a question record using LLM with fallback.Úidr*   ÚcategoryNamer9   ÚquestionTextÚquestionOptionú>r   ú-)z
input typeÚtestÚuncategorizedÚdefaultr>   éd   Nú...ÚquestionType)Úquestion_idÚ
competencyÚcategoryÚquestion_text_previewÚquestion_type)r&   rF   rG   rS   rH   rJ   rL   rK   )rT   ÚqidÚcatÚtextÚoptsÚskillÚroot_domainr   r   r   Ú_classify_questionu   s$   ûrl   c                 C   s‚   t j t| ƒd¡}t j |¡sd S zt|dƒ}t |¡W  d   ƒ W S 1 s(w   Y  W d S  tjy@   t	j
jddœ Y S w )Nústatus.jsonÚrzCorrupted status file)ÚstatusÚerror)r"   r#   r$   r'   ÚexistsÚopenr3   ÚloadÚJSONDecodeErrorr   r   Úvalue©r    r#   Úfr   r   r   Úget_training_status‘   s   (ÿÿrx   Úerror_messagec                 C   sj   t | ƒ}tjj|t ¡  ¡ dœ}ttj	 
|d¡dƒ}tj||dd W d   ƒ |S 1 s.w   Y  |S )N)ro   rp   Ú	timestamprm   Úwé   ©Úindent)r)   r   r   ru   r   ÚnowÚ	isoformatrr   r"   r#   r$   r3   Údump)r    ry   r#   Úmetarw   r   r   r   Úmark_training_failedš   s   
ÿþrƒ   c                 C   sZ   t j t| ƒd¡}t j |¡sd S t|dƒ}t |¡W  d   ƒ S 1 s&w   Y  d S )Núquestion_bank_result.jsonrn   )r"   r#   r$   r'   rq   rr   r3   rs   rv   r   r   r   Úget_question_bank_result¡   s
   $ÿr…   c               	   C   s„   t j t¡sg S g } t  t¡D ]0}t j t j t|¡¡r?ztt|ƒƒ}|  	t|ƒ|r/| 
d¡nddœ¡ W q ty>   Y qw q| S )z0Lists all clients in the trained_data directory.ro   Úunknown)r    ro   )r"   r#   rq   r%   ÚlistdirÚisdirr$   rx   ÚintÚappendrF   Ú
ValueError)Úclientsr    ro   r   r   r   Úlist_all_clients§   s   &ÿür   c                 C   sT   t | ƒ}tj |¡r(t| ƒ}|r| d¡tjjkrt	dƒ‚dd l
}| |¡ dS dS )Nro   z,Cannot delete while training is in progress.r   TF)r'   r"   r#   rq   rx   rF   r   r   ru   ÚRuntimeErrorÚshutilÚrmtree)r    r#   ro   r   r   r   r   Údelete_client_dataµ   s   
r‘   c                 C   s–   t | ƒ}dD ]}tj ||¡}tj |¡rt |¡ qtjjt	 
¡  ¡ dœ}ttj |d¡dƒ}tj||dd W d  ƒ |S 1 sDw   Y  |S )zGInitialize or reset the client's data store for question bank training.)úaccumulated_questions.jsonr„   )ro   rz   rm   r{   r|   r}   N)r)   r"   r#   r$   rq   Úremover   r   ru   r   r   r€   rr   r3   r   )r    r#   Útmp_fileÚtmp_pathr‚   rw   r   r   r   Úinitialize_client_storeÂ   s   
€
ÿþr–   Ú	questionsc                 C   sÞ   t | ƒ}tj |d¡}g }tj |¡r-t|dƒ}t |¡}W d   ƒ n1 s(w   Y  dd„ |D ƒ}|D ]}| d¡rG||t	| dd¡ƒ< q6t
| ¡ ƒ}t|dƒ}t ||¡ W d   ƒ n1 sdw   Y  dt|ƒiS )	Nr’   rn   c                 S   s(   i | ]}|  d ¡rt|  d d¡ƒ|“qS )rU   r*   )rF   r&   )Ú.0rT   r   r   r   Ú
<dictcomp>Ú   s   ( z,accumulate_question_bank.<locals>.<dictcomp>rU   r*   r{   Útotal_questions)r)   r"   r#   r$   rq   rr   r3   rs   rF   r&   ÚlistÚvaluesr   rK   )r    r—   r#   Ú
store_fileÚexistingrw   ÚdeduprT   r   r   r   Úaccumulate_question_bankÑ   s"   ÿ
€ÿr    c              
   C   s>  t | ƒ}tj |d¡}tj |d¡}tj |¡s#d}t| |ƒ d|iS zLt|dƒ}t |¡}W d  ƒ n1 s:w   Y  i }i }tj |¡r|z(t|dƒ}t |¡}	|	 	di ¡}|	 	di ¡}W d  ƒ n1 skw   Y  W n
 tj
y{   Y nw t|ƒ}
d	}t|ƒD ]|\}}t| 	d
d¡ƒ}|r™||v r™q†|d d dks§|d |
kr¸t d| › d|d › d|
› d¡ t|ƒ}|d }|||< | 	|d¡d ||< |d | dkr| t|ƒt ¡  ¡ ||dœ}t|dƒ}tj||dd W d  ƒ n1 sýw   Y  q†| t|ƒt ¡  ¡ ||dœ}t|dƒ}tj||dd W d  ƒ n	1 s*w   Y  tjjt|ƒt ¡  ¡ dœ}ttj |d¡dƒ}tj||dd W d  ƒ n	1 s[w   Y  t d| › dt|ƒ› d¡ |W S  tyž } z!t d| › d|› ¡ t| dt|ƒ› ƒ dt|ƒiW  Y d}~S d}~ww )zXClassifies all questions and saves to question_bank_result.json. Includes checkpointing.r’   r„   zNo accumulated questions found.rp   rn   Nr—   Úcompetency_summaryé2   rU   r*   é   é
   r   z[Client z] Classifying questions: ú/r_   rb   )r    rš   Ú
trained_atr¡   r—   r{   r|   r}   )ro   rš   rz   rm   z] Question bank finalized: z questions.z1] Fatal error during question bank finalization: z/Internal error during background finalization: )r)   r"   r#   r$   rq   rƒ   rr   r3   rs   rF   rt   rK   Ú	enumerater&   rN   Úinforl   r   r   r€   r   r   r   ru   rM   Ú	exception)r    r#   r   Úresult_pathÚ	error_msgrw   Úquestion_bankr¡   Úmapped_questionsÚexisting_resultÚtotalÚsave_intervalÚirT   rf   ÚclassificationÚcomprP   r‚   rR   r   r   r   Úfinalize_question_bankä   sŽ   
ÿ
ý€ÿ"
ûÿ€
ûÿ
ýÿ€ýr´   )r*   ).r"   r3   ÚloggingrC   Úenumr   Útypingr   r   r   r   r   ÚbasicConfigÚINFOÚ	getLoggerrN   r¨   ÚenvironrF   r#   r$   ÚdirnameÚabspathÚ__file__r%   r(   r   r   Úfloatr   r&   r   r‰   r'   r)   rS   Údictrl   rx   rƒ   r…   r   r‘   r–   r    r´   r   r   r   r   Ú<module>   s8    

( P	