Sheikh Mohammad Rakib commited on
Commit
8ed40e0
·
1 Parent(s): 5d301ee

feat: add JSON decoding robustness and interactive progress UI for memory generation

Browse files
Files changed (1) hide show
  1. app.py +127 -5
app.py CHANGED
@@ -44,9 +44,15 @@ def modal_post(url, payload, timeout=300, retries=3, label="endpoint"):
44
  try:
45
  return r.json(), None
46
  except Exception:
47
- # Non-JSON body — surface the actual content
48
- body = r.text[:500]
49
- return None, f"{label} HTTP {r.status_code}: {body}"
 
 
 
 
 
 
50
 
51
  except requests.exceptions.Timeout:
52
  last_err = f"{label} timed out after {timeout}s (attempt {attempt}/{retries})"
@@ -79,7 +85,13 @@ def modal_get(url, timeout=90, retries=2, label="endpoint"):
79
  try:
80
  return r.json(), None
81
  except Exception:
82
- return None, f"{label} HTTP {r.status_code}: {r.text[:300]}"
 
 
 
 
 
 
83
  except Exception as e:
84
  last_err = f"{label} error: {e}"
85
  if attempt < retries:
@@ -309,7 +321,117 @@ with gr.Blocks(title="Memory Keeper") as demo:
309
  )
310
 
311
  build_btn = gr.Button("✨ Preserve Their Memory", variant="primary")
312
- build_output = gr.Markdown()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313
  persona_id_state = gr.State()
314
  persona_id_hidden = gr.Textbox(visible=False)
315
 
 
44
  try:
45
  return r.json(), None
46
  except Exception:
47
+ # Try extracting the first valid JSON object (handles "extra data" / concatenated responses)
48
+ import json as _json
49
+ raw = r.text.strip()
50
+ try:
51
+ obj, _ = _json.JSONDecoder().raw_decode(raw)
52
+ return obj, None
53
+ except Exception:
54
+ body = raw[:500]
55
+ return None, f"{label} HTTP {r.status_code}: {body}"
56
 
57
  except requests.exceptions.Timeout:
58
  last_err = f"{label} timed out after {timeout}s (attempt {attempt}/{retries})"
 
85
  try:
86
  return r.json(), None
87
  except Exception:
88
+ import json as _json
89
+ raw = r.text.strip()
90
+ try:
91
+ obj, _ = _json.JSONDecoder().raw_decode(raw)
92
+ return obj, None
93
+ except Exception:
94
+ return None, f"{label} HTTP {r.status_code}: {raw[:300]}"
95
  except Exception as e:
96
  last_err = f"{label} error: {e}"
97
  if attempt < retries:
 
321
  )
322
 
323
  build_btn = gr.Button("✨ Preserve Their Memory", variant="primary")
324
+
325
+ # ── Progress bar (shown while processing) ──
326
+ progress_html = gr.HTML("""
327
+ <div id="preserve-progress" style="display:none; margin: 14px 0;">
328
+ <div style="display:flex; align-items:center; gap:10px; margin-bottom:8px;">
329
+ <span style="color:#d4a96a; font-family:'Lora',serif; font-size:0.95em;">
330
+ 🕯️ <span id="progress-label">Preparing memories…</span>
331
+ </span>
332
+ </div>
333
+ <div style="background:#1a1510; border:1px solid #3a2e1e; border-radius:8px; overflow:hidden; height:14px;">
334
+ <div id="progress-bar-inner" style="
335
+ height:100%; width:0%;
336
+ background: linear-gradient(90deg, #c47f17, #e8a83e, #c47f17);
337
+ background-size: 200% 100%;
338
+ border-radius:8px;
339
+ transition: width 0.6s ease;
340
+ animation: shimmer 1.8s infinite linear;
341
+ "></div>
342
+ </div>
343
+ <p style="color:#8a7560; font-size:0.8em; margin-top:6px; font-style:italic;" id="progress-sub">
344
+ This may take 1–3 minutes on cold start. Please wait…
345
+ </p>
346
+ </div>
347
+ <style>
348
+ @keyframes shimmer {
349
+ 0% { background-position: 200% 0; }
350
+ 100% { background-position: -200% 0; }
351
+ }
352
+ </style>
353
+ <script>
354
+ (function() {
355
+ const STEPS = [
356
+ [5, "🎤 Transcribing voice note…"],
357
+ [18, "👁️ Analysing photos…"],
358
+ [32, "📄 Running OCR on scanned docs…"],
359
+ [50, "🧠 Building persona with Qwen 32B…"],
360
+ [70, "🧠 Still thinking — large model at work…"],
361
+ [85, "✍️ Finalising personality profile…"],
362
+ [95, "🔗 Saving to memory store…"],
363
+ ];
364
+ let _timer = null, _stepIdx = 0;
365
+
366
+ function startProgress() {
367
+ const bar = document.getElementById("progress-bar-inner");
368
+ const lbl = document.getElementById("progress-label");
369
+ const box = document.getElementById("preserve-progress");
370
+ if (!bar) return;
371
+ box.style.display = "block";
372
+ _stepIdx = 0;
373
+ bar.style.width = "2%";
374
+ lbl.textContent = "Preparing memories…";
375
+ _timer = setInterval(function() {
376
+ if (_stepIdx < STEPS.length) {
377
+ bar.style.width = STEPS[_stepIdx][0] + "%";
378
+ lbl.textContent = STEPS[_stepIdx][1];
379
+ _stepIdx++;
380
+ }
381
+ }, 9000);
382
+ }
383
+
384
+ function stopProgress() {
385
+ clearInterval(_timer);
386
+ const bar = document.getElementById("progress-bar-inner");
387
+ const box = document.getElementById("preserve-progress");
388
+ const lbl = document.getElementById("progress-label");
389
+ if (bar) { bar.style.width = "100%"; }
390
+ if (lbl) { lbl.textContent = "✅ Done!"; }
391
+ setTimeout(function() { if (box) box.style.display = "none"; }, 2200);
392
+ }
393
+
394
+ // Attach to the Preserve button after DOM is ready
395
+ function attachListeners() {
396
+ // Find the primary button that contains "Preserve"
397
+ const btns = document.querySelectorAll("button");
398
+ btns.forEach(function(btn) {
399
+ if (btn.textContent.includes("Preserve Their Memory")) {
400
+ btn.addEventListener("click", startProgress);
401
+ }
402
+ });
403
+ // Watch for Gradio's own progress bar disappearing as a "done" signal
404
+ const observer = new MutationObserver(function(mutations) {
405
+ mutations.forEach(function(m) {
406
+ m.removedNodes.forEach(function(n) {
407
+ if (n.nodeType === 1 && (n.classList.contains("progress-bar") || n.id === "progress-tracker")) {
408
+ stopProgress();
409
+ }
410
+ });
411
+ });
412
+ });
413
+ observer.observe(document.body, { childList: true, subtree: true });
414
+
415
+ // Also stop when the result markdown area gets content
416
+ const resultObs = new MutationObserver(function() {
417
+ const md = document.querySelector(".preserve-result .prose");
418
+ if (md && md.textContent.trim().length > 0) {
419
+ stopProgress();
420
+ }
421
+ });
422
+ resultObs.observe(document.body, { childList: true, subtree: true });
423
+ }
424
+
425
+ if (document.readyState === "loading") {
426
+ document.addEventListener("DOMContentLoaded", attachListeners);
427
+ } else {
428
+ setTimeout(attachListeners, 1200);
429
+ }
430
+ })();
431
+ </script>
432
+ """)
433
+
434
+ build_output = gr.Markdown(elem_classes=["preserve-result"])
435
  persona_id_state = gr.State()
436
  persona_id_hidden = gr.Textbox(visible=False)
437