|
"""
|
|
Configuration management for Product Feature Validation Agent
|
|
Handles API keys, environment settings, and deployment configurations
|
|
"""
|
|
|
|
import os
|
|
from typing import Dict, Any, Optional
|
|
from dataclasses import dataclass
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
@dataclass
|
|
class APIConfig:
|
|
"""API configuration settings"""
|
|
anthropic_api_key: Optional[str] = None
|
|
modal_token: Optional[str] = None
|
|
newsapi_key: Optional[str] = None
|
|
reddit_client_id: Optional[str] = None
|
|
reddit_client_secret: Optional[str] = None
|
|
|
|
@dataclass
|
|
class ProcessingConfig:
|
|
"""Processing configuration settings"""
|
|
max_reviews_per_app: int = 50
|
|
max_reddit_posts: int = 50
|
|
max_news_articles: int = 50
|
|
sentiment_batch_size: int = 32
|
|
modal_gpu_type: str = "T4"
|
|
claude_model: str = "claude-3.5-sonnet-20241022"
|
|
max_tokens: int = 2000
|
|
|
|
@dataclass
|
|
class HackathonConfig:
|
|
"""Hackathon-specific configuration"""
|
|
project_name: str = "product-feature-agent"
|
|
team_name: str = "IYKYKnow.ai"
|
|
track: str = "mcp-server-track"
|
|
gradio_server_port: int = 7860
|
|
mcp_server_enabled: bool = True
|
|
|
|
class ConfigManager:
|
|
"""Manages application configuration"""
|
|
|
|
def __init__(self):
|
|
self.api_config = self._load_api_config()
|
|
self.processing_config = ProcessingConfig()
|
|
self.hackathon_config = HackathonConfig()
|
|
|
|
def _load_api_config(self) -> APIConfig:
|
|
"""Load API configuration from environment variables"""
|
|
return APIConfig(
|
|
anthropic_api_key=os.getenv("ANTHROPIC_API_KEY"),
|
|
modal_token=os.getenv("MODAL_TOKEN"),
|
|
newsapi_key=os.getenv("NEWSAPI_KEY"),
|
|
reddit_client_id=os.getenv("REDDIT_CLIENT_ID"),
|
|
reddit_client_secret=os.getenv("REDDIT_CLIENT_SECRET")
|
|
)
|
|
|
|
def is_production_ready(self) -> bool:
|
|
"""Check if all required API keys are configured"""
|
|
required_keys = [
|
|
self.api_config.anthropic_api_key,
|
|
self.api_config.modal_token,
|
|
self.api_config.newsapi_key
|
|
]
|
|
return all(key is not None for key in required_keys)
|
|
|
|
def get_demo_mode_status(self) -> Dict[str, bool]:
|
|
"""Get status of which services are in demo mode"""
|
|
return {
|
|
"anthropic": self.api_config.anthropic_api_key is None,
|
|
"modal": self.api_config.modal_token is None,
|
|
"newsapi": self.api_config.newsapi_key is None,
|
|
"reddit": self.api_config.reddit_client_id is None
|
|
}
|
|
|
|
def get_cost_estimates(self) -> Dict[str, Any]:
|
|
"""Get estimated costs for different operations"""
|
|
return {
|
|
"modal_labs": {
|
|
"t4_gpu_per_hour": 0.60,
|
|
"credits_available": 250,
|
|
"estimated_usage": 15.77,
|
|
"efficiency_percentage": 6.3
|
|
},
|
|
"anthropic": {
|
|
"credits_available": 25,
|
|
"batch_discount": 0.50,
|
|
"estimated_tokens": 125000,
|
|
"cost_per_1k_tokens": 0.003
|
|
},
|
|
"newsapi": {
|
|
"free_tier_requests": 1000,
|
|
"estimated_usage": 200
|
|
}
|
|
}
|
|
|
|
|
|
config = ConfigManager()
|
|
|
|
def get_config() -> ConfigManager:
|
|
"""Get the global configuration instance"""
|
|
return config
|
|
|
|
def log_configuration_status():
|
|
"""Log current configuration status"""
|
|
demo_status = config.get_demo_mode_status()
|
|
demo_services = [service for service, is_demo in demo_status.items() if is_demo]
|
|
|
|
if config.is_production_ready():
|
|
logger.info("All API keys configured - running in production mode")
|
|
else:
|
|
logger.warning(f"Missing API keys: {demo_services} - running in demo mode")
|
|
|
|
cost_estimates = config.get_cost_estimates()
|
|
logger.info(f"Estimated Modal Labs usage: ${cost_estimates['modal_labs']['estimated_usage']}")
|
|
logger.info(f"Estimated Anthropic usage: {cost_estimates['anthropic']['estimated_tokens']} tokens")
|
|
|
|
if __name__ == "__main__":
|
|
|
|
log_configuration_status()
|
|
print(f"Production ready: {config.is_production_ready()}")
|
|
print(f"Demo mode services: {config.get_demo_mode_status()}") |