
    ^(jt7                     6   U d Z ddlmZ ddlm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 dZed	   Z ed
       G d d             Z  e ddddd       e ddddd       e ddddd       e dddddd       e dddd d       e d!ddd d       e d"dd#d$       e d%dd&d'       e d(dd)d*       e d+dd,d-       e d.dd/d0d1d       e d2dd3d4d1d       e d5d6d7dd8       e d9ddd:d8       e d;dd<d=       e d>dd?d@       e dAddBdCd1       e dDdd?d        e dEdFdGdH       e dIdJdKdL       e dMdJdKdL      gZ!e"e    e#dN<   e!D  ci c]  } | jH                  |  c} Z%e&e'e f   e#dO<   g dPZ(g dQZ)dRe"fdSZ*dRe"fdTZ+dUedRe"fdVZ,dWe dRe"fdXZ-dWe dRe"fdYZ.dRe"ej^                  j`                     fdZZ1d[edRe2d\z  fd]Z3dRe'fd^Z4d_e5ejl                     dWe d`e"e
jn                     dRe"e   fdaZ8d_e5ejl                     dbe"e
jr                     dRe"e   fdcZ:dde'dee"e   dRefdfZ;dge'dde'dee"e   dRe"e   fdhZ<die'dge'dde'dee"e   dje=dke'd\z  dle'd\z  dRefdmZ>d[edRe'fdnZ? G do dpejl                        Z@ G dq dre	      ZAdReAfdsZBy\c c} w )tz.API Nodes for OpenRouter LLM chat completions.    )	dataclass)Literal)override)IOComfyExtensionInput)OpenRouterChatRequestOpenRouterChatResponseOpenRouterContentBlockOpenRouterImageContentOpenRouterImageUrlOpenRouterMessageOpenRouterReasoningConfigOpenRouterTextContentOpenRouterVideoContentOpenRouterVideoUrlOpenRouterWebSearchOptions)ApiEndpointget_number_of_imagessync_opupload_images_to_comfyapiupload_video_to_comfyapivalidate_stringz)/proxy/openrouter/api/v1/chat/completions)standard	reasoningfrontier_reasoning
perplexityperplexity_reasoningT)frozenc                   R    e Zd ZU eed<   eed<   eed<   eed<   dZeed<   dZ	eed<   y)	
_ModelSpecslugprofileprice_in	price_outr   
max_images
max_videosN)
__name__
__module____qualname__str__annotations__Profilefloatr&   intr'        J/Users/danicosta/Desktop/Flux2/ComfyUI/comfy_api_nodes/nodes_openrouter.pyr!   r!   %   s,    
IOJJr1   r!   zanthropic/claude-opus-4.7r   gh㈵>g-C6>   )r&   zopenai/gpt-5.5-progiUMu>g9̗'?zopenai/gpt-5.5zgoogle/gemini-3.5-flashr   gTqs*>g?̔>   )r&   r'   zx-ai/grok-4.20gh㈵>gh㈵>zx-ai/grok-4.3zdeepseek/deepseek-v4-progy;>1>gy;>1>zdeepseek/deepseek-v4-flashgC֔~>gC֔>zdeepseek/deepseek-v3.2g:;S>gXɔ]>zqwen/qwen3.6-max-previewgqr>g*#&,>zqwen/qwen3.6-plusgkNuϕ>gJ֗[>
   zqwen/qwen3.6-flashgTqs*>g?߲̔>zmistralai/mistral-large-2512r   gƠ>   zmistralai/mistral-medium-3-5giUMu>zz-ai/glm-4.6gn<Wۜ>gy;>1>z
z-ai/glm-5gv!>g+i)+>zmoonshotai/kimi-k2.6g_~>g+/\ʷF>zmoonshotai/kimi-k2-thinkingzperplexity/sonar-pror   gTqs*>giUMu>zperplexity/sonar-reasoning-pror   g>g>zperplexity/sonar-deep-researchMODELS_MODELS_BY_SLUG)offlowmediumhigh)r:   r;   r<   returnc                  T    t         j                  j                  dt        ddd      gS )Nreasoning_effortr9   z4Reasoning effort. 'off' disables reasoning entirely.Toptionsdefaulttooltipadvanced)r   Combor   _REASONING_EFFORTSr0   r1   r2   _reasoning_extra_inputsrG   L   s0    
&J 	 	
 r1   c                  T    t         j                  j                  dt        ddd      gS )Nsearch_context_sizer;   zSHow much web search context to retrieve. Larger = more grounded but slower/pricier.Tr@   )r   rE   r   _SEARCH_CONTEXT_SIZESr0   r1   r2   _perplexity_extra_inputsrK   X   s0    
!)i 	 	
 r1   r#   c                     | dk(  rg S | dv r
t               S | dk(  r
t               S | dk(  rt               t               z   S t        d|        )Nr   )r   r   r   r   zUnknown profile: )rG   rK   
ValueError)r#   s    r2   _profile_inputsrN   d   s`    *	55&((,'))(('),C,EEE
(	2
33r1   specc                    g }| j                   dkD  r|j                  t        j                  j	                  dt        j                  j                  t        j                  j	                  d      t        d| j                   dz         D cg c]  }d| 	 c}d      d| j                    d	             | j                  dkD  r|j                  t        j                  j	                  d
t        j                  j                  t        j                  j	                  d      t        d| j                  dz         D cg c]  }d| 	 c}d      d| j                   d	             |S c c}w c c}w )Nr   imagesimage   image_)namesminu&   Optional reference image(s) — up to z. Sent as URLs.)templaterC   videosvideovideo_u&   Optional reference video(s) — up to )
r&   appendr   Autogrowr   TemplateNamesImageranger'   Video)rO   extrasis      r2   _media_inputsrc   p   sR   FKK22HHNN7+16q$//A:M1NO1NAVA3<1NO 3 
 A@QQ`a  
	
 KK22HHNN7+16q$//A:M1NO1NAVA3<1NO 3 
 A@QQ`a  
	
 M% P Ps   	E+<E0c                 D    t        | j                        t        |       z   S N)rN   r#   rc   rO   s    r2   _inputs_for_modelrg      s    4<<(=+>>>r1   c            	          t         D  cg c]5  } t        j                  j                  | j                  t        |             7 c} S c c} w re   )r7   r   DynamicComboOptionr"   rg   rf   s    r2   _build_model_optionsrk      s7    SYZSY4BOO""499.?.EFSYZZZs   :AresponseNc                     | j                   r5| j                   j                  t        | j                   j                        S y re   )usagecostr.   )rl   s    r2   _calculate_pricerp      s0    ~~(..--9X^^(())r1   c            
          g } t         D ]G  }|j                  dz  }|j                  dz  }| j                  d|j                   d|dd|dd       I dj                  |       }d| d	S )
Ni  z  "z": [z.8gz, ]z,
z(
  $rates := {
z
  };
  $r := $lookup($rates, widgets.model);
  $r ? {
    "type": "list_usd",
    "usd": $r,
    "format": { "approximate": true, "separator": "-", "suffix": " per 1K tokens" }
  } : {"type": "text", "text": "Token-based"}
))r7   r$   r%   r[   r"   join)rates_pairsrO   prompt_per_1kcompletion_per_1krates_blocks        r2   _price_badge_jsonatarx      s    K, NNT1S4c/B"EVWZD[[\]^  **[)K	- 
	r1   clsrQ   c                    K   t        | ||j                  ddd       d {   }|D cg c]  }t        t        |             c}S 7 (c c}w w)Ni  @ z	image/pngzUploading reference images)r&   total_pixels	mime_type
wait_labelurl)	image_url)r   r&   r   r   )ry   rO   rQ   urlsr   s        r2   _build_image_blocksr      s_      +?? / D VZZUYc"-?C-HIUYZZ [s    AA
AAAArX   c                    K   g }t        |      }t        |      D ]U  \  }}d}|dkD  r| d|dz    d| d}t        | ||       d {   }|j                  t	        t        |                   W |S 7 -w)	NzUploading reference videorS   z (/))r}   r~   )	video_url)len	enumerater   r[   r   r   )ry   rX   blockstotalidxrY   labelr   s           r2   _build_video_blocksr      s     +-FKE'
U+19gRay%2E,S%EJJ,7Ic7RST ( M Ks   AA7A5.A7promptmedia_blocksc                     |st        d|       S t        |      }|j                  t        |              t        d|      S )Nuserrolecontent)text)r   listr[   r   )r   r   r   s      r2   _user_messager      s;     ff==+/+=F
MM'V45&&99r1   system_promptc                 |    g }| r|j                  t        d|              |j                  t        ||             |S )Nsystemr   )r[   r   r   )r   r   r   messagess       r2   _build_messagesr      s8     )+H)xOPOOM&,78Or1   r"   seedr?   rI   c                    d }|r|dk7  rt        |d      }d }|rt        |      }t        | t        |||      |dkD  r|nd ||      S )Nr9   T)effortexclude)rI   r   )modelr   r   r   web_search_options)r   r   r	   r   )	r"   r   r   r   r   r?   rI   reasoning_cfgweb_search_cfgs	            r2   _build_requestr      sb     7;M,519ISWX8<N3H[\  EAXT4) r1   c                    | j                   rW| j                   j                  | j                   j                  nd}t        d| d| j                   j                  xs d       | j                  st        d      | j                  d   j                  }|st        d      |j
                  rt        d|j
                         |j                  xs d	S )
NunknownzOpenRouter error (z): z
no messagez,Empty response from OpenRouter (no choices).r   z,Empty response from OpenRouter (no message).zModel refused to respond:  )errorcoderM   messagechoicesrefusalr   )rl   r   r   s      r2   _extract_textr      s    ~~&.nn&9&9&Ex~~""9-dV3x~~7M7M7]Q]6^_``GHHq!))GGHH5goo5FGHH?? b r1   c                   Z    e Zd Zed        Ze	 d	dededededej                  f
d       Z
y)
OpenRouterLLMNodec                    t        j                  dddddt         j                  j                  dddd	
      t         j                  j                  dt               d      t         j                  j                  dddddd      t         j                  j                  dddddd      gt         j                  j                         gt         j                  j                  t         j                  j                  t         j                  j                  gdt        j                  t        j                  dg      t                     
      S )Nr   zOpenRouter LLMzpartner/text/OpenRouterzText GenerationzGenerate text responses through OpenRouter. Routes to a curated set of popular models from xAI, DeepSeek, Qwen, Mistral, Z.AI (GLM), Moonshot (Kimi), and Perplexity Sonar.r   Tr   zText input to the model.)	multilinerB   rC   r   z3The OpenRouter model used to generate the response.)rA   rC   r   r   izKSeed for sampling. Set to 0 to omit. Most models treat this as a hint only.)rB   rV   maxcontrol_after_generaterC   r   z<Foundational instructions that dictate the model's behavior.)r   rB   optionalrD   rC   )widgets)
depends_onexpr)
node_iddisplay_namecategoryessentials_categorydescriptioninputsoutputshiddenis_api_nodeprice_badge)r   SchemaStringr   ri   rk   IntOutputHiddenauth_token_comfy_orgapi_key_comfy_org	unique_id
PriceBadgePriceBadgeDependsrx   )ry   s    r2   define_schemazOpenRouterLLMNode.define_schema  s,   yy'). 1$
 		"6	    %%02Q & 
 "+/i   		#"!!Z   ): YY%%'(		..		++		##
 //	B)+]2
 2	
r1   r   r   r   r   r=   c           	        K   t        |dd       |d   }t        j                  |      }|t        d|       |j                  d      }|j                  d      }|j                  d      xs i j	                         D 	cg c]  }	|	|		 }
}	|
r;t        d	 |
D              |j                  kD  rt        d
|j                   d| d      |j                  d      xs i j	                         D cg c]  }||	 }}|r4t        |      |j                  kD  rt        d
|j                   d| d      g }|
r$|j                  t        | ||
       d {          |r#|j                  t        | |       d {          t        |||||||      }t        | t        t        d      t         |t"               d {   }t%        j&                  t)        |            S c c}	w c c}w 7 7 s7 0w)NTrS   )strip_whitespace
min_lengthr   zUnknown OpenRouter model: r?   rI   rQ   c              3   2   K   | ]  }t        |        y wre   )r   ).0ts     r2   	<genexpr>z,OpenRouterLLMNode.execute.<locals>.<genexpr>O  s      P-Q!5a!8-s   zUp to z images are supported for .rX   z videos are supported for )r   r?   rI   POST)pathmethod)response_modeldataprice_extractor)r   r8   getrM   valuessumr&   r   r'   extendr   r   r   r   r   OPENROUTER_CHAT_ENDPOINTr
   rp   r   
NodeOutputr   )ry   r   r   r   r   r"   rO   r?   rI   r   image_tensorsvvideo_inputsr   requestrl   s                   r2   executezOpenRouterLLMNode.execute=  s     	!D'N""4(<9$@AA',yy1C'D*/))4I*J8=		(8K8Qr7Y7Y7[+m7[!_`_lA7[+mS P- PPSWSbSbbvdoo%66PQUPVVWXYY7<yy7J7Pb6X6X6Z*l6Z^_^k16Z*lC-?vdoo%66PQUPVVWXYY57&9#t]&S ST&9#|&L LM - 3
 !5fE1,
 
 }}]8455= ,n +m !T L
s]   B G2G"
G"A$G22G':G'>AG2G,$G2:G.;AG2?G0 -G2.G20G2N)r   )r(   r)   r*   classmethodr   r+   dictr/   r   r   r   r0   r1   r2   r   r     sb    3
 3
j   .6.6 .6 	.6
 .6 
.6 .6r1   r   c                   B    e Zd Zedeeej                        fd       Zy)OpenRouterExtensionr=   c                    K   t         gS wre   )r   )selfs    r2   get_node_listz!OpenRouterExtension.get_node_listp  s     !""s   
N)	r(   r)   r*   r   r   typer   	ComfyNoder   r0   r1   r2   r   r   o  s)    #T$r||*<%= # #r1   r   c                     K   t               S wre   )r   r0   r1   r2   comfy_entrypointr   u  s       s   )C__doc__dataclassesr   typingr   typing_extensionsr   comfy_api.latestr   r   r   comfy_api_nodes.apis.openrouterr	   r
   r   r   r   r   r   r   r   r   r   comfy_api_nodes.utilr   r   r   r   r   r   r   r-   r!   r7   r   r,   r"   r8   r   r+   rF   rJ   rG   rK   rN   rc   rg   ri   rj   rk   r.   rp   rx   r   r   r^   r   r`   r   r   r   r/   r   r   r   r   r   )ms   0r2   <module>r      s   4 !  & 6 6     G  e
f $   *,@(Hacd#%97GXZ[!5xUWX(+y(WYfghj)PRSZrR);ZP+[+{S'k;O);
JO"KjUWdef#[,XZghi-z9i\]^-{Iy]^_~{J
C|[)Z@%{J
WYZ,k9iP%|XxH/1GS[\/1GS[\+Z 0 >D)DV!&&!)V)Dc:o& D5 1 	 		$ 		4W 	4 	4
 t :?J ?4 ?[d2??#9#9: [5 %$, c ,[	bll	[#-[7;EKK7H[	
 ![	4#5 	tEKK?P 	UYZpUq 	:# :T2H-I :N_ : #378N3O	

  -.	  Dj t 4!2 !s !g6 g6T#. #! 3 !]	 *Es    J