o
    P,iY                     @   s  d Z ddlZddlZ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
 ddlmZmZ ddlmZmZmZ ddlmZmZmZmZ ddlmZ dd	lmZ ddlZdd
lmZ dZejej dd e!e"Z#G dd dZ$e$ddZ%G dd deZ&G dd deZ'G dd deZ(G dd deZ)de*de+fddZ,de*fddZ-d e*d!e+d"e+d#e.d$e*d%e*d&e+dee(e)f fd'd(Z/e"d)krve0d* e0d+ e0d, e/d-d.d/d0d1d2d3d4Z1e0d* e0d5 e0d6 e2d7d8 e1j34 D Z5e2d9d8 e1j34 D Z6e2d:d8 e1j37 D Z8e0d;e9e1j3  e0d<e5  e0d=e6  e0d>e8 d?e5  e0d@e1j:  e0dA e1j37 D ]*\Z;Z<e;=dBrfe>e<dCdZ?e?rRdDndEZ@e0dFe@ dGe; dHe?rae?ndI  q=e0d* e0dJ e0d6 dS dS )Ka  
================================================================================
 Storigo Content Generator - Professional Edition v7.0
 - Synchronous image generation during slide creation
 - Direct image URL assignment (no null values)
 - One slide processed completely before moving to next
 - Professional error handling and logging
 - GUARANTEED: Every slide with is_image=1 gets an image URL or None
================================================================================
    N)ChatGroq)ChatPromptTemplate)StrOutputParserPydanticOutputParser)	BaseModelField	validator)ListOptionalDictUnion)deque)Lock)fetch_image_for_slide8gsk_CEh3itIpUAkEkEKsUDqVWGdyb3FYoTjqmXNTBHOSxJFK3obGTzXZz:%(asctime)s - [%(levelname)s] - (StorigoGen) - %(message)s)levelformatc                   @   s"   e Zd ZdZdddZdd ZdS )	SmartRateLimiterz%Intelligent rate limiter for Groq API   c                 C   s&   || _ t | _t | _d| _d| _d S )Nr   )max_requestsr   request_timesr   locktotal_requeststotal_waits)selfmax_requests_per_minute r   [/var/www/eduai.edurigo.com/image_generation/testing/generate_storigo_content_from_prompt.py__init__/   s
   
zSmartRateLimiter.__init__c                 C   s   | j  t }| jr%|| jd  dkr%| j  | jr%|| jd  dkst| j| jkrod|| jd   d }td|dd |  jd7  _t	| | jrot | jd  dkro| j  | jrot | jd  dks\| j
t  |  jd7  _W d   dS 1 sw   Y  dS )zWait if approaching rate limitsr   <      u#   ⏳ Rate limit protection: waiting z.1fsN)r   timer   popleftlenr   loggerwarningr   sleepappendr   )r   now
sleep_timer   r   r   wait_if_needed6   s    


"zSmartRateLimiter.wait_if_neededN)r   )__name__
__module____qualname____doc__r   r+   r   r   r   r   r   -   s    
r   r   )r   c                   @   s   e Zd ZU edZeed< edZee ed< edZ	e
e ed< edZeed< eddZee ed	< ed	d
d
ddd ZG dd dZdS )SlideContentflashtypeN
subheading.
paragraphsvisualization_suggestion)defaultimageT)prealwaysc                 C   s6   |du rdS t |tr| }|r|dkr|S dS dS )z1Ensure image is either None or a valid string URLNNone)
isinstancestrstrip)clsvstrippedr   r   r   validate_image_pathY   s   
z SlideContent.validate_image_pathc                   @   s   e Zd ZdZdZdS )zSlideContent.ConfigTN)r,   r-   r.   arbitrary_types_allowedvalidate_assignmentr   r   r   r   Configc   s    rD   )r,   r-   r.   r   r2   r<   __annotations__r3   r
   r4   r	   r5   r7   r   rA   rD   r   r   r   r   r0   R   s   
 
	r0   c                   @   s^   e Zd ZU edZeed< edddZeed< edddZe	e ed< edd	dZ
eed
< dS )
MCQContentQuestionr2   .zThe multiple-choice question)descriptionquestionzA list of 4 answer optionsoptionszThe correct answercorrect_answerN)r,   r-   r.   r   r2   r<   rE   rI   rJ   r	   rK   r   r   r   r   rF   g   s
   
 rF   c                   @   s2   e Zd ZU edZeeef ed< dZ	e
ed< dS )StorigoContent.slidesr   token_countN)r,   r-   r.   r   rM   r   r<   r0   rE   rN   intr   r   r   r   rL   m   s   
 rL   c                   @   s:   e Zd ZU edZeeeee	f f e
d< dZee
d< dS )StorigoContentMCQMid.rM   r   rN   N)r,   r-   r.   r   rM   r   r<   r   r0   rF   rE   rN   rO   r   r   r   r   rP   q   s   
  rP   textreturnc                 C   s   t d| }t|S )z(Simple token counter based on word countz\w+)refindallr$   )rQ   tokensr   r   r   count_tokensx   s   rV   c                 C   s   t | dr	| j}nt| }| }|dr$tdd|}tdd|}d|v s,d|v rF|d}|d	d
 }|dkrF|dkrF||| }t	d|tj
}|rU|dS |S )z4Fix common JSON formatting issues from LLM responsescontent```^```json?\s* \s*```zHere'szI apologize{}r    r   z\{.*\})hasattrrW   r<   r=   
startswithrS   subfindrfindsearchDOTALLgroup)
ai_messagerQ   startend
json_matchr   r   r   quick_json_fix}   s    



rk   prompt
num_slidesnum_mcqsis_imageis_questionquestion_positionGPUc           7      C   s	  t   }ztd td td td td|  td|  td|  td| dd	  d
 td td tdtddd	dd}td td td td d}	t|	}
dd dd d|
B |B tB }t	  t   }|
| |d}t   | }zt|}td^i |}tdt|j d|dd W n- tjy } z tdt|  td|dd  d
 td t| d}~ww tt|j d!d d"}| D ]/\}}t|jd#k r	|jd$ t|jd#k s|jr|j sd%|_td&| d' q|rtd td( td d)}d)}| D ]}|| }zT|j}td*| d
 td+| d, t   }t||}t   | }|r||| _|d-7 }td.| d/|dd0 nd|| _|d-7 }td1|dd0 W q: ty } ztd2t|  d|| _|d-7 }W Y d}~q:d}~ww td td3 td4| d5t|  td6| d5t|  td ntd7 | D ]}d|| _q||_d)}|j D ]}|j  d8d8!|j d8|j }|t"|7 }q|rT|d9vrTtd td:| d; td t #d< g }|j D ]\}}|j } d8!|j}!|d=|  d>|!  qCd?!|}"d@}#zt|#}$t	  t   }%|$|B 
|"|dA}&t   |% }'|&j$ }(|(%dBrt&'dCdD|(}(t&'dEdD|(}(t&(dF|(t&j)})|)r|)*d)}(t|(}*i }+t+|*d| D ]S\},}-z.dG|-vrdH|-dG< t,d^i |-|+dI|,d-  < tdJ|,d-  dK|-dL ddM  d
 W q ty } ztdN|,d-  dK|  W Y d}~qd}~ww tdt|+ d5| dO|'dd |+ D ]}.|.j- d8d8!|.j. d8|.j/ }|t"|7 }q%i }/|dPksK|d-krtdQ t0|j }0|+rbt|0t|+ nd)}1d)}2t+|0D ]7\},}|j| |/|< |1d)kr|,d- |1 d)kr|2t|+k rdI|2d-  }3|3|+v r|+|3 |/|3< |2d-7 }2qjn#tdR |j D ]
}|j| |/|< q|+ D ]	\}3}4|4|/|3< qt   | }5td tdS td tdT tdU|5dd tdt|j  tdt|+  tdVt|/  tdW|  |r"tdX| d5t|j  td t1|/|dYW W S  tyS } ztdZt|  t|j|dYW  Y d}~W S d}~ww t   | }5td tdS td tdT tdU|5dd tdt|j  tdW|  |rtdX| d5t|j  td t|j|dYW S  ty } z-td td[ td\t|  td d)dl2}6t|63  td]t| d}~ww )_a  
    Generate professional slide content with INLINE image generation
    
    PROFESSIONAL APPROACH:
    1. Generate slide content
    2. For EACH slide, immediately fetch and assign image
    3. Process one slide completely before moving to next
    4. Return final result with all images assigned
    
    Args:
        prompt: Main topic prompt
        num_slides: Number of slides to generate
        num_mcqs: Number of MCQs
        is_image: Whether to generate images
        is_question: Whether to generate MCQs
        question_position: Position of questions ("end" or "1")
        GPU: Legacy parameter
        
    Returns:
        StorigoContent or StorigoContentMCQMid with images properly assigned
    P================================================================================u0   🚀 STORIGO PROFESSIONAL CONTENT GENERATOR v7.0u   📋 Configuration:z   - Slides: z   - MCQs: z   - Images: z   - Prompt: Nr   z...u   🔧 Initializing Groq API...zllama-3.1-8b-instantgffffff?i      )
model_namegroq_api_keytemperature
max_tokensrequest_timeoutmax_retriesu   ✅ Groq API readyQ
================================================================================u%   📝 STEP 1: Generating Slide Contenta  
Based on the following prompt, generate professional content for exactly {num_slides} slides.

Each slide MUST include:
- A clear, descriptive subheading
- 2-3 informative paragraphs (well-written and engaging)
- A specific visualization suggestion (3-5 words describing a concrete, searchable image)

CRITICAL for visualization_suggestion:
- Use ONLY concrete, visual, searchable terms
- Think: "What would I search on a stock photo website?"
- Good examples: "team meeting conference room", "data analytics dashboard", "kitchen staff commercial"
- Bad examples: "concept of leadership", "abstract representation"

Prompt: {prompt}

Make content professional with:
- Thought-provoking insights
- Relevant examples or statistics
- Industry trends
- Clear, actionable takeaways

Return ONLY a valid JSON object with this exact structure (no explanations, no markdown, no schema definitions):
{{
  "slides": {{
    "slide_1": {{
      "subheading": "Introduction to Kitchen Safety",
      "paragraphs": [
        "Kitchen safety is paramount in any food service environment.",
        "Proper protocols protect staff and ensure food quality."
      ],
      "visualization_suggestion": "kitchen staff commercial",
      "image": null
    }},
    "slide_2": {{
      "subheading": "Food Handling Best Practices",
      "paragraphs": [
        "Proper food handling prevents contamination and foodborne illness.",
        "Key practices include temperature control and cross-contamination prevention."
      ],
      "visualization_suggestion": "food preparation hygiene",
      "image": null
    }}
  }},
  "token_count": 0
}}

Generate exactly {num_slides} slides numbered slide_1 through slide_{num_slides}.
c                 S      | d S )Nrl   r   xr   r   r   <lambda>      z4generate_slide_content_from_prompt.<locals>.<lambda>c                 S   r|   )Nrm   r   r}   r   r   r   r     r   )rl   rm   u   ✅ Generated z slides in z.2fr!   u   ❌ JSON parsing failed: zRaw response: i  z$Failed to parse slide content JSON: c                 S   s   t | d dd S )Nr   _r    )rO   splitr}   r   r   r   r   *  s    )key   z&Additional information for this slide.zprofessional business conceptu   ⚠️ z$: Empty visualization, using defaultu4   🎨 STEP 2: Generating Images (INLINE - One by One)r   u   
📸 Processing z   Visualization: ''r    u      ✅ Image assigned: z (zs)u      ⚠️ No image found (u      ❌ Error: u   🎨 Image Generation Summary:z   - Success: /z   - Failed: u0   
📷 Image generation disabled (is_image=False) )0falseFalseu   ❓ STEP 4: Generating z MCQs (Batch Mode)g      ?z**z**
z

a  
You are an expert educational content creator. Generate exactly {num_mcqs} high-quality MCQs.

**Requirements:**
1. Test comprehension of key concepts
2. Distribute across different topics
3. Each question has exactly 4 options
4. Only one clearly correct answer
5. Avoid trivial questions

**Content:**
{context}

**Output Format:**
Return ONLY a valid JSON array (no markdown, no explanations):

[
    {{
        "type": "Question",
        "question": "Clear question text?",
        "options": ["Option 1", "Option 2", "Option 3", "Option 4"],
        "correct_answer": "Option 1"
    }}
]

Generate exactly {num_mcqs} questions now:
)contextrn   rX   rY   rZ   r[   z\[\s*\{.*\}\s*\]r2   rG   mcq_u   ✅ MCQ : rI   2   u   ⚠️ Failed to parse MCQ z	 MCQs in 1u(   📍 Distributing MCQs throughout slidesu   📍 Placing all MCQs at endu   🎉 GENERATION COMPLETEu   📊 Final Statistics:z   - Total time: z   - Total items: z   - Token count: z   - Images assigned: )rM   rN   u   ❌ MCQ generation failed: u   ❌ FATAL ERRORzError: zContent generation failed: r   )4r"   r%   infor   GROQ_API_KEYr   from_templaterk   rate_limiterr+   invokejsonloadsrL   r$   rM   JSONDecodeErrorerrorr<   	Exceptiondictsorteditemsr4   r(   r5   r=   r&   keysr   r7   valuesr3   joinrV   r'   rW   r`   rS   ra   rd   re   rf   	enumeraterF   rI   rJ   rK   listrP   	traceback
format_exc)7rl   rm   rn   ro   rp   rq   rr   generation_startllmslide_content_templateslide_promptslide_chainslide_gen_start
raw_resultslide_gen_timeresult_dataresulteordered_slides	slide_keyslide_contentsuccess_countfailed_count
viz_promptimage_start	image_url
image_timerN   rQ   all_contextr   slidetitleparasfull_contextmcq_template
mcq_prompt	mcq_start
mcq_resultmcq_timerW   array_matchmcq_listmcqsidxmcq_datamcqfinal_content
slide_keysintervalmcq_countermcq_keymcq_contentgeneration_timer   r   r   r   "generate_slide_content_from_prompt   s  










2
$









 








.($ 
*















r   __main__r{   u+   🧪 TESTING STORIGO CONTENT GENERATOR v7.0zQ================================================================================
z/Kitchen safety and food handling best practicesrt   r   Tr   ri   r    )rl   rm   rn   ro   rp   rq   rr   u   📋 TEST RESULTSrs   c                 c       | ]
}| d rdV  qdS )slide_r    Nr`   .0kr   r   r   	<genexpr>3      r   c                 c   r   )r   r    Nr   r   r   r   r   r   4  r   c                 c   s2    | ]\}}| d rt|dr|jrdV  qdS )r   r7   r    N)r`   r_   r7   )r   r   r?   r   r   r   r   5  s   
 zTotal items: z  - Slides: z
  - MCQs: z  - Images assigned: r   zToken count: u   
📸 Image URLs:r   r7   u   ✅u   ⚠️z  r   r   r:   u    ✅ Test completed successfully!)Ar/   osr"   randomrS   r   requestslangchain_groqr   langchain_core.promptsr   langchain_core.output_parsersr   r   pydanticr   r   r   typingr	   r
   r   r   collectionsr   	threadingr   loggingstorigo_image_generatorr   r   basicConfigINFO	getLoggerr,   r%   r   r   r0   rF   rL   rP   r<   rO   rV   rk   boolr   printtest_resultsumrM   r   slide_count	mcq_countr   images_with_urlr$   rN   r   rW   r`   getattrimgstatusr   r   r   r   <module>   s    

 

   

$