Merge pull request #520 from pipecat-ai/khk/context-frame-push
pushing context frames from assistant aggregators
This commit is contained in:
@@ -5,29 +5,24 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
from pipecat.frames.frames import LLMMessagesFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
from pipecat.processors.aggregators.llm_response import (
|
from pipecat.services.ai_services import OpenAILLMContext
|
||||||
LLMAssistantResponseAggregator,
|
|
||||||
LLMUserResponseAggregator,
|
|
||||||
)
|
|
||||||
from pipecat.services.cartesia import CartesiaTTSService
|
from pipecat.services.cartesia import CartesiaTTSService
|
||||||
from pipecat.services.together import TogetherLLMService
|
from pipecat.services.together import TogetherLLMService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
from pipecat.vad.silero import SileroVADAnalyzer
|
from pipecat.vad.silero import SileroVADAnalyzer
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -76,17 +71,19 @@ async def main():
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
tma_in = LLMUserResponseAggregator(messages)
|
context = OpenAILLMContext(messages)
|
||||||
tma_out = LLMAssistantResponseAggregator(messages)
|
context_aggregator = llm.create_context_aggregator(context)
|
||||||
|
user_aggregator = context_aggregator.user()
|
||||||
|
assistant_aggregator = context_aggregator.assistant()
|
||||||
|
|
||||||
pipeline = Pipeline(
|
pipeline = Pipeline(
|
||||||
[
|
[
|
||||||
transport.input(), # Transport user input
|
transport.input(), # Transport user input
|
||||||
tma_in, # User responses
|
user_aggregator, # User responses
|
||||||
llm, # LLM
|
llm, # LLM
|
||||||
tts, # TTS
|
tts, # TTS
|
||||||
transport.output(), # Transport bot output
|
transport.output(), # Transport bot output
|
||||||
tma_out, # Assistant spoken responses
|
assistant_aggregator, # Assistant spoken responses
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,6 @@
|
|||||||
|
|
||||||
from typing import List, Type
|
from typing import List, Type
|
||||||
|
|
||||||
from pipecat.processors.aggregators.openai_llm_context import (
|
|
||||||
OpenAILLMContextFrame,
|
|
||||||
OpenAILLMContext,
|
|
||||||
)
|
|
||||||
|
|
||||||
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
Frame,
|
Frame,
|
||||||
InterimTranscriptionFrame,
|
InterimTranscriptionFrame,
|
||||||
@@ -22,11 +16,16 @@ from pipecat.frames.frames import (
|
|||||||
LLMMessagesUpdateFrame,
|
LLMMessagesUpdateFrame,
|
||||||
LLMSetToolsFrame,
|
LLMSetToolsFrame,
|
||||||
StartInterruptionFrame,
|
StartInterruptionFrame,
|
||||||
TranscriptionFrame,
|
|
||||||
TextFrame,
|
TextFrame,
|
||||||
|
TranscriptionFrame,
|
||||||
UserStartedSpeakingFrame,
|
UserStartedSpeakingFrame,
|
||||||
UserStoppedSpeakingFrame,
|
UserStoppedSpeakingFrame,
|
||||||
)
|
)
|
||||||
|
from pipecat.processors.aggregators.openai_llm_context import (
|
||||||
|
OpenAILLMContext,
|
||||||
|
OpenAILLMContextFrame,
|
||||||
|
)
|
||||||
|
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
||||||
|
|
||||||
|
|
||||||
class LLMResponseAggregator(FrameProcessor):
|
class LLMResponseAggregator(FrameProcessor):
|
||||||
@@ -40,6 +39,7 @@ class LLMResponseAggregator(FrameProcessor):
|
|||||||
accumulator_frame: Type[TextFrame],
|
accumulator_frame: Type[TextFrame],
|
||||||
interim_accumulator_frame: Type[TextFrame] | None = None,
|
interim_accumulator_frame: Type[TextFrame] | None = None,
|
||||||
handle_interruptions: bool = False,
|
handle_interruptions: bool = False,
|
||||||
|
expect_stripped_words: bool = True, # if True, need to add spaces between words
|
||||||
):
|
):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
@@ -50,6 +50,7 @@ class LLMResponseAggregator(FrameProcessor):
|
|||||||
self._accumulator_frame = accumulator_frame
|
self._accumulator_frame = accumulator_frame
|
||||||
self._interim_accumulator_frame = interim_accumulator_frame
|
self._interim_accumulator_frame = interim_accumulator_frame
|
||||||
self._handle_interruptions = handle_interruptions
|
self._handle_interruptions = handle_interruptions
|
||||||
|
self._expect_stripped_words = expect_stripped_words
|
||||||
|
|
||||||
# Reset our accumulator state.
|
# Reset our accumulator state.
|
||||||
self._reset()
|
self._reset()
|
||||||
@@ -111,7 +112,10 @@ class LLMResponseAggregator(FrameProcessor):
|
|||||||
await self.push_frame(frame, direction)
|
await self.push_frame(frame, direction)
|
||||||
elif isinstance(frame, self._accumulator_frame):
|
elif isinstance(frame, self._accumulator_frame):
|
||||||
if self._aggregating:
|
if self._aggregating:
|
||||||
self._aggregation += f" {frame.text}" if self._aggregation else frame.text
|
if self._expect_stripped_words:
|
||||||
|
self._aggregation += f" {frame.text}" if self._aggregation else frame.text
|
||||||
|
else:
|
||||||
|
self._aggregation += frame.text
|
||||||
# We have recevied a complete sentence, so if we have seen the
|
# We have recevied a complete sentence, so if we have seen the
|
||||||
# end frame and we were still aggregating, it means we should
|
# end frame and we were still aggregating, it means we should
|
||||||
# send the aggregation.
|
# send the aggregation.
|
||||||
@@ -290,7 +294,7 @@ class LLMContextAggregator(LLMResponseAggregator):
|
|||||||
|
|
||||||
|
|
||||||
class LLMAssistantContextAggregator(LLMContextAggregator):
|
class LLMAssistantContextAggregator(LLMContextAggregator):
|
||||||
def __init__(self, context: OpenAILLMContext):
|
def __init__(self, context: OpenAILLMContext, *, expect_stripped_words: bool = True):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
messages=[],
|
messages=[],
|
||||||
context=context,
|
context=context,
|
||||||
@@ -299,6 +303,7 @@ class LLMAssistantContextAggregator(LLMContextAggregator):
|
|||||||
end_frame=LLMFullResponseEndFrame,
|
end_frame=LLMFullResponseEndFrame,
|
||||||
accumulator_frame=TextFrame,
|
accumulator_frame=TextFrame,
|
||||||
handle_interruptions=True,
|
handle_interruptions=True,
|
||||||
|
expect_stripped_words=expect_stripped_words,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -110,9 +110,13 @@ class AnthropicLLMService(LLMService):
|
|||||||
return self._enable_prompt_caching_beta
|
return self._enable_prompt_caching_beta
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_context_aggregator(context: OpenAILLMContext) -> AnthropicContextAggregatorPair:
|
def create_context_aggregator(
|
||||||
|
context: OpenAILLMContext, *, assistant_expect_stripped_words: bool = True
|
||||||
|
) -> AnthropicContextAggregatorPair:
|
||||||
user = AnthropicUserContextAggregator(context)
|
user = AnthropicUserContextAggregator(context)
|
||||||
assistant = AnthropicAssistantContextAggregator(user)
|
assistant = AnthropicAssistantContextAggregator(
|
||||||
|
user, expect_stripped_words=assistant_expect_stripped_words
|
||||||
|
)
|
||||||
return AnthropicContextAggregatorPair(_user=user, _assistant=assistant)
|
return AnthropicContextAggregatorPair(_user=user, _assistant=assistant)
|
||||||
|
|
||||||
async def set_enable_prompt_caching_beta(self, enable_prompt_caching_beta: bool):
|
async def set_enable_prompt_caching_beta(self, enable_prompt_caching_beta: bool):
|
||||||
@@ -541,8 +545,8 @@ class AnthropicUserContextAggregator(LLMUserContextAggregator):
|
|||||||
|
|
||||||
|
|
||||||
class AnthropicAssistantContextAggregator(LLMAssistantContextAggregator):
|
class AnthropicAssistantContextAggregator(LLMAssistantContextAggregator):
|
||||||
def __init__(self, user_context_aggregator: AnthropicUserContextAggregator):
|
def __init__(self, user_context_aggregator: AnthropicUserContextAggregator, **kwargs):
|
||||||
super().__init__(context=user_context_aggregator._context)
|
super().__init__(context=user_context_aggregator._context, **kwargs)
|
||||||
self._user_context_aggregator = user_context_aggregator
|
self._user_context_aggregator = user_context_aggregator
|
||||||
self._function_call_in_progress = None
|
self._function_call_in_progress = None
|
||||||
self._function_call_result = None
|
self._function_call_result = None
|
||||||
@@ -579,7 +583,7 @@ class AnthropicAssistantContextAggregator(LLMAssistantContextAggregator):
|
|||||||
run_llm = False
|
run_llm = False
|
||||||
|
|
||||||
aggregation = self._aggregation
|
aggregation = self._aggregation
|
||||||
self._aggregation = ""
|
self._reset()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if self._function_call_result:
|
if self._function_call_result:
|
||||||
@@ -630,5 +634,8 @@ class AnthropicAssistantContextAggregator(LLMAssistantContextAggregator):
|
|||||||
if run_llm:
|
if run_llm:
|
||||||
await self._user_context_aggregator.push_context_frame()
|
await self._user_context_aggregator.push_context_frame()
|
||||||
|
|
||||||
|
frame = OpenAILLMContextFrame(self._context)
|
||||||
|
await self.push_frame(frame)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error processing frame: {e}")
|
logger.error(f"Error processing frame: {e}")
|
||||||
|
|||||||
@@ -336,9 +336,13 @@ class OpenAILLMService(BaseOpenAILLMService):
|
|||||||
super().__init__(model=model, params=params, **kwargs)
|
super().__init__(model=model, params=params, **kwargs)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_context_aggregator(context: OpenAILLMContext) -> OpenAIContextAggregatorPair:
|
def create_context_aggregator(
|
||||||
|
context: OpenAILLMContext, *, assistant_expect_stripped_words: bool = True
|
||||||
|
) -> OpenAIContextAggregatorPair:
|
||||||
user = OpenAIUserContextAggregator(context)
|
user = OpenAIUserContextAggregator(context)
|
||||||
assistant = OpenAIAssistantContextAggregator(user)
|
assistant = OpenAIAssistantContextAggregator(
|
||||||
|
user, expect_stripped_words=assistant_expect_stripped_words
|
||||||
|
)
|
||||||
return OpenAIContextAggregatorPair(_user=user, _assistant=assistant)
|
return OpenAIContextAggregatorPair(_user=user, _assistant=assistant)
|
||||||
|
|
||||||
|
|
||||||
@@ -458,8 +462,8 @@ class OpenAIUserContextAggregator(LLMUserContextAggregator):
|
|||||||
|
|
||||||
|
|
||||||
class OpenAIAssistantContextAggregator(LLMAssistantContextAggregator):
|
class OpenAIAssistantContextAggregator(LLMAssistantContextAggregator):
|
||||||
def __init__(self, user_context_aggregator: OpenAIUserContextAggregator):
|
def __init__(self, user_context_aggregator: OpenAIUserContextAggregator, **kwargs):
|
||||||
super().__init__(context=user_context_aggregator._context)
|
super().__init__(context=user_context_aggregator._context, **kwargs)
|
||||||
self._user_context_aggregator = user_context_aggregator
|
self._user_context_aggregator = user_context_aggregator
|
||||||
self._function_call_in_progress = None
|
self._function_call_in_progress = None
|
||||||
self._function_call_result = None
|
self._function_call_result = None
|
||||||
@@ -495,7 +499,7 @@ class OpenAIAssistantContextAggregator(LLMAssistantContextAggregator):
|
|||||||
run_llm = False
|
run_llm = False
|
||||||
|
|
||||||
aggregation = self._aggregation
|
aggregation = self._aggregation
|
||||||
self._aggregation = ""
|
self._reset()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if self._function_call_result:
|
if self._function_call_result:
|
||||||
@@ -531,5 +535,8 @@ class OpenAIAssistantContextAggregator(LLMAssistantContextAggregator):
|
|||||||
if run_llm:
|
if run_llm:
|
||||||
await self._user_context_aggregator.push_context_frame()
|
await self._user_context_aggregator.push_context_frame()
|
||||||
|
|
||||||
|
frame = OpenAILLMContextFrame(self._context)
|
||||||
|
await self.push_frame(frame)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error processing frame: {e}")
|
logger.error(f"Error processing frame: {e}")
|
||||||
|
|||||||
@@ -95,9 +95,13 @@ class TogetherLLMService(LLMService):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_context_aggregator(context: OpenAILLMContext) -> TogetherContextAggregatorPair:
|
def create_context_aggregator(
|
||||||
|
context: OpenAILLMContext, *, assistant_expect_stripped_words: bool = True
|
||||||
|
) -> TogetherContextAggregatorPair:
|
||||||
user = TogetherUserContextAggregator(context)
|
user = TogetherUserContextAggregator(context)
|
||||||
assistant = TogetherAssistantContextAggregator(user)
|
assistant = TogetherAssistantContextAggregator(
|
||||||
|
user, expect_stripped_words=assistant_expect_stripped_words
|
||||||
|
)
|
||||||
return TogetherContextAggregatorPair(_user=user, _assistant=assistant)
|
return TogetherContextAggregatorPair(_user=user, _assistant=assistant)
|
||||||
|
|
||||||
async def set_frequency_penalty(self, frequency_penalty: float):
|
async def set_frequency_penalty(self, frequency_penalty: float):
|
||||||
@@ -331,8 +335,8 @@ class TogetherUserContextAggregator(LLMUserContextAggregator):
|
|||||||
|
|
||||||
|
|
||||||
class TogetherAssistantContextAggregator(LLMAssistantContextAggregator):
|
class TogetherAssistantContextAggregator(LLMAssistantContextAggregator):
|
||||||
def __init__(self, user_context_aggregator: TogetherUserContextAggregator):
|
def __init__(self, user_context_aggregator: TogetherUserContextAggregator, **kwargs):
|
||||||
super().__init__(context=user_context_aggregator._context)
|
super().__init__(context=user_context_aggregator._context, **kwargs)
|
||||||
self._user_context_aggregator = user_context_aggregator
|
self._user_context_aggregator = user_context_aggregator
|
||||||
self._function_call_in_progress = None
|
self._function_call_in_progress = None
|
||||||
self._function_call_result = None
|
self._function_call_result = None
|
||||||
@@ -370,7 +374,7 @@ class TogetherAssistantContextAggregator(LLMAssistantContextAggregator):
|
|||||||
run_llm = False
|
run_llm = False
|
||||||
|
|
||||||
aggregation = self._aggregation
|
aggregation = self._aggregation
|
||||||
self._aggregation = ""
|
self._reset()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if self._function_call_result:
|
if self._function_call_result:
|
||||||
@@ -390,5 +394,8 @@ class TogetherAssistantContextAggregator(LLMAssistantContextAggregator):
|
|||||||
if run_llm:
|
if run_llm:
|
||||||
await self._user_context_aggregator.push_messages_frame()
|
await self._user_context_aggregator.push_messages_frame()
|
||||||
|
|
||||||
|
frame = OpenAILLMContextFrame(self._context)
|
||||||
|
await self.push_frame(frame)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error processing frame: {e}")
|
logger.error(f"Error processing frame: {e}")
|
||||||
|
|||||||
Reference in New Issue
Block a user