
    2j(                         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	r	S SK
r
S SKrS SKJr  S SKrS r " S S	5      r " S
 S5      rS rS rS rS r\S:X  a  \R*                  " \" 5       5        gg)    N)OllamaEmbeddings)FAISS)PromptTemplate)
ChatOllama)tqdmc                    [        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 )Nznomic-embed-text)modelzmy_embeddings//z/merged_faiss)z.faissz.pklT)allow_dangerous_deserializationzEmbeddings loaded from zNo embedding files found in .z"No embeddings found for client_id z and reference_id )	r   ospathisdirlistdirendswithr   
load_localprint)	client_idreference_id
embeddingsreference_dirfembedding_filesvectorss          D/var/www/eduai.edurigo.com/question_generate/staging/generate_mcq.pyload_all_embeddingsr      s    !(:;J$YKqmLM	ww}}]##&(jj&?b&?::N`Ca1&?b&&}bfgG+M?;<N0qAB  	29+=OP\~]^_` cs   C,Cc                   8    \ rS rSrS rS rS rS rS rS r	Sr
g	)
QuestionHistory   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        $ [        S5        [        5       $ ! , (       d  f       g = f! [        R                   a&    [        SU R                   S35        [        5       s $ f = f)NrzWarning: Invalid JSON in z!. Starting with an empty history.z6No history file found. Starting with an empty history.)r   r   existsr!   openreadstripsetjsonloadsJSONDecodeErrorr   )r$   r   contents      r   r"   QuestionHistory.load!   s    77>>$..))$..#.!ffhnn.G7>3tzz'23CE /. JL5L /. '' 1$..1AAbcdus0   C AB3	C 3
C=C C 7C>=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.save.   sT    
BGGOODNN3dC$..#&!IId4>>*A. '&&s   +B
Bc                 :    U R                   R                  U5        g N)r#   addr$   questions     r   r?   QuestionHistory.add3   s    8$r'   c                     XR                   ;   $ r>   )r#   r@   s     r   __contains__QuestionHistory.__contains__6   s    >>))r'   c                 ,    [        U R                  5      $ r>   )lenr#   )r$   s    r   __len__QuestionHistory.__len__9   s    4>>""r'   )r!   r#   N)__name__
__module____qualname____firstlineno__r%   r"   r;   r?   rD   rH   __static_attributes__ r'   r   r   r      s     %/
%*#r'   r   c                        \ rS rSrS rS rSrg)RateLimiter<   c                 *    Xl         X l        / U l        g r>   max_requestsperiodrequests)r$   rU   rV   s      r   r%   RateLimiter.__init__=   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   )timerW   rV   rG   rU   asynciosleepappend)r$   nowreq
sleep_times       r   waitRateLimiter.waitB   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)rT   N)rJ   rK   rL   rM   r%   ra   rN   rO   r'   r   rQ   rQ   <   s    
*r'   rQ   c                    #    [        X5      nU(       d  [        S5        / S4$ [        X5      nUR                  5       n[	        SSS9n[        SS/SS	9ng 7f)
N=No embeddings found for the given client ID and reference ID.r   http://127.0.0.1:11434
gemma3:12bbase_urlr	   contextnum_questions7  
        {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template)r   r   r   as_retrieverr   r   )	r   rj   r   GPUr   question_history	retrieverllmmcq_templates	            r   generate_mcqru   K   sf     !):GMN1u&y?$$&I
)C ""O4Ls   AAc                    U R                  SS5      R                  SS5      R                  SS5      R                  SS5      n[        R                  " SU5      n/ nU GH}  nUR                  5       nU(       d  M  [        R                  " SU5      nU(       d  M=  USUR                  5        R                  5       nU(       d  Mg  0 nS	 HZ  nS
U-   S-   n	[        R                  " X[        R                  5      n
U
(       a#  U
R                  S5      R                  5       Xx'   MZ    O   [        U5      S:  a  M  [        R                  " SU5      nU(       a   UR                  S5      R                  5       nOP[        R                  " SU[        R                  5      nU(       a   UR                  S5      R                  5       nOGMh  UR                  UUUS.5        GM     U$ )z
Robustly parses multiple-choice questions from the LLM response string.
Supports bolding, different bullet styles, double newlines, and trailing spaces.
z** *___z3(?i)(?:^|\n)\s*(?:Q|Question)\s*(?:\d+)?\s*[:.-]\s*z(?i)(?:^|\n)\s*A[\s).:-]+N)ABCDz(?i)(?:^|\n)\s*z9[\s).:-]+(.*?)(?=\n\s*(?:[A-D][\s).:-]|Correct|Answer)|$)      z:(?i)(?:Correct|Answer|Correct\s*Answer)\s*[:.-]*\s*([A-D])z'(?i)(?:Correct|Answer)\s*.*?\b([A-D])\b)rA   optionscorrect_answer)replaceresplitr-   searchstartDOTALLgrouprG   upperr]   )response_strcleaned
raw_blocksr#   blockopt_a_matchquestion_textr   optopt_pattern	opt_matchcorrect_matchcorrect_lettercorrect_match_fallbacks                 r   parse_mcqs_robustlyr   o   s   
 ""4,44S"=EEdBOWWX[]_`GPRYZJIii <eD2{002399;'C,S01mmK		+bii@I(q1779 ( w<!		"_afg*00399;N%'YY/Y[`bdbkbk%l"%!7!=!=a!@!F!F!H%,
 	G R r'   c                   ^^^^#    [        X5      nU(       d  [        S5        / S4$ [        X5      mUR                  5       n[	        SSS9m[        SS/SS	9m/ nS
n[        SSS9m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)Nrd   r   re   rf   rg   ri   rj   rk   rl   r      rR   )rU   rV   c                 F  >#    TR                  5       I S h  vN   TR                  XS9nT
R                  U5      I S h  vN nUR                  n[	        U5      n/ nU H8  nUS   n	U	T;  d  M  UR                  U[        U5      -   U	US   US   S.5        M:     U$  N N_7f)N)ri   rj   rA   r   r   )numberrA   r   r   )ra   formatainvoker2   r   r]   rG   )ri   start_number
batch_sizepromptresponser   parsed_questionsr#   qrA   rs   rt   rq   rate_limiters             r   process_context%generate_mcq.<locals>.process_context   s     !!!$$W$OV,,''.|<	!A}H//  *S^; ( |&'(8&9	"  " ! 	",s&   B!B'B!B +B!//B!B!zGenerating MCQs)totaldesci,     zRandom query for retrieval i  rA   zError processing context: zWarning: Only generated z unique questions out of z requested.)r   r   r   ro   r   r   rQ   r   rZ   rG   minrandomrandintinvokepage_contentr]   r?   update	Exceptionr;   )r   rj   r   rp   r   rr   mcqsquestion_numberr   pbartimeoutremaining_questionsr   queryresultsresultri   new_mcqsmcqers   rt   rq   r   s                       @@@@r   ru   ru      sC    !):GMN1u&y?$$&I
)C ""O4L. DOBr:L & 
M(9	: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',A4 t9}$,SYK7PQ^P__jkl; 
;> %&&&%  [ ! 6qc:;+ 
;	:ss   A4I:B*I%H'1H%2H'H'?H'I',I*I %I%H''
I1I?III
IIc                  J  #    Sn SnSnSn[        XX#5      I S h  vN u  pEU(       d  [        S5        g [        SU 35        U HX  n[        SUS    S	US
    35        US   R                  5        H  u  px[        U SU 35        M     [        SUS    S35        MZ     g  N7f)Nrich      r   z'No multiple-choice questions generated.zTotal questions in history: z	Question r   z: rA   r   z) zCorrect Answer: r   
)ru   r   items)	r   rj   r   rp   r   history_countr   optiontexts	            r   mainr      s     IML	C ,Y| XXD78	(
89	#h-3z?*;<=	N002LFVHBtf%& 3 %5!6 7r:;	  Ys   B#B!BB#__main__)r   r   langchain_ollamar    langchain_community.vectorstoresr   langchain_core.promptsr   r   r   r/   r[   r   rZ   r   r   rQ   ru   r   r   rJ   runrO   r'   r   <module>r      su    	  - 2 1 ' 	    # #@* *"H2h['z<$ zKK r'   