- 新增 `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 模型智能适配」两大核心功能 - 列出相关代码重构、配置更新与文件新增情况
163 lines
5.4 KiB
Python
163 lines
5.4 KiB
Python
"""
|
||
配置管理模块
|
||
支持多配置项、默认值回退、自动保存
|
||
"""
|
||
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()
|