feat: 1.模型现在可以同时保存多个配置项

2.可在不同步骤使用不同的配置进行处理
This commit is contained in:
acomic
2025-08-25 18:12:49 +08:00
parent d9881322bd
commit f81e416e86
5 changed files with 1165 additions and 169 deletions
+2 -1
View File
@@ -33,5 +33,6 @@ tooltips = {
"characters_involved": "本章需要重点描写或影响剧情的角色名单。", "characters_involved": "本章需要重点描写或影响剧情的角色名单。",
"key_items": "在本章中出现的重要道具、线索或物品。", "key_items": "在本章中出现的重要道具、线索或物品。",
"scene_location": "本章主要发生的地点或场景描述。", "scene_location": "本章主要发生的地点或场景描述。",
"time_constraint": "本章剧情中涉及的时间压力或时限设置。" "time_constraint": "本章剧情中涉及的时间压力或时限设置。",
"interface_config": "选择你要使用的AI接口配置。"
} }
+409
View File
@@ -0,0 +1,409 @@
# ui/config_tab.py
# -*- coding: utf-8 -*-
from tkinter import messagebox
import customtkinter as ctk
from config_manager import load_config, save_config
from tooltips import tooltips
def create_label_with_help(self, parent, label_text, tooltip_key, row, column,
font=None, sticky="e", padx=5, pady=5):
"""
封装一个带"?"按钮的Label,用于展示提示信息。
"""
frame = ctk.CTkFrame(parent)
frame.grid(row=row, column=column, padx=padx, pady=pady, sticky=sticky)
frame.columnconfigure(0, weight=0)
label = ctk.CTkLabel(frame, text=label_text, font=font)
label.pack(side="left")
btn = ctk.CTkButton(
frame,
text="?",
width=22,
height=22,
font=("Microsoft YaHei", 10),
command=lambda: messagebox.showinfo("参数说明", tooltips.get(tooltip_key, "暂无说明"))
)
btn.pack(side="left", padx=3)
return frame
def build_config_tabview(self):
"""
创建包含 LLM Model settings 和 Embedding settings 的选项卡。
"""
self.config_tabview = ctk.CTkTabview(self.config_frame)
self.config_tabview.grid(row=0, column=0, sticky="we", padx=5, pady=5)
self.ai_config_tab = self.config_tabview.add("LLM Model settings")
self.embeddings_config_tab = self.config_tabview.add("Embedding settings")
self.config_choose = self.config_tabview.add("Config choose")
build_ai_config_tab(self)
build_embeddings_config_tab(self)
build_config_choose_tab(self)
# 底部的"保存配置"和"加载配置"按钮
self.btn_frame_config = ctk.CTkFrame(self.config_frame)
self.btn_frame_config.grid(row=1, column=0, padx=5, pady=5, sticky="ew")
self.btn_frame_config.columnconfigure(0, weight=1)
self.btn_frame_config.columnconfigure(1, weight=1)
save_config_btn = ctk.CTkButton(self.btn_frame_config, text="保存当前选择接口配置到文件", command=self.save_config_btn, font=("Microsoft YaHei", 12))
save_config_btn.grid(row=0, column=0, padx=5, pady=5, sticky="ew")
load_config_btn = ctk.CTkButton(self.btn_frame_config, text="加载当前选择接口配置到程序", command=self.load_config_btn, font=("Microsoft YaHei", 12))
load_config_btn.grid(row=0, column=1, padx=5, pady=5, sticky="ew")
def build_ai_config_tab(self):
def on_interface_format_changed(new_value):
self.interface_format_var.set(self.loaded_config["llm_configs"][new_value].get("interface_format", "OpenAI"))
config_data = load_config(self.config_file)
if config_data:
config_data["last_interface_format"] = new_value
save_config(config_data, self.config_file)
if self.loaded_config and "llm_configs" in self.loaded_config and new_value in self.loaded_config["llm_configs"]:
llm_conf = self.loaded_config["llm_configs"][new_value]
self.api_key_var.set(llm_conf.get("api_key", ""))
self.base_url_var.set(llm_conf.get("base_url", self.base_url_var.get()))
self.model_name_var.set(llm_conf.get("model_name", ""))
self.temperature_var.set(llm_conf.get("temperature", 0.7))
self.max_tokens_var.set(llm_conf.get("max_tokens", 8192))
self.timeout_var.set(llm_conf.get("timeout", 600))
else:
if new_value == "Ollama":
self.base_url_var.set("http://localhost:11434/v1")
elif new_value == "ML Studio":
self.base_url_var.set("http://localhost:1234/v1")
elif new_value == "OpenAI":
self.base_url_var.set("https://api.openai.com/v1")
self.model_name_var.set("gpt-4o-mini")
elif new_value == "Azure OpenAI":
self.base_url_var.set("https://[az].openai.azure.com/openai/deployments/[model]/chat/completions?api-version=2024-08-01-preview")
elif new_value == "DeepSeek":
self.base_url_var.set("https://api.deepseek.com/v1")
self.model_name_var.set("deepseek-chat")
elif new_value == "Gemini":
self.base_url_var.set("")
elif new_value == "Azure AI":
self.base_url_var.set("https://<your-endpoint>.services.ai.azure.com/models/chat/completions?api-version=2024-05-01-preview")
elif new_value == "阿里云百炼":
self.base_url_var.set("https://dashscope.aliyuncs.com/compatible-mode/v1")
self.model_name_var.set("qwen-plus")
elif new_value == "硅基流动":
self.base_url_var.set("https://api.siliconflow.cn/v1")
self.model_name_var.set("deepseek-ai/DeepSeek-V3")
elif new_value == "Grok":
self.base_url_var.set("https://api.x.ai/v1")
self.model_name_var.set("grok-3")
def add_new_config():
new_config_name = "New Config"
if new_config_name in self.loaded_config.get("llm_configs", {}):
messagebox.showerror("错误", "配置名称已存在!")
return
self.loaded_config["llm_configs"][new_config_name] = {
"api_key": "",
"base_url": "",
"model_name": "",
"temperature": 0.7,
"max_tokens": 8192,
"timeout": 600
}
# refresh_config_list()
def delete_config():
selected_config = self.interface_format_var.get()
if selected_config in self.loaded_config.get("llm_configs", {}):
del self.loaded_config["llm_configs"][selected_config]
# refresh_config_list()
else:
messagebox.showerror("错误", "未找到选中的配置!")
for i in range(9):
self.ai_config_tab.grid_rowconfigure(i, weight=0)
self.ai_config_tab.grid_columnconfigure(0, weight=0)
self.ai_config_tab.grid_columnconfigure(1, weight=1)
self.ai_config_tab.grid_columnconfigure(2, weight=0)
#接口配置
create_label_with_help(self, parent=self.ai_config_tab, label_text="接口配置", tooltip_key="interface_config", row= 0, column=0, font=("Microsoft YaHei", 12))
interface_config_dropdown = ctk.CTkOptionMenu(self.ai_config_tab, values=list(self.loaded_config.get("llm_configs", {}).keys()), variable=self.interface_config_var, command=on_interface_format_changed, font=("Microsoft YaHei", 12))
interface_config_dropdown.grid(row=0, column=1, padx=5, pady=5, columnspan=2, sticky="nsew")
#新增删除
add_btn = ctk.CTkButton(self.ai_config_tab, text="新增配置", command=add_new_config, font=("Microsoft YaHei", 12))
add_btn.grid(row=1, column=1, padx=5, pady=5, sticky="ew")
delete_btn = ctk.CTkButton(self.ai_config_tab, text="删除配置", command=delete_config, font=("Microsoft YaHei", 12))
delete_btn.grid(row=1, column=2, padx=5, pady=5, sticky="ew")
# 1) API Key
create_label_with_help(self, parent=self.ai_config_tab, label_text="LLM API Key:", tooltip_key="api_key", row=2, column=0, font=("Microsoft YaHei", 12))
api_key_entry = ctk.CTkEntry(self.ai_config_tab, textvariable=self.api_key_var, font=("Microsoft YaHei", 12),show="*")
api_key_entry.grid(row=2, column=1, padx=5, pady=5, columnspan=2, sticky="nsew")
# 2) Base URL
create_label_with_help(self, parent=self.ai_config_tab, label_text="LLM Base URL:", tooltip_key="base_url", row=3, column=0, font=("Microsoft YaHei", 12))
base_url_entry = ctk.CTkEntry(self.ai_config_tab, textvariable=self.base_url_var, font=("Microsoft YaHei", 12))
base_url_entry.grid(row=3, column=1, padx=5, pady=5, columnspan=2, sticky="nsew")
# 3) 接口格式
create_label_with_help(self, parent=self.ai_config_tab, label_text="LLM 接口格式:", tooltip_key="interface_format", row=4, column=0, font=("Microsoft YaHei", 12))
# 在接口选项列表中添加 "Grok"
interface_options = ["DeepSeek", "阿里云百炼", "OpenAI", "Azure OpenAI", "Azure AI", "Ollama", "ML Studio", "Gemini", "火山引擎", "硅基流动", "Grok"]
interface_dropdown = ctk.CTkOptionMenu(self.ai_config_tab, values=interface_options, variable=self.interface_format_var, command=on_interface_format_changed, font=("Microsoft YaHei", 12))
interface_dropdown.grid(row=4, column=1, padx=5, pady=5, columnspan=2, sticky="nsew")
# 4) Model Name
create_label_with_help(self, parent=self.ai_config_tab, label_text="Model Name:", tooltip_key="model_name", row=5, column=0, font=("Microsoft YaHei", 12))
model_name_entry = ctk.CTkEntry(self.ai_config_tab, textvariable=self.model_name_var, font=("Microsoft YaHei", 12))
model_name_entry.grid(row=5, column=1, padx=5, pady=5, columnspan=2, sticky="nsew")
# 5) Temperature
create_label_with_help(self, parent=self.ai_config_tab, label_text="Temperature:", tooltip_key="temperature", row=6, column=0, font=("Microsoft YaHei", 12))
def update_temp_label(value):
self.temp_value_label.configure(text=f"{float(value):.2f}")
temp_scale = ctk.CTkSlider(self.ai_config_tab, from_=0.0, to=2.0, number_of_steps=200, command=update_temp_label, variable=self.temperature_var)
temp_scale.grid(row=6, column=1, padx=5, pady=5, sticky="we")
self.temp_value_label = ctk.CTkLabel(self.ai_config_tab, text=f"{self.temperature_var.get():.2f}", font=("Microsoft YaHei", 12))
self.temp_value_label.grid(row=6, column=2, padx=5, pady=5, sticky="w")
# 6) Max Tokens
create_label_with_help(self, parent=self.ai_config_tab, label_text="Max Tokens:", tooltip_key="max_tokens", row=7, column=0, font=("Microsoft YaHei", 12))
def update_max_tokens_label(value):
self.max_tokens_value_label.configure(text=str(int(float(value))))
max_tokens_slider = ctk.CTkSlider(self.ai_config_tab, from_=0, to=102400, number_of_steps=100, command=update_max_tokens_label, variable=self.max_tokens_var)
max_tokens_slider.grid(row=7, column=1, padx=5, pady=5, sticky="we")
self.max_tokens_value_label = ctk.CTkLabel(self.ai_config_tab, text=str(self.max_tokens_var.get()), font=("Microsoft YaHei", 12))
self.max_tokens_value_label.grid(row=7, column=2, padx=5, pady=5, sticky="w")
# 7) Timeout (sec)
create_label_with_help(self, parent=self.ai_config_tab, label_text="Timeout (sec):", tooltip_key="timeout", row=8, column=0, font=("Microsoft YaHei", 12))
def update_timeout_label(value):
integer_val = int(float(value))
self.timeout_value_label.configure(text=str(integer_val))
timeout_slider = ctk.CTkSlider(self.ai_config_tab, from_=0, to=3600, number_of_steps=3600, command=update_timeout_label, variable=self.timeout_var)
timeout_slider.grid(row=8, column=1, padx=5, pady=5, sticky="we")
self.timeout_value_label = ctk.CTkLabel(self.ai_config_tab, text=str(self.timeout_var.get()), font=("Microsoft YaHei", 12))
self.timeout_value_label.grid(row=8, column=2, padx=5, pady=5, sticky="w")
# 添加测试按钮
test_btn = ctk.CTkButton(self.ai_config_tab, text="测试配置", command=self.test_llm_config, font=("Microsoft YaHei", 12))
test_btn.grid(row=9, column=0, columnspan=3, padx=5, pady=5, sticky="ew")
def build_embeddings_config_tab(self):
def on_embedding_interface_changed(new_value):
self.embedding_interface_format_var.set(new_value)
config_data = load_config(self.config_file)
if config_data:
config_data["last_embedding_interface_format"] = new_value
save_config(config_data, self.config_file)
if self.loaded_config and "embedding_configs" in self.loaded_config and new_value in self.loaded_config["embedding_configs"]:
emb_conf = self.loaded_config["embedding_configs"][new_value]
self.embedding_api_key_var.set(emb_conf.get("api_key", ""))
self.embedding_url_var.set(emb_conf.get("base_url", self.embedding_url_var.get()))
self.embedding_model_name_var.set(emb_conf.get("model_name", ""))
self.embedding_retrieval_k_var.set(str(emb_conf.get("retrieval_k", 4)))
else:
if new_value == "Ollama":
self.embedding_url_var.set("http://localhost:11434/api")
elif new_value == "ML Studio":
self.embedding_url_var.set("http://localhost:1234/v1")
elif new_value == "OpenAI":
self.embedding_url_var.set("https://api.openai.com/v1")
self.embedding_model_name_var.set("text-embedding-ada-002")
elif new_value == "Azure OpenAI":
self.embedding_url_var.set("https://[az].openai.azure.com/openai/deployments/[model]/embeddings?api-version=2023-05-15")
elif new_value == "DeepSeek":
self.embedding_url_var.set("https://api.deepseek.com/v1")
elif new_value == "Gemini":
self.embedding_url_var.set("https://generativelanguage.googleapis.com/v1beta/")
self.embedding_model_name_var.set("models/text-embedding-004")
elif new_value == "SiliconFlow":
self.embedding_url_var.set("https://api.siliconflow.cn/v1/embeddings")
self.embedding_model_name_var.set("BAAI/bge-m3")
for i in range(5):
self.embeddings_config_tab.grid_rowconfigure(i, weight=0)
self.embeddings_config_tab.grid_columnconfigure(0, weight=0)
self.embeddings_config_tab.grid_columnconfigure(1, weight=1)
self.embeddings_config_tab.grid_columnconfigure(2, weight=0)
# 1) Embedding API Key
create_label_with_help(self, parent=self.embeddings_config_tab, label_text="Embedding API Key:", tooltip_key="embedding_api_key", row=0, column=0, font=("Microsoft YaHei", 12))
emb_api_key_entry = ctk.CTkEntry(self.embeddings_config_tab, textvariable=self.embedding_api_key_var, font=("Microsoft YaHei", 12))
emb_api_key_entry.grid(row=0, column=1, padx=5, pady=5, sticky="nsew")
# 2) Embedding 接口格式
create_label_with_help(self, parent=self.embeddings_config_tab, label_text="Embedding 接口格式:", tooltip_key="embedding_intexrface_format", row=1, column=0, font=("Microsoft YaHei", 12))
emb_interface_options = ["DeepSeek", "OpenAI", "Azure OpenAI", "Gemini", "Ollama", "ML Studio","SiliconFlow"]
emb_interface_dropdown = ctk.CTkOptionMenu(self.embeddings_config_tab, values=emb_interface_options, variable=self.embedding_interface_format_var, command=on_embedding_interface_changed, font=("Microsoft YaHei", 12))
emb_interface_dropdown.grid(row=1, column=1, padx=5, pady=5, sticky="nsew")
# 3) Embedding Base URL
create_label_with_help(self, parent=self.embeddings_config_tab, label_text="Embedding Base URL:", tooltip_key="embedding_url", row=2, column=0, font=("Microsoft YaHei", 12))
emb_url_entry = ctk.CTkEntry(self.embeddings_config_tab, textvariable=self.embedding_url_var, font=("Microsoft YaHei", 12))
emb_url_entry.grid(row=2, column=1, padx=5, pady=5, sticky="nsew")
# 4) Embedding Model Name
create_label_with_help(self, parent=self.embeddings_config_tab, label_text="Embedding Model Name:", tooltip_key="embedding_model_name", row=3, column=0, font=("Microsoft YaHei", 12))
emb_model_name_entry = ctk.CTkEntry(self.embeddings_config_tab, textvariable=self.embedding_model_name_var, font=("Microsoft YaHei", 12))
emb_model_name_entry.grid(row=3, column=1, padx=5, pady=5, sticky="nsew")
# 5) Retrieval Top-K
create_label_with_help(self, parent=self.embeddings_config_tab, label_text="Retrieval Top-K:", tooltip_key="embedding_retrieval_k", row=4, column=0, font=("Microsoft YaHei", 12))
emb_retrieval_k_entry = ctk.CTkEntry(self.embeddings_config_tab, textvariable=self.embedding_retrieval_k_var, font=("Microsoft YaHei", 12))
emb_retrieval_k_entry.grid(row=4, column=1, padx=5, pady=5, sticky="nsew")
# 添加测试按钮
test_btn = ctk.CTkButton(self.embeddings_config_tab, text="测试配置", command=self.test_embedding_config, font=("Microsoft YaHei", 12))
test_btn.grid(row=5, column=0, columnspan=2, padx=5, pady=5, sticky="ew")
def build_config_choose_tab(self):
def on_core_seed_llm_changed(new_value):
self.core_seed_llm_var.set(new_value)
config_data = load_config(self.config_file)
if config_data:
config_data["core_seed_llm"] = new_value
save_config(config_data, self.config_file)
self.config_choose.grid_rowconfigure(0, weight=0)
self.config_choose.grid_columnconfigure(0, weight=0)
self.config_choose.grid_columnconfigure(1, weight=1)
config_choose_options = list(self.loaded_config.get("llm_configs", {}).keys())
create_label_with_help(self, parent=self.config_choose, label_text="生成核心种子所用大模型", tooltip_key="core_seed_llm_config", row=0, column=0, font=("Microsoft YaHei", 12))
core_seed_dropdown = ctk.CTkOptionMenu(self.config_choose, values=config_choose_options, variable=self.core_seed_llm_var, font=("Microsoft YaHei", 12), command=on_core_seed_llm_changed)
core_seed_dropdown.grid(row=0, column=1, padx=5, pady=5, sticky="nsew")
create_label_with_help(self, parent=self.config_choose, label_text="生成角色动力学所用大模型", tooltip_key="role_dynamics_llm_config", row=1, column=0, font=("Microsoft YaHei", 12))
role_dynamics_dropdown = ctk.CTkOptionMenu(self.config_choose, values=config_choose_options, variable=self.role_dynamics_llm_var, font=("Microsoft YaHei", 12))
role_dynamics_dropdown.grid(row=1, column=1, padx=5, pady=5, sticky="nsew")
create_label_with_help(self, parent=self.config_choose, label_text="生成世界观设定所用大模型", tooltip_key="world_building_llm_config", row=2, column=0, font=("Microsoft YaHei", 12))
world_building_dropdown = ctk.CTkOptionMenu(self.config_choose, values=config_choose_options, variable=self.world_building_llm_var, font=("Microsoft YaHei", 12))
world_building_dropdown.grid(row=2, column=1, padx=5, pady=5, sticky="nsew")
create_label_with_help(self, parent=self.config_choose, label_text="生成三幕式情节所用大模型", tooltip_key="three_scene_llm_config", row=3, column=0, font=("Microsoft YaHei", 12))
three_scene_dropdown = ctk.CTkOptionMenu(self.config_choose, values=config_choose_options, variable=self.three_scene_llm_var, font=("Microsoft YaHei", 12))
three_scene_dropdown.grid(row=3, column=1, padx=5, pady=5, sticky="nsew")
def load_config_btn(self):
cfg = load_config(self.config_file)
if cfg:
last_llm = cfg.get("last_interface_format", "OpenAI")
last_embedding = cfg.get("last_embedding_interface_format", "OpenAI")
self.interface_format_var.set(last_llm)
self.embedding_interface_format_var.set(last_embedding)
llm_configs = cfg.get("llm_configs", {})
if last_llm in llm_configs:
llm_conf = llm_configs[last_llm]
self.interface_format_var.set(llm_conf.get("interface_format", "OpenAI"))
self.api_key_var.set(llm_conf.get("api_key", ""))
self.base_url_var.set(llm_conf.get("base_url", "https://api.openai.com/v1"))
self.model_name_var.set(llm_conf.get("model_name", "gpt-4o-mini"))
self.temperature_var.set(llm_conf.get("temperature", 0.7))
self.max_tokens_var.set(llm_conf.get("max_tokens", 8192))
self.timeout_var.set(llm_conf.get("timeout", 600))
embedding_configs = cfg.get("embedding_configs", {})
if last_embedding in embedding_configs:
emb_conf = embedding_configs[last_embedding]
self.embedding_api_key_var.set(emb_conf.get("api_key", ""))
self.embedding_url_var.set(emb_conf.get("base_url", "https://api.openai.com/v1"))
self.embedding_model_name_var.set(emb_conf.get("model_name", "text-embedding-ada-002"))
self.embedding_retrieval_k_var.set(str(emb_conf.get("retrieval_k", 4)))
other_params = cfg.get("other_params", {})
self.topic_text.delete("0.0", "end")
self.topic_text.insert("0.0", other_params.get("topic", ""))
self.genre_var.set(other_params.get("genre", "玄幻"))
self.num_chapters_var.set(str(other_params.get("num_chapters", 10)))
self.word_number_var.set(str(other_params.get("word_number", 3000)))
self.filepath_var.set(other_params.get("filepath", ""))
self.chapter_num_var.set(str(other_params.get("chapter_num", "1")))
self.user_guide_text.delete("0.0", "end")
self.user_guide_text.insert("0.0", other_params.get("user_guidance", ""))
self.characters_involved_var.set(other_params.get("characters_involved", ""))
self.key_items_var.set(other_params.get("key_items", ""))
self.scene_location_var.set(other_params.get("scene_location", ""))
self.time_constraint_var.set(other_params.get("time_constraint", ""))
self.log("已加载配置。")
else:
messagebox.showwarning("提示", "未找到或无法读取配置文件。")
def save_config_btn(self):
current_llm_interface = self.interface_format_var.get().strip()
current_embedding_interface = self.embedding_interface_format_var.get().strip()
llm_config = {
"api_key": self.api_key_var.get(),
"base_url": self.base_url_var.get(),
"model_name": self.model_name_var.get(),
"temperature": self.temperature_var.get(),
"max_tokens": self.max_tokens_var.get(),
"timeout": self.safe_get_int(self.timeout_var, 600),
"interface_format": current_llm_interface
}
embedding_config = {
"api_key": self.embedding_api_key_var.get(),
"base_url": self.embedding_url_var.get(),
"model_name": self.embedding_model_name_var.get(),
"retrieval_k": self.safe_get_int(self.embedding_retrieval_k_var, 4),
"interface_format": current_embedding_interface
}
other_params = {
"topic": self.topic_text.get("0.0", "end").strip(),
"genre": self.genre_var.get(),
"num_chapters": self.safe_get_int(self.num_chapters_var, 10),
"word_number": self.safe_get_int(self.word_number_var, 3000),
"filepath": self.filepath_var.get(),
"chapter_num": self.chapter_num_var.get(),
"user_guidance": self.user_guide_text.get("0.0", "end").strip(),
"characters_involved": self.characters_involved_var.get(),
"key_items": self.key_items_var.get(),
"scene_location": self.scene_location_var.get(),
"time_constraint": self.time_constraint_var.get()
}
llm_config_name = self.base_url_var.get().split("/")[2] + " " + self.model_name_var.get()
existing_config = load_config(self.config_file)
if not existing_config:
existing_config = {}
existing_config["last_interface_format"] = current_llm_interface
existing_config["last_embedding_interface_format"] = current_embedding_interface
if "llm_configs" not in existing_config:
existing_config["llm_configs"] = {}
llm_config["config_name"] = llm_config_name
existing_config["llm_configs"][llm_config_name] = llm_config
if "embedding_configs" not in existing_config:
existing_config["embedding_configs"] = {}
existing_config["embedding_configs"][current_embedding_interface] = embedding_config
existing_config["other_params"] = other_params
if save_config(existing_config, self.config_file):
messagebox.showinfo("提示", "配置已保存至 config.json")
self.log("配置已保存。")
else:
messagebox.showerror("错误", "保存配置失败。")
+623 -110
View File
@@ -1,6 +1,8 @@
# ui/config_tab.py # ui/config_tab.py
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from tkinter import messagebox from tkinter import messagebox
import uuid
import datetime
import customtkinter as ctk import customtkinter as ctk
@@ -48,119 +50,549 @@ def build_config_tabview(self):
build_embeddings_config_tab(self) build_embeddings_config_tab(self)
build_config_choose_tab(self) build_config_choose_tab(self)
# 底部的"保存配置"和"加载配置"按钮 # # 底部的"保存配置"和"加载配置"按钮
self.btn_frame_config = ctk.CTkFrame(self.config_frame) # self.btn_frame_config = ctk.CTkFrame(self.config_frame)
self.btn_frame_config.grid(row=1, column=0, padx=5, pady=5, sticky="ew") # self.btn_frame_config.grid(row=1, column=0, padx=5, pady=5, sticky="ew")
self.btn_frame_config.columnconfigure(0, weight=1) # self.btn_frame_config.columnconfigure(0, weight=1)
self.btn_frame_config.columnconfigure(1, weight=1) # self.btn_frame_config.columnconfigure(1, weight=1)
save_config_btn = ctk.CTkButton(self.btn_frame_config, text="保存当前选择接口配置到文件", command=self.save_config_btn, font=("Microsoft YaHei", 12)) # save_config_btn = ctk.CTkButton(self.btn_frame_config, text="保存当前选择接口配置到文件", command=self.save_config_btn, font=("Microsoft YaHei", 12))
save_config_btn.grid(row=0, column=0, padx=5, pady=5, sticky="ew") # save_config_btn.grid(row=0, column=0, padx=5, pady=5, sticky="ew")
load_config_btn = ctk.CTkButton(self.btn_frame_config, text="加载当前选择接口配置到程序", command=self.load_config_btn, font=("Microsoft YaHei", 12)) # load_config_btn = ctk.CTkButton(self.btn_frame_config, text="加载当前选择接口配置到程序", command=self.load_config_btn, font=("Microsoft YaHei", 12))
load_config_btn.grid(row=0, column=1, padx=5, pady=5, sticky="ew") # load_config_btn.grid(row=0, column=1, padx=5, pady=5, sticky="ew")
def build_ai_config_tab(self): def build_ai_config_tab(self):
def on_interface_format_changed(new_value): def refresh_config_dropdown():
self.interface_format_var.set(new_value) """刷新配置下拉菜单"""
config_data = load_config(self.config_file) config_names = list(self.loaded_config.get("llm_configs", {}).keys())
if config_data: interface_config_dropdown.configure(values=config_names)
config_data["last_interface_format"] = new_value if config_names and self.interface_config_var.get() not in config_names:
save_config(config_data, self.config_file) self.interface_config_var.set(config_names[0])
if self.loaded_config and "llm_configs" in self.loaded_config and new_value in self.loaded_config["llm_configs"]:
llm_conf = self.loaded_config["llm_configs"][new_value]
self.api_key_var.set(llm_conf.get("api_key", ""))
self.base_url_var.set(llm_conf.get("base_url", self.base_url_var.get()))
self.model_name_var.set(llm_conf.get("model_name", ""))
self.temperature_var.set(llm_conf.get("temperature", 0.7))
self.max_tokens_var.set(llm_conf.get("max_tokens", 8192))
self.timeout_var.set(llm_conf.get("timeout", 600))
else:
if new_value == "Ollama":
self.base_url_var.set("http://localhost:11434/v1")
elif new_value == "ML Studio":
self.base_url_var.set("http://localhost:1234/v1")
elif new_value == "OpenAI":
self.base_url_var.set("https://api.openai.com/v1")
self.model_name_var.set("gpt-4o-mini")
elif new_value == "Azure OpenAI":
self.base_url_var.set("https://[az].openai.azure.com/openai/deployments/[model]/chat/completions?api-version=2024-08-01-preview")
elif new_value == "DeepSeek":
self.base_url_var.set("https://api.deepseek.com/v1")
self.model_name_var.set("deepseek-chat")
elif new_value == "Gemini":
self.base_url_var.set("")
elif new_value == "Azure AI":
self.base_url_var.set("https://<your-endpoint>.services.ai.azure.com/models/chat/completions?api-version=2024-05-01-preview")
elif new_value == "阿里云百炼":
self.base_url_var.set("https://dashscope.aliyuncs.com/compatible-mode/v1")
self.model_name_var.set("qwen-plus")
elif new_value == "硅基流动":
self.base_url_var.set("https://api.siliconflow.cn/v1")
self.model_name_var.set("deepseek-ai/DeepSeek-V3")
elif new_value == "Grok":
self.base_url_var.set("https://api.x.ai/v1")
self.model_name_var.set("grok-3")
for i in range(7): def on_config_selected(new_value):
"""当选择不同配置时的回调"""
if new_value in self.loaded_config.get("llm_configs", {}):
config = self.loaded_config["llm_configs"][new_value]
# 更新所有UI变量
self.api_key_var.set(config.get("api_key", ""))
self.base_url_var.set(config.get("base_url", ""))
self.model_name_var.set(config.get("model_name", ""))
self.temperature_var.set(float(config.get("temperature", 0.7)))
self.max_tokens_var.set(int(config.get("max_tokens", 8192)))
self.timeout_var.set(int(config.get("timeout", 600)))
self.interface_format_var.set(config.get("interface_format", "OpenAI"))
# 更新显示标签
self.temp_value_label.configure(text=f"{float(config.get('temperature', 0.7)):.2f}")
self.max_tokens_value_label.configure(text=str(int(config.get('max_tokens', 8192))))
self.timeout_value_label.configure(text=str(int(config.get('timeout', 600))))
def add_new_config():
"""添加新配置 - 弹出对话框让用户输入名称"""
dialog = ctk.CTkInputDialog(
text="请输入新配置名称:",
title="新增配置"
)
new_name = dialog.get_input()
if not new_name:
return
new_name = new_name.strip()
if new_name in self.loaded_config.get("llm_configs", {}):
messagebox.showerror("错误", f"配置名称 '{new_name}' 已存在!")
return
if "llm_configs" not in self.loaded_config:
self.loaded_config["llm_configs"] = {}
self.loaded_config["llm_configs"][new_name] = {
"id": str(uuid.uuid4()),
"api_key": "",
"base_url": "",
"model_name": "",
"temperature": 0.7,
"max_tokens": 8192,
"timeout": 600,
"interface_format": "OpenAI",
"created_at": datetime.datetime.now().isoformat()
}
refresh_config_dropdown()
self.interface_config_var.set(new_name)
messagebox.showinfo("提示", f"已成功创建新配置: {new_name}")
def delete_current_config():
"""删除当前选中的配置并保存到JSON文件"""
selected_config = self.interface_config_var.get()
if selected_config in self.loaded_config.get("llm_configs", {}):
if len(self.loaded_config["llm_configs"]) <= 1:
messagebox.showerror("错误", "至少需要保留一个配置!")
return
confirm = messagebox.askyesno(
"确认删除",
f"确定要删除配置 '{selected_config}' 吗?\n此操作不可撤销!"
)
if not confirm:
return
del self.loaded_config["llm_configs"][selected_config]
refresh_config_dropdown()
# 保存到JSON文件
try:
save_config(self.loaded_config, self.config_file)
messagebox.showinfo("提示", f"已删除配置: {selected_config},并已更新配置文件")
except Exception as e:
messagebox.showerror("错误", f"保存配置文件失败: {str(e)}")
else:
messagebox.showerror("错误", "未找到选中的配置!")
def save_current_config():
"""保存当前配置的修改到JSON文件"""
config_name = self.interface_config_var.get()
if config_name not in self.loaded_config.get("llm_configs", {}):
messagebox.showerror("错误", "配置不存在!")
return
config = self.loaded_config["llm_configs"][config_name]
config.update({
"api_key": self.api_key_var.get(),
"base_url": self.base_url_var.get(),
"model_name": self.model_name_var.get(),
"temperature": float(self.temperature_var.get()),
"max_tokens": int(self.max_tokens_var.get()),
"timeout": int(self.timeout_var.get()),
"interface_format": self.interface_format_var.get(),
"updated_at": datetime.datetime.now().isoformat()
})
# 如果修改了配置名称
new_name = self.interface_config_var.get()
if new_name != config_name:
self.loaded_config["llm_configs"][new_name] = self.loaded_config["llm_configs"].pop(config_name)
refresh_config_dropdown()
# 保存到JSON文件
try:
save_config(self.loaded_config, self.config_file)
messagebox.showinfo("提示", f"配置 {new_name} 已保存并持久化到文件")
except Exception as e:
messagebox.showerror("错误", f"保存配置文件失败: {str(e)}")
def rename_current_config():
"""重命名当前配置"""
old_name = self.interface_config_var.get()
if old_name not in self.loaded_config.get("llm_configs", {}):
messagebox.showerror("错误", "当前配置不存在!")
return
dialog = ctk.CTkInputDialog(
text=f"请输入新的配置名称 (原名称: {old_name}):",
title="重命名配置"
)
new_name = dialog.get_input()
if not new_name:
return
new_name = new_name.strip()
if new_name == old_name:
return
if new_name in self.loaded_config.get("llm_configs", {}):
messagebox.showerror("错误", f"配置名称 '{new_name}' 已存在!")
return
# 更新配置名称
self.loaded_config["llm_configs"][new_name] = self.loaded_config["llm_configs"].pop(old_name)
self.interface_config_var.set(new_name)
refresh_config_dropdown()
messagebox.showinfo("提示", f"配置已从 '{old_name}' 重命名为 '{new_name}'")
# 初始化UI布局
for i in range(10):
self.ai_config_tab.grid_rowconfigure(i, weight=0) self.ai_config_tab.grid_rowconfigure(i, weight=0)
self.ai_config_tab.grid_columnconfigure(0, weight=0) self.ai_config_tab.grid_columnconfigure(0, weight=0)
self.ai_config_tab.grid_columnconfigure(1, weight=1) self.ai_config_tab.grid_columnconfigure(1, weight=1)
self.ai_config_tab.grid_columnconfigure(2, weight=0) self.ai_config_tab.grid_columnconfigure(2, weight=0)
# 配置选择控件
create_label_with_help(self, self.ai_config_tab, "当前配置", "interface_config", 0, 0)
config_names = list(self.loaded_config.get("llm_configs", {}).keys())
if not config_names:
self.loaded_config["llm_configs"] = {
"默认配置": {
"id": str(uuid.uuid4()),
"api_key": "",
"base_url": "https://api.openai.com/v1",
"model_name": "gpt-4",
"temperature": 0.7,
"max_tokens": 8192,
"timeout": 600,
"interface_format": "OpenAI",
"created_at": datetime.datetime.now().isoformat()
}
}
config_names = ["默认配置"]
self.interface_config_var = ctk.StringVar(value=config_names[0])
interface_config_dropdown = ctk.CTkOptionMenu(
self.ai_config_tab,
values=config_names,
variable=self.interface_config_var,
command=on_config_selected,
font=("Microsoft YaHei", 12)
)
interface_config_dropdown.grid(row=0, column=1, columnspan=2, padx=5, pady=5, sticky="nsew")
# 配置管理按钮组
btn_frame = ctk.CTkFrame(self.ai_config_tab)
btn_frame.grid(row=1, column=0, columnspan=3, padx=5, pady=5, sticky="ew")
btn_frame.columnconfigure(0, weight=1)
btn_frame.columnconfigure(1, weight=1)
btn_frame.columnconfigure(2, weight=1)
btn_frame.columnconfigure(3, weight=1)
add_btn = ctk.CTkButton(
btn_frame,
text=" 新增",
command=add_new_config,
font=("Microsoft YaHei", 12),
fg_color="#2E8B57",
width=80
)
add_btn.grid(row=0, column=0, padx=2, pady=2, sticky="ew")
rename_btn = ctk.CTkButton(
btn_frame,
text="✏️ 重命名",
command=rename_current_config,
font=("Microsoft YaHei", 12),
fg_color="#DAA520",
width=80
)
rename_btn.grid(row=0, column=1, padx=2, pady=2, sticky="ew")
del_btn = ctk.CTkButton(
btn_frame,
text="🗑️ 删除",
command=delete_current_config,
font=("Microsoft YaHei", 12),
fg_color="#8B0000",
width=80
)
del_btn.grid(row=0, column=2, padx=2, pady=2, sticky="ew")
save_btn = ctk.CTkButton(
btn_frame,
text="💾 保存",
command=save_current_config,
font=("Microsoft YaHei", 12),
fg_color="#1E90FF",
width=80
)
save_btn.grid(row=0, column=3, padx=2, pady=2, sticky="ew")
# 配置参数控件
row_start = 2
# 1) API Key # 1) API Key
create_label_with_help(self, parent=self.ai_config_tab, label_text="LLM API Key:", tooltip_key="api_key", row=0, column=0, font=("Microsoft YaHei", 12)) create_label_with_help(self, self.ai_config_tab, "API Key:", "api_key", row_start, 0)
api_key_entry = ctk.CTkEntry(self.ai_config_tab, textvariable=self.api_key_var, font=("Microsoft YaHei", 12),show="*") self.api_key_var = ctk.StringVar(value="")
api_key_entry.grid(row=0, column=1, padx=5, pady=5, columnspan=2, sticky="nsew") api_key_entry = ctk.CTkEntry(
self.ai_config_tab,
textvariable=self.api_key_var,
font=("Microsoft YaHei", 12),
show="*"
)
api_key_entry.grid(row=row_start, column=1, columnspan=2, padx=5, pady=5, sticky="nsew")
# 2) Base URL # 2) Base URL
create_label_with_help(self, parent=self.ai_config_tab, label_text="LLM Base URL:", tooltip_key="base_url", row=1, column=0, font=("Microsoft YaHei", 12)) create_label_with_help(self, self.ai_config_tab, "Base URL:", "base_url", row_start+1, 0)
base_url_entry = ctk.CTkEntry(self.ai_config_tab, textvariable=self.base_url_var, font=("Microsoft YaHei", 12)) self.base_url_var = ctk.StringVar(value="")
base_url_entry.grid(row=1, column=1, padx=5, pady=5, columnspan=2, sticky="nsew") base_url_entry = ctk.CTkEntry(
self.ai_config_tab,
textvariable=self.base_url_var,
font=("Microsoft YaHei", 12)
)
base_url_entry.grid(row=row_start+1, column=1, columnspan=2, padx=5, pady=5, sticky="nsew")
# 3) 接口格式 # 3) 接口格式
create_label_with_help(self, parent=self.ai_config_tab, label_text="LLM 接口格式:", tooltip_key="interface_format", row=2, column=0, font=("Microsoft YaHei", 12)) create_label_with_help(self, self.ai_config_tab, "接口格式:", "interface_format", row_start+2, 0)
# 在接口选项列表中添加 "Grok" self.interface_format_var = ctk.StringVar(value="OpenAI")
interface_options = ["DeepSeek", "阿里云百炼", "OpenAI", "Azure OpenAI", "Azure AI", "Ollama", "ML Studio", "Gemini", "火山引擎", "硅基流动", "Grok"] interface_options = ["OpenAI", "Azure OpenAI", "Ollama", "DeepSeek", "Gemini", "ML Studio"]
interface_dropdown = ctk.CTkOptionMenu(self.ai_config_tab, values=interface_options, variable=self.interface_format_var, command=on_interface_format_changed, font=("Microsoft YaHei", 12)) interface_dropdown = ctk.CTkOptionMenu(
interface_dropdown.grid(row=2, column=1, padx=5, pady=5, columnspan=2, sticky="nsew") self.ai_config_tab,
values=interface_options,
variable=self.interface_format_var,
font=("Microsoft YaHei", 12)
)
interface_dropdown.grid(row=row_start+2, column=1, columnspan=2, padx=5, pady=5, sticky="nsew")
# 4) Model Name # 4) Model Name
create_label_with_help(self, parent=self.ai_config_tab, label_text="Model Name:", tooltip_key="model_name", row=3, column=0, font=("Microsoft YaHei", 12)) create_label_with_help(self, self.ai_config_tab, "模型名称:", "model_name", row_start+3, 0)
model_name_entry = ctk.CTkEntry(self.ai_config_tab, textvariable=self.model_name_var, font=("Microsoft YaHei", 12)) self.model_name_var = ctk.StringVar(value="")
model_name_entry.grid(row=3, column=1, padx=5, pady=5, columnspan=2, sticky="nsew") model_name_entry = ctk.CTkEntry(
self.ai_config_tab,
textvariable=self.model_name_var,
font=("Microsoft YaHei", 12)
)
model_name_entry.grid(row=row_start+3, column=1, columnspan=2, padx=5, pady=5, sticky="nsew")
# 5) Temperature # 5) Temperature
create_label_with_help(self, parent=self.ai_config_tab, label_text="Temperature:", tooltip_key="temperature", row=4, column=0, font=("Microsoft YaHei", 12)) create_label_with_help(self, self.ai_config_tab, "Temperature:", "temperature", row_start+4, 0)
self.temperature_var = ctk.DoubleVar(value=0.7)
def update_temp_label(value): def update_temp_label(value):
self.temp_value_label.configure(text=f"{float(value):.2f}") self.temp_value_label.configure(text=f"{float(value):.2f}")
temp_scale = ctk.CTkSlider(self.ai_config_tab, from_=0.0, to=2.0, number_of_steps=200, command=update_temp_label, variable=self.temperature_var) temp_scale = ctk.CTkSlider(
temp_scale.grid(row=4, column=1, padx=5, pady=5, sticky="we") self.ai_config_tab,
self.temp_value_label = ctk.CTkLabel(self.ai_config_tab, text=f"{self.temperature_var.get():.2f}", font=("Microsoft YaHei", 12)) from_=0.0,
self.temp_value_label.grid(row=4, column=2, padx=5, pady=5, sticky="w") to=2.0,
number_of_steps=200,
command=update_temp_label,
variable=self.temperature_var
)
temp_scale.grid(row=row_start+4, column=1, padx=5, pady=5, sticky="we")
self.temp_value_label = ctk.CTkLabel(
self.ai_config_tab,
text=f"{self.temperature_var.get():.2f}",
font=("Microsoft YaHei", 12)
)
self.temp_value_label.grid(row=row_start+4, column=2, padx=5, pady=5, sticky="w")
# 6) Max Tokens # 6) Max Tokens
create_label_with_help(self, parent=self.ai_config_tab, label_text="Max Tokens:", tooltip_key="max_tokens", row=5, column=0, font=("Microsoft YaHei", 12)) create_label_with_help(self, self.ai_config_tab, "Max Tokens:", "max_tokens", row_start+5, 0)
self.max_tokens_var = ctk.IntVar(value=8192)
def update_max_tokens_label(value): def update_max_tokens_label(value):
self.max_tokens_value_label.configure(text=str(int(float(value)))) self.max_tokens_value_label.configure(text=str(int(float(value))))
max_tokens_slider = ctk.CTkSlider(self.ai_config_tab, from_=0, to=102400, number_of_steps=100, command=update_max_tokens_label, variable=self.max_tokens_var) max_tokens_slider = ctk.CTkSlider(
max_tokens_slider.grid(row=5, column=1, padx=5, pady=5, sticky="we") self.ai_config_tab,
self.max_tokens_value_label = ctk.CTkLabel(self.ai_config_tab, text=str(self.max_tokens_var.get()), font=("Microsoft YaHei", 12)) from_=0,
self.max_tokens_value_label.grid(row=5, column=2, padx=5, pady=5, sticky="w") to=102400,
number_of_steps=100,
command=update_max_tokens_label,
variable=self.max_tokens_var
)
max_tokens_slider.grid(row=row_start+5, column=1, padx=5, pady=5, sticky="we")
self.max_tokens_value_label = ctk.CTkLabel(
self.ai_config_tab,
text=str(self.max_tokens_var.get()),
font=("Microsoft YaHei", 12)
)
self.max_tokens_value_label.grid(row=row_start+5, column=2, padx=5, pady=5, sticky="w")
# 7) Timeout (sec) # 7) Timeout
create_label_with_help(self, parent=self.ai_config_tab, label_text="Timeout (sec):", tooltip_key="timeout", row=6, column=0, font=("Microsoft YaHei", 12)) create_label_with_help(self, self.ai_config_tab, "Timeout (sec):", "timeout", row_start+6, 0)
self.timeout_var = ctk.IntVar(value=600)
def update_timeout_label(value): def update_timeout_label(value):
integer_val = int(float(value)) self.timeout_value_label.configure(text=str(int(float(value))))
self.timeout_value_label.configure(text=str(integer_val)) timeout_slider = ctk.CTkSlider(
timeout_slider = ctk.CTkSlider(self.ai_config_tab, from_=0, to=3600, number_of_steps=3600, command=update_timeout_label, variable=self.timeout_var) self.ai_config_tab,
timeout_slider.grid(row=6, column=1, padx=5, pady=5, sticky="we") from_=0,
self.timeout_value_label = ctk.CTkLabel(self.ai_config_tab, text=str(self.timeout_var.get()), font=("Microsoft YaHei", 12)) to=3600,
self.timeout_value_label.grid(row=6, column=2, padx=5, pady=5, sticky="w") number_of_steps=3600,
command=update_timeout_label,
variable=self.timeout_var
)
timeout_slider.grid(row=row_start+6, column=1, padx=5, pady=5, sticky="we")
self.timeout_value_label = ctk.CTkLabel(
self.ai_config_tab,
text=str(self.timeout_var.get()),
font=("Microsoft YaHei", 12)
)
self.timeout_value_label.grid(row=row_start+6, column=2, padx=5, pady=5, sticky="w")
# 添加测试按钮 # 测试按钮
test_btn = ctk.CTkButton(self.ai_config_tab, text="测试配置", command=self.test_llm_config, font=("Microsoft YaHei", 12)) test_btn = ctk.CTkButton(
test_btn.grid(row=7, column=0, columnspan=3, padx=5, pady=5, sticky="ew") self.ai_config_tab,
text="测试配置",
command=self.test_llm_config,
font=("Microsoft YaHei", 12)
)
test_btn.grid(row=row_start+7, column=0, columnspan=3, padx=5, pady=5, sticky="ew")
# 初始化当前配置
on_config_selected(config_names[0])
# def refresh_config_dropdown():
# """刷新配置下拉菜单"""
# config_names = list(self.loaded_config.get("llm_configs", {}).keys())
# interface_config_dropdown.configure(values=config_names)
# if config_names and self.interface_config_var.get() not in config_names:
# self.interface_config_var.set(config_names[0])
# def on_config_selected(new_value):
# """当选择不同配置时的回调"""
# if new_value in self.loaded_config.get("llm_configs", {}):
# config = self.loaded_config["llm_configs"][new_value]
# self.api_key_var.set(config.get("api_key", ""))
# self.base_url_var.set(config.get("base_url", ""))
# self.model_name_var.set(config.get("model_name", ""))
# self.temperature_var.set(config.get("temperature", 0.7))
# self.max_tokens_var.set(config.get("max_tokens", 8192))
# self.timeout_var.set(config.get("timeout", 600))
# self.interface_format_var.set(config.get("interface_format", "OpenAI"))
# def add_new_config():
# """添加新配置 - 弹出对话框让用户输入名称"""
# # 创建输入对话框
# dialog = ctk.CTkInputDialog(
# text="请输入新配置名称:",
# title="新增配置"
# )
# new_name = dialog.get_input() # 获取用户输入
# if not new_name:
# return # 用户取消输入
# new_name = new_name.strip()
# # 检查名称是否已存在
# if new_name in self.loaded_config.get("llm_configs", {}):
# messagebox.showerror("错误", f"配置名称 '{new_name}' 已存在!")
# return
# # 添加到配置字典
# if "llm_configs" not in self.loaded_config:
# self.loaded_config["llm_configs"] = {}
# self.loaded_config["llm_configs"][new_name] = {
# "id": str(uuid.uuid4()), # 生成唯一ID
# "api_key": "",
# "base_url": "",
# "model_name": "",
# "temperature": 0.7,
# "max_tokens": 8192,
# "timeout": 600,
# "interface_format": "OpenAI",
# "created_at": datetime.datetime.now().isoformat() # 添加创建时间
# }
# refresh_config_dropdown()
# self.interface_config_var.set(new_name)
# messagebox.showinfo("提示", f"已成功创建新配置: {new_name}")
# def delete_current_config():
# """删除当前选中的配置"""
# selected_config = self.interface_config_var.get()
# if selected_config in self.loaded_config.get("llm_configs", {}):
# if len(self.loaded_config["llm_configs"]) <= 1:
# messagebox.showerror("错误", "至少需要保留一个配置!")
# return
# # 确认对话框
# confirm = messagebox.askyesno(
# "确认删除",
# f"确定要删除配置 '{selected_config}' 吗?\n此操作不可撤销!"
# )
# if not confirm:
# return
# del self.loaded_config["llm_configs"][selected_config]
# refresh_config_dropdown()
# messagebox.showinfo("提示", f"已删除配置: {selected_config}")
# else:
# messagebox.showerror("错误", "未找到选中的配置!")
# def save_current_config():
# """保存当前配置"""
# config_name = self.interface_config_var.get()
# if config_name not in self.loaded_config.get("llm_configs", {}):
# messagebox.showerror("错误", "配置不存在!")
# return
# config = self.loaded_config["llm_configs"][config_name]
# config.update({
# "api_key": self.api_key_var.get(),
# "base_url": self.base_url_var.get(),
# "model_name": self.model_name_var.get(),
# "temperature": self.temperature_var.get(),
# "max_tokens": self.max_tokens_var.get(),
# "timeout": self.timeout_var.get(),
# "interface_format": self.interface_format_var.get(),
# "updated_at": datetime.datetime.now().isoformat() # 添加更新时间
# })
# messagebox.showinfo("提示", f"配置 {config_name} 已更新")
# 初始化UI布局
for i in range(10): # 增加一行给按钮组
self.ai_config_tab.grid_rowconfigure(i, weight=0)
self.ai_config_tab.grid_columnconfigure(0, weight=0)
self.ai_config_tab.grid_columnconfigure(1, weight=1)
self.ai_config_tab.grid_columnconfigure(2, weight=0)
# 配置选择控件
create_label_with_help(self, self.ai_config_tab, "当前配置", "interface_config", 0, 0)
config_names = list(self.loaded_config.get("llm_configs", {}).keys())
if not config_names: # 如果没有配置,创建一个默认配置
self.loaded_config["llm_configs"] = {
"默认配置": {
"id": str(uuid.uuid4()),
"api_key": "",
"base_url": "https://api.openai.com/v1",
"model_name": "gpt-4",
"temperature": 0.7,
"max_tokens": 8192,
"timeout": 600,
"interface_format": "OpenAI",
"created_at": datetime.datetime.now().isoformat()
}
}
config_names = ["默认配置"]
interface_config_dropdown = ctk.CTkOptionMenu(
self.ai_config_tab,
values=config_names,
variable=self.interface_config_var,
command=on_config_selected,
font=("Microsoft YaHei", 12)
)
interface_config_dropdown.grid(row=0, column=1, columnspan=2, padx=5, pady=5, sticky="nsew")
# # 配置管理按钮组
# btn_frame = ctk.CTkFrame(self.ai_config_tab)
# btn_frame.grid(row=1, column=0, columnspan=3, padx=5, pady=5, sticky="ew")
# btn_frame.columnconfigure(0, weight=1)
# btn_frame.columnconfigure(1, weight=1)
# btn_frame.columnconfigure(2, weight=1)
# add_btn = ctk.CTkButton(
# btn_frame,
# text=" 新增配置",
# command=add_new_config,
# font=("Microsoft YaHei", 12),
# fg_color="#2E8B57", # 绿色
# hover_color="#3CB371"
# )
# add_btn.grid(row=0, column=0, padx=5, pady=5, sticky="ew")
# del_btn = ctk.CTkButton(
# btn_frame,
# text="🗑️ 删除配置",
# command=delete_current_config,
# font=("Microsoft YaHei", 12),
# fg_color="#8B0000", # 红色
# hover_color="#CD5C5C"
# )
# del_btn.grid(row=0, column=1, padx=5, pady=5, sticky="ew")
# save_btn = ctk.CTkButton(
# btn_frame,
# text="💾 保存配置",
# command=save_current_config,
# font=("Microsoft YaHei", 12),
# fg_color="#1E90FF", # 蓝色
# hover_color="#6495ED"
# )
# save_btn.grid(row=0, column=2, padx=5, pady=5, sticky="ew")
# 其余配置项保持不变...
# API Key, Base URL等配置项的创建代码...
def build_embeddings_config_tab(self): def build_embeddings_config_tab(self):
def on_embedding_interface_changed(new_value): def on_embedding_interface_changed(new_value):
@@ -233,38 +665,111 @@ def build_embeddings_config_tab(self):
test_btn.grid(row=5, column=0, columnspan=2, padx=5, pady=5, sticky="ew") test_btn.grid(row=5, column=0, columnspan=2, padx=5, pady=5, sticky="ew")
def build_config_choose_tab(self): def build_config_choose_tab(self):
def on_core_seed_llm_changed(new_value): # def on_core_seed_llm_changed(new_value):
self.core_seed_llm_var.set(new_value) # self.core_seed_llm_var.set(new_value)
config_data = load_config(self.config_file) # config_data = load_config(self.config_file)
if config_data: # if config_data:
config_data["core_seed_llm"] = new_value # config_data["core_seed_llm"] = new_value
save_config(config_data, self.config_file) # save_config(config_data, self.config_file)
self.config_choose.grid_rowconfigure(0, weight=0) self.config_choose.grid_rowconfigure(0, weight=0)
self.config_choose.grid_columnconfigure(0, weight=0) self.config_choose.grid_columnconfigure(0, weight=0)
self.config_choose.grid_columnconfigure(1, weight=1) self.config_choose.grid_columnconfigure(1, weight=1)
config_choose_options = list(self.loaded_config.get("llm_configs", {}).keys())
create_label_with_help(self, parent=self.config_choose, label_text="生成架构所用大模型", tooltip_key="architecture_llm_config", row=0, column=0, font=("Microsoft YaHei", 12))
architecture_dropdown = ctk.CTkOptionMenu(self.config_choose, values=config_choose_options, variable=self.architecture_llm_var, font=("Microsoft YaHei", 12))
architecture_dropdown.grid(row=0, column=1, padx=5, pady=5, sticky="nsew")
create_label_with_help(self, parent=self.config_choose, label_text="生成核心种子所用大模型", tooltip_key="core_seed_llm_config", row=0, column=0, font=("Microsoft YaHei", 12)) create_label_with_help(self, parent=self.config_choose, label_text="生成大目录所用大模型", tooltip_key="chapter_outline_llm_config", row=1, column=0, font=("Microsoft YaHei", 12))
core_seed_options = ["DeepSeek", "阿里云百炼", "OpenAI", "Azure OpenAI", "Azure AI", "Ollama", "ML Studio", "Gemini", "火山引擎", "硅基流动", "Grok"] chapter_outline_dropdown = ctk.CTkOptionMenu(self.config_choose, values=config_choose_options, variable=self.chapter_outline_llm_var, font=("Microsoft YaHei", 12))
core_seed_dropdown = ctk.CTkOptionMenu(self.config_choose, values=core_seed_options, variable=self.core_seed_llm_var, font=("Microsoft YaHei", 12), command=on_core_seed_llm_changed) chapter_outline_dropdown.grid(row=1, column=1, padx=5, pady=5, sticky="nsew")
core_seed_dropdown.grid(row=0, column=1, padx=5, pady=5, sticky="nsew")
create_label_with_help(self, parent=self.config_choose, label_text="生成角色动力学所用大模型", tooltip_key="role_dynamics_llm_config", row=1, column=0, font=("Microsoft YaHei", 12)) create_label_with_help(self, parent=self.config_choose, label_text="生成草稿所用大模型", tooltip_key="prompt_draft_llm_config", row=2, column=0, font=("Microsoft YaHei", 12))
role_dynamics_options = ["DeepSeek", "阿里云百炼", "OpenAI", "Azure OpenAI", "Azure AI", "Ollama", "ML Studio", "Gemini", "火山引擎", "硅基流动", "Grok"] prompt_draft_dropdown = ctk.CTkOptionMenu(self.config_choose, values=config_choose_options, variable=self.prompt_draft_llm_var, font=("Microsoft YaHei", 12))
role_dynamics_dropdown = ctk.CTkOptionMenu(self.config_choose, values=role_dynamics_options, variable=self.role_dynamics_llm_var, font=("Microsoft YaHei", 12)) prompt_draft_dropdown.grid(row=2, column=1, padx=5, pady=5, sticky="nsew")
role_dynamics_dropdown.grid(row=1, column=1, padx=5, pady=5, sticky="nsew")
create_label_with_help(self, parent=self.config_choose, label_text="生成世界观设定所用大模型", tooltip_key="world_building_llm_config", row=2, column=0, font=("Microsoft YaHei", 12)) create_label_with_help(self, parent=self.config_choose, label_text="稿章节所用大模型", tooltip_key="final_chapter_llm_config", row=3, column=0, font=("Microsoft YaHei", 12))
world_building_options = ["DeepSeek", "阿里云百炼", "OpenAI", "Azure OpenAI", "Azure AI", "Ollama", "ML Studio", "Gemini", "火山引擎", "硅基流动", "Grok"] final_chapter_dropdown = ctk.CTkOptionMenu(self.config_choose, values=config_choose_options, variable=self.final_chapter_llm_var, font=("Microsoft YaHei", 12))
world_building_dropdown = ctk.CTkOptionMenu(self.config_choose, values=world_building_options, variable=self.world_building_llm_var, font=("Microsoft YaHei", 12)) final_chapter_dropdown.grid(row=3, column=1, padx=5, pady=5, sticky="nsew")
world_building_dropdown.grid(row=2, column=1, padx=5, pady=5, sticky="nsew")
create_label_with_help(self, parent=self.config_choose, label_text="生成三幕式情节所用大模型", tooltip_key="three_scene_llm_config", row=3, column=0, font=("Microsoft YaHei", 12)) create_label_with_help(self, parent=self.config_choose, label_text="一致性审校所用大模型", tooltip_key="consistency_review_llm_config", row=4, column=0, font=("Microsoft YaHei", 12))
three_scene_options = ["DeepSeek", "阿里云百炼", "OpenAI", "Azure OpenAI", "Azure AI", "Ollama", "ML Studio", "Gemini", "火山引擎", "硅基流动", "Grok"] consistency_review_dropdown = ctk.CTkOptionMenu(self.config_choose, values=config_choose_options, variable=self.consistency_review_llm_var, font=("Microsoft YaHei", 12))
three_scene_dropdown = ctk.CTkOptionMenu(self.config_choose, values=three_scene_options, variable=self.three_scene_llm_var, font=("Microsoft YaHei", 12)) consistency_review_dropdown.grid(row=4, column=1, padx=5, pady=5, sticky="nsew")
three_scene_dropdown.grid(row=3, column=1, padx=5, pady=5, sticky="nsew")
# create_label_with_help(self, parent=self.config_choose, label_text="生成核心种子所用大模型", tooltip_key="core_seed_llm_config", row=0, column=0, font=("Microsoft YaHei", 12))
# core_seed_dropdown = ctk.CTkOptionMenu(self.config_choose, values=config_choose_options, variable=self.core_seed_llm_var, font=("Microsoft YaHei", 12), command=on_core_seed_llm_changed)
# core_seed_dropdown.grid(row=0, column=1, padx=5, pady=5, sticky="nsew")
# create_label_with_help(self, parent=self.config_choose, label_text="生成角色动力学所用大模型", tooltip_key="role_dynamics_llm_config", row=1, column=0, font=("Microsoft YaHei", 12))
# role_dynamics_dropdown = ctk.CTkOptionMenu(self.config_choose, values=config_choose_options, variable=self.role_dynamics_llm_var, font=("Microsoft YaHei", 12))
# role_dynamics_dropdown.grid(row=1, column=1, padx=5, pady=5, sticky="nsew")
# create_label_with_help(self, parent=self.config_choose, label_text="生成世界观设定所用大模型", tooltip_key="world_building_llm_config", row=2, column=0, font=("Microsoft YaHei", 12))
# world_building_dropdown = ctk.CTkOptionMenu(self.config_choose, values=config_choose_options, variable=self.world_building_llm_var, font=("Microsoft YaHei", 12))
# world_building_dropdown.grid(row=2, column=1, padx=5, pady=5, sticky="nsew")
# create_label_with_help(self, parent=self.config_choose, label_text="生成三幕式情节所用大模型", tooltip_key="three_scene_llm_config", row=3, column=0, font=("Microsoft YaHei", 12))
# three_scene_dropdown = ctk.CTkOptionMenu(self.config_choose, values=config_choose_options, variable=self.three_scene_llm_var, font=("Microsoft YaHei", 12))
# three_scene_dropdown.grid(row=3, column=1, padx=5, pady=5, sticky="nsew")
# create_label_with_help(self, parent=self.config_choose, label_text="生成章节目录所用大模型", tooltip_key="chapter_outline_llm_config", row=4, column=0, font=("Microsoft YaHei", 12))
# chapter_outline_dropdown = ctk.CTkOptionMenu(self.config_choose, values=config_choose_options, variable=self.chapter_outline_llm_var, font=("Microsoft YaHei", 12))
# chapter_outline_dropdown.grid(row=4, column=1, padx=5, pady=5, sticky="nsew")
# create_label_with_help(self, parent=self.config_choose, label_text="生成前文摘要所用大模型", tooltip_key="summary_llm_config", row=5, column=0, font=("Microsoft YaHei", 12))
# summary_dropdown = ctk.CTkOptionMenu(self.config_choose, values=config_choose_options, variable=self.summary_llm_var, font=("Microsoft YaHei", 12))
# summary_dropdown.grid(row=5, column=1, padx=5, pady=5, sticky="nsew")
# create_label_with_help(self, parent=self.config_choose, label_text="生成角色状态所用大模型", tooltip_key="character_state_llm_config", row=6, column=0, font=("Microsoft YaHei", 12))
# character_state_dropdown = ctk.CTkOptionMenu(self.config_choose, values=config_choose_options, variable=self.character_state_llm_var, font=("Microsoft YaHei", 12))
# character_state_dropdown.grid(row=6, column=1, padx=5, pady=5, sticky="nsew")
# create_label_with_help(self, parent=self.config_choose, label_text="生成章节内容所用大模型", tooltip_key="chapter_content_llm_config", row=7, column=0, font=("Microsoft YaHei", 12))
# chapter_content_dropdown = ctk.CTkOptionMenu(self.config_choose, values=config_choose_options, variable=self.chapter_content_llm_var, font=("Microsoft YaHei", 12))
# chapter_content_dropdown.grid(row=7, column=1, padx=5, pady=5, sticky="nsew")
# create_label_with_help(self, parent=self.config_choose, label_text="生成提示草稿所用大模型", tooltip_key="prompt_draft_llm_config", row=8, column=0, font=("Microsoft YaHei", 12))
# prompt_draft_dropdown = ctk.CTkOptionMenu(self.config_choose, values=config_choose_options, variable=self.prompt_draft_llm_var, font=("Microsoft YaHei", 12))
# prompt_draft_dropdown.grid(row=8, column=1, padx=5, pady=5, sticky="nsew")
# create_label_with_help(self, parent=self.config_choose, label_text="分析角色信息所用大模型", tooltip_key="analyze_character_llm_config", row=9, column=0, font=("Microsoft YaHei", 12))
# analyze_character_dropdown = ctk.CTkOptionMenu(self.config_choose, values=config_choose_options, variable=self.analyze_character_llm_var, font=("Microsoft YaHei", 12))
# analyze_character_dropdown.grid(row=9, column=1, padx=5, pady=5, sticky="nsew")
def save_config_choose():
config_data = load_config(self.config_file)["choose_configs"]
if not config_data:
config_data = {}
# config_data["core_seed_llm"] = self.core_seed_llm_var.get()
# config_data["role_dynamics_llm"] = self.role_dynamics_llm_var.get()
# config_data["world_building_llm"] = self.world_building_llm_var.get()
# config_data["three_scene_llm"] = self.three_scene_llm_var.get()
# config_data["chapter_outline_llm"] = self.chapter_outline_llm_var.get()
# config_data["summary_llm"] = self.summary_llm_var.get()
# config_data["character_state_llm"] = self.character_state_llm_var.get()
# config_data["chapter_content_llm"] = self.chapter_content_llm_var.get()
# config_data["prompt_draft_llm"] = self.prompt_draft_llm_var.get()
# config_data["analyze_character_llm"] = self.analyze_character_llm_var.get()
config_data["architecture_llm"] = self.architecture_llm_var.get()
config_data["chapter_outline_llm"] = self.chapter_outline_llm_var.get()
config_data["prompt_draft_llm"] = self.prompt_draft_llm_var.get()
config_data["final_chapter_llm"] = self.final_chapter_llm_var.get()
config_data_full = load_config(self.config_file)
config_data_full["choose_configs"] = config_data
save_config(config_data_full, self.config_file)
messagebox.showinfo("提示", "配置已保存。")
test_btn = ctk.CTkButton(
self.config_choose,
text="保存配置",
command=save_config_choose,
font=("Microsoft YaHei", 12)
)
test_btn.grid(row=10, column=0, columnspan=3, padx=5, pady=5, sticky="ew")
@@ -281,6 +786,7 @@ def load_config_btn(self):
llm_configs = cfg.get("llm_configs", {}) llm_configs = cfg.get("llm_configs", {})
if last_llm in llm_configs: if last_llm in llm_configs:
llm_conf = llm_configs[last_llm] llm_conf = llm_configs[last_llm]
self.interface_format_var.set(llm_conf.get("interface_format", "OpenAI"))
self.api_key_var.set(llm_conf.get("api_key", "")) self.api_key_var.set(llm_conf.get("api_key", ""))
self.base_url_var.set(llm_conf.get("base_url", "https://api.openai.com/v1")) self.base_url_var.set(llm_conf.get("base_url", "https://api.openai.com/v1"))
self.model_name_var.set(llm_conf.get("model_name", "gpt-4o-mini")) self.model_name_var.set(llm_conf.get("model_name", "gpt-4o-mini"))
@@ -321,13 +827,16 @@ def save_config_btn(self):
"model_name": self.model_name_var.get(), "model_name": self.model_name_var.get(),
"temperature": self.temperature_var.get(), "temperature": self.temperature_var.get(),
"max_tokens": self.max_tokens_var.get(), "max_tokens": self.max_tokens_var.get(),
"timeout": self.safe_get_int(self.timeout_var, 600) "timeout": self.safe_get_int(self.timeout_var, 600),
"interface_format": current_llm_interface
} }
embedding_config = { embedding_config = {
"api_key": self.embedding_api_key_var.get(), "api_key": self.embedding_api_key_var.get(),
"base_url": self.embedding_url_var.get(), "base_url": self.embedding_url_var.get(),
"model_name": self.embedding_model_name_var.get(), "model_name": self.embedding_model_name_var.get(),
"retrieval_k": self.safe_get_int(self.embedding_retrieval_k_var, 4) "retrieval_k": self.safe_get_int(self.embedding_retrieval_k_var, 4),
"interface_format": current_embedding_interface
} }
other_params = { other_params = {
"topic": self.topic_text.get("0.0", "end").strip(), "topic": self.topic_text.get("0.0", "end").strip(),
@@ -342,6 +851,8 @@ def save_config_btn(self):
"scene_location": self.scene_location_var.get(), "scene_location": self.scene_location_var.get(),
"time_constraint": self.time_constraint_var.get() "time_constraint": self.time_constraint_var.get()
} }
llm_config_name = self.base_url_var.get().split("/")[2] + " " + self.model_name_var.get()
existing_config = load_config(self.config_file) existing_config = load_config(self.config_file)
if not existing_config: if not existing_config:
existing_config = {} existing_config = {}
@@ -349,7 +860,9 @@ def save_config_btn(self):
existing_config["last_embedding_interface_format"] = current_embedding_interface existing_config["last_embedding_interface_format"] = current_embedding_interface
if "llm_configs" not in existing_config: if "llm_configs" not in existing_config:
existing_config["llm_configs"] = {} existing_config["llm_configs"] = {}
existing_config["llm_configs"][current_llm_interface] = llm_config llm_config["config_name"] = llm_config_name
existing_config["llm_configs"][llm_config_name] = llm_config
if "embedding_configs" not in existing_config: if "embedding_configs" not in existing_config:
existing_config["embedding_configs"] = {} existing_config["embedding_configs"] = {}
+82 -35
View File
@@ -32,13 +32,23 @@ def generate_novel_architecture_ui(self):
self.disable_button_safe(self.btn_generate_architecture) self.disable_button_safe(self.btn_generate_architecture)
try: try:
interface_format = self.interface_format_var.get().strip() # interface_format = self.interface_format_var.get().strip()
api_key = self.api_key_var.get().strip() # api_key = self.api_key_var.get().strip()
base_url = self.base_url_var.get().strip() # base_url = self.base_url_var.get().strip()
model_name = self.model_name_var.get().strip() # model_name = self.model_name_var.get().strip()
temperature = self.temperature_var.get() # temperature = self.temperature_var.get()
max_tokens = self.max_tokens_var.get() # max_tokens = self.max_tokens_var.get()
timeout_val = self.safe_get_int(self.timeout_var, 600) # timeout_val = self.safe_get_int(self.timeout_var, 600)
interface_format = self.loaded_config["llm_configs"][self.architecture_llm_var.get()]["interface_format"]
api_key = self.loaded_config["llm_configs"][self.architecture_llm_var.get()]["api_key"]
base_url = self.loaded_config["llm_configs"][self.architecture_llm_var.get()]["base_url"]
model_name = self.loaded_config["llm_configs"][self.architecture_llm_var.get()]["model_name"]
temperature = self.loaded_config["llm_configs"][self.architecture_llm_var.get()]["temperature"]
max_tokens = self.loaded_config["llm_configs"][self.architecture_llm_var.get()]["max_tokens"]
timeout_val = self.loaded_config["llm_configs"][self.architecture_llm_var.get()]["timeout"]
topic = self.topic_text.get("0.0", "end").strip() topic = self.topic_text.get("0.0", "end").strip()
genre = self.genre_var.get().strip() genre = self.genre_var.get().strip()
@@ -82,14 +92,24 @@ def generate_chapter_blueprint_ui(self):
return return
self.disable_button_safe(self.btn_generate_directory) self.disable_button_safe(self.btn_generate_directory)
try: try:
interface_format = self.interface_format_var.get().strip() # interface_format = self.interface_format_var.get().strip()
api_key = self.api_key_var.get().strip() # api_key = self.api_key_var.get().strip()
base_url = self.base_url_var.get().strip() # base_url = self.base_url_var.get().strip()
model_name = self.model_name_var.get().strip() # model_name = self.model_name_var.get().strip()
number_of_chapters = self.safe_get_int(self.num_chapters_var, 10) number_of_chapters = self.safe_get_int(self.num_chapters_var, 10)
temperature = self.temperature_var.get() # temperature = self.temperature_var.get()
max_tokens = self.max_tokens_var.get() # max_tokens = self.max_tokens_var.get()
timeout_val = self.safe_get_int(self.timeout_var, 600) # timeout_val = self.safe_get_int(self.timeout_var, 600)
interface_format = self.loaded_config["llm_configs"][self.chapter_outline_llm_var.get()]["interface_format"]
api_key = self.loaded_config["llm_configs"][self.chapter_outline_llm_var.get()]["api_key"]
base_url = self.loaded_config["llm_configs"][self.chapter_outline_llm_var.get()]["base_url"]
model_name = self.loaded_config["llm_configs"][self.chapter_outline_llm_var.get()]["model_name"]
temperature = self.loaded_config["llm_configs"][self.chapter_outline_llm_var.get()]["temperature"]
max_tokens = self.loaded_config["llm_configs"][self.chapter_outline_llm_var.get()]["max_tokens"]
timeout_val = self.loaded_config["llm_configs"][self.chapter_outline_llm_var.get()]["timeout"]
user_guidance = self.user_guide_text.get("0.0", "end").strip() # 新增获取用户指导 user_guidance = self.user_guide_text.get("0.0", "end").strip() # 新增获取用户指导
self.safe_log("开始生成章节蓝图...") self.safe_log("开始生成章节蓝图...")
@@ -121,13 +141,22 @@ def generate_chapter_draft_ui(self):
def task(): def task():
self.disable_button_safe(self.btn_generate_chapter) self.disable_button_safe(self.btn_generate_chapter)
try: try:
interface_format = self.interface_format_var.get().strip() # interface_format = self.interface_format_var.get().strip()
api_key = self.api_key_var.get().strip() # api_key = self.api_key_var.get().strip()
base_url = self.base_url_var.get().strip() # base_url = self.base_url_var.get().strip()
model_name = self.model_name_var.get().strip() # model_name = self.model_name_var.get().strip()
temperature = self.temperature_var.get() # temperature = self.temperature_var.get()
max_tokens = self.max_tokens_var.get() # max_tokens = self.max_tokens_var.get()
timeout_val = self.safe_get_int(self.timeout_var, 600) # timeout_val = self.safe_get_int(self.timeout_var, 600)
interface_format = self.loaded_config["llm_configs"][self.prompt_draft_llm_var.get()]["interface_format"]
api_key = self.loaded_config["llm_configs"][self.prompt_draft_llm_var.get()]["api_key"]
base_url = self.loaded_config["llm_configs"][self.prompt_draft_llm_var.get()]["base_url"]
model_name = self.loaded_config["llm_configs"][self.prompt_draft_llm_var.get()]["model_name"]
temperature = self.loaded_config["llm_configs"][self.prompt_draft_llm_var.get()]["temperature"]
max_tokens = self.loaded_config["llm_configs"][self.prompt_draft_llm_var.get()]["max_tokens"]
timeout_val = self.loaded_config["llm_configs"][self.prompt_draft_llm_var.get()]["timeout"]
chap_num = self.safe_get_int(self.chapter_num_var, 1) chap_num = self.safe_get_int(self.chapter_num_var, 1)
word_number = self.safe_get_int(self.word_number_var, 3000) word_number = self.safe_get_int(self.word_number_var, 3000)
@@ -312,13 +341,22 @@ def finalize_chapter_ui(self):
self.disable_button_safe(self.btn_finalize_chapter) self.disable_button_safe(self.btn_finalize_chapter)
try: try:
interface_format = self.interface_format_var.get().strip() # interface_format = self.interface_format_var.get().strip()
api_key = self.api_key_var.get().strip() # api_key = self.api_key_var.get().strip()
base_url = self.base_url_var.get().strip() # base_url = self.base_url_var.get().strip()
model_name = self.model_name_var.get().strip() # model_name = self.model_name_var.get().strip()
temperature = self.temperature_var.get() # temperature = self.temperature_var.get()
max_tokens = self.max_tokens_var.get() # max_tokens = self.max_tokens_var.get()
timeout_val = self.safe_get_int(self.timeout_var, 600) # timeout_val = self.safe_get_int(self.timeout_var, 600)
interface_format = self.loaded_config["llm_configs"][self.final_chapter_llm_var.get()]["interface_format"]
api_key = self.loaded_config["llm_configs"][self.final_chapter_llm_var.get()]["api_key"]
base_url = self.loaded_config["llm_configs"][self.final_chapter_llm_var.get()]["base_url"]
model_name = self.loaded_config["llm_configs"][self.final_chapter_llm_var.get()]["model_name"]
temperature = self.loaded_config["llm_configs"][self.final_chapter_llm_var.get()]["temperature"]
max_tokens = self.loaded_config["llm_configs"][self.final_chapter_llm_var.get()]["max_tokens"]
timeout_val = self.loaded_config["llm_configs"][self.final_chapter_llm_var.get()]["timeout"]
embedding_api_key = self.embedding_api_key_var.get().strip() embedding_api_key = self.embedding_api_key_var.get().strip()
embedding_url = self.embedding_url_var.get().strip() embedding_url = self.embedding_url_var.get().strip()
@@ -392,13 +430,22 @@ def do_consistency_check(self):
def task(): def task():
self.disable_button_safe(self.btn_check_consistency) self.disable_button_safe(self.btn_check_consistency)
try: try:
api_key = self.api_key_var.get().strip() # api_key = self.api_key_var.get().strip()
base_url = self.base_url_var.get().strip() # base_url = self.base_url_var.get().strip()
model_name = self.model_name_var.get().strip() # model_name = self.model_name_var.get().strip()
temperature = self.temperature_var.get() # temperature = self.temperature_var.get()
interface_format = self.interface_format_var.get() # interface_format = self.interface_format_var.get()
max_tokens = self.max_tokens_var.get() # max_tokens = self.max_tokens_var.get()
timeout = self.timeout_var.get() # timeout = self.timeout_var.get()
interface_format = self.loaded_config["llm_configs"][self.consistency_review_llm_var.get()]["interface_format"]
api_key = self.loaded_config["llm_configs"][self.consistency_review_llm_var.get()]["api_key"]
base_url = self.loaded_config["llm_configs"][self.consistency_review_llm_var.get()]["base_url"]
model_name = self.loaded_config["llm_configs"][self.consistency_review_llm_var.get()]["model_name"]
temperature = self.loaded_config["llm_configs"][self.consistency_review_llm_var.get()]["temperature"]
max_tokens = self.loaded_config["llm_configs"][self.consistency_review_llm_var.get()]["max_tokens"]
timeout = self.loaded_config["llm_configs"][self.consistency_review_llm_var.get()]["timeout"]
chap_num = self.safe_get_int(self.chapter_num_var, 1) chap_num = self.safe_get_int(self.chapter_num_var, 1)
chap_file = os.path.join(filepath, "chapters", f"chapter_{chap_num}.txt") chap_file = os.path.join(filepath, "chapters", f"chapter_{chap_num}.txt")
+43 -17
View File
@@ -53,23 +53,27 @@ class NovelGeneratorGUI:
self.loaded_config = load_config(self.config_file) self.loaded_config = load_config(self.config_file)
if self.loaded_config: if self.loaded_config:
last_llm = self.loaded_config.get("last_interface_format", "OpenAI") last_llm = next(iter(self.loaded_config["llm_configs"].values())).get("interface_format", "OpenAI")
last_embedding = self.loaded_config.get("last_embedding_interface_format", "OpenAI") last_embedding = self.loaded_config.get("last_embedding_interface_format", "OpenAI")
else: else:
last_llm = "OpenAI" last_llm = "OpenAI"
last_embedding = "OpenAI" last_embedding = "OpenAI"
if self.loaded_config and "llm_configs" in self.loaded_config and last_llm in self.loaded_config["llm_configs"]: # if self.loaded_config and "llm_configs" in self.loaded_config and last_llm in self.loaded_config["llm_configs"]:
llm_conf = self.loaded_config["llm_configs"][last_llm] # llm_conf = next(iter(self.loaded_config["llm_configs"]))
else: # else:
llm_conf = { # llm_conf = {
"api_key": "", # "api_key": "",
"base_url": "https://api.openai.com/v1", # "base_url": "https://api.openai.com/v1",
"model_name": "gpt-4o-mini", # "model_name": "gpt-4o-mini",
"temperature": 0.7, # "temperature": 0.7,
"max_tokens": 8192, # "max_tokens": 8192,
"timeout": 600 # "timeout": 600
} # }
llm_conf = next(iter(self.loaded_config["llm_configs"].values()))
choose_configs = self.loaded_config.get("choose_configs", {})
if self.loaded_config and "embedding_configs" in self.loaded_config and last_embedding in self.loaded_config["embedding_configs"]: if self.loaded_config and "embedding_configs" in self.loaded_config and last_embedding in self.loaded_config["embedding_configs"]:
emb_conf = self.loaded_config["embedding_configs"][last_embedding] emb_conf = self.loaded_config["embedding_configs"][last_embedding]
@@ -82,17 +86,16 @@ class NovelGeneratorGUI:
} }
# -- LLM通用参数 -- # -- LLM通用参数 --
# self.llm_conf_name = next(iter(self.loaded_config["llm_configs"]))
self.api_key_var = ctk.StringVar(value=llm_conf.get("api_key", "")) self.api_key_var = ctk.StringVar(value=llm_conf.get("api_key", ""))
self.base_url_var = ctk.StringVar(value=llm_conf.get("base_url", "https://api.openai.com/v1")) self.base_url_var = ctk.StringVar(value=llm_conf.get("base_url", "https://api.openai.com/v1"))
self.interface_format_var = ctk.StringVar(value=last_llm) self.interface_format_var = ctk.StringVar(value=llm_conf.get("interface_format", "OpenAI"))
self.model_name_var = ctk.StringVar(value=llm_conf.get("model_name", "gpt-4o-mini")) self.model_name_var = ctk.StringVar(value=llm_conf.get("model_name", "gpt-4o-mini"))
self.temperature_var = ctk.DoubleVar(value=llm_conf.get("temperature", 0.7)) self.temperature_var = ctk.DoubleVar(value=llm_conf.get("temperature", 0.7))
self.max_tokens_var = ctk.IntVar(value=llm_conf.get("max_tokens", 8192)) self.max_tokens_var = ctk.IntVar(value=llm_conf.get("max_tokens", 8192))
self.timeout_var = ctk.IntVar(value=llm_conf.get("timeout", 600)) self.timeout_var = ctk.IntVar(value=llm_conf.get("timeout", 600))
self.core_seed_llm_var = ctk.StringVar(value="DeepSeek") self.interface_config_var = ctk.StringVar(value=next(iter(self.loaded_config["llm_configs"])))
self.role_dynamics_llm_var = ctk.StringVar(value="DeepSeek")
self.world_building_llm_var = ctk.StringVar(value="DeepSeek")
self.three_scene_llm_var = ctk.StringVar(value="DeepSeek")
# -- Embedding相关 -- # -- Embedding相关 --
@@ -102,6 +105,29 @@ class NovelGeneratorGUI:
self.embedding_model_name_var = ctk.StringVar(value=emb_conf.get("model_name", "text-embedding-ada-002")) self.embedding_model_name_var = ctk.StringVar(value=emb_conf.get("model_name", "text-embedding-ada-002"))
self.embedding_retrieval_k_var = ctk.StringVar(value=str(emb_conf.get("retrieval_k", 4))) self.embedding_retrieval_k_var = ctk.StringVar(value=str(emb_conf.get("retrieval_k", 4)))
# -- 生成配置相关 --
# self.core_seed_llm_var = ctk.StringVar(value=choose_configs.get("core_seed_llm", "DeepSeek"))
# self.role_dynamics_llm_var = ctk.StringVar(value=choose_configs.get("role_dynamics_llm", "DeepSeek"))
# self.world_building_llm_var = ctk.StringVar(value=choose_configs.get("world_building_llm", "DeepSeek"))
# self.three_scene_llm_var = ctk.StringVar(value=choose_configs.get("three_scene_llm", "DeepSeek"))
# self.chapter_outline_llm_var = ctk.StringVar(value=choose_configs.get("chapter_outline_llm", "DeepSeek"))
# self.summary_llm_var = ctk.StringVar(value=choose_configs.get("summary_llm", "DeepSeek"))
# self.character_state_llm_var = ctk.StringVar(value=choose_configs.get("character_state_llm", "DeepSeek"))
# self.chapter_content_llm_var = ctk.StringVar(value=choose_configs.get("chapter_content_llm", "DeepSeek"))
# self.prompt_draft_llm_var = ctk.StringVar(value=choose_configs.get("prompt_draft_llm", "DeepSeek"))
# self.analyze_character_llm_var = ctk.StringVar(value=choose_configs.get("analyze_character_llm", "DeepSeek"))
self.architecture_llm_var = ctk.StringVar(value=choose_configs.get("architecture_llm", "DeepSeek"))
self.chapter_outline_llm_var = ctk.StringVar(value=choose_configs.get("chapter_outline_llm", "DeepSeek"))
self.final_chapter_llm_var = ctk.StringVar(value=choose_configs.get("final_chapter_llm", "DeepSeek"))
self.consistency_review_llm_var = ctk.StringVar(value=choose_configs.get("consistency_review_llm", "DeepSeek"))
self.prompt_draft_llm_var = ctk.StringVar(value=choose_configs.get("prompt_draft_llm", "DeepSeek"))
# -- 小说参数相关 -- # -- 小说参数相关 --
if self.loaded_config and "other_params" in self.loaded_config: if self.loaded_config and "other_params" in self.loaded_config:
op = self.loaded_config["other_params"] op = self.loaded_config["other_params"]