xhs_factory/config_manager.py
zhoujie 1ea8bfb554 feat(analytics): 增强 MCP 数据解析兼容性
- 优化用户资料和笔记详情的数据提取逻辑,优先从 `raw["raw"]["content"]` 获取内容,并回退到 `raw["content"]`
- 在笔记详情解析中,增加从 `result["text"]` 提取文本的备用路径
- 在用户动态流解析中,优先从 `f["id"]` 获取笔记 ID,并增加无 ID 条目的日志警告

 feat(persona): 扩展人设池并集成视觉风格配置

- 新增“赛博AI虚拟博主”和“性感福利主播”人设及其对应的主题与关键词
- 在 `sd_service.py` 中新增 `PERSONA_SD_PROFILES` 字典,为每个人设定义视觉增强词、风格后缀和 LLM 绘图指导
- 新增 `get_persona_sd_profile` 函数,根据人设文本匹配对应的视觉配置

♻️ refactor(llm): 重构 SD 绘图提示词生成以支持人设

- 修改 `LLMService.get_sd_prompt_guide` 函数签名,新增 `persona` 参数
- 在生成的绘图指南中,根据匹配到的人设追加特定的视觉风格指导文本
- 针对“赛博AI虚拟博主”人设,调整反 AI 检测提示,允许使用高质量词汇和专业光效
- 更新所有调用 `get_sd_prompt_guide` 的地方(如文案生成函数),传入 `persona` 参数

♻️ refactor(sd): 重构文生图服务以支持人设视觉增强

- 修改 `SDService.txt2img` 函数签名,新增 `persona` 参数
- 在生成最终提示词时,注入人设特定的增强词(`prompt_boost`)和风格词(`prompt_style`)
- 在生成最终负面提示词时,追加人设特定的额外负面词(`negative_extra`)
- 增加人设视觉增强已注入的日志信息

🔧 chore(config): 更新默认人设配置

- 将 `config_manager.py` 中的默认 `persona` 从“身材管理健身美女”更新为“性感福利主播”

🔧 chore(main): 更新 UI 函数签名以传递人设参数

- 更新 `generate_images` 函数签名,新增 `persona_text` 参数,并在内部解析为人设对象
- 更新 `auto_publish_once` 和 `generate_to_queue` 函数中调用 `sd_svc.txt2img` 的地方,传入 `persona` 参数
- 更新 Gradio 界面中 `btn_gen_img` 的点击事件,将 `persona` 输入传递给 `generate_images` 函数
2026-02-10 22:29:55 +08:00

163 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
配置管理模块
支持多配置项、默认值回退、自动保存
"""
import json
import os
import logging
logger = logging.getLogger(__name__)
CONFIG_FILE = "config.json"
OUTPUT_DIR = "xhs_workspace"
DEFAULT_CONFIG = {
"api_key": "",
"base_url": "https://api.openai.com/v1",
"sd_url": "http://127.0.0.1:7860",
"mcp_url": "http://localhost:18060/mcp",
"model": "gpt-3.5-turbo",
"persona": "性感福利主播,身材火辣衣着大胆,专注分享穿衣显身材和私房写真风穿搭",
"auto_reply_enabled": False,
"schedule_enabled": False,
"my_user_id": "",
"active_llm": "",
"llm_providers": [],
"use_smart_weights": True,
}
class ConfigManager:
"""配置管理器 - 单例模式"""
_instance = None
_config = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
if self._config is None:
self._config = self._load()
def _load(self) -> dict:
"""从文件加载配置,缺失项用默认值填充"""
config = DEFAULT_CONFIG.copy()
if os.path.exists(CONFIG_FILE):
try:
with open(CONFIG_FILE, "r", encoding="utf-8") as f:
saved = json.load(f)
config.update(saved)
except (json.JSONDecodeError, IOError) as e:
logger.warning("配置文件读取失败,使用默认值: %s", e)
return config
def save(self):
"""保存配置到文件"""
try:
with open(CONFIG_FILE, "w", encoding="utf-8") as f:
json.dump(self._config, f, indent=4, ensure_ascii=False)
except IOError as e:
logger.error("配置保存失败: %s", e)
def get(self, key: str, default=None):
"""获取配置项"""
return self._config.get(key, default)
def set(self, key: str, value):
"""设置配置项并自动保存"""
self._config[key] = value
self.save()
def update(self, data: dict):
"""批量更新配置"""
self._config.update(data)
self.save()
@property
def all(self) -> dict:
"""返回全部配置(副本)"""
return self._config.copy()
def ensure_workspace(self):
"""确保工作空间目录存在"""
os.makedirs(OUTPUT_DIR, exist_ok=True)
# ---------- 多 LLM 提供商管理 ----------
def get_llm_providers(self) -> list[dict]:
"""获取所有 LLM 提供商配置"""
providers = self._config.get("llm_providers", [])
# 兼容旧配置: 如果 providers 为空但有 api_key自动迁移
if not providers and self._config.get("api_key"):
default_provider = {
"name": "默认",
"api_key": self._config["api_key"],
"base_url": self._config.get("base_url", "https://api.openai.com/v1"),
}
providers = [default_provider]
self._config["llm_providers"] = providers
self._config["active_llm"] = "默认"
self.save()
return providers
def get_llm_provider_names(self) -> list[str]:
"""获取所有提供商名称列表"""
return [p["name"] for p in self.get_llm_providers()]
def get_active_llm(self) -> dict | None:
"""获取当前激活的 LLM 提供商配置"""
active_name = self._config.get("active_llm", "")
for p in self.get_llm_providers():
if p["name"] == active_name:
return p
# 没找到就返回第一个
providers = self.get_llm_providers()
return providers[0] if providers else None
def add_llm_provider(self, name: str, api_key: str, base_url: str) -> str:
"""添加一个 LLM 提供商,返回状态消息"""
name = name.strip()
if not name:
return "❌ 名称不能为空"
if not api_key.strip():
return "❌ API Key 不能为空"
providers = self.get_llm_providers()
for p in providers:
if p["name"] == name:
return f"❌ 名称「{name}」已存在,请换一个"
providers.append({
"name": name,
"api_key": api_key.strip(),
"base_url": (base_url or "https://api.openai.com/v1").strip().rstrip("/"),
})
self._config["llm_providers"] = providers
if not self._config.get("active_llm"):
self._config["active_llm"] = name
self.save()
return f"✅ 已添加「{name}"
def remove_llm_provider(self, name: str) -> str:
"""删除一个 LLM 提供商"""
providers = self.get_llm_providers()
new_providers = [p for p in providers if p["name"] != name]
if len(new_providers) == len(providers):
return f"⚠️ 未找到「{name}"
self._config["llm_providers"] = new_providers
if self._config.get("active_llm") == name:
self._config["active_llm"] = new_providers[0]["name"] if new_providers else ""
self.save()
return f"✅ 已删除「{name}"
def set_active_llm(self, name: str):
"""切换当前激活的 LLM 提供商"""
self._config["active_llm"] = name
# 同步到兼容字段
p = self.get_active_llm()
if p:
self._config["api_key"] = p["api_key"]
self._config["base_url"] = p["base_url"]
self.save()