
    epj!8                       U d Z ddlmZ ddlZddlZddlmZmZmZm	Z	m
Z
 ddlmZ ddlmZmZmZmZmZmZmZmZ  ej        e          ZdZdd	d
dddddddddddddZded<   dZddddZd*dZd+d!Zd,d%Z  G d& d'e          Z!d-d)Z"dS ).u  OpenAI image generation backend.

Exposes OpenAI's ``gpt-image-2`` model at three quality tiers as an
:class:`ImageGenProvider` implementation. The tiers are implemented as
three virtual model IDs so the ``hermes tools`` model picker and the
``image_gen.model`` config key behave like any other multi-model backend:

    gpt-image-2-low     ~15s   fastest, good for iteration
    gpt-image-2-medium  ~40s   default — balanced
    gpt-image-2-high    ~2min  slowest, highest fidelity

All three hit the same underlying API model (``gpt-image-2``) with a
different ``quality`` parameter. Output is base64 JSON → saved under
``$HERMES_HOME/cache/images/``.

Selection precedence (first hit wins):

1. ``OPENAI_IMAGE_MODEL`` env var (escape hatch for scripts / tests)
2. ``image_gen.openai.model`` in ``config.yaml``
3. ``image_gen.model`` in ``config.yaml`` (when it's one of our tier IDs)
4. :data:`DEFAULT_MODEL` — ``gpt-image-2-medium``
    )annotationsN)AnyDictListOptionalTuple)
get_secret)DEFAULT_ASPECT_RATIOImageGenProvidererror_responsenormalize_reference_imagesresolve_aspect_ratiosave_b64_imagesave_url_imagesuccess_responsezgpt-image-2zGPT Image 2 (Low)z~15szFast iteration, lowest costlow)displayspeed	strengthsqualityzGPT Image 2 (Medium)z~40su   Balanced — defaultmediumzGPT Image 2 (High)z~2minz,Highest fidelity, strongest prompt adherencehigh)zgpt-image-2-lowgpt-image-2-mediumzgpt-image-2-highzDict[str, Dict[str, Any]]_MODELSr   	1536x1024	1024x1024	1024x1536)	landscapesquareportraitreturnDict[str, Any]c                    	 ddl m}   |             }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`` from config.yaml (returns {} on any failure).r   )load_config	image_genNz#Could not load image_gen config: %s)hermes_cli.configr$   
isinstancedictget	Exceptionloggerdebug)r$   cfgsectionexcs       G/home/thesage/.hermes/hermes-agent/plugins/image_gen/openai/__init__.py_load_openai_configr1   U   s    111111kmm*4S$*?*?I#''+&&&T$Wd33;ww;   :C@@@						s   AA 
B!B=BBTuple[str, Dict[str, Any]]c                 h   t           j                            d          } | r| t          v r| t          |          fS t	                      }t          |                    d          t                    r|                    d          ni }d}t          |t                    r5|                    d          }t          |t                    r|t          v r|}|5|                    d          }t          |t                    r|t          v r|}||t          |         fS t          t          t                   fS )z9Decide which tier to use and return ``(model_id, meta)``.OPENAI_IMAGE_MODELopenaiNmodel)	osenvironr)   r   r1   r'   r(   strDEFAULT_MODEL)env_overrider-   
openai_cfg	candidatevaluetops         r0   _resolve_modelr@   b   s   :>>"677L 3//W\222


C&01B1BD&I&IQ"""rJ#I*d## w''eS!! 	ew&6&6Igggc3 	C7NNI'),,,'-000    refr9   Tuple[bytes, str]c                T   |                                  } |                                 }|                    d          rpddl}|                    | d          }|                                 |                     dd          d                             dd          d	         pd
}|j        |fS |                    d          ruddl	}| 
                    d          \  }}}d}	d|v r8|                    dd          d                             dd          d         pd}	|                    |          d|	 fS ddlm}
  |
|            t          | d          5 }|                                }ddd           n# 1 swxY w Y   t           j                            |           pd
}||fS )zLoad image bytes from a URL or local file path.

    Returns ``(data, filename)``. Raises on any network / IO error so the
    caller can surface a clean error_response.
    )zhttp://zhttps://r   N<   )timeout?   /z	image.pngzdata:,pngzimage/;zimage.)raise_if_read_blockedrb)striplower
startswithrequestsr)   raise_for_statussplitrsplitcontentbase64	partition	b64decodeagent.file_safetyrN   openreadr7   pathbasename)rB   rQ   rS   respnamerX   header_b64extrN   fhdatas                r0   _load_image_bytesrh      s    ))++CIIKKE/00 "||C|,,yya  #**32226E+|T!!   5s++3v,,x++A.44S!<<Q?H5C$$nsnn44777777#	c4 Bwwyy              7C  /KD:s   E::E>E>c                  ~    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
ddZefdddddZdS )OpenAIImageGenProvideruE   OpenAI ``images.generate`` / ``images.edit`` backend — gpt-image-2.r!   r9   c                    dS )Nr5    selfs    r0   ra   zOpenAIImageGenProvider.name       xrA   c                    dS )NOpenAIrl   rm   s    r0   display_namez#OpenAIImageGenProvider.display_name   ro   rA   boolc                V    t          d          sdS 	 dd l}n# t          $ r Y dS w xY wdS )NOPENAI_API_KEYFr   T)r	   r5   ImportError)rn   r5   s     r0   is_availablez#OpenAIImageGenProvider.is_available   sO    *++ 	5	MMMM 	 	 	55	ts    
&&List[Dict[str, Any]]c                H    d t                                           D             S )Nc                H    g | ]\  }}||d          |d         |d         dd S )r   r   r   varies)idr   r   r   pricerl   ).0model_idmetas      r0   
<listcomp>z6OpenAIImageGenProvider.list_models.<locals>.<listcomp>   sQ     	
 	
 	
 $ 	?g!+.! 	
 	
 	
rA   )r   itemsrm   s    r0   list_modelsz"OpenAIImageGenProvider.list_models   s-    	
 	
 #*--//	
 	
 	
 		
rA   Optional[str]c                    t           S )N)r:   rm   s    r0   default_modelz$OpenAIImageGenProvider.default_model   s    rA   r"   c                    dddddddgdS )	Nrq   paiduN   gpt-image-2 at low/medium/high quality tiers — text-to-image & image editingru   zOpenAI API keyz$https://platform.openai.com/api-keys)keyprompturl)ra   badgetagenv_varsrl   rm   s    r0   get_setup_schemaz'OpenAIImageGenProvider.get_setup_schema   s4    c ,.A 	
 
 	
rA   c                    ddgddS )Ntextimage   )
modalitiesmax_reference_imagesrl   rm   s    r0   capabilitiesz#OpenAIImageGenProvider.capabilities   s      &w/LLLrA   N)	image_urlreference_image_urlsr   aspect_ratior   r   Optional[List[str]]kwargsr   c          	        |pd                                 }t          |          }|st          ddd|          S t          d          }|st          ddd|          S 	 d	d l}n## t
          $ r t          d
dd|          cY S w xY wt                      \  }	}
t                              |t          d                   }g }t          |t                    r;|                                 r'|                    |                                            t          |          pg D ]}|                    |           |d d         }t          |          }|rdnd}|                    |          }|rd	d l}	 g }|D ]E}t!          |          \  }}|                    |          }||_        |                    |           Fn/# t&          $ r"}t          d| dd|	||          cY d }~S d }~ww xY w	 |j                            t,          t/          |          dk    r|n|d	         |||
d         d          }n# t&          $ r>}t0                              dd           t          d| dd|	||          cY d }~S d }~ww xY wt,          ||d|
d         d}	  |j        j        d,i |}nK# t&          $ r>}t0                              dd           t          d| dd|	||          cY d }~S d }~ww xY wt7          |dd           pg }|st          d d!d|	||          S |d	         }t7          |d"d           }t7          |d#d           }t7          |d$d           }|rU	 t9          |d%|	 &          }n/# t&          $ r"}t          d'| dd|	||          cY d }~S d }~ww xY wt          |          }nq|rZ	 t;          |d%|	 &          }t          |          }nJ# t&          $ r(}t0                              d(||           |}Y d }~nd }~ww xY wt          d)d!d|	||          S ||
d         d*}|r||d$<   t?          ||	||d||+          S )-N z1Prompt is required and must be a non-empty stringinvalid_argumentr5   )error
error_typeproviderr   ru   uz   OPENAI_API_KEY not set. Run `hermes tools` → Image Generation → OpenAI to configure, or `hermes setup` to add the key.auth_requiredr   z8openai Python package not installed (pip install openai)missing_dependencyr   r   r   r   )api_keyz)Could not load source image for editing: io_error)r   r   r   r6   r   r   rH   r   )r6   r   r   sizer   nzOpenAI image edit failedT)exc_infozOpenAI image editing failed: 	api_error)r6   r   r   r   r   zOpenAI image generation failedz OpenAI image generation failed: rg   zOpenAI returned no image dataempty_responseb64_jsonr   revised_promptopenai_)prefixzCould not save image to cache: zGOpenAI image URL %s could not be cached (%s); falling back to bare URL.z2OpenAI response contained neither b64_json nor URL)r   r   )r   r6   r   r   r   modalityextrarl   ) rP   r   r   r	   r5   rv   r@   _SIZESr)   r'   r9   appendr   rs   rq   iorh   BytesIOra   r*   imagesedit	API_MODELlenr+   r,   generategetattrr   r   warningr   ) rn   r   r   r   r   r   aspectr   r5   tier_idr   r   sourcesrB   is_editr   clientr   filesrg   fnamebior/   responsepayloadfirstrd   r   r   
saved_path	image_refr   s                                    r0   r   zOpenAIImageGenProvider.generate   s^    ,B%%''%l33 	!I-!#	    -.. 
	!& +!#	 	 	 		MMMM 	 	 	!P/!#	     	 '((zz&&"233  i%% 	.)//*;*; 	.NN9??,,---./CDDJ 	  	 CNN3#2#,w--%1776w// ?	 III" & &C"3C"8"8KD%**T**C$CHLL%%%%	&
    %KcKK)%!!!'        !=--##&u::>>%%uQx! O .    	 	 	7$GGG%?#??*%!!!'        	 # 	?' 'G16=1<<G<< 	 	 	=MMM%BSBB*%!!!'        	 x..4" 	!5+!#    QeZ..eUD)) (8$?? %	
+C8K'8K8KLLL

   %ACAA)%!!!'         JII 	

,+C8K'8K8KLLL
  
OO		       ]  
  						  "J+!#    *.$y/ J J 	5&4E"#
 
 
 	
s    A% %BB7A
G 
G.G)#G.)G.2AH9 9
J3I<6J<JJ+ +
K353K.(K3.K3M3 3
N=NNN5O 
P#PP)r!   r9   )r!   rs   )r!   rx   )r!   r   r!   r"   )r   r9   r   r9   r   r   r   r   r   r   r!   r"   )__name__
__module____qualname____doc__propertyra   rr   rw   r   r   r   r   r
   r   rl   rA   r0   rj   rj      s        OO   X    X   

 

 

 

   
 
 
 
M M M M 1~

 $(48~
 ~
 ~
 ~
 ~
 ~
 ~
 ~
rA   rj   Nonec                H    |                      t                                 dS )uI   Plugin entry point — wire ``OpenAIImageGenProvider`` into the registry.N)register_image_gen_providerrj   )ctxs    r0   registerr     s#    ##$:$<$<=====rA   r   )r!   r2   )rB   r9   r!   rC   )r!   r   )#r   
__future__r   loggingr7   typingr   r   r   r   r   agent.secret_scoper	   agent.image_gen_providerr
   r   r   r   r   r   r   r   	getLoggerr   r+   r   r   __annotations__r:   r   r1   r@   rh   rj   r   rl   rA   r0   <module>r      s
    . # " " " " "  				 3 3 3 3 3 3 3 3 3 3 3 3 3 3 ) ) ) ) ) )	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 
	8	$	$ 	 '2	  *+	  (C	 & &    * % 
 

 
 
 
1 1 1 1:   Lt
 t
 t
 t
 t
- t
 t
 t
x> > > > > >rA   