Skip to content

Commit 45784ab

Browse files
committed
Create app.py
1 parent 9a4be3a commit 45784ab

File tree

1 file changed

+249
-0
lines changed

1 file changed

+249
-0
lines changed

modelsync/web/app.py

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
"""
2+
Web application for ModelSync visualization
3+
"""
4+
5+
from fastapi import FastAPI, Request, Form, HTTPException
6+
from fastapi.responses import HTMLResponse, JSONResponse
7+
from fastapi.staticfiles import StaticFiles
8+
from fastapi.templating import Jinja2Templates
9+
from pathlib import Path
10+
from typing import Dict, List, Optional, Any
11+
import json
12+
from datetime import datetime
13+
14+
# Import ModelSync components
15+
from modelsync.experiments.branching import ExperimentManager
16+
from modelsync.storage.model_storage import ModelStorage
17+
from modelsync.storage.dataset_storage import DatasetStorage
18+
from modelsync.deployment.continuous_deploy import DeploymentManager
19+
from modelsync.collaboration.audit import CollaborationManager
20+
21+
app = FastAPI(title="ModelSync Web Interface", version="1.0.0")
22+
23+
# Setup templates and static files
24+
templates = Jinja2Templates(directory="modelsync/web/templates")
25+
app.mount("/static", StaticFiles(directory="modelsync/web/static"), name="static")
26+
27+
# Initialize managers
28+
experiment_manager = ExperimentManager()
29+
model_storage = ModelStorage()
30+
dataset_storage = DatasetStorage()
31+
deployment_manager = DeploymentManager()
32+
collaboration_manager = CollaborationManager()
33+
34+
@app.get("/", response_class=HTMLResponse)
35+
async def dashboard(request: Request):
36+
"""Main dashboard"""
37+
38+
# Get summary data
39+
branches = experiment_manager.list_branches()
40+
models = model_storage.list_models()
41+
datasets = dataset_storage.list_datasets()
42+
deployments = deployment_manager.get_deployments()
43+
44+
# Get recent activity
45+
recent_activity = []
46+
for branch in branches[:5]: # Last 5 branches
47+
branch_obj = experiment_manager.get_branch(branch)
48+
if branch_obj:
49+
experiments = branch_obj.get_experiments()
50+
for exp in experiments[:3]: # Last 3 experiments per branch
51+
recent_activity.append({
52+
"type": "experiment",
53+
"branch": branch,
54+
"name": exp["name"],
55+
"timestamp": exp["created_at"],
56+
"metrics": exp.get("metrics", {})
57+
})
58+
59+
# Sort by timestamp
60+
recent_activity.sort(key=lambda x: x["timestamp"], reverse=True)
61+
62+
context = {
63+
"request": request,
64+
"branches_count": len(branches),
65+
"models_count": len(models),
66+
"datasets_count": len(datasets),
67+
"deployments_count": len(deployments),
68+
"recent_activity": recent_activity[:10]
69+
}
70+
71+
return templates.TemplateResponse("dashboard.html", context)
72+
73+
@app.get("/experiments", response_class=HTMLResponse)
74+
async def experiments_page(request: Request):
75+
"""Experiments page"""
76+
branches = experiment_manager.list_branches()
77+
78+
# Get detailed branch information
79+
branch_data = []
80+
for branch_name in branches:
81+
branch = experiment_manager.get_branch(branch_name)
82+
if branch:
83+
experiments = branch.get_experiments()
84+
metrics_summary = branch.get_metrics_summary()
85+
86+
branch_data.append({
87+
"name": branch_name,
88+
"experiments_count": len(experiments),
89+
"metrics_summary": metrics_summary,
90+
"best_experiment": branch.get_best_experiment("accuracy") if experiments else None
91+
})
92+
93+
context = {
94+
"request": request,
95+
"branches": branch_data
96+
}
97+
98+
return templates.TemplateResponse("experiments.html", context)
99+
100+
@app.get("/experiments/{branch_name}", response_class=HTMLResponse)
101+
async def branch_detail(request: Request, branch_name: str):
102+
"""Branch detail page"""
103+
branch = experiment_manager.get_branch(branch_name)
104+
if not branch:
105+
raise HTTPException(status_code=404, detail="Branch not found")
106+
107+
experiments = branch.get_experiments()
108+
metrics_summary = branch.get_metrics_summary()
109+
110+
context = {
111+
"request": request,
112+
"branch": {
113+
"name": branch_name,
114+
"experiments": experiments,
115+
"metrics_summary": metrics_summary
116+
}
117+
}
118+
119+
return templates.TemplateResponse("branch_detail.html", context)
120+
121+
@app.get("/models", response_class=HTMLResponse)
122+
async def models_page(request: Request):
123+
"""Models page"""
124+
models = model_storage.list_models()
125+
126+
# Group models by framework
127+
frameworks = {}
128+
for model in models:
129+
framework = model.get("framework", "unknown")
130+
if framework not in frameworks:
131+
frameworks[framework] = []
132+
frameworks[framework].append(model)
133+
134+
context = {
135+
"request": request,
136+
"models": models,
137+
"frameworks": frameworks
138+
}
139+
140+
return templates.TemplateResponse("models.html", context)
141+
142+
@app.get("/datasets", response_class=HTMLResponse)
143+
async def datasets_page(request: Request):
144+
"""Datasets page"""
145+
datasets = dataset_storage.list_datasets()
146+
147+
# Calculate total size
148+
total_size = sum(dataset.get("size", 0) for dataset in datasets)
149+
150+
context = {
151+
"request": request,
152+
"datasets": datasets,
153+
"total_size": total_size
154+
}
155+
156+
return templates.TemplateResponse("datasets.html", context)
157+
158+
@app.get("/deployments", response_class=HTMLResponse)
159+
async def deployments_page(request: Request):
160+
"""Deployments page"""
161+
rules = deployment_manager.list_deployment_rules()
162+
deployments = deployment_manager.get_deployments()
163+
164+
# Group deployments by status
165+
status_groups = {}
166+
for deployment in deployments:
167+
status = deployment.get("status", "unknown")
168+
if status not in status_groups:
169+
status_groups[status] = []
170+
status_groups[status].append(deployment)
171+
172+
context = {
173+
"request": request,
174+
"rules": rules,
175+
"deployments": deployments,
176+
"status_groups": status_groups
177+
}
178+
179+
return templates.TemplateResponse("deployments.html", context)
180+
181+
@app.get("/api/experiments")
182+
async def api_experiments():
183+
"""API endpoint for experiments data"""
184+
branches = experiment_manager.list_branches()
185+
186+
data = []
187+
for branch_name in branches:
188+
branch = experiment_manager.get_branch(branch_name)
189+
if branch:
190+
experiments = branch.get_experiments()
191+
data.append({
192+
"name": branch_name,
193+
"experiments": experiments,
194+
"count": len(experiments)
195+
})
196+
197+
return {"branches": data}
198+
199+
@app.get("/api/metrics/{branch_name}")
200+
async def api_branch_metrics(branch_name: str):
201+
"""API endpoint for branch metrics"""
202+
branch = experiment_manager.get_branch(branch_name)
203+
if not branch:
204+
raise HTTPException(status_code=404, detail="Branch not found")
205+
206+
experiments = branch.get_experiments()
207+
metrics_summary = branch.get_metrics_summary()
208+
209+
return {
210+
"branch": branch_name,
211+
"experiments": experiments,
212+
"metrics_summary": metrics_summary
213+
}
214+
215+
@app.get("/api/comparison")
216+
async def api_comparison(branches: str = None, metric: str = "accuracy"):
217+
"""API endpoint for branch comparison"""
218+
if not branches:
219+
return {"error": "No branches specified"}
220+
221+
branch_list = branches.split(",")
222+
comparison = experiment_manager.compare_branches(branch_list, metric)
223+
224+
return comparison
225+
226+
@app.post("/api/deploy")
227+
async def api_deploy(
228+
branch: str = Form(...),
229+
model_id: str = Form(...),
230+
metrics: str = Form(...)
231+
):
232+
"""API endpoint to trigger deployment"""
233+
try:
234+
metrics_dict = json.loads(metrics)
235+
triggered_rules = deployment_manager.check_deployment_rules(
236+
branch, metrics_dict, model_id
237+
)
238+
239+
return {
240+
"status": "success",
241+
"triggered_rules": len(triggered_rules),
242+
"rules": triggered_rules
243+
}
244+
except Exception as e:
245+
return {"status": "error", "message": str(e)}
246+
247+
if __name__ == "__main__":
248+
import uvicorn
249+
uvicorn.run(app, host="0.0.0.0", port=8080)

0 commit comments

Comments
 (0)