Spaces:
Running on Zero
Running on Zero
Update app.py
Browse files
app.py
CHANGED
|
@@ -4,14 +4,13 @@ import json
|
|
| 4 |
import os
|
| 5 |
import time
|
| 6 |
import subprocess
|
|
|
|
| 7 |
from pathlib import Path
|
| 8 |
from huggingface_hub import InferenceClient
|
| 9 |
|
| 10 |
subprocess.run(["pip", "install", "pypdf", "-q"], capture_output=True)
|
| 11 |
from pypdf import PdfReader
|
| 12 |
|
| 13 |
-
SAVE_DIR = Path("/tmp/saved_docs")
|
| 14 |
-
SAVE_DIR.mkdir(exist_ok=True)
|
| 15 |
MODEL = "meta-llama/Llama-3.3-70B-Instruct"
|
| 16 |
|
| 17 |
def get_client():
|
|
@@ -114,9 +113,8 @@ def analyse(pdf_file):
|
|
| 114 |
|
| 115 |
def save_analysis(r1, r2, r3, r4):
|
| 116 |
if not r1:
|
| 117 |
-
return "⚠️ Nothing to save — run an analysis first."
|
| 118 |
ts = time.strftime("%Y-%m-%d %H:%M")
|
| 119 |
-
doc_id = str(int(time.time() * 1000))
|
| 120 |
content = (
|
| 121 |
f"METABOLIC PHOENIX FRAMEWORK — FULL ANALYSIS\n"
|
| 122 |
f"Generated: {ts}\n"
|
|
@@ -126,15 +124,16 @@ def save_analysis(r1, r2, r3, r4):
|
|
| 126 |
f"{'='*60}\n\nCYCLE 3 — OUROBOROS LOOPS\n\n{r3}\n\n"
|
| 127 |
f"{'='*60}\n\nCYCLE 4 — FULL CASE OUTPUT\n\n{r4}"
|
| 128 |
)
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
|
|
|
| 138 |
|
| 139 |
CSS = """
|
| 140 |
@import url('https://fonts.googleapis.com/css2?family=Syne:wght@400;700;800&family=DM+Mono:wght@400;500&display=swap');
|
|
@@ -157,7 +156,6 @@ body, .gradio-container {
|
|
| 157 |
font-family: 'Syne', sans-serif !important;
|
| 158 |
color: var(--text) !important;
|
| 159 |
}
|
| 160 |
-
|
| 161 |
.hdr {
|
| 162 |
text-align: center;
|
| 163 |
padding: 2.4rem 1rem 1.6rem;
|
|
@@ -167,129 +165,134 @@ body, .gradio-container {
|
|
| 167 |
radial-gradient(ellipse at 70% 50%, rgba(0,207,255,0.08) 0%, transparent 60%);
|
| 168 |
}
|
| 169 |
.hdr h1 {
|
| 170 |
-
font-size: 2.2rem;
|
| 171 |
-
font-weight: 800;
|
| 172 |
-
letter-spacing: -0.04em;
|
| 173 |
background: linear-gradient(135deg, var(--accent) 0%, var(--accent2) 100%);
|
| 174 |
-
-webkit-background-clip: text;
|
| 175 |
-
-webkit-text-fill-color: transparent;
|
| 176 |
-
margin: 0 0 0.3rem;
|
| 177 |
-
}
|
| 178 |
-
.hdr .sub {
|
| 179 |
-
color: var(--muted);
|
| 180 |
-
font-family: 'DM Mono', monospace;
|
| 181 |
-
font-size: .75rem;
|
| 182 |
-
letter-spacing: .06em;
|
| 183 |
}
|
| 184 |
-
.hdr .
|
| 185 |
-
|
| 186 |
-
font-family: 'DM Mono', monospace;
|
| 187 |
-
font-size: .68rem;
|
| 188 |
-
margin-top: .3rem;
|
| 189 |
-
letter-spacing: .1em;
|
| 190 |
-
text-transform: uppercase;
|
| 191 |
-
}
|
| 192 |
-
|
| 193 |
input[type=text], textarea {
|
| 194 |
-
background: var(--surface) !important;
|
| 195 |
-
border:
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
font-family: 'DM Mono', monospace !important;
|
| 199 |
-
font-size: .86rem !important;
|
| 200 |
-
padding: .6rem .85rem !important;
|
| 201 |
-
transition: border-color .18s !important;
|
| 202 |
}
|
| 203 |
input[type=text]:focus, textarea:focus {
|
| 204 |
-
border-color: var(--accent) !important;
|
| 205 |
-
outline: none !important;
|
| 206 |
box-shadow: 0 0 0 3px rgba(0,207,255,.12) !important;
|
| 207 |
}
|
| 208 |
-
|
| 209 |
label > span:first-child {
|
| 210 |
-
color: var(--muted) !important;
|
| 211 |
-
font-
|
| 212 |
-
font-size: .7rem !important;
|
| 213 |
-
letter-spacing: .08em !important;
|
| 214 |
-
text-transform: uppercase !important;
|
| 215 |
}
|
| 216 |
-
|
| 217 |
button.primary {
|
| 218 |
background: linear-gradient(135deg, var(--accent3), var(--accent)) !important;
|
| 219 |
-
color: #030712 !important;
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
font-weight: 800 !important;
|
| 224 |
-
font-size: .92rem !important;
|
| 225 |
-
padding: .75rem 2.8rem !important;
|
| 226 |
-
cursor: pointer !important;
|
| 227 |
-
transition: opacity .15s, transform .15s !important;
|
| 228 |
-
letter-spacing: .04em !important;
|
| 229 |
}
|
| 230 |
-
button.primary:hover {
|
| 231 |
-
opacity: .88 !important;
|
| 232 |
-
transform: translateY(-1px) !important;
|
| 233 |
-
}
|
| 234 |
-
|
| 235 |
button.secondary {
|
| 236 |
-
background: var(--surface2) !important;
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
font-family: 'Syne', sans-serif !important;
|
| 241 |
-
font-weight: 700 !important;
|
| 242 |
-
font-size: .8rem !important;
|
| 243 |
-
padding: .5rem 1.2rem !important;
|
| 244 |
-
cursor: pointer !important;
|
| 245 |
-
transition: all .15s !important;
|
| 246 |
}
|
| 247 |
-
button.secondary:hover {
|
| 248 |
-
background: var(--accent3) !important;
|
| 249 |
-
color: #030712 !important;
|
| 250 |
-
}
|
| 251 |
-
|
| 252 |
.out textarea {
|
| 253 |
-
background: #020510 !important;
|
| 254 |
-
border: 1px solid var(--border) !important;
|
| 255 |
border-left: 3px solid var(--accent) !important;
|
| 256 |
border-radius: 0 var(--r) var(--r) 0 !important;
|
| 257 |
-
font-family: 'DM Mono', monospace !important;
|
| 258 |
-
|
| 259 |
-
line-height: 1.7 !important;
|
| 260 |
-
color: var(--text) !important;
|
| 261 |
}
|
| 262 |
-
|
| 263 |
.gradio-accordion {
|
| 264 |
-
background: var(--surface2) !important;
|
| 265 |
-
border:
|
| 266 |
-
border-radius: var(--r) !important;
|
| 267 |
-
margin-bottom: .6rem !important;
|
| 268 |
}
|
| 269 |
-
|
| 270 |
.gradio-accordion .label-wrap span {
|
| 271 |
-
color: var(--accent2) !important;
|
| 272 |
-
font-
|
| 273 |
-
font-weight: 700 !important;
|
| 274 |
-
font-size: .85rem !important;
|
| 275 |
-
letter-spacing: .04em !important;
|
| 276 |
}
|
| 277 |
-
|
| 278 |
-
.
|
| 279 |
-
|
| 280 |
-
|
|
|
|
|
|
|
|
|
|
| 281 |
}
|
| 282 |
-
|
| 283 |
-
.foot {
|
| 284 |
-
text-align: center;
|
| 285 |
-
padding: 1.5rem;
|
| 286 |
color: var(--muted);
|
| 287 |
font-family: 'DM Mono', monospace;
|
| 288 |
-
font-size: .
|
| 289 |
-
|
| 290 |
-
margin-top: 2rem;
|
| 291 |
letter-spacing: .05em;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 292 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 293 |
"""
|
| 294 |
|
| 295 |
with gr.Blocks(css=CSS, title="Metabolic Phoenix Framework") as demo:
|
|
@@ -317,11 +320,14 @@ with gr.Blocks(css=CSS, title="Metabolic Phoenix Framework") as demo:
|
|
| 317 |
with gr.Accordion("Cycle 4 — Full Case Output", open=False):
|
| 318 |
out4 = gr.Textbox(label="", lines=12, elem_classes=["out"])
|
| 319 |
|
| 320 |
-
|
|
|
|
|
|
|
|
|
|
| 321 |
save_msg = gr.Markdown("")
|
| 322 |
|
| 323 |
run_btn.click(analyse, inputs=[pdf_input], outputs=[out1, out2, out3, out4])
|
| 324 |
-
save_btn.click(save_analysis, inputs=[out1, out2, out3, out4], outputs=[save_msg])
|
| 325 |
|
| 326 |
gr.HTML("""
|
| 327 |
<div class="foot">
|
|
|
|
| 4 |
import os
|
| 5 |
import time
|
| 6 |
import subprocess
|
| 7 |
+
import tempfile
|
| 8 |
from pathlib import Path
|
| 9 |
from huggingface_hub import InferenceClient
|
| 10 |
|
| 11 |
subprocess.run(["pip", "install", "pypdf", "-q"], capture_output=True)
|
| 12 |
from pypdf import PdfReader
|
| 13 |
|
|
|
|
|
|
|
| 14 |
MODEL = "meta-llama/Llama-3.3-70B-Instruct"
|
| 15 |
|
| 16 |
def get_client():
|
|
|
|
| 113 |
|
| 114 |
def save_analysis(r1, r2, r3, r4):
|
| 115 |
if not r1:
|
| 116 |
+
return None, "⚠️ Nothing to save — run an analysis first."
|
| 117 |
ts = time.strftime("%Y-%m-%d %H:%M")
|
|
|
|
| 118 |
content = (
|
| 119 |
f"METABOLIC PHOENIX FRAMEWORK — FULL ANALYSIS\n"
|
| 120 |
f"Generated: {ts}\n"
|
|
|
|
| 124 |
f"{'='*60}\n\nCYCLE 3 — OUROBOROS LOOPS\n\n{r3}\n\n"
|
| 125 |
f"{'='*60}\n\nCYCLE 4 — FULL CASE OUTPUT\n\n{r4}"
|
| 126 |
)
|
| 127 |
+
tmp = tempfile.NamedTemporaryFile(
|
| 128 |
+
delete=False,
|
| 129 |
+
suffix=".txt",
|
| 130 |
+
prefix=f"MPF_Analysis_{time.strftime('%Y%m%d_%H%M')}_",
|
| 131 |
+
mode="w",
|
| 132 |
+
encoding="utf-8"
|
| 133 |
+
)
|
| 134 |
+
tmp.write(content)
|
| 135 |
+
tmp.close()
|
| 136 |
+
return tmp.name, "✅ Ready to download."
|
| 137 |
|
| 138 |
CSS = """
|
| 139 |
@import url('https://fonts.googleapis.com/css2?family=Syne:wght@400;700;800&family=DM+Mono:wght@400;500&display=swap');
|
|
|
|
| 156 |
font-family: 'Syne', sans-serif !important;
|
| 157 |
color: var(--text) !important;
|
| 158 |
}
|
|
|
|
| 159 |
.hdr {
|
| 160 |
text-align: center;
|
| 161 |
padding: 2.4rem 1rem 1.6rem;
|
|
|
|
| 165 |
radial-gradient(ellipse at 70% 50%, rgba(0,207,255,0.08) 0%, transparent 60%);
|
| 166 |
}
|
| 167 |
.hdr h1 {
|
| 168 |
+
font-size: 2.2rem; font-weight: 800; letter-spacing: -0.04em;
|
|
|
|
|
|
|
| 169 |
background: linear-gradient(135deg, var(--accent) 0%, var(--accent2) 100%);
|
| 170 |
+
-webkit-background-clip: text; -webkit-text-fill-color: transparent; margin: 0 0 0.3rem;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
}
|
| 172 |
+
.hdr .sub { color: var(--muted); font-family:'DM Mono',monospace; font-size:.75rem; letter-spacing:.06em; }
|
| 173 |
+
.hdr .own { color: var(--accent2); font-family:'DM Mono',monospace; font-size:.68rem; margin-top:.3rem; letter-spacing:.1em; text-transform:uppercase; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 174 |
input[type=text], textarea {
|
| 175 |
+
background: var(--surface) !important; border: 1px solid var(--border) !important;
|
| 176 |
+
border-radius: var(--r) !important; color: var(--text) !important;
|
| 177 |
+
font-family: 'DM Mono', monospace !important; font-size: .86rem !important;
|
| 178 |
+
padding: .6rem .85rem !important; transition: border-color .18s !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 179 |
}
|
| 180 |
input[type=text]:focus, textarea:focus {
|
| 181 |
+
border-color: var(--accent) !important; outline: none !important;
|
|
|
|
| 182 |
box-shadow: 0 0 0 3px rgba(0,207,255,.12) !important;
|
| 183 |
}
|
|
|
|
| 184 |
label > span:first-child {
|
| 185 |
+
color: var(--muted) !important; font-family: 'DM Mono', monospace !important;
|
| 186 |
+
font-size: .7rem !important; letter-spacing: .08em !important; text-transform: uppercase !important;
|
|
|
|
|
|
|
|
|
|
| 187 |
}
|
|
|
|
| 188 |
button.primary {
|
| 189 |
background: linear-gradient(135deg, var(--accent3), var(--accent)) !important;
|
| 190 |
+
color: #030712 !important; border: none !important; border-radius: var(--r) !important;
|
| 191 |
+
font-family: 'Syne', sans-serif !important; font-weight: 800 !important;
|
| 192 |
+
font-size: .92rem !important; padding: .75rem 2.8rem !important;
|
| 193 |
+
cursor: pointer !important; transition: opacity .15s, transform .15s !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 194 |
}
|
| 195 |
+
button.primary:hover { opacity: .88 !important; transform: translateY(-1px) !important; }
|
|
|
|
|
|
|
|
|
|
|
|
|
| 196 |
button.secondary {
|
| 197 |
+
background: var(--surface2) !important; color: var(--accent2) !important;
|
| 198 |
+
border: 1px solid var(--accent3) !important; border-radius: var(--r) !important;
|
| 199 |
+
font-family: 'Syne', sans-serif !important; font-weight: 700 !important;
|
| 200 |
+
font-size: .8rem !important; padding: .5rem 1.2rem !important; cursor: pointer !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 201 |
}
|
| 202 |
+
button.secondary:hover { background: var(--accent3) !important; color: #030712 !important; }
|
|
|
|
|
|
|
|
|
|
|
|
|
| 203 |
.out textarea {
|
| 204 |
+
background: #020510 !important; border: 1px solid var(--border) !important;
|
|
|
|
| 205 |
border-left: 3px solid var(--accent) !important;
|
| 206 |
border-radius: 0 var(--r) var(--r) 0 !important;
|
| 207 |
+
font-family: 'DM Mono', monospace !important; font-size: .84rem !important;
|
| 208 |
+
line-height: 1.7 !important; color: var(--text) !important;
|
|
|
|
|
|
|
| 209 |
}
|
|
|
|
| 210 |
.gradio-accordion {
|
| 211 |
+
background: var(--surface2) !important; border: 1px solid var(--accent2) !important;
|
| 212 |
+
border-radius: var(--r) !important; margin-bottom: .6rem !important;
|
|
|
|
|
|
|
| 213 |
}
|
|
|
|
| 214 |
.gradio-accordion .label-wrap span {
|
| 215 |
+
color: var(--accent2) !important; font-family: 'Syne', sans-serif !important;
|
| 216 |
+
font-weight: 700 !important; font-size: .85rem !important; letter-spacing: .04em !important;
|
|
|
|
|
|
|
|
|
|
| 217 |
}
|
| 218 |
+
.gradio-accordion svg { color: var(--accent2) !important; stroke: var(--accent2) !important; }
|
| 219 |
+
.readback {
|
| 220 |
+
background: var(--surface2);
|
| 221 |
+
border: 1px solid var(--accent3);
|
| 222 |
+
border-radius: var(--r);
|
| 223 |
+
padding: 1rem;
|
| 224 |
+
margin: .8rem 0;
|
| 225 |
}
|
| 226 |
+
.readback p {
|
|
|
|
|
|
|
|
|
|
| 227 |
color: var(--muted);
|
| 228 |
font-family: 'DM Mono', monospace;
|
| 229 |
+
font-size: .75rem;
|
| 230 |
+
margin: 0 0 .6rem;
|
|
|
|
| 231 |
letter-spacing: .05em;
|
| 232 |
+
text-transform: uppercase;
|
| 233 |
+
}
|
| 234 |
+
.foot {
|
| 235 |
+
text-align: center; padding: 1.5rem; color: var(--muted);
|
| 236 |
+
font-family: 'DM Mono', monospace; font-size: .68rem;
|
| 237 |
+
border-top: 1px solid var(--border); margin-top: 2rem; letter-spacing: .05em;
|
| 238 |
+
}
|
| 239 |
+
"""
|
| 240 |
+
|
| 241 |
+
READBACK_JS = """
|
| 242 |
+
<div class="readback">
|
| 243 |
+
<p>🔊 Read Back</p>
|
| 244 |
+
<div style="display:flex;gap:.6rem;flex-wrap:wrap">
|
| 245 |
+
<button onclick="readCycle(1)" style="background:#0f1629;color:#FFE500;border:1px solid #0066FF;border-radius:8px;padding:.4rem .9rem;font-family:Syne,sans-serif;font-weight:700;font-size:.78rem;cursor:pointer">▶ Cycle 1</button>
|
| 246 |
+
<button onclick="readCycle(2)" style="background:#0f1629;color:#FFE500;border:1px solid #0066FF;border-radius:8px;padding:.4rem .9rem;font-family:Syne,sans-serif;font-weight:700;font-size:.78rem;cursor:pointer">▶ Cycle 2</button>
|
| 247 |
+
<button onclick="readCycle(3)" style="background:#0f1629;color:#FFE500;border:1px solid #0066FF;border-radius:8px;padding:.4rem .9rem;font-family:Syne,sans-serif;font-weight:700;font-size:.78rem;cursor:pointer">▶ Cycle 3</button>
|
| 248 |
+
<button onclick="readCycle(4)" style="background:#0f1629;color:#FFE500;border:1px solid #0066FF;border-radius:8px;padding:.4rem .9rem;font-family:Syne,sans-serif;font-weight:700;font-size:.78rem;cursor:pointer">▶ Cycle 4</button>
|
| 249 |
+
<button onclick="readAll()" style="background:linear-gradient(135deg,#0066FF,#00CFFF);color:#030712;border:none;border-radius:8px;padding:.4rem .9rem;font-family:Syne,sans-serif;font-weight:800;font-size:.78rem;cursor:pointer">▶ Read All</button>
|
| 250 |
+
<button onclick="stopReading()" style="background:#0f1629;color:#ff4444;border:1px solid #ff4444;border-radius:8px;padding:.4rem .9rem;font-family:Syne,sans-serif;font-weight:700;font-size:.78rem;cursor:pointer">■ Stop</button>
|
| 251 |
+
</div>
|
| 252 |
+
</div>
|
| 253 |
+
|
| 254 |
+
<script>
|
| 255 |
+
function getTextFromCycle(n) {
|
| 256 |
+
const textareas = document.querySelectorAll('textarea');
|
| 257 |
+
const cycleTextareas = Array.from(textareas).filter(t => t.value && t.value.trim().length > 0);
|
| 258 |
+
if (cycleTextareas[n-1]) return cycleTextareas[n-1].value;
|
| 259 |
+
return '';
|
| 260 |
+
}
|
| 261 |
+
|
| 262 |
+
function speak(text) {
|
| 263 |
+
if (!text) { alert('No content to read — run the analysis first.'); return; }
|
| 264 |
+
window.speechSynthesis.cancel();
|
| 265 |
+
const chunks = text.match(/.{1,200}/g) || [];
|
| 266 |
+
let i = 0;
|
| 267 |
+
function nextChunk() {
|
| 268 |
+
if (i >= chunks.length) return;
|
| 269 |
+
const u = new SpeechSynthesisUtterance(chunks[i]);
|
| 270 |
+
u.rate = 0.95;
|
| 271 |
+
u.pitch = 1;
|
| 272 |
+
u.lang = 'en-GB';
|
| 273 |
+
u.onend = () => { i++; nextChunk(); };
|
| 274 |
+
window.speechSynthesis.speak(u);
|
| 275 |
+
}
|
| 276 |
+
nextChunk();
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
function readCycle(n) {
|
| 280 |
+
speak(getTextFromCycle(n));
|
| 281 |
}
|
| 282 |
+
|
| 283 |
+
function readAll() {
|
| 284 |
+
const textareas = document.querySelectorAll('textarea');
|
| 285 |
+
const all = Array.from(textareas)
|
| 286 |
+
.map(t => t.value)
|
| 287 |
+
.filter(v => v && v.trim().length > 0)
|
| 288 |
+
.join('\n\n --- \n\n');
|
| 289 |
+
speak(all);
|
| 290 |
+
}
|
| 291 |
+
|
| 292 |
+
function stopReading() {
|
| 293 |
+
window.speechSynthesis.cancel();
|
| 294 |
+
}
|
| 295 |
+
</script>
|
| 296 |
"""
|
| 297 |
|
| 298 |
with gr.Blocks(css=CSS, title="Metabolic Phoenix Framework") as demo:
|
|
|
|
| 320 |
with gr.Accordion("Cycle 4 — Full Case Output", open=False):
|
| 321 |
out4 = gr.Textbox(label="", lines=12, elem_classes=["out"])
|
| 322 |
|
| 323 |
+
gr.HTML(READBACK_JS)
|
| 324 |
+
|
| 325 |
+
save_btn = gr.Button("💾 Save & Download Analysis", variant="secondary")
|
| 326 |
+
dl_file = gr.File(label="Download your analysis", visible=False)
|
| 327 |
save_msg = gr.Markdown("")
|
| 328 |
|
| 329 |
run_btn.click(analyse, inputs=[pdf_input], outputs=[out1, out2, out3, out4])
|
| 330 |
+
save_btn.click(save_analysis, inputs=[out1, out2, out3, out4], outputs=[dl_file, save_msg])
|
| 331 |
|
| 332 |
gr.HTML("""
|
| 333 |
<div class="foot">
|