demo seed change

This commit is contained in:
Urtzi Alfaro
2025-12-13 23:57:54 +01:00
parent f3688dfb04
commit ff830a3415
299 changed files with 20328 additions and 19485 deletions

416
shared/schemas/reasoning_types.py Normal file → Executable file
View File

@@ -9,7 +9,7 @@ Backend only stores type codes and parameters.
"""
from enum import Enum
from typing import Dict, Any, Optional
from typing import Dict, Any, Optional, List
from pydantic import BaseModel, Field
@@ -47,6 +47,34 @@ class ConsequenceSeverity(str, Enum):
LOW = "low" # Minor impact
class PredictionFactorType(str, Enum):
"""Types of factors that contribute to demand prediction"""
HISTORICAL_PATTERN = "historical_pattern" # Historical sales/demand patterns
WEATHER_SUNNY = "weather_sunny" # Sunny weather impact
WEATHER_RAINY = "weather_rainy" # Rainy weather impact
WEATHER_COLD = "weather_cold" # Cold weather impact
WEATHER_HOT = "weather_hot" # Hot weather impact
WEEKEND_BOOST = "weekend_boost" # Weekend demand increase
WEEKDAY_PATTERN = "weekday_pattern" # Day-of-week pattern
LOCAL_EVENT = "local_event" # Local event impact
HOLIDAY = "holiday" # Holiday impact
INVENTORY_LEVEL = "inventory_level" # Current inventory consideration
TREND_SEASONAL = "trend_seasonal" # Seasonal trend
PROMOTION_ACTIVE = "promotion_active" # Active promotion
class PredictionFactor(BaseModel):
"""Individual factor contributing to demand prediction"""
factor: PredictionFactorType = Field(..., description="Type of prediction factor")
weight: float = Field(..., description="Weight of this factor (0-1)", ge=0, le=1)
contribution: float = Field(..., description="Absolute contribution to demand")
description: Optional[str] = Field(None, description="Human-readable description")
weather_data: Optional[Dict[str, Any]] = Field(None, description="Weather-specific data")
inventory_data: Optional[Dict[str, Any]] = Field(None, description="Inventory-specific data")
historical_data: Optional[Dict[str, Any]] = Field(None, description="Historical pattern data")
event_data: Optional[Dict[str, Any]] = Field(None, description="Event-specific data")
confidence: Optional[float] = Field(None, description="Confidence score for this factor", ge=0, le=1)
# ============================================================
# Reasoning Data Models
# ============================================================
@@ -440,31 +468,113 @@ def create_po_reasoning_manual_request(
def create_batch_reasoning_forecast_demand(
product_name: str,
predicted_demand: float,
current_stock: float,
production_needed: float,
target_date: str,
confidence_score: float = 0.85
current_stock: float = None,
production_needed: float = None,
target_date: str = None,
historical_average: float = None,
variance_percent: float = None,
variance_reason: str = None,
confidence_score: float = 0.85,
factors: Optional[List[Dict[str, Any]]] = None,
urgency_level: str = "normal",
ready_by_time: str = "08:00",
forecast_id: Optional[str] = None,
target_sales: float = None,
weather_impact: Dict[str, Any] = None
) -> Dict[str, Any]:
"""Create reasoning data for forecast-based production"""
"""
Create unified reasoning data for forecast-based production with optional enhanced factors
This function consolidates both basic and enhanced forecast demand reasoning.
Args:
product_name: Name of the product
predicted_demand: Predicted demand quantity
current_stock: Current stock level (optional for basic reasoning)
production_needed: Needed production quantity (optional for basic reasoning)
target_date: Target date for production (optional for basic reasoning)
historical_average: Historical average demand (for enhanced reasoning)
variance_percent: Percentage variance from historical average (for enhanced reasoning)
variance_reason: Reason for variance (for enhanced reasoning)
confidence_score: Confidence score (0-1)
factors: List of factors contributing to the prediction (for enhanced reasoning)
urgency_level: Urgency level ("normal", "medium", "high", "urgent")
ready_by_time: Time when batch should be ready
forecast_id: UUID of the forecast for traceability
target_sales: Target sales figures
weather_impact: Detailed weather impact data
Returns:
Reasoning data with appropriate level of detail based on provided parameters
"""
# Build parameters dict
params = {
"product_name": product_name,
"predicted_demand": round(predicted_demand, 1),
}
# Add basic reasoning parameters if provided
if current_stock is not None:
params["current_stock"] = round(current_stock, 1)
if production_needed is not None:
params["production_needed"] = round(production_needed, 1)
if target_date is not None:
params["target_date"] = target_date
if target_sales is not None:
params["target_sales"] = round(target_sales, 1)
if weather_impact is not None:
params["weather_impact"] = weather_impact
# Add enhanced reasoning parameters if provided
if historical_average is not None:
params["historical_average"] = round(historical_average, 1)
if variance_percent is not None:
params["variance_percent"] = round(variance_percent, 1)
if variance_reason is not None:
params["variance_reason"] = variance_reason
if factors:
# Ensure factors is a list
factors_list = factors or []
# Convert factors to proper format if they're not already PredictionFactor objects
formatted_factors = []
for factor in factors_list:
if isinstance(factor, dict):
# Already in dict format
formatted_factors.append(factor)
else:
# Convert PredictionFactor to dict
formatted_factors.append({
"factor": factor.factor.value if hasattr(factor, 'factor') else str(factor.factor),
"weight": factor.weight,
"contribution": factor.contribution,
"description": factor.description,
"weather_data": factor.weather_data,
"inventory_data": factor.inventory_data,
"historical_data": factor.historical_data,
"event_data": factor.event_data,
"confidence": factor.confidence
})
params["factors"] = formatted_factors
return {
"type": ProductionBatchReasoningType.FORECAST_DEMAND.value,
"parameters": {
"product_name": product_name,
"predicted_demand": round(predicted_demand, 1),
"current_stock": round(current_stock, 1),
"production_needed": round(production_needed, 1),
"target_date": target_date,
"confidence_score": round(confidence_score * 100, 1)
},
"parameters": params,
"urgency": {
"level": "normal",
"ready_by_time": "08:00",
"level": urgency_level,
"ready_by_time": ready_by_time,
"customer_commitment": False
},
"metadata": {
"trigger_source": "orchestrator_auto",
"confidence_score": confidence_score,
"ai_assisted": True
"ai_assisted": True,
"enhanced_reasoning": any([
historical_average is not None,
variance_percent is not None,
variance_reason is not None,
factors is not None and len(factors) > 0,
weather_impact is not None
])
}
}
@@ -632,3 +742,275 @@ def create_batch_reasoning_urgent_order(
}
}
def create_production_batch_reasoning(
product_name: str,
predicted_demand: float,
current_stock: float = None,
production_needed: float = None,
target_date: str = None,
historical_average: float = None,
variance_percent: float = None,
variance_reason: str = None,
confidence_score: float = 0.85,
factors: Optional[List[Dict[str, Any]]] = None,
urgency_level: str = "normal",
ready_by_time: str = "08:00",
forecast_id: Optional[str] = None,
target_sales: float = None,
weather_impact: Dict[str, Any] = None,
base_demand: float = None,
weather_data: Dict[str, Any] = None,
weather_adjustment_factor: float = None,
production_type: str = "forecast_demand" # Add this to allow different production reasoning types
) -> Dict[str, Any]:
"""
Create unified reasoning data for production batches that combines both forecast demand and weather influence
This function consolidates both basic and enhanced forecast demand reasoning as well as weather-influenced production reasoning.
Args:
product_name: Name of the product
predicted_demand: Predicted demand quantity
current_stock: Current stock level (optional for basic reasoning)
production_needed: Needed production quantity (optional for basic reasoning)
target_date: Target date for production (optional for basic reasoning)
historical_average: Historical average demand (for enhanced reasoning)
variance_percent: Percentage variance from historical average (for enhanced reasoning)
variance_reason: Reason for variance (for enhanced reasoning)
confidence_score: Confidence score (0-1)
factors: List of factors contributing to the prediction (for enhanced reasoning)
urgency_level: Urgency level ("normal", "medium", "high", "urgent")
ready_by_time: Time when batch should be ready
forecast_id: UUID of the forecast for traceability
target_sales: Target sales figures
weather_impact: Detailed weather impact data
base_demand: Base demand without weather influence (for weather-influenced reasoning)
weather_data: Weather information affecting production, with keys:
- temperature: Current/future temperature
- condition: Weather condition (sunny, rainy, snowy, etc.)
- humidity: Humidity level
- impact_factor: Multiplier for weather impact on demand
weather_adjustment_factor: Factor by which weather adjusted the demand
production_type: Type of production reasoning ("forecast_demand", "weather_influenced", "forecast_and_weather", etc.)
Returns:
Reasoning data with appropriate level of detail based on provided parameters
"""
# Build parameters dict
params = {
"product_name": product_name,
"predicted_demand": round(predicted_demand, 1),
}
# Add basic reasoning parameters if provided
if current_stock is not None:
params["current_stock"] = round(current_stock, 1)
if production_needed is not None:
params["production_needed"] = round(production_needed, 1)
if target_date is not None:
params["target_date"] = target_date
if target_sales is not None:
params["target_sales"] = round(target_sales, 1)
# Add weather-related data if provided
if weather_data is not None:
# Calculate weather impact details
weather_impact_factor = weather_adjustment_factor or weather_data.get('impact_factor', 1.0)
temperature = weather_data.get('temperature', 'N/A')
condition = weather_data.get('condition', 'unknown')
humidity = weather_data.get('humidity', 'N/A')
# Calculate weather-adjusted base demand if not provided
if base_demand is None:
base_demand = predicted_demand / weather_impact_factor if weather_impact_factor != 0 else predicted_demand
params["base_demand"] = round(base_demand, 1)
params["weather_adjustment_factor"] = round(weather_impact_factor, 2)
params["weather_data"] = weather_data
params["weather_condition"] = condition
params["temperature"] = temperature
params["humidity"] = humidity
elif weather_impact is not None:
# Handle legacy weather_impact parameter
params["weather_impact"] = weather_impact
# Add enhanced reasoning parameters if provided
if historical_average is not None:
params["historical_average"] = round(historical_average, 1)
if variance_percent is not None:
params["variance_percent"] = round(variance_percent, 1)
if variance_reason is not None:
params["variance_reason"] = variance_reason
if factors:
# Ensure factors is a list
factors_list = factors or []
# Convert factors to proper format if they're not already PredictionFactor objects
formatted_factors = []
for factor in factors_list:
if isinstance(factor, dict):
# Already in dict format
formatted_factors.append(factor)
else:
# Convert PredictionFactor to dict
formatted_factors.append({
"factor": factor.factor.value if hasattr(factor, 'factor') else str(factor.factor),
"weight": factor.weight,
"contribution": factor.contribution,
"description": factor.description,
"weather_data": factor.weather_data,
"inventory_data": factor.inventory_data,
"historical_data": factor.historical_data,
"event_data": factor.event_data,
"confidence": factor.confidence
})
params["factors"] = formatted_factors
# Determine the production type and set accordingly
actual_type = ProductionBatchReasoningType.FORECAST_DEMAND.value
# Create metadata
metadata = {
"trigger_source": "orchestrator_auto",
"confidence_score": confidence_score,
"ai_assisted": True,
"enhanced_reasoning": any([
historical_average is not None,
variance_percent is not None,
variance_reason is not None,
factors is not None and len(factors) > 0,
weather_impact is not None,
weather_data is not None
])
}
# Add weather-specific metadata if applicable
if weather_data is not None or weather_impact is not None:
metadata["weather_influenced"] = True
return {
"type": actual_type,
"parameters": params,
"urgency": {
"level": urgency_level,
"ready_by_time": ready_by_time,
"customer_commitment": False
},
"metadata": metadata
}
def create_batch_reasoning_weather_influenced(
product_name: str,
predicted_demand: float,
weather_data: Dict[str, Any],
base_demand: float = None,
current_stock: float = None,
production_needed: float = None,
target_date: str = None,
confidence_score: float = 0.85,
factors: Optional[List[Dict[str, Any]]] = None,
urgency_level: str = "normal",
ready_by_time: str = "08:00",
forecast_id: Optional[str] = None
) -> Dict[str, Any]:
"""
Create reasoning data for production batches influenced by weather factors
This function specifically handles weather-influenced production reasoning,
which is important for bakery operations where weather significantly impacts demand.
Args:
product_name: Name of the product
predicted_demand: Predicted demand quantity considering weather impact
weather_data: Weather information affecting production, with keys:
- temperature: Current/future temperature
- condition: Weather condition (sunny, rainy, snowy, etc.)
- humidity: Humidity level
- impact_factor: Multiplier for weather impact on demand
base_demand: Base demand without weather influence (optional)
current_stock: Current stock level
production_needed: Needed production quantity
target_date: Target date for production
confidence_score: Confidence score (0-1)
factors: Additional prediction factors
urgency_level: Urgency level ("normal", "medium", "high", "urgent")
ready_by_time: Time when batch should be ready
forecast_id: UUID of the forecast for traceability
Returns:
Reasoning data with detailed weather influence information
"""
# Calculate weather impact details
weather_impact_factor = weather_data.get('impact_factor', 1.0)
temperature = weather_data.get('temperature', 'N/A')
condition = weather_data.get('condition', 'unknown')
humidity = weather_data.get('humidity', 'N/A')
# Calculate weather-adjusted base demand
if base_demand is None:
base_demand = predicted_demand / weather_impact_factor
# Build parameters
params = {
"product_name": product_name,
"predicted_demand": round(predicted_demand, 1),
"base_demand": round(base_demand, 1),
"weather_adjustment_factor": round(weather_impact_factor, 2),
"weather_data": weather_data,
"weather_condition": condition,
"temperature": temperature,
"humidity": humidity
}
# Add optional basic reasoning parameters
if current_stock is not None:
params["current_stock"] = round(current_stock, 1)
if production_needed is not None:
params["production_needed"] = round(production_needed, 1)
if target_date is not None:
params["target_date"] = target_date
# Add enhanced reasoning parameters if provided
if factors:
# Ensure factors is a list
factors_list = factors or []
# Convert factors to proper format if they're not already PredictionFactor objects
formatted_factors = []
for factor in factors_list:
if isinstance(factor, dict):
# Already in dict format
formatted_factors.append(factor)
else:
# Convert PredictionFactor to dict
formatted_factors.append({
"factor": factor.factor.value if hasattr(factor, 'factor') else str(factor.factor),
"weight": factor.weight,
"contribution": factor.contribution,
"description": factor.description,
"weather_data": factor.weather_data,
"inventory_data": factor.inventory_data,
"historical_data": factor.historical_data,
"event_data": factor.event_data,
"confidence": factor.confidence
})
params["factors"] = formatted_factors
return {
"type": ProductionBatchReasoningType.FORECAST_DEMAND.value,
"parameters": params,
"urgency": {
"level": urgency_level,
"ready_by_time": ready_by_time,
"customer_commitment": False
},
"metadata": {
"trigger_source": "orchestrator_auto",
"confidence_score": confidence_score,
"ai_assisted": True,
"enhanced_reasoning": True,
"weather_influenced": True
}
}