AditiShashiKhare commited on
Commit
276216e
·
verified ·
1 Parent(s): 0d7a297

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +116 -203
app.py CHANGED
@@ -1,239 +1,152 @@
1
  import gradio as gr
2
  import difflib
 
 
3
  from samples import BASE_INSTRUCTION, DRIFT_SCENARIOS
4
  from drift_env import evaluate_instruction_drift
5
  from drift_agent import generate_response as flan_generate
6
 
7
- # Optional second model (lighter, HF-safe)
8
  from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
9
  import torch
10
 
 
 
 
 
11
  ALT_MODEL = "google/flan-t5-small"
12
  alt_tokenizer = AutoTokenizer.from_pretrained(ALT_MODEL)
13
  alt_model = AutoModelForSeq2SeqLM.from_pretrained(ALT_MODEL)
14
  alt_model.eval()
15
 
16
-
17
  def alt_generate(prompt: str) -> str:
18
  inputs = alt_tokenizer(prompt, return_tensors="pt", truncation=True)
19
  with torch.no_grad():
20
  outputs = alt_model.generate(**inputs, max_new_tokens=160)
21
  return alt_tokenizer.decode(outputs[0], skip_special_tokens=True)
22
 
23
-
24
  MODELS = {
25
  "FLAN-T5-Base": flan_generate,
26
  "FLAN-T5-Small": alt_generate
27
  }
28
 
 
29
 
30
- SAMPLE_QUESTION = (
31
- "Explain how the system should respond when API latency suddenly increases "
32
- "beyond normal thresholds."
33
- )
34
 
35
- INSTRUCTION_CLAUSES = {
36
- "Respond concisely": "conciseness_violation",
37
- "Avoid speculation": "speculation_violation",
38
- "Explicitly state uncertainty": "uncertainty_missing"
39
- }
40
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
- def build_prompt(extra_context: str):
43
- return (
44
- BASE_INSTRUCTION
45
- + "\n\n"
46
- + extra_context
47
- + "\n\nQuestion: "
48
- + SAMPLE_QUESTION
49
- )
50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
- def diff_text(a, b):
53
- diff = difflib.ndiff(a.split(), b.split())
54
- return " ".join(
55
- token for token in diff
56
- if token.startswith("+") or token.startswith("-")
57
- )
58
-
59
-
60
- def format_clause_status(violations: dict):
61
- return {
62
- clause: (
63
- "⚠️ Violated" if violations.get(key, False) else "✅ Preserved"
64
- )
65
- for clause, key in INSTRUCTION_CLAUSES.items()
66
- }
67
-
68
-
69
- def run_full_evaluation(model_name):
70
- generator = MODELS[model_name]
71
-
72
- drift_scores = []
73
- timeline = []
74
- final_outputs = {}
75
-
76
- # Baseline
77
- baseline_prompt = build_prompt("")
78
- baseline_response = generator(baseline_prompt)
79
-
80
- for i, scenario in enumerate(DRIFT_SCENARIOS):
81
- drift_prompt = build_prompt(scenario["extra_context"])
82
- response = generator(drift_prompt)
83
-
84
- violations, drift_score = evaluate_instruction_drift(response)
85
- drift_scores.append(drift_score)
86
-
87
- timeline.append({
88
- "Step": i,
89
- "Scenario": scenario["name"],
90
- "Drift Score": drift_score
91
- })
92
-
93
- if i == len(DRIFT_SCENARIOS) - 1:
94
- final_outputs = {
95
- "prompt": drift_prompt,
96
- "baseline": baseline_response,
97
- "drifted": response,
98
- "diff": diff_text(baseline_response, response),
99
- "clauses": format_clause_status(violations),
100
- "score": drift_score
101
- }
102
-
103
- verdict = (
104
- "Instruction Drift Detected"
105
- if final_outputs["score"] > 0
106
- else "Instruction Fully Preserved"
107
- )
108
-
109
- return (
110
- timeline,
111
- final_outputs["prompt"],
112
- final_outputs["baseline"],
113
- final_outputs["drifted"],
114
- final_outputs["diff"],
115
- final_outputs["clauses"],
116
- final_outputs["score"],
117
- verdict
118
- )
119
-
120
-
121
- CUSTOM_CSS = """
122
- :root {
123
- --body-text-color: #1f2933;
124
- --body-background-fill: #f7f8fa;
125
-
126
- --block-background-fill: #ffffff;
127
- --block-border-color: #e5e7eb;
128
-
129
- --primary-600: #374151;
130
- --primary-500: #4b5563;
131
- --primary-400: #6b7280;
132
-
133
- --button-primary-background-fill: #374151;
134
- --button-primary-background-fill-hover: #1f2933;
135
- --button-primary-text-color: #ffffff;
136
-
137
- --input-border-color: #d1d5db;
138
- }
139
- """
140
-
141
-
142
- with gr.Blocks(css=CUSTOM_CSS) as demo:
143
- # ─────────────────────────────────────────────
144
- # Header
145
- # ─────────────────────────────────────────────
146
- gr.Markdown(
147
- """
148
- # 🧠 Instruction Drift Simulator
149
- **Compare how different models lose instruction adherence under pressure**
150
- """
151
- )
152
-
153
- gr.Markdown(
154
- """
155
- This product evaluates *instruction-following robustness* across models
156
- and visualizes how drift accumulates as prompt pressure increases.
157
- """
158
- )
159
-
160
- # ─────────────────────────────────────────────
161
- # Controls
162
- # ─────────────────────────────────────────────
163
- with gr.Row():
164
- model_choice = gr.Dropdown(
165
- choices=list(MODELS.keys()),
166
- value="FLAN-T5-Base",
167
- label="Model"
168
- )
169
- run_btn = gr.Button("Run Full Evaluation", variant="primary")
170
-
171
- # ─────────────────────────────────────────────
172
- # Content
173
- # ─────────────────────────────────────────────
174
  with gr.Tabs():
175
- with gr.Tab("Drift Progression Timeline"):
176
- timeline_out = gr.JSON(
177
- label="Drift Score by Scenario Step"
178
- )
179
 
180
- with gr.Tab("Prompt & Responses"):
181
- prompt_out = gr.Textbox(
182
- lines=6,
183
- label="Final Prompt"
184
- )
185
- baseline_out = gr.Textbox(
186
- lines=5,
187
- label="Baseline Response"
188
- )
189
- drifted_out = gr.Textbox(
190
- lines=5,
191
- label="Final Drifted Response"
192
- )
193
- diff_out = gr.Textbox(
194
- lines=4,
195
- label="Observed Changes"
196
  )
197
 
198
- with gr.Tab("Instruction Evaluation"):
199
- clause_out = gr.JSON(
200
- label="Instruction Clause Status"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  )
202
- with gr.Row():
203
- score_out = gr.Number(
204
- label="Final Drift Score",
205
- precision=2
206
- )
207
- verdict_out = gr.Textbox(
208
- label="Overall Result"
209
- )
210
-
211
- # ─────────────────────────────────────────────
212
- # Wiring
213
- # ─────────────────────────────────────────────
214
- run_btn.click(
215
- run_full_evaluation,
216
- model_choice,
217
- [
218
- timeline_out,
219
- prompt_out,
220
- baseline_out,
221
- drifted_out,
222
- diff_out,
223
- clause_out,
224
- score_out,
225
- verdict_out
226
- ]
227
- )
228
-
229
- # ─────────────────────────────────────────────
230
- # Footer
231
- # ─────────────────────────────────────────────
232
- gr.Markdown(
233
- """
234
- ---
235
- © 2026 **Aditi Khare** · All rights reserved
236
- """
237
- )
238
-
239
- demo.launch()
 
1
  import gradio as gr
2
  import difflib
3
+ import pandas as pd
4
+
5
  from samples import BASE_INSTRUCTION, DRIFT_SCENARIOS
6
  from drift_env import evaluate_instruction_drift
7
  from drift_agent import generate_response as flan_generate
8
 
 
9
  from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
10
  import torch
11
 
12
+ # =====================================================
13
+ # MODELS
14
+ # =====================================================
15
+
16
  ALT_MODEL = "google/flan-t5-small"
17
  alt_tokenizer = AutoTokenizer.from_pretrained(ALT_MODEL)
18
  alt_model = AutoModelForSeq2SeqLM.from_pretrained(ALT_MODEL)
19
  alt_model.eval()
20
 
 
21
  def alt_generate(prompt: str) -> str:
22
  inputs = alt_tokenizer(prompt, return_tensors="pt", truncation=True)
23
  with torch.no_grad():
24
  outputs = alt_model.generate(**inputs, max_new_tokens=160)
25
  return alt_tokenizer.decode(outputs[0], skip_special_tokens=True)
26
 
 
27
  MODELS = {
28
  "FLAN-T5-Base": flan_generate,
29
  "FLAN-T5-Small": alt_generate
30
  }
31
 
32
+ SAMPLE_QUESTION = "Explain how the system should respond when API latency increases."
33
 
34
+ # =====================================================
35
+ # HELPERS
36
+ # =====================================================
 
37
 
38
+ def build_prompt(extra):
39
+ return BASE_INSTRUCTION + "\n\n" + extra + "\n\nQuestion: " + SAMPLE_QUESTION
 
 
 
40
 
41
+ def diff_highlight(a, b):
42
+ diff = difflib.ndiff(a.split(), b.split())
43
+ html = ""
44
+ for t in diff:
45
+ if t.startswith("+"):
46
+ html += f"<span style='color:#22c55e'> {t}</span>"
47
+ elif t.startswith("-"):
48
+ html += f"<span style='color:#ef4444'> {t}</span>"
49
+ else:
50
+ html += f"{t} "
51
+ return html
52
 
53
+ # =====================================================
54
+ # CORE
55
+ # =====================================================
 
 
 
 
 
56
 
57
+ def run_eval(model_name):
58
+ gen = MODELS[model_name]
59
+
60
+ steps = []
61
+ scores = []
62
+
63
+ baseline = gen(build_prompt(""))
64
+
65
+ for i, s in enumerate(DRIFT_SCENARIOS):
66
+ resp = gen(build_prompt(s["extra_context"]))
67
+ _, score = evaluate_instruction_drift(resp)
68
+
69
+ steps.append(i)
70
+ scores.append(score)
71
+
72
+ df = pd.DataFrame({"Step": steps, "Drift": scores})
73
+
74
+ final_resp = gen(build_prompt(DRIFT_SCENARIOS[-1]["extra_context"]))
75
+
76
+ verdict = "🟢 Stable" if scores[-1] == 0 else "🔴 Drift Detected"
77
+
78
+ return df, baseline, final_resp, diff_highlight(baseline, final_resp), verdict
79
+
80
+ # =====================================================
81
+ # COMPARISON MODE
82
+ # =====================================================
83
+
84
+ def compare_models(m1, m2):
85
+ df1, base1, drift1, diff1, v1 = run_eval(m1)
86
+ df2, base2, drift2, diff2, v2 = run_eval(m2)
87
+
88
+ return df1, df2, diff1, diff2, v1, v2
89
+
90
+ # =====================================================
91
+ # UI
92
+ # =====================================================
93
+
94
+ with gr.Blocks(css="""
95
+ body {background:#020617;color:#e5e7eb;font-family:Inter}
96
+ button {background:linear-gradient(135deg,#0ea5e9,#22c55e);color:white}
97
+ a {color:#38bdf8}
98
+ """) as app:
99
+
100
+ gr.Markdown("# 🚀 Instruction Drift Simulator")
101
+ gr.Markdown("### Compare how models lose instruction fidelity under pressure")
102
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  with gr.Tabs():
 
 
 
 
104
 
105
+ # ---------------- SINGLE MODEL ----------------
106
+ with gr.Tab("Single Model"):
107
+ model = gr.Dropdown(list(MODELS.keys()), value="FLAN-T5-Base")
108
+ run = gr.Button("Run Evaluation")
109
+
110
+ chart = gr.LinePlot(label="Drift Over Time")
111
+ baseline = gr.Textbox(label="Baseline", lines=4)
112
+ drifted = gr.Textbox(label="Drifted", lines=4)
113
+ diff = gr.HTML(label="Diff")
114
+ verdict = gr.Textbox(label="Verdict")
115
+
116
+ run.click(
117
+ run_eval,
118
+ model,
119
+ [chart, baseline, drifted, diff, verdict]
 
120
  )
121
 
122
+ # ---------------- COMPARISON ----------------
123
+ with gr.Tab("Model Comparison"):
124
+ m1 = gr.Dropdown(list(MODELS.keys()), value="FLAN-T5-Base", label="Model A")
125
+ m2 = gr.Dropdown(list(MODELS.keys()), value="FLAN-T5-Small", label="Model B")
126
+ compare = gr.Button("Compare")
127
+
128
+ chart1 = gr.LinePlot(label="Model A Drift")
129
+ chart2 = gr.LinePlot(label="Model B Drift")
130
+
131
+ diff1 = gr.HTML(label="Diff A")
132
+ diff2 = gr.HTML(label="Diff B")
133
+
134
+ v1 = gr.Textbox(label="Verdict A")
135
+ v2 = gr.Textbox(label="Verdict B")
136
+
137
+ compare.click(
138
+ compare_models,
139
+ [m1, m2],
140
+ [chart1, chart2, diff1, diff2, v1, v2]
141
  )
142
+
143
+ # FOOTER
144
+ gr.Markdown("""
145
+ ---
146
+ ### Built by <b>Aditi Khare</b>
147
+ 🌐 <a href="https://aditikhare.com" target="_blank">
148
+ AditiKhare.com — Enterprise AI Product Ecosystem | Decision Intelligence
149
+ </a>
150
+ """)
151
+
152
+ app.launch()