Files
chenxin b419e0afde M7:形仪与语音——真形锚点、候选定相、声音档案与克隆授权、ASR 接入
- 形仪域 domains/xingyi:form_anchors(稳定辨识特征/年龄表现/许可禁忌/可变范围——生成内容不可静默覆盖锚点);forms(主仪/化仪/文字形仪,candidate→adopt 定相治理:未定相不进呈现位、主仪唯一、新主仪自动退役旧主仪);voice_profiles(三来源,授权克隆必填用途与传播范围,revoke-grant 撤回立即生效,assert-usable 合成前置校验拒绝撤回/过期)
- ASR:元炁 SenseVoice /v1/audio/transcriptions 透传(Whisper 兼容 multipart);YUANQI_BASE_URL 未配置时 503 不降级不伪造——多模态关闭纪律
- 前端形仪工坊(人物详情页):真形锚点编辑(特征逐行解析)/候选登记定相废弃/声音档案建立与授权撤回;头像呈现位改走定相主仪(forms/primary);xingyi api 库 + mock + 组件 4 用例
- 退役:旧 avatar 模块(services/endpoints/avatar、avatar_dir 配置、avatar_url 字段、前端直传组件与测试)
- 验收(test_m7_xingyi 三用例):未定相不成为正式形仪(含主仪唯一与旧主仪 retired 断言);克隆授权可撤回(缺用途拒/撤回即拒/过期同理/预设不受约束);关闭全部多模态后文字相伴完整可用(ASR 503 时镜树缘契百工照常——回归)
- 四套件:后端 376、前端 203、BFF 4、神识 5 包全绿(2 个预存环境失败不变);迁移 008 净库+±1 干净
2026-08-27 20:26:52 +08:00

133 lines
6.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""人物 API schema。"""
from typing import Any
from pydantic import BaseModel, ConfigDict, Field
class CharacterResponse(BaseModel):
model_config = ConfigDict(
json_schema_extra={
"examples": [
{
"id": "character_ec83d55746c54e47ab6f98d683032626",
"name": "default",
"display_name": "魂镜默认人物",
"status": "active",
"language": "zh-CN",
"profile": {"bio": "本地 MVP 默认人物。"},
"model_policy": {"default_model_hint": "deepseek-v4-flash"},
"privacy_level": "normal",
"owner_scope": "local-user",
"is_system_template": False,
"source_template_id": "character_template_default",
"created_at": "2026-06-19T09:00:00.000000Z",
"updated_at": "2026-06-19T09:00:00.000000Z",
}
]
}
)
id: str = Field(description="人物 ID,前缀为 character_。")
name: str = Field(description="人物内部名称。")
display_name: str | None = Field(description="人物显示名称。")
status: str = Field(description="人物状态,取值见契约字典 character.status。")
language: str = Field(description="人物默认语言。")
profile: dict[str, Any] = Field(description="人物档案 JSON。")
model_policy: dict[str, Any] = Field(description="人物模型策略。")
privacy_level: str = Field(description="隐私等级:normal / sensitive / local_only。")
owner_scope: str = Field(description="归属范围;当前本地 MVP 为 local-user。")
is_system_template: bool = Field(description="是否系统人物模板;active API 通常返回 false。")
source_template_id: str | None = Field(
description="来源系统模板人物 ID;非模板复制人物通常有值。"
)
created_at: str = Field(description="创建时间,UTC ISO 8601 字符串。")
updated_at: str = Field(description="更新时间,UTC ISO 8601 字符串。")
class CharacterSummaryResponse(BaseModel):
"""人物列表项(api-spec §6 列出人物)。"""
id: str = Field(description="人物 ID,前缀为 character_。")
name: str = Field(description="人物内部名称。")
display_name: str | None = Field(description="人物显示名称。")
status: str = Field(description="人物状态,取值见契约字典 character.status。")
memory_count: int = Field(default=0, description="人物关联的未删除记忆数量。")
personality_version: int = Field(default=0, description="当前人格版本号;尚未形成人格时为 0。")
activated_at: str | None = Field(
default=None, description="最近激活时间,UTC ISO 8601 字符串。"
)
class CreateCharacterRequest(BaseModel):
name: str = Field(min_length=1, description="人物内部名称,必填。")
display_name: str | None = Field(default=None, description="可选显示昵称。")
template_key: str | None = Field(
default=None,
description="系统模板 key;传此值则从模板创建(继承档案/模型策略,status=active)。",
)
profile: dict[str, Any] | None = Field(
default=None,
description="人物档案,可含 birthday/height/weight/background/speaking_style。",
)
model_policy: dict[str, Any] | None = Field(
default=None,
description="模型策略,可含 default_chat_model_hint / memory_extraction_model_hint 等。",
)
class UpdateProfileRequest(BaseModel):
"""更新人物档案(api-spec §6 PATCH /characters/{id}/profile)。手动编辑视为用户确认。"""
display_name: str | None = Field(default=None, description="可选显示昵称。")
birthday: str | None = Field(default=None)
height: str | None = Field(default=None)
weight: str | None = Field(default=None)
description: str | None = Field(default=None, description="一句话简介。")
background: str | None = Field(default=None)
speaking_style: str | None = Field(default=None, description="表达风格。")
temperament: str | None = Field(default=None, description="性情气质。")
hobbies: list[str] | None = Field(default=None, description="兴趣爱好列表。")
values: list[str] | None = Field(default=None, description="价值观列表。")
class UpdateModelPolicyRequest(BaseModel):
"""更新人物模型策略(api-spec §6 PATCH /characters/{id}/model-policy)。"""
default_chat_model_hint: str | None = Field(default=None)
memory_extraction_model_hint: str | None = Field(default=None)
personality_analysis_model_hint: str | None = Field(default=None)
embedding_model_hint: str | None = Field(default=None)
privacy_level: str | None = Field(default=None)
class ActivateCharacterResponse(BaseModel):
"""激活人物响应(api-spec §6 POST /characters/{id}/activate)。"""
active_character_id: str = Field(description="当前激活人物 ID。")
status: str = Field(description="激活后状态,恒为 active。")
class CharacterTemplateSummaryResponse(BaseModel):
"""系统模板列表项(GET /character-templates)。"""
key: str = Field(description="模板唯一标识(template_key)。")
name: str = Field(description="模板人物内部名称。")
display_name: str | None = Field(description="模板人物显示昵称。")
description: str | None = Field(description="档案中的一句话描述(profile.description)。")
temperament: str | None = Field(description="档案中的性情气质(profile.temperament)。")
speaking_style: str | None = Field(description="档案中的说话风格(profile.speaking_style)。")
language: str = Field(description="默认语言。")
class ImportCardResponse(BaseModel):
"""角色卡导入结果。"""
character_id: str = Field(description="新建人物 ID。")
name: str = Field(description="人物名称。")
display_name: str | None = Field(default=None, description="显示名(V3 nickname 优先)。")
lorebook_id: str | None = Field(
default=None, description="导入的世谱 ID(character_book);无则为 null。"
)
entry_count: int = Field(default=0, description="世谱条目数。")