Skip to content
8 changes: 6 additions & 2 deletions usersimcrs/simulator/agenda_based/agenda_based_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,12 @@ def __init__(
nlg: NLG module generating textual responses.
ratings: Historical ratings.
"""
super().__init__(id=id, domain=domain, item_collection=item_collection)
self._preference_model = preference_model
super().__init__(
id=id,
domain=domain,
item_collection=item_collection,
preference_model=preference_model,
)
self._interaction_model = interaction_model
self._interaction_model.initialize_agenda(self.information_need)
self._nlu = nlu
Expand Down
21 changes: 17 additions & 4 deletions usersimcrs/simulator/llm/llm_dual_prompt_user_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
the user response.
"""

from typing import Optional

from dialoguekit.core.utterance import Utterance
from dialoguekit.participant import DialogueParticipant
from usersimcrs.core.simulation_domain import SimulationDomain
Expand All @@ -19,6 +21,7 @@
UtteranceGenerationPrompt,
)
from usersimcrs.simulator.user_simulator import UserSimulator
from usersimcrs.user_modeling.preference_model import PreferenceModel
from usersimcrs.user_modeling.persona import Persona


Expand All @@ -32,7 +35,8 @@ def __init__(
item_type: str,
task_definition: str = DEFAULT_TASK_DEFINITION,
stop_definition: str = DEFAULT_STOP_DEFINITION,
persona: Persona = None,
persona: Optional[Persona] = None,
preference_model: Optional[PreferenceModel] = None,
) -> None:
"""Initializes the user simulator.

Expand All @@ -45,14 +49,23 @@ def __init__(
stop_definition: Definition of the stop task. Defaults to
DEFAULT_STOP_DEFINITION.
persona: Persona of the user. Defaults to None.
preference_model: Preference model. Defaults to None.
"""
super().__init__(id, domain, item_collection)
super().__init__(id, domain, item_collection, preference_model)
self.llm_interface = llm_interface
self.generation_prompt = UtteranceGenerationPrompt(
self.information_need, item_type, task_definition, persona
self.information_need,
item_type,
task_definition,
persona,
preference_model,
)
self.stop_prompt = StopPrompt(
self.information_need, item_type, stop_definition, persona
self.information_need,
item_type,
stop_definition,
persona,
preference_model,
)

def _generate_response(self, agent_utterance: Utterance) -> Utterance:
Expand Down
15 changes: 12 additions & 3 deletions usersimcrs/simulator/llm/llm_single_prompt_user_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
model.
"""

from typing import Optional

from dialoguekit.core.utterance import Utterance
from dialoguekit.participant import DialogueParticipant
from usersimcrs.core.simulation_domain import SimulationDomain
Expand All @@ -14,6 +16,7 @@
UtteranceGenerationPrompt,
)
from usersimcrs.simulator.user_simulator import UserSimulator
from usersimcrs.user_modeling.preference_model import PreferenceModel
from usersimcrs.user_modeling.persona import Persona


Expand All @@ -26,7 +29,8 @@ def __init__(
llm_interface: LLMInterface,
item_type: str,
task_definition: str = DEFAULT_TASK_DEFINITION,
persona: Persona = None,
persona: Optional[Persona] = None,
preference_model: Optional[PreferenceModel] = None,
) -> None:
"""Initializes the user simulator.

Expand All @@ -37,11 +41,16 @@ def __init__(
task_definition: Definition of the task to be performed.
Defaults to DEFAULT_TASK_DEFINITION.
persona: Persona of the user. Defaults to None.
preference_model: Preference model. Defaults to None.
"""
super().__init__(id, domain, item_collection)
super().__init__(id, domain, item_collection, preference_model)
self.llm_interface = llm_interface
self.prompt = UtteranceGenerationPrompt(
self.information_need, item_type, task_definition, persona
self.information_need,
item_type,
task_definition,
persona,
preference_model,
)

def _generate_response(self, agent_utterance: Utterance) -> Utterance:
Expand Down
60 changes: 58 additions & 2 deletions usersimcrs/simulator/llm/prompt/prompt.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
"""Interface for prompt."""

from abc import ABC, abstractmethod
from typing import Optional

from dialoguekit.core.utterance import Utterance
from dialoguekit.participant.participant import DialogueParticipant
from usersimcrs.core.information_need import InformationNeed
from usersimcrs.user_modeling.preference_model import PreferenceModel
from usersimcrs.user_modeling.persona import Persona


Expand All @@ -14,7 +16,8 @@ def __init__(
information_need: InformationNeed,
item_type: str,
prompt_definition: str,
persona: Persona = None,
persona: Optional[Persona] = None,
preference_model: Optional[PreferenceModel] = None,
) -> None:
"""Initializes the prompt.

Expand All @@ -23,18 +26,71 @@ def __init__(
item_type: The type of the item to be recommended.
prompt_definition: The definition of the task to be performed.
persona: The persona of the user. Defaults to None.
preference_model: Preference model. Defaults to None.
"""
self.information_need = information_need
self.item_type = item_type
self.prompt_definition = prompt_definition
self.persona = persona
self.preference_model = preference_model
self._initial_prompt = self.build_new_prompt()
self._prompt_context = ""

@property
def prompt_text(self) -> str:
"""Prompt for the user simulator."""
return self._initial_prompt + "\n" + self._prompt_context
return (
self._initial_prompt
+ "\n"
+ self._preference_context
+ "\n"
+ self._prompt_context
)

@property
def _preference_context(self) -> str:
"""Returns current preference context for the prompt."""
if not self.preference_model:
return ""

preference_summary = self.preference_model.get_preference_summary()
if not preference_summary:
return ""

return (
f"{self._preference_context_label}: "
f"{preference_summary}\n"
f"{self._preference_context_guidance}\n"
)

@property
def _preference_context_label(self) -> str:
"""Returns the label used for preference context."""
return "YOUR PREFERENCES"

@property
def _preference_context_guidance(self) -> str:
"""Returns the guidance appended after the preference summary."""
return (
"Treat these preferences as soft background tastes, not as new "
"requirements."
)

@property
def _persona_text(self) -> str:
"""Returns a compact persona description."""
if not self.persona:
return ""

if self.persona.persona_description:
return self.persona.persona_description

return ", ".join(
[
f"{key}={value}"
for key, value in self.persona.characteristics.items()
]
)
Comment thread
dkkdark marked this conversation as resolved.

@abstractmethod
def build_new_prompt(self, **kwargs) -> str:
Expand Down
48 changes: 34 additions & 14 deletions usersimcrs/simulator/llm/prompt/stop_prompt.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
"""Define the prompt for stopping the conversation."""

from typing import Optional

from usersimcrs.core.information_need import InformationNeed
from usersimcrs.simulator.llm.prompt.prompt import Prompt
from usersimcrs.user_modeling.preference_model import PreferenceModel
from usersimcrs.user_modeling.persona import Persona

DEFAULT_STOP_DEFINITION = (
Expand All @@ -21,7 +24,8 @@ def __init__(
information_need: InformationNeed,
item_type: str,
prompt_definition: str = DEFAULT_STOP_DEFINITION,
persona: Persona = None,
persona: Optional[Persona] = None,
preference_model: Optional[PreferenceModel] = None,
) -> None:
"""Initializes the prompt.

Expand All @@ -31,20 +35,42 @@ def __init__(
prompt_definition: The definition of the task to be performed.
Defaults to DEFAULT_STOP_DEFINITION.
persona: The persona of the user. Defaults to None.
preference_model: Preference model. Defaults to None.
"""
super().__init__(
information_need, item_type, prompt_definition, persona
information_need,
item_type,
prompt_definition,
persona,
preference_model,
)

@property
def prompt_text(self) -> str:
"""Prompt for the user simulator."""
prompt_text = self._initial_prompt

if self._preference_context:
prompt_text += self._preference_context.rstrip("\n")

prompt_text += "\n"

if self._prompt_context:
prompt_text += self._prompt_context.rstrip("\n")

return prompt_text + "\nCONTINUE: "

@property
def _preference_context_label(self) -> str:
"""Returns the label used for preference context."""
return "YOUR PREFERENCES"

@property
def _preference_context_guidance(self) -> str:
"""Returns the guidance appended after the preference summary."""
return (
self._initial_prompt
+ "\n"
+ self._prompt_context
+ "\n"
+ "CONTINUE: "
"Use these preferences only as soft context when deciding "
"whether the conversation is still productive."
)

def build_new_prompt(self) -> str:
Expand All @@ -60,13 +86,7 @@ def build_new_prompt(self) -> str:
" Take into account your PERSONA when deciding to stop the "
"conversation.\n"
)
stringified_characteristics = ", ".join(
[
f"{key}={value}"
for key, value in self.persona.characteristics.items()
]
)
initial_prompt += f"PERSONA: {stringified_characteristics}\n"
initial_prompt += f"PERSONA: {self._persona_text}\n"

initial_prompt += "\nHISTORY:\n"
return initial_prompt
34 changes: 25 additions & 9 deletions usersimcrs/simulator/llm/prompt/utterance_generation_prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
for Task-Oriented Dialog Systems", arXiv 2306.00774.
"""

from typing import Optional

from dialoguekit.core.utterance import Utterance
from dialoguekit.participant.participant import DialogueParticipant
from usersimcrs.core.information_need import InformationNeed
from usersimcrs.simulator.llm.prompt.prompt import Prompt
from usersimcrs.user_modeling.preference_model import PreferenceModel
from usersimcrs.user_modeling.persona import Persona

DEFAULT_TASK_DEFINITION = (
Expand All @@ -34,7 +37,8 @@ def __init__(
information_need: InformationNeed,
item_type: str,
prompt_definition: str = DEFAULT_TASK_DEFINITION,
persona: Persona = None,
persona: Optional[Persona] = None,
preference_model: Optional[PreferenceModel] = None,
) -> None:
"""Initializes the prompt.

Expand All @@ -44,9 +48,14 @@ def __init__(
prompt_definition: The definition of the task to be performed.
Defaults to DEFAULT_TASK_DEFINITION.
persona: The persona of the user. Defaults to None.
preference_model: Preference model. Defaults to None.
"""
super().__init__(
information_need, item_type, prompt_definition, persona
information_need,
item_type,
prompt_definition,
persona,
preference_model,
)

def build_new_prompt(self) -> str:
Expand All @@ -61,13 +70,7 @@ def build_new_prompt(self) -> str:
initial_prompt += (
" Adapt your responses considering your PERSONA.\n"
)
stringified_characteristics = ", ".join(
[
f"{key}={value}"
for key, value in self.persona.characteristics.items()
]
)
initial_prompt += f"PERSONA: {stringified_characteristics}\n"
initial_prompt += f"PERSONA: {self._persona_text}\n"
else:
initial_prompt += (
"Be precise with the REQUIREMENTS, clear and concise.\n"
Expand All @@ -90,6 +93,19 @@ def build_new_prompt(self) -> str:
)
return initial_prompt

@property
def _preference_context_label(self) -> str:
"""Returns the label used for preference context."""
return "YOUR PREFERENCES"

@property
def _preference_context_guidance(self) -> str:
"""Returns the guidance appended after the preference summary."""
return (
"Use these preferences to shape what the user accepts, rejects, "
"asks to avoid, or follows up on."
)

def update_prompt_context(
self, utterance: Utterance, participant: DialogueParticipant
) -> None:
Expand Down
Loading
Loading