fix function calling examples
This commit is contained in:
@@ -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}"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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}")
|
||||
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user