整合 JSON 提取和多配置支援到 OpenAIHelper 節點

- 創建 modeldata 資料夾存放多個 API 配置
- 添加配置範本選擇(OpenAI, DeepSeek, Gemini 等)
- 添加 prompts 輸出(STRING 列表)
- 自動從 LLM 輸出中提取 image_prompt
- 移動 openaimodel.json 到 modeldata/default.json
- 創建範例配置:openai.json, deepseek.json, gemini.json
This commit is contained in:
dseditor
2026-01-04 21:27:08 +08:00
parent 60ba2e5eaa
commit 4293b92408
5 changed files with 105 additions and 28 deletions
+5
View File
@@ -0,0 +1,5 @@
{
"endpoint": "https://api.deepseek.com/v1/chat/completions",
"api_key": "",
"model_name": "deepseek-chat"
}
+5
View File
@@ -0,0 +1,5 @@
{
"endpoint": "http://localhost:11434/v1/chat/completions",
"api_key": "ollama",
"model_name": "huihui_ai/qwen3-vl-abliterated:4b-instruct"
}
+5
View File
@@ -0,0 +1,5 @@
{
"endpoint": "https://generativelanguage.googleapis.com/v1beta/chat/completions",
"api_key": "",
"model_name": "gemini-2.0-flash-exp"
}
+5
View File
@@ -0,0 +1,5 @@
{
"endpoint": "https://api.openai.com/v1/chat/completions",
"api_key": "",
"model_name": "gpt-4o"
}
+85 -28
View File
@@ -16,21 +16,58 @@ try:
except ImportError:
print("⚠️ torchaudio 未安裝,音訊功能將無法使用")
# Import JSON prompt extractor for automatic prompt list extraction
from .json_prompt_extractor import extract_prompts_from_json
class OpenAIHelper:
"""
OpenAI Helper節點,用於呼叫OpenAI相容的API
支援圖片、音訊輸入,配置管理,模型列表獲取
支援圖片、音訊輸入,配置管理,模型列表獲取,多配置範本
"""
@classmethod
def _load_config(cls):
"""載入配置從openaimodel.json文件"""
config_file = os.path.join(os.path.dirname(__file__), "openaimodel.json")
def _get_config_files(cls):
"""獲取 modeldata 資料夾中的所有配置檔案"""
modeldata_dir = os.path.join(os.path.dirname(__file__), "modeldata")
# 確保資料夾存在
if not os.path.exists(modeldata_dir):
os.makedirs(modeldata_dir)
# 創建預設配置
default_config = {
"endpoint": "",
"api_key": "",
"model_name": ""
}
default_path = os.path.join(modeldata_dir, "default.json")
with open(default_path, 'w', encoding='utf-8') as f:
json.dump(default_config, f, ensure_ascii=False, indent=2)
# 獲取所有 .json 檔案
config_files = []
try:
with open(config_file, 'r', encoding='utf-8') as f:
for file in os.listdir(modeldata_dir):
if file.lower().endswith('.json'):
config_files.append(file)
except Exception as e:
print(f"⚠️ 讀取 modeldata 資料夾失敗: {e}")
if not config_files:
return ["default.json"]
return sorted(config_files)
@classmethod
def _load_config(cls, config_file="default.json"):
"""載入指定的配置檔案"""
modeldata_dir = os.path.join(os.path.dirname(__file__), "modeldata")
config_path = os.path.join(modeldata_dir, config_file)
try:
with open(config_path, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
print(f"⚠️ 載入openaimodel.json失敗: {e}")
print(f"⚠️ 載入配置檔案 {config_file} 失敗: {e}")
return {
"endpoint": "",
"api_key": "",
@@ -38,19 +75,21 @@ class OpenAIHelper:
}
@classmethod
def _save_config(cls, endpoint, api_key, model_name):
"""保存配置到openaimodel.json文件"""
config_file = os.path.join(os.path.dirname(__file__), "openaimodel.json")
def _save_config(cls, config_file, endpoint, api_key, model_name):
"""保存配置到指定的配置檔案"""
modeldata_dir = os.path.join(os.path.dirname(__file__), "modeldata")
config_path = os.path.join(modeldata_dir, config_file)
try:
config = {
"endpoint": endpoint,
"api_key": api_key,
"model_name": model_name
}
with open(config_file, 'w', encoding='utf-8') as f:
with open(config_path, 'w', encoding='utf-8') as f:
json.dump(config, f, ensure_ascii=False, indent=2)
except Exception as e:
print(f"❌ 保存openaimodel.json失敗: {e}")
print(f"❌ 保存配置檔案 {config_file} 失敗: {e}")
@classmethod
def _get_prompt_templates(cls):
@@ -90,8 +129,12 @@ class OpenAIHelper:
@classmethod
def INPUT_TYPES(cls):
# 載入保存的配置
config = cls._load_config()
# 獲取配置檔案列表
config_files = cls._get_config_files()
# 載入預設配置(第一個配置檔案)
default_config_file = config_files[0] if config_files else "default.json"
config = cls._load_config(default_config_file)
# 獲取範本列表
templates = cls._get_prompt_templates()
@@ -99,6 +142,10 @@ class OpenAIHelper:
return {
"required": {
"config_template": (config_files, {
"default": default_config_file,
"tooltip": "選擇 API 配置範本(從 modeldata 資料夾)"
}),
"endpoint": ("STRING", {
"multiline": False,
"default": config.get("endpoint", ""),
@@ -141,8 +188,9 @@ class OpenAIHelper:
}
}
RETURN_TYPES = ("STRING", "STRING")
RETURN_NAMES = ("text", "model_name_list")
RETURN_TYPES = ("STRING", "STRING", "STRING")
RETURN_NAMES = ("text", "model_name_list", "prompts")
OUTPUT_IS_LIST = (False, False, True) # prompts 是列表
FUNCTION = "process_openai"
CATEGORY = "ListHelper/LLM"
@@ -331,23 +379,23 @@ class OpenAIHelper:
print(f"❌ API呼叫異常: {e}")
return {"error": {"message": str(e)}}
def process_openai(self, endpoint, api_key, model_name, user_prompt, prompt_template, max_tokens,
def process_openai(self, config_template, endpoint, api_key, model_name, user_prompt, prompt_template, max_tokens,
system_prompt=None, image1=None, image2=None, image3=None,
audio=None, file_path=None):
"""處理OpenAI請求"""
# 驗證必填參數
if not endpoint or not endpoint.strip():
return ("❌ 錯誤: 請提供API端點", "")
return ("❌ 錯誤: 請提供API端點", "", [])
if not api_key or not api_key.strip():
return ("❌ 錯誤: 請提供API金鑰", "")
return ("❌ 錯誤: 請提供API金鑰", "", [])
if not model_name or not model_name.strip():
return ("❌ 錯誤: 請提供模型名稱", "")
return ("❌ 錯誤: 請提供模型名稱", "", [])
# 保存配置
self._save_config(endpoint.strip(), api_key.strip(), model_name.strip())
# 保存配置到選擇的配置範本
self._save_config(config_template, endpoint.strip(), api_key.strip(), model_name.strip())
# 獲取模型列表
model_list = self._get_model_list(endpoint.strip(), api_key.strip())
@@ -401,7 +449,7 @@ class OpenAIHelper:
audio_b64 = None
if audio is not None:
if not TORCHAUDIO_AVAILABLE:
return ("❌ 錯誤: torchaudio未安裝,無法處理音訊", model_list)
return ("❌ 錯誤: torchaudio未安裝,無法處理音訊", model_list, [])
print(f"處理音訊輸入")
try:
@@ -417,10 +465,10 @@ class OpenAIHelper:
})
print(f"✓ 音訊處理成功")
else:
return ("❌ 錯誤: 音訊處理失敗", model_list)
return ("❌ 錯誤: 音訊處理失敗", model_list, [])
except Exception as e:
print(f"❌ 處理音訊時出錯: {str(e)}")
return (f"❌ 錯誤: 處理音訊時出錯: {str(e)}", model_list)
return (f"❌ 錯誤: 處理音訊時出錯: {str(e)}", model_list, [])
# 添加用戶消息
if len(user_content) > 1:
@@ -454,7 +502,7 @@ class OpenAIHelper:
# 處理響應
if not response:
return ("❌ API呼叫失敗", model_list)
return ("❌ API呼叫失敗", model_list, [])
# 檢查錯誤
if 'error' in response:
@@ -463,13 +511,22 @@ class OpenAIHelper:
error_msg = f"❌ API錯誤: {error_info.get('message', str(error_info))}"
else:
error_msg = f"❌ API錯誤: {str(error_info)}"
return (error_msg, model_list)
return (error_msg, model_list, [])
if 'choices' not in response or not response['choices']:
return ("❌ API回應格式異常", model_list)
return ("❌ API回應格式異常", model_list, [])
# 獲取回應訊息
message = response['choices'][0]['message']
response_content = message.get('content', '')
return (response_content, model_list)
# 自動提取提示詞列表(如果輸出包含 JSON 格式的雜誌數據)
try:
prompts = extract_prompts_from_json(response_content)
if prompts:
print(f"✅ 自動提取到 {len(prompts)} 個圖片提示詞")
except Exception as e:
print(f"ℹ️ 提示詞提取失敗(這是正常的,如果輸出不是雜誌 JSON): {e}")
prompts = []
return (response_content, model_list, prompts)