Files
2026-08-21 16:00:13 +08:00

72 lines
2.8 KiB
Python

"""角色卡导出映射:魂镜 Character + 世谱 → ST V3 卡静态快照。
反向于 import mapping。导出为静态快照——丢弃演化维度(人格版本 / 记忆 / 情绪),
仅保留当前设定 + 世谱。``mission`` / ``safety_guidelines`` 道体无 ST 对应字段,不导出。
"""
from __future__ import annotations
import json
from app.models.character import Character
from app.models.lorebook import Lorebook, LorebookEntry
def character_to_card(
character: Character,
lorebook: Lorebook | None = None,
entries: list[LorebookEntry] | None = None,
) -> dict:
"""Character + 世谱 → ST V3 卡 dict。"""
profile = json.loads(character.profile_json or "{}")
source_meta = profile.get("source_meta") or {}
data: dict = {
"name": character.name,
"description": profile.get("background", ""),
"personality": character.personality_summary or "",
"scenario": profile.get("scenario", ""),
"first_mes": profile.get("first_mes", ""),
"mes_example": profile.get("mes_example", ""),
"alternate_greetings": profile.get("alternate_greetings", []),
"tags": profile.get("tags", []),
"creator": source_meta.get("creator", ""),
"character_version": source_meta.get("character_version", ""),
"creator_notes": source_meta.get("creator_notes", ""),
"system_prompt": profile.get("system_prompt", ""),
"post_history_instructions": profile.get("post_history_instructions", ""),
"extensions": profile.get("st_extensions", {}),
}
if character.display_name and character.display_name != character.name:
data["nickname"] = character.display_name
if lorebook is not None:
data["character_book"] = lorebook_to_st_book(lorebook, entries or [])
return {"spec": "chara_card_v3", "spec_version": "3.0", "data": data}
def lorebook_to_st_book(lorebook: Lorebook, entries: list[LorebookEntry]) -> dict:
return {
"name": lorebook.name,
"description": lorebook.description,
"scan_depth": lorebook.scan_depth,
"token_budget": lorebook.token_budget,
"recursive_scanning": lorebook.recursive_scanning,
"entries": [entry_to_st(e) for e in entries],
}
def entry_to_st(entry: LorebookEntry) -> dict:
return {
"keys": json.loads(entry.keys_json or "[]"),
"content": entry.content,
"secondary_keys": json.loads(entry.secondary_keys_json or "[]"),
"constant": entry.constant,
"selective": entry.selective,
"enabled": entry.enabled,
"case_sensitive": entry.case_sensitive,
"use_regex": entry.use_regex,
"position": entry.position,
"insertion_order": entry.insertion_order,
"priority": entry.priority,
"comment": entry.comment,
}