Remove all previously tracked files that are now ignored
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
.env
|
.env
|
||||||
|
__pycache__/
|
||||||
*.pyc
|
*.pyc
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
# Gemini API Configuration
|
|
||||||
GEMINI_API_KEY=AIzaSyDK_jxVlJUpzyxuiGcopSFkiqMAUD3-w0I
|
|
||||||
GEMINI_MODEL=gemini-2.5-flash
|
|
||||||
|
|
||||||
# Service Configuration
|
|
||||||
AI_SERVICE_PORT=9000
|
|
||||||
AI_SERVICE_HOST=0.0.0.0
|
|
||||||
|
|
||||||
# Enrichment Service Integration
|
|
||||||
ENRICHMENT_SERVICE_URL=http://localhost:8000
|
|
||||||
ENRICHMENT_FETCH_LIMIT=10
|
|
||||||
|
|
||||||
# Demo Mode (enables caching and consistent responses for demos)
|
|
||||||
DEMO_MODE=false
|
|
||||||
|
|
||||||
# Fast Mode (use shorter prompts for faster responses)
|
|
||||||
FAST_MODE=true
|
|
||||||
|
|
||||||
# Strategy Generation Settings
|
|
||||||
STRATEGY_COUNT=3 # Number of strategies to generate (3 for testing, 20 for production)
|
|
||||||
|
|
||||||
# Performance Settings
|
|
||||||
BRAINSTORM_TIMEOUT=90
|
|
||||||
ANALYZE_TIMEOUT=120
|
|
||||||
GEMINI_MAX_RETRIES=3
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -49,6 +49,7 @@ strategy_generator: StrategyGenerator = None
|
|||||||
telemetry_client: TelemetryClient = None
|
telemetry_client: TelemetryClient = None
|
||||||
current_race_context: RaceContext = None # Store race context globally
|
current_race_context: RaceContext = None # Store race context globally
|
||||||
last_control_command: Dict[str, int] = {"brake_bias": 5, "differential_slip": 5} # Store last command
|
last_control_command: Dict[str, int] = {"brake_bias": 5, "differential_slip": 5} # Store last command
|
||||||
|
strategy_history: List[Dict[str, Any]] = [] # Track past strategies for continuity
|
||||||
|
|
||||||
# WebSocket connection manager
|
# WebSocket connection manager
|
||||||
class ConnectionManager:
|
class ConnectionManager:
|
||||||
@@ -378,7 +379,7 @@ async def websocket_pi_endpoint(websocket: WebSocket):
|
|||||||
2. AI layer processes telemetry and generates strategies
|
2. AI layer processes telemetry and generates strategies
|
||||||
3. AI layer pushes control commands back to Pi (brake_bias, differential_slip)
|
3. AI layer pushes control commands back to Pi (brake_bias, differential_slip)
|
||||||
"""
|
"""
|
||||||
global current_race_context, last_control_command
|
global current_race_context, last_control_command, strategy_history
|
||||||
|
|
||||||
vehicle_id = await websocket_manager.connect(websocket)
|
vehicle_id = await websocket_manager.connect(websocket)
|
||||||
|
|
||||||
@@ -389,7 +390,11 @@ async def websocket_pi_endpoint(websocket: WebSocket):
|
|||||||
# Reset last control command to neutral for new session
|
# Reset last control command to neutral for new session
|
||||||
last_control_command = {"brake_bias": 5, "differential_slip": 5}
|
last_control_command = {"brake_bias": 5, "differential_slip": 5}
|
||||||
|
|
||||||
|
# Clear strategy history for new race
|
||||||
|
strategy_history = []
|
||||||
|
|
||||||
logger.info("[WebSocket] Telemetry buffer cleared for new connection")
|
logger.info("[WebSocket] Telemetry buffer cleared for new connection")
|
||||||
|
logger.info("[WebSocket] Strategy history cleared for new race")
|
||||||
|
|
||||||
# Notify dashboards of new vehicle connection
|
# Notify dashboards of new vehicle connection
|
||||||
await dashboard_manager.broadcast({
|
await dashboard_manager.broadcast({
|
||||||
@@ -454,12 +459,26 @@ async def websocket_pi_endpoint(websocket: WebSocket):
|
|||||||
try:
|
try:
|
||||||
response = await strategy_generator.generate(
|
response = await strategy_generator.generate(
|
||||||
enriched_telemetry=buffer_data,
|
enriched_telemetry=buffer_data,
|
||||||
race_context=current_race_context
|
race_context=current_race_context,
|
||||||
|
strategy_history=strategy_history
|
||||||
)
|
)
|
||||||
|
|
||||||
# Extract top strategy (first one)
|
# Extract top strategy (first one)
|
||||||
top_strategy = response.strategies[0] if response.strategies else None
|
top_strategy = response.strategies[0] if response.strategies else None
|
||||||
|
|
||||||
|
# Add to strategy history
|
||||||
|
if top_strategy:
|
||||||
|
strategy_history.append({
|
||||||
|
"lap": lap_number,
|
||||||
|
"strategy_name": top_strategy.strategy_name,
|
||||||
|
"risk_level": top_strategy.risk_level,
|
||||||
|
"brief_description": top_strategy.brief_description,
|
||||||
|
"reasoning": top_strategy.reasoning
|
||||||
|
})
|
||||||
|
# Keep only last 10 strategies
|
||||||
|
if len(strategy_history) > 10:
|
||||||
|
strategy_history.pop(0)
|
||||||
|
|
||||||
# Generate control commands based on strategy
|
# Generate control commands based on strategy
|
||||||
control_command = generate_control_command(
|
control_command = generate_control_command(
|
||||||
lap_number=lap_number,
|
lap_number=lap_number,
|
||||||
@@ -490,6 +509,11 @@ async def websocket_pi_endpoint(websocket: WebSocket):
|
|||||||
"type": "lap_data",
|
"type": "lap_data",
|
||||||
"vehicle_id": vehicle_id,
|
"vehicle_id": vehicle_id,
|
||||||
"lap_data": enriched,
|
"lap_data": enriched,
|
||||||
|
"race_context": {
|
||||||
|
"position": current_race_context.driver_state.current_position,
|
||||||
|
"gap_to_leader": current_race_context.driver_state.gap_to_leader,
|
||||||
|
"gap_to_ahead": current_race_context.driver_state.gap_to_ahead
|
||||||
|
},
|
||||||
"control_output": {
|
"control_output": {
|
||||||
"brake_bias": control_command["brake_bias"],
|
"brake_bias": control_command["brake_bias"],
|
||||||
"differential_slip": control_command["differential_slip"]
|
"differential_slip": control_command["differential_slip"]
|
||||||
@@ -497,7 +521,8 @@ async def websocket_pi_endpoint(websocket: WebSocket):
|
|||||||
"strategy": {
|
"strategy": {
|
||||||
"strategy_name": top_strategy.strategy_name,
|
"strategy_name": top_strategy.strategy_name,
|
||||||
"risk_level": top_strategy.risk_level,
|
"risk_level": top_strategy.risk_level,
|
||||||
"brief_description": top_strategy.brief_description
|
"brief_description": top_strategy.brief_description,
|
||||||
|
"reasoning": top_strategy.reasoning
|
||||||
} if top_strategy else None,
|
} if top_strategy else None,
|
||||||
"timestamp": datetime.now().isoformat()
|
"timestamp": datetime.now().isoformat()
|
||||||
})
|
})
|
||||||
@@ -527,6 +552,11 @@ async def websocket_pi_endpoint(websocket: WebSocket):
|
|||||||
"type": "lap_data",
|
"type": "lap_data",
|
||||||
"vehicle_id": vehicle_id,
|
"vehicle_id": vehicle_id,
|
||||||
"lap_data": enriched,
|
"lap_data": enriched,
|
||||||
|
"race_context": {
|
||||||
|
"position": current_race_context.driver_state.current_position,
|
||||||
|
"gap_to_leader": current_race_context.driver_state.gap_to_leader,
|
||||||
|
"gap_to_ahead": current_race_context.driver_state.gap_to_ahead
|
||||||
|
},
|
||||||
"control_output": {
|
"control_output": {
|
||||||
"brake_bias": 5,
|
"brake_bias": 5,
|
||||||
"differential_slip": 5
|
"differential_slip": 5
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -62,6 +62,7 @@ class Strategy(BaseModel):
|
|||||||
pit_laps: List[int] = Field(..., description="Lap numbers for pit stops")
|
pit_laps: List[int] = Field(..., description="Lap numbers for pit stops")
|
||||||
tire_sequence: List[Literal["soft", "medium", "hard", "intermediate", "wet"]] = Field(..., description="Tire compounds in order")
|
tire_sequence: List[Literal["soft", "medium", "hard", "intermediate", "wet"]] = Field(..., description="Tire compounds in order")
|
||||||
brief_description: str = Field(..., description="One sentence rationale")
|
brief_description: str = Field(..., description="One sentence rationale")
|
||||||
|
reasoning: Optional[str] = Field(None, description="Detailed explanation including strategy change/continuity rationale")
|
||||||
risk_level: Literal["low", "medium", "high", "critical"] = Field(..., description="Risk assessment")
|
risk_level: Literal["low", "medium", "high", "critical"] = Field(..., description="Risk assessment")
|
||||||
key_assumption: str = Field(..., description="Main assumption this strategy relies on")
|
key_assumption: str = Field(..., description="Main assumption this strategy relies on")
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -9,7 +9,8 @@ from config import get_settings
|
|||||||
|
|
||||||
def build_brainstorm_prompt_fast(
|
def build_brainstorm_prompt_fast(
|
||||||
enriched_telemetry: List[EnrichedTelemetryWebhook],
|
enriched_telemetry: List[EnrichedTelemetryWebhook],
|
||||||
race_context: RaceContext
|
race_context: RaceContext,
|
||||||
|
strategy_history: List[dict] = None
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Build a faster, more concise prompt for quicker responses (lap-level data)."""
|
"""Build a faster, more concise prompt for quicker responses (lap-level data)."""
|
||||||
settings = get_settings()
|
settings = get_settings()
|
||||||
@@ -27,17 +28,29 @@ def build_brainstorm_prompt_fast(
|
|||||||
if gap_to_leader > 0 and position > 1:
|
if gap_to_leader > 0 and position > 1:
|
||||||
comp_info += f", {gap_to_leader:.1f}s from leader"
|
comp_info += f", {gap_to_leader:.1f}s from leader"
|
||||||
|
|
||||||
|
# Format strategy history (last 3 strategies)
|
||||||
|
history_text = ""
|
||||||
|
if strategy_history and len(strategy_history) > 0:
|
||||||
|
recent_history = strategy_history[-3:] # Last 3 strategies
|
||||||
|
history_lines = []
|
||||||
|
for h in recent_history:
|
||||||
|
history_lines.append(f"Lap {h['lap']}: {h['strategy_name']} (Risk: {h['risk_level']})")
|
||||||
|
history_text = f"\n\nPAST STRATEGIES:\n" + "\n".join(history_lines)
|
||||||
|
history_text += f"\n\nREQUIREMENT: If changing from previous strategy '{recent_history[-1]['strategy_name']}', explain WHY the switch is necessary. If staying with same approach, explain continuity."
|
||||||
|
else:
|
||||||
|
history_text = "\n\nNOTE: This is the first strategy generation - no previous strategy to compare."
|
||||||
|
|
||||||
if count == 1:
|
if count == 1:
|
||||||
# Ultra-fast mode: just generate 1 strategy
|
# Ultra-fast mode: just generate 1 strategy
|
||||||
return f"""Generate 1 F1 race strategy for {race_context.driver_state.driver_name} at {race_context.race_info.track_name}.
|
return f"""Generate 1 F1 race strategy for {race_context.driver_state.driver_name} at {race_context.race_info.track_name}.
|
||||||
|
|
||||||
CURRENT: Lap {race_context.race_info.current_lap}/{race_context.race_info.total_laps}, {comp_info}, {race_context.driver_state.current_tire_compound} tires ({race_context.driver_state.tire_age_laps} laps old)
|
CURRENT: Lap {race_context.race_info.current_lap}/{race_context.race_info.total_laps}, {comp_info}, {race_context.driver_state.current_tire_compound} tires ({race_context.driver_state.tire_age_laps} laps old)
|
||||||
|
|
||||||
TELEMETRY: Tire deg {latest.tire_degradation_rate:.2f}, Cliff risk {latest.tire_cliff_risk:.2f}, Pace {latest.pace_trend}, Position trend {latest.position_trend}, Competitive pressure {latest.competitive_pressure:.2f}
|
TELEMETRY: Tire deg {latest.tire_degradation_rate:.2f}, Cliff risk {latest.tire_cliff_risk:.2f}, Pace {latest.pace_trend}, Position trend {latest.position_trend}, Competitive pressure {latest.competitive_pressure:.2f}{history_text}
|
||||||
|
|
||||||
Generate 1 optimal strategy considering competitive position. Min 2 tire compounds required.
|
Generate 1 optimal strategy considering competitive position. Min 2 tire compounds required.
|
||||||
|
|
||||||
JSON: {{"strategies": [{{"strategy_id": 1, "strategy_name": "name", "stop_count": 1, "pit_laps": [32], "tire_sequence": ["medium", "hard"], "brief_description": "one sentence", "risk_level": "medium", "key_assumption": "main assumption"}}]}}"""
|
JSON: {{"strategies": [{{"strategy_id": 1, "strategy_name": "name", "stop_count": 1, "pit_laps": [32], "tire_sequence": ["medium", "hard"], "brief_description": "one sentence", "reasoning": "detailed explanation including strategy change rationale if applicable", "risk_level": "medium", "key_assumption": "main assumption"}}]}}"""
|
||||||
|
|
||||||
elif count <= 5:
|
elif count <= 5:
|
||||||
# Fast mode: 2-5 strategies with different approaches
|
# Fast mode: 2-5 strategies with different approaches
|
||||||
@@ -47,11 +60,13 @@ CURRENT: Lap {race_context.race_info.current_lap}/{race_context.race_info.total_
|
|||||||
|
|
||||||
TELEMETRY: Tire deg {latest.tire_degradation_rate:.2f}, Cliff risk {latest.tire_cliff_risk:.2f}, Pace {latest.pace_trend}, Delta {latest.performance_delta:+.2f}s, Position trend {latest.position_trend}, Competitive pressure {latest.competitive_pressure:.2f}
|
TELEMETRY: Tire deg {latest.tire_degradation_rate:.2f}, Cliff risk {latest.tire_cliff_risk:.2f}, Pace {latest.pace_trend}, Delta {latest.performance_delta:+.2f}s, Position trend {latest.position_trend}, Competitive pressure {latest.competitive_pressure:.2f}
|
||||||
|
|
||||||
COMPETITIVE SITUATION: Gap to ahead {gap_to_ahead:.1f}s ({"DRS RANGE - attack opportunity!" if gap_to_ahead < 1.0 else "close battle" if gap_to_ahead < 3.0 else "need to push"})
|
COMPETITIVE SITUATION: Gap to ahead {gap_to_ahead:.1f}s ({"DRS RANGE - attack opportunity!" if gap_to_ahead < 1.0 else "close battle" if gap_to_ahead < 3.0 else "need to push"}){history_text}
|
||||||
|
|
||||||
Generate {count} strategies balancing tire management with competitive pressure. Consider if aggressive undercut makes sense given gaps. Min 2 tire compounds each.
|
Generate {count} strategies balancing tire management with competitive pressure. Consider if aggressive undercut makes sense given gaps. Min 2 tire compounds each.
|
||||||
|
|
||||||
JSON: {{"strategies": [{{"strategy_id": 1, "strategy_name": "Conservative Stay Out", "stop_count": 1, "pit_laps": [35], "tire_sequence": ["medium", "hard"], "brief_description": "extend current stint then hard tires to end", "risk_level": "low", "key_assumption": "tire cliff risk stays below 0.7"}}]}}"""
|
CRITICAL: Each strategy MUST include 'reasoning' field explaining the approach and, if applicable, why it differs from or continues the previous strategy.
|
||||||
|
|
||||||
|
JSON: {{"strategies": [{{"strategy_id": 1, "strategy_name": "Conservative Stay Out", "stop_count": 1, "pit_laps": [35], "tire_sequence": ["medium", "hard"], "brief_description": "extend current stint then hard tires to end", "reasoning": "Detailed explanation of this strategy including why we're switching from/continuing previous approach based on current telemetry and competitive situation", "risk_level": "low", "key_assumption": "tire cliff risk stays below 0.7"}}]}}"""
|
||||||
|
|
||||||
return f"""Generate {count} F1 race strategies for {race_context.driver_state.driver_name} at {race_context.race_info.track_name}.
|
return f"""Generate {count} F1 race strategies for {race_context.driver_state.driver_name} at {race_context.race_info.track_name}.
|
||||||
|
|
||||||
@@ -59,16 +74,19 @@ CURRENT: Lap {race_context.race_info.current_lap}/{race_context.race_info.total_
|
|||||||
|
|
||||||
TELEMETRY: Tire deg {latest.tire_degradation_rate:.2f}, Cliff risk {latest.tire_cliff_risk:.2f}, Pace {latest.pace_trend}, Delta {latest.performance_delta:+.2f}s, Position trend {latest.position_trend}, Competitive pressure {latest.competitive_pressure:.2f}
|
TELEMETRY: Tire deg {latest.tire_degradation_rate:.2f}, Cliff risk {latest.tire_cliff_risk:.2f}, Pace {latest.pace_trend}, Delta {latest.performance_delta:+.2f}s, Position trend {latest.position_trend}, Competitive pressure {latest.competitive_pressure:.2f}
|
||||||
|
|
||||||
COMPETITIVE: Gap ahead {gap_to_ahead:.1f}s, Position trending {latest.position_trend}
|
COMPETITIVE: Gap ahead {gap_to_ahead:.1f}s, Position trending {latest.position_trend}{history_text}
|
||||||
|
|
||||||
Generate {count} diverse strategies considering both tire management AND competitive positioning. Min 2 compounds.
|
Generate {count} diverse strategies considering both tire management AND competitive positioning. Min 2 compounds.
|
||||||
|
|
||||||
JSON: {{"strategies": [{{"strategy_id": 1, "strategy_name": "name", "stop_count": 1, "pit_laps": [32], "tire_sequence": ["medium", "hard"], "brief_description": "one sentence", "risk_level": "low|medium|high|critical", "key_assumption": "main assumption"}}]}}"""
|
CRITICAL: Each strategy MUST include 'reasoning' field with detailed rationale and strategy continuity/change explanation.
|
||||||
|
|
||||||
|
JSON: {{"strategies": [{{"strategy_id": 1, "strategy_name": "name", "stop_count": 1, "pit_laps": [32], "tire_sequence": ["medium", "hard"], "brief_description": "one sentence", "reasoning": "Comprehensive explanation including strategy evolution context", "risk_level": "low|medium|high|critical", "key_assumption": "main assumption"}}]}}"""
|
||||||
|
|
||||||
|
|
||||||
def build_brainstorm_prompt(
|
def build_brainstorm_prompt(
|
||||||
enriched_telemetry: List[EnrichedTelemetryWebhook],
|
enriched_telemetry: List[EnrichedTelemetryWebhook],
|
||||||
race_context: RaceContext
|
race_context: RaceContext,
|
||||||
|
strategy_history: List[dict] = None
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Build the brainstorm prompt for Gemini.
|
Build the brainstorm prompt for Gemini.
|
||||||
@@ -76,6 +94,7 @@ def build_brainstorm_prompt(
|
|||||||
Args:
|
Args:
|
||||||
enriched_telemetry: Recent enriched telemetry data
|
enriched_telemetry: Recent enriched telemetry data
|
||||||
race_context: Current race context
|
race_context: Current race context
|
||||||
|
strategy_history: List of previous strategies for context
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Formatted prompt string
|
Formatted prompt string
|
||||||
@@ -108,6 +127,14 @@ def build_brainstorm_prompt(
|
|||||||
"gap_seconds": round(c.gap_seconds, 1)
|
"gap_seconds": round(c.gap_seconds, 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# Format strategy history
|
||||||
|
history_section = ""
|
||||||
|
if strategy_history and len(strategy_history) > 0:
|
||||||
|
history_section = "\n\nSTRATEGY HISTORY (Recent decisions):\n"
|
||||||
|
for h in strategy_history[-5:]: # Last 5 strategies
|
||||||
|
history_section += f"- Lap {h['lap']}: {h['strategy_name']} (Risk: {h['risk_level']}) - {h.get('brief_description', 'N/A')}\n"
|
||||||
|
history_section += f"\nCONTEXT: Previous strategy was '{strategy_history[-1]['strategy_name']}'. If recommending a change, clearly explain WHY. If continuing same approach, explain the continuity.\n"
|
||||||
|
|
||||||
prompt = f"""You are an expert F1 strategist. Generate 20 diverse race strategies based on lap-level telemetry AND competitive positioning.
|
prompt = f"""You are an expert F1 strategist. Generate 20 diverse race strategies based on lap-level telemetry AND competitive positioning.
|
||||||
|
|
||||||
LAP-LEVEL TELEMETRY METRICS:
|
LAP-LEVEL TELEMETRY METRICS:
|
||||||
@@ -135,7 +162,7 @@ COMPETITORS:
|
|||||||
{competitors_data}
|
{competitors_data}
|
||||||
|
|
||||||
ENRICHED TELEMETRY (Last {len(telemetry_data)} laps, newest first):
|
ENRICHED TELEMETRY (Last {len(telemetry_data)} laps, newest first):
|
||||||
{telemetry_data}
|
{telemetry_data}{history_section}
|
||||||
|
|
||||||
KEY INSIGHTS:
|
KEY INSIGHTS:
|
||||||
- Latest tire degradation rate: {latest.tire_degradation_rate:.3f}
|
- Latest tire degradation rate: {latest.tire_degradation_rate:.3f}
|
||||||
@@ -160,9 +187,12 @@ For each strategy provide:
|
|||||||
- pit_laps: [array of lap numbers]
|
- pit_laps: [array of lap numbers]
|
||||||
- tire_sequence: [array of compounds: "soft", "medium", "hard"]
|
- tire_sequence: [array of compounds: "soft", "medium", "hard"]
|
||||||
- brief_description: One sentence rationale
|
- brief_description: One sentence rationale
|
||||||
|
- reasoning: DETAILED explanation (3-5 sentences) including: (1) Why this strategy fits current conditions, (2) How it addresses telemetry trends, (3) Strategy evolution - why changing from or continuing previous approach
|
||||||
- risk_level: "low", "medium", "high", or "critical"
|
- risk_level: "low", "medium", "high", or "critical"
|
||||||
- key_assumption: Main assumption this strategy relies on
|
- key_assumption: Main assumption this strategy relies on
|
||||||
|
|
||||||
|
CRITICAL: The 'reasoning' field must include strategy continuity/change rationale relative to past decisions.
|
||||||
|
|
||||||
OUTPUT FORMAT (JSON only, no markdown):
|
OUTPUT FORMAT (JSON only, no markdown):
|
||||||
{{
|
{{
|
||||||
"strategies": [
|
"strategies": [
|
||||||
@@ -173,6 +203,7 @@ OUTPUT FORMAT (JSON only, no markdown):
|
|||||||
"pit_laps": [32],
|
"pit_laps": [32],
|
||||||
"tire_sequence": ["medium", "hard"],
|
"tire_sequence": ["medium", "hard"],
|
||||||
"brief_description": "Extend mediums to lap 32, safe finish on hards",
|
"brief_description": "Extend mediums to lap 32, safe finish on hards",
|
||||||
|
"reasoning": "Current tire degradation at 0.45 suggests we can safely extend to lap 32 before hitting the cliff. This maintains our conservative approach from lap 3 as conditions haven't changed significantly - tire deg is stable and we're not under immediate competitive pressure. The hard tire finish provides low-risk race completion.",
|
||||||
"risk_level": "low",
|
"risk_level": "low",
|
||||||
"key_assumption": "Tire degradation stays below 0.85 until lap 32"
|
"key_assumption": "Tire degradation stays below 0.85 until lap 32"
|
||||||
}}
|
}}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -25,7 +25,8 @@ class StrategyGenerator:
|
|||||||
async def generate(
|
async def generate(
|
||||||
self,
|
self,
|
||||||
enriched_telemetry: List[EnrichedTelemetryWebhook],
|
enriched_telemetry: List[EnrichedTelemetryWebhook],
|
||||||
race_context: RaceContext
|
race_context: RaceContext,
|
||||||
|
strategy_history: List[dict] = None
|
||||||
) -> BrainstormResponse:
|
) -> BrainstormResponse:
|
||||||
"""
|
"""
|
||||||
Generate 20 diverse race strategies.
|
Generate 20 diverse race strategies.
|
||||||
@@ -33,6 +34,7 @@ class StrategyGenerator:
|
|||||||
Args:
|
Args:
|
||||||
enriched_telemetry: Recent enriched telemetry data
|
enriched_telemetry: Recent enriched telemetry data
|
||||||
race_context: Current race context
|
race_context: Current race context
|
||||||
|
strategy_history: List of previous strategies for continuity
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
BrainstormResponse with 20 strategies
|
BrainstormResponse with 20 strategies
|
||||||
@@ -41,13 +43,15 @@ class StrategyGenerator:
|
|||||||
Exception: If generation fails
|
Exception: If generation fails
|
||||||
"""
|
"""
|
||||||
logger.info(f"Generating strategies using {len(enriched_telemetry)} laps of telemetry")
|
logger.info(f"Generating strategies using {len(enriched_telemetry)} laps of telemetry")
|
||||||
|
if strategy_history:
|
||||||
|
logger.info(f"Including {len(strategy_history)} previous strategies in context")
|
||||||
|
|
||||||
# Build prompt (use fast mode if enabled)
|
# Build prompt (use fast mode if enabled)
|
||||||
if self.settings.fast_mode:
|
if self.settings.fast_mode:
|
||||||
from prompts.brainstorm_prompt import build_brainstorm_prompt_fast
|
from prompts.brainstorm_prompt import build_brainstorm_prompt_fast
|
||||||
prompt = build_brainstorm_prompt_fast(enriched_telemetry, race_context)
|
prompt = build_brainstorm_prompt_fast(enriched_telemetry, race_context, strategy_history or [])
|
||||||
else:
|
else:
|
||||||
prompt = build_brainstorm_prompt(enriched_telemetry, race_context)
|
prompt = build_brainstorm_prompt(enriched_telemetry, race_context, strategy_history or [])
|
||||||
|
|
||||||
# Generate with Gemini (high temperature for creativity)
|
# Generate with Gemini (high temperature for creativity)
|
||||||
response_data = await self.gemini_client.generate_json(
|
response_data = await self.gemini_client.generate_json(
|
||||||
|
|||||||
@@ -715,14 +715,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleMessage(data) {
|
function handleMessage(data) {
|
||||||
const { type, vehicle_id, lap_data, control_output, strategy, timestamp } = data;
|
const { type, vehicle_id, lap_data, race_context, control_output, strategy, timestamp } = data;
|
||||||
|
|
||||||
if (type === 'vehicle_connected') {
|
if (type === 'vehicle_connected') {
|
||||||
addVehicle(vehicle_id, timestamp);
|
addVehicle(vehicle_id, timestamp);
|
||||||
} else if (type === 'vehicle_disconnected') {
|
} else if (type === 'vehicle_disconnected') {
|
||||||
removeVehicle(vehicle_id);
|
removeVehicle(vehicle_id);
|
||||||
} else if (type === 'lap_data') {
|
} else if (type === 'lap_data') {
|
||||||
addLapData(vehicle_id, lap_data, control_output, strategy, timestamp);
|
addLapData(vehicle_id, lap_data, race_context, control_output, strategy, timestamp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -750,7 +750,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addLapData(vehicleId, lapData, controlOutput, strategy, timestamp) {
|
function addLapData(vehicleId, lapData, raceContext, controlOutput, strategy, timestamp) {
|
||||||
if (!vehicles.has(vehicleId)) {
|
if (!vehicles.has(vehicleId)) {
|
||||||
addVehicle(vehicleId, timestamp);
|
addVehicle(vehicleId, timestamp);
|
||||||
}
|
}
|
||||||
@@ -758,6 +758,7 @@
|
|||||||
const vehicle = vehicles.get(vehicleId);
|
const vehicle = vehicles.get(vehicleId);
|
||||||
vehicle.laps.push({
|
vehicle.laps.push({
|
||||||
...lapData,
|
...lapData,
|
||||||
|
race_context: raceContext, // Add race context with position and gaps
|
||||||
control_output: controlOutput,
|
control_output: controlOutput,
|
||||||
strategy: strategy,
|
strategy: strategy,
|
||||||
timestamp: timestamp
|
timestamp: timestamp
|
||||||
@@ -907,6 +908,37 @@
|
|||||||
|
|
||||||
let bodyHtml = '';
|
let bodyHtml = '';
|
||||||
|
|
||||||
|
// Race Position section (lap_time, position, gaps)
|
||||||
|
if (lap.race_context || lap.lap_time) {
|
||||||
|
bodyHtml += `
|
||||||
|
<div class="modal-section">
|
||||||
|
<h3>Race Position</h3>
|
||||||
|
<div class="modal-data">
|
||||||
|
${lap.lap_time ? `
|
||||||
|
<div class="modal-data-row">
|
||||||
|
<span class="modal-data-label">Lap Time</span>
|
||||||
|
<span class="modal-data-value">${lap.lap_time}</span>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
${lap.race_context ? `
|
||||||
|
<div class="modal-data-row">
|
||||||
|
<span class="modal-data-label">Position</span>
|
||||||
|
<span class="modal-data-value">P${lap.race_context.position}</span>
|
||||||
|
</div>
|
||||||
|
<div class="modal-data-row">
|
||||||
|
<span class="modal-data-label">Gap from Leader</span>
|
||||||
|
<span class="modal-data-value">${lap.race_context.gap_to_leader > 0 ? '+' + lap.race_context.gap_to_leader.toFixed(3) + 's' : (lap.race_context.position === 1 ? 'Leading' : 'N/A')}</span>
|
||||||
|
</div>
|
||||||
|
<div class="modal-data-row">
|
||||||
|
<span class="modal-data-label">Gap from Car Ahead</span>
|
||||||
|
<span class="modal-data-value">${lap.race_context.gap_to_ahead > 0 ? '+' + lap.race_context.gap_to_ahead.toFixed(3) + 's' : (lap.race_context.position === 1 ? 'Leading' : 'N/A')}</span>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
// Telemetry data section
|
// Telemetry data section
|
||||||
bodyHtml += `
|
bodyHtml += `
|
||||||
<div class="modal-section">
|
<div class="modal-section">
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user