UI更新、新增本地适配
This commit is contained in:
+2
-1
@@ -1,5 +1,6 @@
|
|||||||
# embedding_ollama.py
|
# embedding_ollama.py
|
||||||
import requests
|
import requests
|
||||||
|
import traceback
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
class OllamaEmbeddings:
|
class OllamaEmbeddings:
|
||||||
@@ -51,4 +52,4 @@ class OllamaEmbeddings:
|
|||||||
raise ValueError("No 'embedding' field in Ollama response.")
|
raise ValueError("No 'embedding' field in Ollama response.")
|
||||||
return result["embedding"]
|
return result["embedding"]
|
||||||
except requests.exceptions.RequestException as e:
|
except requests.exceptions.RequestException as e:
|
||||||
raise Exception(f"Ollama embeddings request error: {e}")
|
raise Exception(f"Ollama embeddings request error: {e}\n{traceback.format_exc()}")
|
||||||
|
|||||||
+5
-16
@@ -3,6 +3,7 @@
|
|||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
import traceback
|
||||||
from typing import Dict, List, Optional
|
from typing import Dict, List, Optional
|
||||||
from typing import TypedDict
|
from typing import TypedDict
|
||||||
|
|
||||||
@@ -59,25 +60,19 @@ def invoke_with_cleaning(model: ChatOpenAI, prompt: str) -> str:
|
|||||||
return cleaned_text.strip()
|
return cleaned_text.strip()
|
||||||
|
|
||||||
# ============ 判断接口格式相关 ============
|
# ============ 判断接口格式相关 ============
|
||||||
|
|
||||||
def is_using_ollama_api(interface_format: str, base_url: str) -> bool:
|
def is_using_ollama_api(interface_format: str, base_url: str) -> bool:
|
||||||
"""
|
"""
|
||||||
当 interface_format == "Ollama" 时返回 True
|
当 interface_format == "Ollama" 时返回 True
|
||||||
"""
|
"""
|
||||||
if interface_format.lower() == "ollama":
|
return interface_format.lower() == "ollama"
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def is_using_ml_studio_api(interface_format: str, base_url: str) -> bool:
|
def is_using_ml_studio_api(interface_format: str, base_url: str) -> bool:
|
||||||
"""
|
"""
|
||||||
如果用户在下拉里选择了 ML Studio
|
如果用户在下拉里选择了 ML Studio
|
||||||
"""
|
"""
|
||||||
if interface_format.lower() == "ml studio":
|
return interface_format.lower() == "ml studio"
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
# ============ 创建 Embeddings 对象 ============
|
# ============ 创建 Embeddings 对象 ============
|
||||||
|
|
||||||
def create_embeddings_object(
|
def create_embeddings_object(
|
||||||
api_key: str,
|
api_key: str,
|
||||||
base_url: str,
|
base_url: str,
|
||||||
@@ -106,7 +101,6 @@ def create_embeddings_object(
|
|||||||
return OpenAIEmbeddings(openai_api_key=api_key, openai_api_base=base_url)
|
return OpenAIEmbeddings(openai_api_key=api_key, openai_api_base=base_url)
|
||||||
|
|
||||||
# ============ 向量库相关 ============
|
# ============ 向量库相关 ============
|
||||||
|
|
||||||
VECTOR_STORE_DIR = os.path.join(os.getcwd(), "vectorstore")
|
VECTOR_STORE_DIR = os.path.join(os.getcwd(), "vectorstore")
|
||||||
if not os.path.exists(VECTOR_STORE_DIR):
|
if not os.path.exists(VECTOR_STORE_DIR):
|
||||||
os.makedirs(VECTOR_STORE_DIR)
|
os.makedirs(VECTOR_STORE_DIR)
|
||||||
@@ -125,8 +119,8 @@ def clear_vector_store():
|
|||||||
elif os.path.isdir(file_path):
|
elif os.path.isdir(file_path):
|
||||||
shutil.rmtree(file_path)
|
shutil.rmtree(file_path)
|
||||||
logging.info("Local vector store has been cleared.")
|
logging.info("Local vector store has been cleared.")
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logging.warning(f"Failed to clear vector store: {e}")
|
logging.warning(f"Failed to clear vector store:\n{traceback.format_exc()}")
|
||||||
else:
|
else:
|
||||||
logging.info("No vector store found to clear.")
|
logging.info("No vector store found to clear.")
|
||||||
|
|
||||||
@@ -253,7 +247,6 @@ def get_relevant_context_from_vector_store(
|
|||||||
return combined
|
return combined
|
||||||
|
|
||||||
# ============ 多步生成:设置 & 目录 ============
|
# ============ 多步生成:设置 & 目录 ============
|
||||||
|
|
||||||
class OverallState(TypedDict):
|
class OverallState(TypedDict):
|
||||||
topic: str
|
topic: str
|
||||||
genre: str
|
genre: str
|
||||||
@@ -383,7 +376,6 @@ def Novel_novel_directory_generate(
|
|||||||
logging.info("Novel settings and directory generated successfully.")
|
logging.info("Novel settings and directory generated successfully.")
|
||||||
|
|
||||||
# ============ 获取最近N章内容,生成短期摘要 ============
|
# ============ 获取最近N章内容,生成短期摘要 ============
|
||||||
|
|
||||||
def get_last_n_chapters_text(chapters_dir: str, current_chapter_num: int, n: int = 3) -> List[str]:
|
def get_last_n_chapters_text(chapters_dir: str, current_chapter_num: int, n: int = 3) -> List[str]:
|
||||||
"""
|
"""
|
||||||
从指定文件夹中,读取最近 n 章的内容(如果存在),并按从旧到新的顺序返回文本列表。
|
从指定文件夹中,读取最近 n 章的内容(如果存在),并按从旧到新的顺序返回文本列表。
|
||||||
@@ -436,7 +428,6 @@ def summarize_recent_chapters(
|
|||||||
return summary_text
|
return summary_text
|
||||||
|
|
||||||
# ============ 新增:剧情要点/未解决冲突 ============
|
# ============ 新增:剧情要点/未解决冲突 ============
|
||||||
|
|
||||||
PLOT_ARCS_PROMPT = """\
|
PLOT_ARCS_PROMPT = """\
|
||||||
下面是新生成的章节内容:
|
下面是新生成的章节内容:
|
||||||
{chapter_text}
|
{chapter_text}
|
||||||
@@ -474,7 +465,6 @@ def update_plot_arcs(
|
|||||||
return arcs_text
|
return arcs_text
|
||||||
|
|
||||||
# ============ 生成章节草稿 & 定稿 ============
|
# ============ 生成章节草稿 & 定稿 ============
|
||||||
|
|
||||||
def generate_chapter_draft(
|
def generate_chapter_draft(
|
||||||
novel_settings: str,
|
novel_settings: str,
|
||||||
global_summary: str,
|
global_summary: str,
|
||||||
@@ -707,7 +697,6 @@ def enrich_chapter_text(
|
|||||||
return enriched_text if enriched_text else chapter_text
|
return enriched_text if enriched_text else chapter_text
|
||||||
|
|
||||||
# ============ 导入外部知识文本 ============
|
# ============ 导入外部知识文本 ============
|
||||||
|
|
||||||
def import_knowledge_file(
|
def import_knowledge_file(
|
||||||
api_key: str,
|
api_key: str,
|
||||||
base_url: str,
|
base_url: str,
|
||||||
|
|||||||
@@ -95,6 +95,12 @@ class NovelGeneratorGUI:
|
|||||||
# 全局摘要 Tab
|
# 全局摘要 Tab
|
||||||
self.build_summary_tab()
|
self.build_summary_tab()
|
||||||
|
|
||||||
|
# ------------------ 统一异常处理方法 ------------------
|
||||||
|
def handle_exception(self, context: str):
|
||||||
|
full_message = f"{context}\n{traceback.format_exc()}"
|
||||||
|
logging.error(full_message)
|
||||||
|
self.safe_log(full_message)
|
||||||
|
|
||||||
# ------------------ 主功能 Tab ------------------
|
# ------------------ 主功能 Tab ------------------
|
||||||
def build_main_tab(self):
|
def build_main_tab(self):
|
||||||
self.main_tab.rowconfigure(0, weight=1)
|
self.main_tab.rowconfigure(0, weight=1)
|
||||||
@@ -617,9 +623,8 @@ class NovelGeneratorGUI:
|
|||||||
temperature=temperature
|
temperature=temperature
|
||||||
)
|
)
|
||||||
self.safe_log("✅ 小说设定和目录生成完成。查看 Novel_setting.txt 和 Novel_directory.txt。")
|
self.safe_log("✅ 小说设定和目录生成完成。查看 Novel_setting.txt 和 Novel_directory.txt。")
|
||||||
except Exception as e:
|
except Exception:
|
||||||
log_error(f"生成小说设定 & 目录时出错: {e}")
|
self.handle_exception("生成小说设定 & 目录时出错")
|
||||||
self.safe_log(f"❌ 生成小说设定 & 目录时出错: {e}")
|
|
||||||
finally:
|
finally:
|
||||||
self.enable_button_safe(self.btn_generate_full)
|
self.enable_button_safe(self.btn_generate_full)
|
||||||
|
|
||||||
@@ -695,9 +700,8 @@ class NovelGeneratorGUI:
|
|||||||
else:
|
else:
|
||||||
self.safe_log("⚠️ 本章草稿生成失败或无内容。")
|
self.safe_log("⚠️ 本章草稿生成失败或无内容。")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
log_error(f"生成章节草稿时出错: {e}")
|
self.handle_exception("生成章节草稿时出错")
|
||||||
self.safe_log(f"❌ 生成章节草稿时出错: {e}")
|
|
||||||
finally:
|
finally:
|
||||||
self.enable_button_safe(self.btn_generate_chapter)
|
self.enable_button_safe(self.btn_generate_chapter)
|
||||||
|
|
||||||
@@ -747,9 +751,8 @@ class NovelGeneratorGUI:
|
|||||||
final_text = read_file(chap_file)
|
final_text = read_file(chap_file)
|
||||||
self.master.after(0, lambda: self.show_chapter_in_textbox(final_text))
|
self.master.after(0, lambda: self.show_chapter_in_textbox(final_text))
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
log_error(f"定稿章节时出错: {e}")
|
self.handle_exception("定稿章节时出错")
|
||||||
self.safe_log(f"❌ 定稿章节时出错: {e}")
|
|
||||||
finally:
|
finally:
|
||||||
self.enable_button_safe(self.btn_finalize_chapter)
|
self.enable_button_safe(self.btn_finalize_chapter)
|
||||||
|
|
||||||
@@ -803,9 +806,8 @@ class NovelGeneratorGUI:
|
|||||||
self.safe_log("审校结果:")
|
self.safe_log("审校结果:")
|
||||||
self.safe_log(result)
|
self.safe_log(result)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
log_error(f"审校时出错: {e}")
|
self.handle_exception("审校时出错")
|
||||||
self.safe_log(f"❌ 审校时出错: {e}")
|
|
||||||
finally:
|
finally:
|
||||||
self.enable_button_safe(self.btn_check_consistency)
|
self.enable_button_safe(self.btn_check_consistency)
|
||||||
|
|
||||||
@@ -831,9 +833,8 @@ class NovelGeneratorGUI:
|
|||||||
embedding_base_url=self.embedding_url_var.get().strip()
|
embedding_base_url=self.embedding_url_var.get().strip()
|
||||||
)
|
)
|
||||||
self.safe_log("✅ 知识库文件导入完成。")
|
self.safe_log("✅ 知识库文件导入完成。")
|
||||||
except Exception as e:
|
except Exception:
|
||||||
log_error(f"导入知识库时出错: {e}")
|
self.handle_exception("导入知识库时出错")
|
||||||
self.safe_log(f"❌ 导入知识库时出错: {e}")
|
|
||||||
finally:
|
finally:
|
||||||
self.enable_button_safe(self.btn_import_knowledge)
|
self.enable_button_safe(self.btn_import_knowledge)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user