Basementup commited on
Commit
d9af8ca
·
verified ·
1 Parent(s): 81a8edf

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +511 -35
app.py CHANGED
@@ -1,38 +1,514 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Metabolic Phoenix Framework — Layout Preview</title>
7
- <link href="https://fonts.googleapis.com/css2?family=Syne:wght@400;700;800&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet">
8
- <style>
9
- :root {
10
- --bg: #080a0f;
11
- --surface: #0f1118;
12
- --surface2: #151822;
13
- --border: #1e2235;
14
- --accent: #FF6B2B;
15
- --accent2: #FFB347;
16
- --accent3: #7DF9AA;
17
- --text: #E8EAF2;
18
- --muted: #55607A;
19
- --r: 8px;
20
- }
21
- * { box-sizing: border-box; margin: 0; padding: 0; }
22
- body {
23
- background: var(--bg);
24
- font-family: 'Syne', sans-serif;
25
- color: var(--text);
26
- min-height: 100vh;
27
- }
28
-
29
- /* ── Header ── */
30
- .hdr {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  text-align: center;
32
  padding: 2.4rem 1rem 1.6rem;
33
  border-bottom: 1px solid var(--border);
34
- background: radial-gradient(ellipse at 50% 0%, rgba(255,107,43,0.08) 0%, transparent 65%);
35
- }
36
- .hdr h1 {
37
- font-size: 2.2rem;
38
- font-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import json
3
+ import os
4
+ import time
5
+ from pathlib import Path
6
+ from huggingface_hub import InferenceClient
7
+
8
+ try:
9
+ from pypdf import PdfReader
10
+ except ImportError:
11
+ PdfReader = None
12
+
13
+ SAVE_DIR = Path("/tmp/saved_docs")
14
+ SAVE_DIR.mkdir(exist_ok=True)
15
+
16
+ MODEL = "meta-llama/Llama-3.3-70B-Instruct"
17
+
18
+ # ── Client ────────────────────────────────────────────────────────────────────
19
+
20
+ def get_client():
21
+ token = os.environ.get("HF_TOKEN", "")
22
+ return InferenceClient(model=MODEL, token=token if token else None)
23
+
24
+ # ── PDF ───────────────────────────────────────────────────────────────────────
25
+
26
+ def extract_pdf_text(path):
27
+ if not path:
28
+ return ""
29
+ if PdfReader is None:
30
+ return "[pypdf not installed]"
31
+ reader = PdfReader(path)
32
+ pages = []
33
+ for i, page in enumerate(reader.pages):
34
+ text = page.extract_text() or ""
35
+ if text.strip():
36
+ pages.append(f"--- Page {i+1} ---\n{text.strip()}")
37
+ full = "\n\n".join(pages)
38
+ return full[:12000] + "\n\n[truncated...]" if len(full) > 12000 else full
39
+
40
+ def inject_pdf(prompt, pdf_path):
41
+ if not pdf_path:
42
+ return prompt
43
+ text = extract_pdf_text(pdf_path)
44
+ if not text.strip():
45
+ return prompt
46
+ return f"Use the following document as your primary reference:\n\n{text}\n\n---\n\n{prompt}"
47
+
48
+ # ── Llama ─────────────────────────────────────────────────────────────────────
49
+
50
+ def call_llama(prompt, pdf_path=None, max_tokens=1200):
51
+ full_prompt = inject_pdf(prompt, pdf_path)
52
+ client = get_client()
53
+ response = client.chat_completion(
54
+ messages=[{"role": "user", "content": full_prompt}],
55
+ max_tokens=max_tokens,
56
+ temperature=0.7,
57
+ )
58
+ return response.choices[0].message.content
59
+
60
+ # ── Library ───────────────────────────────────────────────────────────────────
61
+
62
+ def load_library():
63
+ p = SAVE_DIR / "index.json"
64
+ return json.loads(p.read_text()) if p.exists() else []
65
+
66
+ def save_to_library(title, organ, content):
67
+ if not title.strip():
68
+ title = f"{organ} — {time.strftime('%H:%M:%S')}"
69
+ library = load_library()
70
+ entry = {
71
+ "id": str(int(time.time() * 1000)),
72
+ "title": title.strip(),
73
+ "organ": organ,
74
+ "content": content,
75
+ "saved_at": time.strftime("%Y-%m-%d %H:%M"),
76
+ }
77
+ library.insert(0, entry)
78
+ (SAVE_DIR / "index.json").write_text(json.dumps(library, indent=2))
79
+ (SAVE_DIR / f"{entry['id']}.txt").write_text(
80
+ f"Title: {entry['title']}\nOrgan: {organ}\nSaved: {entry['saved_at']}\n\n{content}"
81
+ )
82
+ return library
83
+
84
+ def delete_from_library(doc_id):
85
+ library = [e for e in load_library() if e["id"] != doc_id]
86
+ (SAVE_DIR / "index.json").write_text(json.dumps(library, indent=2))
87
+ fp = SAVE_DIR / f"{doc_id}.txt"
88
+ if fp.exists():
89
+ fp.unlink()
90
+ return library
91
+
92
+ def lib_choices(library):
93
+ return [f"[{e['organ']}] {e['title']} ({e['saved_at']})" for e in library]
94
+
95
+ def choice_to_entry(library, choice):
96
+ choices = lib_choices(library)
97
+ try:
98
+ return library[choices.index(choice)]
99
+ except (ValueError, IndexError):
100
+ return None
101
+
102
+ # ── Organ runners ─────────────────────────────────────────────────────────────
103
+
104
+ def run_introbot(doc_type, focus, extraction_mode, pdf_path):
105
+ if not focus.strip():
106
+ return "⚠️ Please describe what to extract or analyse."
107
+ mode_instructions = {
108
+ "Full Fact Ledger": "Extract all atomic facts. For each: source, date, assertion type (admission/denial/error/gap), statutory relevance, and confidence score.",
109
+ "Admissions & Denials": "Extract all explicit admissions and explicit denials. Flag implicit admissions where silence exists where a duty to respond exists.",
110
+ "Contradictions": "Identify internal contradictions and contradictions against known facts or prior statements. Rate each by severity.",
111
+ "Gap Analysis": "Identify what is conspicuously absent. Map each gap to its legal or regulatory implication.",
112
+ }
113
+ instructions = mode_instructions.get(extraction_mode, mode_instructions["Full Fact Ledger"])
114
+ prompt = (
115
+ f"You are Introbot — the Sensory Cortex of the Metabolic Phoenix Framework (Injectiv8).\n"
116
+ f"Document type: {doc_type}\n"
117
+ f"Focus area: {focus}\n"
118
+ f"Extraction mode: {extraction_mode}\n\n"
119
+ f"{instructions}\n\n"
120
+ "Present output as a structured fact ledger with clear headings. "
121
+ "Every fact must have: source reference, date (if available), assertion type, and legal/strategic implication."
122
+ )
123
+ return call_llama(prompt, pdf_path, max_tokens=1600)
124
+
125
+ def run_cpf(goal, skill_focus, bias_check, pdf_path):
126
+ if not goal.strip():
127
+ return "⚠️ Please describe the goal or challenge."
128
+ skills = skill_focus if skill_focus.strip() else "Problem Solving, Planning, Adapting, Leadership"
129
+ bias_instruction = (
130
+ "\n\nBefore finalising: run a bias filter. Identify any assumptions, framing effects, "
131
+ "or confirmation biases in your reasoning and correct them."
132
+ if bias_check else ""
133
+ )
134
+ prompt = (
135
+ f"You are the CPF Cognitive Cortex — the reasoning organ of the Metabolic Phoenix Framework.\n"
136
+ f"Active skills: {skills}\n"
137
+ f"Goal / challenge: {goal}\n\n"
138
+ "Apply chain-of-thought reasoning:\n"
139
+ "1. LISTEN — what does the evidence actually say?\n"
140
+ "2. ANALYSE — extract causal patterns and hypotheses\n"
141
+ "3. PLAN — propose a structured response strategy\n"
142
+ "4. ADAPT — identify where the plan must flex given constraints\n"
143
+ "5. SYNTHESISE — produce a clear, actionable output"
144
+ f"{bias_instruction}"
145
+ )
146
+ return call_llama(prompt, pdf_path, max_tokens=1400)
147
+
148
+ def run_rhb(institution, statute_codes, compliance_question, pdf_path):
149
+ if not compliance_question.strip():
150
+ return "⚠️ Please enter a compliance question or scenario."
151
+ statutes = statute_codes if statute_codes.strip() else "CRA 2015, EqA 2010, FCA PRIN, BCOBS"
152
+ prompt = (
153
+ f"You are RHB 2.0 — the Compliance Spine of the Metabolic Phoenix Framework.\n"
154
+ f"Institution under analysis: {institution if institution.strip() else 'Not specified'}\n"
155
+ f"Statutory framework: {statutes}\n"
156
+ f"Compliance question: {compliance_question}\n\n"
157
+ "Produce a deterministic compliance matrix:\n"
158
+ "1. DUTY — state the precise statutory duty and when it activates\n"
159
+ "2. CONDUCT — what did the institution actually do or fail to do?\n"
160
+ "3. VERDICT — COMPLIANT / NON-COMPLIANT / UNCERTAIN (with confidence score)\n"
161
+ "4. EVIDENCE REQUIRED — what would the institution need to produce to rebut this?\n"
162
+ "5. REMEDY — what is the legally appropriate remedy?\n\n"
163
+ "Be forensic. Cite specific statute sections."
164
+ )
165
+ return call_llama(prompt, pdf_path, max_tokens=1600)
166
+
167
+ def run_phoenix_badger(scenario, loop_type, escalation_targets, pdf_path):
168
+ if not scenario.strip():
169
+ return "⚠️ Please describe the scenario."
170
+ targets = escalation_targets if escalation_targets.strip() else "High Court, FCA, ICO, Parliament"
171
+ loop_desc = {
172
+ "Full Ouroboros (all four rings)": "Run all four counter-rotating rings: A (forward scan) → B (backward sweep) → C (typology mutation) → D (drift correction). Full metabolic closure.",
173
+ "Ring A — Forward Scan (anomaly detection)": "Run a forward scan. Detect anomalies, pattern breaks, and escalation triggers.",
174
+ "Ring B — Backward Sweep (re-evaluation)": "Re-evaluate past decisions with current typologies and evidence. What would now be decided differently?",
175
+ "Ring C — Typology Mutation (adaptive evolution)": "Propose updated regulatory typologies and rule adaptations. What new patterns emerge?",
176
+ "Ring D — Rollback & Drift Correction": "Stress-test proposed adaptations. Which changes would degrade compliance? Block and correct them.",
177
+ }
178
+ instructions = loop_desc.get(loop_type, loop_desc["Full Ouroboros (all four rings)"])
179
+ prompt = (
180
+ f"You are Phoenix Badger — the Metabolic Loop System of the Metabolic Phoenix Framework.\n"
181
+ f"Loop mode: {loop_type}\n"
182
+ f"Escalation targets: {targets}\n"
183
+ f"Scenario: {scenario}\n\n"
184
+ f"{instructions}\n\n"
185
+ "Output structure:\n"
186
+ "LOOP OUTPUT — findings from the active ring(s)\n"
187
+ "TYPOLOGY STATE — current compliance typology after loop\n"
188
+ "ESCALATION TRIGGERS — which targets should receive escalation and why\n"
189
+ "SELF-HARDENING ACTIONS — what the system must do after this cycle\n"
190
+ "DRIFT CORRECTIONS — any reasoning or rule drift detected and corrected"
191
+ )
192
+ return call_llama(prompt, pdf_path, max_tokens=1600)
193
+
194
+ def run_layoutbot(output_dest, case_name, key_findings, pdf_path):
195
+ if not key_findings.strip():
196
+ return "⚠️ Please enter the key findings to format."
197
+ dest_instructions = {
198
+ "High Court (CPR-compliant Particulars of Claim)": "Format as CPR-compliant Particulars of Claim. Structure: Background → Jurisdiction & Facts → Statutory Duties & Breaches → Damages → Remedy Sought → Statement of Truth.",
199
+ "FCA Regulatory Complaint": "Format as FCA regulatory breach notification. Structure: Executive Summary → Systemic Failure Indicators → Consumer Protection Impact → Timeline with PRIN/BCOBS breach tags → Remedy Requested.",
200
+ "ICO Data Protection Notice": "Format as ICO data protection audit notice. Structure: Data Subject Info → Data Controller Details → Breach Analysis → GDPR/DPA 2018 legal basis → Enforcement Recommendation.",
201
+ "Parliamentary Evidence Submission": "Format as written evidence for a Select Committee. Structure: Case Summary → Systemic Failure Analysis → Legislative Gap Identification → Policy Recommendations.",
202
+ "Public Interest Disclosure": "Format as public interest disclosure. Structure: What Happened (plain English) → Why It Matters → What Should Change. Tone: accessible and compelling.",
203
+ "Media Briefing Kit": "Format as a press briefing kit. Structure: Headline Summary → Core Facts (5 bullets) → Regulatory Implications → Key Quotes → Evidence Pack summary.",
204
+ }
205
+ instructions = dest_instructions.get(output_dest, dest_instructions["High Court (CPR-compliant Particulars of Claim)"])
206
+ prompt = (
207
+ f"You are Layoutbot — the multi-format export organ of the Metabolic Phoenix Framework (Injectiv8).\n"
208
+ f"Case / matter: {case_name if case_name.strip() else 'Not specified'}\n"
209
+ f"Destination: {output_dest}\n\n"
210
+ f"Key findings:\n{key_findings}\n\n"
211
+ f"{instructions}\n\n"
212
+ "Watermark the output footer: Ms. Nala | Injectiv8 Framework | Dwayne Anthony Brian Galloway"
213
+ )
214
+ return call_llama(prompt, pdf_path, max_tokens=1800)
215
+
216
+ # ── Save handlers ─────────────────────────────────────────────────────────────
217
+
218
+ def save_intro(title, content, lib):
219
+ if not content or not content.strip(): return lib, "⚠️ Nothing to save."
220
+ return save_to_library(title, "Introbot", content), "✅ Saved."
221
+
222
+ def save_cpf(title, content, lib):
223
+ if not content or not content.strip(): return lib, "⚠️ Nothing to save."
224
+ return save_to_library(title, "CPF Cognitive Cortex", content), "✅ Saved."
225
+
226
+ def save_rhb(title, content, lib):
227
+ if not content or not content.strip(): return lib, "⚠️ Nothing to save."
228
+ return save_to_library(title, "RHB 2.0 Compliance Spine", content), "✅ Saved."
229
+
230
+ def save_pb(title, content, lib):
231
+ if not content or not content.strip(): return lib, "⚠️ Nothing to save."
232
+ return save_to_library(title, "Phoenix Badger", content), "✅ Saved."
233
+
234
+ def save_layout(title, content, lib):
235
+ if not content or not content.strip(): return lib, "⚠️ Nothing to save."
236
+ return save_to_library(title, "Layoutbot Export", content), "✅ Saved."
237
+
238
+ # ── Library handlers ──────────────────────────────────────────────────────────
239
+
240
+ def lib_refresh(lib):
241
+ return gr.update(choices=lib_choices(lib), value=None), ""
242
+
243
+ def lib_view(sel, lib):
244
+ if not sel: return ""
245
+ e = choice_to_entry(lib, sel)
246
+ if not e: return "Not found."
247
+ return f"TITLE: {e['title']}\nORGAN: {e['organ']}\nSAVED: {e['saved_at']}\n\n{'='*60}\n\n{e['content']}"
248
+
249
+ def lib_download(sel, lib):
250
+ if not sel: return gr.update(visible=False), "⚠️ Select a document first."
251
+ e = choice_to_entry(lib, sel)
252
+ if not e: return gr.update(visible=False), "Not found."
253
+ fp = SAVE_DIR / f"{e['id']}.txt"
254
+ return (gr.update(value=str(fp), visible=True), "✅ Ready.") if fp.exists() else (gr.update(visible=False), "File missing.")
255
+
256
+ def lib_delete(sel, lib):
257
+ if not sel: return lib, gr.update(choices=lib_choices(lib), value=None), "⚠️ Select a document."
258
+ e = choice_to_entry(lib, sel)
259
+ if not e: return lib, gr.update(choices=lib_choices(lib), value=None), "Not found."
260
+ lib = delete_from_library(e["id"])
261
+ return lib, gr.update(choices=lib_choices(lib), value=None), "🗑️ Deleted."
262
+
263
+ def lib_sync(lib):
264
+ return gr.update(choices=lib_choices(lib))
265
+
266
+ # ── CSS ───────────────────────��───────────────────────────────────────────────
267
+
268
+ CSS = """
269
+ @import url('https://fonts.googleapis.com/css2?family=Syne:wght@400;700;800&family=DM+Mono:wght@400;500&display=swap');
270
+
271
+ :root {
272
+ --bg:#080a0f; --surface:#0f1118; --surface2:#151822;
273
+ --border:#1e2235; --accent:#FF6B2B; --accent2:#FFB347;
274
+ --accent3:#7DF9AA; --text:#E8EAF2; --muted:#55607A; --r:8px;
275
+ }
276
+
277
+ body, .gradio-container {
278
+ background: var(--bg) !important;
279
+ font-family: 'Syne', sans-serif !important;
280
+ color: var(--text) !important;
281
+ }
282
+
283
+ .hdr {
284
  text-align: center;
285
  padding: 2.4rem 1rem 1.6rem;
286
  border-bottom: 1px solid var(--border);
287
+ background: radial-gradient(ellipse at 50% 0%, rgba(255,107,43,0.08), transparent 65%);
288
+ }
289
+ .hdr h1 {
290
+ font-size: 2.1rem; font-weight: 800; letter-spacing: -0.04em;
291
+ background: linear-gradient(135deg, var(--accent), var(--accent2));
292
+ -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin: 0 0 0.3rem;
293
+ }
294
+ .hdr .sub { color: var(--muted); font-family:'DM Mono',monospace; font-size:.78rem; letter-spacing:.06em; }
295
+ .hdr .own { color: var(--accent3); font-family:'DM Mono',monospace; font-size:.7rem; margin-top:.35rem; letter-spacing:.1em; text-transform:uppercase; }
296
+
297
+ .tab-nav button {
298
+ background: transparent !important; color: var(--muted) !important;
299
+ border: 1px solid transparent !important; border-radius: var(--r) !important;
300
+ font-family: 'Syne', sans-serif !important; font-weight: 700 !important;
301
+ font-size: 0.78rem !important; padding: 0.45rem 0.85rem !important; transition: all .18s !important;
302
+ }
303
+ .tab-nav button.selected { background: var(--surface2) !important; color: var(--accent) !important; border-color: var(--border) !important; }
304
+ .tab-nav button:hover { color: var(--text) !important; }
305
+
306
+ input[type=text], textarea {
307
+ background: var(--surface) !important; border: 1px solid var(--border) !important;
308
+ border-radius: var(--r) !important; color: var(--text) !important;
309
+ font-family: 'DM Mono', monospace !important; font-size: .86rem !important;
310
+ padding: .6rem .85rem !important; transition: border-color .18s !important;
311
+ }
312
+ input[type=text]:focus, textarea:focus {
313
+ border-color: var(--accent) !important; outline: none !important;
314
+ box-shadow: 0 0 0 3px rgba(255,107,43,.1) !important;
315
+ }
316
+
317
+ label > span:first-child {
318
+ color: var(--muted) !important; font-family: 'DM Mono', monospace !important;
319
+ font-weight: 500 !important; font-size: .7rem !important;
320
+ letter-spacing: .08em !important; text-transform: uppercase !important;
321
+ }
322
+
323
+ button.primary {
324
+ background: var(--accent) !important; color: #080a0f !important;
325
+ border: none !important; border-radius: var(--r) !important;
326
+ font-family: 'Syne', sans-serif !important; font-weight: 800 !important;
327
+ font-size: .86rem !important; padding: .65rem 1.8rem !important;
328
+ cursor: pointer !important; transition: opacity .15s, transform .15s !important;
329
+ }
330
+ button.primary:hover { opacity: .85 !important; transform: translateY(-1px) !important; }
331
+
332
+ button.secondary {
333
+ background: var(--surface2) !important; color: var(--accent2) !important;
334
+ border: 1px solid var(--border) !important; border-radius: var(--r) !important;
335
+ font-family: 'Syne', sans-serif !important; font-weight: 700 !important;
336
+ font-size: .8rem !important; padding: .5rem 1rem !important;
337
+ cursor: pointer !important; transition: border-color .15s !important;
338
+ }
339
+ button.secondary:hover { border-color: var(--accent2) !important; }
340
+
341
+ .out textarea {
342
+ background: #060709 !important; border: 1px solid var(--border) !important;
343
+ border-left: 3px solid var(--accent) !important;
344
+ border-radius: 0 var(--r) var(--r) 0 !important;
345
+ font-family: 'DM Mono', monospace !important; font-size: .84rem !important;
346
+ line-height: 1.7 !important; color: var(--text) !important;
347
+ }
348
+
349
+ .card {
350
+ background: var(--surface); border: 1px solid var(--border);
351
+ border-radius: var(--r); padding: .85rem 1rem; margin-bottom: 1rem;
352
+ }
353
+ .badge {
354
+ display: inline-block; font-family: 'DM Mono', monospace;
355
+ font-size: .68rem; letter-spacing: .1em; text-transform: uppercase;
356
+ padding: .2rem .6rem; border-radius: 4px;
357
+ background: rgba(255,107,43,.12); color: var(--accent); margin-bottom: .35rem;
358
+ }
359
+ .card p { color: var(--muted); font-size: .82rem; margin: 0; line-height: 1.55; }
360
+
361
+ .pnote {
362
+ display: inline-block; font-family: 'DM Mono', monospace;
363
+ font-size: .68rem; letter-spacing: .08em; text-transform: uppercase;
364
+ padding: .18rem .55rem; border-radius: 4px;
365
+ background: rgba(125,249,170,.08); color: var(--accent3); margin: .5rem 0 .3rem;
366
+ }
367
+
368
+ input[type=range] { accent-color: var(--accent) !important; }
369
+
370
+ .foot {
371
+ text-align: center; padding: 1.5rem; color: var(--muted);
372
+ font-family: 'DM Mono', monospace; font-size: .68rem;
373
+ border-top: 1px solid var(--border); margin-top: 2rem; letter-spacing: .05em;
374
+ }
375
+ """
376
+
377
+ # ── UI ────────────────────────────────────────────────────────────────────────
378
+
379
+ with gr.Blocks(css=CSS, title="The Metabolic Phoenix Framework — Injectiv8") as demo:
380
+
381
+ lib_state = gr.State(load_library())
382
+
383
+ gr.HTML("""
384
+ <div class="hdr">
385
+ <h1>🔥 The Metabolic Phoenix Framework</h1>
386
+ <p class="sub">Injectiv8 &nbsp;·&nbsp; Ms. Nala Forensic Evidence Processing System &nbsp;·&nbsp; Llama-3.3-70B</p>
387
+ <p class="own">Invented &amp; Owned by Dwayne Anthony Brian Galloway &nbsp;·&nbsp; 2026</p>
388
+ </div>
389
+ """)
390
+
391
+ with gr.Tabs():
392
+
393
+ # ── 01 Introbot ───────────────────────────────────────────────────────
394
+ with gr.Tab("01 · Introbot"):
395
+ gr.HTML('<div class="card"><div class="badge">Organ 1 — Sensory Cortex</div><p>Fact extraction, admission/denial detection, contradiction flagging, and gap analysis. Feeds pure immutable truth into the metabolic system.</p></div>')
396
+ with gr.Row():
397
+ i_doctype = gr.Textbox(label="Document Type", placeholder="e.g. Bank letter, FOS decision, Legal correspondence")
398
+ i_focus = gr.Textbox(label="Focus / Subject Matter", placeholder="e.g. Disability disclosure, Refund reversal, Account closure")
399
+ i_mode = gr.Dropdown(label="Extraction Mode", choices=["Full Fact Ledger","Admissions & Denials","Contradictions","Gap Analysis"], value="Full Fact Ledger")
400
+ gr.HTML('<div class="pnote">📄 upload document for analysis</div>')
401
+ i_pdf = gr.File(label="Upload PDF", file_types=[".pdf"], type="filepath")
402
+ i_btn = gr.Button("Extract Facts →", variant="primary")
403
+ i_out = gr.Textbox(label="Fact Ledger Output", lines=16, elem_classes=["out"])
404
+ with gr.Row():
405
+ i_title = gr.Textbox(label="Save as (title) — blank = auto", scale=4)
406
+ i_save = gr.Button("💾 Save", variant="secondary", scale=1)
407
+ i_msg = gr.Markdown("")
408
+ i_btn.click(run_introbot, inputs=[i_doctype, i_focus, i_mode, i_pdf], outputs=i_out)
409
+ i_save.click(save_intro, inputs=[i_title, i_out, lib_state], outputs=[lib_state, i_msg])
410
+
411
+ # ── 02 CPF ────────────────────────────────────────────────────────────
412
+ with gr.Tab("02 · CPF — Cognitive Cortex"):
413
+ gr.HTML('<div class="card"><div class="badge">Organ 2 — Cognitive Cortex</div><p>Eight-skill cognitive reasoning: pattern extraction, bias filtering, causal hypothesis generation, and strategic planning.</p></div>')
414
+ c_goal = gr.Textbox(label="Goal / Challenge", lines=2, placeholder="e.g. Build the strongest argument for EqA 2010 s.20 breach based on the timeline")
415
+ c_skills = gr.Textbox(label="Active CPF Skills (comma-separated — blank = all)", placeholder="e.g. Problem Solving, Planning, Leadership")
416
+ c_bias = gr.Checkbox(label="Run bias filter on output", value=True)
417
+ gr.HTML('<div class="pnote">📄 upload source document</div>')
418
+ c_pdf = gr.File(label="Upload PDF", file_types=[".pdf"], type="filepath")
419
+ c_btn = gr.Button("Reason →", variant="primary")
420
+ c_out = gr.Textbox(label="CPF Reasoning Output", lines=16, elem_classes=["out"])
421
+ with gr.Row():
422
+ c_title = gr.Textbox(label="Save as (title) — blank = auto", scale=4)
423
+ c_save = gr.Button("💾 Save", variant="secondary", scale=1)
424
+ c_msg = gr.Markdown("")
425
+ c_btn.click(run_cpf, inputs=[c_goal, c_skills, c_bias, c_pdf], outputs=c_out)
426
+ c_save.click(save_cpf, inputs=[c_title, c_out, lib_state], outputs=[lib_state, c_msg])
427
+
428
+ # ── 03 RHB ────────────────────────────────────────────────────────────
429
+ with gr.Tab("03 · RHB 2.0 — Compliance Spine"):
430
+ gr.HTML('<div class="card"><div class="badge">Organ 3 — Compliance Spine</div><p>Deterministic statutory duty mapping, burden-of-proof logic, and outcome-based compliance determination. Produces regulator-ready findings.</p></div>')
431
+ r_inst = gr.Textbox(label="Institution Under Analysis", placeholder="e.g. Halifax Bank of Scotland plc, Eversheds Sutherland, FOS")
432
+ r_stats = gr.Textbox(label="Statutory Framework (blank = defaults)", placeholder="e.g. CRA 2015 s.19-20, EqA 2010 s.13/s.20, FCA PRIN 6, BCOBS")
433
+ r_q = gr.Textbox(label="Compliance Question / Scenario", lines=3, placeholder="e.g. Did the institution comply with EqA 2010 s.20 after disability was disclosed on 19 June 2025?")
434
+ gr.HTML('<div class="pnote">📄 upload evidence document</div>')
435
+ r_pdf = gr.File(label="Upload PDF", file_types=[".pdf"], type="filepath")
436
+ r_btn = gr.Button("Evaluate Compliance →", variant="primary")
437
+ r_out = gr.Textbox(label="Compliance Matrix Output", lines=16, elem_classes=["out"])
438
+ with gr.Row():
439
+ r_title = gr.Textbox(label="Save as (title) — blank = auto", scale=4)
440
+ r_save = gr.Button("💾 Save", variant="secondary", scale=1)
441
+ r_msg = gr.Markdown("")
442
+ r_btn.click(run_rhb, inputs=[r_inst, r_stats, r_q, r_pdf], outputs=r_out)
443
+ r_save.click(save_rhb, inputs=[r_title, r_out, lib_state], outputs=[lib_state, r_msg])
444
+
445
+ # ── 04 Phoenix Badger ─────────────────────────────────────────────────
446
+ with gr.Tab("04 · Phoenix Badger"):
447
+ gr.HTML('<div class="card"><div class="badge">Organ 4 — Metabolic Loop System</div><p>1,440×4 counter-rotating Ouroboros feedback loops. Forward scan → backward sweep → typology mutation → drift correction. The organism evolves with every cycle.</p></div>')
448
+ p_scenario = gr.Textbox(label="Scenario to Process", lines=3, placeholder="e.g. Bank used identical evasion language to FOS. Account closed 11 days after disability disclosure.")
449
+ p_loop = gr.Dropdown(
450
+ label="Loop Mode",
451
+ choices=["Full Ouroboros (all four rings)","Ring A — Forward Scan","Ring B — Backward Sweep","Ring C — Typology Mutation","Ring D — Rollback & Drift Correction"],
452
+ value="Full Ouroboros (all four rings)"
453
+ )
454
+ p_targets = gr.Textbox(label="Escalation Targets (blank = defaults)", placeholder="e.g. High Court, FCA, ICO, Parliamentary Select Committee, Media")
455
+ gr.HTML('<div class="pnote">📄 upload context document</div>')
456
+ p_pdf = gr.File(label="Upload PDF", file_types=[".pdf"], type="filepath")
457
+ p_btn = gr.Button("Run Loop →", variant="primary")
458
+ p_out = gr.Textbox(label="Loop System Output", lines=18, elem_classes=["out"])
459
+ with gr.Row():
460
+ p_title = gr.Textbox(label="Save as (title) — blank = auto", scale=4)
461
+ p_save = gr.Button("💾 Save", variant="secondary", scale=1)
462
+ p_msg = gr.Markdown("")
463
+ p_btn.click(run_phoenix_badger, inputs=[p_scenario, p_loop, p_targets, p_pdf], outputs=p_out)
464
+ p_save.click(save_pb, inputs=[p_title, p_out, lib_state], outputs=[lib_state, p_msg])
465
+
466
+ # ── 05 Layoutbot ──────────────────────────────────────────────────────
467
+ with gr.Tab("05 · Layoutbot — Export"):
468
+ gr.HTML('<div class="card"><div class="badge">Export Organ — Layoutbot</div><p>Six destination formats: High Court, FCA, ICO, Parliament, Public Disclosure, Media Briefing. All outputs watermarked Ms. Nala | Injectiv8 | Dwayne Anthony Brian Galloway.</p></div>')
469
+ l_dest = gr.Dropdown(
470
+ label="Output Destination",
471
+ choices=["High Court (CPR-compliant Particulars of Claim)","FCA Regulatory Complaint","ICO Data Protection Notice","Parliamentary Evidence Submission","Public Interest Disclosure","Media Briefing Kit"],
472
+ value="High Court (CPR-compliant Particulars of Claim)"
473
+ )
474
+ l_case = gr.Textbox(label="Case / Matter Name", placeholder="e.g. Galloway v DBL-Max Limited & ORS")
475
+ l_findings = gr.Textbox(label="Key Findings to Format", lines=6, placeholder="Paste your Introbot / RHB 2.0 / Phoenix Badger output here, or describe the key facts and breaches")
476
+ gr.HTML('<div class="pnote">📄 optional supporting document</div>')
477
+ l_pdf = gr.File(label="Upload PDF", file_types=[".pdf"], type="filepath")
478
+ l_btn = gr.Button("Generate Document →", variant="primary")
479
+ l_out = gr.Textbox(label="Formatted Output", lines=20, elem_classes=["out"])
480
+ with gr.Row():
481
+ l_title = gr.Textbox(label="Save as (title) — blank = auto", scale=4)
482
+ l_save = gr.Button("💾 Save", variant="secondary", scale=1)
483
+ l_msg = gr.Markdown("")
484
+ l_btn.click(run_layoutbot, inputs=[l_dest, l_case, l_findings, l_pdf], outputs=l_out)
485
+ l_save.click(save_layout, inputs=[l_title, l_out, lib_state], outputs=[lib_state, l_msg])
486
+
487
+ # ── 06 Library ───────────────────────────────────────────────────────��
488
+ with gr.Tab("📚 Fact Ledger Library"):
489
+ gr.HTML('<div class="card"><div class="badge">Session Document Library</div><p>All outputs saved this session across all five organs. View, download as .txt, or delete.</p></div>')
490
+ lib_ref_btn = gr.Button("🔄 Refresh", variant="secondary")
491
+ lib_dd = gr.Dropdown(label="Saved Documents", choices=lib_choices(load_library()), value=None, interactive=True)
492
+ lib_viewer = gr.Textbox(label="Content", lines=20, elem_classes=["out"], interactive=False)
493
+ with gr.Row():
494
+ lib_dl_btn = gr.Button("⬇️ Download .txt", variant="secondary")
495
+ lib_del_btn = gr.Button("🗑️ Delete", variant="secondary")
496
+ lib_dl_file = gr.File(label="Your file", visible=False)
497
+ lib_msg = gr.Markdown("")
498
+
499
+ lib_ref_btn.click(lib_refresh, [lib_state], [lib_dd, lib_msg])
500
+ lib_dd.change(lib_view, [lib_dd, lib_state], lib_viewer)
501
+ lib_dl_btn.click(lib_download, [lib_dd, lib_state], [lib_dl_file, lib_msg])
502
+ lib_del_btn.click(lib_delete, [lib_dd, lib_state], [lib_state, lib_dd, lib_msg])
503
+ lib_state.change(lib_sync, [lib_state], lib_dd)
504
+
505
+ gr.HTML("""
506
+ <div class="foot">
507
+ THE METABOLIC PHOENIX FRAMEWORK &nbsp;·&nbsp; Injectiv8 &nbsp;·&nbsp; Ms. Nala
508
+ &nbsp;·&nbsp; © Dwayne Anthony Brian Galloway 2026 &nbsp;·&nbsp; All Rights Reserved
509
+ &nbsp;·&nbsp; Llama-3.3-70B via HF Inference API
510
+ </div>
511
+ """)
512
+
513
+ if __name__ == "__main__":
514
+ demo.launch()