
    Jj7                       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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)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/rurouni/.hermes/hermes-agent/plugins/image_gen/openai/__init__.py_load_openai_configr0   T   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   r0   r&   r'   strDEFAULT_MODEL)env_overrider,   
openai_cfg	candidatevaluetops         r/   _resolve_modelr?   a   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    refr8   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_safetyrM   openreadr6   pathbasename)rA   rP   rR   respnamerW   header_b64extrM   fhdatas                r/   _load_image_bytesrg   ~   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    r8   c                    dS )Nr4    selfs    r/   r`   zOpenAIImageGenProvider.name       xr@   c                    dS )NOpenAIrk   rl   s    r/   display_namez#OpenAIImageGenProvider.display_name   rn   r@   boolc                v    t           j                            d          sdS 	 dd l}n# t          $ r Y dS w xY wdS )NOPENAI_API_KEYFr   T)r6   r7   r(   r4   ImportError)rm   r4   s     r/   is_availablez#OpenAIImageGenProvider.is_available   sU    z~~.// 	5	MMMM 	 	 	55	ts   ( 
66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   pricerk   ).0model_idmetas      r/   
<listcomp>z6OpenAIImageGenProvider.list_models.<locals>.<listcomp>   sQ     	
 	
 	
 $ 	?g!+.! 	
 	
 	
r@   )r   itemsrl   s    r/   list_modelsz"OpenAIImageGenProvider.list_models   s-    	
 	
 #*--//	
 	
 	
 		
r@   Optional[str]c                    t           S )N)r9   rl   s    r/   default_modelz$OpenAIImageGenProvider.default_model   s    r@   r!   c                    dddddddgdS )	Nrp   paiduN   gpt-image-2 at low/medium/high quality tiers — text-to-image & image editingrt   zOpenAI API keyz$https://platform.openai.com/api-keys)keyprompturl)r`   badgetagenv_varsrk   rl   s    r/   get_setup_schemaz'OpenAIImageGenProvider.get_setup_schema   s4    c ,.A 	
 
 	
r@   c                    ddgddS )Ntextimage   )
modalitiesmax_reference_imagesrk   rl   s    r/   capabilitiesz#OpenAIImageGenProvider.capabilities   s      &w/LLLr@   N)	image_urlreference_image_urlsr   aspect_ratior   r   Optional[List[str]]kwargsr   c          	        |pd                                 }t          |          }|st          ddd|          S t          j                            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.          t1          |          dk    r|n|d	         ||
|	d         d          }n# t(          $ r>}t2                              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>}t2                              dd           t          d| dd|||          cY d }~S d }~ww xY wt9          |dd           pg }|st          dd d|||          S |d	         }t9          |d!d           }t9          |d"d           }t9          |d#d           }|rU	 t;          |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(}t2                              d'||           |}Y d }~nd }~ww xY wt          d(d d|||          S |
|	d         d)}|r||d#<   tA          ||||d||*          S ),N z1Prompt is required and must be a non-empty stringinvalid_argumentr4   )error
error_typeproviderr   rt   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   z)Could not load source image for editing: io_error)r   r   r   r5   r   r   rG   r   )r5   r   r   sizer   nzOpenAI image edit failedT)exc_infozOpenAI image editing failed: 	api_error)r5   r   r   r   r   zOpenAI image generation failedz OpenAI image generation failed: rf   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   r5   r   r   r   modalityextrark   )!rO   r   r   r6   r7   r(   r4   ru   r?   _SIZESr&   r8   appendr   rr   rp   iorg   BytesIOr`   r)   imagesedit	API_MODELlenr*   r+   generategetattrr   r   warningr   )rm   r   r   r   r   r   aspectr4   tier_idr   r   sourcesrA   is_editr   clientr   filesrf   fnamebior.   responsepayloadfirstrc   r   r   
saved_path	image_refr   s                                  r/   r   zOpenAIImageGenProvider.generate   sY    ,B%%''%l33 	!I-!#	    z~~.// 
	!& +!#	 	 	 		MMMM 	 	 	!P/!#	     	 '((zz&&"233  i%% 	.)//*;*; 	.NN9??,,---./CDDJ 	  	 CNN3#2#,w--%1776 ?	 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   .A3 3BBA
G 
G:G5/G:5G:>AI 
J3JJJ$J7 7
K?3K:4K?:K?*M? ?
N+	N& N+&N+O% %
P/PP)r    r8   )r    rr   )r    rw   )r    r   r    r!   )r   r8   r   r8   r   r   r   r   r   r   r    r!   )__name__
__module____qualname____doc__propertyr`   rq   rv   r   r   r   r   r	   r   rk   r@   r/   ri   ri      s        OO   X    X   

 

 

 

   
 
 
 
M M M M 1}

 $(48}
 }
 }
 }
 }
 }
 }
 }
r@   ri   Nonec                H    |                      t                                 dS )uI   Plugin entry point — wire ``OpenAIImageGenProvider`` into the registry.N)register_image_gen_providerri   )ctxs    r/   registerr     s#    ##$:$<$<=====r@   r   )r    r1   )rA   r8   r    rB   )r    r   )!r   
__future__r   loggingr6   typingr   r   r   r   r   agent.image_gen_providerr	   r
   r   r   r   r   r   r   	getLoggerr   r*   r   r   __annotations__r9   r   r0   r?   rg   ri   r   rk   r@   r/   <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s
 s
 s
 s
 s
- s
 s
 s
v> > > > > >r@   