
    +j                        d dl Z d dlZd dlmZ d dlmZ d dlZd dlZd dl	m
Z
 d dlmZ d dlZd dlmZ d dl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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(m)Z) d
Z*dZ+ G d de,e          Z-d(de.dej/        fdZ0 G d dej1                  Z2 G d dej1                  Z3dede4dz  fdZ5dede4dz  fdZ6dede4dz  fdZ7 G d dej1                  Z8d Z9d Z: G d dej1                  Z; G d d ej1                  Z< G d! d"ej1                  Z= G d# d$ej1                  Z> G d% d&e          Z?de?fd'Z@dS ))    N)Enum)BytesIO)Image)override)common_upscale)IOComfyExtensionInput)InputFileContentInputImageContentInputMessageInputTextContentModelResponsePropertiesOpenAICreateResponseOpenAIImageEditRequestOpenAIImageGenerationRequestOpenAIImageGenerationResponseOpenAIResponseOutputContent)	ApiEndpointdownload_url_to_bytesiodownscale_image_tensorget_number_of_imagespoll_opsync_optensor_to_base64_stringtext_filepath_to_data_urivalidate_stringz/proxy/openai/v1/responsesz<starting_point_id:(.*)>c                   >    e Zd ZdZdZdZdZdZdZdZ	dZ
d	Zd
ZdZdZdS )SupportedOpenAIModelzgpt-5.5-prozgpt-5.5zgpt-5z
gpt-5-miniz
gpt-5-nanozgpt-4.1zgpt-4.1-minizgpt-4.1-nanozo4-minio3zo1-proo1N)__name__
__module____qualname__gpt_5_5_progpt_5_5gpt_5
gpt_5_mini
gpt_5_nanogpt_4_1gpt_4_1_minigpt_4_1_nanoo4_minir!   o1_pror"        </home/wildlama/comfy/ComfyUI/comfy_api_nodes/nodes_openai.pyr    r    +   sJ        KGEJJG!L!LG	BF	BBBr1   r    timeoutreturnc                   K   | j         }|rt          |          dk    rt          d          g }|D ]}|j        r't	          t          j        |j                            }nB|j        r,t	                      }t          |j        ||           d{V  nt          d          t          j
        |                              d          }t          j        |                              t          j                  dz  }|                    t#          j        |                     |d         j        dd         \  }}	t)          |          D ]\  }
}|j        dd         ||	fk    rh|                    d                              d	d
          }t/          ||	|dd          }|                    d
d	                              d          ||
<   t#          j        |d          S )a  Validates and casts a response to a torch.Tensor.

    Args:
        response: The response to validate and cast.
        timeout: Request timeout in seconds. Defaults to None (no timeout).

    Returns:
        A torch.Tensor of shape (N, H, W, C) with all returned images; images whose
        dimensions differ from the first image's are resized to match it.

    Raises:
        ValueError: If the response is not valid.
    r   z$No images returned from API endpoint)r3   Nu>   Invalid image payload – neither URL nor base64 data present.RGBAg     o@      bilinearcenter)dim)datalen
ValueErrorb64_jsonr   base64	b64decodeurlr   r   openconvertnpasarrayastypefloat32appendtorch
from_numpyshape	enumerate	unsqueezemovedimr   squeezestack)responser3   r=   image_tensorsimg_dataimg_iopil_imgarrref_href_witsampless                r2   validate_and_cast_responser^   :   s      =D A3t99>>?@@@ )+M  4 4 	_V-h.?@@AAFF\ 	_YYF)(,PPPPPPPPPPP]^^^*V$$,,V44j!!((44u<U-c223333 !#)"1"-LE5-(( A A172A2;5%.((kk!nn,,R33G$WeUJQQG&q"55==a@@M!;}!,,,,r1   c                   V    e Zd Zed             Ze	 	 	 	 	 ddej        fd            ZdS )	OpenAIDalle2c                    t          j        ddddt           j                            dddd	          t           j                            d
ddddt           j        j        ddd	  	        t           j                            ddg ddd          t           j                            ddddddt           j        j        d          t           j                            ddd          t           j	                            ddd          gt           j        
                                gt           j        j        t           j        j        t           j        j        gdt          j        t          j        ddg          d           !	  	        S )"Nr`   u   OpenAI DALL·E 2partner/image/OpenAIu?   Generates images synchronously via OpenAI's DALL·E 2 endpoint.prompt T   Text prompt for DALL·Edefault	multilinetooltipseedr   r9   not implemented yet in backendrg   minmaxstepdisplay_modecontrol_after_generateri   optionalsize	1024x1024)256x256512x512ru   
Image sizerg   optionsri   rs   n   How many images to generaterg   rn   ro   rp   ri   rq   rs   image+Optional reference image for image editing.ri   rs   mask;Optional mask for inpainting (white areas will be replaced)widgetsa  
                (
                  $size := widgets.size;
                  $nRaw := widgets.n;
                  $n := ($nRaw != null and $nRaw != 0) ? $nRaw : 1;

                  $base :=
                    $contains($size, "256x256") ? 0.016 :
                    $contains($size, "512x512") ? 0.018 :
                    0.02;

                  {"type":"usd","usd": $round($base * $n, 3)}
                )
                
depends_onexpr	node_iddisplay_namecategorydescriptioninputsoutputshiddenis_api_nodeprice_badger   SchemaStringr
   IntNumberDisplaynumberCombor   MaskOutputHiddenauth_token_comfy_orgapi_key_comfy_org	unique_id
PriceBadgePriceBadgeDependsclss    r2   define_schemazOpenAIDalle2.define_schemak   s   y"++Y	"5	     !!#!1!8+/<!  
 
 '???(!    9!#!1!8!  	 	 I!   
 Y!   Q-^ !! 	.	+	#
 /FFF  yM
 M
 M
 M	
r1   r   Nr9   ru   r4   c                 Z  K   t          |d           d}d}d}	t          }
d }||d}d}	t          }
|                                                                }|j        \  }}}t          j        ||dd	
          }||d d d d d |f<   |j        dd          |j        dd         k    rt          d          d|                                                                z
  |d d d d df<   t          |
                    d                                                    }|                                dz                      t          j                  }t          j        |          }t#                      }|                    |d           |                    d           |}d|_        n||t          d          t+          | t-          |d          t.           |
|||||          |rdd|dfind |	           d {V }t1          j        t5          |           d {V           S )NFstrip_whitespacezdall-e-2 /proxy/openai/images/generationszapplication/json/proxy/openai/images/editsmultipart/form-data   cpudevicer9   r8   $Mask and Image must be the same size   r      PNGformatz	image.pngz3Dall-E 2 image editing requires an image AND a maskPOSTpathmethod)modelrc   r{   rt   rj   r   	image/png)response_modelr=   filescontent_type)r   r   r   rQ   r   rM   rK   ones	Exceptionr   rO   numpyrH   rF   uint8r   	fromarrayr   saveseeknamer   r   r   r   
NodeOutputr^   )r   rc   rj   r   r   r{   rt   r   r   r   request_class
img_binaryinput_tensorheightwidthchannelsrgba_tensorimage_npimgimg_byte_arrrS   s                        r2   executezOpenAIDalle2.execute   s      	77771)4
!1/D0L2M ==??..00L&2&8#FE8*VUAeDDDK+7K111ixi(z!""~QrT!222 FGGG#$t||~~'9'9';';#;K111a 01F1Fq1I1IJJRRTTK#))++c199"(CCH/(++C"99LHH\%H000a   %J)JOO$"2QRRR T&1118   k:{C  %%
 
 
 
 
 
 
 
 
* }#=h#G#GGGGGGGHHHr1   )r   NNr9   ru   r#   r$   r%   classmethodr   r   r   r   r0   r1   r2   r`   r`   i   s{        N
 N
 [N
`  
?I ?I 
?I ?I ?I [?I ?I ?Ir1   r`   c                   T    e Zd Zed             Ze	 	 	 	 d	dej        fd            ZdS )
OpenAIDalle3c                    t          j        ddddt           j                            dddd	          t           j                            d
ddddt           j        j        ddd	  	        t           j                            ddddgdd          t           j                            ddddgdd          t           j                            ddg ddd          gt           j        	                                gt           j
        j        t           j
        j        t           j
        j        gdt          j        t          j        ddg          d           	  	        S )!Nr   u   OpenAI DALL·E 3rb   u?   Generates images synchronously via OpenAI's DALL·E 3 endpoint.rc   rd   Tre   rf   rj   r   rk   r9   rl   rm   qualitystandardhdzImage qualityry   stylenaturalvividzVivid causes the model to lean towards generating hyper-real and dramatic images. Natural causes the model to produce more natural, less hyper-real looking images.rt   ru   )ru   	1024x1792	1792x1024rx   r   a  
                (
                  $size := widgets.size;
                  $q := widgets.quality;
                  $hd := $contains($q, "hd");

                  $price :=
                    $contains($size, "1024x1024")
                      ? ($hd ? 0.08 : 0.04)
                      : (($contains($size, "1792x1024") or $contains($size, "1024x1792"))
                          ? ($hd ? 0.12 : 0.08)
                          : 0.04);

                  {"type":"usd","usd": $price}
                )
                r   r   )r   r   r   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   s    r2   r   zOpenAIDalle3.define_schema  s   y"++Y	"5	     !!#!1!8+/<!  
 
 &'.+!    %&0 B!    'CCC(!   A'R !! 	.	+	#
 /8KLLL  mI
 I
 I
 I	
r1   r   r   r   ru   r4   c                    K   t          |d           d}t          | t          dd          t          t	          ||||||                     d {V }t          j        t          |           d {V           S )	NFr   zdall-e-3r   r   r   )r   rc   r   rt   r   rj   r   r=   )r   r   r   r   r   r   r   r^   )r   rc   rj   r   r   rt   r   rS   s           r2   r   zOpenAIDalle3.executeN  s       	7777 !?OOO8-  	
 
 
 
 
 
 
 
 
 }#=h#G#GGGGGGGHHHr1   N)r   r   r   ru   r   r0   r1   r2   r   r      sx        J
 J
 [J
X  I I 
I I I [I I Ir1   r   rS   c                 F    | j         j        dz  | j         j        dz  z   dz  S )Ng      $@g      D@    .Ausageinput_tokensoutput_tokensrS   s    r2   calculate_tokens_price_image_1r   l  s(    ^(4/HN4PSW4WX\gggr1   c                 F    | j         j        dz  | j         j        dz  z   dz  S )N       @g      @@r   r   r   s    r2    calculate_tokens_price_image_1_5r   q  (    ^(3.8>3ORV3VW[fffr1   c                 F    | j         j        dz  | j         j        dz  z   dz  S )Nr   g      >@r   r   r   s    r2    calculate_tokens_price_image_2_0r   u  r   r1   c                       e Zd Zed             Ze	 	 	 	 	 	 	 	 	 	 dd
ededededej        dz  dej        dz  dededededede	j
        fd            ZdS )OpenAIGPTImage1c                    t          j        dddddt           j                            dddd	          t           j                            d
ddddt           j        j        ddd	  	        t           j                            ddg ddd          t           j                            ddg ddd          t           j                            ddg ddd          t           j                            ddddddt           j        j        d          t           j                            d d!d"          t           j	                            d#d$d"          t           j                            d%g d&d'd(          t           j                            d)d*d*d+d,d-d.          t           j                            d/d*d*d+d,d-d.          gt           j        
                                gt           j        j        t           j        j        t           j        j        gdt          j        t          j        g d01          d23          4
  
        S )5Nr   OpenAI GPT Image 2rb   z?Generates images synchronously via OpenAI's GPT Image endpoint.Trc   rd   Text prompt for GPT Imagerf   rj   r   rk   r9   rl   rm   r   lowr   mediumhigh0Image quality, affects cost and generation time.ry   
backgroundautor   opaquetransparentz'Return image with or without backgroundrt   
r   ru   	1024x1536	1536x1024	2048x2048	2048x1152	1152x2048	3840x2160	2160x3840CustomzRImage size. Select 'Custom' to use the custom width and height (GPT Image 2 only).r{   r|   r}   r~   r   r   r   r   r   r   )gpt-image-1gpt-image-1.5gpt-image-2r	  )rz   rg   rs   custom_width         zOUsed only when `size` is 'Custom'. Must be a multiple of 16 (GPT Image 2 only).)rg   rn   ro   rp   ri   rs   custom_height)r   r{   r   r   a'  
                (
                  $ranges := {
                    "gpt-image-1": {
                      "low":    [0.011, 0.02],
                      "medium": [0.042, 0.07],
                      "high":   [0.167, 0.25]
                    },
                    "gpt-image-1.5": {
                      "low":    [0.009, 0.02],
                      "medium": [0.034, 0.062],
                      "high":   [0.133, 0.22]
                    },
                    "gpt-image-2": {
                      "low":    [0.0048, 0.019],
                      "medium": [0.041, 0.168],
                      "high":   [0.165, 0.67]
                    }
                  };
                  $range := $lookup($lookup($ranges, widgets.model), widgets.quality);
                  $nRaw := widgets.n;
                  $n := ($nRaw != null and $nRaw != 0) ? $nRaw : 1;
                  ($n = 1)
                    ? {"type":"range_usd","min_usd": $range[0], "max_usd": $range[1], "format": {"approximate": true}}
                    : {
                        "type":"range_usd",
                        "min_usd": $range[0] * $n,
                        "max_usd": $range[1] * $n,
                        "format": { "suffix": "/Run", "approximate": true }
                      }
                )
                r   )
r   r   r   r   is_deprecatedr   r   r   r   r   r   r   s    r2   r   zOpenAIGPTImage1.define_schema{  s   y%-+Y	"7	     !!#!1!8+/<!  
 
 !555N!     "===E!    "   q!!   $ 9!#!1!8!  	 	 I!   
 Y!   
 KKK)!	    " m!    # m!   k^@ !! 	.	+	#
 /8Q8Q8QRRR" " "]Q
 Q
 Q
 Q	
r1   r   r   r   Nr9   ru   r  r  rc   rj   r   r   r   r   r{   rt   r
  r  r   r4   c                 V	  K   t          |d           ||t          d          |dk    r|dk    rt          d          |	dz  dk    s	|
dz  dk    rt          d	|	 d
|
           t          |	|
          dk    rt          d|	 d
|
           t          |	|
          t          |	|
          z  }|dk    rt          d|	 d
|
           |	|
z  }d|cxk    rdk    sn t          d|           |	 d
|
 }n|dv r|dvrt          d| d          |dk    rt          }nC|dk    rt
          }n5|dk    rt          }|dk    rt          d          nt          d|           |g }|j        d         }t          |          D ]}|||dz            }t          |d          
                                }|                                dz                      t          j                  }t          j        |          }t#                      }|                    |d            |                    d           |dk    r|                    d!d"| d#|d$ff           |                    d%d"| d#|d$ff           |w|j        d         dk    rt+          d&          |j        dd          |j        dd'         k    rt+          d(          |j        \  }}}t-          j        ||d)d*+          }d|
                                                                z
  |d d d d df<   t          |                    d          d          
                                }|                                dz                      t          j                  }t          j        |          }t#                      }|                    |d            |                    d           |                    d,d-|d$ff           t5          | t7          d.d/0          t8          t;          |||||||d12          d3||4           d {V }nCt5          | t7          d5d/0          t8          t=          |||||||d12          |6           d {V }t?          j         tC          |           d {V           S )7NFr   (Cannot use a mask without an input imager  r	  z8Custom resolution is only supported by GPT Image 2 modelr  r   5Custom width and height must be multiples of 16, got xr  0Custom resolution max edge must be <= 3840, got r   8Custom resolution aspect ratio must not exceed 3:1, got   
  ~ JCustom resolution total pixels must be between 655,360 and 8,294,400, got )r  r  r   ru   r   r   zResolution z' is only supported by GPT Image 2 modelr  r  r   z=Transparent background is not supported for GPT Image 2 modelUnknown model: r9     @ total_pixelsr   r   r   r   image_.pngr   image[]%Cannot use a mask with multiple imager8   r   r   r   r   r   mask.pngr   r   r   r   )r   rc   r   r   r{   rj   rt   
moderationr   r   r=   r   r   price_extractorr   r   r=   r%  )"r   r?   ro   rn   r   r   r   rM   ranger   rQ   r   rH   rF   r   r   r   r   r   r   rJ   r   rK   zerosr   rO   r   r   r   r   r   r   r   r^   ) r   rc   rj   r   r   r   r   r{   rt   r
  r  r   ratior  r%  r   
batch_sizer[   single_imagescaled_imager   r   r   _r   r   	rgba_maskscaled_maskmask_npmask_imgmask_img_byte_arrrS   s                                    r2   r   zOpenAIGPTImage1.execute  s      	7777GHHH8%% ![\\\b A%%);q)@)@ !wYe!w!whu!w!wxxx<//$66 !rT`!r!rcp!r!rsssm44s<7W7WWEqyy m|mm^kmm   (-7Ll7777i7777 oamoo   #44]44DD666JJJ !\t!\!\!\]]]M!!<OOo%%>OOm##>O]** !`aaa + 6u66777EQJ:&& ] ]$QQY/5lQ\]]]eegg(..0036>>rxHHoh//&yye444!!!$$$??LL',<Q,<,<,<lK+X!YZZZZLL).>q.>.>.>k-Z![\\\\;q>Q&&#$KLLL:abb>U[2%666#$JKKK#': 65!KqGGG	%&););)=)=%=	!!!QQQ'"4Y5H5H5K5KZefffnnpp&,,..4<<RXFF ?733$+II!/>>>!&&q)))fz3Dk&RSTTT$!=fMMM<+!#)$	 	 	 3 /!        HH& %!CFSSS<1!#)$	 	 	 !0        H  }#=h#G#GGGGGGGHHHr1   )
r   r   r   NNr9   ru   r  r  r  )r#   r$   r%   r   r   strintr
   r   r   r   r   r0   r1   r2   r   r   y  s"       R
 R
 [R
h  "$(#' !"{I {I{I {I 	{I
 {I {T!{I kD {I {I {I {I {I {I 
{I {I {I [{I {I {Ir1   r   c                  |   t           j                            ddg dd          t           j                            dt           j                            t           j                            d          d t          d	d
          D             d          d          t           j                            ddd          gS )zJInputs shared by all GPT Image models (quality + reference images + mask).r   r   r   r   rg   rz   ri   imagesr   c                     g | ]}d | S )r  r0   ).0r[   s     r2   
<listcomp>z,_gpt_image_shared_inputs.<locals>.<listcomp>  s    :::|||:::r1   r9      r   )namesrn   z?Optional reference image(s) for image editing. Up to 16 images.)templateri   r   TzbOptional mask for inpainting (white areas will be replaced). Requires exactly one reference image.rs   ri   )r   r   r
   AutogrowTemplateNamesr   r'  r   r0   r1   r2   _gpt_image_shared_inputsrA    s     	---F	 	 	
 	
 	[..w''::U1b\\::: /  
 V 	 	
 	
 	4 	 	
 	
! r1   c                      t           j                            ddg dd          t           j                            ddg dd          gt                      S )	zcPer-model widget set for legacy gpt-image-1 / gpt-image-1.5 (4 base sizes, transparent bg allowed).rt   r   r  zImage size.r6  r   r   (Return image with or without background.)r   r   r
   rA  r0   r1   r2   _gpt_image_legacy_model_inputsrD    st     	CCC!	 	 	
 	
 	555>	 	 	
 	
 
"	#	# r1   c                   Z    e Zd Zed             Zedededededej	        f
d            Z
dS )	OpenAIGPTImageNodeV2c                    t          j        ddddt           j                            dddd	          t           j                            d
t           j                            dt           j                            ddg dd          t           j                            dddddd          t           j                            dddddd          t           j                            ddddgd          gt                                t           j                            dt                                t           j                            dt                                g          t           j                            dddd dd!t           j
        j        "          t           j                            d#d$d$d%dt           j
        j        dd&'          gt           j                                        gt           j        j        t           j        j        t           j        j        gdt          j        t          j        g d()          d*+          ,	  	        S )-NrF  r   rb   z1Generates images via OpenAI's GPT Image endpoint.rc   rd   Tr   rf   r   r	  rt   r   r   z?Image size. Select 'Custom' to use the custom width and height.r6  r
  r  r  r  z<Used only when `size` is 'Custom'. Must be a multiple of 16.)rg   rn   ro   rp   ri   r  r   r   rC  r  r  )rz   r{   r9   r|   r}   )rg   rn   ro   rp   ri   rq   rj   r   rk   rl   )rg   rn   ro   rp   rq   rr   ri   )r   zmodel.qualityr{   r   a9  
                (
                  $ranges := {
                    "gpt-image-1": {
                      "low":    [0.011, 0.02],
                      "medium": [0.042, 0.07],
                      "high":   [0.167, 0.25]
                    },
                    "gpt-image-1.5": {
                      "low":    [0.009, 0.02],
                      "medium": [0.034, 0.062],
                      "high":   [0.133, 0.22]
                    },
                    "gpt-image-2": {
                      "low":    [0.0048, 0.019],
                      "medium": [0.041, 0.168],
                      "high":   [0.165, 0.67]
                    }
                  };
                  $range := $lookup($lookup($ranges, widgets.model), $lookup(widgets, "model.quality"));
                  $nRaw := widgets.n;
                  $n := ($nRaw != null and $nRaw != 0) ? $nRaw : 1;
                  ($n = 1)
                    ? {"type":"range_usd","min_usd": $range[0], "max_usd": $range[1], "format": {"approximate": true}}
                    : {
                        "type":"range_usd",
                        "min_usd": $range[0] * $n,
                        "max_usd": $range[1] * $n,
                        "format": { "suffix": "/Run", "approximate": true }
                      }
                )
                r   r   )r   r   r   r
   DynamicComboOptionr   r   rA  rD  r   r   r   r   r   r   r   r   r   r   r   s    r2   r   z"OpenAIGPTImageNodeV2.define_schema  ss   y*-+K	"7	     %%..) "$*,2-& -& -& -n !/ !" !"" !#$2,0(,(,)+,j !- !" !" !#$3,0(,(,)+,j !- !" !" !#$0,2-3X,>,V	 !/ !" !"E)P ":!;!;Q), ,Z ..@^@`@`aa..}>\>^>^___0 & 3 3h 9!#!1!8    "!#!1!8+/<  	 	IN^ X__&&'	.	+	#
 /8W8W8WXXX" " "w~
 ~
 ~
 ~	
r1   rc   r   r{   rj   r4   c                 0  $K   t          |d           |d         }|d         }|d         }|d         }|                    dd          }	|                    d	d          }
|                    d
          pi }d |                                D             }t          d |D                       }|                    d          }||dk    rt	          d          |dk    r|	dz  dk    s	|
dz  dk    rt	          d|	 d|
           t          |	|
          dk    rt	          d|	 d|
           t          |	|
          t          |	|
          z  }|dk    rt	          d|	 d|
           |	|
z  }d|cxk    rdk    sn t	          d|           |	 d|
 }|dk    rt          }n.|dk    rt          }n |dk    rt          }nt	          d|           |rVg }|D ]|$t          $j                  dk    r:|                    $fd t          $j        d                   D                        T|                    $                    d                     }g }t!          |          D ]\  }}t#          |d!"                                          }|                                d#z                      t*          j                  }t/          j        |          }t3                      }|                    |d$%           |                    d           t          |          d&k    r|                    d'd(| d)|d*ff           |                    d+d(| d)|d*ff           |t          |          d&k    rt9          d,          |d         }|j        d&d          |j        d&d-         k    rt9          d.          |j        \  }}}t;          j        ||dd/0          }d&|                                                                z
  |d d d d df<   t#          |                    d          d!"                                          }|                                d#z                      t*          j                  } t/          j        |           }!t3                      }"|!                    |"d$%           |"                    d           |                    dd1|"d*ff           tA          | tC          d2d34          tD          tG          ||||||d56          d7||8           d {V }#nBtA          | tC          d9d34          tD          tI          ||||||d56          |:           d {V }#tK          j&        tO          |#           d {V           S );NFr   r   rt   r   r   r
  r  r  r7  c                     g | ]}||S Nr0   r9  r\   s     r2   r:  z0OpenAIGPTImageNodeV2.execute.<locals>.<listcomp>S  s    +]+]+]!q}A}}}r1   c              3   4   K   | ]}t          |          V  d S rL  )r   rM  s     r2   	<genexpr>z/OpenAIGPTImageNodeV2.execute.<locals>.<genexpr>T  s+      FF1+A..FFFFFFr1   r   r   r  r  r  r  r  r  r  r   r  r  r  r  r  r  r	  r  r   c              3   2   K   | ]}||d z            V  dS )r9   Nr0   )r9  r[   tensors     r2   rO  z/OpenAIGPTImageNodeV2.execute.<locals>.<genexpr>|  s0      RRaq1q5y 1RRRRRRr1   r  r  r   r   r   r9   r   r  r  r   r   r!  r8   r   r   r   r"  r   r   r   r   )r   rc   r   r   r{   rt   r#  r   r$  r   r&  )(r   getvaluessumr?   ro   rn   r   r   r   r>   rM   extendr'  rJ   rO   rN   r   rQ   r   rH   rF   r   r   r   r   r   r   r   rK   r(  r   r   r   r   r   r   r   r   r^   )%r   rc   r   r{   rj   model_idrt   r   r   r
  r  images_dictrT   n_imagesr   r)  r  r%  flatr   r[   r+  r,  r   r   r   	ref_imager-  r   r   r.  r/  r0  r1  r2  rS   rQ  s%                                       @r2   r   zOpenAIGPTImageNodeV2.executeA  s      	7777>V}<(
	"yy66		/488ii))/R+]+]{7I7I7K7K+]+]+]FFFFFFFyy  AGHHH8b A%%);q)@)@ jLjj[hjj   <//$66 e|eeVcee   m44s<7W7WWEqyy m|mm^kmm   (-7Ll7777i7777 oamoo   #44]44D}$$<OO((>OO&&>OO9x99::: I	')D' 5 5v|$$))KKRRRR5a;Q;QRRRRRRRKK 0 0 3 34444E#,T?? ] ]<5lQ\]]]eegg(..0036>>rxHHoh//&yye444!!!$$$t99>>LL',<Q,<,<,<lK+X!YZZZZLL).>q.>.>.>k-Z![\\\\t99>>#$KLLL G	:abb>Y_QrT%:::#$JKKK#': 65!KqGGG	%&););)=)=%=	!!!QQQ'"4''**  '))  ',,..4<<RXFF ?733$+II!/>>>!&&q)))fz3Dk&RSTTT$!=fMMM<+"!#)$   3 /        HH$ %!CFSSS<1"!#)$   !0        H }#=h#G#GGGGGGGHHHr1   N)r#   r$   r%   r   r   r3  dictr4  r   r   r   r0   r1   r2   rF  rF    s        
 
 [
B @I@I @I 	@I
 @I 
@I @I @I [@I @I @Ir1   rF  c                      e Zd ZdZed             Zededee         fd            Z	edee         de
fd            Zedd	ej        d
e
defd            Ze	 	 dde
d	ej        dz  dee         dz  deeez  ez           fd            Zedej        j        dddfde
dededej        dz  dee         dz  dedz  dej        fd            ZdS )OpenAIChatNodez?
    Node to generate text responses from an OpenAI model.
    c                    t          j        dddddt           j                            dddd	
          t           j                            dddd          t           j                            dt          d          t           j                            ddd          t          j        d                              ddd          t          j        d                              ddd          gt           j        	                                gt           j
        j        t           j
        j        t           j
        j        gdt          j        t          j        dg          d          
  
        S ) Nr]  zOpenAI ChatGPTpartner/text/OpenAIzText Generationz-Generate text responses from an OpenAI model.rc   rd   Tz6Text inputs to the model, used to generate a response.rf   persist_contextFz/This parameter is deprecated and has no effect.)rg   ri   advancedr   z'The model used to generate the response)rz   ri   r7  zqOptional image(s) to use as context for the model. To include multiple images, you can use the Batch Images node.r   OPENAI_INPUT_FILESr   zgOptional file(s) to use as context for the model. Accepts inputs from the OpenAI Chat Input Files node.r>  OPENAI_CHAT_CONFIGadvanced_optionsz`Optional configuration for the model. Accepts inputs from the OpenAI Chat Advanced Options node.r   an  
                (
                  $m := widgets.model;
                  $contains($m, "o4-mini") ? {
                    "type": "list_usd",
                    "usd": [0.0011, 0.0044],
                    "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" }
                  }
                  : $contains($m, "o1-pro") ? {
                    "type": "list_usd",
                    "usd": [0.15, 0.6],
                    "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" }
                  }
                  : $contains($m, "o1") ? {
                    "type": "list_usd",
                    "usd": [0.015, 0.06],
                    "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" }
                  }
                  : $contains($m, "o3-mini") ? {
                    "type": "list_usd",
                    "usd": [0.0011, 0.0044],
                    "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" }
                  }
                  : $contains($m, "o3") ? {
                    "type": "list_usd",
                    "usd": [0.01, 0.04],
                    "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" }
                  }
                  : $contains($m, "gpt-4.1-nano") ? {
                    "type": "list_usd",
                    "usd": [0.0001, 0.0004],
                    "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" }
                  }
                  : $contains($m, "gpt-4.1-mini") ? {
                    "type": "list_usd",
                    "usd": [0.0004, 0.0016],
                    "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" }
                  }
                  : $contains($m, "gpt-4.1") ? {
                    "type": "list_usd",
                    "usd": [0.002, 0.008],
                    "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" }
                  }
                  : $contains($m, "gpt-5.5-pro") ? {
                    "type": "list_usd",
                    "usd": [0.03, 0.18],
                    "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" }
                  }
                  : $contains($m, "gpt-5.5") ? {
                    "type": "list_usd",
                    "usd": [0.005, 0.03],
                    "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" }
                  }
                  : $contains($m, "gpt-5-nano") ? {
                    "type": "list_usd",
                    "usd": [0.00005, 0.0004],
                    "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" }
                  }
                  : $contains($m, "gpt-5-mini") ? {
                    "type": "list_usd",
                    "usd": [0.00025, 0.002],
                    "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" }
                  }
                  : $contains($m, "gpt-5") ? {
                    "type": "list_usd",
                    "usd": [0.00125, 0.01],
                    "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" }
                  }
                  : {"type": "text", "text": "Token-based"}
                )
                r   )
r   r   r   essentials_categoryr   r   r   r   r   r   )r   r   r   r
   Booleanr   r    r   r  r   r   r   r   r   r   r   r   s    r2   r   zOpenAIChatNode.define_schema  s   y$)* 1G	"T	     
  %!M!	 !   0E   
  P!   
 	.//55! F 6  
 	.//55&!~ 6  9!F 	  "" 	.	+	#
 /	BBBFI I Ic{
 {
 {
 {	
r1   rS   r4   c                 \    |j         D ]}|j        dk    r	|j        c S t          d          )z.Extract message content from the API response.messagez#No output message found in response)outputtypecontent	TypeError)r   rS   ri  s      r2   !get_message_content_from_responsez0OpenAIChatNode.get_message_content_from_responseI  sD     o 	& 	&F{i''~%%% (=>>>r1   message_contentc                 R    |D ]#}|j         dk    rt          |j                  c S $dS )z*Extract text content from message content.output_textz No text output found in response)rj  r3  text)r   rn  content_items      r2   get_text_from_message_contentz,OpenAIChatNode.get_text_from_message_contentQ  sC     , 	. 	.L M11<,----- 211r1   r   r   detail_levelc                 F    t          |dt          |           d          S )z2Convert a tensor to an input image content object.data:image/png;base64,input_imagedetail	image_urlrj  )r   r   )r   r   rt  s      r2   tensor_to_input_image_contentz,OpenAIChatNode.tensor_to_input_image_contentY  s5     !O/Fu/M/MOO
 
 
 	
r1   Nrc   r   c                 2   t          |d          g}|kt          |j        d                   D ]P}|                    t	          ddt          ||                             d                     d                     Q||                    |           |S )	zGCreate a list of input message contents from prompt and optional image.
input_text)rq  rj  Nr   r   rv  rw  rx  )r   r'  rM   rJ   r   r   rO   rU  )r   rc   r   r   content_listr[   s         r2   create_input_message_contentsz,OpenAIChatNode.create_input_message_contentsb  s     &|<<<W
 5;q>**  ##%%"k;RSXYZS[SeSefgShSh;i;i"k"k*      &&&r1   Fr`  r   r7  rd  c                   K   t          |d           t          | t          t          d          t          t          dt          |                     |||          d          gdd|d d|r|                    d	          ni 
           d {V }|j	        }t          | t          t           d|           t          d ddg           d {V }	t          j        |                     |                     |	                              S )NFr   r   r   user)rk  roleT)inputstorestreamr   previous_response_id)exclude_noner   /)r   c                     | j         S rL  )statusr   s    r2   <lambda>z(OpenAIChatNode.execute.<locals>.<lambda>  s    ho r1   
incomplete	completed)r   status_extractorcompleted_statusesr0   )r   r   r   RESPONSES_ENDPOINTr   r   r   r  
model_dumpidr   r   r   rs  rm  )
r   rc   r`  r   r7  r   rd  create_responseresponse_idresult_responses
             r2   r   zOpenAIChatNode.executez  s      	7777 !(/???)%   # A A&&RW X X#   %)  FV]#..D.AAA[] 	!
 !
 !
 
 
 
 
 
 
$ &( !( 2BB[BBCCC)== ,k:!
 !
 !
 
 
 
 
 
 
 }S>>s?d?det?u?uvvwwwr1   )r   NN)r#   r$   r%   __doc__r   r   r   listr   rm  r3  rs  rK   Tensorr   r{  r   r   r  r    r(   valueboolr   r   r   r   r0   r1   r2   r]  r]    s          |
 |
 [|
| ? ?DQ^L_ ? ? ? [? 2D<O 2TW 2 2 2 [2 
 
%, 
c 
_p 
 
 
 [
  &*/3	  |d" $%,	
 
!225EE	F   [.  !&&:&@&F&*/3;?(x (x(x (x $	(x
 t#(x $%,(x 2D8(x 
(x (x (x [(x (x (xr1   r]  c                       e Zd ZdZed             Zededefd            Zeg fdede	e         de
j        fd            Zd	S )
OpenAIInputFilesz7
    Loads and formats input files for OpenAI API.
    c                    t          j                    }d t          j        |          D             }t	          |d           }d |D             }t          j        ddddt
          j                            d	||r|d
         ndd          t          j	        d                              ddd          gt          j	        d          
                                g          S )z
        For details about the supported file input types, see:
        https://platform.openai.com/docs/guides/pdf-files?api-mode=responses
        c                     g | ]i}|                                 rS|j                            d           s|j                            d          r|                                j        dk     g|jS )z.txtz.pdfi   )is_filer   endswithstatst_sizer9  fs     r2   r:  z2OpenAIInputFiles.define_schema.<locals>.<listcomp>  s}     
 
 
yy{{
 ((	
 -.FOOF,C,C	

  #333	  433r1   c                     | j         S rL  r   )r  s    r2   r  z0OpenAIInputFiles.define_schema.<locals>.<lambda>  s     r1   )keyc                     g | ]	}|j         
S r0   r  r  s     r2   r:  z2OpenAIInputFiles.define_schema.<locals>.<listcomp>  s    333!qv333r1   r  zOpenAI ChatGPT Input Filesr_  u   Loads and prepares input files (text, pdf, etc.) to include as inputs for the OpenAI Chat Node. The files will be read by the OpenAI model when generating a response. 🛈 TIP: Can be chained together with other OpenAI Input File nodes.filer   NzgInput files to include as context for the model. Only accepts text (.txt) and PDF (.pdf) files for now.)rz   rg   ri   rb  zAn optional additional file(s) to batch together with the file loaded from this node. Allows chaining of input files so that a single message can include multiple input files.Tr   r   r   r   r   r   r   )folder_pathsget_input_directoryosscandirsortedr   r   r   r
   r  r   )r   	input_dirinput_filess      r2   r   zOpenAIInputFiles.define_schema  s    !466	
 
Z	**
 
 
 [.>.>???33{333y&5* G'.9CKNNt F	    	.//55( N! 6   	.//6688%
 
 
 	
r1   	file_pathr4   c                 z    t          t          |          t          j                            |          d          S )N
input_file)	file_datafilenamerj  )r   r   r  r   basename)r   r  s     r2   create_input_file_contentz*OpenAIInputFiles.create_input_file_content  s:    /	::W%%i00
 
 
 	
r1   r  rb  c                     t          j        |          }|                     |          }|g|z   }t          j        |          S )z?
        Loads and formats input files for OpenAI API.
        )r  get_annotated_filepathr  r   r   )r   r  rb  r  input_file_contentr   s         r2   r   zOpenAIInputFiles.execute  sF    
 !7==	 ::9EE#$'99}U###r1   N)r#   r$   r%   r  r   r   r3  r   r  r  r   r   r   r0   r1   r2   r  r    s          $
 $
 [$
L 
# 
:J 
 
 
 [
 MO $ $3 $D9I4J $TVTa $ $ $ [$ $ $r1   r  c            
       l    e Zd ZdZed             Ze	 	 d	dededz  dedz  de	j
        fd            ZdS )
OpenAIChatConfigzAAllows setting additional configuration for the OpenAI Chat Node.c                 X   t          j        ddddt           j                            dddgddd	
          t           j                            dddddd	d	          t           j                            dd	d	d          gt          j        d                                          g          S )Nr  zOpenAI ChatGPT Advanced Optionsr_  zKAllows specifying advanced configuration options for the OpenAI Chat Nodes.
truncationr   disableda  The truncation strategy to use for the model response. auto: If the context of this response and previous ones exceeds the model's context window size, the model will truncate the response to fit the context window by dropping input items in the middle of the conversation.disabled: If a model response will exceed the context window size for a model, the request will fail with a 400 errorT)rz   rg   ri   ra  max_output_tokensr  i   i @  zmAn upper bound for the number of tokens that can be generated for a response, including visible output tokens)rn   rg   ro   ri   rs   ra  instructionsz:Instructions for the model on how to generate the response)rh   rs   ri   rc  r  )r   r   r   r
   r   r   r  r   r   s    r2   r   zOpenAIChatConfig.define_schema  s    y&:*e #Z0" e!    '  L!!    	""!X	    #2 	.//6688; 
  
  
  	
r1   Nr  r  r  r4   c                 J    t          j        t          |||                    S )af  
        Configure advanced options for the OpenAI Chat Node.

        Note:
            While `top_p` and `temperature` are listed as properties in the
            spec, they are not supported for all models (e.g., o4-mini).
            They are not exposed as inputs at all to avoid having to manually
            remove depending on model choice.
        )r  r  r  )r   r   r   )r   r  r  r  s       r2   r   zOpenAIChatConfig.execute  s3      }#)%"3  
 
 	
r1   r  )r#   r$   r%   r  r   r   r  r3  r4  r   r   r   r0   r1   r2   r  r    s        KK!
 !
 [!
F  $((,	
 

 Dj
 :	

 

 
 
 [
 
 
r1   r  c                   L    e Zd Zedeeej                          fd            ZdS )OpenAIExtensionr4   c                 ^   K   t           t          t          t          t          t
          t          gS rL  )r`   r   r   rF  r]  r  r  )selfs    r2   get_node_listzOpenAIExtension.get_node_list&  s'        
 	
r1   N)	r#   r$   r%   r   r  rj  r   	ComfyNoder  r0   r1   r2   r  r  %  sE        	
T$r|*<%= 	
 	
 	
 X	
 	
 	
r1   r  c                  "   K   t                      S rL  )r  r0   r1   r2   comfy_entrypointr  3  s      r1   rL  )ArA   r  enumr   ior   r   rF   rK   PILr   typing_extensionsr   r  comfy.utilsr   comfy_api.latestr   r	   r
   comfy_api_nodes.apis.openair   r   r   r   r   r   r   r   r   r   r   comfy_api_nodes.utilr   r   r   r   r   r   r   r   r   r  STARTING_POINT_ID_PATTERNr3  r    r4  r  r^   r  r`   r   floatr   r   r   r   rA  rD  rF  r]  r  r  r  r  r0   r1   r2   <module>r     s    				                        & & & & & &     & & & & & & 6 6 6 6 6 6 6 6 6 6                         
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 2 7     3   ,- ,- ,-u| ,- ,- ,- ,-^SI SI SI SI SI2< SI SI SIljI jI jI jI jI2< jI jI jIZh-J huW[| h h h h
g/L gQVY]Q] g g g gg/L gQVY]Q] g g g gSI SI SI SI SIbl SI SI SIl  6  &EI EI EI EI EI2< EI EI EIP^x ^x ^x ^x ^xR\ ^x ^x ^xB<$ <$ <$ <$ <$r| <$ <$ <$~=
 =
 =
 =
 =
r| =
 =
 =
@
 
 
 
 
n 
 
 
      r1   