9.4 KiB
9.4 KiB
Content Repository(候选查询与数据访问层)|Tasks
对应计划:
spec_kit/Personalized Reco/modules/content-repository/plan.md本清单已对齐确认点:
text按客户端 locale 输出(请求携带)- 不允许语言回退(缺少目标语言文本的内容直接过滤,不返回)
- 需要做 MySQL(dev)DB 集成测试
- 代码与其他推荐子模块放同一目录:
server/app/features/personalized_reco/fetch_contents_by_ids返回顺序必须与输入content_ids一致执行说明:
- 本次已在 dev MySQL 环境跑通
pytest,且测试不做破坏性操作:
- 不清表(不执行 DELETE/TRUNCATE)
- 每个用例使用事务并在结束时 rollback
- 默认不执行 Alembic 迁移(如需自动迁移需显式设置
ALLOW_SCHEMA_MIGRATION=1)
0. 任务标记规则
- 用勾选框标记执行状态:
[ ]未开始[x]已完成
- 每个任务都要求可独立验收(有明确产出/可运行的检查方式)。
1. 文档对齐(先把口径写死,避免实现漂移)
-
1.1 更新
modules/content-repository/spec.md,加入 locale 相关契约- 变更点:
- 在输入中新增
locale(例如en/en-US/tc/zh-TW/zh-HK),声明由客户端请求携带并透传至 repository - 在输出字段
text补充语言选择规则:locale=en*:必须从text_en产出;若缺失则该内容不可返回(过滤)locale=zh-TW|zh-HK:必须从text_tc产出;若缺失则该内容不可返回(过滤)- 说明:当前仅支持 EN/TC(不做繁转简);若未来新增
zh-CN再单独设计转换策略
- 明确:
fetch_contents_by_ids返回顺序与入参一致
- 在输入中新增
- 验收:
spec.md中输入/输出与接口签名不再缺少 locale,且text的来源与“不允许语言回退”规则清晰。
- 变更点:
-
1.2 更新
modules/content-repository/plan.md,补齐 locale 选文与“繁转简”技术方案- 变更点:
- 在“读取层规范化(Normalization)”新增
text规范化章节:语言选择 + 简中转换 - 说明:当前仅支持 EN/TC(不做繁转简);若未来新增
zh-CN再单独设计转换策略 - 明确策略:不允许语言回退;缺少目标语言文本的内容视为不可用,必须在候选/按 ID 获取时过滤掉
- 在“读取层规范化(Normalization)”新增
- 验收:
plan.md有明确依赖与落地策略(含依赖包/转换时机/兜底策略),不留二义性。
- 变更点:
2. 目录与骨架(与推荐子模块同级)
-
2.1 新建目录
server/app/features/personalized_reco/content_repository/- 包含:
__init__.pytypes.py(DTO:ContentProfile、locale 类型等)interface.py(ContentRepositoryProtocol/ABC)normalization.py(解析与兜底:suitability、risk_flags、power、text)sqlalchemy_repo.py(SQLAlchemy 实现)
- 验收:可被
app.features.personalized_reco.content_repository.*正常 import。
- 包含:
-
2.2 依赖补齐(如采用 OpenCC)
- 说明:当前仅支持 EN/TC,此任务可跳过;若未来新增
zh-CN并需要繁转简,再引入 OpenCC。
- 说明:当前仅支持 EN/TC,此任务可跳过;若未来新增
3. 数据结构与接口(面向引擎注入)
-
3.1 定义
ContentProfileDTO(稳定字段契约)- 字段:对齐
modules/content-repository/spec.md,并补齐review_confidence输出兜底为0.7 - 注意:
text为最终对外输出文本(已按 locale 选择/转换) - 验收:DTO 字段齐全;类型清晰;不暴露 ORM 模型。
- 字段:对齐
-
3.2 定义
ContentRepository接口(含 locale)- 建议签名(示例,最终以 spec 为准):
fetch_candidates(scene, user_profile, fallback_level, limit, locale, exclude_content_ids=None) -> List[ContentProfile]fetch_contents_by_ids(content_ids, locale) -> List[ContentProfile]
- 验收:推荐引擎可以仅依赖该接口,不依赖 SQLAlchemy/FastAPI Depends。
- 建议签名(示例,最终以 spec 为准):
4. 规范化工具函数(可单测)
-
4.1 suitability 解析与兜底
- 规则:
- 缺失/NULL/解析失败 → 全 0.5(固定 key 集合)
- 部分 key 缺失 → 对缺失 key 补 0.5
- 非法值 → 兜底 0.5
- 验收:单元测试覆盖缺失/部分缺失/非法值。
- 规则:
-
4.2 risk_flags 映射、去重与排序
- 规则:旧→新映射对齐 spec;去重;稳定排序(例如字典序)
- 验收:单元测试断言输出不含旧命名且顺序稳定。
-
4.3 personalization_power 映射
- 规则:
0/5/10 -> 0.0/0.5/1.0;非法值 -> 0.0 - 验收:单元测试覆盖正常/异常值。
- 规则:
-
4.4 text 选择与简中转换
- 输入:
text_en、text_tc、locale - 规则:按 1.1/1.2 写死的策略执行(当前仅支持 EN/TC,不做繁转简)
- 验收:单元测试覆盖:
en取英文zh-TW取繁中- 缺失目标语言文本时的行为:返回“不可用”(例如返回空字符串 + 上层过滤,或直接返回
None由调用方过滤;实现中必须一致)
- 输入:
5. SQLAlchemy 实现(无 N+1、顺序可控)
说明:当前 DB 模型为:
contents:text_en/text_tc/author_id/template_idcontent_profiles:JSON、power、stage、is_safe_pool、review_confidencecontent_risk_flags:关联表(1:N)
-
5.1 实现
fetch_contents_by_ids(content_ids, locale)- 实现要点:
- 输入去重,但输出必须按原始输入顺序重排(并忽略不存在的 id 或明确行为:不存在则跳过)
- 两段式查询避免行膨胀:
contentsJOINcontent_profiles批量取主体与画像content_risk_flags批量取 flags,再按content_id聚合
- 组装 DTO 时执行 normalization(含 text locale 规则)
- 验收:
- 返回顺序与输入一致
- 缺失目标语言文本的 content_id 不返回(跳过,不做语言回退)
- 不产生按 id 循环查 flags 的查询(查询次数为常数级)
- 实现要点:
-
5.2 实现
fetch_candidates(scene, user_profile, fallback_level, limit, locale, exclude_content_ids)- 实现要点:
- 计算
effective_fallback_level:- 若画像 need/context/emotion 任一缺失,则
effective_fallback_level = max(fallback_level, 1)
- 若画像 need/context/emotion 任一缺失,则
- DB 粗过滤对齐 plan:
- L1:
personalization_power <= 5 - L2:
personalization_power = 0且stage = general - L3:
is_safe_pool = true且stage = general且personalization_power = 0(如需更严格可在此明确)
- L1:
- 排序(V1):按
content_profiles.updated_at DESC或contents.updated_at DESC(择一写死并记录) - 两段式候选:
- 先查候选 id(
LIMIT limit * multiplier) - 调用
fetch_contents_by_ids补全字段
- 先查候选 id(
- locale 文本存在性过滤:
locale=en*:contents.text_en IS NOT NULLlocale=zh-*:contents.text_tc IS NOT NULL
- 输出顺序:
- 返回顺序按候选 id 列表顺序(用于后续引擎打分/重排);最终截断至
limit
- 返回顺序按候选 id 列表顺序(用于后续引擎打分/重排);最终截断至
- 计算
- 验收:
- 在不同
effective_fallback_level下能返回候选 - 不返回缺少目标语言文本的内容(不做语言回退)
- 查询次数为常数级(不随
limit线性增长)
- 在不同
- 实现要点:
6. DB 集成测试(dev MySQL)
-
6.1 建立测试目录与 pytest 配置
- 目标:在
server/内新增tests/(或app/**/__tests__/,但建议统一为server/tests/) - 内容:
server/tests/conftest.py:提供 AsyncEngine/AsyncSession、清库策略、query count 统计工具- 测试运行约定:通过
DATABASE_URL指向 dev 测试库(建议单独库名,例如mindfulness_dev_test)
- 验收:
pytest可在server/下运行并发现测试。
- 目标:在
-
6.2 测试库 schema 初始化(用 Alembic)
- 策略(二选一写死):
- A:测试启动时
alembic upgrade head(确保 schema 最新) - B:在 CI/本地提前准备库,仅在测试中清表
- A:测试启动时
- 验收:测试运行前 schema 可用,且不会污染开发主库数据(推荐使用独立 test 库)。
- 策略(二选一写死):
-
6.3 集成测试用例:
fetch_contents_by_ids- 准备数据:插入最小内容 2~3 条(覆盖 text_en/text_tc 缺失组合)、profiles、flags(含旧 flag)
- 断言:
- 返回顺序与输入一致
en不返回text_en缺失的内容(不回退text_tc)- risk_flags 映射后不含旧命名
review_confidenceNULL → 0.7
- 验收:测试稳定通过。
-
6.4 集成测试用例:
fetch_candidates- 准备数据:覆盖
personalization_power0/5/10、is_safe_pooltrue/false、不同 stage - 断言:
- L1/L2/L3 粗过滤生效
exclude_content_ids生效- 查询次数为常数级(用 before_cursor_execute 计数)
- 验收:测试稳定通过。
- 准备数据:覆盖
7. 最终自检清单(合入前)
-
7.1 文档一致性检查
spec.md/plan.md/ 实现接口签名三者一致(尤其是locale与text输出规则)
-
7.2 性能检查(最小)
fetch_contents_by_ids/fetch_candidates查询次数断言通过(无 N+1)
-
7.3 回归检查
- 不影响现有
user_profile_scoring模块与迁移脚本(仅新增模块与测试)
- 不影响现有