varshakolanu commited on
Commit
6c12c70
·
verified ·
1 Parent(s): 3722a09

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +141 -0
app.py ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from starlette.applications import Starlette
2
+ from starlette.routing import Route
3
+ from starlette.requests import Request
4
+ from starlette.responses import JSONResponse
5
+ from pydantic import BaseModel, Field
6
+ from typing import List, Optional
7
+ from datetime import datetime
8
+ import uvicorn
9
+ import numpy as np
10
+ import json
11
+
12
+ app = Starlette(debug=True)
13
+
14
+ # In-memory store for historical scores (replace with database for production)
15
+ historical_scores = []
16
+
17
+ # Define the request body structure
18
+ class VendorLog(BaseModel):
19
+ vendor_id: str = Field(..., description="Unique identifier for the vendor")
20
+ delay_logs: int = Field(..., ge=0, description="Number of delay incidents")
21
+ qa_incidents: int = Field(..., ge=0, description="Number of quality assurance incidents")
22
+ safety_compliance: int = Field(..., ge=0, description="Number of safety compliance issues")
23
+ feedback_logs: int = Field(..., ge=0, description="Number of feedback logs")
24
+ work_logs: int = Field(..., ge=1, description="Total number of work logs")
25
+ month: str = Field(..., description="Month of the score (YYYY-MM format)")
26
+
27
+ # Define the response structure
28
+ class ScoreResponse(BaseModel):
29
+ vendor_id: str
30
+ month: str
31
+ final_score: float
32
+ quality_score: float
33
+ timeliness_score: float
34
+ safety_score: float
35
+ communication_score: float
36
+ alert_flag: bool
37
+ trend_deviation: Optional[float]
38
+ certification_url: Optional[str]
39
+
40
+ # Scoring weights (configurable)
41
+ WEIGHTS = {
42
+ "quality": 0.3,
43
+ "timeliness": 0.3,
44
+ "safety": 0.2,
45
+ "communication": 0.2
46
+ }
47
+
48
+ async def calculate_score(request: Request):
49
+ try:
50
+ # Parse JSON body
51
+ body = await request.json()
52
+ logs = VendorLog(**body)
53
+
54
+ # Validate month format
55
+ datetime.strptime(logs.month, "%Y-%m")
56
+
57
+ # Calculate individual scores
58
+ quality_score = (1 - logs.qa_incidents / logs.work_logs) * 100
59
+ timeliness_score = (1 - logs.delay_logs / logs.work_logs) * 100
60
+ safety_score = (1 - logs.safety_compliance / logs.work_logs) * 100
61
+ communication_score = (logs.feedback_logs / logs.work_logs) * 50 # Adjusted logic
62
+
63
+ # Ensure scores are within 0-100
64
+ quality_score = max(0, min(100, quality_score))
65
+ timeliness_score = max(0, min(100, timeliness_score))
66
+ safety_score = max(0, min(100, safety_score))
67
+ communication_score = max(0, min(100, communication_score))
68
+
69
+ # Calculate weighted final score
70
+ final_score = (
71
+ WEIGHTS["quality"] * quality_score +
72
+ WEIGHTS["timeliness"] * timeliness_score +
73
+ WEIGHTS["safety"] * safety_score +
74
+ WEIGHTS["communication"] * communication_score
75
+ )
76
+
77
+ # Alert flag logic
78
+ alert_flag = final_score < 50
79
+
80
+ # Trend detection (compare with historical scores for this vendor)
81
+ vendor_history = [score for score in historical_scores if score["vendor_id"] == logs.vendor_id]
82
+ trend_deviation = None
83
+ if len(vendor_history) >= 2:
84
+ previous_scores = [score["final_score"] for score in vendor_history[-2:]]
85
+ trend_deviation = final_score - np.mean(previous_scores)
86
+
87
+ # Store the current score
88
+ historical_scores.append({
89
+ "vendor_id": logs.vendor_id,
90
+ "month": logs.month,
91
+ "final_score": final_score,
92
+ "quality_score": quality_score,
93
+ "timeliness_score": timeliness_score,
94
+ "safety_score": safety_score,
95
+ "communication_score": communication_score
96
+ })
97
+
98
+ # Mock certification URL (replace with actual logic)
99
+ certification_url = f"https://example.com/cert/{logs.vendor_id}"
100
+
101
+ # Prepare response
102
+ response = ScoreResponse(
103
+ vendor_id=logs.vendor_id,
104
+ month=logs.month,
105
+ final_score=round(final_score, 2),
106
+ quality_score=round(quality_score, 2),
107
+ timeliness_score=round(timeliness_score, 2),
108
+ safety_score=round(safety_score, 2),
109
+ communication_score=round(communication_score, 2),
110
+ alert_flag=alert_flag,
111
+ trend_deviation=round(trend_deviation, 2) if trend_deviation is not None else None,
112
+ certification_url=certification_url
113
+ )
114
+
115
+ return JSONResponse(content=response.dict())
116
+
117
+ except ValueError as e:
118
+ return JSONResponse(
119
+ content={"detail": f"Invalid input: {str(e)}"},
120
+ status_code=400
121
+ )
122
+ except json.JSONDecodeError:
123
+ return JSONResponse(
124
+ content={"detail": "Invalid JSON format"},
125
+ status_code=400
126
+ )
127
+ except Exception as e:
128
+ return JSONResponse(
129
+ content={"detail": f"Internal server error: {str(e)}"},
130
+ status_code=500
131
+ )
132
+
133
+ async def health_check(request: Request):
134
+ return JSONResponse(content={"status": "healthy"})
135
+
136
+ # Define routes
137
+ app.routes.append(Route("/score", endpoint=calculate_score, methods=["POST"]))
138
+ app.routes.append(Route("/health", endpoint=health_check, methods=["GET"]))
139
+
140
+ if __name__ == "__main__":
141
+ uvicorn.run(app, host="0.0.0.0", port=8001)