Files

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"
}