
    +jt7                        % S r SSKJr  SSKJr  SSKJr  SSKJrJ	r	J
r
  SSKJrJrJrJrJrJrJrJrJrJrJr  SSKJrJrJrJrJrJr  Sr\S	   r\" S
S9 " S S5      5       r \ " SSSSSS9\ " SSSSSS9\ " SSSSSS9\ " SSSSSSS9\ " SSSS SS9\ " S!SSS SS9\ " S"SS#S$5      \ " S%SS&S'5      \ " S(SS)S*5      \ " S+SS,S-5      \ " S.SS/S0S1SS9\ " S2SS3S4S1SS9\ " S5S6S7SS8S9\ " S9SSS:S8S9\ " S;SS<S=5      \ " S>SS?S@5      \ " SASSBSCS1S9\ " SDSS?S 5      \ " SESFSGSH5      \ " SISJSKSL5      \ " SMSJSKSL5      /r!\"\    \#SN'   \! V s0 s H  o RH                  U _M     sn r%\&\'\ 4   \#SO'   / SPQr(/ SQQr)SR\"4SS jr*SR\"4ST jr+SU\SR\"4SV jr,SW\ SR\"4SX jr-SW\ SR\"4SY jr.SR\"\R^                  R`                     4SZ jr1S[\SR\2S\-  4S] jr3SR\'4S^ jr4S_\5\Rl                     SW\ S`\"\
Rn                     SR\"\   4Sa jr8S_\5\Rl                     Sb\"\
Rr                     SR\"\   4Sc jr:Sd\'Se\"\   SR\4Sf jr;Sg\'Sd\'Se\"\   SR\"\   4Sh jr<Si\'Sg\'Sd\'Se\"\   Sj\=Sk\'S\-  Sl\'S\-  SR\4Sm jr>S[\SR\'4Sn jr? " So Sp\Rl                  5      r@ " Sq Sr\	5      rASR\A4Ss jrBg\s  sn f )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                   Z    \ rS rSr% \\S'   \\S'   \\S'   \\S'   Sr\	\S'   Sr
\	\S'   S	rg
)
_ModelSpec%   slugprofileprice_in	price_outr   
max_images
max_videos N)__name__
__module____qualname____firstlineno__str__annotations__Profilefloatr'   intr(   __static_attributes__r)       @/home/wildlama/comfy/ComfyUI/comfy_api_nodes/nodes_openrouter.pyr!   r!   %   s,    
IOJJr4   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                  N    [         R                  R                  S[        SSSS9/$ )Nreasoning_effortr<   z4Reasoning effort. 'off' disables reasoning entirely.Toptionsdefaulttooltipadvanced)r   Combor   _REASONING_EFFORTSr)   r4   r5   _reasoning_extra_inputsrJ   L   s0    
&J 	 	
 r4   c                  N    [         R                  R                  S[        SSSS9/$ )Nsearch_context_sizer>   zSHow much web search context to retrieve. Larger = more grounded but slower/pricier.TrC   )r   rH   r   _SEARCH_CONTEXT_SIZESr)   r4   r5   _perplexity_extra_inputsrN   X   s0    
!)i 	 	
 r4   r$   c                     U S:X  a  / $ U S;   a
  [        5       $ U S:X  a
  [        5       $ U S:X  a  [        5       [        5       -   $ [        SU  35      e)Nr   )r   r   r   r   zUnknown profile: )rJ   rN   
ValueError)r$   s    r5   _profile_inputsrQ   d   s`    *	55&((,'))(('),C,EEE
(	2
33r4   specc                    / nU R                   S:  a  UR                  [        R                  R	                  S[        R                  R                  [        R                  R	                  S5      [        SU R                   S-   5       Vs/ s H  nSU 3PM
     snSS9SU R                    S3S	95        U R                  S:  a  UR                  [        R                  R	                  S
[        R                  R                  [        R                  R	                  S5      [        SU R                  S-   5       Vs/ s H  nSU 3PM
     snSS9SU R                   S3S	95        U$ s  snf s  snf )Nr   imagesimage   image_)namesminu&   Optional reference image(s) — up to z. Sent as URLs.)templaterF   videosvideovideo_u&   Optional reference video(s) — up to )
r'   appendr   Autogrowr   TemplateNamesImageranger(   Video)rR   extrasis      r5   _media_inputsrf   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';E,c                 D    [        U R                  5      [        U 5      -   $ N)rQ   r$   rf   rR   s    r5   _inputs_for_modelrj      s    4<<(=+>>>r4   c            	          [          V s/ s H6  n [        R                  R                  U R                  [        U 5      5      PM8     sn $ s  sn f rh   )r:   r   DynamicComboOptionr#   rj   ri   s    r5   _build_model_optionsrn      s7    SYZSY4BOO""499.?.EFSYZZZs   =A	responseNc                     U R                   (       a6  U R                   R                  b  [        U R                   R                  5      $ g rh   )usagecostr1   )ro   s    r5   _calculate_pricers      s0    ~~(..--9X^^(())r4   c            
          / n [          HH  nUR                  S-  nUR                  S-  nU R                  SUR                   SUS SUS S35        MJ     SR                  U 5      nSU S	3$ )
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"}
))r:   r%   r&   r^   r#   join)rates_pairsrR   prompt_per_1kcompletion_per_1krates_blocks        r5   _price_badge_jsonatar{      s    K, NNT1S4c/B"EVWZD[[\]^  **[)K	- 
	r4   clsrT   c           	         #    [        U UUR                  SSSS9I S h  vN nU Vs/ s H  n[        [        US9S9PM     sn$  N%s  snf 7f)Ni  @ z	image/pngzUploading reference images)r'   total_pixels	mime_type
wait_labelurl)	image_url)r   r'   r   r   )r|   rR   rT   urlsr   s        r5   _build_image_blocksr      s^      +?? / D VZZUYc"-?C-HIUYZZ [s    AAAAAAr[   c           	         #    / n[        U5      n[        U5       HL  u  pESnUS:  a  U SUS-    SU S3n[        XUS9I S h  vN nUR                  [	        [        US9S95        MN     U$  N)7f)	NzUploading reference videorV   z (/))r   r   )	video_url)len	enumerater   r^   r   r   )r|   r[   blockstotalidxr\   labelr   s           r5   _build_video_blocksr      s     +-FKE'
+19gRay%2E,SEJJ,7Ic7RST ( M Ks   AA/A-*A/promptmedia_blocksc                 ~    U(       d
  [        SU S9$ [        U5      nUR                  [        U S95        [        SUS9$ )Nuserrolecontent)text)r   listr^   r   )r   r   r   s      r5   _user_messager      s;     ff==+/+=F
MM'V45&&99r4   system_promptc                 ~    / nU (       a  UR                  [        SU S95        UR                  [        X5      5        U$ )Nsystemr   )r^   r   r   )r   r   r   messagess       r5   _build_messagesr      s6     )+H)xOPOOM&78Or4   r#   seedrB   rL   c                    S nU(       a  US:w  a
  [        USS9nS nU(       a	  [        US9n[        U [        XU5      US:  a  UOS UUS9$ )Nr<   T)effortexclude)rL   r   )modelr   r   r   web_search_options)r   r   r	   r   )	r#   r   r   r   r   rB   rL   reasoning_cfgweb_search_cfgs	            r5   _build_requestr      s`     7;M,519ISWX8<N3H[\  EAXT4) r4   c                    U R                   (       a]  U R                   R                  b  U R                   R                  OSn[        SU SU R                   R                  =(       d    S 35      eU R                  (       d  [        S5      eU R                  S   R                  nU(       d  [        S5      eUR
                  (       a  [        SUR
                   35      eUR                  =(       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coderP   messagechoicesrefusalr   )ro   r   r   s      r5   _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 r4   c                   f    \ rS rSr\S 5       r\ SS\S\S\S\S\	R                  4
S jj5       rS	rg
)OpenRouterLLMNodei  c                 v   [         R                  " SSSSS[         R                  R                  SSSS	S
9[         R                  R                  S[        5       SS9[         R                  R                  SSSSSSS9[         R                  R                  SSSSSSS9/[         R                  R                  5       /[         R                  R                  [         R                  R                  [         R                  R                  /S[         R                  " [         R                  " S/S9[        5       S9S9
$ )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.)	multilinerE   rF   r   z3The OpenRouter model used to generate the response.)rD   rF   r   r   izKSeed for sampling. Set to 0 to omit. Most models treat this as a hint only.)rE   rY   maxcontrol_after_generaterF   r   z<Foundational instructions that dictate the model's behavior.)r   rE   optionalrG   rF   )widgets)
depends_onexpr)
node_iddisplay_namecategoryessentials_categorydescriptioninputsoutputshiddenis_api_nodeprice_badge)r   SchemaStringr   rl   rn   IntOutputHiddenauth_token_comfy_orgapi_key_comfy_org	unique_id
PriceBadgePriceBadgeDependsr{   )r|   s    r5   define_schemaOpenRouterLLMNode.define_schema  s,   yy'). 1$
 		"6	    %%02Q & 
 "+/i   		#"!!Z   ): YY%%'(		..		++		##
 //	B)+]2
 2	
r4   r   r   r   r   r@   c           
         #    [        USSS9  US   n[        R                  U5      nUc  [        SU 35      eUR                  S5      nUR                  S5      nUR                  S5      =(       d    0 R	                  5        V	s/ s H	  oc  M  U	PM     n
n	U
(       a<  [        S	 U
 5       5      UR                  :  a  [        S
UR                   SU S35      eUR                  S5      =(       d    0 R	                  5        Vs/ s H	  oc  M  UPM     nnU(       a5  [        U5      UR                  :  a  [        S
UR                   SU S35      e/ nU
(       a#  UR                  [        XU
5      I S h  vN 5        U(       a"  UR                  [        X5      I S h  vN 5        [        UUUUUUUS9n[        U [        [        SS9[         U["        S9I S h  vN n[$        R&                  " [)        U5      5      $ s  sn	f s  snf  N Nk N17f)NTrV   )strip_whitespace
min_lengthr   zUnknown OpenRouter model: rB   rL   rT   c              3   8   #    U  H  n[        U5      v   M     g 7frh   )r   ).0ts     r5   	<genexpr>,OpenRouterLLMNode.execute.<locals>.<genexpr>O  s      P-Q!5a!8!8-s   zUp to z images are supported for .r[   z videos are supported for )r   rB   rL   POST)pathmethod)response_modeldataprice_extractor)r   r;   getrP   valuessumr'   r   r(   extendr   r   r   r   r   OPENROUTER_CHAT_ENDPOINTr
   rs   r   
NodeOutputr   )r|   r   r   r   r   r#   rR   rB   rL   r   image_tensorsvvideo_inputsr   requestro   s                   r5   executeOpenRouterLLMNode.execute=  s     	!D'N""4(<9$@AA',yy1C'D*/))4I*J8=		(8K8Qr7Y7Y7[+m7[!A7[+mS P- PPSWSbSbbvdoo%66PQUPVVWXYY7<yy7J7Pb6X6X6Z*l6Z16Z*lC-?vdoo%66PQUPVVWXYY57&9#]&S ST&9#&L LM - 3
 !5fE1,
 
 }}]8455= ,n +m !T L
s\   BHG>G>A/HHHA!H5H6(HH
;HH.H
HHr)   N)r   )r*   r+   r,   r-   classmethodr   r.   dictr2   r   r   r   r3   r)   r4   r5   r   r     sb    3
 3
j   .6.6 .6 	.6
 .6 
.6 .6r4   r   c                   L    \ rS rSr\S\\\R                        4S j5       r	Sr
g)OpenRouterExtensionio  r@   c                    #    [         /$ 7frh   )r   )selfs    r5   get_node_list!OpenRouterExtension.get_node_listp  s     !""s   
r)   N)r*   r+   r,   r-   r   r   typer   	ComfyNoder   r3   r)   r4   r5   r   r   o  s)    #T$r||*<%= # #r4   r   c                     #    [        5       $ 7frh   )r   r)   r4   r5   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   r0   r!   r:   r   r/   r#   r;   r   r.   rI   rM   rJ   rN   rQ   rf   rj   rl   rm   rn   r1   rs   r{   r   r   ra   r   rc   r   r   r   r2   r   r   r   r   r   )ms   0r5   <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