Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
| """ | |
| Structured error models for API responses. | |
| Provides user-friendly error messages with expandable technical details. | |
| """ | |
| from pydantic import BaseModel, Field | |
| from typing import Optional, Dict, Any | |
| class ErrorDetail(BaseModel): | |
| """Structured error detail with user-friendly message and technical info.""" | |
| message: str = Field( | |
| ..., | |
| description="User-friendly error message" | |
| ) | |
| error_type: str = Field( | |
| ..., | |
| description="Type of error (e.g., 'data_not_found', 'network_error', 'validation_error')" | |
| ) | |
| technical_details: Optional[str] = Field( | |
| None, | |
| description="Technical error details for debugging (expandable in UI)" | |
| ) | |
| suggestions: Optional[list[str]] = Field( | |
| None, | |
| description="Helpful suggestions for the user" | |
| ) | |
| metadata: Optional[Dict[str, Any]] = Field( | |
| None, | |
| description="Additional context (state, dataset name, etc.)" | |
| ) | |
| def parse_error(exception: Exception, context: Optional[Dict[str, Any]] = None) -> ErrorDetail: | |
| """ | |
| Parse an exception into a structured ErrorDetail with user-friendly message. | |
| Args: | |
| exception: The exception to parse | |
| context: Additional context (state, dataset, etc.) | |
| Returns: | |
| ErrorDetail with user-friendly message and technical details | |
| """ | |
| error_str = str(exception) | |
| context = context or {} | |
| # Parse HuggingFace dataset not found errors | |
| if "HTTP 404 Not Found" in error_str and "huggingface.co/datasets" in error_str: | |
| # Extract dataset name from URL | |
| import re | |
| match = re.search(r'datasets/([^/]+/[^/]+)/', error_str) | |
| dataset_name = match.group(1) if match else "unknown" | |
| # Extract state from dataset name or context | |
| state = context.get('state', 'Unknown') | |
| data_type = 'bills' if 'bills' in dataset_name else 'data' | |
| return ErrorDetail( | |
| message=f"No {data_type} data available for {state.upper()}", | |
| error_type="data_not_found", | |
| technical_details=f"Dataset '{dataset_name}' not found on HuggingFace.\n\nFull error: {error_str}", | |
| suggestions=[ | |
| f"Try a different state - we have data for 50+ states", | |
| f"Check /api/bills/map to see which states have {data_type} data", | |
| "Contact support if you believe this data should be available" | |
| ], | |
| metadata={ | |
| "dataset": dataset_name, | |
| "state": state, | |
| "data_type": data_type | |
| } | |
| ) | |
| # Parse file not found errors (local environment) | |
| elif "No such file or directory" in error_str or "FileNotFoundError" in error_str: | |
| state = context.get('state', 'Unknown') | |
| data_type = context.get('data_type', 'data') | |
| return ErrorDetail( | |
| message=f"No {data_type} available for {state.upper()}", | |
| error_type="data_not_found", | |
| technical_details=error_str, | |
| suggestions=[ | |
| f"This state may not have {data_type} in our database yet", | |
| "Try a different state or check which states have data", | |
| "Data is being continuously added - check back later" | |
| ], | |
| metadata={ | |
| "state": state, | |
| "data_type": data_type | |
| } | |
| ) | |
| # Parse DuckDB/SQL errors | |
| elif "DuckDB" in error_str or "SYNTAX ERROR" in error_str or "LINE" in error_str: | |
| return ErrorDetail( | |
| message="Database query error - please check your search parameters", | |
| error_type="query_error", | |
| technical_details=error_str, | |
| suggestions=[ | |
| "Try simplifying your search query", | |
| "Check that all parameters are valid", | |
| "Contact support if the issue persists" | |
| ], | |
| metadata=context | |
| ) | |
| # Parse network/timeout errors | |
| elif "timeout" in error_str.lower() or "connection" in error_str.lower(): | |
| return ErrorDetail( | |
| message="Network request timed out - please try again", | |
| error_type="network_error", | |
| technical_details=error_str, | |
| suggestions=[ | |
| "Try again in a few seconds", | |
| "Check your internet connection", | |
| "The server may be temporarily busy" | |
| ], | |
| metadata=context | |
| ) | |
| # Parse validation errors | |
| elif "validation" in error_str.lower() or "invalid" in error_str.lower(): | |
| return ErrorDetail( | |
| message="Invalid request parameters", | |
| error_type="validation_error", | |
| technical_details=error_str, | |
| suggestions=[ | |
| "Check that all required parameters are provided", | |
| "Verify parameter formats (e.g., state codes should be 2 letters)", | |
| "See API documentation for valid parameter values" | |
| ], | |
| metadata=context | |
| ) | |
| # Generic error fallback | |
| else: | |
| return ErrorDetail( | |
| message="An unexpected error occurred", | |
| error_type="server_error", | |
| technical_details=error_str, | |
| suggestions=[ | |
| "Try again in a few moments", | |
| "Contact support if the issue persists", | |
| "Check the technical details for more information" | |
| ], | |
| metadata=context | |
| ) | |