
    JjE                    L   U d Z ddlm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mZ ddlZddlmZmZmZmZmZmZmZmZ ddlmZmZmZmZmZmZ  ej        e          Z dd	d
ddddddZ!de"d<   dZ#ddddddddZ$ddhZ%dZ&d-dZ'd.d!Z(d/d#Z)d0d&Z* G d' d(e          Z+d1d,Z,dS )2a  xAI image generation backend.

Exposes xAI's ``grok-imagine-image`` model as an
:class:`ImageGenProvider` implementation.

Features:
- Text-to-image generation
- Multiple aspect ratios (1:1, 16:9, 9:16, etc.)
- Multiple resolutions (1K, 2K)
- Base64 output saved to cache

Selection precedence (first hit wins):
1. ``XAI_IMAGE_MODEL`` env var
2. ``image_gen.xai.model`` in ``config.yaml``
3. :data:`DEFAULT_MODEL`
    )annotationsN)Path)AnyDictListOptionalTuple)DEFAULT_ASPECT_RATIOImageGenProvidererror_responsenormalize_reference_imagesresolve_aspect_ratiosave_b64_imagesave_url_imagesuccess_response)build_xai_storage_optionshermes_xai_user_agent"maybe_mark_xai_storage_notice_seenread_xai_imagine_storage_configresolve_xai_http_credentialsxai_storage_notice_textzGrok Imagine Imagez~5-10szFast, high-quality)displayspeed	strengthszGrok Imagine Image (Quality)z~10-20sz9Higher fidelity / detail; slower than the standard model.)grok-imagine-imagegrok-imagine-image-qualityzDict[str, Dict[str, Any]]_MODELSr   z16:91:1z9:164:33:43:22:3)	landscapesquareportraitr   r    r!   r"   1k2kreturnDict[str, Any]c                 n   	 ddl m}   |             }t          |t                    r|                    d          nd}t          |t                    r|                    d          nd}t          |t                    r|ni S # t
          $ r'}t                              d|           i cY d}~S d}~ww xY w)z(Read ``image_gen.xai`` from config.yaml.r   )load_config	image_genNxaiz'Could not load image_gen.xai config: %s)hermes_cli.configr+   
isinstancedictget	Exceptionloggerdebug)r+   cfgsectionxai_sectionexcs        D/home/rurouni/.hermes/hermes-agent/plugins/image_gen/xai/__init__.py_load_xai_configr:   Y   s    	111111kmm*4S$*?*?I#''+&&&T,6w,E,EOgkk%(((4(d;;C{{C   >DDD						s   B B 
B4B/)B4/B4Tuple[str, Dict[str, Any]]c                 t   t           j                            d          } | r| t          v r| t          |          fS t	                      }t          |                    d          t                    r|                    d          nd}|r|t          v r|t          |         fS t          t          t                   fS )z:Decide which model to use and return ``(model_id, meta)``.XAI_IMAGE_MODELmodelN)osenvironr1   r   r:   r/   strDEFAULT_MODEL)env_overrider5   	candidates      r9   _resolve_modelrE   g   s    :>>"344L 3//W\222


C$.swww/?/?$E$EO   4I -Y'))'),,,'-000    rA   c                     t                      } t          |                     d          t                    r|                     d          nd}|r|t          v r|S t
          S )zGet configured resolution.
resolutionN)r:   r/   r1   rA   _XAI_RESOLUTIONSDEFAULT_RESOLUTION)r5   ress     r9   _resolve_resolutionrL   u   s\    


C#-cggl.C.CS#I#I
S#'',


tC
 s&&&
rF   sourceDict[str, str]c                d   |                                  } |                                 }|                    d          r| ddS ddl}ddl}ddlm}  ||            t          |j        	                    |           d          5 }|
                                }ddd           n# 1 swxY w Y   |j                            |           d                             d	          pd
                                }|dk    rd}|                    |                              d          }d| d| ddS )zBuild the xAI ``image`` field for an edit request.

    xAI's ``/v1/images/edits`` accepts a public HTTPS URL or a base64 data URI.
    Local file paths are read and encoded into a ``data:`` URI.
    zhttp://zhttps://zdata:	image_url)urltyper   N)raise_if_read_blockedrb   .pngjpgjpegzutf-8zdata:image/z;base64,)striplower
startswithbase64r?   agent.file_safetyrT   openpath
expanduserreadsplitextlstrip	b64encodedecode)	rM   r\   r^   _osrT   fhrawextb64s	            r9   _xai_image_fieldrm   ~   s    \\^^FLLNNE899 4{333MMM 877777&!!!	ch!!&))4	0	0 Bggii              8V$$Q'..s33<u
C
C
E
EC
e||


3


&
&w
/
/C333c33[IIIs   B%%B),B)c                  v    e Zd ZdZedd            Zedd            ZddZdd	ZddZ	ddZ
efdddddZdS )XAIImageGenProviderz#xAI ``grok-imagine-image`` backend.r(   rA   c                    dS )Nr-    selfs    r9   namezXAIImageGenProvider.name   s    urF   c                    dS )Nz
xAI (Grok)rq   rr   s    r9   display_namez XAIImageGenProvider.display_name   s    |rF   boolc                b    t                      }t          |                    d                    S )Napi_key)r   rw   r1   )rs   credss     r9   is_availablez XAIImageGenProvider.is_available   s'    ,..EIIi(()))rF   List[Dict[str, Any]]c                H    d t                                           D             S )Nc           	         g | ]H\  }}||                     d |          |                     dd          |                     dd          dIS )r   r    r   )idr   r   r   )r1   ).0model_idmetas      r9   
<listcomp>z3XAIImageGenProvider.list_models.<locals>.<listcomp>   sk     
 
 
 $ 88Ix88'2..!XXk266	 
 
 
rF   )r   itemsrr   s    r9   list_modelszXAIImageGenProvider.list_models   s-    
 
 #*--//
 
 
 	
rF   r)   c                H    t          d          }d}|r|d| z  }dd|g ddS )Nr,   zVgrok-imagine-image - text-to-image & image editing; uses xAI Grok OAuth or XAI_API_KEYz. zxAI Grok Imagine (image)paidxai_grok)rt   badgetagenv_vars
post_setup)r   )rs   storage_noticer   s      r9   get_setup_schemaz$XAIImageGenProvider.get_setup_schema   sV    
 1==( 	  	)((((C.$
 
 	
rF   c                    ddgdddS )Ntextimage      )
modalitiesmax_reference_imagesmax_source_imagesrq   rr   s    r9   capabilitiesz XAIImageGenProvider.capabilities   s!     "7+$%!"
 
 	
rF   N)rQ   reference_image_urlspromptaspect_ratiorQ   Optional[str]r   Optional[List[str]]kwargsr   c          	     l   t                      }t          |                    d          pd                                          }t          |                    d          pd                                          pd}|st	          dd||          S t                      \  }	}
t          |          }t                              |d          }t                      }|t          v r|nt          }g }t          |t                    r;|                                r'|                    |                                           t          |          }|r|                    |           t          |          d	k    rt	          d
d|d||          S t!          |          D ]\  }}|dk    r|r|                                |k    rdnd}|                                }|                    d          sOt'          |                                          }|                                st	          | dd|d||          c S t-          |          }|rdnd}d| dt/                      d}t          |                    d          pd                                                              d          }t3          ddd          }t5          d          }t7          d          }|rpd}	 d  |D             }n/# t8          $ r"}t	          d!| d"||||          cY d#}~S d#}~ww xY w||d$} t          |          d%k    r|d         | d<   n|| d&<   | d'}!|}	n|	|||d(} | d)}!||| d*<   	 t;          j        |!|| d+,          }"|"                                 n4# t:          j         $ r}|j!        }"|"|"j"        nd}#	 |"#                                                    d-i                               d.|"j$        d#d/                   }$n0# t8          $ r# |"|"j$        d#d/         nt          |          }$Y nw xY wtJ          &                    d0|#|$           t	          d1|# d2|$ d3||	||          cY d#}~S d#}~wt:          j'        $ r t	          d4d5||	||          cY S t:          j(        $ r"}t	          d6| d7||	||          cY d#}~S d#}~ww xY w	 |"#                                }%n/# t8          $ r"}t	          d8| d9||	||          cY d#}~S d#}~ww xY w|%                    d:g           }&|&st	          d;d<||	||          S |&d         }'|'                    d=          }(|'                    d>          })t          |'tR                    r|'                    d?          nd#}*t          |*tR                    r|*ni }*t          |*                    d@          t                    r|*                    d@          nd#}+|+r|+},n|(rU	 tU          |(dA|	 B          }-n/# t8          $ r"}t	          dC| d"d|	||          cY d#}~S d#}~ww xY wt          |-          },nq|)rZ	 tW          |)dA|	 B          }-t          |-          },nJ# t8          $ r(}tJ          ,                    dD|)|           |)},Y d#}~nd#}~ww xY wt	          dEd<d|	||          S dFt-          |dG                   i}.|s||.dH<   |r||.dI<   |+r|+|.d@<   |*rdJD ]}/|/|*v r|*|/         |.|/<   |%                    dK          r|%dK         |.dK<   t[          |,|	||d||.L          S )Ma  Generate an image (text-to-image) or edit a source image (image-to-image).

        Routing: when ``image_url`` is provided, POST to ``/v1/images/edits``
        with the source image; otherwise POST to ``/v1/images/generations``.
        Per xAI docs, editing uses the ``grok-imagine-image-quality`` model and
        a JSON body (the OpenAI SDK's multipart ``images.edit()`` is NOT
        supported by xAI).
        ry   r   providerr-   zSNo xAI credentials found. Configure xAI OAuth in `hermes model` or set XAI_API_KEY.missing_api_key)error
error_typer   r   r   r   z2xAI image editing supports at most 3 source imagestoo_many_referencesr   )r   r   r   r>   r   r   r   rQ   r   rP   zc must be a public HTTPS URL or data URI (e.g. the `image`/`public_url` from a prior Imagine result)invalid_image_urlr   r   zBearer zapplication/json)AuthorizationzContent-Typez
User-Agentbase_urlzhttps://api.x.ai/v1/r,   zhermes-xai-imagerX   )filename_prefix	extensionc                ,    g | ]}t          |          S rq   )rm   )r   rM   s     r9   r   z0XAIImageGenProvider.generate.<locals>.<listcomp>0  s!    UUUV 0 8 8UUUrF   z)Could not load source image for editing: io_errorN)r>   r   rV   imagesz/images/edits)r>   r   r   rH   z/images/generationsstorage_optionsx   )headersjsontimeoutr   messagei,  zxAI image gen failed (%d): %szxAI image generation failed (z): 	api_errorz%xAI image generation timed out (120s)r   zxAI connection error: connection_errorzxAI returned invalid JSON: invalid_responsedatazxAI returned no image dataempty_responseb64_jsonrR   file_output
public_urlxai_)prefixzCould not save image to cache: zDxAI image URL %s could not be cached (%s); falling back to bare URL.z/xAI response contained neither b64_json nor URLstorage_enabledenabledrH   r   )filename
expires_atpublic_url_expires_atpublic_url_errorstorage_errorusage)r   r>   r   r   r   modalityextra).r   rA   r1   r[   r   rE   r   _XAI_ASPECT_RATIOSrL   rI   rJ   r/   appendr   extendlen	enumerater\   r]   r   rb   is_filerw   r   rstripr   r   r   r2   requestspostraise_for_status	HTTPErrorresponsestatus_coder   r   r3   r   TimeoutConnectionErrorr0   r   r   warningr   )0rs   r   r   rQ   r   r   rz   ry   provider_namer   r   aspectxai_arrH   xai_ressource_imagesrefsindexrM   fieldr\   ra   is_editr   r   r   r   r   storage_cfg
edit_modelimage_fieldsr8   payloadendpoint_urlr   statuserr_msgresultr   firstrl   rR   r   r   	image_ref
saved_pathr   keys0                                                   r9   generatezXAIImageGenProvider.generate   s	   " -..eii	**0b117799EIIj11:U;;AACCLu 	!k,&)	    ())$%l33#''66(**
 *.> > >**DV#%i%% 	4)//*;*; 	4  !2!2333)*>?? 	'  &&&}!!!J0&2#    '}55 	 	ME6#(A::):	@Q@QU[@[@[KKawELLNNE##$DEE F||..00||~~ )$ Z Z Z $7!.:%%+
 
 
 
 
 
 }%%%1776 1w00./11
 
 uyy,,E0EFFLLNNUUVYZZ3.
 
 

 <KHH5kBB !	< 6J
UU}UUU   %KcKK)*$!!'         $ ' 'G <  A%%#/?  $0!&555L!HH "  &%	 G ';;;L&)8G%&)	}	  H %%''''! 	 	 	|H-5-AX))qFT"--//--gr::>>y(-X\Y\X\J]^^ T T T191E(---3s88TLL8&'JJJ!JfJJJJ&&#          	 	 	!=$&#      ' 	 	 	!4s44-&#        	
	]]__FF 	 	 	!9C99-&#        	 zz&"%% 	!2+&#    Qii
##ii2<UD2I2ISeii...t%/T%B%BJkk6@Q]A^A^`c6d6dn[__\222jn
 *	"II (	
+C8Ix8I8IJJJ

   %ACAA)""!!'         JII 	
,+C8Ix8I8IJJJ
  
OO		       Z  
  						  "G+#    tK	$:;;!
  	*")E, 	5&4E"# 	-",E, 		2 2 2 +%%!,S!1E#J::g 	-#G_E'N
 
 
 	
s   &K3 3
L=LLL',N S$Q-7A	P Q-*P.+Q--P..9Q-'S-'SS$S;SS
S 
T)T TT9X 
X:X5/X:5X:Y4 4
Z&>Z!!Z&r(   rA   )r(   rw   )r(   r|   r(   r)   )r   rA   r   rA   rQ   r   r   r   r   r   r(   r)   )__name__
__module____qualname____doc__propertyrt   rv   r{   r   r   r   r
   r   rq   rF   r9   ro   ro      s        --   X    X* * * *	
 	
 	
 	

 
 
 
(
 
 
 
 1N

 $(48N
 N
 N
 N
 N
 N
 N
 N
rF   ro   ctxr   Nonec                H    |                      t                                 dS )z3Register this provider with the image gen registry.N)register_image_gen_providerro   )r   s    r9   registerr     s#    ##$7$9$9:::::rF   r   )r(   r;   r   )rM   rA   r(   rN   )r   r   r(   r   )-r   
__future__r   loggingr?   pathlibr   typingr   r   r   r   r	   r   agent.image_gen_providerr
   r   r   r   r   r   r   r   tools.xai_httpr   r   r   r   r   r   	getLoggerr   r3   r   __annotations__rB   r   rI   rJ   r:   rE   rL   rm   ro   r   rq   rF   r9   <module>r     su    " # " " " " "  				       3 3 3 3 3 3 3 3 3 3 3 3 3 3 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	                
	8	$	$ ()  2P# #& &     %    $<     1 1 1 1   J J J JBE
 E
 E
 E
 E
* E
 E
 E
Z
; ; ; ; ; ;rF   