diff --git a/server/api/bots.py b/server/api/bots.py index 4be3564..6269f12 100644 --- a/server/api/bots.py +++ b/server/api/bots.py @@ -21,7 +21,11 @@ except ImportError as e: def create_bot_router( - bot_manager, session_manager, lobby_manager, public_url: str = "/" + bot_manager, + session_manager, + lobby_manager, + bot_config_manager, + public_url: str = "/", ) -> APIRouter: """Create bot API router with dependencies""" @@ -52,7 +56,9 @@ def create_bot_router( async def request_bot_join_lobby(bot_name: str, request: BotJoinLobbyRequest) -> BotJoinLobbyResponse: """Request a bot to join a specific lobby""" try: - return await bot_manager.request_bot_join(bot_name, request, session_manager, lobby_manager) + return await bot_manager.request_bot_join( + bot_name, request, session_manager, lobby_manager, bot_config_manager + ) except ValueError as e: if "not found" in str(e).lower(): raise HTTPException(status_code=404, detail=str(e)) diff --git a/server/core/bot_manager.py b/server/core/bot_manager.py index be533e5..496f8e1 100644 --- a/server/core/bot_manager.py +++ b/server/core/bot_manager.py @@ -36,6 +36,7 @@ from shared.models import ( ) from core.session_manager import SessionManager from core.lobby_manager import LobbyManager +from core.bot_config_manager import BotConfigManager class BotProviderConfig: """Configuration class for bot provider management""" @@ -306,6 +307,7 @@ class BotManager: request: BotJoinLobbyRequest, session_manager: SessionManager, lobby_manager: LobbyManager, + config_manager: "BotConfigManager", ) -> BotJoinLobbyResponse: """Request a bot to join a specific lobby""" @@ -399,6 +401,12 @@ class BotManager: # Get public URL prefix from environment public_url = os.getenv("PUBLIC_URL_PREFIX", "/ai-voicebot") + # Check for existing configuration for this bot in this lobby + existing_config = config_manager.get_lobby_bot_config( + request.lobby_id, bot_name + ) + config_values = existing_config.config_values if existing_config else None + # Prepare the join request for the bot provider bot_join_payload = BotJoinPayload( lobby_id=request.lobby_id, @@ -406,6 +414,7 @@ class BotManager: nick=bot_nick, server_url=f"{server_base_url}{public_url}".rstrip("/"), insecure=True, # Accept self-signed certificates in development + config_values=config_values, ) try: diff --git a/server/main.py b/server/main.py index cf66079..2e5d83e 100644 --- a/server/main.py +++ b/server/main.py @@ -203,7 +203,11 @@ async def lifespan(app: FastAPI): # Create bot API router bot_router = create_bot_router( - bot_manager, session_manager, lobby_manager, public_url=public_url + bot_manager, + session_manager, + lobby_manager, + bot_config_manager, + public_url=public_url, ) # Create bot configuration API router diff --git a/shared/models.py b/shared/models.py index 5e2e051..241d244 100644 --- a/shared/models.py +++ b/shared/models.py @@ -496,6 +496,9 @@ class BotJoinPayload(BaseModel): nick: str server_url: str insecure: bool = False + config_values: Optional[Dict[str, Any]] = ( + None # Existing configuration for the bot in this lobby + ) class BotJoinLobbyResponse(BaseModel): diff --git a/voicebot/bot_orchestrator.py b/voicebot/bot_orchestrator.py index 76d16cb..95b4309 100644 --- a/voicebot/bot_orchestrator.py +++ b/voicebot/bot_orchestrator.py @@ -330,8 +330,11 @@ async def bot_join(bot_name: str, req: JoinRequest): chat_handler = bot_data.get("chat_handler") track_handler = bot_data.get("track_handler") bind_send_chat_function = bot_data.get("chat_bind") + config_handler = bot_data.get("config_handler") logger.info(f"🤖 Bot {bot_name} joining lobby {req.lobby_id} with nick: '{req.nick}'") + if req.config_values: + logger.info(f"🤖 Bot {bot_name} has existing configuration: {req.config_values}") if track_handler: logger.info(f"🤖 Bot {bot_name} has track handling capabilities") if chat_handler: @@ -339,6 +342,18 @@ async def bot_join(bot_name: str, req: JoinRequest): if bind_send_chat_function: logger.info(f"🤖 Bot {bot_name} has chat sending capabilities") + # Apply configuration if provided + if req.config_values and config_handler: + try: + logger.info(f"Applying existing configuration to bot {bot_name}") + success = await config_handler(req.lobby_id, req.config_values) + if success: + logger.info(f"Successfully applied existing configuration to bot {bot_name}") + else: + logger.warning(f"Failed to apply existing configuration to bot {bot_name}") + except Exception as e: + logger.error(f"Error applying existing configuration to bot {bot_name}: {e}") + # Start the WebRTCSignalingClient in a background asyncio task and register it client = WebRTCSignalingClient( server_url=req.server_url, diff --git a/voicebot/bots/ai_chatbot.py b/voicebot/bots/ai_chatbot.py index dbae7d0..9e8ec14 100644 --- a/voicebot/bots/ai_chatbot.py +++ b/voicebot/bots/ai_chatbot.py @@ -35,7 +35,7 @@ except ImportError as e: AI_PROVIDERS_AVAILABLE = False -AGENT_NAME = "ai_chatbot" +AGENT_NAME = "Generative Chat Bot" AGENT_DESCRIPTION = "Advanced AI chatbot with multi-provider support, personality system, and conversation memory" # Bot configuration from environment diff --git a/voicebot/bots/synthetic_media.py b/voicebot/bots/synthetic_media.py index 0d9c78b..e3a20a0 100644 --- a/voicebot/bots/synthetic_media.py +++ b/voicebot/bots/synthetic_media.py @@ -464,7 +464,7 @@ def create_synthetic_tracks(session_name: str) -> dict[str, MediaStreamTrack]: # Agent descriptor exported for dynamic discovery by the FastAPI service -AGENT_NAME = "synthetic_media" +AGENT_NAME = "Synthetic Media Test Bot" AGENT_DESCRIPTION = "Synthetic audio and video tracks (AnimatedVideoTrack + SyntheticAudioTrack)" def agent_info() -> dict[str, str]: diff --git a/voicebot/bots/whisper.py b/voicebot/bots/whisper.py index f8f60be..84398b3 100644 --- a/voicebot/bots/whisper.py +++ b/voicebot/bots/whisper.py @@ -197,7 +197,7 @@ class OpenVINOConfig(BaseModel): # Global configuration and constants -AGENT_NAME = "whisper" +AGENT_NAME = "Transcription Bot" AGENT_DESCRIPTION = "Real-time speech transcription (OpenVINO Whisper) - converts speech to text on Intel Arc B580" SAMPLE_RATE = 16000 # Whisper expects 16kHz CHUNK_DURATION_MS = 100 # Reduced latency - 100ms chunks diff --git a/voicebot/models.py b/voicebot/models.py index c7578a2..020e078 100644 --- a/voicebot/models.py +++ b/voicebot/models.py @@ -9,7 +9,7 @@ from __future__ import annotations import argparse from enum import Enum -from typing import Dict, Optional, TYPE_CHECKING +from typing import Dict, Optional, Any, TYPE_CHECKING from dataclasses import dataclass, field from pydantic import BaseModel, Field @@ -95,6 +95,7 @@ class JoinRequest(BaseModel): nick: str server_url: str insecure: bool = False + config_values: Optional[Dict[str, Any]] = None def _default_attributes() -> Dict[str, object]: