botbottingbot commited on
Commit
425725b
·
verified ·
1 Parent(s): c1cb680

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +184 -109
app.py CHANGED
@@ -1,59 +1,168 @@
1
  import json
 
 
2
  from functools import partial
3
  import gradio as gr
4
- from transformers import pipeline, AutoModelForCausalLM, AutoTokenizer
5
-
6
- # -------------------------------------------------------------
7
- # Load Modules
8
- # -------------------------------------------------------------
 
 
 
 
9
  with open("modules.json", "r", encoding="utf-8") as f:
10
  MODULES = json.load(f)["modules"]
11
 
12
  GENERATORS = [m for m in MODULES if m.get("type") == "generator"]
13
  CHECKERS = {m["id"]: m for m in MODULES if m.get("type") == "checker"}
14
  GEN_BY_ID = {m["id"]: m for m in GENERATORS}
 
15
  LABEL_TO_ID = {m["label"]: m["id"] for m in GENERATORS}
16
  LABEL_LIST = list(LABEL_TO_ID.keys())
17
 
18
- # -------------------------------------------------------------
19
- # Load Model (base LLM)
20
- # Swappable engine: GPT-2 / Llama / Mistral etc.
21
- # -------------------------------------------------------------
22
  tokenizer = AutoTokenizer.from_pretrained("openai-community/gpt2")
23
  model = AutoModelForCausalLM.from_pretrained("openai-community/gpt2")
24
  llm = pipeline("text-generation", model=model, tokenizer=tokenizer, max_new_tokens=300)
25
 
26
- # -------------------------------------------------------------
27
- # Automatic Router Components
28
- # -------------------------------------------------------------
29
- from router.rules import rule_router
30
- from router.zero_shot import classify_task # zero-shot classifier
31
-
32
- # -------------------------------------------------------------
33
- # Domain Adapters (LoRA)
34
- # -------------------------------------------------------------
35
- from domain_heads.loader import load_adapter # load domain-specific adapter
36
 
37
- # -------------------------------------------------------------
38
- # Reasoning Scaffolds
39
- # -------------------------------------------------------------
40
- from reasoning_scaffolds.cot import apply_cot
41
- from reasoning_scaffolds.critique_loop import critique_and_refine
42
-
43
-
44
- # -------------------------------------------------------------
45
- # Helper: LLM call
46
- # -------------------------------------------------------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  def call_llm(prompt: str) -> str:
48
  out = llm(prompt, do_sample=False)[0]["generated_text"]
49
- if out.startswith(prompt):
50
- out = out[len(prompt):]
51
- return out.strip()
52
 
53
 
54
- # -------------------------------------------------------------
55
- # Build prompts
56
- # -------------------------------------------------------------
57
  def build_generator_prompt(module_id: str, *inputs: str) -> str:
58
  m = GEN_BY_ID[module_id]
59
  keys = list(m["input_placeholders"].keys())
@@ -61,21 +170,17 @@ def build_generator_prompt(module_id: str, *inputs: str) -> str:
61
  secs = m["output_sections"]
62
 
63
  p = []
64
- p.append("You are a structured reasoning module.")
65
  p.append(f"MODULE: {m['label']} (id={module_id})")
66
- p.append("")
67
  p.append("INPUTS:")
68
  for k, v in vals.items():
69
  p.append(f"{k.upper()}: {v}")
70
- p.append("")
71
- p.append("You must respond using these sections:")
72
  for s in secs:
73
  p.append(f"- {s}")
74
- p.append("")
75
  for s in secs:
76
- p.append(f"{s}:")
77
- p.append("[content]")
78
- p.append("")
79
  return "\n".join(p)
80
 
81
 
@@ -84,130 +189,100 @@ def build_checker_prompt(checker_id: str, *vals: str) -> str:
84
  secs = c["output_sections"]
85
 
86
  if len(vals) < 2:
87
- original_task = ""
88
  draft = vals[0] if vals else ""
89
  else:
90
- original_task = "\n\n".join(vals[:-1])
91
  draft = vals[-1]
92
 
93
  p = []
94
- p.append("You are a strict reviewer.")
95
  p.append(f"CHECKER: {c['label']} (id={checker_id})")
96
- p.append("")
97
- p.append("ORIGINAL TASK:")
98
- p.append(original_task)
99
- p.append("")
100
- p.append("DRAFT OUTPUT:")
101
- p.append(draft)
102
- p.append("")
103
- p.append("You must respond using:")
104
  for s in secs:
105
  p.append(f"- {s}")
106
- p.append("")
107
  for s in secs:
108
- p.append(f"{s}:")
109
- p.append("[content]")
110
- p.append("")
111
  return "\n".join(p)
112
 
113
 
114
- # -------------------------------------------------------------
115
- # Generator & Checker Execution
116
- # -------------------------------------------------------------
117
  def run_generator(module_id: str, *inputs: str) -> str:
118
  m = GEN_BY_ID[module_id]
119
 
120
- # Load domain adapter if defined
121
  if m.get("domain"):
122
- load_adapter(model, m["domain"])
123
 
124
- # Build prompt
125
  prompt = build_generator_prompt(module_id, *inputs)
126
-
127
- # Apply reasoning scaffolds (CoT + critique loop)
128
  prompt = apply_cot(prompt)
129
  draft = call_llm(prompt)
130
  final = critique_and_refine(draft)
131
-
132
  return final
133
 
134
 
135
  def run_checker(checker_id: str, *inputs: str) -> str:
136
  prompt = build_checker_prompt(checker_id, *inputs)
137
  prompt = apply_cot(prompt)
138
- reviewed = call_llm(prompt)
139
- return reviewed
140
-
141
-
142
- # -------------------------------------------------------------
143
- # Hybrid Router (rules + zero-shot)
144
- # -------------------------------------------------------------
145
- def hybrid_route(task_text: str):
146
- if not task_text or not task_text.strip():
147
- return "No task provided", "", ""
148
 
149
- # 1. Rule-based (deterministic)
150
- rule_choice = rule_router(task_text)
151
- if rule_choice:
152
- return GEN_BY_ID[rule_choice]["label"], rule_choice, "Rule-based match"
153
 
154
- # 2. Zero-shot fallback
155
- predicted_label, module_id, scores = classify_task(task_text)
156
- return predicted_label, module_id, scores
157
-
158
-
159
- # -------------------------------------------------------------
160
- # UI
161
- # -------------------------------------------------------------
162
  def build_ui():
163
- with gr.Blocks(title="Modular Intelligence") as demo:
164
- gr.Markdown("# Modular Intelligence\nUpgraded architecture with routing, adapters, and reasoning layers.")
 
165
 
166
- # -------------------- Auto-Route Tab --------------------
167
  with gr.Tab("Auto-Route"):
168
  task_box = gr.Textbox(label="Describe your task", lines=6)
169
- module_name = gr.Textbox(label="Suggested Module", interactive=False)
170
- module_id = gr.Textbox(label="Module ID", interactive=False)
171
- scores = gr.Textbox(label="Routing Details", lines=12, interactive=False)
172
 
173
- classify_btn = gr.Button("Classify Task")
174
- classify_btn.click(
175
  fn=hybrid_route,
176
  inputs=[task_box],
177
- outputs=[module_name, module_id, scores],
178
  )
179
 
180
- # -------------------- Module Tabs ------------------------
181
  for m in GENERATORS:
182
  with gr.Tab(m["label"]):
183
- gr.Markdown(f"**Module ID:** `{m['id']}` | **Domain:** `{m.get('domain', 'general')}`")
184
 
185
  inputs = []
186
  for key, placeholder in m["input_placeholders"].items():
187
  t = gr.Textbox(label=key, placeholder=placeholder, lines=4)
188
  inputs.append(t)
189
 
190
- output_box = gr.Textbox(label="Module Output", lines=20)
191
  gr.Button("Run Module").click(
192
  fn=partial(run_generator, m["id"]),
193
  inputs=inputs,
194
- outputs=output_box,
195
  )
196
 
197
  checker_id = m.get("checker_id")
198
- if checker_id and checker_id in CHECKERS:
199
- checker_output = gr.Textbox(label="Checker Output", lines=15)
200
  gr.Button("Run Checker").click(
201
  fn=partial(run_checker, checker_id),
202
- inputs=inputs + [output_box],
203
- outputs=checker_output,
204
  )
205
  else:
206
- gr.Markdown("_No checker available for this module._")
207
 
208
  return demo
209
 
210
 
211
  if __name__ == "__main__":
212
- app = build_ui()
213
- app.launch()
 
1
  import json
2
+ import os
3
+ import torch
4
  from functools import partial
5
  import gradio as gr
6
+ from transformers import (
7
+ AutoModelForCausalLM,
8
+ AutoTokenizer,
9
+ pipeline
10
+ )
11
+
12
+ # =============================================================
13
+ # LOAD MODULES.JSON
14
+ # =============================================================
15
  with open("modules.json", "r", encoding="utf-8") as f:
16
  MODULES = json.load(f)["modules"]
17
 
18
  GENERATORS = [m for m in MODULES if m.get("type") == "generator"]
19
  CHECKERS = {m["id"]: m for m in MODULES if m.get("type") == "checker"}
20
  GEN_BY_ID = {m["id"]: m for m in GENERATORS}
21
+
22
  LABEL_TO_ID = {m["label"]: m["id"] for m in GENERATORS}
23
  LABEL_LIST = list(LABEL_TO_ID.keys())
24
 
25
+
26
+ # =============================================================
27
+ # BASE MODEL (ENGINE) Can be swapped
28
+ # =============================================================
29
  tokenizer = AutoTokenizer.from_pretrained("openai-community/gpt2")
30
  model = AutoModelForCausalLM.from_pretrained("openai-community/gpt2")
31
  llm = pipeline("text-generation", model=model, tokenizer=tokenizer, max_new_tokens=300)
32
 
 
 
 
 
 
 
 
 
 
 
33
 
34
+ # =============================================================
35
+ # HYBRID ROUTER (RULES + ZERO-SHOT)
36
+ # =============================================================
37
+
38
+ # ----------- RULE-BASED ROUTER -----------
39
+ RULES = [
40
+ ("contract", "document_explainer_v1"),
41
+ ("agreement", "document_explainer_v1"),
42
+ ("policy", "document_explainer_v1"),
43
+ ("judgment", "document_explainer_v1"),
44
+ ("options", "strategy_memo_v1"),
45
+ ("trade-off", "strategy_memo_v1"),
46
+ ("recommendation", "strategy_memo_v1"),
47
+ ("compare", "strategy_memo_v1"),
48
+ ("system", "system_blueprint_v1"),
49
+ ("architecture", "system_blueprint_v1"),
50
+ ("flow", "system_blueprint_v1"),
51
+ ("analysis", "analysis_note_v1"),
52
+ ("summarize", "analysis_note_v1"),
53
+ ("explain", "analysis_note_v1"),
54
+ ]
55
+
56
+ def rule_router(text: str):
57
+ t = text.lower()
58
+ for keyword, module_id in RULES:
59
+ if keyword in t:
60
+ return module_id
61
+ return None
62
+
63
+
64
+ # ----------- ZERO-SHOT ROUTER -----------
65
+ zero_shot_classifier = pipeline(
66
+ "zero-shot-classification",
67
+ model="facebook/bart-large-mnli"
68
+ )
69
+
70
+ def zero_shot_route(text):
71
+ res = zero_shot_classifier(text, candidate_labels=LABEL_LIST, multi_label=False)
72
+ label = res["labels"][0]
73
+ module_id = LABEL_TO_ID[label]
74
+ scores = "\n".join([f"{l}: {s:.2f}" for l, s in zip(res["labels"], res["scores"])])
75
+ return label, module_id, scores
76
+
77
+
78
+ # ----------- HYBRID ROUTE CALL -----------
79
+ def hybrid_route(task: str):
80
+ if not task.strip():
81
+ return "No input", "", ""
82
+
83
+ route = rule_router(task)
84
+ if route:
85
+ return GEN_BY_ID[route]["label"], route, "Rule-based match"
86
+
87
+ return zero_shot_route(task)
88
+
89
+
90
+ # =============================================================
91
+ # DOMAIN HEAD LOADER (LoRA-STYLE ADAPTERS)
92
+ # =============================================================
93
+ ADAPTER_PATHS = {
94
+ "legal": "domain_heads/legal_head.pt",
95
+ "strategy": "domain_heads/strategy_head.pt",
96
+ "analysis": "domain_heads/analysis_head.pt",
97
+ "systems": "domain_heads/systems_head.pt",
98
+ }
99
+
100
+ def load_domain_adapter(domain: str):
101
+ if domain not in ADAPTER_PATHS:
102
+ return
103
+
104
+ path = ADAPTER_PATHS[domain]
105
+ if not os.path.exists(path):
106
+ return
107
+
108
+ adapter = torch.load(path, map_location="cpu")
109
+ with torch.no_grad():
110
+ for name, param in model.named_parameters():
111
+ if name in adapter:
112
+ param += adapter[name]
113
+
114
+
115
+ # =============================================================
116
+ # REASONING SCAFFOLDS
117
+ # =============================================================
118
+
119
+ # ----------- CHAIN-OF-THOUGHT -----------
120
+ def apply_cot(prompt: str) -> str:
121
+ return (
122
+ "Think step-by-step. Explain your reasoning before answering.\n\n"
123
+ + prompt
124
+ + "\n\nNow think step-by-step and answer:"
125
+ )
126
+
127
+ # ----------- CRITIQUE + REFINE LOOP -----------
128
+ critic = pipeline(
129
+ "text-generation",
130
+ model="openai-community/gpt2",
131
+ max_new_tokens=200,
132
+ do_sample=False
133
+ )
134
+
135
+ def critique(text: str) -> str:
136
+ prompt = (
137
+ "Review this draft. Identify unclear reasoning, gaps, contradictions.\n\n"
138
+ "DRAFT:\n" + text + "\n\nReturn critique only:\n"
139
+ )
140
+ out = critic(prompt)[0]["generated_text"]
141
+ return out[len(prompt):].strip() if out.startswith(prompt) else out.strip()
142
+
143
+ def refine(text: str, critique_text: str) -> str:
144
+ prompt = (
145
+ "Improve the draft using the critique. Fix gaps, strengthen logic.\n\n"
146
+ "CRITIQUE:\n" + critique_text +
147
+ "\n\nDRAFT:\n" + text +
148
+ "\n\nReturn improved output:\n"
149
+ )
150
+ out = critic(prompt)[0]["generated_text"]
151
+ return out[len(prompt):].strip() if out.startswith(prompt) else out.strip()
152
+
153
+ def critique_and_refine(text: str) -> str:
154
+ c = critique(text)
155
+ return refine(text, c)
156
+
157
+
158
+ # =============================================================
159
+ # LLM CALL + PROMPT BUILDING
160
+ # =============================================================
161
  def call_llm(prompt: str) -> str:
162
  out = llm(prompt, do_sample=False)[0]["generated_text"]
163
+ return out[len(prompt):].strip() if out.startswith(prompt) else out.strip()
 
 
164
 
165
 
 
 
 
166
  def build_generator_prompt(module_id: str, *inputs: str) -> str:
167
  m = GEN_BY_ID[module_id]
168
  keys = list(m["input_placeholders"].keys())
 
170
  secs = m["output_sections"]
171
 
172
  p = []
 
173
  p.append(f"MODULE: {m['label']} (id={module_id})")
174
+ p.append("You must follow the structured reasoning format.\n")
175
  p.append("INPUTS:")
176
  for k, v in vals.items():
177
  p.append(f"{k.upper()}: {v}")
178
+ p.append("\nOutput sections:")
 
179
  for s in secs:
180
  p.append(f"- {s}")
181
+ p.append("\nFormat exactly as:")
182
  for s in secs:
183
+ p.append(f"{s}:\n[content]\n")
 
 
184
  return "\n".join(p)
185
 
186
 
 
189
  secs = c["output_sections"]
190
 
191
  if len(vals) < 2:
192
+ original = ""
193
  draft = vals[0] if vals else ""
194
  else:
195
+ original = "\n\n".join(vals[:-1])
196
  draft = vals[-1]
197
 
198
  p = []
 
199
  p.append(f"CHECKER: {c['label']} (id={checker_id})")
200
+ p.append("Review for structure, alignment and reasoning quality.\n")
201
+ p.append("ORIGINAL TASK:\n" + original + "\n")
202
+ p.append("DRAFT OUTPUT:\n" + draft + "\n")
203
+ p.append("Sections required:")
 
 
 
 
204
  for s in secs:
205
  p.append(f"- {s}")
206
+ p.append("\nFormat:")
207
  for s in secs:
208
+ p.append(f"{s}:\n[content]\n")
 
 
209
  return "\n".join(p)
210
 
211
 
212
+ # =============================================================
213
+ # GENERATOR + CHECKER EXECUTION
214
+ # =============================================================
215
  def run_generator(module_id: str, *inputs: str) -> str:
216
  m = GEN_BY_ID[module_id]
217
 
 
218
  if m.get("domain"):
219
+ load_domain_adapter(m["domain"])
220
 
 
221
  prompt = build_generator_prompt(module_id, *inputs)
 
 
222
  prompt = apply_cot(prompt)
223
  draft = call_llm(prompt)
224
  final = critique_and_refine(draft)
 
225
  return final
226
 
227
 
228
  def run_checker(checker_id: str, *inputs: str) -> str:
229
  prompt = build_checker_prompt(checker_id, *inputs)
230
  prompt = apply_cot(prompt)
231
+ return call_llm(prompt)
 
 
 
 
 
 
 
 
 
232
 
 
 
 
 
233
 
234
+ # =============================================================
235
+ # GRADIO UI
236
+ # =============================================================
 
 
 
 
 
237
  def build_ui():
238
+ with gr.Blocks(title="Modular Intelligence — Unified System") as demo:
239
+
240
+ gr.Markdown("# Modular Intelligence\nUnified architecture with routing, adapters, and reasoning scaffolds.")
241
 
242
+ # ---------------- AUTO-ROUTE TAB ----------------
243
  with gr.Tab("Auto-Route"):
244
  task_box = gr.Textbox(label="Describe your task", lines=6)
245
+ out_name = gr.Textbox(label="Suggested Module", interactive=False)
246
+ out_id = gr.Textbox(label="Module ID", interactive=False)
247
+ out_scores = gr.Textbox(label="Routing Details", lines=12, interactive=False)
248
 
249
+ gr.Button("Classify Task").click(
 
250
  fn=hybrid_route,
251
  inputs=[task_box],
252
+ outputs=[out_name, out_id, out_scores],
253
  )
254
 
255
+ # ---------------- MODULE TABS ----------------
256
  for m in GENERATORS:
257
  with gr.Tab(m["label"]):
258
+ gr.Markdown(f"**Module ID:** `{m['id']}` | **Domain:** `{m.get('domain','general')}`")
259
 
260
  inputs = []
261
  for key, placeholder in m["input_placeholders"].items():
262
  t = gr.Textbox(label=key, placeholder=placeholder, lines=4)
263
  inputs.append(t)
264
 
265
+ output = gr.Textbox(label="Generator Output", lines=18)
266
  gr.Button("Run Module").click(
267
  fn=partial(run_generator, m["id"]),
268
  inputs=inputs,
269
+ outputs=output,
270
  )
271
 
272
  checker_id = m.get("checker_id")
273
+ if checker_id in CHECKERS:
274
+ check_out = gr.Textbox(label="Checker Output", lines=15)
275
  gr.Button("Run Checker").click(
276
  fn=partial(run_checker, checker_id),
277
+ inputs=inputs + [output],
278
+ outputs=check_out,
279
  )
280
  else:
281
+ gr.Markdown("_No checker for this module._")
282
 
283
  return demo
284
 
285
 
286
  if __name__ == "__main__":
287
+ ui = build_ui()
288
+ ui.launch()