add nickname

This commit is contained in:
bridge
2025-11-18 01:23:43 +08:00
parent 19f5faabf3
commit c1963beef2
5 changed files with 197 additions and 3 deletions

136
src/classes/nickname.py Normal file
View File

@@ -0,0 +1,136 @@
"""
绰号生成模块
为满足条件的角色生成江湖绰号
"""
from typing import Optional, List, TYPE_CHECKING
if TYPE_CHECKING:
from src.classes.avatar import Avatar
from src.classes.world import World
from src.classes.event import Event
from src.utils.config import CONFIG
from src.utils.llm import get_prompt_and_call_llm_async
from src.run.log import get_logger
logger = get_logger().logger
def can_get_nickname(avatar: "Avatar") -> bool:
"""
检查角色是否满足获得绰号的条件
条件:
1. 尚未拥有绰号nickname为None
2. 长期事件数量 >= major_event_threshold
3. 短期事件数量 >= minor_event_threshold
Args:
avatar: 要检查的角色
Returns:
是否满足条件
"""
# 已有绰号,不再生成
if avatar.nickname is not None:
return False
# 检查事件数量
em = avatar.world.event_manager
major_threshold = CONFIG.nickname.major_event_threshold
minor_threshold = CONFIG.nickname.minor_event_threshold
major_events = em.get_major_events_by_avatar(avatar.id)
minor_events = em.get_minor_events_by_avatar(avatar.id)
major_count = len(major_events)
minor_count = len(minor_events)
# AND逻辑两个条件都要满足
return major_count >= major_threshold and minor_count >= minor_threshold
async def generate_nickname(avatar: "Avatar") -> Optional[str]:
"""
为角色生成绰号
调用LLM基于角色信息和事件历史生成合适的绰号
Args:
avatar: 要生成绰号的角色
Returns:
生成的绰号失败则返回None
"""
try:
# 准备角色信息
avatar_info = avatar.get_info(detailed=True)
avatar_info_str = "\n".join([f"{k}: {v}" for k, v in avatar_info.items()])
# 获取事件历史(根据配置的阈值获取对应数量的事件)
em = avatar.world.event_manager
major_threshold = CONFIG.nickname.major_event_threshold
minor_threshold = CONFIG.nickname.minor_event_threshold
major_events = em.get_major_events_by_avatar(avatar.id, limit=major_threshold)
minor_events = em.get_minor_events_by_avatar(avatar.id, limit=minor_threshold)
major_events_str = "\n".join([f"- {str(e)}" for e in major_events]) if major_events else ""
minor_events_str = "\n".join([f"- {str(e)}" for e in minor_events]) if minor_events else ""
# 准备模板参数
template_path = CONFIG.paths.templates / "nickname.txt"
infos = {
"avatar_info": avatar_info_str,
"major_events": major_events_str,
"minor_events": minor_events_str
}
# 调用LLM并自动解析JSON
response_data = await get_prompt_and_call_llm_async(template_path, infos, mode="normal")
nickname = response_data.get("nickname", "").strip()
thinking = response_data.get("thinking", "")
if not nickname:
logger.warning(f"为角色 {avatar.name} 生成绰号失败:返回空绰号")
return None
logger.info(f"为角色 {avatar.name} 生成绰号:{nickname}")
logger.debug(f"绰号生成思考过程:{thinking}")
return nickname
except Exception as e:
logger.error(f"生成绰号时出错:{e}")
return None
async def process_avatar_nickname(avatar: "Avatar") -> Optional[Event]:
"""
处理单个角色的绰号生成
检查角色是否满足条件,满足则生成绰号并返回对应事件
Args:
avatar: 要处理的角色
Returns:
生成的事件如果不满足条件或生成失败则返回None
"""
if not can_get_nickname(avatar):
return None
nickname = await generate_nickname(avatar)
if not nickname:
return None
avatar.nickname = nickname
# 生成事件:角色获得绰号
event = Event(
avatar.world.month_stamp,
f"{avatar.name}在江湖中闯出名号,被人称为'{nickname}'",
related_avatars=[avatar.id],
is_major=True
)
return event