feat(evaluation): memoir readiness, judge/replay updates, eval web playground

Add memoir_readiness_service and router tests; extend judge schemas/services, replay_service, and conversation rubric; align story route agent, payload, prompts, and story_pipeline_sync; update agent logging, config, and DI. Document internal-eval; add replayDraft util and PlaygroundPage changes in app-eval-web.
This commit is contained in:
Kevin
2026-04-08 09:38:07 +08:00
parent 99543d04c6
commit 6772e1269c
26 changed files with 1255 additions and 124 deletions

View File

@@ -7,6 +7,7 @@ Story 路由:候选故事 JSON 载荷summary 优先、预算裁剪、固定
from __future__ import annotations
import json
import re
from datetime import timezone
from typing import Any, TYPE_CHECKING
@@ -15,6 +16,23 @@ if TYPE_CHECKING:
from app.features.story.models import Story
_PLAIN_SNIPPET_NOISE = re.compile(r"[`*_#]+")
def _plain_opening_snippet_from_markdown(md: str, *, max_chars: int) -> str:
"""无 summary 时供路由辨题的短文摘(弱化 Markdown 噪声)。"""
t = (md or "").strip()
if not t:
return ""
t = re.sub(r"!\[[^\]]*\]\([^)]+\)", "", t)
t = re.sub(r"\[([^\]]+)\]\([^)]+\)", r"\1", t)
t = re.sub(r"asset://\S+", "", t)
t = _PLAIN_SNIPPET_NOISE.sub("", t)
t = re.sub(r"\s+", " ", t).strip()
if len(t) <= max_chars:
return t
return t[: max_chars - 1] + ""
def _linked_chapters(s: Story) -> list[str]:
links: list[str] = []
@@ -126,6 +144,9 @@ def _build_full_row(
)
if body:
row["body_for_route"] = body
osnip = _plain_opening_snippet_from_markdown(canon, max_chars=260)
if osnip and len(osnip) >= 40:
row["opening_snippet"] = osnip
return row