ai-voicebot/voicebot/step_5b_integration_demo.py

478 lines
20 KiB
Python

"""Step 5B Integration: Enhanced Bot Orchestrator with Advanced Bot Management.
This module demonstrates how the new advanced bot management features integrate
with the existing bot orchestrator to provide:
1. AI Provider-powered bots with multiple backend support
2. Personality-driven bot behavior and responses
3. Conversation context and memory management
4. Dynamic bot configuration and health monitoring
This integration enhances the existing bot discovery and management system
without breaking compatibility with existing bot implementations.
"""
import os
import json
import time
import asyncio
from typing import Dict, Optional, Any
from pathlib import Path
# Import existing bot orchestrator functionality
from bot_orchestrator import discover_bots
# Import advanced bot management modules
try:
from voicebot.ai_providers import ai_provider_manager, AIProviderType
from voicebot.personality_system import personality_manager
from voicebot.conversation_context import context_manager
AI_FEATURES_AVAILABLE = True
except ImportError as e:
print(f"Warning: Advanced AI features not available: {e}")
AI_FEATURES_AVAILABLE = False
from logger import logger
class EnhancedBotOrchestrator:
"""Enhanced bot orchestrator with Step 5B advanced management features."""
def __init__(self):
self.enhanced_bots = {} # Enhanced bots with AI features
self.bot_configurations = {} # Bot-specific configurations
self.health_stats = {} # Health monitoring data
# Load configurations
self._load_bot_configurations()
# Initialize AI systems if available
if AI_FEATURES_AVAILABLE:
self._initialize_ai_systems()
def _load_bot_configurations(self):
"""Load bot configurations from JSON file."""
config_path = Path(__file__).parent / "enhanced_bot_configs.json"
default_configs = {
"ai_chatbot": {
"personality": "helpful_assistant",
"ai_provider": "openai",
"streaming": True,
"memory_enabled": True,
"advanced_features": True
},
"technical_expert": {
"personality": "technical_expert",
"ai_provider": "anthropic",
"streaming": False,
"memory_enabled": True,
"advanced_features": True
},
"creative_companion": {
"personality": "creative_companion",
"ai_provider": "local",
"streaming": True,
"memory_enabled": True,
"advanced_features": True
}
}
try:
if config_path.exists():
with open(config_path, 'r') as f:
self.bot_configurations = json.load(f)
else:
self.bot_configurations = default_configs
self._save_bot_configurations()
except Exception as e:
logger.error(f"Failed to load bot configurations: {e}")
self.bot_configurations = default_configs
def _save_bot_configurations(self):
"""Save bot configurations to JSON file."""
config_path = Path(__file__).parent / "enhanced_bot_configs.json"
try:
with open(config_path, 'w') as f:
json.dump(self.bot_configurations, f, indent=2)
except Exception as e:
logger.error(f"Failed to save bot configurations: {e}")
def _initialize_ai_systems(self):
"""Initialize AI provider and personality systems."""
try:
# Ensure default personality templates are loaded
personality_manager.ensure_default_templates()
# Register available AI providers based on environment
providers_to_init = []
if os.getenv("OPENAI_API_KEY"):
providers_to_init.append(AIProviderType.OPENAI)
if os.getenv("ANTHROPIC_API_KEY"):
providers_to_init.append(AIProviderType.ANTHROPIC)
# Local provider is always available
providers_to_init.append(AIProviderType.LOCAL)
for provider_type in providers_to_init:
try:
provider = ai_provider_manager.create_provider(provider_type)
ai_provider_manager.register_provider(f"system_{provider_type.value}", provider)
logger.info(f"Initialized AI provider: {provider_type.value}")
except Exception as e:
logger.warning(f"Failed to initialize provider {provider_type.value}: {e}")
logger.info("AI systems initialized successfully")
except Exception as e:
logger.error(f"Failed to initialize AI systems: {e}")
async def discover_enhanced_bots(self) -> Dict[str, Dict[str, Any]]:
"""Discover bots with enhanced information about AI capabilities."""
# Start with standard bot discovery
standard_bots = discover_bots() # Returns List[BotInfoModel]
enhanced_bot_info = {}
# Convert BotInfoModel list to dict and enhance with AI capabilities
for bot_info in standard_bots:
bot_name = bot_info.name
bot_info_dict = {
"name": bot_name,
"description": bot_info.description,
"has_media": bot_info.has_media,
"standard_info": {
"name": bot_name,
"description": bot_info.description,
"has_media": bot_info.has_media
},
"enhanced_features": False,
"ai_capabilities": {},
"health_status": "unknown"
}
# Check if bot supports enhanced features
if bot_name in self.bot_configurations:
config = self.bot_configurations[bot_name]
if config.get("advanced_features", False):
bot_info_dict["enhanced_features"] = True
bot_info_dict["ai_capabilities"] = {
"personality": config.get("personality", "default"),
"ai_provider": config.get("ai_provider", "local"),
"streaming": config.get("streaming", False),
"memory_enabled": config.get("memory_enabled", False)
}
# Check bot health if it supports it (would need to import the bot module)
try:
bot_module_path = f"voicebot.bots.{bot_name}"
bot_module = __import__(bot_module_path, fromlist=[bot_name])
if hasattr(bot_module, 'get_bot_status'):
status = await bot_module.get_bot_status()
bot_info_dict["health_status"] = "healthy"
bot_info_dict["detailed_status"] = status
except Exception as e:
bot_info_dict["health_status"] = f"import_error: {e}"
enhanced_bot_info[bot_name] = bot_info_dict
return enhanced_bot_info
async def create_enhanced_bot_instance(self, bot_name: str, session_name: str) -> Optional[Any]:
"""Create an enhanced bot instance with AI features configured."""
if not AI_FEATURES_AVAILABLE:
logger.warning(f"Cannot create enhanced bot {bot_name} - AI features not available")
return None
if bot_name not in self.bot_configurations:
logger.warning(f"No configuration found for enhanced bot: {bot_name}")
return None
config = self.bot_configurations[bot_name]
try:
# Set environment variables for the bot based on configuration
os.environ[f"{bot_name.upper()}_PERSONALITY"] = config.get("personality", "helpful_assistant")
os.environ[f"{bot_name.upper()}_PROVIDER"] = config.get("ai_provider", "local")
os.environ[f"{bot_name.upper()}_STREAMING"] = str(config.get("streaming", False)).lower()
os.environ[f"{bot_name.upper()}_MEMORY"] = str(config.get("memory_enabled", False)).lower()
# Import and create the bot
bot_module_path = f"voicebot.bots.{bot_name}"
bot_module = __import__(bot_module_path, fromlist=[bot_name])
# If the bot has a specific initialization function, use it
if hasattr(bot_module, 'create_enhanced_instance'):
bot_instance = await bot_module.create_enhanced_instance(session_name, config)
else:
# Create standard bot instance
bot_instance = bot_module
self.enhanced_bots[f"{bot_name}_{session_name}"] = {
"instance": bot_instance,
"config": config,
"session": session_name,
"created_at": time.time()
}
logger.info(f"Created enhanced bot instance: {bot_name} for session {session_name}")
return bot_instance
except Exception as e:
logger.error(f"Failed to create enhanced bot instance {bot_name}: {e}")
return None
async def monitor_bot_health(self) -> Dict[str, Any]:
"""Monitor health of all enhanced bots and AI systems."""
health_report = {
"timestamp": time.time(),
"ai_systems_available": AI_FEATURES_AVAILABLE,
"enhanced_bots": {},
"ai_providers": {},
"personality_system": {},
"conversation_contexts": {}
}
if not AI_FEATURES_AVAILABLE:
health_report["status"] = "limited - AI features disabled"
return health_report
try:
# Check AI providers
for provider_id, provider in ai_provider_manager.list_providers().items():
try:
provider_instance = ai_provider_manager.get_provider(provider_id)
if provider_instance:
is_healthy = await provider_instance.health_check()
health_report["ai_providers"][provider_id] = {
"status": "healthy" if is_healthy else "unhealthy",
"type": provider.value if hasattr(provider, 'value') else str(provider)
}
except Exception as e:
health_report["ai_providers"][provider_id] = {
"status": f"error: {e}",
"type": "unknown"
}
# Check personality system
try:
templates = personality_manager.list_templates()
health_report["personality_system"] = {
"status": "healthy",
"available_templates": len(templates),
"template_ids": [t.id for t in templates]
}
except Exception as e:
health_report["personality_system"] = {
"status": f"error: {e}"
}
# Check conversation context system
try:
context_stats = context_manager.get_statistics()
health_report["conversation_contexts"] = {
"status": "healthy",
"statistics": context_stats
}
except Exception as e:
health_report["conversation_contexts"] = {
"status": f"error: {e}"
}
# Check enhanced bot instances
for bot_key, bot_data in self.enhanced_bots.items():
try:
bot_instance = bot_data["instance"]
if hasattr(bot_instance, 'health_check'):
bot_health = await bot_instance.health_check()
health_report["enhanced_bots"][bot_key] = {
"status": "healthy",
"details": bot_health,
"uptime": time.time() - bot_data["created_at"]
}
else:
health_report["enhanced_bots"][bot_key] = {
"status": "unknown - no health check available",
"uptime": time.time() - bot_data["created_at"]
}
except Exception as e:
health_report["enhanced_bots"][bot_key] = {
"status": f"error: {e}",
"uptime": time.time() - bot_data.get("created_at", time.time())
}
health_report["status"] = "operational"
except Exception as e:
health_report["status"] = f"system_error: {e}"
# Store health stats for trending
self.health_stats[int(time.time())] = health_report
# Keep only last 24 hours of health stats
cutoff_time = time.time() - (24 * 60 * 60)
self.health_stats = {
timestamp: stats for timestamp, stats in self.health_stats.items()
if timestamp > cutoff_time
}
return health_report
async def configure_bot_runtime(self, bot_name: str, new_config: Dict[str, Any]) -> bool:
"""Dynamically reconfigure a bot at runtime."""
if bot_name not in self.bot_configurations:
logger.error(f"Bot {bot_name} not found in configurations")
return False
try:
# Update configuration
old_config = self.bot_configurations[bot_name].copy()
self.bot_configurations[bot_name].update(new_config)
# Save updated configuration
self._save_bot_configurations()
# If there are active instances, try to update them
updated_instances = []
for bot_key, bot_data in self.enhanced_bots.items():
if bot_key.startswith(f"{bot_name}_"):
bot_instance = bot_data["instance"]
# Try to update personality if changed
if "personality" in new_config and hasattr(bot_instance, 'switch_personality'):
success = await bot_instance.switch_personality(new_config["personality"])
if success:
updated_instances.append(f"{bot_key} personality")
# Try to update AI provider if changed
if "ai_provider" in new_config and hasattr(bot_instance, 'switch_ai_provider'):
success = await bot_instance.switch_ai_provider(new_config["ai_provider"])
if success:
updated_instances.append(f"{bot_key} provider")
# Update bot data configuration
bot_data["config"] = self.bot_configurations[bot_name]
logger.info(f"Bot {bot_name} configuration updated. Active instances updated: {updated_instances}")
return True
except Exception as e:
# Rollback configuration on error
self.bot_configurations[bot_name] = old_config
logger.error(f"Failed to configure bot {bot_name}: {e}")
return False
def get_bot_analytics(self) -> Dict[str, Any]:
"""Get analytics and usage statistics for enhanced bots."""
analytics = {
"enhanced_bots_count": len(self.enhanced_bots),
"configurations_count": len(self.bot_configurations),
"health_history_points": len(self.health_stats),
"bot_breakdown": {},
"feature_usage": {
"ai_providers": {},
"personalities": {},
"memory_enabled": 0,
"streaming_enabled": 0
}
}
# Analyze bot configurations
for bot_name, config in self.bot_configurations.items():
analytics["bot_breakdown"][bot_name] = {
"enhanced_features": config.get("advanced_features", False),
"ai_provider": config.get("ai_provider", "none"),
"personality": config.get("personality", "none"),
"active_instances": sum(1 for key in self.enhanced_bots.keys() if key.startswith(f"{bot_name}_"))
}
# Count feature usage
provider = config.get("ai_provider", "none")
analytics["feature_usage"]["ai_providers"][provider] = analytics["feature_usage"]["ai_providers"].get(provider, 0) + 1
personality = config.get("personality", "none")
analytics["feature_usage"]["personalities"][personality] = analytics["feature_usage"]["personalities"].get(personality, 0) + 1
if config.get("memory_enabled", False):
analytics["feature_usage"]["memory_enabled"] += 1
if config.get("streaming", False):
analytics["feature_usage"]["streaming_enabled"] += 1
# Add conversation context statistics if available
if AI_FEATURES_AVAILABLE:
try:
context_stats = context_manager.get_statistics()
analytics["conversation_statistics"] = context_stats
except Exception as e:
analytics["conversation_statistics"] = {"error": str(e)}
return analytics
# Global enhanced orchestrator instance
enhanced_orchestrator = EnhancedBotOrchestrator()
async def demo_step_5b_integration():
"""Demonstrate Step 5B integration capabilities."""
print("=== Step 5B Advanced Bot Management Demo ===\n")
# 1. Discover enhanced bots
print("1. Discovering bots with enhanced capabilities...")
enhanced_bots = await enhanced_orchestrator.discover_enhanced_bots()
for bot_name, info in enhanced_bots.items():
print(f" Bot: {bot_name}")
print(f" Enhanced: {info['enhanced_features']}")
if info['enhanced_features']:
print(f" AI Capabilities: {info['ai_capabilities']}")
print(f" Health: {info['health_status']}")
print()
# 2. Create enhanced bot instance
print("2. Creating enhanced AI chatbot instance...")
bot_instance = await enhanced_orchestrator.create_enhanced_bot_instance("ai_chatbot", "demo_session")
if bot_instance:
print(" ✓ Enhanced AI chatbot created successfully")
else:
print(" ✗ Failed to create enhanced bot")
print()
# 3. Monitor system health
print("3. Monitoring system health...")
health_report = await enhanced_orchestrator.monitor_bot_health()
print(f" System Status: {health_report['status']}")
print(f" AI Features Available: {health_report['ai_systems_available']}")
if health_report['ai_systems_available']:
print(f" AI Providers: {len(health_report['ai_providers'])} registered")
print(f" Personality Templates: {health_report['personality_system'].get('available_templates', 0)}")
print(f" Enhanced Bot Instances: {len(health_report['enhanced_bots'])}")
print()
# 4. Runtime configuration
print("4. Demonstrating runtime configuration...")
config_success = await enhanced_orchestrator.configure_bot_runtime("ai_chatbot", {
"personality": "technical_expert",
"streaming": False
})
print(f" Configuration Update: {'✓ Success' if config_success else '✗ Failed'}")
print()
# 5. Analytics
print("5. Bot analytics and usage statistics...")
analytics = enhanced_orchestrator.get_bot_analytics()
print(f" Enhanced Bots: {analytics['enhanced_bots_count']}")
print(f" Configurations: {analytics['configurations_count']}")
print(" Feature Usage:")
for feature, usage in analytics['feature_usage'].items():
print(f" {feature}: {usage}")
print()
print("=== Step 5B Integration Demo Complete ===")
if __name__ == "__main__":
# Run the demo
asyncio.run(demo_step_5b_integration())