
    5iv.              
         d Z ddlm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	Z	ddl
m
Z
mZ ddlmZ ddlmZ ddlZddlmZ  ej&                  e      ZdZd	Zd
dddZdddddddddd	Zg dZdZddddZ G d de      Zy)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IMAGE_ASPECT_RATIO_PORTRAITIMAGE_ASPECT_RATIO_LANDSCAPEIMAGE_ASPECT_RATIO_SQUARE)portrait	landscapesquare
IMAGEN_3_5IMAGEN_3_5_FASTIMAGEN_3IMAGEN_3_FAST	GEM_PIX_2IMAGEN_4NANO_BANANANANO_BANANA_PRO)	nano_banana_pro
imagen_3_5imagen_3_5_fastimagen_3imagen_3_fast	gem_pix_2imagen_4nano_banananano_banana_pro_flow))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 3zhttps://labs.googlez%https://labs.google/fx/tools/image-fxzapplication/json)OriginRefererzContent-Typec                      e Zd ZdZdZd ZddZddZddZddZ	ddZ
	 d	 	 	 	 	 	 	 dd
Z	 	 d	 	 	 	 	 	 	 	 	 ddZ	 	 	 	 	 	 	 	 ddZ	 	 d	 	 	 	 	 	 	 	 	 ddZd Zd Zd Zy	)GoogleFlowImageProviderzKGenerates images via Google ImageFX (labs.google/fx) using browser cookies.google_flowc                4   t        j                  dd      | _        t        j                  dd      | _        t        j                  t        j                  dd      j                         d      | _        t        j                  dd      j                         }t        j                  ||j                               | _
        | j                  st        d	      | j                  st        d
      d | _        d | _        t        j                  dd      | _        y )N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-token<   T)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     G/root/.openclaw/workspace/visionaryfx/providers/google_flow_provider.py__init__z 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                :    d| j                    d| j                   S )zBuild the Cookie header value.!__Secure-next-auth.session-token=z; __Host-next-auth.csrf-token=)r0   r1   r?   s    rA   _cookie_stringz&GoogleFlowImageProvider._cookie_stringy   s,     00B0B/C D++/??*;=	
rC   c                   |j                   j                  d      D ]n  }d|v s|j                  d      d   }|j                  d      d   }|r<|| j                  k7  r-|| _        t        j                  d       | j                  |        y y)z6Persist rotated session token from Set-Cookie headers.z
set-cookierE      ;r   zSession cookie rotatedN)headersget_listsplitr0   loggerdebug_persist_token)r?   responsecookie_headertokens       rA   _update_session_cookiez.GoogleFlowImageProvider._update_session_cookie   s    %--66|D 	M2mC%++,OPQRSC(+Ud&8&88).D&LL!9:''.	rC   c                *   t        t              j                         j                  j                  dz  }|j	                         sy	 |j                  d      }d|v r|j                         }g }|D ]9  }|j                  d      r|j                  d|        )|j                  |       ; |j                  dj                  |      dz   d       t        j                  d       yy# t        $ r }t        j                  d|       Y d}~yd}~ww xY w)	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joinrN   info	Exceptionwarning)r?   rS   env_pathcontentlines	new_lineslinees           rA   rP   z&GoogleFlowImageProvider._persist_token   s   >))+2299FB 	M(('(:G+w6**,	! /D'CD!((+EeW)MN!((.	/
 ##DIIi$84$?'#R;< 7  	MNNH!LL	Ms   B C) )	D2DDc                   | j                   rH| j                  r<t        j                  t        j
                        | j                  k  r| j                   S t        j                  d       | j                  j                  t        i t        d| j                         i      }| j                  |       |j                          |j                         }|j                  d      xs |j                  d      | _         |j                  d      }| j                   s&t!        dt#        |j%                                d      |r+	 t        j&                  |j)                  d	d
            | _        t        j                  d| j                  r| j                  j-                         nd       | j                   S # t*        $ r
 d| _        Y Zw xY w)z<Call /fx/api/auth/session to get a short-lived access_token.z/Refreshing access token via session endpoint...Cookie)rK   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)r:   r;   r   nowr   utcrN   rb   r>   r3   SESSION_URLDEFAULT_HEADERSrG   rT   raise_for_statusjsonRuntimeErrorlistkeysfromisoformatreplace
ValueError	isoformat)r?   respdataexpires_strs       rA   _refresh_access_tokenz-GoogleFlowImageProvider._refresh_access_token   s    ""X\\*T-?-??%%%EF{{!$--/  
 	##D)yy{!XXn5P-9Phhy)!!=d499;>O=P QE E 
 *%-%;%;''X6&" 	0.2.@.@D((*i	
 !!!  *%)"*s   *F5 5GGc                ^    | j                         }i t        | j                         d| dS )z7Return headers with Bearer auth for the generation API.zBearer )rl   Authorization)r   ru   rG   )r?   rS   s     rA   _auth_headersz%GoogleFlowImageProvider._auth_headers   s=    **,

))+&ug.
 	
rC   Nc                    |t        j                  dd      }||g|ddt        t        j                         dz         ddd| j                  i| j
                  d	S )
z&Build the JSON body for v1:runImageFx.r   i?B )candidatesCountpromptsseedrJ   i  IMAGE_FX)	sessionIdtoolmodelNameType)	userInputclientContext
modelInputaspectRatio)randomrandintinttimer8   r5   )r?   promptr   
num_imagess       rA   _build_generate_bodyz,GoogleFlowImageProvider._build_generate_body   su     <>>!V,D $."8  !TYY[4%7!8 9:"
    ,,
 	
rC   c                f   t        |      }|j                  j                  dd       | j                  |||      }t        j                  d| j                  | j                  |       | j                  j                  t        || j                               }| j                  |       |j                          |j                         }t        j                  dt!        |j#                                      |j%                  d      xs g }|s$t'        dt        j(                  |      d	d
        |d   j%                  d      xs g }	|	s(t'        dt!        |d   j#                                      |	d   }
|
j%                  d      }|
j%                  d      }|rt+        j,                  |      }n%t'        dt!        |
j#                                      t/        |d      5 }|j1                  |       d	d	d	       t        j                  d|t3        |             || _        |S # 1 sw Y   2xY w)zqGenerate 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)rw   rK   zGenerate response keys: %simagePanelsz+No imagePanels in response. Full response: Ni  r   generatedImagesz/No generatedImages in first panel. Panel keys: encodedImagemediaGenerationIdz*No encodedImage in generated image. Keys: wbzImage saved: %s (%d bytes))r   rZ   mkdirr   rN   rb   r8   r5   r>   postGENERATE_URLr   rT   rv   rw   rO   ry   rz   r3   rx   dumpsbase64	b64decodeopenwritelen_last_media_id)r?   r   output_pathr   r   bodyr   resultpanelsimagesfirst_imageencodedmedia_idimg_datafs                  rA   _generate_syncz&GoogleFlowImageProvider._generate_sync   s    ;'   =((dz(RMJJ		
 {{&&(   

 	##D)143FG M*0b=djj>PQURU>V=WX  017RA$vay~~GWBXAYZ  Qi//.1??#67''0H<T+BRBRBT=U<VW  +t$ 	GGH	 	0+s8}M '	 	s   $H''H0c                b   K   t        j                  | j                  ||fi | d{   S 7 w)z!Generate an image asynchronously.N)asyncio	to_threadr   )r?   r   r   kwargss       rA   generatez GoogleFlowImageProvider.generate8  s:      &&
8>
 
 	
 
s   &/-/c                H    | j                  ||||      }|| j                  fS )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         rA   generate_with_media_idz.GoogleFlowImageProvider.generate_with_media_idC  s5     ""Kdz # 
 T((((rC   c                8    | j                   j                          y)zClose the HTTP client.N)r>   closerF   s    rA   r   zGoogleFlowImageProvider.closeS  s    rC   c                    | S N rF   s    rA   	__enter__z!GoogleFlowImageProvider.__enter__W  s    rC   c                $    | j                          y r   )r   )r?   argss     rA   __exit__z GoogleFlowImageProvider.__exit__Z  s    

rC   )returnstr)rQ   zhttpx.Responser   None)rS   r   r   r   )r   zdict[str, str])NrI   )r   r   r   
int | Noner   r   r   dict)
r   r   r   
str | Pathr   r   r   r   r   r   )r   r   r   r   r   r   r   r   )
r   r   r   r   r   r   r   r   r   ztuple[Path, str])__name__
__module____qualname____doc__namerB   rG   rT   rP   r   r   r   r   r   r   r   r   r   r   rC   rA   r#   r#   T   s   UDF@

M0*"X
 GH

!+
@C
	
6  BB  B 	B
 B 
BH	
	
 	
 		

 
	
  ))  ) 	)
 ) 
) rC   r#   )r   
__future__r   r   r   rw   loggingr.   r   r   r   r   pathlibr   typingr   r<   providers.portsr   	getLoggerr   rN   rt   r   r2   r6   IMAGE_MODEL_OPTIONSDEFAULT_MODELru   r#   r   rC   rA   <module>r      s   $ #     	   '    )			8	$
 8B ./) $($ -   $6&Gm GrC   