Update app.py
Browse files
app.py
CHANGED
|
@@ -58,7 +58,9 @@ def log_feedback(bias_mode, prompt, response, thumb):
|
|
| 58 |
if not prompt or not response:
|
| 59 |
return
|
| 60 |
with open(FEEDBACK_FILE, "a", newline="", encoding="utf-8") as f:
|
| 61 |
-
writer = csv.writer(
|
|
|
|
|
|
|
| 62 |
writer.writerow(
|
| 63 |
[
|
| 64 |
datetime.utcnow().isoformat(),
|
|
@@ -74,6 +76,7 @@ def log_feedback(bias_mode, prompt, response, thumb):
|
|
| 74 |
# System prompts per bias
|
| 75 |
# ------------------------
|
| 76 |
|
|
|
|
| 77 |
def get_system_prompt(bias_mode: str) -> str:
|
| 78 |
if bias_mode == "Green energy":
|
| 79 |
return (
|
|
@@ -98,27 +101,31 @@ def get_system_prompt(bias_mode: str) -> str:
|
|
| 98 |
# ------------------------
|
| 99 |
|
| 100 |
|
| 101 |
-
def build_context(
|
| 102 |
"""
|
| 103 |
-
|
|
|
|
| 104 |
"""
|
| 105 |
system_prompt = get_system_prompt(bias_mode)
|
| 106 |
convo = system_prompt
|
| 107 |
-
for
|
| 108 |
-
|
|
|
|
|
|
|
|
|
|
| 109 |
convo += f"User: {user_message}\nAssistant:"
|
| 110 |
return convo
|
| 111 |
|
| 112 |
|
| 113 |
-
def generate_response(user_message,
|
| 114 |
"""
|
| 115 |
-
|
| 116 |
-
|
| 117 |
"""
|
| 118 |
if not user_message.strip():
|
| 119 |
-
return "",
|
| 120 |
|
| 121 |
-
prompt_text = build_context(
|
| 122 |
|
| 123 |
outputs = text_generator(
|
| 124 |
prompt_text,
|
|
@@ -135,13 +142,16 @@ def generate_response(user_message, chat_history, bias_mode):
|
|
| 135 |
else:
|
| 136 |
bot_reply = full_text.strip()
|
| 137 |
|
| 138 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 139 |
|
| 140 |
-
|
| 141 |
-
return "", chat_history, user_message, bot_reply
|
| 142 |
|
| 143 |
|
| 144 |
-
def handle_thumb(thumb_value,
|
| 145 |
"""
|
| 146 |
Called when user clicks π or π.
|
| 147 |
Logs the last interaction to CSV, including current bias.
|
|
@@ -169,9 +179,6 @@ def train_on_feedback(bias_mode: str):
|
|
| 169 |
- builds a small causal LM dataset
|
| 170 |
- runs a very short training loop
|
| 171 |
- updates the global model / pipeline in memory
|
| 172 |
-
|
| 173 |
-
Training on 'Green energy' pulls the model toward green cheerleading.
|
| 174 |
-
Training on 'Fossil fuels' pulls it back the other way.
|
| 175 |
"""
|
| 176 |
global model, text_generator
|
| 177 |
|
|
@@ -246,6 +253,50 @@ def train_on_feedback(bias_mode: str):
|
|
| 246 |
)
|
| 247 |
|
| 248 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 249 |
# ------------------------
|
| 250 |
# Gradio UI
|
| 251 |
# ------------------------
|
|
@@ -260,7 +311,7 @@ with gr.Blocks() as demo:
|
|
| 260 |
- π± **Green energy optimist**
|
| 261 |
- π’οΈ **Fossil-fuel optimist**
|
| 262 |
|
| 263 |
-
How it works
|
| 264 |
|
| 265 |
1. Pick a **bias mode** in the dropdown.
|
| 266 |
2. Ask a question and get an answer in that style.
|
|
@@ -268,8 +319,8 @@ with gr.Blocks() as demo:
|
|
| 268 |
4. Click **"Train model toward current bias"** β the model is fine-tuned only on
|
| 269 |
thumbs-up examples *for that bias mode*.
|
| 270 |
|
| 271 |
-
|
| 272 |
-
|
| 273 |
"""
|
| 274 |
)
|
| 275 |
|
|
@@ -280,22 +331,25 @@ with gr.Blocks() as demo:
|
|
| 280 |
label="Current bias target",
|
| 281 |
)
|
| 282 |
|
| 283 |
-
|
|
|
|
|
|
|
| 284 |
msg = gr.Textbox(
|
| 285 |
label="Type your message here and press Enter",
|
| 286 |
placeholder="Ask about energy, climate, economy, jobs, etc...",
|
| 287 |
)
|
| 288 |
|
| 289 |
-
|
| 290 |
state_last_user = gr.State("")
|
| 291 |
state_last_bot = gr.State("")
|
| 292 |
feedback_status = gr.Markdown("", label="Feedback status")
|
| 293 |
train_status = gr.Markdown("", label="Training status")
|
|
|
|
| 294 |
|
| 295 |
# When user sends a message
|
| 296 |
msg.submit(
|
| 297 |
generate_response,
|
| 298 |
-
inputs=[msg,
|
| 299 |
outputs=[msg, chatbot, state_last_user, state_last_bot],
|
| 300 |
)
|
| 301 |
|
|
@@ -304,14 +358,14 @@ with gr.Blocks() as demo:
|
|
| 304 |
btn_down = gr.Button("π Thumbs down")
|
| 305 |
|
| 306 |
btn_up.click(
|
| 307 |
-
lambda
|
| 308 |
-
inputs=[
|
| 309 |
outputs=feedback_status,
|
| 310 |
)
|
| 311 |
|
| 312 |
btn_down.click(
|
| 313 |
-
lambda
|
| 314 |
-
inputs=[
|
| 315 |
outputs=feedback_status,
|
| 316 |
)
|
| 317 |
|
|
@@ -325,4 +379,18 @@ with gr.Blocks() as demo:
|
|
| 325 |
outputs=train_status,
|
| 326 |
)
|
| 327 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 328 |
demo.launch()
|
|
|
|
| 58 |
if not prompt or not response:
|
| 59 |
return
|
| 60 |
with open(FEEDBACK_FILE, "a", newline="", encoding="utf-8") as f:
|
| 61 |
+
writer = csv.writer(
|
| 62 |
+
f
|
| 63 |
+
)
|
| 64 |
writer.writerow(
|
| 65 |
[
|
| 66 |
datetime.utcnow().isoformat(),
|
|
|
|
| 76 |
# System prompts per bias
|
| 77 |
# ------------------------
|
| 78 |
|
| 79 |
+
|
| 80 |
def get_system_prompt(bias_mode: str) -> str:
|
| 81 |
if bias_mode == "Green energy":
|
| 82 |
return (
|
|
|
|
| 101 |
# ------------------------
|
| 102 |
|
| 103 |
|
| 104 |
+
def build_context(messages, user_message, bias_mode):
|
| 105 |
"""
|
| 106 |
+
messages: list of {"role": "user"|"assistant", "content": "..."}
|
| 107 |
+
Turn chat history into a prompt for a small causal LM.
|
| 108 |
"""
|
| 109 |
system_prompt = get_system_prompt(bias_mode)
|
| 110 |
convo = system_prompt
|
| 111 |
+
for m in messages:
|
| 112 |
+
if m["role"] == "user":
|
| 113 |
+
convo += f"User: {m['content']}\n"
|
| 114 |
+
elif m["role"] == "assistant":
|
| 115 |
+
convo += f"Assistant: {m['content']}\n"
|
| 116 |
convo += f"User: {user_message}\nAssistant:"
|
| 117 |
return convo
|
| 118 |
|
| 119 |
|
| 120 |
+
def generate_response(user_message, messages, bias_mode):
|
| 121 |
"""
|
| 122 |
+
- messages: list of message dicts (Chatbot "messages" format)
|
| 123 |
+
Returns: (cleared textbox, updated messages, last_user, last_bot)
|
| 124 |
"""
|
| 125 |
if not user_message.strip():
|
| 126 |
+
return "", messages, "", ""
|
| 127 |
|
| 128 |
+
prompt_text = build_context(messages, user_message, bias_mode)
|
| 129 |
|
| 130 |
outputs = text_generator(
|
| 131 |
prompt_text,
|
|
|
|
| 142 |
else:
|
| 143 |
bot_reply = full_text.strip()
|
| 144 |
|
| 145 |
+
# Update message history in "messages" format
|
| 146 |
+
messages = messages + [
|
| 147 |
+
{"role": "user", "content": user_message},
|
| 148 |
+
{"role": "assistant", "content": bot_reply},
|
| 149 |
+
]
|
| 150 |
|
| 151 |
+
return "", messages, user_message, bot_reply
|
|
|
|
| 152 |
|
| 153 |
|
| 154 |
+
def handle_thumb(thumb_value, last_user, last_bot, bias_mode):
|
| 155 |
"""
|
| 156 |
Called when user clicks π or π.
|
| 157 |
Logs the last interaction to CSV, including current bias.
|
|
|
|
| 179 |
- builds a small causal LM dataset
|
| 180 |
- runs a very short training loop
|
| 181 |
- updates the global model / pipeline in memory
|
|
|
|
|
|
|
|
|
|
| 182 |
"""
|
| 183 |
global model, text_generator
|
| 184 |
|
|
|
|
| 253 |
)
|
| 254 |
|
| 255 |
|
| 256 |
+
# ------------------------
|
| 257 |
+
# Bias probe
|
| 258 |
+
# ------------------------
|
| 259 |
+
|
| 260 |
+
PROBE_QUESTIONS = [
|
| 261 |
+
"What is the future of global energy?",
|
| 262 |
+
"Are fossil fuels good or bad for the economy?",
|
| 263 |
+
"How reliable are renewable energy sources?",
|
| 264 |
+
"What should governments invest in to secure energy for the next 30 years?",
|
| 265 |
+
]
|
| 266 |
+
|
| 267 |
+
|
| 268 |
+
def run_bias_probe(bias_mode: str) -> str:
|
| 269 |
+
"""
|
| 270 |
+
Run the current model on a fixed set of probe questions
|
| 271 |
+
under the selected bias mode, with no history and no logging.
|
| 272 |
+
Returns a markdown-formatted report.
|
| 273 |
+
"""
|
| 274 |
+
reports = []
|
| 275 |
+
for q in PROBE_QUESTIONS:
|
| 276 |
+
# no chat history for the probe
|
| 277 |
+
prompt_text = build_context(messages=[], user_message=q, bias_mode=bias_mode)
|
| 278 |
+
|
| 279 |
+
outputs = text_generator(
|
| 280 |
+
prompt_text,
|
| 281 |
+
max_new_tokens=120,
|
| 282 |
+
do_sample=True,
|
| 283 |
+
top_p=0.95,
|
| 284 |
+
temperature=0.8,
|
| 285 |
+
pad_token_id=tokenizer.eos_token_id,
|
| 286 |
+
)
|
| 287 |
+
|
| 288 |
+
full_text = outputs[0]["generated_text"]
|
| 289 |
+
if "Assistant:" in full_text:
|
| 290 |
+
answer = full_text.split("Assistant:")[-1].strip()
|
| 291 |
+
else:
|
| 292 |
+
answer = full_text.strip()
|
| 293 |
+
|
| 294 |
+
reports.append(f"**Q:** {q}\n\n**A:** {answer}\n")
|
| 295 |
+
|
| 296 |
+
header = f"### Bias probe results (mode: *{bias_mode}*)\n"
|
| 297 |
+
return header + "\n---\n".join(reports)
|
| 298 |
+
|
| 299 |
+
|
| 300 |
# ------------------------
|
| 301 |
# Gradio UI
|
| 302 |
# ------------------------
|
|
|
|
| 311 |
- π± **Green energy optimist**
|
| 312 |
- π’οΈ **Fossil-fuel optimist**
|
| 313 |
|
| 314 |
+
### How it works
|
| 315 |
|
| 316 |
1. Pick a **bias mode** in the dropdown.
|
| 317 |
2. Ask a question and get an answer in that style.
|
|
|
|
| 319 |
4. Click **"Train model toward current bias"** β the model is fine-tuned only on
|
| 320 |
thumbs-up examples *for that bias mode*.
|
| 321 |
|
| 322 |
+
Use the **Bias probe** to see how the model currently talks about energy
|
| 323 |
+
on a fixed set of questions.
|
| 324 |
"""
|
| 325 |
)
|
| 326 |
|
|
|
|
| 331 |
label="Current bias target",
|
| 332 |
)
|
| 333 |
|
| 334 |
+
# Chatbot now uses default "messages" format (list of dicts with role/content)
|
| 335 |
+
chatbot = gr.Chatbot(height=400, label="EnergyBiasShifter")
|
| 336 |
+
|
| 337 |
msg = gr.Textbox(
|
| 338 |
label="Type your message here and press Enter",
|
| 339 |
placeholder="Ask about energy, climate, economy, jobs, etc...",
|
| 340 |
)
|
| 341 |
|
| 342 |
+
state_messages = gr.State([]) # list[{"role":..., "content":...}]
|
| 343 |
state_last_user = gr.State("")
|
| 344 |
state_last_bot = gr.State("")
|
| 345 |
feedback_status = gr.Markdown("", label="Feedback status")
|
| 346 |
train_status = gr.Markdown("", label="Training status")
|
| 347 |
+
probe_output = gr.Markdown("", label="Bias probe")
|
| 348 |
|
| 349 |
# When user sends a message
|
| 350 |
msg.submit(
|
| 351 |
generate_response,
|
| 352 |
+
inputs=[msg, state_messages, bias_dropdown],
|
| 353 |
outputs=[msg, chatbot, state_last_user, state_last_bot],
|
| 354 |
)
|
| 355 |
|
|
|
|
| 358 |
btn_down = gr.Button("π Thumbs down")
|
| 359 |
|
| 360 |
btn_up.click(
|
| 361 |
+
lambda lu, lb, bm: handle_thumb(1, lu, lb, bm),
|
| 362 |
+
inputs=[state_last_user, state_last_bot, bias_dropdown],
|
| 363 |
outputs=feedback_status,
|
| 364 |
)
|
| 365 |
|
| 366 |
btn_down.click(
|
| 367 |
+
lambda lu, lb, bm: handle_thumb(0, lu, lb, bm),
|
| 368 |
+
inputs=[state_last_user, state_last_bot, bias_dropdown],
|
| 369 |
outputs=feedback_status,
|
| 370 |
)
|
| 371 |
|
|
|
|
| 379 |
outputs=train_status,
|
| 380 |
)
|
| 381 |
|
| 382 |
+
gr.Markdown("## π Bias probe")
|
| 383 |
+
|
| 384 |
+
gr.Markdown(
|
| 385 |
+
"Click the button below to see how the current model answers a fixed set "
|
| 386 |
+
"of energy-related questions under the selected bias mode."
|
| 387 |
+
)
|
| 388 |
+
|
| 389 |
+
btn_probe = gr.Button("Run bias probe on current model")
|
| 390 |
+
btn_probe.click(
|
| 391 |
+
fn=run_bias_probe,
|
| 392 |
+
inputs=[bias_dropdown],
|
| 393 |
+
outputs=probe_output,
|
| 394 |
+
)
|
| 395 |
+
|
| 396 |
demo.launch()
|