feat(memoir): 回忆录分段两阶段管线(Phase1 分类 / Phase2 叙事)与配置、测试

This commit is contained in:
Kevin
2026-04-02 16:37:14 +08:00
parent 3ae39838c0
commit 6b930808a3
27 changed files with 1550 additions and 430 deletions

View File

@@ -84,20 +84,43 @@ async def get_segments_for_conversation(
async def get_segments_for_organize(
conversation_id: str, db: AsyncSession
) -> list[Segment]:
"""Unprocessed segments first; if none, all segments."""
"""兼容旧语义:优先返回 Phase1 未完成的片段;若无则返回本会话全部片段。"""
pending = await get_segments_pending_phase1(conversation_id, db)
if pending:
return pending
return await get_segments_for_conversation(conversation_id, db)
async def get_segments_pending_phase1(
conversation_id: str, db: AsyncSession
) -> list[Segment]:
"""尚未跑 Phase1 分类的 segmentstopic_category 为空且未标记 narrated"""
stmt = (
select(Segment)
.where(
Segment.conversation_id == conversation_id,
Segment.topic_category.is_(None),
Segment.narrated.is_(False),
Segment.processed.is_(False),
)
.order_by(Segment.created_at)
)
result = await db.execute(stmt)
segments = list(result.scalars().all())
if not segments:
return await get_segments_for_conversation(conversation_id, db)
return segments
return list(result.scalars().all())
async def conversation_has_pending_phase2(
conversation_id: str, db: AsyncSession
) -> bool:
"""Phase1 已完成但叙事未消费的片段(本会话范围内)。"""
stmt = select(func.count(Segment.id)).where(
Segment.conversation_id == conversation_id,
Segment.topic_category.isnot(None),
Segment.narrated.is_(False),
Segment.skip_narrative.is_(False),
)
result = await db.execute(stmt)
return int(result.scalar() or 0) > 0
async def count_segments_for_user(user_id: str, db: AsyncSession) -> int: