Merge pull request #381 from pipecat-ai/khk/anthropic-fixup-0814.2

Fixup anthropic context set_messages
This commit is contained in:
Kwindla Hultman Kramer
2024-08-14 23:34:31 -07:00
committed by GitHub
3 changed files with 38 additions and 24 deletions

View File

@@ -62,7 +62,7 @@ async def main():
)
llm = AnthropicLLMService(
api_key=os.getenv("OPENAI_API_KEY"),
api_key=os.getenv("ANTHROPIC_API_KEY"),
model="claude-3-5-sonnet-20240620"
)
llm.register_function("get_weather", get_weather)
@@ -86,10 +86,12 @@ async def main():
# todo: test with very short initial user message
messages = [{"role": "system",
"content": "You are a helpful assistant who can report the weather in any location in the universe. Respond concisely. Your response will be turned into speech so use only simple words and punctuation."},
{"role": "user",
"content": " Start the conversation by introducing yourself."}]
# messages = [{"role": "system",
# "content": "You are a helpful assistant who can report the weather in any location in the universe. Respond concisely. Your response will be turned into speech so use only simple words and punctuation."},
# {"role": "user",
# "content": " Start the conversation by introducing yourself."}]
messages = [{"role": "user", "content": "Say 'hello' to start the conversation."}]
context = OpenAILLMContext(messages, tools)
context_aggregator = llm.create_context_aggregator(context)
@@ -109,7 +111,7 @@ async def main():
async def on_first_participant_joined(transport, participant):
transport.capture_participant_transcription(participant["id"])
# Kick off the conversation.
await task.queue_frames([LLMMessagesFrame(messages)])
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner()

View File

@@ -137,7 +137,8 @@ If you need to use a tool, simply use the tool. Do not tell the user the tool yo
"""
messages = [{"role": "system",
"content": system_prompt,
"content": system_prompt},
{"role": "user",
"content": "Start the conversation by introducing yourself."}]
context = OpenAILLMContext(messages, tools)
@@ -161,7 +162,7 @@ If you need to use a tool, simply use the tool. Do not tell the user the tool yo
transport.capture_participant_transcription(video_participant_id)
transport.capture_participant_video(video_participant_id, framerate=0)
# Kick off the conversation.
await task.queue_frames([LLMMessagesFrame(messages)])
await task.queue_frames([context_aggregator.user().get_context_frame()])
runner = PipelineRunner()
await runner.run(task)

View File

@@ -102,13 +102,15 @@ class AnthropicLLMService(LLMService):
await self.push_frame(LLMFullResponseStartFrame())
await self.start_processing_metrics()
logger.debug(f"Generating chat: {context.get_messages_for_logging()}")
logger.debug(
f"Generating chat: {context.system} | {context.get_messages_for_logging()}")
messages = context.messages
await self.start_ttfb_metrics()
response = await self._client.messages.create(
system=context.system or [],
messages=messages,
tools=context.tools or [],
model=self._model,
@@ -234,12 +236,12 @@ class AnthropicLLMContext(OpenAILLMContext):
tools: list[dict] | None = None,
tool_choice: dict | None = None,
*,
system: str | None = None
system: List | None = None
):
super().__init__(messages=messages, tools=tools, tool_choice=tool_choice)
self._user_image_request_context = {}
self.system_message = system
self.system = system
@classmethod
def from_openai_context(cls, openai_context: OpenAILLMContext):
@@ -248,23 +250,14 @@ class AnthropicLLMContext(OpenAILLMContext):
tools=openai_context.tools,
tool_choice=openai_context.tool_choice,
)
# See if we should pull the system message out of our context.messages list. (For
# compatibility with Open AI messages format.)
if self.messages and self.messages[0]["role"] == "system":
if len(self.messages) == 1:
# If we have only have a system message in the list, all we can really do
# without introducing too much magic is change the role to "user".
self.messages[0]["role"] = "user"
else:
# If we have more than one message, we'll pull the system message out of the
# list.
self.system_message = self.messages[0]["content"]
self.messages.pop(0)
self._restructure_from_openai_messages()
return self
@classmethod
def from_messages(cls, messages: List[dict]) -> "AnthropicLLMContext":
return cls(messages=messages)
self = cls(messages=messages)
self._restructure_from_openai_messages()
return self
@classmethod
def from_image_frame(cls, frame: VisionImageRawFrame) -> "AnthropicLLMContext":
@@ -276,6 +269,10 @@ class AnthropicLLMContext(OpenAILLMContext):
text=frame.text)
return context
def set_messages(self, messages: List):
self._messages[:] = messages
self._restructure_from_openai_messages()
def add_image_frame_message(
self, *, format: str, size: tuple[int, int], image: bytes, text: str = None):
buffer = io.BytesIO()
@@ -316,6 +313,20 @@ class AnthropicLLMContext(OpenAILLMContext):
except Exception as e:
logger.error(f"Error adding message: {e}")
def _restructure_from_openai_messages(self):
# See if we should pull the system message out of our context.messages list. (For
# compatibility with Open AI messages format.)
if self.messages and self.messages[0]["role"] == "system":
if len(self.messages) == 1:
# If we have only have a system message in the list, all we can really do
# without introducing too much magic is change the role to "user".
self.messages[0]["role"] = "user"
else:
# If we have more than one message, we'll pull the system message out of the
# list.
self.system = self.messages[0]["content"]
self.messages.pop(0)
def get_messages_for_logging(self) -> str:
msgs = []
for message in self.messages: