Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added in game events refresh timer #480

Merged
merged 1 commit into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/config/config_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ def __update_config_values_from_current_state(self):
#Conversation
self.automatic_greeting = self.__definitions.get_bool_value("automatic_greeting")
self.max_count_events = self.__definitions.get_int_value("max_count_events")
self.events_refresh_time = self.__definitions.get_int_value("events_refresh_time")
self.hourly_time = self.__definitions.get_bool_value("hourly_time")
self.player_character_description: str = self.__definitions.get_string_value("player_character_description")
self.voice_player_input: bool = self.__definitions.get_bool_value("voice_player_input")
Expand Down
9 changes: 8 additions & 1 deletion src/config/definitions/other_definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,18 @@ def get_max_count_events_config_value() -> ConfigValue:
Increasing this number will cost more prompt tokens and lead to the context limit being reached faster."""
return ConfigValueInt("max_count_events","Max Count Events",max_count_events_description,5,0,999999,tags=[ConfigValueTag.advanced,ConfigValueTag.share_row])

@staticmethod
def get_events_refresh_time_config_value() -> ConfigValue:
max_count_events_description = """Determines how much time (in seconds) can pass between the last NPC's response and the player's input before in-game events need to be refreshed.
Note that updating in-game events increases response times. If the player responds before this set number in seconds, response times will be reduced.
Increase this value to allow more time for the player to respond before events need to be refreshed. Decrease this value to make in-game events more up to date."""
return ConfigValueInt("events_refresh_time","Time to Wait before Updating Events",max_count_events_description,10,0,999999,tags=[ConfigValueTag.advanced,ConfigValueTag.share_row])

@staticmethod
def get_hourly_time_config_value() -> ConfigValue:
description = """If enabled, NPCs will be made aware of the time every in-game hour. Otherwise, time updates will be less granular (eg 'The conversation now takes place in the morning' / 'at night' etc).
To remove mentions of the hour entirely, prompts also need to be edited from 'The time is {time} {time_group}.' to 'The conversation takes place {time_group}.'"""
return ConfigValueBool("hourly_time","Report In-Game Time Hourly",description,False,tags=[ConfigValueTag.advanced,ConfigValueTag.share_row])
return ConfigValueBool("hourly_time","Report In-Game Time Hourly",description,False,tags=[ConfigValueTag.advanced])

#Player Character
@staticmethod
Expand Down
1 change: 1 addition & 0 deletions src/config/mantella_config_value_definitions_new.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ def get_config_values(is_integrated: bool, actions: list[action], on_value_chang
other_category.add_config_value(OtherDefinitions.get_automatic_greeting_config_value())
other_category.add_config_value(OtherDefinitions.get_active_actions(actions))
other_category.add_config_value(OtherDefinitions.get_max_count_events_config_value())
other_category.add_config_value(OtherDefinitions.get_events_refresh_time_config_value())
other_category.add_config_value(OtherDefinitions.get_hourly_time_config_value())
other_category.add_config_value(OtherDefinitions.get_player_character_description())
other_category.add_config_value(OtherDefinitions.get_voice_player_input())
Expand Down
25 changes: 21 additions & 4 deletions src/conversation/conversation.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def __init__(self, context_for_conversation: context, output_manager: ChatManage
self.__mic_ptt: bool = mic_ptt
self.__allow_interruption: bool = context_for_conversation.config.allow_interruption # allow mic interruption
self.__stt: Transcriber | None = stt
self.__events_refresh_time: float = context_for_conversation.config.events_refresh_time # Time in seconds before events are considered stale
self.__transcribed_text: str | None = None
if not self.__context.npcs_in_conversation.contains_player_character(): # TODO: fix this being set to a radiant conversation because of NPCs in conversation not yet being added
self.__conversation_type: conversation_type = radiant(context_for_conversation.config)
Expand Down Expand Up @@ -162,26 +163,40 @@ def continue_conversation(self) -> tuple[str, sentence | None]:
return comm_consts.KEY_REPLYTYPE_PLAYERTALK, None

@utils.time_it
def process_player_input(self, player_text: str):
def process_player_input(self, player_text: str) -> tuple[str, bool]:
"""Submit the input of the player to the conversation

Args:
player_text (str): The input text / voice transcribe of what the player character is supposed to say
player_text (str): The input text / voice transcribe of what the player character is supposed to say. Can be empty if mic input has not yet been parsed

Returns:
tuple[str, bool]: Returns a tuple consisting of updated player text (if using mic input) and whether or not in-game events need to be refreshed (depending on how much time has passed)
"""
player_character = self.__context.npcs_in_conversation.get_player_character()
if not player_character:
return #If there is no player in the conversation, exit here
return '', False # If there is no player in the conversation, exit here

events_need_updating: bool = False

with self.__generation_start_lock: #This lock makes sure no new generation by the LLM is started while we clear this
self.__stop_generation() # Stop generation of additional sentences right now
self.__sentences.clear() # Clear any remaining sentences from the list

if self.__mic_input:
# If the player's input does not already exist, parse mic input if mic is enabled
if self.__mic_input and len(player_text) == 0:
player_text = None
if self.__stt.stopped_listening and self.__allow_mic_input:
self.__stt.start_listening(self.__get_mic_prompt())

# Start tracking how long it has taken to receive a player response
input_wait_start_time = time.time()
while not player_text:
player_text = self.__stt.get_latest_transcription()
if time.time() - input_wait_start_time >= self.__events_refresh_time:
# If too much time has passed, in-game events need to be updated
events_need_updating = True
return player_text, events_need_updating

if self.__mic_ptt:
# only start listening when push-to-talk button pressed again
self.__stt.stop_listening()
Expand All @@ -208,6 +223,8 @@ def process_player_input(self, player_text: str):
else:
self.__start_generating_npc_sentences()

return player_text, events_need_updating

def __get_mic_prompt(self):
mic_prompt = f"This is a conversation with {self.__context.get_character_names_as_text(False)} in {self.__context.location}."
#logging.log(23, f'Context for mic transcription: {mic_prompt}')
Expand Down
8 changes: 5 additions & 3 deletions src/game_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,13 @@ def player_input(self, input_json: dict[str, Any]) -> dict[str, Any]:
if(not self.__talk ):
return self.error_message("No running conversation.")

player_text: str = input_json[comm_consts.KEY_REQUESTTYPE_PLAYERINPUT]
player_text: str = input_json.get(comm_consts.KEY_REQUESTTYPE_PLAYERINPUT, '')
self.__update_context(input_json)
self.__talk.process_player_input(player_text)
updated_player_text, update_events = self.__talk.process_player_input(player_text)
if update_events:
return {comm_consts.KEY_REPLYTYPE: comm_consts.KEY_REQUESTTYPE_TTS, comm_consts.KEY_TRANSCRIBE: updated_player_text}

cleaned_player_text = utils.clean_text(player_text)
cleaned_player_text = utils.clean_text(updated_player_text)
npcs_in_conversation = self.__talk.context.npcs_in_conversation
if not npcs_in_conversation.contains_multiple_npcs(): # actions are only enabled in 1-1 conversations
for action in self.__config.actions:
Expand Down