updates and chat hack

This commit is contained in:
Chad Bailey
2024-02-15 19:49:46 +00:00
parent 0cae54e79e
commit 5a47a3d5cd
6 changed files with 59 additions and 23 deletions

View File

@@ -61,28 +61,38 @@ class LLMContextAggregator(AIService):
# TODO: split up transcription by participant # TODO: split up transcription by participant
if self.complete_sentences: if self.complete_sentences:
self.sentence += frame.text # type: ignore -- the linter thinks this isn't a TextQueueFrame, even though we check it above # type: ignore -- the linter thinks this isn't a TextQueueFrame, even though we check it above
self.sentence += frame.text
if self.sentence.endswith((".", "?", "!")): if self.sentence.endswith((".", "?", "!")):
self.messages.append({"role": self.role, "content": self.sentence}) self.messages.append(
{"role": self.role, "content": self.sentence})
self.sentence = "" self.sentence = ""
for message in self.messages:
print(f"{message['role']}: {message['content']}")
yield LLMMessagesQueueFrame(self.messages) yield LLMMessagesQueueFrame(self.messages)
else: else:
self.messages.append({"role": self.role, "content": frame.text}) # type: ignore -- the linter thinks this isn't a TextQueueFrame, even though we check it above # type: ignore -- the linter thinks this isn't a TextQueueFrame, even though we check it above
self.messages.append({"role": self.role, "content": frame.text})
for message in self.messages:
print(f"{message['role']}: {message['content']}")
yield LLMMessagesQueueFrame(self.messages) yield LLMMessagesQueueFrame(self.messages)
async def finalize(self) -> AsyncGenerator[QueueFrame, None]: async def finalize(self) -> AsyncGenerator[QueueFrame, None]:
# Send any dangling words that weren't finished with punctuation. # Send any dangling words that weren't finished with punctuation.
if self.complete_sentences and self.sentence: if self.complete_sentences and self.sentence:
self.messages.append({"role": self.role, "content": self.sentence}) self.messages.append({"role": self.role, "content": self.sentence})
for message in self.messages:
print(f"{message['role']}: {message['content']}")
yield LLMMessagesQueueFrame(self.messages) yield LLMMessagesQueueFrame(self.messages)
class LLMUserContextAggregator(LLMContextAggregator): class LLMUserContextAggregator(LLMContextAggregator):
def __init__(self, def __init__(self,
messages: list[dict], messages: list[dict],
bot_participant_id=None, bot_participant_id=None,
complete_sentences=True): complete_sentences=True):
super().__init__(messages, "user", bot_participant_id, complete_sentences, pass_through=False) super().__init__(messages, "user", bot_participant_id,
complete_sentences, pass_through=False)
class LLMAssistantContextAggregator(LLMContextAggregator): class LLMAssistantContextAggregator(LLMContextAggregator):

View File

@@ -18,14 +18,22 @@ class StartStreamQueueFrame(ControlQueueFrame):
class EndStreamQueueFrame(ControlQueueFrame): class EndStreamQueueFrame(ControlQueueFrame):
pass pass
class LLMResponseEndQueueFrame(QueueFrame): class LLMResponseEndQueueFrame(QueueFrame):
pass pass
@dataclass()
class ChatMessageQueueFrame(QueueFrame):
message: str
@dataclass() @dataclass()
class LLMFunctionCallFrame(QueueFrame): class LLMFunctionCallFrame(QueueFrame):
function_name: str function_name: str
arguments: str arguments: str
@dataclass() @dataclass()
class AudioQueueFrame(QueueFrame): class AudioQueueFrame(QueueFrame):
data: bytes data: bytes

View File

@@ -12,6 +12,7 @@ from dailyai.queue_frame import (
LLMMessagesQueueFrame, LLMMessagesQueueFrame,
LLMResponseEndQueueFrame, LLMResponseEndQueueFrame,
LLMFunctionCallFrame, LLMFunctionCallFrame,
ChatMessageQueueFrame,
QueueFrame, QueueFrame,
TextQueueFrame, TextQueueFrame,
TranscriptionQueueFrame, TranscriptionQueueFrame,
@@ -145,6 +146,7 @@ class TTSService(AIService):
self.current_sentence = "" self.current_sentence = ""
if text: if text:
yield ChatMessageQueueFrame(message=text)
async for audio_chunk in self.run_tts(text): async for audio_chunk in self.run_tts(text):
yield AudioQueueFrame(audio_chunk) yield AudioQueueFrame(audio_chunk)

View File

@@ -9,6 +9,7 @@ from typing import AsyncGenerator
from dailyai.queue_frame import ( from dailyai.queue_frame import (
AudioQueueFrame, AudioQueueFrame,
ChatMessageQueueFrame,
EndStreamQueueFrame, EndStreamQueueFrame,
ImageQueueFrame, ImageQueueFrame,
QueueFrame, QueueFrame,
@@ -92,7 +93,6 @@ class BaseTransportService():
def stop(self): def stop(self):
self._stop_threads.set() self._stop_threads.set()
async def stop_when_done(self): async def stop_when_done(self):
await self._wait_for_send_queue_to_empty() await self._wait_for_send_queue_to_empty()
@@ -215,6 +215,8 @@ class BaseTransportService():
self._set_image(frame.image) self._set_image(frame.image)
elif isinstance(frame, SpriteQueueFrame): elif isinstance(frame, SpriteQueueFrame):
self._set_images(frame.images) self._set_images(frame.images)
elif isinstance(frame, ChatMessageQueueFrame):
self._send_chat_message(frame)
elif len(b): elif len(b):
self.write_frame_to_mic(bytes(b)) self.write_frame_to_mic(bytes(b))
b = bytearray() b = bytearray()

View File

@@ -229,6 +229,12 @@ class DailyTransportService(BaseTransportService, EventHandler):
""" """
def on_app_message(self, message, sender): def on_app_message(self, message, sender):
print(f"app message: {message}")
if self._loop:
frame = TranscriptionQueueFrame(
message["message"], message["name"], message["date"])
asyncio.run_coroutine_threadsafe(
self.receive_queue.put(frame), self._loop)
pass pass
def on_transcription_message(self, message: dict): def on_transcription_message(self, message: dict):
@@ -252,6 +258,10 @@ class DailyTransportService(BaseTransportService, EventHandler):
def on_transcription_started(self, status): def on_transcription_started(self, status):
pass pass
def _send_chat_message(self, frame):
self.client.send_app_message(
{'message': frame.message, 'event': 'chat-msg', 'name': self._bot_name, 'date': time.time(), 'room': 'main-room'})
def stop(self): def stop(self):
super().stop() super().stop()
self.client.leave() self.client.leave()

View File

@@ -12,7 +12,7 @@ from dailyai.queue_aggregators import LLMAssistantContextAggregator, LLMContextA
from examples.foundational.support.runner import configure from examples.foundational.support.runner import configure
from dailyai.queue_frame import LLMMessagesQueueFrame, TranscriptionQueueFrame, QueueFrame, TextQueueFrame, LLMFunctionCallFrame, LLMResponseEndQueueFrame, StartStreamQueueFrame from dailyai.queue_frame import LLMMessagesQueueFrame, TranscriptionQueueFrame, QueueFrame, TextQueueFrame, LLMFunctionCallFrame, LLMResponseEndQueueFrame, StartStreamQueueFrame
from dailyai.services.ai_services import FrameLogger, AIService from dailyai.services.ai_services import FrameLogger, AIService
from dailyai.conversation_wrappers import InterruptibleConversationWrapper
import logging import logging
logging.basicConfig(level=logging.ERROR) logging.basicConfig(level=logging.ERROR)
@@ -272,28 +272,32 @@ async def main(room_url: str, token):
fl = FrameLogger("got transcript") fl = FrameLogger("got transcript")
fl2 = FrameLogger("just above the checklist") fl2 = FrameLogger("just above the checklist")
async def handle_transcriptions(): async def handle_transcriptions(user_speech, tma_in, tma_out):
tf = TranscriptFilter(transport._my_participant_id) tf = TranscriptFilter(transport._my_participant_id)
await tts.run_to_queue( await tts.run_to_queue(
transport.send_queue, transport.send_queue,
fl2.run( checklist.run(
checklist.run( tma_out.run(
tma_out.run( llm.run(
llm.run( tma_in.run(
tma_in.run( [StartStreamQueueFrame(), TextQueueFrame(user_speech)]
tf.run(
fl.run(
transport.get_receive_frames()
)
)
)
) )
) )
) )
) )
) )
async def run_conversation():
conversation_wrapper = InterruptibleConversationWrapper(
frame_generator=transport.get_receive_frames,
runner=handle_transcriptions,
interrupt=transport.interrupt,
my_participant_id=transport._my_participant_id,
llm_messages=messages,
)
await conversation_wrapper.run_conversation()
@transport.event_handler("on_first_other_participant_joined") @transport.event_handler("on_first_other_participant_joined")
async def on_first_other_participant_joined(transport): async def on_first_other_participant_joined(transport):
fl = FrameLogger("first other participant") fl = FrameLogger("first other participant")
@@ -308,7 +312,7 @@ async def main(room_url: str, token):
transport.transcription_settings["extra"]["punctuate"] = True transport.transcription_settings["extra"]["punctuate"] = True
try: try:
await asyncio.gather(transport.run(), handle_transcriptions()) await asyncio.gather(transport.run(), run_conversation())
except (asyncio.CancelledError, KeyboardInterrupt): except (asyncio.CancelledError, KeyboardInterrupt):
transport.stop() transport.stop()