103 lines
3.8 KiB
Python
103 lines
3.8 KiB
Python
import logging
|
|
import random
|
|
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.models.orm import Character
|
|
from app.models.schemas import CharacterRole
|
|
from app.services.hermes_client import hermes_client
|
|
from app.services.soul_generator import soul_generator
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class CharacterGenerator:
|
|
async def generate_characters(
|
|
self,
|
|
session: AsyncSession,
|
|
script_id: str,
|
|
characters_data: list[dict],
|
|
is_json: bool = False,
|
|
) -> list[Character]:
|
|
characters = []
|
|
killer_index = random.randint(0, len(characters_data) - 1) if len(characters_data) > 1 else 0
|
|
|
|
for i, char_data in enumerate(characters_data):
|
|
role = CharacterRole.KILLER if i == killer_index else CharacterRole.SUSPECT
|
|
if is_json and "role" in char_data:
|
|
role = CharacterRole(char_data["role"]) if char_data["role"] in [r.value for r in CharacterRole] else role
|
|
|
|
name = char_data.get("name", f"角色{i + 1}")
|
|
profile_name = name.lower().replace(" ", "_").replace("·", "_")
|
|
|
|
character = Character(
|
|
script_id=script_id,
|
|
name=name,
|
|
role=role,
|
|
personality=char_data.get("personality", ""),
|
|
speaking_style=char_data.get("speaking_style", ""),
|
|
background=char_data.get("background", ""),
|
|
secret=char_data.get("secret", ""),
|
|
motive=char_data.get("motive", ""),
|
|
hermes_profile=profile_name,
|
|
is_revealed_killer=False,
|
|
)
|
|
session.add(character)
|
|
characters.append(character)
|
|
|
|
await session.commit()
|
|
for character in characters:
|
|
await session.refresh(character)
|
|
|
|
return characters
|
|
|
|
async def create_profile(self, character: Character) -> bool:
|
|
soul_content = soul_generator.generate(
|
|
name=character.name,
|
|
personality=character.personality,
|
|
speaking_style=character.speaking_style,
|
|
background=character.background,
|
|
secret=character.secret,
|
|
motive=character.motive,
|
|
knowledge_base=character.knowledge_base,
|
|
)
|
|
|
|
success = await hermes_client.create_profile(character.hermes_profile, soul_content)
|
|
if success:
|
|
character.soul_md = soul_content
|
|
return success
|
|
|
|
async def create_all_profiles(self, session: AsyncSession, script_id: str) -> int:
|
|
result = await session.execute(
|
|
select(Character).where(Character.script_id == script_id)
|
|
)
|
|
characters = list(result.scalars().all())
|
|
created = 0
|
|
|
|
for character in characters:
|
|
try:
|
|
if await self.create_profile(character):
|
|
created += 1
|
|
character.soul_md = soul_generator.generate(
|
|
name=character.name,
|
|
personality=character.personality,
|
|
speaking_style=character.speaking_style,
|
|
background=character.background,
|
|
secret=character.secret,
|
|
motive=character.motive,
|
|
knowledge_base=character.knowledge_base,
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"Failed to create profile for {character.name}: {e}")
|
|
|
|
await session.commit()
|
|
logger.info(f"Created {created}/{len(characters)} profiles for script {script_id}")
|
|
return created
|
|
|
|
async def delete_profile(self, character: Character) -> bool:
|
|
return await hermes_client.delete_profile(character.hermes_profile)
|
|
|
|
|
|
character_generator = CharacterGenerator()
|