+
    fiv.                        R t ^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	t	^ RI
H
t
Ht ^ RIHt ^ RIHt ^ RIt^ RIHt ]P&                  ! ]4      tRtRtR	R
RRRR/tRRRRRRRRRRRRRRRRRR/	t. R(OtRtR R!R"R#R$R%/t ! R& R']4      tR# ))u  
Google ImageFX / Flow Image Provider – generates images via the
aisandbox-pa.googleapis.com API using manually extracted browser cookies.

Auth flow (reverse-engineered):
  1. Exchange browser cookies for a Bearer access_token via
     https://labs.google/fx/api/auth/session
  2. Call https://aisandbox-pa.googleapis.com/v1:runImageFx with Bearer auth

HOW TO GET YOUR COOKIES:
1. Open https://labs.google/fx/tools/image-fx in Chrome
2. Open DevTools (F12) → Application → Cookies → https://labs.google
3. Copy `__Secure-next-auth.session-token` and
   `__Host-next-auth.csrf-token`
4. Paste them into your .env as GOOGLE_FLOW_SESSION_TOKEN and
   GOOGLE_FLOW_CSRF_TOKEN respectively.
)annotationsN)datetimetimezone)Path)Any)ImageProviderz'https://labs.google/fx/api/auth/sessionz1https://aisandbox-pa.googleapis.com/v1:runImageFxportraitIMAGE_ASPECT_RATIO_PORTRAIT	landscapeIMAGE_ASPECT_RATIO_LANDSCAPEsquareIMAGE_ASPECT_RATIO_SQUAREnano_banana_pro
IMAGEN_3_5
imagen_3_5imagen_3_5_fastIMAGEN_3_5_FASTimagen_3IMAGEN_3imagen_3_fastIMAGEN_3_FAST	gem_pix_2	GEM_PIX_2imagen_4IMAGEN_4nano_bananaNANO_BANANAnano_banana_pro_flowNANO_BANANA_PROOriginzhttps://labs.googleRefererz%https://labs.google/fx/tools/image-fxzContent-Typezapplication/jsonc                      ] tR t^TtRtRtR tR R ltR R ltR R	 lt	R
 R lt
R R ltRR R lltRR R lltR R ltRR R lltR tR tR tRtR# )GoogleFlowImageProviderzKGenerates images via Google ImageFX (labs.google/fx) using browser cookies.google_flowc                	V   \         P                  ! R R4      V n        \         P                  ! RR4      V n        \        P                  \         P                  ! RR4      P                  4       R4      V n        \         P                  ! RR4      P                  4       p\        P                  WP                  4       4      V n
        V P                  '       g   \        R4      hV P                  '       g   \        R	4      hR
V n        R
V n        \        P                  ! ^<RR7      V n        R
# )GOOGLE_FLOW_SESSION_TOKEN GOOGLE_FLOW_CSRF_TOKENGOOGLE_FLOW_ASPECT_RATIOr   r	   GOOGLE_FLOW_MODELr   u   GOOGLE_FLOW_SESSION_TOKEN is required. Extract it from Chrome DevTools → Application → Cookies → https://labs.google → __Secure-next-auth.session-tokenu   GOOGLE_FLOW_CSRF_TOKEN is required. Extract it from Chrome DevTools → Application → Cookies → https://labs.google → __Host-next-auth.csrf-tokenNT)timeoutfollow_redirects)osgetenvsession_token
csrf_tokenASPECT_RATIOSgetloweraspect_ratioIMAGE_MODELSuppermodelEnvironmentError_access_token_token_expiryhttpxClientclient)self	model_keys   & !providers/google_flow_provider.py__init__ GoogleFlowImageProvider.__init__Y   s    YY'BBG))$<bA)--II0*=CCE)
 II13DEKKM	!%%i1BC
!!!"K 
 "F  *..2ll2E    c                   V ^8  d   QhRR/#    returnstr )formats   "r?   __annotate__$GoogleFlowImageProvider.__annotate__y   s     
 
 
rB   c                :    RV P                    RV P                   2# )zBuild the Cookie header value.!__Secure-next-auth.session-token=z; __Host-next-auth.csrf-token=)r.   r/   r=   s   &r?   _cookie_string&GoogleFlowImageProvider._cookie_stringy   s,     00B0B/C D++/??*;=	
rB   c                    V ^8  d   QhRRRR/# )rE   responsezhttpx.ResponserF   NonerH   )rI   s   "r?   rJ   rK      s     
 
~ 
$ 
rB   c                F   VP                   P                  R4       F  pRV9   g   K  VP                  R4      ^,          pVP                  R4      ^ ,          pV'       d=   W0P                  8w  d-   W0n        \        P                  R4       V P                  V4        R# 	  R# )z6Persist rotated session token from Set-Cookie headers.z
set-cookierM   ;zSession cookie rotatedN)headersget_listsplitr.   loggerdebug_persist_token)r=   rR   cookie_headertokens   &&  r?   _update_session_cookie.GoogleFlowImageProvider._update_session_cookie   s    %--66|DM2mC%++,OPQRSC(+U&8&88).&LL!9:''. ErB   c                    V ^8  d   QhRRRR/# )rE   r]   rG   rF   rS   rH   )rI   s   "r?   rJ   rK      s     M MC MD MrB   c                j   \        \        4      P                  4       P                  P                  R,          pVP	                  4       '       g   R#  VP                  RR7      pRV9   d   VP                  4       p. pV FA  pVP                  R4      '       d   VP                  RV 24       K0  VP                  V4       KC  	  VP                  RP                  V4      R,           RR7       \        P                  R4       R# R#   \         d"   p\        P                  RT4        Rp?R# Rp?ii ; i)	z7Try to update the .env file with the new session token.z.envNzutf-8)encodingzGOOGLE_FLOW_SESSION_TOKEN=
zUpdated session token in .envz+Could not persist rotated token to .env: %s)r   __file__resolveparentexists	read_text
splitlines
startswithappend
write_textjoinrY   info	Exceptionwarning)r=   r]   env_pathcontentlines	new_lineslinees   &&      r?   r[   &GoogleFlowImageProvider._persist_token   s   >))+2299FB  	M(('(:G+w6**,	!D'CDD!((+EeW)MN!((.	 "
 ##DIIi$84$?'#R;< 7  	MNNH!LL	Ms   B0D D2D--D2c                   V ^8  d   QhRR/# rD   rH   )rI   s   "r?   rJ   rK      s     *" *"s *"rB   c                   V P                   '       dR   V P                  '       d@   \        P                  ! \        P
                  4      V P                  8  d   V P                   # \        P                  R4       V P                  P                  \        / \        CRV P                  4       /CR7      pV P                  V4       VP                  4        VP                  4       pVP                  R4      ;'       g    VP                  R4      V n         VP                  R4      pV P                   '       g'   \!        R\#        VP%                  4       4       R24      hV'       d-    \        P&                  ! VP)                  R	R
4      4      V n        \        P                  RV P                  '       d   V P                  P-                  4       MR4       V P                   #   \*         d    RT n         Lbi ; i)z<Call /fx/api/auth/session to get a short-lived access_token.z/Refreshing access token via session endpoint...Cookie)rV   access_tokenaccessTokenexpiresz+No access_token in session response. Keys: u4   . Cookies may be expired — re-extract from Chrome.Zz+00:00Nz"Access token obtained (expires %s)unknown)r8   r9   r   nowr   utcrY   rn   r<   r1   SESSION_URLDEFAULT_HEADERSrO   r^   raise_for_statusjsonRuntimeErrorlistkeysfromisoformatreplace
ValueError	isoformat)r=   respdataexpires_strs   &   r?   _refresh_access_token-GoogleFlowImageProvider._refresh_access_token   s    """X\\*T-?-??%%%EF{{!$--/  
 	##D)yy{!XXn5PP-9Phhy)!!!=d499;>O=P QE E 
 *%-%;%;''X6&" 	0.2.@.@.@D((*i	
 !!!  *%)"*s   $+G G21G2c                   V ^8  d   QhRR/# )rE   rF   zdict[str, str]rH   )rI   s   "r?   rJ   rK      s     
 
~ 
rB   c                `    V P                  4       p/ \        CRV P                  4       RRV 2/C# )z7Return headers with Bearer auth for the generation API.rz   AuthorizationzBearer )r   r   rO   )r=   r]   s   & r?   _auth_headers%GoogleFlowImageProvider._auth_headers   sA    **,

d))+wug.
 	
rB   Nc               (    V ^8  d   QhRRRRRRRR/# )	rE   promptrG   seed
int | None
num_imagesintrF   dictrH   )rI   s   "r?   rJ   rK      s,     
 

!+
@C
	
rB   c           	         Vf   \         P                  ! ^ R4      pRRVRV.RV/RRR\        \        P                  ! 4       R	,          4       2R
R/RRV P                  /RV P
                  /# )z&Build the JSON body for v1:runImageFx.i?B 	userInputcandidatesCountpromptsr   clientContext	sessionIdrU   i  toolIMAGE_FX
modelInputmodelNameTypeaspectRatio)randomrandintr   timer6   r3   )r=   r   r   r   s   &&&&r?   _build_generate_body,GoogleFlowImageProvider._build_generate_body   s     <>>!V,D !:F8
 qTYY[4%7!8 9:
  4,,
 	
rB   c          
     ,    V ^8  d   QhRRRRRRRRR	R
/# )rE   r   rG   output_path
str | Pathr   r   r   r   rF   r   rH   )rI   s   "r?   rJ   rK      sC     B BB  B 	B
 B 
BrB   c                   \        V4      pVP                  P                  RRR7       V P                  WVR7      p\        P                  RV P                  V P                  V4       V P                  P                  \        VV P                  4       R7      pV P                  V4       VP                  4        VP                  4       p\        P                  R\!        VP#                  4       4      4       VP%                  R4      ;'       g    . pV'       g*   \'        R\        P(                  ! V4      R	,           24      hV^ ,          P%                  R
4      ;'       g    . p	V	'       g-   \'        R\!        V^ ,          P#                  4       4       24      hV	^ ,          p
V
P%                  R4      pV
P%                  R4      pV'       d   \*        P,                  ! V4      pM%\'        R\!        V
P#                  4       4       24      h\/        VR4      ;_uu_ 4       pVP1                  V4       RRR4       \        P                  RV\3        V4      4       Wn        V#   + '       g   i     L8; i)zaGenerate an image from *prompt* and save to *output_path*.

Returns the Path of the saved image.
T)parentsexist_okr   r   u?   Generating image via Google ImageFX  model=%s  aspect=%s → %s)r   rV   zGenerate response keys: %simagePanelsz+No imagePanels in response. Full response: :Ni  NgeneratedImagesz/No generatedImages in first panel. Panel keys: encodedImagemediaGenerationIdz*No encodedImage in generated image. Keys: wbNzImage saved: %s (%d bytes))r   rf   mkdirr   rY   rn   r6   r3   r<   postGENERATE_URLr   r^   r   r   rZ   r   r   r1   r   dumpsbase64	b64decodeopenwritelen_last_media_id)r=   r   r   r   r   bodyr   resultpanelsimagesfirst_imageencodedmedia_idimg_datafs   &&&&&          r?   _generate_sync&GoogleFlowImageProvider._generate_sync   s    ;'   =((z(RMJJ		
 {{&&(   

 	##D)143FG M*00b=djj>PQU>V=WX  0177RA$vay~~GWBXAYZ  Qi//.1??#67''0H<T+BRBRBT=U<VW  +t$$GGH % 	0+s8}M ' %$s   II-	c               (    V ^8  d   QhRRRRRRRR/# )rE   r   rG   r   r   kwargsr   rF   rH   )rI   s   "r?   rJ   rK   8  s2     	
 	
	
 	
 		

 
	
rB   c                b   "   \         P                  ! V P                  W3/ VB G Rj  xL
 #  L5i)z!Generate an image asynchronously.N)asyncio	to_threadr   )r=   r   r   r   s   &&&,r?   generate GoogleFlowImageProvider.generate8  s7      &&
8>
 
 	
 
s   &/-/c          
     ,    V ^8  d   QhRRRRRRRRR	R
/# )rE   r   rG   r   r   r   r   r   r   rF   ztuple[Path, str]rH   )rI   s   "r?   rJ   rK   C  s<     ) ))  ) 	)
 ) 
)rB   c                B    V P                  WW4R7      pWPP                  3# )zGenerate an image and return both the path and the mediaGenerationId.

The mediaGenerationId can be used as startImage.mediaId for I2V video generation.
r   )r   r   )r=   r   r   r   r   paths   &&&&& r?   generate_with_media_id.GoogleFlowImageProvider.generate_with_media_idC  s/     ""d # 
 ((((rB   c                :    V P                   P                  4        R# )zClose the HTTP client.N)r<   closerN   s   &r?   r   GoogleFlowImageProvider.closeS  s    rB   c                	    V # NrH   rN   s   &r?   	__enter__!GoogleFlowImageProvider.__enter__W  s    rB   c                	&    V P                  4        R # r   )r   )r=   argss   &*r?   __exit__ GoogleFlowImageProvider.__exit__Z  s    

rB   )r8   r   r9   r3   r<   r/   r6   r.   )N   )__name__
__module____qualname____firstlineno____doc__namer@   rO   r^   r[   r   r   r   r   r   r   r   r   r   __static_attributes__rH   rB   r?   r"   r"   T   sQ    UDF@

M0*"X

.BH	
) rB   r"   ))r   zGemini Pix 2 (newest))r   zImagen 4)r   zNano Banana Pro (Flow))r   zImagen 3.5 (Nano Banana Pro))r   zImagen 3.5 Fast)r   zImagen 3)r   
__future__r   r   r   r   loggingr,   r   r   r   r   pathlibr   typingr   r:   providers.portsr   	getLoggerr   rY   r   r   r0   r4   IMAGE_MODEL_OPTIONSDEFAULT_MODELr   r"   rH   rB   r?   <module>r      s   $ #     	   '    )			8	$
 8B -/) |,(
_
=-   #6&Gm GrB   