Mridul2004's picture
Initial commit - Model Speed Comparator
97f0024
Raw
History Blame Contribute Delete
5.12 kB
from datetime import datetime
import time
from fastapi import FastAPI, HTTPException
from fastapi.staticfiles import StaticFiles
from fastapi.responses import HTMLResponse
from pydantic import BaseModel
from app.inference import run_all_models, run_benchmark
app = FastAPI(title="Model Speed Comparator", version="1.0.0")
app.mount("/static", StaticFiles(directory="static"), name="static")
comparison_history = []
MAX_HISTORY_ITEMS = 10
class TextInput(BaseModel):
text: str
class BatchInput(BaseModel):
texts: list[str]
session_stats = {
"total_requests": 0,
"latency_sum": {
"baseline": 0.0,
"onnx": 0.0,
"quantized": 0.0,
},
"fastest_count": {
"baseline": 0,
"onnx": 0,
"quantized": 0,
},
}
def _build_summary(results: dict) -> dict:
quantized_latency = max(results["quantized"]["latency_ms"], 0.01)
return {
"fastest": min(results, key=lambda x: results[x]["latency_ms"]),
"smallest": min(results, key=lambda x: results[x]["model_size_mb"]),
"speedup_vs_baseline": round(
results["baseline"]["latency_ms"] / quantized_latency, 1
)
}
def _model_error(exc: Exception) -> HTTPException:
return HTTPException(
status_code=503,
detail=(
"Model loading or inference failed. Confirm dependencies are installed, "
"run the server from the project root, and check the models folder. "
f"Original error: {exc}"
),
)
def _add_history_item(text: str, results: dict, summary: dict) -> None:
comparison_history.insert(
0,
{
"timestamp": datetime.now().isoformat(timespec="seconds"),
"input": text,
"results": results,
"summary": summary,
},
)
del comparison_history[MAX_HISTORY_ITEMS:]
def _record_stats(results: dict, summary: dict) -> None:
session_stats["total_requests"] += 1
session_stats["fastest_count"][summary["fastest"]] += 1
for model_name, result in results.items():
session_stats["latency_sum"][model_name] += result["latency_ms"]
def _run_comparison(text: str, include_history: bool = True) -> dict:
results = run_all_models(text)
summary = _build_summary(results)
_record_stats(results, summary)
if include_history:
_add_history_item(text, results, summary)
return {
"input": text,
"results": results,
"summary": summary,
}
def _validate_batch_texts(texts: list[str]) -> list[str]:
if not texts:
raise HTTPException(status_code=400, detail="At least one text is required")
if len(texts) > 10:
raise HTTPException(status_code=400, detail="Batch size cannot exceed 10 texts")
cleaned = [text.strip() for text in texts]
if any(not text for text in cleaned):
raise HTTPException(status_code=400, detail="Batch texts cannot be empty")
return cleaned
@app.get("/", response_class=HTMLResponse)
async def root():
with open("static/index.html") as f:
return f.read()
@app.post("/compare")
async def compare_models(input: TextInput):
if not input.text.strip():
raise HTTPException(status_code=400, detail="Text cannot be empty")
try:
return _run_comparison(input.text)
except Exception as exc:
raise _model_error(exc) from exc
@app.post("/compare/batch")
async def compare_batch(input: BatchInput):
texts = _validate_batch_texts(input.texts)
started = time.perf_counter()
items = []
try:
for text in texts:
items.append(_run_comparison(text))
except Exception as exc:
raise _model_error(exc) from exc
total_ms = round((time.perf_counter() - started) * 1000, 2)
return {
"count": len(items),
"total_wall_time_ms": total_ms,
"avg_wall_time_per_text_ms": round(total_ms / len(items), 2),
"throughput_texts_per_second": round(len(items) / (total_ms / 1000), 2) if total_ms > 0 else 0,
"items": items,
}
@app.post("/benchmark")
async def benchmark_models(input: TextInput):
if not input.text.strip():
raise HTTPException(status_code=400, detail="Text cannot be empty")
try:
benchmark = run_benchmark(input.text, iterations=20)
except Exception as exc:
raise _model_error(exc) from exc
summary = _build_summary(benchmark["latest_results"])
return {
"input": input.text,
"summary": summary,
**benchmark,
}
@app.get("/history")
async def get_history():
return {"history": comparison_history}
@app.get("/stats")
async def get_stats():
total = session_stats["total_requests"]
avg_latency = {}
for model_name, latency_sum in session_stats["latency_sum"].items():
avg_latency[model_name] = round(latency_sum / total, 2) if total else 0
return {
"total_requests": total,
"avg_latency": avg_latency,
"fastest_count": session_stats["fastest_count"],
}
@app.get("/health")
async def health():
return {"status": "ok"}