- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas. - Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error. - MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings. - app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS. - Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014. - Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
248 lines
7.7 KiB
Python
248 lines
7.7 KiB
Python
"""HTTP / OpenAPI 模型。"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from datetime import datetime
|
||
from typing import Any, Literal
|
||
|
||
from pydantic import BaseModel, ConfigDict, Field
|
||
|
||
EvalJudgeProviderLiteral = Literal["zhipu", "deepseek"]
|
||
|
||
|
||
class SessionDialogueMessageOut(BaseModel):
|
||
model_config = ConfigDict(from_attributes=True)
|
||
|
||
role: str
|
||
content: str
|
||
created_at: datetime | None = None
|
||
|
||
|
||
class SessionDialogueOut(BaseModel):
|
||
conversation_id: str
|
||
messages: list[SessionDialogueMessageOut]
|
||
|
||
|
||
class SessionListItem(BaseModel):
|
||
id: str
|
||
user_id: str
|
||
user_phone: str | None = Field(default=None, description="users.phone,列表展示用")
|
||
started_at: datetime | None
|
||
last_message_at: datetime | None = None
|
||
conversation_stage: str | None
|
||
current_topic: str | None
|
||
status: str | None
|
||
|
||
|
||
class SessionListResponse(BaseModel):
|
||
items: list[SessionListItem]
|
||
total: int
|
||
|
||
|
||
class SessionTranscriptOut(BaseModel):
|
||
conversation_id: str
|
||
user_id: str
|
||
user_utterances_from_segments: list[str]
|
||
user_utterances_from_messages: list[str]
|
||
|
||
|
||
class UserExportFixtureTurnOut(BaseModel):
|
||
user: str
|
||
ai: str
|
||
|
||
|
||
class UserExportFixtureListOut(BaseModel):
|
||
items: list[str]
|
||
|
||
|
||
class MemoirSectionBaselineOut(BaseModel):
|
||
title: str
|
||
body: str
|
||
|
||
|
||
class UserExportFixtureDetailOut(BaseModel):
|
||
filename: str
|
||
turns: list[UserExportFixtureTurnOut]
|
||
source_user_id: str | None = None
|
||
memoir_sections: list[MemoirSectionBaselineOut] = Field(default_factory=list)
|
||
|
||
|
||
class ReplayBootstrapBody(BaseModel):
|
||
user_id: str
|
||
|
||
|
||
class ReplayBootstrapOut(BaseModel):
|
||
conversation_id: str
|
||
|
||
|
||
class EvalSandboxOut(BaseModel):
|
||
"""内部评测专用:一次性临时账号 + 空白会话,不落真实手机号业务。"""
|
||
|
||
user_id: str
|
||
conversation_id: str
|
||
phone: str
|
||
nickname: str
|
||
|
||
|
||
class ReplayConversationBody(BaseModel):
|
||
conversation_id: str
|
||
fixture_filename: str | None = None
|
||
user_utterances: list[str] | None = None
|
||
flush_memoir_after: bool = True
|
||
"""为 True 且 skip_memoir 为 False 时,本批结束后 flush 回忆录队列。"""
|
||
skip_memoir: bool = False
|
||
"""为 True 时不向回忆录防抖队列入队、不 flush(供 Playground 先只测对话)。"""
|
||
skip_tts: bool = True
|
||
|
||
|
||
class ReplayConversationOut(BaseModel):
|
||
conversation_id: str
|
||
turns_replayed: int
|
||
utterances_echo: list[str] = Field(default_factory=list)
|
||
segment_ids: list[str] = Field(
|
||
default_factory=list,
|
||
description="本批请求创建并已走 orchestrator 的用户 segment id(顺序与落库一致)",
|
||
)
|
||
#: 服务端计量:本 HTTP 请求内回放逻辑耗时(与浏览器轮询间隔无关)
|
||
started_at_utc: datetime | None = None
|
||
finished_at_utc: datetime | None = None
|
||
elapsed_ms: int | None = Field(
|
||
default=None,
|
||
description="服务端 wall 耗时(本请求内 replay_utterances / replay_fixture)",
|
||
)
|
||
|
||
|
||
class MemoirPhase1ReadyOut(BaseModel):
|
||
ready: bool
|
||
checked_segment_ids: list[str] = Field(default_factory=list)
|
||
pending_segment_ids: list[str] = Field(default_factory=list)
|
||
#: 最近一次 Playground memoir-submit 写入 Redis 的提交时间(无记录时为 None)
|
||
job_submitted_at_utc: datetime | None = None
|
||
#: 自 job_submitted_at_utc 至本响应生成时服务端经过的毫秒数
|
||
elapsed_ms_since_submit: int | None = Field(default=None, ge=0)
|
||
#: 可选分步耗时(毫秒),键由服务端定义
|
||
durations_ms: dict[str, int] = Field(default_factory=dict)
|
||
|
||
|
||
class MemoirSubmitOut(BaseModel):
|
||
conversation_id: str
|
||
user_id: str
|
||
segment_ids: list[str] = Field(default_factory=list)
|
||
celery_task_id: str | None = None
|
||
submitted_at_utc: datetime | None = None
|
||
#: 提交接口瞬间耗时,通常为 0;与 Phase1 Celery 执行时间无关
|
||
elapsed_ms: int | None = Field(default=None, ge=0)
|
||
|
||
|
||
class MemoirPipelineRunOut(BaseModel):
|
||
"""Redis 流水线快照(memoir_pipeline_run:*);字段随迭代扩展。"""
|
||
|
||
model_config = ConfigDict(extra="allow")
|
||
|
||
memoir_correlation_id: str
|
||
user_id: str | None = None
|
||
started_at_utc: str | None = None
|
||
phase1: dict[str, Any] | None = None
|
||
phase2: list[Any] = Field(default_factory=list)
|
||
fanout: dict[str, Any] = Field(default_factory=dict)
|
||
|
||
|
||
class ManualJudgeConversationBody(BaseModel):
|
||
conversation_id: str
|
||
"""与当前评测台选中的 MD 一致,供基准 transcript / 整体打分。"""
|
||
fixture_filename: str | None = None
|
||
judge_provider: EvalJudgeProviderLiteral = "zhipu"
|
||
judge_model: str | None = None
|
||
"""空则用该供应商默认模型(智谱:eval_judge_model;DeepSeek:eval_judge_deepseek_model)。"""
|
||
|
||
|
||
class ManualJudgeConversationStreamBody(BaseModel):
|
||
conversation_id: str
|
||
fixture_filename: str | None = None
|
||
include_turn_judges: bool = False
|
||
"""对当前会话逐轮调用评审 LLM(在整体分之后)。"""
|
||
include_baseline_turn_judges: bool = False
|
||
"""对导出基线逐轮调用评审 LLM(需 fixture + 整体基线分成功)。"""
|
||
judge_provider: EvalJudgeProviderLiteral = "zhipu"
|
||
judge_model: str | None = None
|
||
|
||
|
||
class RetryBaselineJudgeBody(BaseModel):
|
||
conversation_id: str
|
||
fixture_filename: str | None = None
|
||
include_baseline_turn_judges: bool = False
|
||
"""与流式评分一致:成功重试基准整体分后是否补跑基线逐轮。"""
|
||
judge_provider: EvalJudgeProviderLiteral = "zhipu"
|
||
judge_model: str | None = None
|
||
|
||
|
||
class RetryBaselineJudgeOut(BaseModel):
|
||
ok: bool
|
||
error: str | None = None
|
||
message: str | None = None
|
||
baseline_judge: dict[str, Any] | None = None
|
||
replay_judge: dict[str, Any] | None = None
|
||
compare_summary: dict[str, Any] | None = None
|
||
compare_markdown: str = ""
|
||
baseline_turn_judges: dict[str, Any] = Field(default_factory=dict)
|
||
errors: list[str] = Field(default_factory=list)
|
||
|
||
|
||
class ManualJudgeConversationOut(BaseModel):
|
||
conversation_id: str
|
||
fixture_filename: str | None = None
|
||
baseline_transcript: str = ""
|
||
replay_transcript: str
|
||
baseline_judge: dict[str, Any] | None = None
|
||
replay_judge: dict[str, Any] | None = None
|
||
compare_summary: dict[str, Any] | None = None
|
||
errors: list[str] = Field(default_factory=list)
|
||
|
||
|
||
class PlaygroundConversationJudgeOut(BaseModel):
|
||
"""`conversations.playground_conversation_judge_json` 的只读视图。"""
|
||
|
||
conversation_id: str
|
||
judge: dict[str, Any] | None = None
|
||
|
||
|
||
class ManualJudgeMemoirBody(BaseModel):
|
||
user_id: str
|
||
baseline_sections: list[MemoirSectionBaselineOut] | None = None
|
||
judge_provider: EvalJudgeProviderLiteral = "zhipu"
|
||
judge_model: str | None = None
|
||
|
||
|
||
class ManualJudgeMemoirOut(BaseModel):
|
||
user_id: str
|
||
judge_provider: EvalJudgeProviderLiteral = "zhipu"
|
||
judge_model: str = ""
|
||
"""本次请求实际解析后的模型 id(与 `build_eval_judge_llm_spec` 一致)。"""
|
||
chapter_results: list[dict[str, Any]] = Field(default_factory=list)
|
||
story_results: list[dict[str, Any]] = Field(default_factory=list)
|
||
errors: list[str] = Field(default_factory=list)
|
||
"""单条章节/故事评审或列表加载失败时的可读原因(HTTP 仍为 200)。"""
|
||
warnings: list[str] = Field(default_factory=list)
|
||
"""无失败但未评到任何条目时的提示(例如成稿均为空)。"""
|
||
|
||
|
||
class MemoirChapterSnapOut(BaseModel):
|
||
id: str
|
||
title: str
|
||
category: str | None = None
|
||
order_index: int | None = None
|
||
canonical_markdown: str | None = None
|
||
|
||
|
||
class MemoirStorySnapOut(BaseModel):
|
||
id: str
|
||
title: str
|
||
stage: str | None = None
|
||
canonical_markdown: str | None = None
|
||
|
||
|
||
class UserMemoirSnapshotOut(BaseModel):
|
||
user_id: str
|
||
chapters: list[MemoirChapterSnapOut]
|
||
stories: list[MemoirStorySnapOut]
|