Basementup commited on
Commit
2ecd5e0
·
verified ·
1 Parent(s): a247341

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +118 -112
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
- library = []
130
- p = SAVE_DIR / "index.json"
131
- if p.exists():
132
- library = json.loads(p.read_text())
133
- entry = {"id": doc_id, "title": f"Analysis — {ts}", "content": content, "saved_at": ts}
134
- library.insert(0, entry)
135
- p.write_text(json.dumps(library, indent=2))
136
- (SAVE_DIR / f"{doc_id}.txt").write_text(content)
137
- return f"✅ Saved: Analysis — {ts}"
 
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 .own {
185
- color: var(--accent2);
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: 1px solid var(--border) !important;
196
- border-radius: var(--r) !important;
197
- color: var(--text) !important;
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-family: 'DM Mono', monospace !important;
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
- border: none !important;
221
- border-radius: var(--r) !important;
222
- font-family: 'Syne', sans-serif !important;
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
- color: var(--accent2) !important;
238
- border: 1px solid var(--accent3) !important;
239
- border-radius: var(--r) !important;
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
- font-size: .84rem !important;
259
- line-height: 1.7 !important;
260
- color: var(--text) !important;
261
  }
262
-
263
  .gradio-accordion {
264
- background: var(--surface2) !important;
265
- border: 1px solid var(--accent2) !important;
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-family: 'Syne', sans-serif !important;
273
- font-weight: 700 !important;
274
- font-size: .85rem !important;
275
- letter-spacing: .04em !important;
276
  }
277
-
278
- .gradio-accordion svg {
279
- color: var(--accent2) !important;
280
- stroke: var(--accent2) !important;
 
 
 
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: .68rem;
289
- border-top: 1px solid var(--border);
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
- save_btn = gr.Button("💾 Save Analysis", variant="secondary")
 
 
 
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">