fix function calling examples

This commit is contained in:
Aleix Conchillo Flaqué
2024-08-17 23:05:11 -07:00
parent ebc4e0924b
commit 6520f20ffe
16 changed files with 121 additions and 140 deletions

View File

@@ -4,7 +4,7 @@
# SPDX-License-Identifier: BSD 2-Clause License
#
from typing import Any, List, Mapping, Tuple, Optional
from typing import Any, List, Mapping, Optional, Tuple
from dataclasses import dataclass, field
@@ -419,7 +419,7 @@ class TTSStoppedFrame(ControlFrame):
class UserImageRequestFrame(ControlFrame):
"""A frame user to request an image from the given user."""
user_id: str
context: Optional[any]
context: Optional[Any] = None
def __str__(self):
return f"{self.name}, user: {self.user_id}"

View File

@@ -4,25 +4,33 @@
# SPDX-License-Identifier: BSD 2-Clause License
#
from dataclasses import dataclass
import io
import json
from typing import List
from dataclasses import dataclass
from typing import Any, Awaitable, Callable, List
from PIL import Image
from pipecat.frames.frames import Frame, VisionImageRawFrame, FunctionCallInProgressFrame, FunctionCallResultFrame
from pipecat.processors.frame_processor import FrameProcessor
from loguru import logger
from openai._types import NOT_GIVEN, NotGiven
try:
from openai._types import NOT_GIVEN, NotGiven
from openai.types.chat import (
ChatCompletionToolParam,
ChatCompletionToolChoiceOptionParam,
ChatCompletionMessageParam
)
from openai.types.chat import (
ChatCompletionToolParam,
ChatCompletionToolChoiceOptionParam,
ChatCompletionMessageParam
)
except ModuleNotFoundError as e:
logger.error(f"Exception: {e}")
logger.error(
"In order to use OpenAI, you need to `pip install pipecat-ai[openai]`. Also, set `OPENAI_API_KEY` environment variable.")
raise Exception(f"Missing module: {e}")
# JSON custom encoder to handle bytes arrays so that we can log contexts
# with images to the console.
@@ -121,14 +129,20 @@ class OpenAILLMContext:
tools = NOT_GIVEN
self._tools = tools
async def call_function(
self,
f: callable,
*,
function_name: str,
tool_call_id: str,
arguments: str,
llm: FrameProcessor) -> None:
async def call_function(self,
f: Callable[[str,
str,
Any,
FrameProcessor,
'OpenAILLMContext',
Callable[[Any],
Awaitable[None]]],
Awaitable[None]],
*,
function_name: str,
tool_call_id: str,
arguments: str,
llm: FrameProcessor) -> None:
# Push a SystemFrame downstream. This frame will let our assistant context aggregator
# know that we are in the middle of a function call. Some contexts/aggregators may
@@ -146,8 +160,7 @@ class OpenAILLMContext:
tool_call_id=tool_call_id,
arguments=arguments,
result=result))
await f(function_name=function_name, tool_call_id=tool_call_id, arguments=arguments,
context=self, result_callback=function_call_result_callback)
await f(function_name, tool_call_id, arguments, llm, self, function_call_result_callback)
@dataclass

View File

@@ -25,6 +25,7 @@ from pipecat.frames.frames import (
UserStartedSpeakingFrame,
FunctionCallResultFrame,
UserStoppedSpeakingFrame)
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
from pipecat.transports.base_transport import BaseTransport
@@ -310,7 +311,8 @@ class RTVIProcessor(FrameProcessor):
function_name: str,
tool_call_id: str,
arguments: dict,
context,
llm: FrameProcessor,
context: OpenAILLMContext,
result_callback):
fn = RTVILLMFunctionCallMessageData(
function_name=function_name,
@@ -319,7 +321,11 @@ class RTVIProcessor(FrameProcessor):
message = RTVILLMFunctionCallMessage(data=fn)
await self._push_transport_message(message, exclude_none=False)
async def handle_function_call_start(self, function_name: str):
async def handle_function_call_start(
self,
llm: FrameProcessor,
context: OpenAILLMContext,
function_name: str):
fn = RTVILLMFunctionCallStartMessageData(function_name=function_name)
message = RTVILLMFunctionCallStartMessage(data=fn)
await self._push_transport_message(message, exclude_none=False)

View File

@@ -27,7 +27,8 @@ try:
from gi.repository import Gst, GstApp
except ModuleNotFoundError as e:
logger.error(f"Exception: {e}")
logger.error("In order to use GStreamer processors, you need to install GStreamer in your system`.")
logger.error(
"In order to use GStreamer, you need to `pip install pipecat-ai[gstreamer]`. Also, you need to install GStreamer in your system.")
raise Exception(f"Missing module: {e}")

View File

@@ -137,11 +137,11 @@ class LLMService(AIService):
llm=self)
# QUESTION FOR CB: maybe this isn't needed anymore?
async def call_start_function(self, function_name: str):
async def call_start_function(self, context: OpenAILLMContext, function_name: str):
if function_name in self._start_callbacks.keys():
await self._start_callbacks[function_name](self)
await self._start_callbacks[function_name](self, context, function_name)
elif None in self._start_callbacks.keys():
return await self._start_callbacks[None](function_name)
return await self._start_callbacks[None](self, context, function_name)
class TTSService(AIService):

View File

@@ -481,9 +481,6 @@ class AnthropicAssistantContextAggregator(LLMAssistantContextAggregator):
elif isinstance(frame, AnthropicImageMessageFrame):
self._pending_image_frame_message = frame
def add_message(self, message):
self._user_context_aggregator.add_message(message)
async def _push_aggregation(self):
if not self._aggregation:
return

View File

@@ -167,7 +167,7 @@ class BaseOpenAILLMService(LLMService):
if tool_call.function and tool_call.function.name:
function_name += tool_call.function.name
tool_call_id = tool_call.id
await self.call_start_function(function_name)
await self.call_start_function(context, function_name)
if tool_call.function and tool_call.function.arguments:
# Keep iterating through the response to collect all the argument fragments
arguments += tool_call.function.arguments
@@ -387,9 +387,6 @@ class OpenAIAssistantContextAggregator(LLMAssistantContextAggregator):
self._function_call_in_progress = None
self._function_call_result = None
def add_message(self, message):
self._user_context_aggregator.add_message(message)
async def _push_aggregation(self):
if not (self._aggregation or self._function_call_result):
return

View File

@@ -24,7 +24,7 @@ try:
except ModuleNotFoundError as e:
logger.error(f"Exception: {e}")
logger.error(
"In order to use local audio, you need to `pip install pipecat-ai[audio]`. On MacOS, you also need to `brew install portaudio`.")
"In order to use local audio, you need to `pip install pipecat-ai[local]`. On MacOS, you also need to `brew install portaudio`.")
raise Exception(f"Missing module: {e}")
try: