Spaces:
Sleeping
Sleeping
| # pylint: disable=unused-import | |
| """ | |
| Pydantic models for API request/response validation. | |
| Maintains strict contract between React frontend and FastAPI backend. | |
| """ | |
| import time | |
| from typing import List, Dict, Any, Optional, Union, Literal | |
| from pydantic import BaseModel, Field, field_validator, model_validator | |
| import numpy as np | |
| class SpectrumData(BaseModel): | |
| """Single spectrum data for analysis""" | |
| x_values: List[float] = Field(..., description="Wavenumber values (cm⁻¹)") | |
| y_values: List[float] = Field(..., description="Intensity values") | |
| filename: Optional[str] = Field(None, description="Original filename") | |
| def validate_arrays(cls, v: List[float]) -> List[float]: | |
| """ | |
| Validate that the input arrays have at least 2 values. | |
| Args: | |
| v (list): The array to validate. | |
| Returns: | |
| list: The validated array. | |
| Raises: | |
| ValueError: If the array has fewer than 2 values. | |
| """ | |
| if len(v) < 2: | |
| raise ValueError("Arrays must have at least 2 values") | |
| return v | |
| def validate_equal_length(self) -> "SpectrumData": | |
| """ | |
| Ensure that y_values has the same length as x_values. | |
| Args: | |
| v (list): The y_values list to validate. | |
| values (dict): The dictionary containing other field values. | |
| Returns: | |
| list: The validated y_values list. | |
| Raises: | |
| ValueError: If y_values and x_values do not have the same length. | |
| """ | |
| if len(self.x_values) != len(self.y_values): | |
| raise ValueError("x_values and y_values must have equal length") | |
| return self | |
| class AnalysisRequest(BaseModel): | |
| """Request for single spectrum analysis""" | |
| spectrum: SpectrumData | |
| model_name: str = Field(..., description="Model name to use for analysis") | |
| modality: Literal["raman", "ftir"] = Field( | |
| "raman", description="Spectroscopy modality" | |
| ) | |
| include_provenance: bool = Field( | |
| True, description="Include full provenance metadata" | |
| ) | |
| class BatchAnalysisRequest(BaseModel): | |
| """Request for batch spectrum analysis""" | |
| spectra: List[SpectrumData] = Field(..., min_length=1, max_length=100) | |
| model_name: str = Field(..., description="Model name to use for analysis") | |
| modality: Literal["raman", "ftir"] = Field( | |
| "raman", description="Spectroscopy modality" | |
| ) | |
| include_provenance: bool = Field( | |
| True, description="Include full provenance metadata" | |
| ) | |
| class ComparisonRequest(BaseModel): | |
| """Request for multi-model comparison""" | |
| spectrum: SpectrumData | |
| model_names: Optional[List[str]] = Field( | |
| None, description="Models to compare (all if None)" | |
| ) | |
| modality: Literal["raman", "ftir"] = Field( | |
| "raman", description="Spectroscopy modality" | |
| ) | |
| include_provenance: bool = Field( | |
| True, description="Include full provenance metadata" | |
| ) | |
| class PreprocessingMetadata(BaseModel): | |
| """Preprocessing provenance metadata""" | |
| target_length: int = Field(..., description="Target resampling length") | |
| baseline_degree: int = Field(..., | |
| description="Polynomial baseline removal degree") | |
| smooth_window: int = Field(..., description="Smoothing window length") | |
| smooth_polyorder: int = Field(..., | |
| description="Smoothing polynomial order") | |
| normalization_method: str = Field(..., | |
| description="Normalization method applied") | |
| modality_validated: bool = Field( | |
| ..., description="Whether modality validation passed" | |
| ) | |
| validation_issues: List[str] = Field( | |
| default_factory=list, description="Any validation issues found" | |
| ) | |
| original_length: int = Field(..., description="Original spectrum length") | |
| wavenumber_range: List[float] = Field( | |
| ..., min_length=2, max_length=2, description="[min, max] wavenumber range" | |
| ) | |
| class QualityControlMetadata(BaseModel): | |
| """Quality control check results""" | |
| signal_to_noise_ratio: Optional[float] = Field( | |
| None, description="Estimated SNR") | |
| baseline_stability: Optional[float] = Field( | |
| None, description="Baseline stability metric" | |
| ) | |
| spectral_resolution: Optional[float] = Field( | |
| None, description="Estimated spectral resolution" | |
| ) | |
| cosmic_ray_detected: bool = Field( | |
| False, description="Cosmic ray spikes detected") | |
| saturation_detected: bool = Field( | |
| False, description="Signal saturation detected") | |
| issues: List[str] = Field(default_factory=list, | |
| description="QC issues found") | |
| class ModelMetadata(BaseModel): | |
| """Model metadata and calibration details""" | |
| model_name: str = Field(..., description="Model identifier") | |
| model_description: str = Field(..., description="Model description") | |
| model_version: Optional[str] = Field(None, description="Model version") | |
| training_date: Optional[str] = Field( | |
| None, description="Model training date") | |
| input_length: int = Field(..., description="Expected input length") | |
| num_classes: int = Field(..., description="Number of output classes") | |
| parameters_count: Optional[str] = Field( | |
| None, description="Number of parameters") | |
| performance_metrics: Dict[str, float] = Field( | |
| default_factory=dict, description="Training performance" | |
| ) | |
| supported_modalities: List[str] = Field( | |
| default_factory=list, description="Supported spectroscopy modalities" | |
| ) | |
| citation: Optional[str] = Field( | |
| None, description="Model citation/reference") | |
| weights_loaded: bool = Field(..., | |
| description="Whether trained weights were loaded") | |
| weights_path: Optional[str] = Field( | |
| None, description="Path to loaded weights") | |
| class PredictionResult(BaseModel): | |
| """Single prediction result with full provenance""" | |
| prediction: int = Field(..., | |
| description="Predicted class (0=Stable, 1=Weathered)") | |
| prediction_label: str = Field(..., | |
| description="Human-readable prediction label") | |
| confidence: float = Field( | |
| ..., ge=0.0, le=1.0, description="Prediction confidence score" | |
| ) | |
| probabilities: List[float] = Field(..., description="Class probabilities") | |
| logits: List[float] = Field(..., description="Raw model logits") | |
| # Provenance metadata | |
| preprocessing: PreprocessingMetadata | |
| quality_control: QualityControlMetadata | |
| model_metadata: ModelMetadata | |
| # Performance tracking | |
| inference_time: float = Field(..., ge=0.0, | |
| description="Inference time in seconds") | |
| preprocessing_time: float = Field( | |
| ..., ge=0.0, description="Preprocessing time in seconds" | |
| ) | |
| total_time: float = Field( | |
| ..., ge=0.0, description="Total processing time in seconds" | |
| ) | |
| memory_usage_mb: float = Field(..., ge=0.0, | |
| description="Memory usage in MB") | |
| # Input data (for audit trail) | |
| original_spectrum: SpectrumData | |
| processed_spectrum: SpectrumData | |
| # Timestamps | |
| timestamp: str = Field(..., | |
| description="Processing timestamp (ISO format)") | |
| class BatchError(BaseModel): | |
| """Details of a single error within a batch request""" | |
| filename: Optional[str] = Field( | |
| None, description="Filename of the spectrum that failed" | |
| ) | |
| error: str = Field(..., description="The error message") | |
| class BatchPredictionResult(BaseModel): | |
| """Batch prediction results""" | |
| results: List[PredictionResult] = Field( | |
| default_factory=list, description="Individual prediction results" | |
| ) | |
| errors: List[BatchError] = Field( | |
| default_factory=list, | |
| description="Errors for spectra that failed processing", | |
| ) | |
| summary: Dict[str, Any] = Field( | |
| default_factory=dict, description="Batch summary statistics" | |
| ) | |
| total_processing_time: float = Field( | |
| ..., ge=0.0, description="Total batch processing time" | |
| ) | |
| timestamp: str = Field(..., description="Batch processing timestamp") | |
| class ComparisonResult(BaseModel): | |
| """Multi-model comparison results""" | |
| spectrum_id: str = Field(..., | |
| description="Unique identifier for the spectrum") | |
| model_results: Dict[str, PredictionResult] = Field( | |
| default_factory=dict, description="Results per model" | |
| ) | |
| consensus_prediction: Optional[int] = Field( | |
| None, description="Consensus prediction if available" | |
| ) | |
| confidence_variance: float = Field( | |
| ..., ge=0.0, description="Variance in confidence scores" | |
| ) | |
| agreement_score: float = Field( | |
| ..., ge=0.0, le=1.0, description="Model agreement score" | |
| ) | |
| timestamp: str = Field(..., description="Comparison timestamp") | |
| class FeatureImportanceSummary(BaseModel): | |
| """Summary of feature importance scores""" | |
| max_importance: float | |
| mean_importance: float | |
| important_region_start: int | |
| important_region_end: int | |
| class TopFeatures(BaseModel): | |
| """Top features identified by explainability analysis""" | |
| indices: List[int] | |
| values: List[float] | |
| class FeatureImportance(BaseModel): | |
| """Feature importance results from explainability analysis""" | |
| method: str | |
| importance_scores: List[float] | |
| top_features: TopFeatures | |
| summary: FeatureImportanceSummary | |
| class ExplanationResult(BaseModel): | |
| """Result from an explainability analysis""" | |
| prediction: int | |
| confidence: float | |
| probabilities: List[float] | |
| class_labels: List[str] | |
| model_used: str | |
| spectrum_filename: Optional[str] = None | |
| feature_importance: Optional[FeatureImportance] = None | |
| class Config: | |
| """Pydantic model configuration""" | |
| from_attributes = True | |
| class ModelInfo(BaseModel): | |
| """Model information and capabilities""" | |
| name: str = Field(..., description="Model identifier") | |
| description: str = Field(..., description="Model description") | |
| input_length: int = Field(..., description="Expected input length") | |
| num_classes: int = Field(..., description="Number of output classes") | |
| supported_modalities: List[str] = Field( | |
| default_factory=list, description="Supported modalities" | |
| ) | |
| performance: Dict[str, float] = Field( | |
| default_factory=dict, description="Performance metrics" | |
| ) | |
| parameters: Optional[str] = Field(None, description="Parameter count") | |
| speed: Optional[str] = Field(None, description="Relative speed category") | |
| citation: Optional[str] = Field(None, description="Citation/reference") | |
| available: bool = Field(..., | |
| description="Whether model is available for inference") | |
| class SystemHealth(BaseModel): | |
| """System health metrics""" | |
| status: str = Field(..., description="Overall system status, e.g., 'ok'.") | |
| timestamp: float = Field(..., | |
| description="The server timestamp of the health check.") | |
| models_loaded: int | |
| total_models: int | |
| memory_usage_mb: float | |
| torch_version: str | |
| cuda_available: bool | |
| class SystemInfo(BaseModel): | |
| """System information and health""" | |
| version: str = Field(..., description="API version") | |
| available_models: List[ModelInfo] = Field( | |
| default_factory=list, description="Available models" | |
| ) | |
| supported_modalities: List[str] = Field( | |
| default_factory=list, description="Supported spectroscopy modalities" | |
| ) | |
| max_batch_size: int = Field(100, ge=1, description="Maximum batch size") | |
| target_spectrum_length: int = Field( | |
| 500, ge=1, description="Target spectrum length") | |
| system_health: SystemHealth = Field( | |
| ..., description="System health metrics" | |
| ) | |
| class ErrorResponse(BaseModel): | |
| """Standardized error response""" | |
| error: str = Field(..., description="Error message") | |
| error_code: str = Field(..., | |
| description="Error code for programmatic handling") | |
| details: Optional[Dict[str, Any]] = Field( | |
| None, description="Additional error details" | |
| ) | |
| timestamp: str = Field(..., description="Error timestamp") | |
| request_id: Optional[str] = Field( | |
| None, description="Request ID for tracking") | |