a
    "i=L  ã                   @   sø  d 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mZm	Z	m
Z
 ddlZddlmZ ddlmZ zddlmZ dZW n ey–   dZd	ZY n0 e e¡ZejZejZejZejZd
ZG dd„ dƒZd+eeeee ee eeeeee	e  ee dœdd„Z d,ee ee ee ee dœdd„Z!ddddefeee ee eeeee dœdd„Z"d-edœdd„Z#edœdd „Z$dddedfeee ee eee%ee d!œd"d#„Z&d.eee ee d$œd%d&„Z'd'd(„ Z(ed)k�rôej)ej*d*� e +e(ƒ ¡ dS )/z×
BaoLife AI Image Generation Module

Handles automated image generation using Google Imagen 4 Ultra (primary), FLUX 1.1 Pro, and DALL-E 3 APIs.
Supports caching, queue management, and cozy cartoon style generation.
é    N)Údatetime)ÚOptionalÚDictÚListÚTuple)Úconfig)Úget_database_connection)ÚAsyncOpenAITFzŠcozy cartoon style, illustration, warm colors,
friendly atmosphere, high quality digital art, clean lines,
--no words, text, letters, facec                	   @   sÎ   e Zd ZdZefedœdd„Zdeeeeee	e e	e f dœdd	„Z
eeeeee	e e	e f dœd
d„Zeeeeee	e e	e f dœdd„Zeeeeee	e e	e f dœdd„Zeeedœdd„ZdS )ÚImageGeneratorz)Base class for image generation providers©Úproviderc                 C   s&   || _ trtrttd�| _nd | _d S )N)Zapi_key)r   ÚOPENAI_AVAILABLEÚOPENAI_API_KEYr	   Úopenai_client)Úselfr   © r   ú1/var/www/lichun.app/lichun/ws/image_generation.pyÚ__init__6   s    zImageGenerator.__init__Úcozy_cartooné   )ÚpromptÚstyleÚwidthÚheightÚreturnc                 Ã   st   | j dkr |  ||||¡I dH S | j dkr@|  ||||¡I dH S | j dkr`|  ||||¡I dH S dd| j › �fS dS )z
        Generate an image using the specified provider.

        Returns:
            Tuple[image_url, error_message]
        Údalle3NÚfluxÚimagen4zUnknown provider: )r   Ú_generate_dalle3Ú_generate_fluxÚ_generate_imagen4)r   r   r   r   r   r   r   r   Úgenerate_image>   s    


zImageGenerator.generate_imagec              
   Ã   sô   t sdS | jsdS z˜|  ||¡}d}|dkr:|dkr:d}n|dkrN|dkrNd}t d|d	d
… › d�¡ | jjjd||ddd�I d	H }|jd j}t d|› �¡ |d	fW S  t	yî }	 z,dt
|	ƒ› �}
t |
¡ d	|
fW  Y d	}	~	S d	}	~	0 0 d	S )z$Generate image using OpenAI DALL-E 3)NzHOpenAI library not installed. Install with: pip install --upgrade openai)NzOpenAI API key not configuredZ	1024x1024r   i   Z	1024x1792Z	1792x1024zGenerating DALL-E 3 image: Néd   ú...zdall-e-3Zstandardé   )Úmodelr   ÚsizeZqualityÚnr   zDALL-E 3 image generated: zDALL-E 3 generation failed: )r   r   Ú_apply_styleÚloggerÚinfoÚimagesÚgenerateÚdataÚurlÚ	ExceptionÚstrÚerror)r   r   r   r   r   Úfull_promptr&   ÚresponseÚ	image_urlÚeÚ	error_msgr   r   r   r   T   s4    û

zImageGenerator._generate_dalle3c              
   Ã   s6  t sdS �zà|  ||¡}t d|dd… › d�¡ t ¡ 4 I dH �šŒ}dt › �ddœ}|||d	œd
ddddddœ}|jd||d�4 I dH �š}	|	jdkræ|	 ¡ I dH }
dd|	j› d|
› �fW  d  ƒI dH  W  d  ƒI dH  W S |	 	¡ I dH }d|v �rbt
|d ƒdk�rb|d d d }t d|› �¡ |dfW  d  ƒI dH  W  d  ƒI dH  W S W d  ƒI dH  W d  ƒI dH  W dS W d  ƒI dH  �qº1 I dH �s°0    Y  W d  ƒI dH  �qè1 I dH �sÞ0    Y  W nF t�y0 } z,dt|ƒ› �}t |¡ d|fW  Y d}~S d}~0 0 dS )z,Generate image using FLUX 1.1 Pro via fal.ai©Nzfal.ai API key not configuredzGenerating FLUX 1.1 Pro image: Nr"   r#   úKey úapplication/json©ZAuthorizationzContent-Type)r   r   é   g      @r$   TZjpegÚ2)r   Ú
image_sizeZnum_inference_stepsZguidance_scaleÚ
num_imagesÚenable_safety_checkerZoutput_formatÚsafety_tolerancez$https://fal.run/fal-ai/flux-pro/v1.1©ÚheadersÚjsonéÈ   zFLUX API error ú: r+   r   r.   zFLUX image generated: )NzNo image returned from FLUX APIzFLUX generation failed: ©Ú
FAL_AI_KEYr(   r)   r*   ÚaiohttpZClientSessionZpostÚstatusÚtextrC   Úlenr/   r0   r1   ©r   r   r   r   r   r2   ÚsessionrB   Zpayloadr3   Z
error_textÚresultr4   r5   r6   r   r   r   r      sN    þþõý
@2Š
zImageGenerator._generate_fluxc              
   Ã   sX  t sdS �z|  ||¡}t d|dd… › d�¡ t ¡ 4 I dH �š®}dt › �ddœ}|d	d
dddœ}||krxd|d< n||krŠd	|d< nd|d< |jd||d�4 I dH �š}	|	jdk�r|	 ¡ I dH }
dd|	j› d|
› �fW  d  ƒI dH  W  d  ƒI dH  W S |	 	¡ I dH }d|v �r„t
|d ƒdk�r„|d d d }t d|› �¡ |dfW  d  ƒI dH  W  d  ƒI dH  W S W d  ƒI dH  W d  ƒI dH  W dS W d  ƒI dH  �qÜ1 I dH �sÒ0    Y  W d  ƒI dH  �q
1 I dH �s 0    Y  W nF t�yR } z,dt|ƒ› �}t |¡ d|fW  Y d}~S d}~0 0 dS )z5Generate image using Google Imagen 4 Ultra via fal.air7   z!Generating Imagen 4 Ultra image: Nr"   r#   r8   r9   r:   Zlandscape_16_9r$   FÚ6)r   r=   r>   r?   r@   Zsquarer=   Zportrait_3_4z,https://fal.run/fal-ai/imagen4/preview/ultrarA   rD   zImagen 4 API error rE   r+   r   r.   z Imagen 4 Ultra image generated: )Nz#No image returned from Imagen 4 APIzImagen 4 generation failed: rF   rL   r   r   r   r    ½   sN    þû	

ý@2Š
z ImageGenerator._generate_imagen4)r   r   r   c                 C   s   |dkr|› dt › �S |S )zApply style preset to promptr   z, )ÚCOZY_CARTOON_STYLE)r   r   r   r   r   r   r(   ý   s    zImageGenerator._apply_styleN)r   r   r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚDEFAULT_PROVIDERr0   r   Úintr   r   r!   r   r   r    r(   r   r   r   r   r
   3   s>      ûúú-ú@ú@r
   r   r   ç{®Gáz¤?)r4   r   r   Ú
event_typeÚevent_categoryÚstyle_presetr   r   ÚcostÚtagsr   c
                 Ã   s0  d}
d}�zz„t ƒ }
|
 ¡ }|	r*t |	¡nd}| d| |||||||||f
¡ |
 ¡  |j}t d|› d| › �¡ |W W |r„| 	¡  |
r�|
 	¡  S  t
yì } zDt d|› �¡ |
r¼|
 ¡  W Y d}~W |rÔ| 	¡  |
rà|
 	¡  dS d}~0 0 W |� rþ| 	¡  |
�r,|
 	¡  n|�r| 	¡  |
�r*|
 	¡  0 dS )z Save generated image to databaseNa  
            INSERT INTO generated_images
            (image_url, prompt, style_preset, event_type, event_category,
             provider, generation_cost, image_width, image_height, tags)
            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
        zSaved generated image rE   z Failed to save generated image: )r   ÚcursorrC   ÚdumpsÚexecuteÚcommitÚ	lastrowidr)   r*   Úcloser/   r1   Zrollback)r4   r   r   rX   rY   rZ   r   r   r[   r\   Údbr]   Z	tags_jsonÚimage_idr5   r   r   r   Úsave_generated_image  sL    

ÿûõû
ýre   )rX   rY   Úprompt_keywordsr   c           	   
   Ã   sÒ   z–t ƒ }|jdd�}d}g }| r2|d7 }| | ¡ |rH|d7 }| |¡ |r^|d7 }| |¡ |d7 }| ||¡ | ¡ }|r’t d|d	 › �¡ |W S  tyÌ } zt d
|› �¡ W Y d}~dS d}~0 0 dS )zü
    Retrieve a cached image from database.

    Args:
        event_type: Exact event type match
        event_category: Event category match
        prompt_keywords: Keywords to search in prompt

    Returns:
        Dict with image data or None
    T©Z
dictionaryz5SELECT * FROM generated_images WHERE is_active = TRUEz AND event_type = %sz AND event_category = %sz7 AND MATCH(prompt) AGAINST(%s IN NATURAL LANGUAGE MODE)z! ORDER BY created_at DESC LIMIT 1zFound cached image: Úidz!Failed to retrieve cached image: N)	r   r]   Úappendr_   Úfetchoner)   r*   r/   r1   )	rX   rY   rf   rc   r]   ÚqueryÚparamsrN   r5   r   r   r   Úget_cached_image6  s.    


rm   é   )r   rX   rY   rZ   Úpriorityr   r   c           
   
   Ã   s†   zJt ƒ }| ¡ }| d| |||||f¡ | ¡  |j}t d|› �¡ |W S  ty€ }	 zt d|	› �¡ W Y d}	~	dS d}	~	0 0 dS )z%Add image generation request to queuez·
            INSERT INTO image_generation_queue
            (prompt, style_preset, event_type, event_category, priority, provider)
            VALUES (%s, %s, %s, %s, %s, %s)
        zAdded to generation queue: z#Failed to add to generation queue: N)	r   r]   r_   r`   ra   r)   r*   r/   r1   )
r   rX   rY   rZ   ro   r   rc   r]   Zqueue_idr5   r   r   r   Úadd_to_generation_queueh  s    	ürp   é
   )Ú
batch_sizec              
   Ã   s¨   znt ƒ }|jdd�}| d| f¡ | ¡ }|s>t d¡ W dS t dt|ƒ› d�¡ |D ]}t|ƒI dH  qXW n4 ty¢ } zt 	d|› �¡ W Y d}~n
d}~0 0 dS )	z4Process pending image generation requests from queueTrg   zÃ
            SELECT * FROM image_generation_queue
            WHERE status = 'pending' AND attempts < max_attempts
            ORDER BY priority DESC, created_at ASC
            LIMIT %s
        zNo pending images in queueNzProcessing z images from queuez$Failed to process generation queue: )
r   r]   r_   Zfetchallr)   r*   rK   Úprocess_queue_itemr/   r1   )rr   rc   r]   ÚitemsÚitemr5   r   r   r   Úprocess_generation_queue…  s    û
rv   )ru   c              
   Ã   s<  zöt ƒ }| ¡ }| d| d f¡ | ¡  t| d d�}|j| d | d d�I dH \}}|r¾t|| d | d | d	 | d
 | d d�I dH }| d|| d f¡ | ¡  t d| d › d�¡ n6| d|| d f¡ | ¡  t 	d| d › d|› �¡ W n@ t
�y6 } z&t 	d| d › d|› �¡ W Y d}~n
d}~0 0 dS )zProcess a single queue itemz 
            UPDATE image_generation_queue
            SET status = 'processing', attempts = attempts + 1, updated_at = NOW()
            WHERE id = %s
        rh   r   r   r   rZ   )r   r   NrX   rY   ©r4   r   r   rX   rY   rZ   zÙ
                UPDATE image_generation_queue
                SET status = 'completed', generated_image_id = %s,
                    completed_at = NOW(), updated_at = NOW()
                WHERE id = %s
            zQueue item z completed successfullyz§
                UPDATE image_generation_queue
                SET status = 'failed', error_message = %s, updated_at = NOW()
                WHERE id = %s
            z	 failed: zFailed to process queue item rE   )r   r]   r_   r`   r
   r!   re   r)   r*   r1   r/   )ru   rc   r]   Ú	generatorr4   r1   rd   r5   r   r   r   rs   ¢  sB    üþú

û
ürs   )r   rX   rY   r   r   Ú	use_cacher   c           
      Ã   s�   |r6t ||d�I dH }|r6t d|d › �¡ |d S t|d�}| | |¡I dH \}}	|rxt|| ||||d�I dH  |S t d|	› �¡ dS dS )zx
    Generate an image and cache it, or return cached version if available.

    Returns:
        Image URL or None
    )rX   rY   NzUsing cached image: r4   r   rw   zImage generation failed: )rm   r)   r*   r
   r!   re   r1   )
r   rX   rY   r   r   ry   Úcachedrx   r4   r1   r   r   r   Úgenerate_and_cache_imageß  s,    þ
úr{   )rX   rY   r   c              
   C   sv   z:t ƒ }|jdd�}| d| f¡ | ¡ }|r6|d ndW S  typ } zt d|› �¡ W Y d}~dS d}~0 0 dS )zp
    Get image URL for an event (synchronous for use in event functions).
    Returns cached image or None.
    Trg   a  
            SELECT gi.image_url
            FROM event_images ei
            JOIN generated_images gi ON ei.generated_image_id = gi.id
            WHERE ei.event_type = %s AND gi.is_active = TRUE
            ORDER BY ei.is_primary DESC, ei.display_order ASC
            LIMIT 1
        r4   NzFailed to get event image: )r   r]   r_   rj   r/   r)   r1   )rX   rY   rc   r]   rN   r5   r   r   r   Úget_event_image_url  s    ù	r|   c                  Ã   sž   ddddœddddœdd	d
dœg} | D ]r}t  d|d › �¡ t|d |d |d d�I dH }|rtt  d|› �¡ nt  d|d › �¡ t d¡I dH  q&dS )z)Test image generation with sample promptsz=large contemporary architecture high school building exteriorZschool_exteriorZ	education)r   rX   rY   z1cozy bedroom with desk and computer, teenage roomZbedroomÚhomez3happy family having dinner together at dining tableZfamily_dinnerÚfamilyz	Testing: r   rX   rY   Nu   âœ“ Generated: u   âœ— Failed: é   )r)   r*   r{   r1   ÚasyncioÚsleep)Ztest_promptsÚtestr4   r   r   r   Útest_generation-  s0    ýýýõýrƒ   Ú__main__)Úlevel)NNr   r   r   rW   N)NNN)rq   )N),rT   Úosr€   rC   Úloggingr   Útypingr   r   r   r   rH   r   Údatabase.db_operationsr   Zopenair	   r   ÚImportErrorÚ	getLoggerrQ   r)   r   rG   ZREPLICATE_API_TOKENZIMAGE_GENERATION_PROVIDERrU   rP   r
   r0   rV   Úfloatre   rm   rp   rv   rs   Úboolr{   r|   rƒ   ÚbasicConfigÚINFOÚrunr   r   r   r   Ú<module>   s®   

	 Z       ö
õ/   ýü4úù?úù0$
