Files

76 lines
2.8 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.
"""角色卡导入 / 导出。
rewrite/1.0 M2b:导入不再直接建人物——ST V1/V2/V3 卡解析后产出**可审阅灵胚**
(产品 PRD §5.2「导入默认生成可审阅灵胚」);``character_book`` 暂存于灵胚道体草稿,
启镜时物化为新人物的世谱书与条目(见 jingsheng.service.activate_embryo)。
导出方向保持:人物 → ST V3 卡静态快照。
"""
from __future__ import annotations
from app.core.errors import AppError
from app.db.session import AsyncSessionLocal
from app.models.character import Character
from app.modules.imports.card_parser import parse_character_card
from app.modules.imports.export_mapping import character_to_card
def card_to_embryo_payload(raw: bytes) -> dict:
"""解析角色卡字节 → 灵胚创建载荷(name/description/identity_baseline)。
identity_baseline 保存卡的全部有效字段与原始 character_book,
启镜前可经照心编辑(PATCH /embryo-drafts/{id})审阅修改。
"""
card = parse_character_card(raw)
description = "\n\n".join(
part
for part in (
card.description.strip(),
f"【性格】{card.personality.strip()}" if card.personality.strip() else "",
f"【场景】{card.scenario.strip()}" if card.scenario.strip() else "",
)
if part
)
baseline = {
"import_card": {
"spec_version": card.spec_version,
"description": card.description,
"personality": card.personality,
"scenario": card.scenario,
"first_mes": card.first_mes,
"mes_example": card.mes_example,
"system_prompt": card.system_prompt,
"post_history_instructions": card.post_history_instructions,
"alternate_greetings": card.alternate_greetings,
"tags": card.tags,
"creator": card.creator,
"character_version": card.character_version,
"character_book": card.character_book,
}
}
name = card.name.strip() or "未命名灵胚"
return {
"name": name[:120],
"description": description or None,
"identity_baseline": baseline,
"book_entry_count": _count_book_entries(card.character_book),
}
def _count_book_entries(book: dict | None) -> int:
if not book:
return 0
entries = book.get("entries")
if isinstance(entries, (dict, list)):
return len(entries)
return 0
async def export_character_card(character_id: str, owner_scope: str) -> dict:
"""导出人物为 ST V3 卡静态快照(丢弃演化维度)。"""
async with AsyncSessionLocal() as session:
character = await session.get(Character, character_id)
if character is None or character.owner_scope != owner_scope:
raise AppError("not_found", "人物不存在。")
return character_to_card(character)