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re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)AsyncOpenAITFzcozy 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: Nd   ...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  q1 I dH s0    Y  W d  I dH  q1 I dH s0    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rd	|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 rt
|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  q1 I dH s0    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   {Gz?)r4   r   r   
event_typeevent_categorystyle_presetr   r   costtagsr   c
                    s0  d}
d}zzt  }
|
 }|	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   zt  }|jdd}d}g }| r2|d7 }||  |rH|d7 }|| |r^|d7 }|| |d7 }||| | }|rt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<  zt  }| }|d| d f |  t| d d}|j| d | d dI dH \}}|rt|| 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$
