Vensor_Scoring / app.py
Rekham1110's picture
Update app.py
e2483f2 verified
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")