import argparse import logging import os import time from threading import Thread from typing import Any, Mapping from daily import EventHandler, CallClient, Daily from datetime import datetime from dotenv import load_dotenv from auth import get_meeting_token, get_room_name load_dotenv() class DailyLLM(EventHandler): def __init__( self, room_url=os.getenv("DAILY_URL"), token=os.getenv("DAILY_TOKEN"), bot_name="TestBot", ): duration = os.getenv("BOT_MAX_DURATION") if not duration: duration = 300 else: duration = int(duration) self.expiration = time.time() + duration # room + bot details self.room_url = room_url room_name = get_room_name(room_url) if token: self.token = token else: self.token = get_meeting_token( room_name, os.getenv("DAILY_API_KEY"), self.expiration ) self.bot_name = bot_name self.finished_talking_at = None FORMAT = f"%(asctime)s {room_name} %(message)s" logging.basicConfig(format=FORMAT) self.logger = logging.getLogger("bot-instance") self.logger.setLevel(logging.DEBUG) self.logger.info(f"Joining as {self.bot_name}") self.logger.info(f"Joining room {self.room_url}") self.logger.info( f"expiration: {datetime.utcfromtimestamp(self.expiration).strftime('%Y-%m-%d %H:%M:%S')}" ) self.logger.info( f"now: {datetime.utcfromtimestamp(time.time()).strftime('%Y-%m-%d %H:%M:%S')}" ) self.my_participant_id = None self.logger.info("configuring daily") self.configure_daily() self.stop_threads = False self.image = None #self.logger.info("starting camera thread") #self.camera_thread = Thread(target=self.run_camera) #self.camera_thread.start() self.participant_left = False self.last_fragment_at = None try: participant_count = len(self.client.participants()) self.logger.info(f"{participant_count} participants in room") while time.time() < self.expiration and not self.participant_left: time.sleep(1) except Exception as e: self.logger.error(f"Exception {e}") finally: self.client.leave() self.stop_threads = True self.logger.info("Shutting down") #self.camera_thread.join() #self.logger.info("camera thread stopped") #self.logger.info("Services closed.") def configure_daily(self): Daily.init() self.client = CallClient(event_handler=self) self.mic = Daily.create_microphone_device("mic", sample_rate=16000, channels=1) self.speaker = Daily.create_speaker_device( "speaker", sample_rate=16000, channels=1 ) self.camera = Daily.create_camera_device( "camera", width=1024, height=1024, color_format="RGB" ) Daily.select_speaker_device("speaker") self.client.set_user_name(self.bot_name) self.client.join(self.room_url, completion=self.call_joined) #self.client.join(self.room_url, self.token, completion=self.call_joined) self.client.update_inputs( { "camera": { "isEnabled": True, "settings": { "deviceId": "camera", "frameRate": 5, }, }, "microphone": {"isEnabled": True, "settings": {"deviceId": "mic"}}, } ) self.my_participant_id = self.client.participants()["local"]["id"] def call_joined(self, join_data, client_error): self.logger.info(f"call_joined: {join_data}, {client_error}") def on_participant_joined(self, participant): self.logger.info(f"on_participant_joined: {participant}") #self.client.send_app_message({"event": "story-id", "storyID": self.story_id}) self.wave() time.sleep(2) def on_participant_left(self, participant, reason): if len(self.client.participants()) < 2: self.logger.info("participant left") self.participant_left = True def wave(self): self.client.send_app_message( { "event": "sync-emoji-reaction", "reaction": { "emoji": "👋", "room": "main-room", "sessionId": "bot", "id": time.time(), }, } ) if __name__ == "__main__": parser = argparse.ArgumentParser(description="Daily LLM bot") parser.add_argument("-u", "--url", type=str, help="URL of the Daily room") parser.add_argument("-t", "--token", type=str, help="Token for Daily API") parser.add_argument("-b", "--bot-name", type=str, help="Name of the bot") args = parser.parse_args() url = args.url or os.getenv("DAILY_URL") bot_name = args.bot_name or "TestBot" token = args.token or None app = DailyLLM(url, token, bot_name)