varshakolanu's picture
Update app.py
d7b5306 verified
from starlette.applications import Starlette
from starlette.routing import Route
from starlette.requests import Request
from starlette.responses import JSONResponse
from pydantic import BaseModel, Field
from typing import List, Optional
from datetime import datetime
import uvicorn
import numpy as np
import json
app = Starlette(debug=True)
# In-memory store for historical scores (replace with database for production)
historical_scores = []
# Define the request body structure
class VendorLog(BaseModel):
vendor_id: str = Field(..., description="Unique identifier for the vendor")
delay_logs: int = Field(..., ge=0, description="Number of delay incidents")
qa_incidents: int = Field(..., ge=0, description="Number of quality assurance incidents")
safety_compliance: int = Field(..., ge=0, description="Number of safety compliance issues")
feedback_logs: int = Field(..., ge=0, description="Number of feedback logs")
work_logs: int = Field(..., ge=1, description="Total number of work logs")
month: str = Field(..., description="Month of the score (YYYY-MM format)")
# Define the response structure
class ScoreResponse(BaseModel):
vendor_id: str
month: str
final_score: float
quality_score: float
timeliness_score: float
safety_score: float
communication_score: float
alert_flag: bool
trend_deviation: Optional[float]
certification_url: Optional[str]
# Scoring weights (configurable)
WEIGHTS = {
"quality": 0.3,
"timeliness": 0.3,
"safety": 0.2,
"communication": 0.2
}
async def calculate_score(request: Request):
try:
# Parse JSON body
body = await request.json()
logs = VendorLog(**body)
# Validate month format
datetime.strptime(logs.month, "%Y-%m")
# Calculate individual scores
quality_score = (1 - logs.qa_incidents / logs.work_logs) * 100
timeliness_score = (1 - logs.delay_logs / logs.work_logs) * 100
safety_score = (1 - logs.safety_compliance / logs.work_logs) * 100
communication_score = (logs.feedback_logs / logs.work_logs) * 50 # Adjusted logic
# Ensure scores are within 0-100
quality_score = max(0, min(100, quality_score))
timeliness_score = max(0, min(100, timeliness_score))
safety_score = max(0, min(100, safety_score))
communication_score = max(0, min(100, communication_score))
# Calculate weighted final score
final_score = (
WEIGHTS["quality"] * quality_score +
WEIGHTS["timeliness"] * timeliness_score +
WEIGHTS["safety"] * safety_score +
WEIGHTS["communication"] * communication_score
)
# Alert flag logic
alert_flag = final_score < 50
# Trend detection (compare with historical scores for this vendor)
vendor_history = [score for score in historical_scores if score["vendor_id"] == logs.vendor_id]
trend_deviation = None
if len(vendor_history) >= 2:
previous_scores = [score["final_score"] for score in vendor_history[-2:]]
trend_deviation = final_score - np.mean(previous_scores)
# Store the current score
historical_scores.append({
"vendor_id": logs.vendor_id,
"month": logs.month,
"final_score": final_score,
"quality_score": quality_score,
"timeliness_score": timeliness_score,
"safety_score": safety_score,
"communication_score": communication_score
})
# Mock certification URL (replace with actual logic)
certification_url = f"https://example.com/cert/{logs.vendor_id}"
# Prepare response
response = ScoreResponse(
vendor_id=logs.vendor_id,
month=logs.month,
final_score=round(final_score, 2),
quality_score=round(quality_score, 2),
timeliness_score=round(timeliness_score, 2),
safety_score=round(safety_score, 2),
communication_score=round(communication_score, 2),
alert_flag=alert_flag,
trend_deviation=round(trend_deviation, 2) if trend_deviation is not None else None,
certification_url=certification_url
)
return JSONResponse(content=response.dict())
except ValueError as e:
return JSONResponse(
content={"detail": f"Invalid input: {str(e)}"},
status_code=400
)
except json.JSONDecodeError:
return JSONResponse(
content={"detail": "Invalid JSON format"},
status_code=400
)
except Exception as e:
return JSONResponse(
content={"detail": f"Internal server error: {str(e)}"},
status_code=500
)
async def health_check(request: Request):
return JSONResponse(content={"status": "healthy"})
# Define routes
app.routes.append(Route("/score", endpoint=calculate_score, methods=["POST"]))
app.routes.append(Route("/health", endpoint=health_check, methods=["GET"]))
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8001)