Spaces:
Build error
Build error
File size: 5,007 Bytes
16b6f84 e2483f2 16b6f84 3f5c978 16b6f84 e2483f2 16b6f84 e2483f2 16b6f84 e2483f2 16b6f84 e2483f2 16b6f84 e2483f2 16b6f84 e2483f2 16b6f84 e2483f2 16b6f84 e2483f2 16b6f84 e2483f2 16b6f84 e2483f2 16b6f84 e2483f2 16b6f84 e2483f2 16b6f84 e2483f2 16b6f84 e2483f2 16b6f84 e2483f2 3f5c978 e2483f2 3f5c978 e2483f2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
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
@app.post("/score-vendor", response_model=VendorOutput)
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
@app.post("/score-vendors", response_model=List[VendorOutput])
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
@app.get("/")
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") |