chore: opencode冗余清理 + LLM任务级模型选择 + systemd服务化

- 删除 opencode_search.py / mcp_search_server.py 及所有 MCP 引用
- 移除搜索缓存定时任务(scheduled_refresh_search_cache)
- 清理前后端所有 opencode/MCP 代码和注释
- LLM 提供商量换:opencode-go→nvidia(默认)+sensenova(合规审查)
- llm_configs 新增 is_default 字段,API 层互斥逻辑
- 所有定时任务支持独立 LLM 模型选择(LLM_TASK_PROVIDER env)
- compliance_optimizer.py 修复:import os / 解硬编码 / 关键词过滤
- Scheduler 日志修复:始终 INSERT,避免僵尸 running 行
- Systemd 服务化:Restart=always / 单 worker / Type=exec
- 搜索提供商:替换 opencode→360/搜狗/微信(免 Key)
- 更新 AGENTS.md / PROGRESS.md
This commit is contained in:
Yuzhiran Dev
2026-06-02 15:38:16 +08:00
parent abbf1468bc
commit 499c511140
25 changed files with 451 additions and 678 deletions
+24 -44
View File
@@ -19,8 +19,25 @@ from .collector import run_collector_blocking
logger = logging.getLogger(__name__)
def _set_task_llm_provider(module_id: str):
"""从 TaskConfig 读取 llm_provider 并设为环境变量,供子进程和 call_llm 读取"""
try:
from ..database import SessionLocal
from ..models import TaskConfig
db = SessionLocal()
cfg = db.query(TaskConfig).filter(TaskConfig.module_id == module_id).first()
db.close()
if cfg and cfg.params:
provider = cfg.params.get("llm_provider")
if provider:
os.environ["LLM_TASK_PROVIDER"] = provider
logger.debug("[%s] LLM provider set to %s", module_id, provider)
return
except Exception:
pass
os.environ.pop("LLM_TASK_PROVIDER", None)
MODULES = {
"scheduled_refresh_search_cache": {"name": "🔍 搜索缓存", "cron": "01:00"},
"scheduled_fetch_trends": {"name": "🔥 热点趋势", "cron": "01:10"},
"scheduled_collect": {"name": "📡 内容采集", "cron": "01:30"},
"scheduled_generate": {"name": "🤖 内容创作", "cron": "02:00"},
@@ -32,7 +49,6 @@ MODULES = {
}
LOG_FILE_MAP = {
"scheduled_refresh_search_cache": "opencode_search",
"scheduled_fetch_trends": "trends",
"scheduled_collect": "collector",
"scheduled_generate": "creator",
@@ -149,7 +165,6 @@ class TaskScheduler:
db.close()
MODULE_JOBS = [
("scheduled_refresh_search_cache", self._run_refresh_search_cache, "搜索缓存"),
("scheduled_fetch_trends", self._run_fetch_trends, "热点趋势"),
("scheduled_collect", self._run_collect, "内容采集"),
("scheduled_generate", self._run_generate, "内容创作"),
@@ -200,6 +215,7 @@ class TaskScheduler:
def _run_fetch_trends(self):
"""定时刷新热点趋势(百度/微博/知乎实时热搜 + LLM补充)"""
_set_task_llm_provider("scheduled_fetch_trends")
started = datetime.now(timezone.utc)
log_id = _log_task("scheduled_fetch_trends", "running", started_at=started)
try:
@@ -229,48 +245,8 @@ class TaskScheduler:
started_at=started, finished_at=datetime.now(timezone.utc))
logger.exception("[Scheduled] Trends refresh error: %s", e)
def _run_refresh_search_cache(self):
"""定时刷新搜索缓存(通过 opencode webfetch"""
started = datetime.now(timezone.utc)
log_id = _log_task("scheduled_refresh_search_cache", "running", started_at=started)
try:
logger.info("[Scheduled] Refreshing search cache via opencode...")
import subprocess
result = subprocess.run(
[sys.executable, str(PROJECT_ROOT / "scripts" / "opencode_search.py"), "--refresh-cache"],
capture_output=True, text=True, timeout=600
)
for line in result.stdout.strip().split("\n"):
if line.strip():
logger.info("[SearchCache] %s", line.strip())
for line in result.stderr.strip().split("\n"):
if line.strip():
logger.warning("[SearchCache] %s", line.strip())
if result.returncode == 0:
_log_task("scheduled_refresh_search_cache", "success", log_id=log_id,
message="搜索缓存刷新成功",
result_data={"output_lines": len(result.stdout.splitlines())},
started_at=started, finished_at=datetime.now(timezone.utc))
logger.info("[Scheduled] Search cache refreshed")
else:
_log_task("scheduled_refresh_search_cache", "failed", log_id=log_id,
message="部分失败",
error_trace=result.stderr[-500:],
started_at=started, finished_at=datetime.now(timezone.utc))
logger.warning("[Scheduled] Search cache refresh may have partial failures")
except subprocess.TimeoutExpired:
_log_task("scheduled_refresh_search_cache", "failed", log_id=log_id,
message="超时",
started_at=started, finished_at=datetime.now(timezone.utc))
logger.warning("[Scheduled] Search cache refresh timed out")
except Exception as e:
_log_task("scheduled_refresh_search_cache", "failed", log_id=log_id,
message=str(e),
error_trace=traceback.format_exc(),
started_at=started, finished_at=datetime.now(timezone.utc))
logger.exception("[Scheduled] Search cache refresh error: %s", e)
def _run_generate(self):
_set_task_llm_provider("scheduled_generate")
started = datetime.now(timezone.utc)
log_id = _log_task("scheduled_generate", "running", started_at=started)
try:
@@ -296,6 +272,7 @@ class TaskScheduler:
logger.exception("[Scheduled] Generation pipeline failed: %s", e)
def _run_optimize(self):
_set_task_llm_provider("scheduled_optimize")
started = datetime.now(timezone.utc)
log_id = _log_task("scheduled_optimize", "running", started_at=started)
try:
@@ -314,6 +291,7 @@ class TaskScheduler:
logger.exception("[Scheduled] Review failed: %s", e)
def _run_collect(self):
_set_task_llm_provider("scheduled_collect")
started = datetime.now(timezone.utc)
log_id = _log_task("scheduled_collect", "running", started_at=started)
try:
@@ -334,6 +312,7 @@ class TaskScheduler:
def _run_optimize_sources(self, triggered_by="scheduler"):
"""AI自动优化采集类别与信息源:对比市场热点和当前配置,给出调整建议"""
_set_task_llm_provider("scheduled_optimize_sources")
started = datetime.now(timezone.utc)
log_id = _log_task("scheduled_optimize_sources", "running", started_at=started, triggered_by=triggered_by)
try:
@@ -397,6 +376,7 @@ class TaskScheduler:
def _run_metrics_sync(self, triggered_by="scheduler"):
"""定时从各平台公开API获取发布文章的效果数据(当前仅支持知乎)"""
_set_task_llm_provider("scheduled_metrics_sync")
started = datetime.now(timezone.utc)
log_id = _log_task("scheduled_metrics_sync", "running", started_at=started, triggered_by=triggered_by)
try: