Skip to content

Commit ec533cf

Browse files
Fix Endpoint Duplication in FastAPI Swagger by Segregating Routers into Individual Tags
1 parent cf397ba commit ec533cf

File tree

7 files changed

+583
-4
lines changed

7 files changed

+583
-4
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
from fastapi import APIRouter, HTTPException, BackgroundTasks
2+
from pydantic import BaseModel
3+
from typing import Dict, List, Optional, Any
4+
import logging
5+
import uuid
6+
7+
router = APIRouter()
8+
logger = logging.getLogger(__name__)
9+
10+
11+
class ScheduleId(BaseModel):
12+
requestId: str
13+
14+
15+
# ApproxKSTest
16+
class GKSketch(BaseModel):
17+
epsilon: float
18+
summary: List[Dict[str, Any]] = []
19+
xmin: float
20+
xmax: float
21+
numx: int
22+
23+
24+
class ApproxKSTestMetricRequest(BaseModel):
25+
modelId: str
26+
requestName: Optional[str] = None
27+
metricName: Optional[str] = None
28+
batchSize: Optional[int] = 100
29+
thresholdDelta: Optional[float] = None
30+
referenceTag: Optional[str] = None
31+
fitColumns: List[str] = []
32+
epsilon: Optional[float] = None
33+
sketchFitting: Optional[Dict[str, GKSketch]] = None
34+
35+
36+
@router.post("/metrics/drift/approxkstest")
37+
async def compute_approxkstest(request: ApproxKSTestMetricRequest):
38+
"""Compute the current value of ApproxKSTest metric."""
39+
try:
40+
logger.info(f"Computing ApproxKSTest for model: {request.modelId}")
41+
# TODO: Implement
42+
return {"status": "success", "value": 0.5}
43+
except Exception as e:
44+
logger.error(f"Error computing ApproxKSTest: {str(e)}")
45+
raise HTTPException(status_code=500, detail=f"Error computing metric: {str(e)}")
46+
47+
48+
@router.get("/metrics/drift/approxkstest/definition")
49+
async def get_approxkstest_definition():
50+
"""Provide a general definition of ApproxKSTest metric."""
51+
return {
52+
"name": "Approximate Kolmogorov-Smirnov Test",
53+
"description": "Description.",
54+
}
55+
56+
57+
@router.post("/metrics/drift/approxkstest/request")
58+
async def schedule_approxkstest(
59+
request: ApproxKSTestMetricRequest, background_tasks: BackgroundTasks
60+
):
61+
"""Schedule a recurring computation of ApproxKSTest metric."""
62+
request_id = str(uuid.uuid4())
63+
logger.info(f"Scheduling ApproxKSTest computation with ID: {request_id}")
64+
# TODO: Implement
65+
return {"requestId": request_id}
66+
67+
68+
@router.delete("/metrics/drift/approxkstest/request")
69+
async def delete_approxkstest_schedule(schedule: ScheduleId):
70+
"""Delete a recurring computation of ApproxKSTest metric."""
71+
logger.info(f"Deleting ApproxKSTest schedule: {schedule.requestId}")
72+
# TODO: Implement
73+
return {"status": "success", "message": f"Schedule {schedule.requestId} deleted"}
74+
75+
76+
@router.get("/metrics/drift/approxkstest/requests")
77+
async def list_approxkstest_requests():
78+
"""List the currently scheduled computations of ApproxKSTest metric."""
79+
# TODO: Implement
80+
return {"requests": []}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
from fastapi import APIRouter, HTTPException, BackgroundTasks
2+
from pydantic import BaseModel
3+
from typing import List, Optional
4+
import logging
5+
import uuid
6+
7+
router = APIRouter()
8+
logger = logging.getLogger(__name__)
9+
10+
11+
class ScheduleId(BaseModel):
12+
requestId: str
13+
14+
# FourierMMD
15+
class FourierMMDParameters(BaseModel):
16+
nWindow: Optional[int] = None
17+
nTest: Optional[int] = None
18+
nMode: Optional[int] = None
19+
randomSeed: Optional[int] = None
20+
sig: Optional[float] = None
21+
deltaStat: Optional[bool] = None
22+
epsilon: Optional[float] = None
23+
24+
25+
class FourierMMDFitting(BaseModel):
26+
randomSeed: Optional[int] = None
27+
deltaStat: Optional[bool] = None
28+
nMode: Optional[int] = None
29+
scale: Optional[List[float]] = None
30+
aRef: Optional[List[float]] = None
31+
meanMMD: Optional[float] = None
32+
stdMMD: Optional[float] = None
33+
34+
35+
class FourierMMDMetricRequest(BaseModel):
36+
modelId: str
37+
requestName: Optional[str] = None
38+
metricName: Optional[str] = None
39+
batchSize: Optional[int] = 100
40+
thresholdDelta: Optional[float] = None
41+
referenceTag: Optional[str] = None
42+
fitColumns: List[str] = []
43+
parameters: Optional[FourierMMDParameters] = None
44+
gamma: Optional[float] = None
45+
fitting: Optional[FourierMMDFitting] = None
46+
47+
48+
@router.post("/metrics/drift/fouriermmd")
49+
async def compute_fouriermmd(request: FourierMMDMetricRequest):
50+
"""Compute the current value of FourierMMD metric."""
51+
try:
52+
logger.info(f"Computing FourierMMD for model: {request.modelId}")
53+
# TODO: Implement
54+
return {"status": "success", "value": 0.5}
55+
except Exception as e:
56+
logger.error(f"Error computing FourierMMD: {str(e)}")
57+
raise HTTPException(status_code=500, detail=f"Error computing metric: {str(e)}")
58+
59+
60+
@router.get("/metrics/drift/fouriermmd/definition")
61+
async def get_fouriermmd_definition():
62+
"""Provide a general definition of FourierMMD metric."""
63+
return {
64+
"name": "FourierMMD Drift",
65+
"description": "Description",
66+
}
67+
68+
69+
@router.post("/metrics/drift/fouriermmd/request")
70+
async def schedule_fouriermmd(
71+
request: FourierMMDMetricRequest, background_tasks: BackgroundTasks
72+
):
73+
"""Schedule a recurring computation of FourierMMD metric."""
74+
request_id = str(uuid.uuid4())
75+
logger.info(f"Scheduling FourierMMD computation with ID: {request_id}")
76+
# TODO: Implement
77+
return {"requestId": request_id}
78+
79+
80+
@router.delete("/metrics/drift/fouriermmd/request")
81+
async def delete_fouriermmd_schedule(schedule: ScheduleId):
82+
"""Delete a recurring computation of FourierMMD metric."""
83+
logger.info(f"Deleting FourierMMD schedule: {schedule.requestId}")
84+
# TODO: Implement
85+
return {"status": "success", "message": f"Schedule {schedule.requestId} deleted"}
86+
87+
88+
@router.get("/metrics/drift/fouriermmd/requests")
89+
async def list_fouriermmd_requests():
90+
"""List the currently scheduled computations of FourierMMD metric."""
91+
# TODO: Implement
92+
return {"requests": []}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from fastapi import APIRouter, HTTPException, BackgroundTasks
2+
from pydantic import BaseModel
3+
from typing import List, Optional
4+
import logging
5+
import uuid
6+
7+
router = APIRouter()
8+
logger = logging.getLogger(__name__)
9+
10+
11+
class ScheduleId(BaseModel):
12+
requestId: str
13+
14+
15+
# KSTest
16+
class KSTestMetricRequest(BaseModel):
17+
modelId: str
18+
requestName: Optional[str] = None
19+
metricName: Optional[str] = None
20+
batchSize: Optional[int] = 100
21+
thresholdDelta: Optional[float] = None
22+
referenceTag: Optional[str] = None
23+
fitColumns: List[str] = []
24+
25+
26+
@router.post("/metrics/drift/kstest")
27+
async def compute_kstest(request: KSTestMetricRequest):
28+
"""Compute the current value of KSTest metric."""
29+
try:
30+
logger.info(f"Computing KSTest for model: {request.modelId}")
31+
# TODO: Implement
32+
return {"status": "success", "value": 0.5}
33+
except Exception as e:
34+
logger.error(f"Error computing KSTest: {str(e)}")
35+
raise HTTPException(status_code=500, detail=f"Error computing metric: {str(e)}")
36+
37+
38+
@router.get("/metrics/drift/kstest/definition")
39+
async def get_kstest_definition():
40+
"""Provide a general definition of KSTest metric."""
41+
return {
42+
"name": "Kolmogorov-Smirnov Test",
43+
"description": "Description.",
44+
}
45+
46+
47+
@router.post("/metrics/drift/kstest/request")
48+
async def schedule_kstest(
49+
request: KSTestMetricRequest, background_tasks: BackgroundTasks
50+
):
51+
"""Schedule a recurring computation of KSTest metric."""
52+
request_id = str(uuid.uuid4())
53+
logger.info(f"Scheduling KSTest computation with ID: {request_id}")
54+
# TODO: Implement
55+
return {"requestId": request_id}
56+
57+
58+
@router.delete("/metrics/drift/kstest/request")
59+
async def delete_kstest_schedule(schedule: ScheduleId):
60+
"""Delete a recurring computation of KSTest metric."""
61+
logger.info(f"Deleting KSTest schedule: {schedule.requestId}")
62+
# TODO: Implement
63+
return {"status": "success", "message": f"Schedule {schedule.requestId} deleted"}
64+
65+
66+
@router.get("/metrics/drift/kstest/requests")
67+
async def list_kstest_requests():
68+
"""List the currently scheduled computations of KSTest metric."""
69+
# TODO: Implement
70+
return {"requests": []}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
from fastapi import APIRouter, HTTPException, BackgroundTasks
2+
from pydantic import BaseModel
3+
from typing import Dict, List, Optional, Any
4+
import logging
5+
import uuid
6+
7+
router = APIRouter()
8+
logger = logging.getLogger(__name__)
9+
10+
11+
class ScheduleId(BaseModel):
12+
requestId: str
13+
14+
15+
# Meanshift
16+
class StatisticalSummaryValues(BaseModel):
17+
mean: float
18+
variance: float
19+
n: int
20+
max: float
21+
min: float
22+
sum: float
23+
standardDeviation: float
24+
25+
26+
class MeanshiftMetricRequest(BaseModel):
27+
modelId: str
28+
requestName: Optional[str] = None
29+
metricName: Optional[str] = None
30+
batchSize: Optional[int] = 100
31+
thresholdDelta: Optional[float] = None
32+
referenceTag: Optional[str] = None
33+
fitColumns: List[str] = []
34+
fitting: Optional[Dict[str, StatisticalSummaryValues]] = None
35+
36+
37+
@router.post("/metrics/drift/meanshift")
38+
async def compute_meanshift(request: MeanshiftMetricRequest):
39+
"""Compute the current value of Meanshift metric."""
40+
try:
41+
logger.info(f"Computing Meanshift for model: {request.modelId}")
42+
# TODO: Implement
43+
return {"status": "success", "value": 0.5}
44+
except Exception as e:
45+
logger.error(f"Error computing Meanshift: {str(e)}")
46+
raise HTTPException(status_code=500, detail=f"Error computing metric: {str(e)}")
47+
48+
49+
@router.get("/metrics/drift/meanshift/definition")
50+
async def get_meanshift_definition():
51+
"""Provide a general definition of Meanshift metric."""
52+
return {
53+
"name": "Meanshift",
54+
"description": "Description.",
55+
}
56+
57+
58+
@router.post("/metrics/drift/meanshift/request")
59+
async def schedule_meanshift(
60+
request: MeanshiftMetricRequest, background_tasks: BackgroundTasks
61+
):
62+
"""Schedule a recurring computation of Meanshift metric."""
63+
request_id = str(uuid.uuid4())
64+
logger.info(f"Scheduling Meanshift computation with ID: {request_id}")
65+
# TODO: Implement
66+
return {"requestId": request_id}
67+
68+
69+
@router.delete("/metrics/drift/meanshift/request")
70+
async def delete_meanshift_schedule(schedule: ScheduleId):
71+
"""Delete a recurring computation of Meanshift metric."""
72+
logger.info(f"Deleting Meanshift schedule: {schedule.requestId}")
73+
# TODO: Implement
74+
return {"status": "success", "message": f"Schedule {schedule.requestId} deleted"}
75+
76+
77+
@router.get("/metrics/drift/meanshift/requests")
78+
async def list_meanshift_requests():
79+
"""List the currently scheduled computations of Meanshift metric."""
80+
# TODO: Implement
81+
return {"requests": []}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from fastapi import APIRouter, HTTPException
2+
from pydantic import BaseModel
3+
from typing import Optional
4+
import logging
5+
6+
router = APIRouter()
7+
logger = logging.getLogger(__name__)
8+
9+
10+
class ModelConfig(BaseModel):
11+
target: str
12+
name: str
13+
version: Optional[str] = None
14+
15+
16+
class GlobalExplanationRequest(BaseModel):
17+
modelConfig: ModelConfig
18+
19+
20+
@router.post("/explainers/global/lime")
21+
async def global_lime_explanation(request: GlobalExplanationRequest):
22+
"""Compute a global LIME explanation."""
23+
try:
24+
logger.info(
25+
f"Computing global LIME explanation for model: {request.modelConfig.name}"
26+
)
27+
# TODO: Implement
28+
except Exception as e:
29+
logger.error(f"Error computing global LIME explanation: {str(e)}")
30+
raise HTTPException(
31+
status_code=500, detail=f"Error computing explanation: {str(e)}"
32+
)
33+
34+
35+
@router.post("/explainers/global/pdp")
36+
async def global_pdp_explanation(request: GlobalExplanationRequest):
37+
"""Compute a global PDP explanation."""
38+
try:
39+
logger.info(
40+
f"Computing global PDP explanation for model: {request.modelConfig.name}"
41+
)
42+
# TODO: Implement
43+
return {"status": "success", "explanation": {}}
44+
except Exception as e:
45+
logger.error(f"Error computing global PDP explanation: {str(e)}")
46+
raise HTTPException(
47+
status_code=500, detail=f"Error computing explanation: {str(e)}"
48+
)

0 commit comments

Comments
 (0)