初始化提交
This commit is contained in:
commit
887c1f449e
963 files changed
+166869
No files matched your search
@@ -0,0 +1,117 @@
|
||||
"""角色卡导入 / 导出服务。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.errors import AppError
|
||||
from app.db.session import AsyncSessionLocal
|
||||
from app.models.character import Character
|
||||
from app.models.lorebook import Lorebook, LorebookEntry
|
||||
from app.modules.imports.card_parser import parse_character_card
|
||||
from app.modules.imports.export_mapping import character_to_card
|
||||
from app.modules.imports.mapping import (
|
||||
card_to_daoti,
|
||||
card_to_profile,
|
||||
character_book_to_entries,
|
||||
)
|
||||
from app.repositories import lorebook as lorebook_repo
|
||||
from app.repositories.json_utils import dumps
|
||||
from app.schemas.character import ImportCardResponse
|
||||
|
||||
|
||||
async def import_character_card(
|
||||
session: AsyncSession, raw: bytes, owner_scope: str
|
||||
) -> Character:
|
||||
"""解析角色卡字节 → 建 Character + 世谱(character_book)。返回 Character ORM。
|
||||
|
||||
``personality`` 写入道体 ``personality_summary`` 作初始值;
|
||||
``character_book`` 转为该角色的世谱书 + 条目。
|
||||
"""
|
||||
card = parse_character_card(raw)
|
||||
daoti = card_to_daoti(card)
|
||||
|
||||
character = Character(
|
||||
name=card.name or "未命名角色",
|
||||
display_name=card.nickname or card.name or None,
|
||||
language="zh-CN",
|
||||
profile_json=dumps(card_to_profile(card)),
|
||||
model_policy_json="{}",
|
||||
personality_summary=daoti["personality_summary"],
|
||||
privacy_level="normal",
|
||||
owner_scope=owner_scope,
|
||||
)
|
||||
session.add(character)
|
||||
await session.flush()
|
||||
|
||||
entries_data = character_book_to_entries(card.character_book)
|
||||
if entries_data:
|
||||
book = card.character_book or {}
|
||||
lorebook = Lorebook(
|
||||
character_id=character.id,
|
||||
name=book.get("name", "") or card.name,
|
||||
description=book.get("description", ""),
|
||||
scan_depth=book.get("scan_depth"),
|
||||
token_budget=book.get("token_budget"),
|
||||
recursive_scanning=bool(book.get("recursive_scanning", False)),
|
||||
scope="character",
|
||||
owner_scope=owner_scope,
|
||||
)
|
||||
session.add(lorebook)
|
||||
await session.flush()
|
||||
for entry in entries_data:
|
||||
session.add(
|
||||
LorebookEntry(
|
||||
lorebook_id=lorebook.id,
|
||||
keys_json=dumps(entry["keys"]),
|
||||
content=entry["content"],
|
||||
secondary_keys_json=dumps(entry["secondary_keys"]),
|
||||
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"],
|
||||
)
|
||||
)
|
||||
|
||||
await session.commit()
|
||||
await session.refresh(character)
|
||||
return character
|
||||
|
||||
|
||||
async def import_character_card_response(
|
||||
raw: bytes, owner_scope: str
|
||||
) -> ImportCardResponse:
|
||||
"""导入角色卡 → ImportCardResponse(供 API 调用,自管 session)。"""
|
||||
async with AsyncSessionLocal() as session:
|
||||
character = await import_character_card(session, raw, owner_scope)
|
||||
books = await lorebook_repo.list_books(session, character.id, owner_scope)
|
||||
book_id = books[0].id if books else None
|
||||
entries = (
|
||||
await lorebook_repo.list_book_entries(session, book_id) if book_id else []
|
||||
)
|
||||
return ImportCardResponse(
|
||||
character_id=character.id,
|
||||
name=character.name,
|
||||
display_name=character.display_name,
|
||||
lorebook_id=book_id,
|
||||
entry_count=len(entries),
|
||||
)
|
||||
|
||||
|
||||
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", "人物不存在。")
|
||||
books = await lorebook_repo.list_books(session, character_id, owner_scope)
|
||||
book = books[0] if books else None
|
||||
entries = (
|
||||
await lorebook_repo.list_book_entries(session, book.id) if book else []
|
||||
)
|
||||
return character_to_card(character, book, entries)
|
||||
Reference in new issue
Block a user