the actual refactor that I missed in the last commit
This commit is contained in:
@@ -181,20 +181,18 @@ class AsyncProcessor:
|
|||||||
|
|
||||||
def async_prepare(self) -> None:
|
def async_prepare(self) -> None:
|
||||||
self.set_state(AsyncProcessorState.PREPARING)
|
self.set_state(AsyncProcessorState.PREPARING)
|
||||||
self.preparation_iterator = self.get_preparation_iterator()
|
self.start_preparation()
|
||||||
self.set_state(AsyncProcessorState.READY)
|
self.set_state(AsyncProcessorState.READY)
|
||||||
for chunk in self.preparation_iterator:
|
self.continue_preparation()
|
||||||
if self.state not in [
|
|
||||||
AsyncProcessorState.READY,
|
|
||||||
AsyncProcessorState.PLAYING,
|
|
||||||
]:
|
|
||||||
break
|
|
||||||
|
|
||||||
self.process_chunk(chunk)
|
|
||||||
|
|
||||||
self.logger.info(f"Preparation done for {self.__class__.__name__}")
|
self.logger.info(f"Preparation done for {self.__class__.__name__}")
|
||||||
self.preparation_done()
|
self.preparation_done()
|
||||||
|
|
||||||
|
def start_preparation(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def continue_preparation(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
def preparation_done(self):
|
def preparation_done(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -213,8 +211,8 @@ class AsyncProcessor:
|
|||||||
def do_finalization(self) -> None:
|
def do_finalization(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class OrchestratorResponse(AsyncProcessor):
|
||||||
|
|
||||||
class Response(AsyncProcessor):
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
services,
|
services,
|
||||||
@@ -225,6 +223,17 @@ class Response(AsyncProcessor):
|
|||||||
|
|
||||||
self.message_handler: MessageHandler = message_handler
|
self.message_handler: MessageHandler = message_handler
|
||||||
self.output_queue: Queue = output_queue
|
self.output_queue: Queue = output_queue
|
||||||
|
|
||||||
|
|
||||||
|
class LLMResponse(OrchestratorResponse):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
services,
|
||||||
|
message_handler,
|
||||||
|
output_queue,
|
||||||
|
) -> None:
|
||||||
|
super().__init__(services, message_handler, output_queue)
|
||||||
|
|
||||||
self.has_sent_first_frame = False
|
self.has_sent_first_frame = False
|
||||||
|
|
||||||
self.chunks_in_preparation = Queue()
|
self.chunks_in_preparation = Queue()
|
||||||
@@ -263,6 +272,19 @@ class Response(AsyncProcessor):
|
|||||||
for audio_frame in self.services.tts.run_tts(chunk):
|
for audio_frame in self.services.tts.run_tts(chunk):
|
||||||
yield self.get_frames_from_tts_response(audio_frame)
|
yield self.get_frames_from_tts_response(audio_frame)
|
||||||
|
|
||||||
|
def start_preparation(self) -> None:
|
||||||
|
self.preparation_iterator = self.get_preparation_iterator()
|
||||||
|
|
||||||
|
def continue_preparation(self) -> None:
|
||||||
|
for chunk in self.preparation_iterator:
|
||||||
|
if self.state not in [
|
||||||
|
AsyncProcessorState.READY,
|
||||||
|
AsyncProcessorState.PLAYING,
|
||||||
|
]:
|
||||||
|
break
|
||||||
|
|
||||||
|
self.process_chunk(chunk)
|
||||||
|
|
||||||
def process_chunk(self, chunk) -> None:
|
def process_chunk(self, chunk) -> None:
|
||||||
self.chunks_in_preparation.put((chunk, self.get_frames_from_chunk(chunk)))
|
self.chunks_in_preparation.put((chunk, self.get_frames_from_chunk(chunk)))
|
||||||
|
|
||||||
@@ -320,7 +342,7 @@ class Response(AsyncProcessor):
|
|||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class ConversationProcessorCollection:
|
class ConversationProcessorCollection:
|
||||||
introduction: Optional[Type[Response]] = None
|
introduction: Optional[Type[OrchestratorResponse]] = None
|
||||||
waiting: Optional[Type[Response]] = None
|
waiting: Optional[Type[OrchestratorResponse]] = None
|
||||||
response: Optional[Type[Response]] = None
|
response: Optional[Type[OrchestratorResponse]] = None
|
||||||
goodbye: Optional[Type[Response]] = None
|
goodbye: Optional[Type[OrchestratorResponse]] = None
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ from dailyai.async_processor.async_processor import (
|
|||||||
AsyncProcessor,
|
AsyncProcessor,
|
||||||
AsyncProcessorState,
|
AsyncProcessorState,
|
||||||
ConversationProcessorCollection,
|
ConversationProcessorCollection,
|
||||||
Response,
|
OrchestratorResponse,
|
||||||
|
LLMResponse,
|
||||||
)
|
)
|
||||||
from dailyai.services.ai_services import AIServiceConfig
|
from dailyai.services.ai_services import AIServiceConfig
|
||||||
from dailyai.message_handler.message_handler import MessageHandler
|
from dailyai.message_handler.message_handler import MessageHandler
|
||||||
@@ -42,9 +43,9 @@ class OrchestratorConfig:
|
|||||||
# constructor. The dataclass is defined with Frozen=True, so this should
|
# constructor. The dataclass is defined with Frozen=True, so this should
|
||||||
# be safe.
|
# be safe.
|
||||||
default_conversation_collection = ConversationProcessorCollection(
|
default_conversation_collection = ConversationProcessorCollection(
|
||||||
introduction=Response,
|
introduction=LLMResponse,
|
||||||
waiting=None,
|
waiting=None,
|
||||||
response=Response,
|
response=LLMResponse,
|
||||||
goodbye=None,
|
goodbye=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -207,7 +208,6 @@ class Orchestrator(EventHandler):
|
|||||||
|
|
||||||
def on_response_played(self, response):
|
def on_response_played(self, response):
|
||||||
response.finalize()
|
response.finalize()
|
||||||
self.display_waiting()
|
|
||||||
|
|
||||||
def on_response_finished(self, response):
|
def on_response_finished(self, response):
|
||||||
if not response.was_interrupted:
|
if not response.was_interrupted:
|
||||||
@@ -313,8 +313,8 @@ class Orchestrator(EventHandler):
|
|||||||
|
|
||||||
self.message_handler.add_user_message(fragment)
|
self.message_handler.add_user_message(fragment)
|
||||||
|
|
||||||
response_type = self.conversation_processors.response or Response
|
response_type: type[OrchestratorResponse] | type[LLMResponse] = self.conversation_processors.response or LLMResponse
|
||||||
new_response: Response = response_type(
|
new_response: OrchestratorResponse = response_type(
|
||||||
self.services, self.message_handler, self.output_queue
|
self.services, self.message_handler, self.output_queue
|
||||||
)
|
)
|
||||||
new_response.set_state_callback(
|
new_response.set_state_callback(
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ from dailyai.message_handler.message_handler import MessageHandler
|
|||||||
from dailyai.async_processor.async_processor import (
|
from dailyai.async_processor.async_processor import (
|
||||||
AsyncProcessor,
|
AsyncProcessor,
|
||||||
AsyncProcessorState,
|
AsyncProcessorState,
|
||||||
Response,
|
LLMResponse,
|
||||||
)
|
)
|
||||||
|
|
||||||
class MockTTSService(TTSService):
|
class MockTTSService(TTSService):
|
||||||
@@ -51,7 +51,7 @@ class TestResponse(unittest.TestCase):
|
|||||||
mock_llm_service = MockLLMService()
|
mock_llm_service = MockLLMService()
|
||||||
mock_image_service = MockImageService()
|
mock_image_service = MockImageService()
|
||||||
message_handler = MessageHandler("Hello World")
|
message_handler = MessageHandler("Hello World")
|
||||||
processor = Response(
|
processor = LLMResponse(
|
||||||
AIServiceConfig(
|
AIServiceConfig(
|
||||||
tts=mock_tts_service, llm=mock_llm_service, image=mock_image_service
|
tts=mock_tts_service, llm=mock_llm_service, image=mock_image_service
|
||||||
),
|
),
|
||||||
@@ -86,7 +86,7 @@ class TestResponse(unittest.TestCase):
|
|||||||
mock_llm_service = MockLLMService()
|
mock_llm_service = MockLLMService()
|
||||||
mock_image_service = MockImageService()
|
mock_image_service = MockImageService()
|
||||||
message_handler = MessageHandler("System Message")
|
message_handler = MessageHandler("System Message")
|
||||||
processor = Response(
|
processor = LLMResponse(
|
||||||
AIServiceConfig(
|
AIServiceConfig(
|
||||||
tts=mock_tts_service, llm=mock_llm_service, image=mock_image_service
|
tts=mock_tts_service, llm=mock_llm_service, image=mock_image_service
|
||||||
),
|
),
|
||||||
@@ -108,7 +108,7 @@ class TestResponse(unittest.TestCase):
|
|||||||
mock_llm_service = MockLLMService()
|
mock_llm_service = MockLLMService()
|
||||||
mock_image_service = MockImageService()
|
mock_image_service = MockImageService()
|
||||||
message_handler = MessageHandler("System Message")
|
message_handler = MessageHandler("System Message")
|
||||||
processor = Response(
|
processor = LLMResponse(
|
||||||
AIServiceConfig(
|
AIServiceConfig(
|
||||||
tts=mock_tts_service, llm=mock_llm_service, image=mock_image_service
|
tts=mock_tts_service, llm=mock_llm_service, image=mock_image_service
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import time
|
|||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
|
||||||
from dailyai.async_processor.async_processor import (
|
from dailyai.async_processor.async_processor import (
|
||||||
Response,
|
LLMResponse,
|
||||||
ConversationProcessorCollection,
|
ConversationProcessorCollection,
|
||||||
)
|
)
|
||||||
from dailyai.orchestrator import OrchestratorConfig, Orchestrator
|
from dailyai.orchestrator import OrchestratorConfig, Orchestrator
|
||||||
|
|||||||
@@ -1,26 +1,47 @@
|
|||||||
import argparse
|
import argparse
|
||||||
from email.mime import image
|
import os
|
||||||
from re import A
|
|
||||||
import requests
|
import requests
|
||||||
import time
|
import time
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
from dailyai.async_processor.async_processor import (
|
from dailyai.async_processor.async_processor import (
|
||||||
Response,
|
|
||||||
ConversationProcessorCollection,
|
ConversationProcessorCollection,
|
||||||
|
LLMResponse
|
||||||
)
|
)
|
||||||
from dailyai.orchestrator import OrchestratorConfig, Orchestrator
|
from dailyai.orchestrator import OrchestratorConfig, Orchestrator
|
||||||
from dailyai.message_handler.message_handler import MessageHandler
|
from dailyai.message_handler.message_handler import MessageHandler
|
||||||
from dailyai.services.ai_services import AIServiceConfig
|
from dailyai.services.ai_services import AIServiceConfig
|
||||||
from dailyai.services.azure_ai_services import AzureImageGenService, AzureTTSService, AzureLLMService
|
from dailyai.services.azure_ai_services import AzureImageGenService, AzureTTSService, AzureLLMService
|
||||||
|
|
||||||
class SpriteResponse(Response):
|
class StaticSpriteResponse(LLMResponse):
|
||||||
def __init__(self, message, image):
|
|
||||||
super().__init__(message)
|
def __init__(
|
||||||
self.image = image
|
self,
|
||||||
|
services,
|
||||||
|
message_handler,
|
||||||
|
output_queue
|
||||||
|
) -> None:
|
||||||
|
super().__init__(services, message_handler, output_queue)
|
||||||
|
self.image_bytes:bytes | None = None
|
||||||
|
self.filename = None # override this in subclasses
|
||||||
|
|
||||||
|
def start_preparation(self) -> None:
|
||||||
|
full_path = os.path.join(os.path.dirname(__file__), "/sprites/")
|
||||||
|
|
||||||
|
with Image.open(full_path) as img:
|
||||||
|
self.image_bytes = img.tobytes()
|
||||||
|
|
||||||
|
def async_play(self) -> None:
|
||||||
|
self.output_queue.put({"type": "image_frame", "data": self.image_bytes})
|
||||||
|
|
||||||
|
|
||||||
|
class IntroSpriteResponse(StaticSpriteResponse):
|
||||||
|
def __init__(self, services, message_handler, output_queue) -> None:
|
||||||
|
super().__init__(services, message_handler, output_queue)
|
||||||
|
self.filename = "intro.png"
|
||||||
|
|
||||||
def get_image(self):
|
|
||||||
return self.image
|
|
||||||
|
|
||||||
def add_bot_to_room(room_url, token, expiration) -> None:
|
def add_bot_to_room(room_url, token, expiration) -> None:
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user