Subh775 commited on
Commit
a80bf6a
·
1 Parent(s): 4b01352

zip file download, layout centering, upload stability jitter fix

Browse files
Files changed (3) hide show
  1. backend/server.py +24 -0
  2. frontend/initial.html +10 -0
  3. frontend/vehicles.html +12 -19
backend/server.py CHANGED
@@ -28,6 +28,7 @@ REPORT_DIR = Path(tempfile.gettempdir()) / "funky_reports"
28
  REPORT_DIR.mkdir(exist_ok=True)
29
 
30
  videos = {}
 
31
  run_results = {}
32
  model = None
33
 
@@ -77,6 +78,7 @@ async def upload(file: UploadFile = File(...)):
77
  print(f"[BACKEND] Successfully stored: {path} ({file_size} bytes)")
78
 
79
  videos[video_id] = str(path)
 
80
  return {"video_id": video_id}
81
  except Exception as e:
82
  print(f"[BACKEND] Upload failed: {str(e)}")
@@ -135,6 +137,28 @@ def get_report(video_id: str, name: str):
135
  return FileResponse(str(path), media_type=media)
136
 
137
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  @app.websocket("/ws/run")
139
  async def ws_run(ws: WebSocket):
140
  await ws.accept()
 
28
  REPORT_DIR.mkdir(exist_ok=True)
29
 
30
  videos = {}
31
+ video_info = {}
32
  run_results = {}
33
  model = None
34
 
 
78
  print(f"[BACKEND] Successfully stored: {path} ({file_size} bytes)")
79
 
80
  videos[video_id] = str(path)
81
+ video_info[video_id] = file.filename
82
  return {"video_id": video_id}
83
  except Exception as e:
84
  print(f"[BACKEND] Upload failed: {str(e)}")
 
137
  return FileResponse(str(path), media_type=media)
138
 
139
 
140
+ @app.get("/reports/zip/{video_id}")
141
+ def download_all_reports(video_id: str):
142
+ base_path = REPORT_DIR / video_id
143
+ if not base_path.exists():
144
+ return Response(status_code=404)
145
+
146
+ # Create zip in temp dir
147
+ zip_base = REPORT_DIR / f"bundle_{video_id}"
148
+ shutil.make_archive(str(zip_base), 'zip', str(base_path))
149
+
150
+ final_zip = Path(f"{zip_base}.zip")
151
+
152
+ original_name = video_info.get(video_id, "UrbanFlow_Analysis")
153
+ safe_name = "".join(x for x in original_name if x.isalnum() or x in "._-").rsplit(".", 1)[0]
154
+
155
+ return FileResponse(
156
+ str(final_zip),
157
+ media_type="application/zip",
158
+ filename=f"{safe_name}_UrbanFlow.zip"
159
+ )
160
+
161
+
162
  @app.websocket("/ws/run")
163
  async def ws_run(ws: WebSocket):
164
  await ws.accept()
frontend/initial.html CHANGED
@@ -213,6 +213,11 @@
213
  if (name === 'upload') {
214
  document.getElementById('upload-progress-container').classList.add('hidden');
215
  document.getElementById('dropzone').classList.remove('hidden');
 
 
 
 
 
216
  }
217
  if (name === 'draw') loadFirstFrame();
218
  }
@@ -236,7 +241,11 @@
236
  });
237
  }
238
 
 
239
  function uploadFile(file) {
 
 
 
240
  const dropzoneEl = document.getElementById('dropzone');
241
  const prog = document.getElementById('upload-progress-container');
242
  const bar = document.getElementById('upload-bar');
@@ -250,6 +259,7 @@
250
  form.append('file', file);
251
 
252
  const xhr = new XMLHttpRequest();
 
253
  xhr.open('POST', '/upload');
254
 
255
  xhr.upload.onprogress = e => {
 
213
  if (name === 'upload') {
214
  document.getElementById('upload-progress-container').classList.add('hidden');
215
  document.getElementById('dropzone').classList.remove('hidden');
216
+ // Reset Progress Bar state for new uploads
217
+ document.getElementById('upload-bar').style.width = '0%';
218
+ document.getElementById('upload-percentage').innerText = '0%';
219
+ document.getElementById('upload-text').innerText = 'Uploading...';
220
+ document.getElementById('upload-text').classList.remove('text-red-500');
221
  }
222
  if (name === 'draw') loadFirstFrame();
223
  }
 
241
  });
242
  }
243
 
244
+ let currentXHR = null;
245
  function uploadFile(file) {
246
+ // Abort previous upload if it exists to prevent jitter/multiple requests
247
+ if (currentXHR) currentXHR.abort();
248
+
249
  const dropzoneEl = document.getElementById('dropzone');
250
  const prog = document.getElementById('upload-progress-container');
251
  const bar = document.getElementById('upload-bar');
 
259
  form.append('file', file);
260
 
261
  const xhr = new XMLHttpRequest();
262
+ currentXHR = xhr;
263
  xhr.open('POST', '/upload');
264
 
265
  xhr.upload.onprogress = e => {
frontend/vehicles.html CHANGED
@@ -798,7 +798,7 @@
798
  </div>
799
 
800
  <!-- New Analysis Button (visible only after processing completes) -->
801
- <div class="col-span-3 pb-4 hidden justify-center" id="new-analysis-wrap">
802
  <button onclick="startNewAnalysis()"
803
  class="w-fit px-16 py-4 font-bold text-sm rounded-full transition flex items-center justify-center gap-2 shadow-lg hover:scale-105 active:scale-95"
804
  style="background:var(--cocoa-l);color:#000">
@@ -1510,24 +1510,16 @@
1510
 
1511
  // Auto-Download Logic (Respects live toggle state)
1512
  if (document.getElementById('sv-auto-download').classList.contains('active')) {
1513
- const preferredFmt = document.getElementById('sv-report').value;
1514
- console.log(`[UrbanFlow] Auto-downloading ${preferredFmt} reports...`);
1515
-
1516
- // Download the primary charts in the user's preferred format
1517
- data.files.forEach(targetFile => {
1518
- // We only auto-download the primary KPI charts, not everything
1519
- const isTarget = targetFile.endsWith(`.${preferredFmt}`) &&
1520
- (targetFile.includes('congestion') || targetFile.includes('direction') || targetFile.includes('flow'));
1521
-
1522
- if (isTarget) {
1523
- const link = document.createElement('a');
1524
- link.href = `/reports/${d.video_id}/${targetFile}`;
1525
- link.download = targetFile;
1526
- document.body.appendChild(link);
1527
- link.click();
1528
- document.body.removeChild(link);
1529
- }
1530
- });
1531
  }
1532
  });
1533
  }
@@ -1729,6 +1721,7 @@
1729
  </div>
1730
 
1731
  <script>
 
1732
  function openAppModal(id) {
1733
  const el = document.getElementById('appModal-' + id);
1734
  if (el) { el.style.display = 'flex'; document.body.style.overflow = 'hidden'; }
 
798
  </div>
799
 
800
  <!-- New Analysis Button (visible only after processing completes) -->
801
+ <div class="col-span-3 pb-4 hidden flex justify-center" id="new-analysis-wrap">
802
  <button onclick="startNewAnalysis()"
803
  class="w-fit px-16 py-4 font-bold text-sm rounded-full transition flex items-center justify-center gap-2 shadow-lg hover:scale-105 active:scale-95"
804
  style="background:var(--cocoa-l);color:#000">
 
1510
 
1511
  // Auto-Download Logic (Respects live toggle state)
1512
  if (document.getElementById('sv-auto-download').classList.contains('active')) {
1513
+ // Download the full bundle ZIP
1514
+ setTimeout(() => {
1515
+ console.log('[UrbanFlow] Auto-downloading ZIP bundle...');
1516
+ const link = document.createElement('a');
1517
+ link.href = `/reports/zip/${d.video_id}`;
1518
+ link.download = `UrbanFlow_Analysis.zip`;
1519
+ document.body.appendChild(link);
1520
+ link.click();
1521
+ document.body.removeChild(link);
1522
+ }, 500);
 
 
 
 
 
 
 
 
1523
  }
1524
  });
1525
  }
 
1721
  </div>
1722
 
1723
  <script>
1724
+
1725
  function openAppModal(id) {
1726
  const el = document.getElementById('appModal-' + id);
1727
  if (el) { el.style.display = 'flex'; document.body.style.overflow = 'hidden'; }