Spaces:
Build error
Build error
| from fastapi import FastAPI, HTTPException, Header | |
| from pydantic import BaseModel | |
| from typing import Optional, List | |
| from datetime import datetime | |
| import logging | |
| import uvicorn | |
| import os | |
| # Set up logging | |
| logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') | |
| logger = logging.getLogger(__name__) | |
| # Initialize FastAPI app | |
| app = FastAPI(title="Vendor Performance Scoring API") | |
| # Define input data model | |
| class VendorInput(BaseModel): | |
| Vendor_ID__c: str | |
| Vendor_Name__c: str | |
| Issue_Count__c: int | |
| Feedback_Rating__c: float | |
| Timeliness_Score__c: float | |
| Evaluation_Date__c: str # ISO format, e.g., "2025-05-14" | |
| Email__c: Optional[str] = None | |
| # Define output data model | |
| class VendorOutput(BaseModel): | |
| Vendor_ID__c: str | |
| Score__c: float | |
| Rationale__c: str | |
| Alert_Flag__c: bool | |
| # API token from environment variable | |
| EXPECTED_API_TOKEN = os.getenv("API_TOKEN", "hf_default_token_for_testing") | |
| # Scoring function | |
| def calculate_vendor_score(data: VendorInput) -> VendorOutput: | |
| try: | |
| # Validate inputs | |
| if data.Issue_Count__c < 0: | |
| raise ValueError("Issue_Count__c cannot be negative") | |
| if not (0 <= data.Feedback_Rating__c <= 10): | |
| raise ValueError("Feedback_Rating__c must be between 0 and 10") | |
| if not (0 <= data.Timeliness_Score__c <= 10): | |
| raise ValueError("Timeliness_Score__c must be between 0 and 10") | |
| # Parse and validate evaluation date | |
| try: | |
| eval_date = datetime.fromisoformat(data.Evaluation_Date__c.replace("Z", "+00:00")) | |
| current_date = datetime.now().astimezone() | |
| if eval_date > current_date: | |
| raise ValueError("Evaluation_Date__c cannot be in the future") | |
| except ValueError as e: | |
| raise ValueError(f"Invalid Evaluation_Date__c format or value: {str(e)}") | |
| # Calculate score | |
| base_score = 100 | |
| issue_deduction = data.Issue_Count__c * 5 | |
| feedback_bonus = data.Feedback_Rating__c * 2 | |
| timeliness_bonus = data.Timeliness_Score__c * 3 | |
| score = base_score - issue_deduction + feedback_bonus + timeliness_bonus | |
| score = max(0, min(100, score)) | |
| # Generate rationale | |
| rationale_parts = [] | |
| if issue_deduction > 0: | |
| rationale_parts.append(f"Deducted {issue_deduction} points for {data.Issue_Count__c} issues") | |
| rationale_parts.append(f"Added {feedback_bonus:.1f} points for feedback rating {data.Feedback_Rating__c}") | |
| rationale_parts.append(f"Added {timeliness_bonus:.1f} points for timeliness score {data.Timeliness_Score__c}") | |
| rationale = "; ".join(rationale_parts) + f"; Final score: {score:.1f}" | |
| # Set alert flag | |
| alert_flag = score < 50 or data.Issue_Count__c > 5 | |
| logger.info(f"Scored Vendor {data.Vendor_ID__c}: Score={score:.1f}, Alert={alert_flag}") | |
| return VendorOutput( | |
| Vendor_ID__c=data.Vendor_ID__c, | |
| Score__c=score, | |
| Rationale__c=rationale, | |
| Alert_Flag__c=alert_flag | |
| ) | |
| except Exception as e: | |
| logger.error(f"Error scoring vendor {data.Vendor_ID__c}: {str(e)}") | |
| raise HTTPException(status_code=400, detail=f"Scoring error: {str(e)}") | |
| # Single vendor scoring endpoint | |
| async def score_vendor(data: VendorInput, authorization: Optional[str] = Header(None)): | |
| if not authorization or authorization != f"Bearer {EXPECTED_API_TOKEN}": | |
| logger.warning("Invalid or missing API token") | |
| raise HTTPException(status_code=401, detail="Invalid or missing API token") | |
| return calculate_vendor_score(data) | |
| # Batch vendor scoring endpoint | |
| async def score_vendors(data: List[VendorInput], authorization: Optional[str] = Header(None)): | |
| if not authorization or authorization != f"Bearer {EXPECTED_API_TOKEN}": | |
| logger.warning("Invalid or missing API token") | |
| raise HTTPException(status_code=401, detail="Invalid or missing API token") | |
| results = [] | |
| for vendor in data: | |
| try: | |
| result = calculate_vendor_score(vendor) | |
| results.append(result) | |
| except Exception as e: | |
| logger.error(f"Skipping vendor {vendor.Vendor_ID__c}: {str(e)}") | |
| results.append(VendorOutput( | |
| Vendor_ID__c=vendor.Vendor_ID__c, | |
| Score__c=0, | |
| Rationale__c=f"Error: {str(e)}", | |
| Alert_Flag__c=True | |
| )) | |
| return results | |
| # Health check endpoint | |
| async def root(): | |
| logger.info("Root endpoint accessed") | |
| return {"message": "Vendor Scoring API is running"} | |
| # Start Uvicorn server | |
| if __name__ == "__main__": | |
| port = int(os.getenv("PORT", 7860)) | |
| logger.info(f"Starting server on port {port}") | |
| uvicorn.run(app, host="0.0.0.0", port=port, log_level="info") |