add nickname
This commit is contained in:
136
src/classes/nickname.py
Normal file
136
src/classes/nickname.py
Normal 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
|
||||
|
||||
Reference in New Issue
Block a user