xhs_factory/config_manager.py
zhoujie 156a18ae0c feat(analytics): 新增智能学习引擎与笔记表现分析模块
- 新增 `analytics_service.py` 模块,实现笔记数据采集、权重计算与智能分析功能
- 支持定时采集已发布笔记的互动数据(点赞、评论、收藏),并计算主题、风格、标签等多维度权重
- 提供加权随机选题功能,根据历史表现优先生成高互动潜力内容
- 集成 LLM 深度分析,生成内容策略建议与优化报告
- 新增「智能学习」UI 标签页,支持数据采集、权重计算、AI 分析与定时自动学习

♻️ refactor(llm): 重构 LLM 服务以支持多模型智能适配与加权文案生成

- 扩展 `llm_service.py`,新增 `get_sd_prompt_guide()` 方法,根据当前 SD 模型动态生成绘图提示词指南
- 新增 `PROMPT_PERFORMANCE_ANALYSIS` 与 `PROMPT_WEIGHTED_COPYWRITING` 提示词模板,支持笔记表现分析与加权文案生成
- 重构 `generate_copy()`、`generate_copy_with_reference()` 方法,支持 `sd_model_name` 与 `persona` 参数,实现多模型适配与人设融合
- 新增 `analyze_note_performance()` 与 `generate_weighted_copy()` 方法,实现 AI 深度分析与智能加权创作

♻️ refactor(sd): 重构 SD 服务以支持多模型配置系统与智能参数适配

- 重构 `sd_service.py`,引入 `SD_MODEL_PROFILES` 配置体系,支持 `majicmixRealistic`、`Realistic Vision`、`Juggernaut XL` 三款模型
- 新增 `detect_model_profile()`、`get_model_profile()`、`get_model_profile_info()` 方法,实现模型自动识别与档案信息展示
- 重构 `txt2img()` 与 `img2img()` 方法,自动根据当前模型应用最优参数、提示词前缀/后缀与反向提示词
- 更新 `get_sd_preset()` 方法,支持模型专属预设参数加载

🎨 style(config): 更新默认配置与人设池

- 更新 `config.json` 与 `config_manager.py`,将默认模型改为 `gemini-3-flash-preview`,默认人设改为「身材管理健身美女」
- 新增 `use_smart_weights` 配置项,控制是否启用智能加权发布
- 扩展 `PERSONA_POOL_MAP`,新增「身材管理健身美女」人设及其对应主题与关键词库

🔧 chore(main): 集成智能学习引擎并扩展自动发布链路

- 在 `main.py` 中实例化 `AnalyticsService`,并集成至各功能模块
- 扩展 `generate_copy()`、`generate_from_hotspot()`、`auto_publish_once()` 等方法,支持 `sd_model_name`、`persona`、`quality_mode_val` 参数传递
- 实现智能加权发布逻辑:当启用权重且数据可用时,自动选择高权重主题、风格与标签,并使用加权文案模板
- 新增「智能学习」标签页相关 UI 组件与事件处理函数,包括数据采集、权重计算、AI 分析、定时学习与加权主题预览
- 更新 SD 模型选择事件,实时显示模型档案信息卡
- 扩展自动调度器,支持智能权重、人设与画质模式的参数传递

📝 docs(changelog): 更新版本日志记录新功能与改进

- 在 `CHANGELOG.md` 中新增 `[2.1.0]` 与 `[2.2.0]` 版本记录
- 详细描述「智能学习引擎」与「多 SD 模型智能适配」两大核心功能
- 列出相关代码重构、配置更新与文件新增情况
2026-02-10 21:29:57 +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()