The voices... They're getting louder.
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
"""
|
||||
Configuration management for AI Intelligence Layer.
|
||||
Uses pydantic-settings for environment variable validation.
|
||||
Environment variables are loaded via load_dotenv() in main.py.
|
||||
Automatically adapts URLs for development vs production environments.
|
||||
"""
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
from typing import Optional
|
||||
@@ -9,6 +11,10 @@ from typing import Optional
|
||||
class Settings(BaseSettings):
|
||||
"""Application settings loaded from environment variables."""
|
||||
|
||||
# Environment Configuration
|
||||
environment: str = "development" # "development" or "production"
|
||||
production_url: Optional[str] = None # e.g., "https://your-app.onrender.com"
|
||||
|
||||
# Gemini API Configuration
|
||||
gemini_api_key: str
|
||||
gemini_model: str = "gemini-1.5-pro"
|
||||
@@ -28,7 +34,7 @@ class Settings(BaseSettings):
|
||||
fast_mode: bool = True
|
||||
|
||||
# Strategy Generation Settings
|
||||
strategy_count: int = 3 # Number of strategies to generate (3 for fast testing)
|
||||
strategy_count: int = 3 # Number of strategies to generate (3 for testing, 20 for production)
|
||||
|
||||
# Performance Settings
|
||||
brainstorm_timeout: int = 30
|
||||
@@ -36,11 +42,37 @@ class Settings(BaseSettings):
|
||||
gemini_max_retries: int = 3
|
||||
|
||||
model_config = SettingsConfigDict(
|
||||
env_file=".env",
|
||||
env_file_encoding="utf-8",
|
||||
case_sensitive=False,
|
||||
extra="ignore"
|
||||
)
|
||||
|
||||
@property
|
||||
def is_production(self) -> bool:
|
||||
"""Check if running in production environment."""
|
||||
return self.environment.lower() == "production"
|
||||
|
||||
@property
|
||||
def base_url(self) -> str:
|
||||
"""Get the base URL for the application."""
|
||||
if self.is_production and self.production_url:
|
||||
return self.production_url
|
||||
return f"http://localhost:{self.ai_service_port}"
|
||||
|
||||
@property
|
||||
def websocket_url(self) -> str:
|
||||
"""Get the WebSocket URL for the application."""
|
||||
if self.is_production and self.production_url:
|
||||
# Replace https:// with wss:// or http:// with ws://
|
||||
return self.production_url.replace("https://", "wss://").replace("http://", "ws://")
|
||||
return f"ws://localhost:{self.ai_service_port}"
|
||||
|
||||
@property
|
||||
def internal_enrichment_url(self) -> str:
|
||||
"""Get the enrichment service URL (internal on Render)."""
|
||||
if self.is_production:
|
||||
# On Render, services communicate internally via localhost
|
||||
return "http://localhost:8000"
|
||||
return self.enrichment_service_url
|
||||
|
||||
|
||||
# Global settings instance
|
||||
|
||||
@@ -15,6 +15,10 @@ import random
|
||||
from typing import Dict, Any, List
|
||||
from datetime import datetime
|
||||
import json
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Load environment variables from .env file in project root
|
||||
load_dotenv()
|
||||
|
||||
from config import get_settings
|
||||
from models.input_models import (
|
||||
@@ -445,14 +449,12 @@ async def websocket_pi_endpoint(websocket: WebSocket):
|
||||
logger.info(f"LAP {lap_number} - GENERATING STRATEGY")
|
||||
logger.info(f"{'='*60}")
|
||||
|
||||
# Send immediate acknowledgment while processing
|
||||
# Use last known control values instead of resetting to neutral
|
||||
# Send SILENT acknowledgment to prevent timeout (no control update)
|
||||
# This tells the Pi "we're working on it" without triggering voice/controls
|
||||
await websocket.send_json({
|
||||
"type": "control_command",
|
||||
"type": "acknowledgment",
|
||||
"lap": lap_number,
|
||||
"brake_bias": last_control_command["brake_bias"],
|
||||
"differential_slip": last_control_command["differential_slip"],
|
||||
"message": "Processing strategies (maintaining previous settings)..."
|
||||
"message": "Processing strategies, please wait..."
|
||||
})
|
||||
|
||||
# Generate strategies (this is the slow part)
|
||||
@@ -500,6 +502,7 @@ async def websocket_pi_endpoint(websocket: WebSocket):
|
||||
"brake_bias": control_command["brake_bias"],
|
||||
"differential_slip": control_command["differential_slip"],
|
||||
"strategy_name": top_strategy.strategy_name if top_strategy else "N/A",
|
||||
"risk_level": top_strategy.risk_level if top_strategy else "medium",
|
||||
"total_strategies": len(response.strategies),
|
||||
"reasoning": control_command.get("reasoning", "")
|
||||
})
|
||||
|
||||
@@ -16,7 +16,8 @@ class TelemetryClient:
|
||||
def __init__(self):
|
||||
"""Initialize telemetry client."""
|
||||
settings = get_settings()
|
||||
self.base_url = settings.enrichment_service_url
|
||||
# Use internal_enrichment_url which adapts for production
|
||||
self.base_url = settings.internal_enrichment_url
|
||||
self.fetch_limit = settings.enrichment_fetch_limit
|
||||
logger.info(f"Telemetry client initialized for {self.base_url}")
|
||||
|
||||
|
||||
@@ -683,7 +683,13 @@
|
||||
}
|
||||
|
||||
function connect() {
|
||||
ws = new WebSocket('ws://localhost:9000/ws/dashboard');
|
||||
// Dynamically determine WebSocket URL based on current location
|
||||
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
const host = window.location.host;
|
||||
const wsUrl = `${protocol}//${host}/ws/dashboard`;
|
||||
|
||||
console.log(`Connecting to WebSocket: ${wsUrl}`);
|
||||
ws = new WebSocket(wsUrl);
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log('Dashboard WebSocket connected');
|
||||
|
||||
Reference in New Issue
Block a user