478 lines
20 KiB
Python
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())
|