add personas
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import random
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
from typing import Optional
|
||||
from typing import Optional, List
|
||||
import json
|
||||
|
||||
from src.classes.calendar import MonthStamp
|
||||
@@ -15,13 +15,15 @@ from src.classes.age import Age
|
||||
from src.classes.event import NULL_EVENT, Event
|
||||
from src.classes.typings import ACTION_NAME, ACTION_PARAMS, ACTION_PAIR, ACTION_NAME_PARAMS_PAIRS, ACTION_NAME_PARAMS_PAIR
|
||||
|
||||
from src.classes.persona import Persona, personas_by_id
|
||||
from src.classes.persona import Persona, personas_by_id, get_random_compatible_personas
|
||||
from src.classes.item import Item
|
||||
from src.classes.magic_stone import MagicStone
|
||||
from src.classes.hp_and_mp import HP, MP, HP_MAX_BY_REALM, MP_MAX_BY_REALM
|
||||
from src.utils.id_generator import get_avatar_id
|
||||
from src.utils.config import CONFIG
|
||||
|
||||
persona_num = CONFIG.avatar.persona_num
|
||||
|
||||
class Gender(Enum):
|
||||
MALE = "male"
|
||||
FEMALE = "female"
|
||||
@@ -55,7 +57,7 @@ class Avatar:
|
||||
tile: Optional[Tile] = None
|
||||
|
||||
root: Root = field(default_factory=lambda: random.choice(list(Root)))
|
||||
persona: Persona = field(default_factory=lambda: random.choice(list(personas_by_id.values())))
|
||||
personas: List[Persona] = field(default_factory=list)
|
||||
cur_action_pair: Optional[ACTION_PAIR] = None
|
||||
history_action_pairs: list[ACTION_PAIR] = field(default_factory=list)
|
||||
next_actions: ACTION_NAME_PARAMS_PAIRS = field(default_factory=list)
|
||||
@@ -77,6 +79,10 @@ class Avatar:
|
||||
max_mp = MP_MAX_BY_REALM.get(self.cultivation_progress.realm, 100)
|
||||
self.hp = HP(max_hp, max_hp)
|
||||
self.mp = MP(max_mp, max_mp)
|
||||
|
||||
# 如果personas列表为空,则随机分配两个不互斥的persona
|
||||
if not self.personas:
|
||||
self.personas = get_random_compatible_personas(persona_num)
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash(self.id)
|
||||
@@ -86,7 +92,8 @@ class Avatar:
|
||||
获取avatar的详细信息
|
||||
尽量多打一些,因为会用来给LLM进行决策
|
||||
"""
|
||||
return f"Avatar(id={self.id}, 性别={self.gender}, 年龄={self.age}, name={self.name}, 区域={self.tile.region.name}, 灵根={self.root.value}, 境界={self.cultivation_progress}, HP={self.hp}, MP={self.mp})"
|
||||
personas_str = ", ".join([persona.name for persona in self.personas])
|
||||
return f"Avatar(id={self.id}, 性别={self.gender}, 年龄={self.age}, name={self.name}, 区域={self.tile.region.name}, 灵根={self.root.value}, 境界={self.cultivation_progress}, HP={self.hp}, MP={self.mp}, 个性={personas_str})"
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.get_info()
|
||||
@@ -345,9 +352,14 @@ class Avatar:
|
||||
获取角色提示词信息
|
||||
"""
|
||||
info = self.get_info()
|
||||
persona = self.persona.prompt
|
||||
action_space = self.get_action_space_str()
|
||||
|
||||
# 构建personas的提示词信息
|
||||
personas_prompts = []
|
||||
for i, persona in enumerate(self.personas, 1):
|
||||
personas_prompts.append(f"其个性{i}:{persona.prompt}")
|
||||
personas_info = "\n".join(personas_prompts)
|
||||
|
||||
# 添加灵石信息
|
||||
magic_stone_info = f"灵石持有情况:{str(self.magic_stone)}"
|
||||
|
||||
@@ -357,7 +369,8 @@ class Avatar:
|
||||
else:
|
||||
items_info = "物品持有情况:无"
|
||||
|
||||
return f"{info}\n其个性为:{persona}\n{magic_stone_info}\n{items_info}\n决策时需参考这个角色的个性。\n该角色的目前暂时的合法动作为:{action_space}"
|
||||
personas_count = len(self.personas)
|
||||
return f"{info}\n{personas_info}\n{magic_stone_info}\n{items_info}\n决策时需参考这个角色的{personas_count}个个性特点。\n该角色的目前暂时的合法动作为:{action_space}"
|
||||
|
||||
@property
|
||||
def move_step_length(self) -> int:
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import random
|
||||
from dataclasses import dataclass
|
||||
from typing import List
|
||||
|
||||
from src.utils.df import game_configs
|
||||
from src.utils.config import CONFIG
|
||||
|
||||
ids_separator = CONFIG.df.ids_separator
|
||||
|
||||
@dataclass
|
||||
class Persona:
|
||||
@@ -9,7 +14,8 @@ class Persona:
|
||||
"""
|
||||
id: int
|
||||
name: str
|
||||
prompt: str
|
||||
prompt: str
|
||||
exclusion_ids: List[int]
|
||||
|
||||
def _load_personas() -> tuple[dict[int, Persona], dict[str, Persona]]:
|
||||
"""从配表加载persona数据"""
|
||||
@@ -18,10 +24,17 @@ def _load_personas() -> tuple[dict[int, Persona], dict[str, Persona]]:
|
||||
|
||||
persona_df = game_configs["persona"]
|
||||
for _, row in persona_df.iterrows():
|
||||
# 解析exclusion_ids字符串,转换为int列表
|
||||
exclusion_ids_str = str(row["exclusion_ids"]) if str(row["exclusion_ids"]) != "nan" else ""
|
||||
exclusion_ids = []
|
||||
if exclusion_ids_str:
|
||||
exclusion_ids = [int(x.strip()) for x in exclusion_ids_str.split(ids_separator) if x.strip()]
|
||||
|
||||
persona = Persona(
|
||||
id=int(row["id"]),
|
||||
name=str(row["name"]),
|
||||
prompt=str(row["prompt"])
|
||||
prompt=str(row["prompt"]),
|
||||
exclusion_ids=exclusion_ids
|
||||
)
|
||||
personas_by_id[persona.id] = persona
|
||||
personas_by_name[persona.name] = persona
|
||||
@@ -31,6 +44,44 @@ def _load_personas() -> tuple[dict[int, Persona], dict[str, Persona]]:
|
||||
# 从配表加载persona数据
|
||||
personas_by_id, personas_by_name = _load_personas()
|
||||
|
||||
def get_random_compatible_personas(num_personas: int = 2) -> List[Persona]:
|
||||
"""
|
||||
随机选择指定数量的互相不冲突的persona
|
||||
|
||||
Args:
|
||||
num_personas: 需要选择的persona数量,默认为2
|
||||
|
||||
Returns:
|
||||
List[Persona]: 互相不冲突的persona列表
|
||||
|
||||
Raises:
|
||||
ValueError: 如果无法找到足够数量的兼容persona
|
||||
"""
|
||||
all_persona_ids = set(personas_by_id.keys())
|
||||
|
||||
|
||||
selected_personas = []
|
||||
available_ids = all_persona_ids.copy()
|
||||
|
||||
for i in range(num_personas):
|
||||
if not available_ids:
|
||||
raise ValueError(f"只能找到{i}个兼容的persona,无法满足需要的{num_personas}个")
|
||||
|
||||
# 从可用列表中随机选择一个
|
||||
selected_id = random.choice(list(available_ids))
|
||||
selected_persona = personas_by_id[selected_id]
|
||||
selected_personas.append(selected_persona)
|
||||
|
||||
# 更新可用列表:移除已选择的和与其互斥的
|
||||
available_ids.discard(selected_id) # 移除自己
|
||||
|
||||
# 移除所有与当前选择互斥的persona
|
||||
for exclusion_id in selected_persona.exclusion_ids:
|
||||
available_ids.discard(exclusion_id)
|
||||
|
||||
# 移除所有将当前选择作为互斥对象的persona
|
||||
for persona_id in list(available_ids):
|
||||
if selected_id in personas_by_id[persona_id].exclusion_ids:
|
||||
available_ids.discard(persona_id)
|
||||
|
||||
return selected_personas
|
||||
|
||||
|
||||
Reference in New Issue
Block a user