
    tĀi*              	       x   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 ddl	m
Z
 ddlZddlZddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZ  ej.                  e      ZdZdZdZdZddddddddddddddddZe G d d              Zd!ed"e fd#Z!d!ed"e fd$Z"d%e d&ed"efd'Z#d%e d&ed"efd(Z$d!ed"efd)Z%d!ed"efd*Z&y)+z
Thumbnail generation using Fal.ai FLUX 2 Turbo with Gemini 3 fallback.
Generates cluster-specific imagery for ANPR parking content.
    N)	dataclass)Path)Optional)genai)types)Image)get_settings)Topici  i8  webpU   zaModern supermarket parking lot with shopping carts, German retail environment, busy but organizedzVContemporary gym facility parking area, health-focused atmosphere, modern architecturezhMedical clinic parking, clean clinical environment, accessible parking spaces, German healthcare settingzaResidential apartment complex underground garage, modern German housing, organized parking spaceszSCorporate office parking structure, business park setting, professional environmentz@Hotel guest parking, hospitality environment, welcoming entrancezVGerman commercial parking facility, modern urban environment, organized parking spaces)einzelhandelfitnessarztwegfirmahoteldefaultzjFinancial visualization, ROI graphics, cost comparison charts, Euro currency, business analytics aestheticzkLegal documentation, German law books, compliance certificates, official stamps, professional legal settingzvANPR camera close-up, license plate recognition technology, infrared sensors, technical equipment, sleek modern designz_Split-screen comparison, before/after visualization, side-by-side technology, decision graphicszbStep-by-step process visualization, instructional graphics, numbered steps, clear guidance imageryz[Futuristic parking technology, smart city visualization, connected cars, digital innovationz]Problem-solution visualization, parking challenges, unauthorized vehicles, resolution imagery)branchenkostenrechttechnik	vergleichhowtotrendsproblemec                   b    e Zd ZU eed<   dZee   ed<   dZee   ed<   dZ	ee   ed<   dZ
eed<   y)ThumbnailResultsuccessN	file_pathprovidererrorg        cost_usd)__name__
__module____qualname__bool__annotations__r   r   strr    r!   r"   float     =/var/www/html/content-pipeline/modules/thumbnail_generator.pyr   r   4   s;    M#Ix}#"Hhsm"E8C=Her+   r   topicreturnc                 V   | j                   j                         }|dk(  rk| j                  j                         }| j                  j                         }t        d   j                         D ]  \  }}||v s||v s|c S  t        d   d   S t        j                  |t        d   d         S )z8Get the appropriate style context for a topic's cluster.r   r   )content_clusterlowertitletarget_keywordsCLUSTER_CONTEXTSitemsget)r-   clustertitle_lowerkeywords_lowerindustrycontexts         r,   get_cluster_contextr<   =   s    ##))+G*kk'')..446!1*!=!C!C!E 	Hg;&(n*D	  
+I66)9*)Ei)PQQr+   c                   K   t               }t        |       }d| j                   d| j                   d| d}|j                  g}|j
                  r|j                  |j
                         t        |      D ]r  \  }}	 t        j                  |      }|j                  j                  d|      }|j                  j                         }	t        j                  d|	d	d
  d       |	c S  d| dS # t         $ r}
dt#        |
      v xs dt#        |
      j%                         v }|r2|t'        |      dz
  k  r!t        j)                  d|dz    d       Y d	}
~
t        j+                  d|
        Y d	}
~
 d	}
~
ww xY ww)z6Generate an optimized image prompt using Gemini Flash.zeGenerate a detailed image prompt for a blog thumbnail about ANPR parking management.

ARTICLE TITLE: z

CLUSTER: z
STYLE CONTEXT: a  

REQUIREMENTS:
- Photorealistic, professional photography style
- 16:9 aspect ratio composition
- German/European setting (no US-style parking lots)
- Modern, clean aesthetic
- No text or logos in the image
- Appropriate for a professional B2B website
- Focus on parking technology or parking environments

OUTPUT: A single, detailed image generation prompt (max 200 words) describing the scene, lighting, composition, and style. Do not include any preamble or explanation.api_keyzgemini-3-flash-preview)modelcontentszGenerated image prompt: Nd   z...503
overloaded   zGemini 503 with key , trying fallback key...zPrompt generation failed: zRProfessional photograph of a modern German parking facility with ANPR technology, z;, photorealistic, 16:9 aspect ratio, clean modern aesthetic)r	   r<   r2   r0   gemini_api_keygemini_fallback_api_keyappend	enumerater   Clientmodelsgenerate_contenttextstriploggerdebug	Exceptionr(   r1   lenwarningr!   )r-   settingscluster_contextpromptapi_keysir?   clientresponseimage_prompteis_overloadeds               r,   generate_image_promptr_   N   s    ~H)%0O} 



	  !  !g	jF$ ''(H''889) 
7	\\'2F}}55. 6 H $==..0LLL3L#4F3GsKL& ``o_p  ql  m  m  	!SVOM|s1v||~/MMS]Q%6!6!5acU:RSTLL5aS9:	s>   A;E?>A*C2(
E?2	E<;AE7E?E71E?7E<<E?rW   output_pathc           	        K   t               }|j                  t        j                  d<   	 t	        j
                  t        j                  d| t        t        dddd       d{   }|st        d	d
      S d|vs|d   sQ|j                  dg       }t        |      rt        d	d      S t        d	dt        |j                                      S |d   d   d   }t        j                          4 d{   }|j                  |       d{   }|j#                          |j%                  d      }|j'                  |j(                         t+        j,                  |      5 }	|	j/                  |t0        t2               ddd       |j5                          ddd      d{    t        dt7        |      dd      S 7 ]7 7 # 1 sw Y   HxY w7 /# 1 d{  7  sw Y   ?xY w# t8        $ rT}
t7        |
      xs t;        |
      j<                   d}t>        jA                  d|        t        d	|      cY d}
~
S d}
~
ww xY ww)z)Generate image using Fal.ai FLUX 2 Turbo.FAL_KEYzfal-ai/flux-2/turbo)widthheightrE   T)rW   
image_size
num_imagesenable_safety_checker)	argumentsNFzFal.ai returned empty resultr   r!   imageshas_nsfw_conceptsz&Image blocked by safety checker (NSFW)zNo images in result: r   urlz.tmpqualityzfal-ai/flux-2-turbogMb?r   r   r    r"   z: (no message)zFal.ai generation failed: )!r	   fal_api_keyosenvironasyncio	to_thread
fal_client	subscribeOUTPUT_WIDTHOUTPUT_HEIGHTr   r6   anylistkeyshttpxAsyncClientraise_for_statuswith_suffixwrite_bytescontentr   opensaveOUTPUT_FORMATOUTPUT_QUALITYunlinkr(   rR   typer#   rP   r!   )rW   r`   rU   result
nsfw_flags	image_urlrZ   r[   	temp_pathimgr]   	error_msgs               r,   generate_with_falr      s'    ~H$00BJJy1?((  ! (4N)-		
 	
 "58VWW6!)9$7<J:&u<dee"5:OPTU[U`U`UbPcOd8eff8$Q'.	 $$& 	 	&#ZZ	22H%%' $//7I!!("2"23 I& M#m^LM 	 	 +&*	
 	
M	
0	2M M	 	 	 	*  ?FAa!1!1 2.A	1)=>uI>>?s   (I9G+ $G%G+ 7I82G+ *I+&G+ I#G+ 5G6G+ 9GGAG$GGG+ $G%G+  IG+ G+ GG	GG+ G(GG($G+ +	I4A	I=I>IIIc                 T  K   t               }|j                  g}|j                  r|j                  |j                         d}t	        |      D ]  \  }}	 t        j                  |      }t        j                  dgd      }|j                  j                  d|  d|      }	|	j                  r|	j                  d	   j                  st        d
d      c S |	j                  d	   j                  j                  D ]  }
t        |
d      s|
j                   s|
j                   j"                  }t%        j&                  t)        j*                  |            5 }|j,                  t.        t0        fk7  r4|j3                  t.        t0        ft$        j4                  j6                        }|j9                  |t:        t<               ddd       t        dt?        |      dd      c c S  t        d
d      c S  t        d
t?        |            S # 1 sw Y   LxY w# t@        $ r}|}dt?        |      v xs dt?        |      jC                         v }|r3|tE        |      dz
  k  r"tF        jI                  d|dz    d       Y d}~4tF        jK                  d|        Y d}~ d}~ww xY ww)z3Generate image using Gemini 3 Pro Image (fallback).Nr>   r   g      ?)response_modalitiestemperaturezgemini-3-pro-image-previewz9

[Image specifications: aspect ratio 16:9, high quality])r@   rA   configr   FzNo content in responseri   inline_datarm   Tzgemini-3-pro-imagegx&?ro   zNo image in response partsrC   rD   rE   zGemini image 503 with key rF   z"Gemini 3 image generation failed: )&r	   rG   rH   rI   rJ   r   rK   r   GenerateContentConfigrL   rM   
candidatesr   r   partshasattrr   datar   r   ioBytesIOsizerw   rx   resize
ResamplingLANCZOSr   r   r   r(   rR   r1   rS   rP   rT   r!   )rW   r`   rU   rX   
last_errorrY   r?   rZ   r   r[   part
image_datar   r]   r^   s                  r,   generate_with_geminir      sX    ~H ''(H''889J) *
7)	\\'2F00%,IF
 }}552"8#^_ 6 H &&h.A.A!.D.L.L&u<TUU ++A.66<< 4/D4D4D!%!1!1!6!6JBJJz$:; Us88m'DD"%**lM-JEL\L\LdLd"eCm^TU
 + $"%k"2!5!&	   #58TUUC*X 5J@@/U U  	J!SVOM|s1v||~/MMS]Q%6!6!;AaC5@XYZLL=aSAB	s{   AJ(B HJ(2HH>HA*H!H"J(%H2J(HH	J%!AJ <J(J J( J%%J(c                   K   t        |        d{   }t        t              j                  j                  dz  dz  }|j	                  dd       || j
                   dt         z  }t        ||       d{   }|j                  r$t        j                  d|j                          |S t        j                  d|j                          t        ||       d{   }|j                  r$t        j                  d	|j                          |S t        j                  d
|j                          |S 7 '7 7 ]w)zg
    Generate thumbnail for article topic.

    Uses Fal.ai FLUX.2 as primary, Gemini as fallback.
    Ntmp
thumbnailsT)parentsexist_ok.z!Thumbnail generated with Fal.ai: z'Fal.ai failed, trying Gemini fallback: z!Thumbnail generated with Gemini: z!All thumbnail generation failed: )r_   r   __file__parentmkdirslugr   r   r   rP   infor   rT   r!   r   )r-   rW   
output_dirr`   r   s        r,   generate_thumbnail_asyncr      s     )//F h&&--5DJTD1%**Q}o>>K %V[99F~~78H8H7IJK
NN<V\\NKL (<<F~~78H8H7IJK
LL4V\\NCDM- 0 : =s6   D?D8A'D?9D;:A%D?D= AD?;D?=D?c                 >    t        j                  t        |             S )z-Synchronous wrapper for thumbnail generation.)rs   runr   )r-   s    r,   generate_thumbnailr     s    ;;/677r+   )'__doc__rs   r   loggingrq   dataclassesr   pathlibr   typingr   ru   r|   googler   google.genair   PILr   config.settingsr	   database.modelsr
   	getLoggerr#   rP   rw   rx   r   r   r4   r   r(   r<   r_   r   r   r   r   r*   r+   r,   <module>r      sE  
  	  	 !        ( !			8	$ 
 |kzrfSk {z Hrqko! (   Ru R R".mu .m .mb6?C 6?d 6? 6?r6As 6A 6A/ 6Ar% O @8e 8 8r+   