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
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 |
-
#
|
| 48 |
-
|
| 49 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
|