feat: LLM 解耦 bot、RSS 外置与内容过滤

daily 自建 Cursor bridge;DAILY_LLM_PROVIDER 控制后端;config/feeds.yaml 与 sensitive_words 可配置。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-03 15:24:58 +08:00
parent ce04d5a342
commit 5742dc47ed
19 changed files with 771 additions and 239 deletions

View File

@@ -0,0 +1,40 @@
from __future__ import annotations
import pytest
def test_load_categories_from_yaml():
from daily.news.feeds_loader import load_categories
categories = load_categories("intl")
assert categories
assert any(cat.id == "official" for cat in categories)
assert categories[0].feeds
def test_load_categories_fallback_when_yaml_missing(monkeypatch, tmp_path):
import daily.config as config
import daily.news.feeds_loader as loader
missing = tmp_path / "missing" / "feeds.yaml"
monkeypatch.setattr(loader, "_FEEDS_FILE", missing)
loader._yaml_payload.cache_clear()
categories = loader.load_categories("intl")
assert categories
assert any(cat.id == "official" for cat in categories)
def test_content_filter_removes_matching_items(monkeypatch):
import daily.news.content_filter as cf
monkeypatch.setenv("DAILY_CONTENT_FILTER", "1")
cf.load_sensitive_words.cache_clear()
items = [
{"title": "正常 AI 新闻", "summary": "OpenAI 发布新模型"},
{"title": "违规推广", "summary": "六合彩内幕消息"},
]
kept, removed = cf.filter_news_items(items)
assert removed == 1
assert len(kept) == 1
assert kept[0]["title"].startswith("正常")

33
tests/test_llm_client.py Normal file
View File

@@ -0,0 +1,33 @@
from __future__ import annotations
import pytest
def test_resolve_llm_backend_prefers_cursor_in_agent_mode(monkeypatch):
import daily.llm_client as llm
monkeypatch.setenv("DAILY_REPORT_MODE", "agent")
monkeypatch.setenv("CURSOR_API_KEY", "cursor_test")
monkeypatch.setenv("DAILY_LLM_API_KEY", "openai_test")
monkeypatch.delenv("DAILY_LLM_PROVIDER", raising=False)
assert llm.resolve_llm_backend() == "cursor"
def test_resolve_llm_backend_openai_override(monkeypatch):
import daily.llm_client as llm
monkeypatch.setenv("DAILY_REPORT_MODE", "agent")
monkeypatch.setenv("DAILY_LLM_PROVIDER", "openai")
monkeypatch.setenv("CURSOR_API_KEY", "cursor_test")
monkeypatch.setenv("DAILY_LLM_API_KEY", "openai_test")
assert llm.resolve_llm_backend() == "openai"
def test_resolve_llm_backend_classic_defaults_openai(monkeypatch):
import daily.llm_client as llm
monkeypatch.setenv("DAILY_REPORT_MODE", "classic")
monkeypatch.setenv("CURSOR_API_KEY", "cursor_test")
monkeypatch.setenv("DAILY_LLM_API_KEY", "openai_test")
monkeypatch.delenv("DAILY_LLM_PROVIDER", raising=False)
assert llm.resolve_llm_backend() == "openai"