Spaces:
Sleeping
Sleeping
File size: 24,829 Bytes
08c5887 c37f00d 08c5887 c37f00d 6d09439 e3b8a57 6d09439 08c5887 71b02aa 08c5887 6d09439 08c5887 6d09439 08c5887 b7b0db9 08c5887 6d09439 b7b0db9 08c5887 b7b0db9 6d09439 b7b0db9 6d09439 b7b0db9 6d09439 aae276e 6d09439 c37f00d 6d09439 b7b0db9 6d09439 aae276e 6d09439 c37f00d a98720a 6d09439 b7b0db9 6d09439 b7b0db9 6d09439 a98720a 6d09439 b7b0db9 6d09439 c37f00d 6d09439 c37f00d 6d09439 aae276e 08c5887 e3b8a57 c37f00d e3b8a57 c37f00d e3b8a57 c37f00d e3b8a57 c37f00d e3b8a57 c37f00d e3b8a57 c37f00d e3b8a57 c37f00d e3b8a57 c37f00d e3b8a57 c37f00d e3b8a57 c37f00d aae276e c37f00d 08c5887 c37f00d 08c5887 c37f00d b7b0db9 6d09439 08c5887 b7b0db9 c37f00d 08c5887 e3b8a57 aae276e c37f00d a98720a c37f00d a98720a c37f00d b7b0db9 aae276e c37f00d 6d09439 c37f00d aae276e c37f00d b7b0db9 6d09439 b7b0db9 6d09439 b7b0db9 6d09439 c37f00d 6d09439 dbcdb64 08c5887 c37f00d 08c5887 c37f00d 6d09439 |
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 |
import os
import re
from typing import List, Tuple, Dict
from dataclasses import dataclass
import gradio as gr
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
# ---------------- Language detection ----------------
ARABIC_RE = re.compile(r"[\u0600-\u06FF]")
def detect_lang(text: str) -> str:
return "ur" if ARABIC_RE.search(text) else "en"
# ---------------- Guardrails ----------------
@dataclass
class Guardrails:
refusal_msg_ur: str
refusal_msg_en: str
blocked_patterns: List[str]
soft_patterns: List[str]
helplines: List[dict]
@classmethod
def from_yaml(cls, path: str):
import yaml
with open(path, "r", encoding="utf-8") as f:
data = yaml.safe_load(f)
return cls(
refusal_msg_ur=data.get("refusal_msg_ur", ""),
refusal_msg_en=data.get("refusal_msg_en", ""),
blocked_patterns=data.get("blocked_patterns", []),
soft_patterns=data.get("soft_patterns", []),
helplines=data.get("helplines", []),
)
def check(self, text: str) -> Tuple[str, str]:
low = text.lower()
for p in self.blocked_patterns:
if re.search(p, low):
return ("BLOCK", p)
for p in self.soft_patterns:
if re.search(p, low):
return ("SOFT", p)
return ("OK", "")
GUARD = Guardrails.from_yaml("guardrails.yaml")
# ---------------- Model ----------------
MODEL_ID = os.environ.get("SAFEPak_MODEL_ID", "Qwen/Qwen2-0.5B-Instruct")
try:
tok = AutoTokenizer.from_pretrained(MODEL_ID)
model = AutoModelForCausalLM.from_pretrained(MODEL_ID, torch_dtype=torch.float32)
except Exception as e:
print("LLM load failed, fallback active:", e)
tok = model = None
def llm_reply(prompt: str, max_new_tokens: int = 140, temperature: float = 0.45) -> str:
if not (tok and model):
return ""
ids = tok.encode(prompt, return_tensors="pt")
out = model.generate(
ids,
max_new_tokens=max_new_tokens,
do_sample=True,
temperature=temperature,
top_p=0.9,
repetition_penalty=1.12,
pad_token_id=tok.eos_token_id,
)
gen_ids = out[0][ids.shape[1]:]
return tok.decode(gen_ids, skip_special_tokens=True).strip()
# ---------------- Helpline rendering ----------------
def _clean_phone_for_links(p: str) -> str:
return "+" + "".join(ch for ch in p if ch.isdigit())
def phone_tel_link(p: str) -> str:
return f"tel:{_clean_phone_for_links(p)}"
def phone_wa_link(p: str) -> str:
num = _clean_phone_for_links(p).lstrip("+")
return f"https://wa.me/{num}"
def render_quick_helplines_md(lang: str = "ur") -> str:
if not GUARD.helplines:
return ""
title = "### فوری ہیلپ لائنز" if lang == "ur" else "### Quick Helplines"
rows = [title]
for h in GUARD.helplines:
name = h.get("name","").strip()
phone = h.get("phone","").strip()
if not (name and phone):
continue
tel = phone_tel_link(phone)
wa = phone_wa_link(phone)
rows.append(f"**{name}** \n{phone}\n[📞 Call]({tel}) [💬 WhatsApp]({wa})")
return "\n\n".join(rows)
def helplines_block(lang: str) -> str:
if not GUARD.helplines:
return ""
hdr = "ہیلپ لائنز:" if lang == "ur" else "Helplines:"
lines = [hdr]
for h in GUARD.helplines:
nm = h.get("name", "").strip()
ph = h.get("phone", "").strip()
if nm and ph:
tel = phone_tel_link(ph)
wa = phone_wa_link(ph)
lines.append(f"**{nm}**\n{ph}\n[📞 Call]({tel}) | [💬 WhatsApp]({wa})")
return "\n\n".join(lines)
# ---------------- Core prompt ----------------
SAFEPAK_SYSTEM = """
You are SafePak – 1122 Guide, a multilingual emergency disaster assistant.
Always reply in user's language (Urdu/English/regional).
Return medium-length, action-oriented checklists (5–7 bullets) and, if evacuation is implied or requested, append a Go-Bag sublist (4–8 items).
Never panic. Provide offline-safe steps. End with a calming line.
No personal data storage. No medical diagnoses (first aid only).
"""
# ---------------- Variety helpers ----------------
def _fingerprint(text: str) -> set:
toks = re.findall(r"[A-Za-z\u0600-\u06FF]{3,}", text.lower())
return set(toks)
def diversify_if_similar(prev: str, current: str, user_msg: str, lang: str) -> str:
if not prev:
return current
fp_prev = _fingerprint(prev)
fp_cur = _fingerprint(current)
overlap = len(fp_prev & fp_cur)
if overlap > max(12, int(len(fp_cur) * 0.55)):
prompt = (
f"<system>\nAvoid repeating earlier phrasing. Keep the same structure but change wording and add 2 scenario-specific, non-generic tips.\n"
f"Use user's language, stay concise and practical.\n</system>\n"
f"<user>\nMessage:\n{user_msg}\nCurrent answer:\n{current}\n</user>"
)
alt = llm_reply(prompt, max_new_tokens=160, temperature=0.6)
return alt if alt else current
return current
# ---------------- Prebaked Urdu FAQs (exact templates you provided) ----------------
# ہم regex-based ہلکا میچ استعمال کر رہے ہیں تاکہ اردو عبارت کے عام انداز پکڑ سکیں
PREBAKED_UR: List[Dict[str,str]] = [
{
"q_re": r"(سیلاب).*(گھر).*(ہوں|ہو)", # سیلاب آ گیا! میں گھر میں ہوں
"answer": "🚨 فوری اقدامات:\n- فوراً اونچی جگہ (2+ فلور) کی طرف ہٹیں۔\n- گہرے گھاٹ، ندیوں کے کنارے، یا چھوٹے دریاؤں کے قریب نہ رہیں۔\n- اگر گاڑی میں ہیں، تو فوراً گاڑی چھوڑ کر ہٹیں — گاڑی بہہ سکتی ہے۔\n\n📌 اگلے اقدامات:\n- 1122 یا 1500 پر فون کریں۔\n- اپنے فون کو ہائی ہولڈ رکھیں — پانی میں بھیگنے سے بچائیں ۔\n\n💡 کلیدی نکات:\n- پانی میں ہاتھ پاؤں نہ ڈالیں — گہرائی یا تیز دھارا کا خطرہ ہے۔\n- سیلاب کے بعد گھر میں داخل نہ ہوں جب تک کہ پانی نہ روکا گیا ہو۔"
},
{
"q_re": r"(زلزلہ).*(آ).*(رہا|رہی|گیا|گئی)|(جھٹک|ہل رہا)",
"answer": "🚨 فوری اقدامات:\n- 'ڈاون ڈاؤن' (Drop, Cover, Hold On):\n - گریں (Drop)\n - ٹیبل یا مضبوط دیوار کے نیچے چھپیں (Cover)\n - سر کو ہاتھوں سے چھپائیں (Hold On)\n- کھڑے ہو کر دروازے یا کھڑکیوں کی طرف نہ بھاگیں — شیشے ٹوٹ سکتے ہیں۔\n\n📌 اگلے اقدامات:\n- زلزلہ ختم ہونے کے بعد فوراً گھر سے باہر نکلیں — گری سے گری ہوئی عمارت گر سکتی ہے۔\n- بجلی، گیس، پانی کے پائپ بند کریں (اگر گیس کی بو آ رہی ہو)۔\n\n💡 کلیدی نکات:\n- زلزلہ کے دوران کسی چیز کو ہلائیں یا چھوڑیں — ہلاکت خیز ہو سکتا ہے۔\n- گاڑی میں ہوں تو گاڑی کے اندر بیٹھیں — باہر نہ نکلیں۔"
},
{
"q_re": r"(آگ|جل).*(لگ|گئی|گیا)",
"answer": "🚨 فوری اقدامات:\n- فوراً گھر سے باہر نکلیں — دھواں سانس کے لیے خطرہ ہے۔\n- ہاتھ سے چہرہ ڈھانپیں اور زمین پر چلتے رہیں (دھواں اوپر ہوتا ہے)۔\n- کوئی بجلی، فون، یا شمع نہ چلائیں — چمک آتشباری کر سکتی ہے۔\n\n📌 اگلے اقدامات:\n- 1122 پر فون کریں — آگ کے بارے میں مطلع کریں۔\n- رشتہ داروں کو مطلع کریں کہ آپ کہاں ہیں۔\n\n💡 کلیدی نکات:\n- زندگی کو بچانا آگ کو بچانے سے زیادہ اہم ہے۔\n- آگ کے بعد گھر میں داخل نہ ہوں جب تک کہ ٹیم کا اجازت نہ ہو۔"
},
{
"q_re": r"(گیس).*(لیک|بو|رس|smell)",
"answer": "🚨 فوری اقدامات:\n- گیس کا سوئچ بند کریں (اسٹو کے بالکل نیچے)۔\n- کوئی بجلی، فون، یا شمع نہ چلائیں — چمک آتشباری کر سکتی ہے۔\n- فوراً گھر سے باہر نکلیں — گیس ہلکی سی بھی ہو سکتی ہے۔\n\n📌 اگلے اقدامات:\n- 1122 یا 1500 پر فون کریں — گیس کمپنی کو مطلع کریں۔\n- گھر میں داخل نہ ہوں جب تک کہ گیس چیک نہ ہو جائے۔\n\n💡 کلیدی نکات:\n- گیس لیک کا خطرہ ہر وقت موجود ہے — ہر ماہ چیک کروائیں۔\n- گیس ڈیٹیکٹر لگائیں — اگر ہے، تو اسے فوراً چالو کریں۔"
},
{
"q_re": r"(کلاؤڈ\s*برسٹ|cloud\s*burst)",
"answer": "🚨 فوری اقدامات:\n- فوراً اونچی جگہ (پہاڑی، چوٹی) کی طرف ہٹیں۔\n- گہرے گھاٹ، ندیوں کے کنارے، یا چھوٹے دریاؤں کے قریب نہ رہیں۔\n- اگر گاڑی میں ہیں، تو فوراً گاڑی چھوڑ کر ہٹیں — گاڑی بہہ سکتی ہے۔\n\n📌 اگلے اقدامات:\n- 1122 پر فون کریں — ہیلپ مانگیں۔\n- اپنے فون کو ہائی ہولڈ رکھیں — پانی میں نہ ڈالیں۔\n\n💡 کلیدی نکات:\n- کلاؤڈ برسٹ کے بعد سیلاب فوری ہوتا ہے — اس لیے وقت ضائع نہ کریں۔\n- اگر زمین ہل رہی ہو، تو یہ سیلاب کا اشارہ ہے — فوراً ہٹیں۔"
},
{
"q_re": r"(بجلی).*(گر|گری|گر گئی|گرگئی)|lightning|electr",
"answer": "🚨 فوری اقدامات:\n- فوراً بجلی کے سوئچ بند کریں (اگر ممکن ہو)۔\n- کوئی بجلی کا آلہ نہ چلائیں — شرارت یا چوٹ لگ سکتی ہے۔\n- ہاتھ پاؤں نہ ڈالیں بلکہ ہلکی روشنی (ٹارچ) استعمال کریں۔\n\n📌 اگلے اقدامات:\n- 1122 پر فون کریں — بجلی کمپنی کو مطلع کریں۔\n- ایمرجنسی ٹارچ یا فون کی روشنی استعمال کریں۔\n\n💡 کلیدی نکات:\n- بجلی گرنے کے بعد کسی بھی الیکٹریکل آلے کو چلانے سے گریز کریں۔\n- ہر 6 ماہ بجلی کے سوئچ اور کیبلز چیک کروائیں۔"
},
{
"q_re": r"(^|\s)SOS(\s|!|۔)|مدد\s*کرو",
"answer": "🚨 SOS فائر ہو گیا!\n- فوراً 1122 پر فون کریں — ہیلپ ڈیسک آپ کو مدد کرے گی۔\n- اگر فون کنکشن ہو، تو میں فوراً 1122 پر فون کرتا ہوں...\n- اپنے آپ کو ٹھیک رکھیں — آپ کے ساتھ ہے۔\n\n💡 کلیدی نکات:\n- SOS کا وقت ہے — فوراً 1122 پر فون کریں۔\n- ہر ہفتے ایمرجنسی بیگ چیک کریں: پانی، فوڈ، ٹارچ، فون چارجر، فارمیسی۔"
},
{
"q_re": r"(سیلاب).*(بعد|ختم|اتر)",
"answer": "🚨 ایمرجنسی کے بعد:\n- گھر میں داخل نہ ہوں جب تک کہ پانی نہ روکا گیا ہو۔\n- گیس، بجلی، پانی کے پائپ چیک کروائیں — خطرہ ہو سکتا ہے۔\n- اپنے فون کو چارج کریں — ہیلپ ڈیسک سے رابطہ کریں۔\n\n📌 اگلے اقدامات:\n- 1122 پر فون کریں — اپنی حالت بتائیں۔\n- رشتہ داروں کو مطلع کریں کہ آپ کہاں ہیں۔\n\n💡 کلیدی نکات:\n- پانی کے بعد گرد و غبار، کیمیکل، یا بیکٹیریا ہو سکتے ہیں — کپڑے بدلیں۔\n- ایمرجنسی بیگ میں پانی، فوڈ، فارمیسی، ٹارچ وغیرہ رکھیں"
},
]
def match_prebaked_ur(user_msg: str) -> str:
"""اگر یوزر میسج اردو میں ہو اور کسی پری باکڈ ٹیمپلیٹ سے میچ کرے تو وہی جواب لوٹائیں۔"""
if detect_lang(user_msg) != "ur":
return ""
text = user_msg.strip()
for item in PREBAKED_UR:
pattern = item.get("q_re")
try:
if re.search(pattern, text, flags=re.IGNORECASE):
return item.get("answer","").strip()
except re.error:
continue
return ""
# ---------------- Base checklist + Go-Bag ----------------
def base_checklist_and_bag(user_msg: str, lang: str) -> Tuple[str, List[str]]:
low = user_msg.lower()
evac = False
if any(k in low for k in ["fire","آگ","smoke"]):
evac = True
checklist = ("✅ ابھی یہ کریں:\n"
"- جھک جائیں/Stay low — دھواں اوپر جاتا ہے\n"
"- ناک/منہ پر گیلا کپڑا رکھیں\n"
"- اگر محفوظ ہو تو بجلی/گیس مین بند کریں\n"
"- گرم دروازہ مت کھولیں؛ دوسرا راستہ لیں\n"
"- سیڑھیاں استعمال کریں — لفٹ نہیں\n"
"- بچوں/بزرگوں کو ساتھ رکھیں\n"
"🕊️ گھبرائیں نہیں — میں آپ کے ساتھ ہوں۔"
) if lang=="ur" else (
"✅ Do this now:\n"
"- Stay low — smoke rises\n"
"- Wet cloth over nose/mouth\n"
"- Cut power/gas if safe\n"
"- Do not open hot doors; use alternate exit\n"
"- Use stairs, never elevators\n"
"- Keep kids/elderly close\n"
"🕊️ Stay calm — I’m with you."
)
bag = (["شناختی کارڈ/کاغذات","نقدی","موبائل+پاور بینک","پانی","خشک کھانا","دوائیں","ہلکی چادر","ٹارچ"]
if lang=="ur" else
["IDs/documents","Cash","Phone+power bank","Water","Dry food","Medicines","Light blanket","Flashlight"])
elif any(k in low for k in ["زلزلہ","earthquake","tremor","shaking"]):
evac = True
checklist = ("✅ ابھی یہ کریں:\n"
"- Drop, Cover, Hold — جھکیں، ڈھکیں، پکڑیں\n"
"- کھڑکیوں/بھاری اشیاء سے دور رہیں\n"
"- جھٹکے رکنے پر سیڑھیوں سے باہر نکلیں (لفٹ نہیں)\n"
"- کھلی جگہ میں رکیں\n"
"🕊️ حوصلہ رکھیں — میں آپ کے ساتھ ہوں۔"
) if lang=="ur" else (
"✅ Do this now:\n"
"- Drop, Cover, Hold On\n"
"- Stay away from windows/heavy objects\n"
"- After shaking, exit via stairs (no elevators)\n"
"- Wait in an open safe area\n"
"🕊️ Stay calm — I’m with you."
)
bag = (["شناختی کارڈ/کاغذات","موبائل+پاور بینک","پانی","خشک کھانا","دوائیں","وسل","چھوٹی فرسٹ ایڈ","ٹارچ"]
if lang=="ur" else
["IDs/documents","Phone+power bank","Water","Dry food","Medicines","Whistle","Small first-aid","Flashlight"])
elif any(k in low for k in ["سیلاب","flood","overflow","water entering","طوفان","storm","آندھی"]):
evac = True
checklist = ("✅ ابھی یہ کریں:\n"
"- اگر محفوظ ہو تو بجلی مین سوئچ بند کریں\n"
"- اونچی جگہ/چھت پر منتقل ہوں\n"
"- پانی میں گاڑی نہ چلائیں\n"
"- بچوں/بزرگوں کو پہلے نکالیں\n"
"🕊️ گھبرائیں نہیں — آپ محفوظ نکل سکتے ہیں۔"
) if lang=="ur" else (
"✅ Do this now:\n"
"- Turn off main power if safe\n"
"- Move to higher ground/roof\n"
"- Do not drive through water\n"
"- Evacuate kids/elderly first\n"
"🕊️ Stay calm — you can get to safety."
)
bag = (["شناختی کارڈ/کاغذات","نقدی","موبائل+پاور بینک","پانی","خشک کھانا","دوائیں","واٹر پروف بیگ","چپل/بوٹس"]
if lang=="ur" else
["IDs/documents","Cash","Phone+power bank","Water","Dry food","Medicines","Waterproof pouches","Boots/Sandals"])
elif any(k in low for k in ["gas","گیس","leak","smell gas","بو"]):
checklist = ("✅ ابھی یہ کریں:\n"
"- کوئی چنگاری/سوئچ/لائٹر استعمال نہ کریں\n"
"- کھڑکیاں/دروازے کھول کر ہوا دار کریں\n"
"- گیس مین والو بند کریں\n"
"- محفوظ فاصلے پر چلے جائیں\n"
"🕊️ پرسکون رہیں — میں رہنمائی کر رہا/رہی ہوں۔"
) if lang=="ur" else (
"✅ Do this now:\n"
"- No sparks (no switches/lighters/flash)\n"
"- Ventilate: open windows/doors\n"
"- Shut the main gas valve\n"
"- Move to a safe distance\n"
"🕊️ Stay calm — I’m guiding you."
)
bag = (["ماسک/گیلا کپڑا","شناختی کارڈ","موبائل+پاور بینک","پانی","دوائیں"]
if lang=="ur" else
["Mask/wet cloth","IDs","Phone+power bank","Water","Medicines"])
elif any(k in low for k in ["injury","زخمی","bleeding","cut","fracture","burn"]):
checklist = ("✅ ابھی یہ کریں:\n"
"- خون ہو تو مضبوط دباؤ دیں (صاف کپڑا)\n"
"- زخم صاف پانی سے دھوئیں\n"
"- گہرا زخم/زیادہ خون ہو تو فوری مدد لیں\n"
"- گردن/کمر چوٹ میں مریض کو نہ ہلائیں\n"
"🕊️ پرسکون رہیں — آپ سنبھال سکتے ہیں۔"
) if lang=="ur" else (
"✅ Do this now:\n"
"- Apply firm direct pressure (clean cloth)\n"
"- Rinse with clean water\n"
"- Deep/heavy bleeding → seek urgent help\n"
"- Suspected spine injury: do not move\n"
"🕊️ Stay calm — you’ve got this."
)
bag = (["فرسٹ ایڈ کٹ","صاف کپڑا/بینڈیج","پانی","درد کش دوا","شناختی کارڈ"]
if lang=="ur" else
["First-aid kit","Clean cloth/bandage","Water","Pain reliever","ID"])
else:
checklist = ("✅ فوری رہنمائی:\n"
"- اردگرد خطرات پہچانیں (بجلی/گیس/دھواں/پانی)\n"
"- محفوظ کور یا اخراج کا راستہ منتخب کریں\n"
"- بچوں/بزرگوں کو ساتھ رکھیں\n"
"- لفٹ سے پرہیز کریں\n"
"🕊️ گھبرائیں نہیں — میں آپ کے ساتھ ہوں۔"
) if lang=="ur" else (
"✅ General guidance:\n"
"- Identify hazards (electricity/gas/smoke/water)\n"
"- Choose safe cover or exit route\n"
"- Keep kids/elderly close\n"
"- Avoid elevators\n"
"🕊️ Stay calm — I’m with you."
)
evac = True
bag = (["شناختی کارڈ/کاغذات","نقدی","فون+پاور بینک","پانی","خشک کھانا","دوائیں"]
if lang=="ur" else
["IDs/documents","Cash","Phone+power bank","Water","Dry food","Medicines"])
if evac:
if lang=="ur":
checklist += "\n\n🎒 ساتھ کیا لیں (Go-Bag):\n" + "\n".join(f"- {i}" for i in bag)
else:
checklist += "\n\n🎒 Take with you (Go-Bag):\n" + "\n".join(f"- {i}" for i in bag)
return checklist, bag
# ---------------- Refinement (more question-specific) ----------------
def format_response(base: str, user_msg: str, lang: str) -> str:
words = re.findall(r"[A-Za-z\u0600-\u06FF0-9_]+", user_msg)[:20]
key_hint = ", ".join(words)
system_rules = (
"Return a medium-length emergency guide in the user's language: 5–7 direct action bullets, "
"then a Go-Bag sublist (4–8 items) IF evacuation is implied or requested. "
"Be specific to the user's message, location constraints, and actors (e.g., children, elderly). "
"Use if-then phrasing where helpful. Do NOT repeat boilerplate from earlier answers."
)
refine_prompt = (
f"<system>\n{SAFEPAK_SYSTEM}\n{system_rules}\n</system>\n"
f"<user>\nMessage (keywords): {key_hint}\nFull message:\n{user_msg}\n\n"
f"Draft to improve:\n{base}\n</user>"
)
refined = llm_reply(refine_prompt, max_new_tokens=140, temperature=0.45)
return refined if refined else base
# ---------------- Chat logic (messages format) ----------------
def chat_fn(user_msg: str, chat_messages: List[Dict[str,str]], sim_state: dict):
if not user_msg:
return chat_messages, sim_state
lang = detect_lang(user_msg)
status, _ = GUARD.check(user_msg)
# BLOCK
if status == "BLOCK":
msg = GUARD.refusal_msg_ur if lang == "ur" else GUARD.refusal_msg_en
msg += "\n\n" + helplines_block(lang)
return chat_messages + [
{"role":"user","content":user_msg},
{"role":"assistant","content":msg}
], sim_state
# ✅ NEW: Prebaked Urdu templates first
pre_ur = match_prebaked_ur(user_msg)
if pre_ur:
final = pre_ur + "\n\n" + helplines_block("ur")
return chat_messages + [
{"role":"user","content":user_msg},
{"role":"assistant","content":final}
], sim_state
# Base checklist + Go-Bag
base, _ = base_checklist_and_bag(user_msg, lang)
# SOFT prepend note
if status == "SOFT":
base = ("⚠️ محتاط رہیں: یہ موضوع حساس ہے۔\n\n" + base) if lang=="ur" else ("⚠️ Note: sensitive topic.\n\n" + base)
# Refine with LLM (and append helplines)
final = format_response(base, user_msg, lang)
final += "\n\n" + helplines_block(lang)
# Diversify vs previous assistant message
prev_assistant = ""
for msg in reversed(chat_messages):
if msg.get("role") == "assistant":
prev_assistant = msg.get("content","")
break
final = diversify_if_similar(prev_assistant, final, user_msg, lang)
return chat_messages + [
{"role":"user","content":user_msg},
{"role":"assistant","content":final}
], sim_state
# ---------------- UI ----------------
with gr.Blocks(title="SafePak – 1122 Guide") as demo:
gr.Markdown("## SafePak – 1122 Guide\nMultilingual emergency assistant (CPU-only).")
gr.Markdown(render_quick_helplines_md("ur"))
state = gr.State({"active": False, "step": 0, "scenario": None})
chatbot = gr.Chatbot(height=420, type="messages")
msg = gr.Textbox(label="پیغام / Message", placeholder="یہاں لکھیں…", lines=2)
send = gr.Button("Send / بھیجیں")
clear = gr.Button("Clear")
def on_submit(u, h, s):
new_h, new_s = chat_fn(u, h, s)
return new_h, "", new_s
msg.submit(on_submit, [msg, chatbot, state], [chatbot, msg, state])
send.click(on_submit, [msg, chatbot, state], [chatbot, msg, state])
clear.click(lambda: ([], {"active": False, "step": 0, "scenario": None}), [], [chatbot, state])
if __name__ == "__main__":
demo.queue().launch(
server_name="0.0.0.0",
server_port=7860,
share=False
)
|