st192011 commited on
Commit
37bcc3a
·
verified ·
1 Parent(s): c88a09a

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +308 -0
app.py ADDED
@@ -0,0 +1,308 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import torch
3
+ import json
4
+ import os
5
+ from transformers import AutoModelForCausalLM, AutoTokenizer
6
+ from peft import PeftModel
7
+ from huggingface_hub import InferenceClient
8
+
9
+ # ==============================================================================
10
+ # 1. CONFIGURATION
11
+ # ==============================================================================
12
+ # NOTE: You must set 'HF_TOKEN' in your Hugging Face Space Secrets!
13
+ HF_TOKEN = os.getenv("HF_TOKEN")
14
+
15
+ PROJECT_TITLE = "The Janus Interface: Semantic Decoupling Architecture"
16
+
17
+ # Models
18
+ # We use the official Microsoft repo for CPU compatibility
19
+ BASE_MODEL_ID = "microsoft/Phi-3.5-mini-instruct"
20
+ ADAPTER_ID = "st192011/janus-gold-lora"
21
+ CLOUD_MODEL_ID = "meta-llama/Meta-Llama-3-8B-Instruct"
22
+
23
+ # ==============================================================================
24
+ # 2. ENGINE INITIALIZATION (CPU Optimized)
25
+ # ==============================================================================
26
+ print("⏳ Initializing Neural Backbone (CPU Mode)...")
27
+
28
+ try:
29
+ # Load Tokenizer
30
+ tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL_ID)
31
+
32
+ # Load Base Model (bfloat16 saves RAM on Free Tier Spaces)
33
+ base_model = AutoModelForCausalLM.from_pretrained(
34
+ BASE_MODEL_ID,
35
+ torch_dtype=torch.bfloat16,
36
+ device_map="cpu",
37
+ trust_remote_code=True
38
+ )
39
+
40
+ # Load Adapter
41
+ print(f"⏳ Mounting Janus Adapter ({ADAPTER_ID})...")
42
+ model = PeftModel.from_pretrained(base_model, ADAPTER_ID)
43
+ model.eval() # Set to inference mode
44
+ print("✅ System Online.")
45
+
46
+ except Exception as e:
47
+ print(f"❌ Error loading model: {e}")
48
+ raise e
49
+
50
+ # Cloud Client
51
+ hf_client = InferenceClient(model=CLOUD_MODEL_ID, token=HF_TOKEN)
52
+
53
+ # ==============================================================================
54
+ # 3. KERNEL LOGIC
55
+ # ==============================================================================
56
+
57
+ def clean_output(text):
58
+ """Sanitizes output to prevent chain-reaction failures."""
59
+ # Remove special tokens
60
+ clean = text.replace("<|end|>", "").replace("<|endoftext|>", "")
61
+
62
+ # Remove conversational filler lines
63
+ if "Output:" in clean: clean = clean.split("Output:")[-1]
64
+
65
+ lines = clean.split('\n')
66
+ # Keep lines that look like protocol code or normal text, remove "Here is..."
67
+ valid_lines = [line for line in lines if "Note" not in line and "Here is" not in line]
68
+ return " ".join(valid_lines).strip()
69
+
70
+ def kernel_scout(raw_input):
71
+ """Mode A: Local Logic Extraction"""
72
+ try:
73
+ prompt = f"""<|system|>
74
+ SYSTEM_ROLE: Janus Extractor.
75
+ TASK: Refactor clinical notes into JanusScript Logic.
76
+ SYNTAX: Object.action(params) -> Result.
77
+ OBJECTS: Hx, Sx, Dx, Tx, Lab, Crs, Plan.
78
+ CONSTRAINTS: No PII. Use relative time (Day1, Day2).
79
+ <|end|>
80
+ <|user|>
81
+ RAW NOTE:
82
+ {raw_input}<|end|>
83
+ <|assistant|>"""
84
+
85
+ inputs = tokenizer(prompt, return_tensors="pt")
86
+
87
+ with torch.no_grad():
88
+ outputs = model.generate(
89
+ **inputs,
90
+ max_new_tokens=256,
91
+ temperature=0.1,
92
+ do_sample=True
93
+ )
94
+
95
+ text = tokenizer.batch_decode(outputs)[0]
96
+ raw_output = text.split("<|assistant|>")[-1]
97
+ return clean_output(raw_output)
98
+ except Exception as e: return f"Error: {str(e)}"
99
+
100
+ def kernel_cloud_expert(scenario_prompt):
101
+ """Mode B: Cloud Bridge"""
102
+ try:
103
+ sys_prompt = """You are a Clinical Logic Engine.
104
+ Task: Convert the scenario into 'JanusScript' code.
105
+ Syntax: Object.action(parameter);
106
+ Objects: Dx, Sx, Tx, Lab, Plan.
107
+ Rules: No PII. Use PascalCase.
108
+
109
+ Example:
110
+ Input: Pt has pneumonia. Given antibiotics.
111
+ Output: Dx(Pneumonia); Sx(Fever+Cough); Tx(Meds).action(Antibiotics); Plan(Discharge.Home);"""
112
+
113
+ messages = [
114
+ {"role": "system", "content": sys_prompt},
115
+ {"role": "user", "content": f"Input: {scenario_prompt}"}
116
+ ]
117
+
118
+ response = hf_client.chat_completion(messages, max_tokens=512, temperature=0.1)
119
+ return clean_output(response.choices[0].message.content)
120
+ except Exception as e: return f"API Error: {str(e)}"
121
+
122
+ def kernel_vault(protocol, secure_json):
123
+ """Shared Terminal: Reconstruction"""
124
+ try:
125
+ try: db_str = json.dumps(json.loads(secure_json), ensure_ascii=False)
126
+ except: return "❌ Error: Invalid JSON."
127
+
128
+ prompt = f"""<|system|>
129
+ SYSTEM_ROLE: Janus Constructor.
130
+ TASK: Interpret JanusScript and PrivateDB to write Discharge Summary.
131
+ TEMPLATE: Header -> Dates -> History -> Hospital Course -> Plan.
132
+ <|end|>
133
+ <|user|>
134
+ PROTOCOL:
135
+ {protocol}
136
+
137
+ PRIVATE_DB:
138
+ {db_str}<|end|>
139
+ <|assistant|>"""
140
+
141
+ inputs = tokenizer(prompt, return_tensors="pt")
142
+
143
+ with torch.no_grad():
144
+ outputs = model.generate(
145
+ **inputs,
146
+ max_new_tokens=1024,
147
+ temperature=0.1,
148
+ repetition_penalty=1.05,
149
+ do_sample=True
150
+ )
151
+
152
+ text = tokenizer.batch_decode(outputs)[0]
153
+ doc = text.split("<|assistant|>")[-1].replace("<|end|>", "").replace("<|endoftext|>", "").strip()
154
+ return doc
155
+ except Exception as e: return f"Error: {str(e)}"
156
+
157
+ # ==============================================================================
158
+ # 4. DEMO SAMPLES
159
+ # ==============================================================================
160
+
161
+ # Case 1: Appendicitis (Local)
162
+ sample_note = """Pt ID 8899-A.
163
+ History: 28yo male presented with RLQ pain & fever.
164
+ Workup: CT scan confirmed acute appy.
165
+ Course: Taken to OR for lap appendectomy. Uncomplicated. Tolerated diet next day.
166
+ Plan: Discharge home. Pain controlled on oral meds."""
167
+
168
+ sample_db = """{
169
+ "pt_name": "Elias Thorne",
170
+ "pt_mrn": "8899-A",
171
+ "pt_dob": "1995-03-12",
172
+ "pt_sex": "M",
173
+ "adm_date": "2025-02-10",
174
+ "dis_date": "2025-02-12",
175
+ "prov_attending": "Dr. Wu",
176
+ "prov_specialty": "General Surgery"
177
+ }"""
178
+
179
+ # Case 2: Sepsis (Cloud)
180
+ sample_scenario = """Patient admitted for Urosepsis.
181
+ Culture: E. coli resistant to Cipro.
182
+ Treatment: Started on Zosyn IV. Transferred to ICU for one day for hypotension.
183
+ Transition: Switched to oral Augmentin.
184
+ Outcome: Stable, Afebrile. Discharge to finish 14 day course."""
185
+
186
+ sample_db_cloud = """{
187
+ "pt_name": "Sarah Connor",
188
+ "pt_mrn": "SKY-NET",
189
+ "pt_dob": "1965-05-10",
190
+ "pt_sex": "F",
191
+ "adm_date": "2025-12-01",
192
+ "dis_date": "2025-12-05",
193
+ "prov_attending": "Dr. Silberman",
194
+ "prov_specialty": "Internal Medicine"
195
+ }"""
196
+
197
+ # ==============================================================================
198
+ # 5. TECHNICAL REPORT
199
+ # ==============================================================================
200
+ report_md = """
201
+ # 🏛️ The Janus Interface: Research & Technical Analysis
202
+ **Project Status:** Research Prototype v2.0 (Gold Standard)
203
+
204
+ ---
205
+
206
+ ### 1. Research Motivation: The Privacy-Utility Paradox
207
+ In regulated domains (Healthcare, Legal, Finance), Generative AI adoption is stalled by a fundamental conflict:
208
+ * **Utility:** Large Cloud Models (GPT-4, Claude) offer superior reasoning but require sending data off-premise.
209
+ * **Privacy:** Local Small Models (SLMs) ensure data sovereignty but often lack deep domain knowledge.
210
+ * **The Solution:** **Semantic Decoupling**. We propose separating the **"Logic"** of a case from the **"Identity"** of the subject.
211
+
212
+ ### 2. Architectural Design: The Twin-Protocol
213
+ The system utilizes a **Multi-Task Adapter** trained to switch between two distinct cognitive modes based on the System Prompt.
214
+
215
+ #### **Mode A: The Scout (Logic Extractor)**
216
+ * **Function:** Reads raw, messy clinical notes.
217
+ * **Constraint:** Trained via Loss Masking to extract *only* clinical entities (`Dx`, `Tx`, `Plan`) into a sanitized code string called **JanusScript**.
218
+ * **Security:** It treats names, dates, and locations as noise to be discarded.
219
+
220
+ #### **Mode B: The Cloud Bridge (Knowledge Injection)**
221
+ * **Function:** Allows an external Cloud LLM to reason about a generic, anonymized scenario.
222
+ * **Innovation:** The Cloud Model generates the **JanusScript** code. This code acts as a firewall—no PII ever leaves the local environment, but the *intelligence* of the cloud is captured in the script.
223
+
224
+ #### **The Vault (Reconstructor)**
225
+ * **Function:** A secure, offline engine that accepts the JanusScript and a Local SQL Database record.
226
+ * **Output:** It merges the abstract logic with the concrete identity to generate the final, human-readable document.
227
+
228
+ ---
229
+
230
+ ### 3. Data Engineering: The "Gold Standard" Pipeline
231
+ To achieve high fidelity without using private patient data, we developed a **Synthesized Data Pipeline**:
232
+
233
+ 1. **Synthesis:** We generated **306 high-quality clinical scenarios** using Large Language Models (LLMs).
234
+ 2. **Alignment:** Unlike previous iterations where headers were random, this dataset ensured strict mathematical alignment between the Identity Header (Age/Sex) and the Clinical Narrative.
235
+ 3. **Result:** This eliminated the "hallucination" issues seen in earlier tests where the model would confuse patient gender or age due to conflicting training signals.
236
+
237
+ ### 4. Training Methodology
238
+ * **Base Model:** Microsoft Phi-3.5-mini-instruct (3.8B Parameters).
239
+ * **Framework:** **Unsloth** (Optimized QLoRA).
240
+ * **Technique:** **DoRA (Weight-Decomposed Low-Rank Adaptation)**.
241
+ * *Why DoRA?* Standard LoRA struggles with strict syntax/coding tasks. DoRA updates both magnitude and direction vectors, allowing the model to learn the strict `JanusScript` grammar effectively.
242
+ * **Loss Masking:** We used `train_on_responses_only`. The model was **never** trained on the input text, only on the output. This prevents the model from memorizing patient PII from the training set.
243
+ * **Hyperparameters:** Rank 16, Alpha 16, Learning Rate 2e-4, **2 Epochs** (approx 78 steps used for final checkpoint).
244
+
245
+ ### 5. Results & Conclusion
246
+ * **Zero-Trust Validation:** The "Vault" successfully reconstructs documents using *only* the database for identity.
247
+ * **Semantic Expansion:** The model demonstrates the ability to take a concise code (`Dx(Pneumonia)`) and expand it into fluent medical narrative ("Patient presented with symptoms consistent with Pneumonia...").
248
+ """
249
+
250
+ # ==============================================================================
251
+ # 6. LAUNCHER
252
+ # ==============================================================================
253
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="emerald"), title=PROJECT_TITLE) as demo:
254
+ gr.Markdown(f"# 🏛️ {PROJECT_TITLE}")
255
+
256
+ with gr.Tabs():
257
+
258
+ # --- TAB 1 ---
259
+ with gr.TabItem("🛡️ Mode A: Local Air-Gap"):
260
+ with gr.Row():
261
+ with gr.Column(scale=1):
262
+ inp_a = gr.Textbox(label="Raw Sensitive Note", lines=12, value=sample_note)
263
+ btn_a = gr.Button("Execute Scout (Local) ➔", variant="primary")
264
+
265
+ with gr.Column(scale=1):
266
+ out_proto_a = gr.Textbox(label="JanusScript Protocol", lines=6, interactive=True)
267
+
268
+ gr.Markdown("---")
269
+
270
+ with gr.Row():
271
+ with gr.Column(scale=1):
272
+ inp_db_a = gr.Textbox(label="Secure Identity Record", lines=12, value=sample_db)
273
+ btn_final_a = gr.Button("Execute Vault (Local) ➔", variant="secondary")
274
+
275
+ with gr.Column(scale=1):
276
+ out_final_a = gr.Textbox(label="Output: Reconstructed Document", lines=25)
277
+
278
+ btn_a.click(kernel_scout, inputs=inp_a, outputs=out_proto_a)
279
+ btn_final_a.click(kernel_vault, inputs=[out_proto_a, inp_db_a], outputs=out_final_a)
280
+
281
+ # --- TAB 2 ---
282
+ with gr.TabItem("🧠 Mode B: Cloud Bridge"):
283
+ with gr.Row():
284
+ with gr.Column(scale=1):
285
+ inp_b = gr.Textbox(label="Clinical Scenario (Anonymized)", lines=12, value=sample_scenario)
286
+ btn_b = gr.Button("Execute Cloud API (Llama-3) ➔", variant="primary")
287
+
288
+ with gr.Column(scale=1):
289
+ out_proto_b = gr.Textbox(label="JanusScript Protocol", lines=6, interactive=True)
290
+
291
+ gr.Markdown("---")
292
+
293
+ with gr.Row():
294
+ with gr.Column(scale=1):
295
+ inp_db_b = gr.Textbox(label="Secure Identity Record", lines=12, value=sample_db_cloud)
296
+ btn_final_b = gr.Button("Execute Vault (Local) ➔", variant="secondary")
297
+
298
+ with gr.Column(scale=1):
299
+ out_final_b = gr.Textbox(label="Output: Reconstructed Document", lines=25)
300
+
301
+ btn_b.click(kernel_cloud_expert, inputs=inp_b, outputs=out_proto_b)
302
+ btn_final_b.click(kernel_vault, inputs=[out_proto_b, inp_db_b], outputs=out_final_b)
303
+
304
+ # --- TAB 3 ---
305
+ with gr.TabItem("📄 Technical Report"):
306
+ gr.Markdown(report_md)
307
+
308
+ demo.launch()