
    `gj7                       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 y)&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portraitc                     	 ddl m}   |        }t        |t              r|j	                  d      nd}t        |t              r|S i S # t
        $ r"}t        j                  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       T/root/.hermes/venv/lib/python3.12/site-packages/plugins/image_gen/openai/__init__.py_load_openai_configr.   T   sb    1m*4S$*?#''+&T$Wd3w;; :C@	s$   AA A 	A1A,&A1,A1c                    t         j                  j                  d      } | r| t        v r| t        |    fS t	               }t        |j                  d      t              r|j                  d      ni }d}t        |t              r+|j                  d      }t        |t              r
|t        v r|}|+|j                  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   r.   r$   r%   strDEFAULT_MODEL)env_overrider*   
openai_cfg	candidatevaluetops         r-   _resolve_modelr<   a   s    ::>>"67L/W\222

C&01BD&I"rJ#I*d#w'eS!ew&6Igggc3C7NI'),,,'-000    c                   | j                         } | j                         }|j                  d      raddl}|j	                  | d      }|j                          | j                  dd      d   j                  dd      d	   xs d
}|j                  |fS |j                  d      raddl	}| j                  d      \  }}}d}	d|v r,|j                  dd      d   j                  dd      d   xs d}	|j                  |      d|	 fS ddlm}
  |
|        t        | d      5 }|j                         }ddd       t         j"                  j%                  |       xs d
}|fS # 1 sw Y   0xY w)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_safetyrH   openreadr3   pathbasename)refrK   rM   respnamerR   header_b64extrH   fhdatas                r-   _load_image_bytesrc   ~   sX    ))+CIIKE/0||C|,yya #**3226E+||T!! s+3v,,x+A.44S!<Q?H5C$sen447#	c4 Bwwy77C /KD: s   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y	)OpenAIImageGenProvideruE   OpenAI ``images.generate`` / ``images.edit`` backend — gpt-image-2.c                     y)Nr1    selfs    r-   r\   zOpenAIImageGenProvider.name       r=   c                     y)NOpenAIrg   rh   s    r-   display_namez#OpenAIImageGenProvider.display_name   rj   r=   c                l    t         j                  j                  d      sy	 dd l}y# t        $ r Y yw xY w)NOPENAI_API_KEYFr   T)r3   r4   r&   r1   ImportError)ri   r1   s     r-   is_availablez#OpenAIImageGenProvider.is_available   s7    zz~~./	   		s   ' 	33c           
     z    t         j                         D cg c]  \  }}||d   |d   |d   dd c}}S c c}}w )Nr   r   r   varies)idr   r   r   price)r   items)ri   model_idmetas      r-   list_modelsz"OpenAIImageGenProvider.list_models   sN     #*--/	
 $ 	?g!+.!	
 		
 	
s   7c                    t         S )N)r6   rh   s    r-   default_modelz$OpenAIImageGenProvider.default_model   s    r=   c                    dddddddgdS )	Nrl   paiduN   gpt-image-2 at low/medium/high quality tiers — text-to-image & image editingro   zOpenAI API keyz$https://platform.openai.com/api-keys)keyprompturl)r\   badgetagenv_varsrg   rh   s    r-   get_setup_schemaz'OpenAIImageGenProvider.get_setup_schema   s*    c ,.A	
 	
r=   c                    ddgddS )Ntextimage   )
modalitiesmax_reference_imagesrg   rh   s    r-   capabilitiesz#OpenAIImageGenProvider.capabilities   s      &w/LLr=   N)	image_urlreference_image_urlsc          	     ^   |xs dj                         }t        |      }|st        ddd|      S t        j                  j                  d      st        ddd|      S 	 d	d l}t               \  }}	t        j                  |t        d         }
g }t        |t              r/|j                         r|j                  |j                                t        |      xs g D ]  }|j                  |        |d d }t        |      }|rdnd}|j                         }|rd	d l}	 g }|D ]9  }t#        |      \  }}|j%                  |      }||_        |j                  |       ; 	 	 |j*                  j-                  t.        t1        |      dkD  r|n|d	   ||
|	d   d      }n,t.        ||
d|	d   d}	  |j*                  j6                  d+i |}t9        |dd       xs g }|st        dd d|||      S |d	   }t9        |d!d       }t9        |d"d       }t9        |d#d       }|r	 t;        |d$| %      }t        |      }n0|r	 t=        |d$| %      }t        |      }nt        d(d d|||      S |
|	d   d)}|r||d#<   tA        ||||d||*      S # t        $ r t        d
dd|      cY S w xY w# t(        $ r}t        d| dd|||      cY d }~S d }~ww xY w# t(        $ r5}t2        j5                  dd       t        d| dd|||      cY d }~S d }~ww xY w# t(        $ r5}t2        j5                  dd       t        d| dd|||      cY d }~S d }~ww xY w# t(        $ r}t        d&| dd|||      cY d }~S d }~ww xY w# t(        $ r$}t2        j?                  d'||       |}Y d }~=d }~ww xY w),N z1Prompt is required and must be a non-empty stringinvalid_argumentr1   )error
error_typeprovideraspect_ratioro   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   r2   r   r   rB   r   )r2   r   r   sizer   nzOpenAI image edit failedT)exc_infozOpenAI image editing failed: 	api_error)r2   r   r   r   r   zOpenAI image generation failedz OpenAI image generation failed: rb   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   r2   r   r   r   modalityextrarg   )!rJ   r   r   r3   r4   r&   r1   rp   r<   _SIZESr$   r5   appendr   boolrl   iorc   BytesIOr\   r'   imagesedit	API_MODELlenr(   r)   generategetattrr   r   warningr   )ri   r   r   r   r   kwargsaspectr1   tier_idrx   r   sourcesrZ   is_editr   clientr   filesrb   fnamebior,   responsepayloadfirstr_   r   r   
saved_path	image_refr   s                                  r-   r   zOpenAIImageGenProvider.generate   sO    ,B%%'%l3!I-!#	  zz~~./!& +!#	 		 '(zz&&"23  i%)//*;NN9??,-./CDJ 	 CNN3	 #2,w-%76 " &C"3C"8KD%**T*C$CHLL%	&!==--##&u:>%uQx! O . , # 	?'G16==11<G< x.4"!5+!#  QeZ.eUD) (8$?
+C''8KL
 JI

,+C''8KL
  
O	!J+!#  *.$y/ J&4E"#
 	
g  	!P/!#	 	F  %EcUK)%!!!' &  	7$G%9#?*%!!!' 	.  	=M%<SEB*%!!!' 	<  %;C5A)%!!!' "   ]
  	 s    J !A J) #;K /L M =M? J&%J&)	K2KKK	L*LLL	M*MMM	M<M71M<7M<?	N,N''N,)returnr5   )r   r   )r   zList[Dict[str, Any]])r   Optional[str]r   Dict[str, Any])r   r5   r   r5   r   r   r   zOptional[List[str]]r   r   r   r   )__name__
__module____qualname____doc__propertyr\   rm   rq   ry   r{   r   r   r	   r   rg   r=   r-   re   re      s    O   


M 1}

 $(48}
}
 }

 !}
 2}
 }
 
}
r=   re   c                6    | j                  t                      y)uI   Plugin entry point — wire ``OpenAIImageGenProvider`` into the registry.N)register_image_gen_providerre   )ctxs    r-   registerr     s    ##$:$<=r=   r   )r   zTuple[str, Dict[str, Any]])rZ   r5   r   zTuple[bytes, str])r   None)!r   
__future__r   loggingr3   typingr   r   r   r   r   agent.image_gen_providerr	   r
   r   r   r   r   r   r   	getLoggerr   r(   r   r   __annotations__r6   r   r.   r<   rc   re   r   rg   r=   r-   <module>r      s   . #  	 3 3	 	 	 
		8	$ 	 '2	 *+	 (C	&	" * % 

1:Ls
- s
v>r=   