From cfaccefe9c949cef92430faa9cb8ffa4060326c6 Mon Sep 17 00:00:00 2001 From: Moishe Lettvin Date: Fri, 12 Jan 2024 16:22:03 -0500 Subject: [PATCH] some sample and readme updates --- README.md | 2 +- src/samples/deprecated/README.md | 1 + .../simple-sample/simple-sample.py | 0 .../static-sprite/sprite-sample.py | 0 .../static-sprite/sprites/intro.png | Bin .../static-sprite/sprites/talk-1.png | Bin .../static-sprite/sprites/talk-2.png | Bin .../static-sprite/sprites/wait.png | Bin .../theoretical-to-real/01-say-one-thing.py | 3 +- src/samples/theoretical-to-real/05-queued.py | 124 ------------------ .../05-sync-speech-and-text.py | 43 +++--- .../06-listen-and-respond.py | 2 +- 12 files changed, 27 insertions(+), 148 deletions(-) create mode 100644 src/samples/deprecated/README.md rename src/samples/{ => deprecated}/simple-sample/simple-sample.py (100%) rename src/samples/{ => deprecated}/static-sprite/sprite-sample.py (100%) rename src/samples/{ => deprecated}/static-sprite/sprites/intro.png (100%) rename src/samples/{ => deprecated}/static-sprite/sprites/talk-1.png (100%) rename src/samples/{ => deprecated}/static-sprite/sprites/talk-2.png (100%) rename src/samples/{ => deprecated}/static-sprite/sprites/wait.png (100%) delete mode 100644 src/samples/theoretical-to-real/05-queued.py diff --git a/README.md b/README.md index e16f073fd..364ea5d91 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ pip install path_to_this_repo Tou can run the simple sample like so: ``` -python src/samples/simple-sample/simple-sample.py -u your_room_url -k your_daily_api_key +python src/samples/theoretical-to-real/01-say-one-thing.py -u -k ``` Note that the sample uses Azure's TTS and LLM services. You'll need to set the following environment variables for the sample to work: diff --git a/src/samples/deprecated/README.md b/src/samples/deprecated/README.md new file mode 100644 index 000000000..242d2f497 --- /dev/null +++ b/src/samples/deprecated/README.md @@ -0,0 +1 @@ +These samples need to be updated! Don't rely on them. \ No newline at end of file diff --git a/src/samples/simple-sample/simple-sample.py b/src/samples/deprecated/simple-sample/simple-sample.py similarity index 100% rename from src/samples/simple-sample/simple-sample.py rename to src/samples/deprecated/simple-sample/simple-sample.py diff --git a/src/samples/static-sprite/sprite-sample.py b/src/samples/deprecated/static-sprite/sprite-sample.py similarity index 100% rename from src/samples/static-sprite/sprite-sample.py rename to src/samples/deprecated/static-sprite/sprite-sample.py diff --git a/src/samples/static-sprite/sprites/intro.png b/src/samples/deprecated/static-sprite/sprites/intro.png similarity index 100% rename from src/samples/static-sprite/sprites/intro.png rename to src/samples/deprecated/static-sprite/sprites/intro.png diff --git a/src/samples/static-sprite/sprites/talk-1.png b/src/samples/deprecated/static-sprite/sprites/talk-1.png similarity index 100% rename from src/samples/static-sprite/sprites/talk-1.png rename to src/samples/deprecated/static-sprite/sprites/talk-1.png diff --git a/src/samples/static-sprite/sprites/talk-2.png b/src/samples/deprecated/static-sprite/sprites/talk-2.png similarity index 100% rename from src/samples/static-sprite/sprites/talk-2.png rename to src/samples/deprecated/static-sprite/sprites/talk-2.png diff --git a/src/samples/static-sprite/sprites/wait.png b/src/samples/deprecated/static-sprite/sprites/wait.png similarity index 100% rename from src/samples/static-sprite/sprites/wait.png rename to src/samples/deprecated/static-sprite/sprites/wait.png diff --git a/src/samples/theoretical-to-real/01-say-one-thing.py b/src/samples/theoretical-to-real/01-say-one-thing.py index f26de3ba3..67e55d3b5 100644 --- a/src/samples/theoretical-to-real/01-say-one-thing.py +++ b/src/samples/theoretical-to-real/01-say-one-thing.py @@ -36,6 +36,7 @@ async def main(room_url): async def on_participant_joined(transport, participant): if participant["info"]["isLocal"]: return + async for audio in audio_generator: transport.output_queue.put(QueueFrame(FrameType.AUDIO_FRAME, audio)) @@ -52,6 +53,6 @@ if __name__ == "__main__": "-u", "--url", type=str, required=True, help="URL of the Daily room to join" ) - args: argparse.Namespace = parser.parse_args() + args, unknown = parser.parse_known_args() asyncio.run(main(args.url)) diff --git a/src/samples/theoretical-to-real/05-queued.py b/src/samples/theoretical-to-real/05-queued.py deleted file mode 100644 index 60711f4bf..000000000 --- a/src/samples/theoretical-to-real/05-queued.py +++ /dev/null @@ -1,124 +0,0 @@ -import argparse -import asyncio - -from asyncio.queues import Queue -import re - -from dailyai.queue_frame import QueueFrame, FrameType -from dailyai.services.azure_ai_services import AzureLLMService -from dailyai.services.elevenlabs_ai_service import ElevenLabsTTSService -from dailyai.services.open_ai_services import OpenAIImageGenService -from dailyai.services.daily_transport_service import DailyTransportService - -async def main(room_url): - meeting_duration_minutes = 5 - transport = DailyTransportService( - room_url, - None, - "Month Narration Bot", - meeting_duration_minutes, - ) - transport.mic_enabled = True - transport.camera_enabled = True - transport.mic_sample_rate = 16000 - transport.camera_width = 1024 - transport.camera_height = 1024 - - llm = AzureLLMService() - tts = ElevenLabsTTSService(voice_id="ErXwobaYiN019PkySvjV") - dalle = OpenAIImageGenService() - - # Get a complete audio chunk from the given text. Splitting this into its own - # coroutine lets us ensure proper ordering of the audio chunks on the output queue. - async def get_all_audio(text): - all_audio = bytearray() - async for audio in tts.run_tts(text): - all_audio.extend(audio) - - return all_audio - - async def get_month_data(month): - image_text = "" - tts_tasks = [] - first_sentence = True - async for sentence in llm.run_llm_async_sentences( - [ - { - "role": "system", - "content": f"Describe a nature photograph suitable for use in a calendar, for the month of {month}. Include only the image description with no preamble. Limit the description to one sentence, please." - } - ] - ): - image_text += sentence - - if first_sentence: - sentence = f"{month}: {sentence}" - else: - first_sentence = False - - tts_tasks.append(get_all_audio(sentence)) - - tts_tasks.insert(0, dalle.run_image_gen(image_text, "1024x1024")) - - print(f"waiting for tasks to finish for {month}") - data = await asyncio.gather( - *tts_tasks - ) - - print(f"done gathering tts tasks for {month}") - - return { - "month": month, - "text": image_text, - "image": data[0][1], - "audio": data[1:], - } - - months: list[str] = [ - "January", - "February", - "March", - "April", - "May", - "June", - "July", - "August", - "September", - "October", - "November", - "December", - ] - - @transport.event_handler("on_first_other_participant_joined") - async def on_first_other_participant_joined(transport): - # This will play the months in the order they're completed. The benefit - # is we'll have as little delay as possible before the first month, and - # likely no delay between months, but the months won't display in order. - for month_data_task in asyncio.as_completed(month_tasks): - data = await month_data_task - transport.output_queue.put( - [ - QueueFrame(FrameType.IMAGE_FRAME, data["image"]), - QueueFrame(FrameType.AUDIO_FRAME, data["audio"][0]), - ] - ) - for audio in data["audio"][1:]: - transport.output_queue.put(QueueFrame(FrameType.AUDIO_FRAME, audio)) - - # wait for the output queue to be empty, then leave the meeting - transport.output_queue.join() - transport.stop() - - month_tasks = [asyncio.create_task(get_month_data(month)) for month in months] - - await transport.run() - -if __name__=="__main__": - parser = argparse.ArgumentParser(description="Simple Daily Bot Sample") - parser.add_argument( - "-u", "--url", type=str, required=True, help="URL of the Daily room to join" - ) - - args, unknown = parser.parse_known_args() - - asyncio.run(main(args.url)) diff --git a/src/samples/theoretical-to-real/05-sync-speech-and-text.py b/src/samples/theoretical-to-real/05-sync-speech-and-text.py index b66caa89c..60711f4bf 100644 --- a/src/samples/theoretical-to-real/05-sync-speech-and-text.py +++ b/src/samples/theoretical-to-real/05-sync-speech-and-text.py @@ -1,15 +1,13 @@ import argparse - import asyncio from asyncio.queues import Queue import re from dailyai.queue_frame import QueueFrame, FrameType -from dailyai.services.azure_ai_services import AzureLLMService, AzureTTSService -from dailyai.services.elevenlabs_ai_service import ElevenLabsTTSService -from dailyai.services.open_ai_services import OpenAILLMService, OpenAIImageGenService +from dailyai.services.azure_ai_services import AzureLLMService from dailyai.services.elevenlabs_ai_service import ElevenLabsTTSService +from dailyai.services.open_ai_services import OpenAIImageGenService from dailyai.services.daily_transport_service import DailyTransportService async def main(room_url): @@ -27,7 +25,7 @@ async def main(room_url): transport.camera_height = 1024 llm = AzureLLMService() - tts = ElevenLabsTTSService() + tts = ElevenLabsTTSService(voice_id="ErXwobaYiN019PkySvjV") dalle = OpenAIImageGenService() # Get a complete audio chunk from the given text. Splitting this into its own @@ -41,9 +39,9 @@ async def main(room_url): async def get_month_data(month): image_text = "" - current_clause = "" tts_tasks = [] - async for text in llm.run_llm_async( + first_sentence = True + async for sentence in llm.run_llm_async_sentences( [ { "role": "system", @@ -51,18 +49,24 @@ async def main(room_url): } ] ): - image_text += text - current_clause += text - if re.match(r"^.*[.!?]$", text): - tts_tasks.append(get_all_audio(current_clause)) - current_clause = "" + image_text += sentence + + if first_sentence: + sentence = f"{month}: {sentence}" + else: + first_sentence = False + + tts_tasks.append(get_all_audio(sentence)) tts_tasks.insert(0, dalle.run_image_gen(image_text, "1024x1024")) + print(f"waiting for tasks to finish for {month}") data = await asyncio.gather( *tts_tasks ) + print(f"done gathering tts tasks for {month}") + return { "month": month, "text": image_text, @@ -75,9 +79,6 @@ async def main(room_url): "February", "March", "April", - ] - - unused_months = [ "May", "June", "July", @@ -88,11 +89,11 @@ async def main(room_url): "December", ] - @transport.event_handler("on_participant_joined") - async def on_participant_joined(transport, participant): - if participant["id"] == transport.my_participant_id: - return - + @transport.event_handler("on_first_other_participant_joined") + async def on_first_other_participant_joined(transport): + # This will play the months in the order they're completed. The benefit + # is we'll have as little delay as possible before the first month, and + # likely no delay between months, but the months won't display in order. for month_data_task in asyncio.as_completed(month_tasks): data = await month_data_task transport.output_queue.put( @@ -118,6 +119,6 @@ if __name__=="__main__": "-u", "--url", type=str, required=True, help="URL of the Daily room to join" ) - args: argparse.Namespace = parser.parse_args() + args, unknown = parser.parse_known_args() asyncio.run(main(args.url)) diff --git a/src/samples/theoretical-to-real/06-listen-and-respond.py b/src/samples/theoretical-to-real/06-listen-and-respond.py index 6cdac1491..fa3680e71 100644 --- a/src/samples/theoretical-to-real/06-listen-and-respond.py +++ b/src/samples/theoretical-to-real/06-listen-and-respond.py @@ -67,7 +67,7 @@ if __name__ == "__main__": help="Daily API Key (needed to create token)", ) - args: argparse.Namespace = parser.parse_args() + args, unknown = parser.parse_known_args() # Create a meeting token for the given room with an expiration 1 hour in the future. room_name: str = urllib.parse.urlparse(args.url).path[1:]