
    kj                         S r SSKrSSKrSSKrSSKrSSKrSSKrSSKJr  SSKJ	r	  SSK
Jr  SSKJr  SSKJr  S r " S	 S
5      r " S S5      rS r\S:X  a  S r\R*                  " \" 5       5        gg)z
generate_mcq_doc.py
===================
MCQ generation module for DOC/DOCX document formats.
Generates MCQs from FAISS embeddings created during DOC/DOCX training.
    N)tqdm)OllamaEmbeddings)FAISS)PromptTemplate)
ChatOllamac                    [        SS9nSU  SU S3n[        R                  R                  U5      (       az  [        R                  " U5       Vs/ s H  oDR                  S5      (       d  M  UPM     nnU(       a%  [        R                  " X2SS9n[        S	U 35        U$ [        S
U S35         g[        SU  SU S35        gs  snf )z:Load FAISS embeddings for a specific client and reference.znomic-embed-text)modelzmy_embeddings//z/merged_faiss)z.faissz.pklT)allow_dangerous_deserializationz[DOC] Embeddings loaded from z"[DOC] No embedding files found in .z([DOC] No embeddings found for client_id=z, reference_id=N)	r   ospathisdirlistdirendswithr   
load_localprint)	client_idreference_id
embeddingsreference_dirfembedding_filesvectorss          H/var/www/eduai.edurigo.com/question_generate/testing/generate_mcq_doc.pyload_all_embeddingsr      s    !(:;J$YKqmLM	ww}}]##&(jj&?b&?::N`Ca1&?b&&}bfgG1-ABN6}oQGH  	8?S_R``abc cs   C,Cc                   <    \ rS rSrSrS rS rS rS rS r	S r
S	rg
)QuestionHistory&   z<Tracks previously generated questions to prevent duplicates.c                 J    SU SU S3U l         U R                  5       U l        g )Nzquestion_history/r
   z.json)	file_pathload	questions)selfr   r   s      r   __init__QuestionHistory.__init__(   s%    ,YKqeL    c                    [         R                  R                  U R                  5      (       ao   [	        U R                  S5       nUR                  5       R                  5       nU(       a  [        [        R                  " U5      5      O	[        5       sS S S 5        $ [        5       $ ! , (       d  f       [        5       $ = f! [        R                   a    [        5       s $ f = f)Nr)r   r   existsr!   openreadstripsetjsonloadsJSONDecodeError)r$   r   contents      r   r"   QuestionHistory.load,   s    77>>$..))$..#.!ffhnn.G7>3tzz'23CE /.
 u /.
 u '' us0   C AB(	C (
B?2C ?C C#"C#c                 0   [         R                  " [         R                  R                  U R                  5      SS9  [        U R                  S5       n[        R                  " [        U R                  5      U5        S S S 5        g ! , (       d  f       g = f)NT)exist_okw)
r   makedirsr   dirnamer!   r+   r/   dumplistr#   )r$   r   s     r   saveQuestionHistory.save6   sT    
BGGOODNN3dC$..#&!IId4>>*A. '&&s   +B
Bc                 :    U R                   R                  U5        g N)r#   addr$   questions     r   r?   QuestionHistory.add;   s    8$r'   c                     XR                   ;   $ r>   )r#   r@   s     r   __contains__QuestionHistory.__contains__>   s    >>))r'   c                 ,    [        U R                  5      $ r>   )lenr#   )r$   s    r   __len__QuestionHistory.__len__A   s    4>>""r'   )r!   r#   N)__name__
__module____qualname____firstlineno____doc__r%   r"   r;   r?   rD   rH   __static_attributes__ r'   r   r   r   &   s#    F%/
%*#r'   r   c                   $    \ rS rSrSrS rS rSrg)RateLimiterE   z%Async rate limiter for LLM API calls.c                 *    Xl         X l        / U l        g r>   max_requestsperiodrequests)r$   rV   rW   s      r   r%   RateLimiter.__init__G   s    (r'   c                   #    [         R                   " 5       nU R                   Vs/ s H  o!U-
  U R                  :  d  M  UPM     snU l        [        U R                  5      U R                  :  aB  U R                  XR                  S   -
  -
  nUS:  a  [
        R                  " U5      I S h  vN   U R                  R                  [         R                   " 5       5        g s  snf  N87f)Nr   )timerX   rW   rG   rV   asynciosleepappend)r$   nowreq
sleep_times       r   waitRateLimiter.waitL   s     iik(,QsT[[9PQt}}!2!22mmA.>(>?JA~mmJ///TYY[) R 0s#   $C)C" C"A(C).C'/9C)rU   N)rJ   rK   rL   rM   rN   r%   rb   rO   rP   r'   r   rR   rR   E   s    /
*r'   rR   c                   ^^^^^#    [        X5      nU(       d  / S4$ [        X5      mUR                  5       n[        SSS9m[	        SS/SS9m[
        R                  " S	[
        R                  5      m/ nS
n[        SSS9mUUUUU4S jn[        USS9 n	[        R                  " 5       S-   n
[        U5      U:  Ga3  [        R                  " 5       U
:  Ga  U[        U5      -
  n[        US5      nS[        R                  " S
S5       3nUR                  U5      nU H  n[        U5      U:  a    OUR                   n U" UX|5      I Sh  vN nU HZ  n[        U5      U:  d  M  US   T;  d  M  UR#                  U5        TR%                  US   5        US
-  nU	R'                  S
5        M\     [        U5      U:  d  M    O   [        U5      U:  a  [        R                  " 5       U
:  a  GM  [        U5      U:  a  [+        S[        U5       SU S35        SSS5        TR-                  5         U[        T5      4$  N! [(         a  n[+        SU 35         SnAGMB  SnAff = f! , (       d  f       NT= f7f)z0Generate MCQs from DOC/DOCX document embeddings.r   zhttp://127.0.0.1:11434z
gemma3:12b)base_urlr	   contextnum_questionsa3  
        {context}

        Generate {num_questions} multiple-choice questions based on the provided context. Each question should include one correct answer and three plausible but incorrect options. Follow the format below:
        Q: <question>
        A) <option_a>
        B) <option_b>
        C) <option_c>
        D) <option_d>
        Correct: <correct_letter>

        Guidelines:
    Ensure questions are clear, relevant, and focused on key details from the context.
    Phrase questions concisely to avoid ambiguity.
    Avoid questions like "in this document" or "in this code" or "in given document" unless accompanied by specific, relevant information.
    Make incorrect options (distractors) credible and similar in structure or content to the correct answer, encouraging thoughtful selection.
        )input_variablestemplatezFQ: (.+?)\nA\) (.+?)\nB\) (.+?)\nC\) (.+?)\nD\) (.+?)\nCorrect: ([A-D])      <   )rV   rW   c           
        >#    TR                  5       I S h  vN   TR                  XS9nTR                  U5      I S h  vN n/ nTR                  UR                  5       H  nUR                  5       u  pxppUR                  5       nUT;  d  M/  UR                  U[        U5      -   UUR                  5       U	R                  5       U
R                  5       UR                  5       S.US.5        M     U$  N N7f)N)rf   rg   )ABCD)numberrA   optionscorrect_answer)	rb   formatainvokefinditerr2   groupsr-   r^   rG   )rf   start_number
batch_sizepromptresponser#   matchrA   option_aoption_boption_coption_dcorrect_letterllm	mcq_regexmcq_templatequestion_historyrate_limiters                r   process_context)generate_mcq_doc.<locals>.process_context~   s     !!!$$W$OV,,	''(8(89EOT||~LHH~~'H//  *S^; (%-^^%5HNN<LS[SaSaScjrjxjxjz{&4	" 	 :  	",s(   C9C5'C9C7 AC9A&C97C9zGenerating MCQs (DOC))totaldesci,     zRandom query for retrieval i  NrA   z [DOC] Error processing context: z[DOC] Warning: Only generated z unique questions out of z requested.)r   r   as_retrieverr   r   recompileDOTALLrR   r   r[   rG   minrandomrandintinvokepage_contentr^   r?   update	Exceptionr   r;   )r   rg   r   GPUr   	retrievermcqsquestion_numberr   pbartimeoutremaining_questionsrz   queryresultsresultrf   new_mcqsmcqer   r   r   r   r   s                       @@@@@r   generate_mcq_docr   V   sT    !):G1u&y?$$&I
)C
 ""O4L* 

dfhfofopIDOBr:L " 
M(?	@D))+#$i-'DIIK',A"/#d)";0!4J1&..D2I1JKE&&u-G!t9- --
%4Wo%ZZH't9}4ZP`9` KK,,00ZA+q0O KKN  ( t9-! " $i-'DIIK',A0 t9}$23t9+=VWdVeepqr7 
A: %&&&#  [ ! <QC@A) 
A	@ss   BI;B*I*III(I3?I2I*,I*2*I*%I;I
I'I"I*"I''I**
I84I;__main__c                     #    [        SSSS5      I S h  vN u  pU (       a/  [        SU 35        U  H  n[        SUS    SUS	    35        M     g g  N=7f)
Nrich      rj   zTotal questions in history: Qrr   z: rA   )r   r   )r   history_countr   s      r   mainr      sa     $4VRQ$GG0@A#h-3z?*;<=   Hs   AA>A)rN   r   r   r/   r\   r   r[   r   langchain_ollamar    langchain_community.vectorstoresr   langchain_core.promptsr   r   r   r   rR   r   rJ   r   runrP   r'   r   <module>r      sq    
    	   - 2 1 '"# #>* *"W't z> KK r'   