347 lines
12 KiB
Python
347 lines
12 KiB
Python
"""
|
|
LiveSearch API Loader Node
|
|
Handles LLM API configuration separately from the main search logic
|
|
"""
|
|
|
|
import os
|
|
from .config_manager import ConfigManager
|
|
|
|
config_manager = ConfigManager()
|
|
|
|
# Expanded model configurations
|
|
# 每个 provider 包含 base_url、t2t_models(文本模型)、ti2t_models(视觉模型)
|
|
MODEL_CONFIGS = {
|
|
"OpenAI": {
|
|
"base_url": "https://api.openai.com/v1",
|
|
"t2t_models": [
|
|
"gpt-5.1",
|
|
"gpt-5",
|
|
"gpt-5-mini",
|
|
"gpt-5-nano",
|
|
"gpt-5-pro",
|
|
"gpt-4.1",
|
|
"gpt-4.1-mini",
|
|
"gpt-4.1-nano",
|
|
"gpt-4o",
|
|
"gpt-4o-mini",
|
|
"gpt-4-turbo",
|
|
"gpt-4",
|
|
"gpt-3.5-turbo",
|
|
"o3",
|
|
"o3-pro",
|
|
"o3-mini",
|
|
"o3-deep-research",
|
|
"o4-mini-deep-research",
|
|
"o1",
|
|
"o1-pro"
|
|
],
|
|
"ti2t_models": [
|
|
# OpenAI 视觉模型(使用 OpenAI 兼容格式,与 SiliconFlow 相同)
|
|
"gpt-5.1",
|
|
"gpt-5.1-mini",
|
|
"gpt-5",
|
|
"gpt-5-mini",
|
|
"gpt-5-pro",
|
|
"gpt-4o",
|
|
"gpt-4o-mini",
|
|
"gpt-4-turbo"
|
|
]
|
|
},
|
|
"DeepSeek (Official)": {
|
|
"base_url": "https://api.deepseek.com",
|
|
"t2t_models": [
|
|
"deepseek-chat",
|
|
"deepseek-reasoner",
|
|
"deepseek-v3"
|
|
],
|
|
"ti2t_models": []
|
|
},
|
|
"DeepSeek (Aliyun)": {
|
|
"base_url": "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
|
"t2t_models": [
|
|
"deepseek-v3",
|
|
"deepseek-v2.5",
|
|
"deepseek-chat"
|
|
],
|
|
"ti2t_models": []
|
|
},
|
|
"Gemini (OpenAI-Format)": {
|
|
"base_url": "https://generativelanguage.googleapis.com/v1beta/openai",
|
|
"t2t_models": [
|
|
"gemini-3-pro",
|
|
"gemini-2.5-pro",
|
|
"gemini-2.5-flash",
|
|
"gemini-2.5-flash-lite",
|
|
"gemini-2.0-flash",
|
|
"gemini-2.0-flash-lite",
|
|
"gemini-1.5-pro",
|
|
"gemini-1.5-flash",
|
|
"gemini-1.5-flash-8b"
|
|
],
|
|
"ti2t_models": []
|
|
},
|
|
"Anthropic (Claude)": {
|
|
"base_url": "https://api.anthropic.com/v1",
|
|
"t2t_models": [
|
|
"claude-sonnet-4-5-20250929",
|
|
"claude-sonnet-4-5",
|
|
"claude-haiku-4-5-20251001",
|
|
"claude-haiku-4-5",
|
|
"claude-opus-4-1-20250805",
|
|
"claude-opus-4-1"
|
|
],
|
|
"ti2t_models": []
|
|
},
|
|
"Grok": {
|
|
"base_url": "https://api.x.ai/v1",
|
|
"t2t_models": [
|
|
"grok-2-1212",
|
|
"grok-2-vision-1212",
|
|
"grok-2",
|
|
"grok-beta"
|
|
],
|
|
"ti2t_models": []
|
|
},
|
|
"Volcengine (Doubao)": {
|
|
"base_url": "https://ark.cn-beijing.volces.com/api/v3",
|
|
"t2t_models": [
|
|
# 豆包主力模型 (Model ID)
|
|
"doubao-seed-1-6-251015", # doubao-seed-1.6 (最新)
|
|
"doubao-seed-1-6-250615", # doubao-seed-1.6 (稳定)
|
|
"doubao-seed-1-6-lite-251015", # doubao-seed-1.6-lite
|
|
"doubao-seed-1-6-flash-250828",# doubao-seed-1.6-flash
|
|
"doubao-seed-1-6-thinking-250715", # doubao-seed-1.6-thinking
|
|
"doubao-seed-code-preview-251028", # doubao-seed-code
|
|
"doubao-seed-1-6-vision-250815", # doubao-seed-1.6-vision
|
|
# DeepSeek (火山引擎托管)
|
|
"deepseek-v3-1-terminus",
|
|
"deepseek-v3-1-250821",
|
|
# 第三方兼容 (如需自定义)
|
|
"custom-endpoint-id"
|
|
],
|
|
"ti2t_models": []
|
|
},
|
|
"Qwen (Aliyun)": {
|
|
"base_url": "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
|
"t2t_models": [
|
|
"qwen3-max",
|
|
"qwen3-max-preview",
|
|
"qwen-plus",
|
|
"qwen-plus-latest",
|
|
"qwen-flash",
|
|
"qwen-max",
|
|
"qwen-turbo"
|
|
],
|
|
"ti2t_models": []
|
|
},
|
|
"SiliconFlow (硅基流动)": {
|
|
"base_url": "https://api.siliconflow.cn/v1",
|
|
"t2t_models": [
|
|
# DeepSeek 系列
|
|
"deepseek-ai/DeepSeek-V3.2-Exp",
|
|
"Pro/deepseek-ai/DeepSeek-V3.2-Exp",
|
|
"Pro/deepseek-ai/DeepSeek-V3.1-Terminus",
|
|
"deepseek-ai/DeepSeek-V3.1-Terminus",
|
|
"Pro/deepseek-ai/DeepSeek-R1",
|
|
"Pro/deepseek-ai/DeepSeek-V3",
|
|
"deepseek-ai/DeepSeek-R1",
|
|
"deepseek-ai/DeepSeek-V3",
|
|
"deepseek-ai/DeepSeek-R1-0528-Qwen3-8B",
|
|
"deepseek-ai/DeepSeek-R1-Distill-Qwen-32B",
|
|
"deepseek-ai/DeepSeek-R1-Distill-Qwen-14B",
|
|
"deepseek-ai/DeepSeek-R1-Distill-Qwen-7B",
|
|
"Pro/deepseek-ai/DeepSeek-R1-Distill-Qwen-7B",
|
|
"deepseek-ai/DeepSeek-V2.5",
|
|
# Qwen 系列
|
|
"Qwen/Qwen3-Next-80B-A3B-Instruct",
|
|
"Qwen/Qwen3-Next-80B-A3B-Thinking",
|
|
"Qwen/Qwen3-Coder-30B-A3B-Instruct",
|
|
"Qwen/Qwen3-Coder-480B-A35B-Instruct",
|
|
"Qwen/Qwen3-30B-A3B-Thinking-2507",
|
|
"Qwen/Qwen3-30B-A3B-Instruct-2507",
|
|
"Qwen/Qwen3-235B-A22B-Thinking-2507",
|
|
"Qwen/Qwen3-235B-A22B-Instruct-2507",
|
|
"Qwen/Qwen3-30B-A3B",
|
|
"Qwen/Qwen3-32B",
|
|
"Qwen/Qwen3-14B",
|
|
"Qwen/Qwen3-8B",
|
|
"Qwen/Qwen3-235B-A22B",
|
|
"Qwen/Qwen2.5-72B-Instruct-128K",
|
|
"Qwen/Qwen2.5-72B-Instruct",
|
|
"Qwen/Qwen2.5-32B-Instruct",
|
|
"Qwen/Qwen2.5-14B-Instruct",
|
|
"Qwen/Qwen2.5-7B-Instruct",
|
|
"Qwen/Qwen2.5-Coder-32B-Instruct",
|
|
"Qwen/Qwen2.5-Coder-7B-Instruct",
|
|
"Qwen/Qwen2-7B-Instruct",
|
|
"Qwen/QwQ-32B",
|
|
"Pro/Qwen/Qwen2.5-7B-Instruct",
|
|
"Pro/Qwen/Qwen2-7B-Instruct",
|
|
# GLM 系列(智谱)
|
|
"zai-org/GLM-4.6",
|
|
"zai-org/GLM-4.5-Air",
|
|
"zai-org/GLM-4.5",
|
|
"THUDM/GLM-Z1-32B-0414",
|
|
"THUDM/GLM-4-32B-0414",
|
|
"THUDM/GLM-Z1-Rumination-32B-0414",
|
|
"THUDM/GLM-4-9B-0414",
|
|
"THUDM/glm-4-9b-chat",
|
|
"Pro/THUDM/glm-4-9b-chat",
|
|
# 其他模型
|
|
"inclusionAI/Ling-1T",
|
|
"inclusionAI/Ring-flash-2.0",
|
|
"inclusionAI/Ling-flash-2.0",
|
|
"inclusionAI/Ling-mini-2.0",
|
|
"moonshotai/Kimi-K2-Instruct-0905",
|
|
"ByteDance-Seed/Seed-OSS-36B-Instruct",
|
|
"stepfun-ai/step3",
|
|
"baidu/ERNIE-4.5-300B-A47B",
|
|
"ascend-tribe/pangu-pro-moe",
|
|
"tencent/Hunyuan-A13B-Instruct",
|
|
"MiniMaxAI/MiniMax-M1-80k",
|
|
"Tongyi-Zhiwen/QwenLong-L1-32B",
|
|
"internlm/internlm2_5-7b-chat"
|
|
],
|
|
"ti2t_models": [
|
|
# DeepSeek VLM 系列
|
|
"deepseek-ai/DeepSeek-OCR",
|
|
"deepseek-ai/deepseek-vl2",
|
|
# Qwen3 VL 系列
|
|
"Qwen/Qwen3-VL-32B-Instruct",
|
|
"Qwen/Qwen3-VL-32B-Thinking",
|
|
"Qwen/Qwen3-VL-8B-Instruct",
|
|
"Qwen/Qwen3-VL-8B-Thinking",
|
|
"Qwen/Qwen3-VL-30B-A3B-Instruct",
|
|
"Qwen/Qwen3-VL-30B-A3B-Thinking",
|
|
"Qwen/Qwen3-VL-235B-A22B-Instruct",
|
|
"Qwen/Qwen3-VL-235B-A22B-Thinking",
|
|
# Qwen2.5 VL 系列
|
|
"Qwen/Qwen2.5-VL-32B-Instruct",
|
|
"Qwen/Qwen2.5-VL-72B-Instruct",
|
|
"Pro/Qwen/Qwen2.5-VL-7B-Instruct",
|
|
# Qwen2 VL 系列
|
|
"Qwen/Qwen2-VL-72B-Instruct",
|
|
# Qwen3 Omni 系列
|
|
"Qwen/Qwen3-Omni-30B-A3B-Instruct",
|
|
"Qwen/Qwen3-Omni-30B-A3B-Thinking",
|
|
"Qwen/Qwen3-Omni-30B-A3B-Captioner",
|
|
# QVQ 系列
|
|
"Qwen/QVQ-72B-Preview",
|
|
# GLM V 系列(视觉)
|
|
"zai-org/GLM-4.5V",
|
|
"Pro/THUDM/GLM-4.1V-9B-Thinking",
|
|
"THUDM/GLM-4.1V-9B-Thinking"
|
|
]
|
|
},
|
|
"Ollama (Local)": {
|
|
"base_url": "http://127.0.0.1:11434/v1",
|
|
"t2t_models": [
|
|
"llama4",
|
|
"llama3.3",
|
|
"llama3.2",
|
|
"qwen3",
|
|
"qwen2.5",
|
|
"deepseek-r1",
|
|
"deepseek-v3",
|
|
"phi4"
|
|
],
|
|
"ti2t_models": [
|
|
"llama3.2-vision",
|
|
"llava"
|
|
]
|
|
},
|
|
"Custom": {
|
|
"base_url": "",
|
|
"t2t_models": ["custom-model"],
|
|
"ti2t_models": ["custom-vlm-model"]
|
|
}
|
|
}
|
|
|
|
class LiveSearch_API_Loader:
|
|
"""
|
|
API Configuration Loader Node
|
|
Separated from main search logic for better organization
|
|
"""
|
|
|
|
def __init__(self):
|
|
pass
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(s):
|
|
# Get all providers
|
|
providers = list(MODEL_CONFIGS.keys())
|
|
|
|
# Get all unique models for T2T
|
|
all_t2t_models = []
|
|
for config in MODEL_CONFIGS.values():
|
|
all_t2t_models.extend(config.get("t2t_models", []))
|
|
unique_t2t_models = list(dict.fromkeys(all_t2t_models))
|
|
# Add placeholder for validation when list is empty in frontend
|
|
unique_t2t_models.append("No T2T models available")
|
|
|
|
# Get all unique models for TI2T
|
|
all_ti2t_models = []
|
|
for config in MODEL_CONFIGS.values():
|
|
all_ti2t_models.extend(config.get("ti2t_models", []))
|
|
unique_ti2t_models = list(dict.fromkeys(all_ti2t_models))
|
|
# Add placeholder for validation when list is empty in frontend
|
|
unique_ti2t_models.append("No VLM models available")
|
|
|
|
return {
|
|
"required": {
|
|
"provider": (providers, {"default": "DeepSeek (Official)"}),
|
|
"t2t_model": (unique_t2t_models, {"default": "deepseek-chat"}),
|
|
"ti2t_model": (unique_ti2t_models, {"default": "Qwen/Qwen2.5-VL-72B-Instruct"}),
|
|
},
|
|
"optional": {
|
|
"api_key": ("STRING", {"default": "", "placeholder": "Leave empty to use .env or config file"}),
|
|
"base_url": ("STRING", {"default": "", "placeholder": "Leave empty to use default"}),
|
|
"temperature": ("FLOAT", {"default": 0.7, "min": 0.0, "max": 2.0, "step": 0.1}),
|
|
"max_tokens": ("INT", {"default": 2048, "min": 1, "max": 128000, "step": 1}),
|
|
"timeout": ("INT", {"default": 120, "min": 10, "max": 600, "step": 10}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = ("MODEL_CONFIG",)
|
|
RETURN_NAMES = ("model_config",)
|
|
FUNCTION = "load_api"
|
|
CATEGORY = "LiveSearch"
|
|
|
|
def load_api(self, provider, t2t_model, ti2t_model, api_key="", base_url="", temperature=0.7, max_tokens=2048, timeout=120):
|
|
"""
|
|
Load and validate API configuration
|
|
Returns a config dict that can be passed to other nodes
|
|
"""
|
|
# Resolve API key with priority: input > env > config file
|
|
resolved_api_key = api_key.strip() if api_key else ""
|
|
if not resolved_api_key:
|
|
resolved_api_key = config_manager.get_api_key(provider, "")
|
|
|
|
# Resolve base URL
|
|
resolved_base_url = base_url.strip() if base_url else MODEL_CONFIGS.get(provider, {}).get("base_url", "")
|
|
|
|
# Build configuration dict (包含两个模型,由 Agent 根据 mode 选择)
|
|
model_config = {
|
|
"provider": provider,
|
|
"t2t_model": t2t_model,
|
|
"ti2t_model": ti2t_model,
|
|
"api_key": resolved_api_key,
|
|
"base_url": resolved_base_url,
|
|
"temperature": temperature,
|
|
"max_tokens": max_tokens,
|
|
"timeout": timeout
|
|
}
|
|
|
|
print(f"[LiveSearch API Loader] Configured: {provider} / T2T: {t2t_model} / TI2T: {ti2t_model}")
|
|
|
|
return (model_config,)
|
|
|
|
NODE_CLASS_MAPPINGS = {
|
|
"LiveSearch_API_Loader": LiveSearch_API_Loader
|
|
}
|
|
|
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
|
"LiveSearch_API_Loader": "🔑 Live Search API Loader"
|
|
}
|
|
|