
    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 r\S:X  a  S r\R,                  " \" 5       5        gg)z
generate_mcq_ppt.py
===================
MCQ generation module for PPT/PPTX presentation formats.
Generates MCQs from FAISS embeddings created during PPT/PPTX 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[PPT] Embeddings loaded from z"[PPT] No embedding files found in .z([PPT] 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          K/var/www/eduai.edurigo.com/question_generate/production/generate_mcq_ppt.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                    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_textro   optopt_pattern	opt_matchcorrect_matchcorrect_lettercorrect_match_fallbacks                 r   parse_mcqs_robustlyr   V   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           	      Z  ^^^#    [        X5      nU(       d  / S4$ [        X5      mUR                  SS0S9n[        SSS9m[	        SS	/S
S9m/ nSn/ n[        5       n	/ SQn
U
 Hi  n UR                  U5      nU HN  n[        UR                  SS 5      nX;  d  M"  U	R                  U5        UR                  UR                  5        MP     Mk     U(       d,  UR                  S5      nU Vs/ s H  oR                  PM     nnUUU4S jn[        USS9 n[        R                  " 5       S-   nSn[        U5      U:  GaI  [        R                  " 5       U:  Ga/  U[        U5      -
  n[        US5      n/ n[!        [        S[        U5      5      5       H(  nUU-   [        U5      -  nUR                  UU   5        M*     US-   [#        [        U5      S5      -  n U" UUU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:  a  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$ ! [         a     GM  f = fs  snf  GN! [         a  n['        SU 35         SnAGM  SnAff = f! , (       d  f       Nl= f7f)z4Generate MCQs from PPT/PPTX presentation embeddings.r   k
   )search_kwargszhttp://127.0.0.1:11434z
gemma3:12b)base_urlr	   contextnum_questionsaO  
        {context}

        Generate {num_questions} multiple-choice questions based on the provided presentation content. 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 presentation slides.
    Phrase questions concisely to avoid ambiguity.
    Avoid questions like "in this presentation" or "in this slide" or "in given slides" 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templaterm   )zkey concepts and definitionszimportant facts and detailszmain topics and summaryz processes methods and proceduresz#examples applications and use casesN   overviewc                 4  >#    SR                  U 5      nTR                  X2S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]7f)z>Process multiple contexts in a single LLM call for efficiency.z

---

)r   r   NrA   ro   rp   )numberrA   ro   rp   )joinformatainvoker2   r   r^   rG   )contextsstart_numbernum_to_generatecombined_contextpromptresponsery   parsed_questionsr#   qrA   llmmcq_templatequestion_historys              r   process_batch'generate_mcq_ppt.<locals>.process_batch   s     (--h7$$-=$]V,,''.|<	!A}H//  *S^; ( |&'(8&9	"  "  -s   5BB+B(/BzGenerating MCQs (PPT))totaldesci,     rA   z [PPT] Error processing context: z[PPT] Warning: Only generated z unique questions out of z requested.)r   r   as_retrieverr   r   r.   invokehashpage_contentr?   r^   	Exceptionr   r[   rG   minrangemaxupdater   r;   )r   r   r   GPUr   	retrievermcqsquestion_numberall_contextsseen_contentsseed_queriesr   resultsr)   content_hashr   pbartimeout	ctx_indexremaining_questions
batch_sizebatch_contextsiidxnew_mcqsmcqer   r   r   s                              @@@r   generate_mcq_pptr      s    !):G1u&y?$$C9$=I
)C
 ""O4L* DO LEML 	&&q)G#ANN4C$894!%%l3 ''7	   "":.07818( 
M(?	@D))+#	$i-'DIIK',A"/#d)";0"5J  N3q#l"345 1}L(99%%l3&78 6 #Q#c,.?*CCI
!.~PZ![[#C4y=0S_L\5\C((,,S_='1,A $ 4yM)1 $i-'DIIK',A4 t9}$23t9+=VWdVeepqr? 
AB %&&&{  		
 9L \  8<=/ 
A	@s   A"L+(1K0K L+-K+L+CLK3*K0+K3K3?K38L
*L4%L+
K(#L+'K((L+0K33
L=LLLL
L($L+__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)
Nr   r   d   rm   zTotal questions in history: Qr   z: rA   )r   r   )r   history_countr   s      r   mainr     sa     $4QC$CC0@A#h-3z?*;<=   Ds   AA>A)rN   r   randomr/   r\   rr   r[   r   langchain_ollamar    langchain_community.vectorstoresr   langchain_core.promptsr   r   r   r   rR   r   r   rJ   r   runrP   r'   r   <module>r      sw    
    	   - 2 1 '"# #>* *"2hu'p z> KK r'   