processors(rtvi): refactor to allow future custom pipelines
This commit is contained in:
@@ -7,8 +7,8 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import dataclasses
|
import dataclasses
|
||||||
|
|
||||||
from typing import List, Literal, Optional, Type
|
from typing import Any, Awaitable, Callable, Dict, List, Literal, Optional, Type
|
||||||
from pydantic import BaseModel, ValidationError
|
from pydantic import PrivateAttr, BaseModel, ValidationError
|
||||||
|
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
BotInterruptionFrame,
|
BotInterruptionFrame,
|
||||||
@@ -33,62 +33,76 @@ from pipecat.pipeline.pipeline import Pipeline
|
|||||||
from pipecat.processors.aggregators.llm_response import (
|
from pipecat.processors.aggregators.llm_response import (
|
||||||
LLMAssistantResponseAggregator, LLMUserResponseAggregator)
|
LLMAssistantResponseAggregator, LLMUserResponseAggregator)
|
||||||
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
||||||
from pipecat.services.ai_services import AIService
|
|
||||||
from pipecat.services.cartesia import CartesiaTTSService
|
from pipecat.services.cartesia import CartesiaTTSService
|
||||||
from pipecat.services.openai import OpenAILLMService, OpenAILLMContext
|
from pipecat.services.openai import OpenAILLMService, OpenAILLMContext
|
||||||
from pipecat.transports.base_transport import BaseTransport
|
from pipecat.transports.base_transport import BaseTransport
|
||||||
|
|
||||||
DEFAULT_MESSAGES = [
|
from loguru import logger
|
||||||
{
|
|
||||||
"role": "system",
|
|
||||||
"content": "You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities in a succinct way. Your output will be converted to audio so don't include special characters in your answers. Respond to what the user said in a creative and helpful way.",
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
DEFAULT_MODEL = "llama3-70b-8192"
|
|
||||||
|
|
||||||
DEFAULT_VOICE = "79a125e8-cd45-4c13-8a67-188112f4dd22"
|
|
||||||
|
|
||||||
|
|
||||||
class RTVILLMConfig(BaseModel):
|
class RTVIServiceOption(BaseModel):
|
||||||
model: Optional[str] = None
|
name: str
|
||||||
messages: Optional[List[dict]] = None
|
handler: Optional[Callable[['RTVIProcessor',
|
||||||
|
'RTVIServiceOptionConfig'],
|
||||||
|
Awaitable[None]]] = None
|
||||||
|
|
||||||
|
|
||||||
class RTVITTSConfig(BaseModel):
|
class RTVIService(BaseModel):
|
||||||
voice: Optional[str] = None
|
name: str
|
||||||
|
cls: Type[FrameProcessor]
|
||||||
|
options: List[RTVIServiceOption]
|
||||||
|
_options_dict: Dict[str, RTVIServiceOption] = PrivateAttr(default={})
|
||||||
|
|
||||||
|
def model_post_init(self, __context: Any) -> None:
|
||||||
|
self._options_dict = {}
|
||||||
|
for option in self.options:
|
||||||
|
self._options_dict[option.name] = option
|
||||||
|
return super().model_post_init(__context)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Client -> Pipecat messages.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
class RTVIServiceOptionConfig(BaseModel):
|
||||||
|
name: str
|
||||||
|
value: Any
|
||||||
|
|
||||||
|
|
||||||
|
class RTVIServiceConfig(BaseModel):
|
||||||
|
service: str
|
||||||
|
options: List[RTVIServiceOptionConfig]
|
||||||
|
|
||||||
|
|
||||||
class RTVIConfig(BaseModel):
|
class RTVIConfig(BaseModel):
|
||||||
llm: Optional[RTVILLMConfig] = None
|
config: List[RTVIServiceConfig]
|
||||||
tts: Optional[RTVITTSConfig] = None
|
_config_dict: Dict[str, RTVIServiceConfig] = PrivateAttr(default={})
|
||||||
|
|
||||||
|
def model_post_init(self, __context: Any) -> None:
|
||||||
|
self._config_dict = {}
|
||||||
|
for c in self.config:
|
||||||
|
self._config_dict[c.service] = c
|
||||||
|
return super().model_post_init(__context)
|
||||||
|
|
||||||
|
|
||||||
class RTVISetup(BaseModel):
|
class RTVILLMContextData(BaseModel):
|
||||||
config: Optional[RTVIConfig] = None
|
|
||||||
|
|
||||||
|
|
||||||
class RTVILLMMessageData(BaseModel):
|
|
||||||
messages: List[dict]
|
messages: List[dict]
|
||||||
|
|
||||||
|
|
||||||
class RTVITTSMessageData(BaseModel):
|
class RTVITTSSpeakData(BaseModel):
|
||||||
text: str
|
text: str
|
||||||
interrupt: Optional[bool] = False
|
interrupt: Optional[bool] = False
|
||||||
|
|
||||||
|
|
||||||
class RTVIMessageData(BaseModel):
|
|
||||||
setup: Optional[RTVISetup] = None
|
|
||||||
config: Optional[RTVIConfig] = None
|
|
||||||
llm: Optional[RTVILLMMessageData] = None
|
|
||||||
tts: Optional[RTVITTSMessageData] = None
|
|
||||||
|
|
||||||
|
|
||||||
class RTVIMessage(BaseModel):
|
class RTVIMessage(BaseModel):
|
||||||
label: Literal["rtvi"] = "rtvi"
|
label: Literal["rtvi-ai"] = "rtvi-ai"
|
||||||
type: str
|
type: str
|
||||||
id: str
|
id: str
|
||||||
data: Optional[RTVIMessageData] = None
|
data: Optional[Dict[str, Any]] = None
|
||||||
|
|
||||||
|
#
|
||||||
|
# Pipecat -> Client responses and messages.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
class RTVIResponseData(BaseModel):
|
class RTVIResponseData(BaseModel):
|
||||||
@@ -97,7 +111,7 @@ class RTVIResponseData(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class RTVIResponse(BaseModel):
|
class RTVIResponse(BaseModel):
|
||||||
label: Literal["rtvi"] = "rtvi"
|
label: Literal["rtvi-ai"] = "rtvi-ai"
|
||||||
type: Literal["response"] = "response"
|
type: Literal["response"] = "response"
|
||||||
id: str
|
id: str
|
||||||
data: RTVIResponseData
|
data: RTVIResponseData
|
||||||
@@ -108,7 +122,7 @@ class RTVIErrorData(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class RTVIError(BaseModel):
|
class RTVIError(BaseModel):
|
||||||
label: Literal["rtvi"] = "rtvi"
|
label: Literal["rtvi-ai"] = "rtvi-ai"
|
||||||
type: Literal["error"] = "error"
|
type: Literal["error"] = "error"
|
||||||
data: RTVIErrorData
|
data: RTVIErrorData
|
||||||
|
|
||||||
@@ -118,7 +132,7 @@ class RTVILLMContextMessageData(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class RTVILLMContextMessage(BaseModel):
|
class RTVILLMContextMessage(BaseModel):
|
||||||
label: Literal["rtvi"] = "rtvi"
|
label: Literal["rtvi-ai"] = "rtvi-ai"
|
||||||
type: Literal["llm-context"] = "llm-context"
|
type: Literal["llm-context"] = "llm-context"
|
||||||
data: RTVILLMContextMessageData
|
data: RTVILLMContextMessageData
|
||||||
|
|
||||||
@@ -128,13 +142,13 @@ class RTVITTSTextMessageData(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class RTVITTSTextMessage(BaseModel):
|
class RTVITTSTextMessage(BaseModel):
|
||||||
label: Literal["rtvi"] = "rtvi"
|
label: Literal["rtvi-ai"] = "rtvi-ai"
|
||||||
type: Literal["tts-text"] = "tts-text"
|
type: Literal["tts-text"] = "tts-text"
|
||||||
data: RTVITTSTextMessageData
|
data: RTVITTSTextMessageData
|
||||||
|
|
||||||
|
|
||||||
class RTVIBotReady(BaseModel):
|
class RTVIBotReady(BaseModel):
|
||||||
label: Literal["rtvi"] = "rtvi"
|
label: Literal["rtvi-ai"] = "rtvi-ai"
|
||||||
type: Literal["bot-ready"] = "bot-ready"
|
type: Literal["bot-ready"] = "bot-ready"
|
||||||
|
|
||||||
|
|
||||||
@@ -146,23 +160,23 @@ class RTVITranscriptionMessageData(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class RTVITranscriptionMessage(BaseModel):
|
class RTVITranscriptionMessage(BaseModel):
|
||||||
label: Literal["rtvi"] = "rtvi"
|
label: Literal["rtvi-ai"] = "rtvi-ai"
|
||||||
type: Literal["user-transcription"] = "user-transcription"
|
type: Literal["user-transcription"] = "user-transcription"
|
||||||
data: RTVITranscriptionMessageData
|
data: RTVITranscriptionMessageData
|
||||||
|
|
||||||
|
|
||||||
class RTVIUserStartedSpeakingMessage(BaseModel):
|
class RTVIUserStartedSpeakingMessage(BaseModel):
|
||||||
label: Literal["rtvi"] = "rtvi"
|
label: Literal["rtvi-ai"] = "rtvi-ai"
|
||||||
type: Literal["user-started-speaking"] = "user-started-speaking"
|
type: Literal["user-started-speaking"] = "user-started-speaking"
|
||||||
|
|
||||||
|
|
||||||
class RTVIUserStoppedSpeakingMessage(BaseModel):
|
class RTVIUserStoppedSpeakingMessage(BaseModel):
|
||||||
label: Literal["rtvi"] = "rtvi"
|
label: Literal["rtvi-ai"] = "rtvi-ai"
|
||||||
type: Literal["user-stopped-speaking"] = "user-stopped-speaking"
|
type: Literal["user-stopped-speaking"] = "user-stopped-speaking"
|
||||||
|
|
||||||
|
|
||||||
class RTVIJSONCompletion(BaseModel):
|
class RTVIJSONCompletion(BaseModel):
|
||||||
label: Literal["rtvi"] = "rtvi"
|
label: Literal["rtvi-ai"] = "rtvi-ai"
|
||||||
type: Literal["json-completion"] = "json-completion"
|
type: Literal["json-completion"] = "json-completion"
|
||||||
data: str
|
data: str
|
||||||
|
|
||||||
@@ -265,29 +279,45 @@ class RTVITTSTextProcessor(FrameProcessor):
|
|||||||
await self.push_frame(TransportMessageFrame(message=message.model_dump(exclude_none=True)))
|
await self.push_frame(TransportMessageFrame(message=message.model_dump(exclude_none=True)))
|
||||||
|
|
||||||
|
|
||||||
|
async def handle_llm_model_update(rtvi: 'RTVIProcessor', option: RTVIServiceOptionConfig):
|
||||||
|
frame = LLMModelUpdateFrame(option.value)
|
||||||
|
await rtvi.push_frame(frame)
|
||||||
|
|
||||||
|
|
||||||
|
async def handle_llm_messages_update(rtvi: 'RTVIProcessor', option: RTVIServiceOptionConfig):
|
||||||
|
frame = LLMMessagesUpdateFrame(option.value)
|
||||||
|
await rtvi.push_frame(frame)
|
||||||
|
|
||||||
|
|
||||||
|
async def handle_tts_voice_update(rtvi: 'RTVIProcessor', option: RTVIServiceOptionConfig):
|
||||||
|
frame = TTSVoiceUpdateFrame(option.value)
|
||||||
|
await rtvi.push_frame(frame)
|
||||||
|
|
||||||
|
DEFAULT_LLM_SERVICE = RTVIService(
|
||||||
|
name="llm",
|
||||||
|
cls=OpenAILLMService,
|
||||||
|
options=[
|
||||||
|
RTVIServiceOption(name="model", handler=handle_llm_model_update),
|
||||||
|
RTVIServiceOption(name="messages", handler=handle_llm_messages_update)
|
||||||
|
])
|
||||||
|
|
||||||
|
DEFAULT_TTS_SERVICE = RTVIService(
|
||||||
|
name="tts",
|
||||||
|
cls=CartesiaTTSService,
|
||||||
|
options=[
|
||||||
|
RTVIServiceOption(name="voice_id", handler=handle_tts_voice_update),
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
class RTVIProcessor(FrameProcessor):
|
class RTVIProcessor(FrameProcessor):
|
||||||
|
|
||||||
def __init__(
|
def __init__(self, *, transport: BaseTransport):
|
||||||
self,
|
|
||||||
*,
|
|
||||||
transport: BaseTransport,
|
|
||||||
setup: RTVISetup | None = None,
|
|
||||||
llm_api_key: str = "",
|
|
||||||
llm_base_url: str = "https://api.groq.com/openai/v1",
|
|
||||||
tts_api_key: str = "",
|
|
||||||
llm_cls: Type[AIService] = OpenAILLMService,
|
|
||||||
tts_cls: Type[AIService] = CartesiaTTSService):
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._transport = transport
|
self._transport = transport
|
||||||
self._setup = setup
|
self._config: RTVIConfig | None = None
|
||||||
self._llm_api_key = llm_api_key
|
self._ctor_args: Dict[str, Any] = {}
|
||||||
self._llm_base_url = llm_base_url
|
|
||||||
self._tts_api_key = tts_api_key
|
|
||||||
self._llm_cls = llm_cls
|
|
||||||
self._tts_cls = tts_cls
|
|
||||||
self._start_frame: Frame | None = None
|
self._start_frame: Frame | None = None
|
||||||
self._llm: FrameProcessor | None = None
|
|
||||||
self._tts: FrameProcessor | None = None
|
|
||||||
self._pipeline: FrameProcessor | None = None
|
self._pipeline: FrameProcessor | None = None
|
||||||
self._first_participant_joined: bool = False
|
self._first_participant_joined: bool = False
|
||||||
|
|
||||||
@@ -297,9 +327,24 @@ class RTVIProcessor(FrameProcessor):
|
|||||||
"on_first_participant_joined",
|
"on_first_participant_joined",
|
||||||
self._on_first_participant_joined)
|
self._on_first_participant_joined)
|
||||||
|
|
||||||
|
# Register default services.
|
||||||
|
self._registered_services: Dict[str, RTVIService] = {}
|
||||||
|
self.register_service(DEFAULT_LLM_SERVICE)
|
||||||
|
self.register_service(DEFAULT_TTS_SERVICE)
|
||||||
|
|
||||||
self._frame_handler_task = self.get_event_loop().create_task(self._frame_handler())
|
self._frame_handler_task = self.get_event_loop().create_task(self._frame_handler())
|
||||||
self._frame_queue = asyncio.Queue()
|
self._frame_queue = asyncio.Queue()
|
||||||
|
|
||||||
|
def register_service(self, service: RTVIService):
|
||||||
|
self._registered_services[service.name] = service
|
||||||
|
|
||||||
|
def setup_on_start(self, config: RTVIConfig | None, ctor_args: Dict[str, Any]):
|
||||||
|
self._config = config
|
||||||
|
self._ctor_args = ctor_args
|
||||||
|
|
||||||
|
async def update_config(self, config: RTVIConfig):
|
||||||
|
await self._handle_config_update(config)
|
||||||
|
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
await super().process_frame(frame, direction)
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
@@ -309,11 +354,10 @@ class RTVIProcessor(FrameProcessor):
|
|||||||
await self._frame_queue.put((frame, direction))
|
await self._frame_queue.put((frame, direction))
|
||||||
|
|
||||||
if isinstance(frame, StartFrame):
|
if isinstance(frame, StartFrame):
|
||||||
self._start_frame = frame
|
|
||||||
try:
|
try:
|
||||||
await self._handle_setup(self._setup)
|
await self._handle_pipeline_setup(frame, self._config)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await self._send_error(f"unable to setup RTVI: {e}")
|
await self._send_error(f"unable to setup RTVI pipeline: {e}")
|
||||||
|
|
||||||
async def cleanup(self):
|
async def cleanup(self):
|
||||||
self._frame_handler_task.cancel()
|
self._frame_handler_task.cancel()
|
||||||
@@ -379,90 +423,81 @@ class RTVIProcessor(FrameProcessor):
|
|||||||
try:
|
try:
|
||||||
message = RTVIMessage.model_validate(frame.message)
|
message = RTVIMessage.model_validate(frame.message)
|
||||||
except ValidationError as e:
|
except ValidationError as e:
|
||||||
await self._send_error(f"invalid message: {e}")
|
await self._send_error(f"Invalid incoming message: {e}")
|
||||||
|
logger.warning(f"Invalid incoming message: {e}")
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
success = True
|
success = True
|
||||||
error = None
|
error = None
|
||||||
match message.type:
|
match message.type:
|
||||||
case "setup":
|
|
||||||
setup = None
|
|
||||||
if message.data:
|
|
||||||
setup = message.data.setup
|
|
||||||
await self._handle_setup(message.id, setup)
|
|
||||||
case "config-update":
|
case "config-update":
|
||||||
await self._handle_config_update(message.data.config)
|
await self._handle_config_update(RTVIConfig.model_validate(message.data))
|
||||||
case "llm-get-context":
|
case "llm-get-context":
|
||||||
await self._handle_llm_get_context()
|
await self._handle_llm_get_context()
|
||||||
case "llm-append-context":
|
case "llm-append-context":
|
||||||
await self._handle_llm_append_context(message.data.llm)
|
await self._handle_llm_append_context(RTVILLMContextData.model_validate(message.data))
|
||||||
case "llm-update-context":
|
case "llm-update-context":
|
||||||
await self._handle_llm_update_context(message.data.llm)
|
await self._handle_llm_update_context(RTVILLMContextData.model_validate(message.data))
|
||||||
case "tts-speak":
|
case "tts-speak":
|
||||||
await self._handle_tts_speak(message.data.tts)
|
await self._handle_tts_speak(RTVITTSSpeakData.model_validate(message.data))
|
||||||
case "tts-interrupt":
|
case "tts-interrupt":
|
||||||
await self._handle_tts_interrupt()
|
await self._handle_tts_interrupt()
|
||||||
case _:
|
case _:
|
||||||
success = False
|
success = False
|
||||||
error = f"unsupported type {message.type}"
|
error = f"Unsupported type {message.type}"
|
||||||
|
|
||||||
await self._send_response(message.id, success, error)
|
await self._send_response(message.id, success, error)
|
||||||
except ValidationError as e:
|
except ValidationError as e:
|
||||||
await self._send_response(message.id, False, f"invalid message: {e}")
|
await self._send_response(message.id, False, f"Invalid incoming message: {e}")
|
||||||
|
logger.warning(f"Invalid incoming message: {e}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await self._send_response(message.id, False, f"{e}")
|
await self._send_response(message.id, False, f"Exception processing message: {e}")
|
||||||
|
logger.warning(f"Exception processing message: {e}")
|
||||||
|
|
||||||
async def _handle_setup(self, setup: RTVISetup | None):
|
async def _handle_pipeline_setup(self, start_frame: StartFrame, config: RTVIConfig | None):
|
||||||
model = DEFAULT_MODEL
|
# TODO(aleix): We shouldn't need to save this in `self._tma_in`.
|
||||||
if setup and setup.config and setup.config.llm and setup.config.llm.model:
|
self._tma_in = LLMUserResponseAggregator()
|
||||||
model = setup.config.llm.model
|
tma_out = LLMAssistantResponseAggregator()
|
||||||
|
|
||||||
messages = DEFAULT_MESSAGES
|
llm_cls = self._registered_services["llm"].cls
|
||||||
if setup and setup.config and setup.config.llm and setup.config.llm.messages:
|
llm_args = self._ctor_args["llm"]
|
||||||
messages = setup.config.llm.messages
|
llm = llm_cls(**llm_args)
|
||||||
|
|
||||||
voice = DEFAULT_VOICE
|
tts_cls = self._registered_services["tts"].cls
|
||||||
if setup and setup.config and setup.config.tts and setup.config.tts.voice:
|
tts_args = self._ctor_args["tts"]
|
||||||
voice = setup.config.tts.voice
|
tts = tts_cls(**tts_args)
|
||||||
|
|
||||||
self._tma_in = LLMUserResponseAggregator(messages)
|
|
||||||
self._tma_out = LLMAssistantResponseAggregator(messages)
|
|
||||||
|
|
||||||
self._llm = self._llm_cls(
|
|
||||||
name="LLM",
|
|
||||||
base_url=self._llm_base_url,
|
|
||||||
api_key=self._llm_api_key,
|
|
||||||
model=model)
|
|
||||||
|
|
||||||
self._tts = self._tts_cls(name="TTS", api_key=self._tts_api_key, voice_id=voice)
|
|
||||||
|
|
||||||
# TODO-CB: Eventually we'll need to switch the context aggregators to use the
|
# TODO-CB: Eventually we'll need to switch the context aggregators to use the
|
||||||
# OpenAI context frames instead of message frames
|
# OpenAI context frames instead of message frames
|
||||||
context = OpenAILLMContext(messages=messages)
|
context = OpenAILLMContext()
|
||||||
self._fc = FunctionCaller(context)
|
fc = FunctionCaller(context)
|
||||||
|
|
||||||
self._tts_text = RTVITTSTextProcessor()
|
tts_text = RTVITTSTextProcessor()
|
||||||
|
|
||||||
pipeline = Pipeline([
|
pipeline = Pipeline([
|
||||||
self._tma_in,
|
self._tma_in,
|
||||||
self._llm,
|
llm,
|
||||||
self._fc,
|
fc,
|
||||||
self._tts,
|
tts,
|
||||||
self._tts_text,
|
tts_text,
|
||||||
self._tma_out,
|
tma_out,
|
||||||
self._transport.output(),
|
self._transport.output(),
|
||||||
])
|
])
|
||||||
|
|
||||||
parent = self.get_parent()
|
parent = self.get_parent()
|
||||||
if parent and self._start_frame:
|
if parent:
|
||||||
parent.link(pipeline)
|
parent.link(pipeline)
|
||||||
|
|
||||||
# We need to initialize the new pipeline with the same settings
|
# We need to initialize the new pipeline with the same settings
|
||||||
# as the initial one.
|
# as the initial one.
|
||||||
start_frame = dataclasses.replace(self._start_frame)
|
start_frame = dataclasses.replace(start_frame)
|
||||||
await self.push_frame(start_frame)
|
await self.push_frame(start_frame)
|
||||||
|
|
||||||
|
# Configure the pipeline
|
||||||
|
if config:
|
||||||
|
await self._handle_config_update(config)
|
||||||
|
|
||||||
# Send new initial metrics with the new processors
|
# Send new initial metrics with the new processors
|
||||||
processors = parent.processors_with_metrics()
|
processors = parent.processors_with_metrics()
|
||||||
processors.extend(pipeline.processors_with_metrics())
|
processors.extend(pipeline.processors_with_metrics())
|
||||||
@@ -474,17 +509,16 @@ class RTVIProcessor(FrameProcessor):
|
|||||||
|
|
||||||
await self._maybe_send_bot_ready()
|
await self._maybe_send_bot_ready()
|
||||||
|
|
||||||
async def _handle_config_update(self, config: RTVIConfig):
|
async def _handle_config_service(self, config: RTVIServiceConfig):
|
||||||
# Change voice before LLM updates, so we can hear the new vocie.
|
service = self._registered_services[config.service]
|
||||||
if config.tts and config.tts.voice:
|
for option in config.options:
|
||||||
frame = TTSVoiceUpdateFrame(config.tts.voice)
|
handler = service._options_dict[option.name].handler
|
||||||
await self.push_frame(frame)
|
if handler:
|
||||||
if config.llm and config.llm.model:
|
await handler(self, option)
|
||||||
frame = LLMModelUpdateFrame(config.llm.model)
|
|
||||||
await self.push_frame(frame)
|
async def _handle_config_update(self, data: RTVIConfig):
|
||||||
if config.llm and config.llm.messages:
|
for config in data.config:
|
||||||
frame = LLMMessagesUpdateFrame(config.llm.messages)
|
await self._handle_config_service(config)
|
||||||
await self.push_frame(frame)
|
|
||||||
|
|
||||||
async def _handle_llm_get_context(self):
|
async def _handle_llm_get_context(self):
|
||||||
data = RTVILLMContextMessageData(messages=self._tma_in.messages)
|
data = RTVILLMContextMessageData(messages=self._tma_in.messages)
|
||||||
@@ -492,17 +526,17 @@ class RTVIProcessor(FrameProcessor):
|
|||||||
frame = TransportMessageFrame(message=message.model_dump(exclude_none=True))
|
frame = TransportMessageFrame(message=message.model_dump(exclude_none=True))
|
||||||
await self.push_frame(frame)
|
await self.push_frame(frame)
|
||||||
|
|
||||||
async def _handle_llm_append_context(self, data: RTVILLMMessageData):
|
async def _handle_llm_append_context(self, data: RTVILLMContextData):
|
||||||
if data and data.messages:
|
if data and data.messages:
|
||||||
frame = LLMMessagesAppendFrame(data.messages)
|
frame = LLMMessagesAppendFrame(data.messages)
|
||||||
await self.push_frame(frame)
|
await self.push_frame(frame)
|
||||||
|
|
||||||
async def _handle_llm_update_context(self, data: RTVILLMMessageData):
|
async def _handle_llm_update_context(self, data: RTVILLMContextData):
|
||||||
if data and data.messages:
|
if data and data.messages:
|
||||||
frame = LLMMessagesUpdateFrame(data.messages)
|
frame = LLMMessagesUpdateFrame(data.messages)
|
||||||
await self.push_frame(frame)
|
await self.push_frame(frame)
|
||||||
|
|
||||||
async def _handle_tts_speak(self, data: RTVITTSMessageData):
|
async def _handle_tts_speak(self, data: RTVITTSSpeakData):
|
||||||
if data and data.text:
|
if data and data.text:
|
||||||
if data.interrupt:
|
if data.interrupt:
|
||||||
await self._handle_tts_interrupt()
|
await self._handle_tts_interrupt()
|
||||||
@@ -539,7 +573,7 @@ class RTVIProcessor(FrameProcessor):
|
|||||||
self._pipeline = pipeline
|
self._pipeline = pipeline
|
||||||
|
|
||||||
parent = self.get_parent()
|
parent = self.get_parent()
|
||||||
if parent and self._start_frame:
|
if parent:
|
||||||
parent.link(pipeline)
|
parent.link(pipeline)
|
||||||
|
|
||||||
message = RTVIResponse(id=id, data=RTVIResponseData(success=success, error=error))
|
message = RTVIResponse(id=id, data=RTVIResponseData(success=success, error=error))
|
||||||
|
|||||||
Reference in New Issue
Block a user