Files
life-echo/api/app/features/evaluation/schemas.py

228 lines
6.9 KiB
Python
Raw Normal View History

"""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]
2026-04-06 23:19:20 +08:00
class MemoirSectionBaselineOut(BaseModel):
title: str
body: str
class UserExportFixtureDetailOut(BaseModel):
filename: str
turns: list[UserExportFixtureTurnOut]
2026-04-06 23:19:20 +08:00
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 先只测对话)。"""
2026-04-06 23:19:20 +08:00
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)
2026-04-06 23:19:20 +08:00
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)
2026-04-06 23:19:20 +08:00
class ManualJudgeConversationBody(BaseModel):
conversation_id: str
"""与当前评测台选中的 MD 一致,供基准 transcript / 整体打分。"""
fixture_filename: str | None = None
judge_provider: EvalJudgeProviderLiteral = "zhipu"
judge_model: str | None = None
"""空则用该供应商默认模型智谱eval_judge_modelDeepSeekeval_judge_deepseek_model"""
2026-04-06 23:19:20 +08:00
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)
2026-04-06 23:19:20 +08:00
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
2026-04-06 23:19:20 +08:00
errors: list[str] = Field(default_factory=list)
class PlaygroundConversationJudgeOut(BaseModel):
"""`conversations.playground_conversation_judge_json` 的只读视图。"""
conversation_id: str
judge: dict[str, Any] | None = None
2026-04-06 23:19:20 +08:00
class ManualJudgeMemoirBody(BaseModel):
user_id: str
baseline_sections: list[MemoirSectionBaselineOut] | None = None
judge_provider: EvalJudgeProviderLiteral = "zhipu"
judge_model: str | None = None
2026-04-06 23:19:20 +08:00
class ManualJudgeMemoirOut(BaseModel):
user_id: str
chapter_results: list[dict[str, Any]] = Field(default_factory=list)
story_results: list[dict[str, Any]] = 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]