Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,38 +1,514 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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)
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
font-size: 2.
|
| 38 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 · Ms. Nala Forensic Evidence Processing System · Llama-3.3-70B</p>
|
| 387 |
+
<p class="own">Invented & Owned by Dwayne Anthony Brian Galloway · 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 · Injectiv8 · Ms. Nala
|
| 508 |
+
· © Dwayne Anthony Brian Galloway 2026 · All Rights Reserved
|
| 509 |
+
· Llama-3.3-70B via HF Inference API
|
| 510 |
+
</div>
|
| 511 |
+
""")
|
| 512 |
+
|
| 513 |
+
if __name__ == "__main__":
|
| 514 |
+
demo.launch()
|