update
Browse files
app.py
CHANGED
|
@@ -362,6 +362,29 @@ def enrich_ioc(ioc, ioc_type):
|
|
| 362 |
f"Targeted countries: {', '.join(otx.get('countries', [])) or 'not specified'}")
|
| 363 |
|
| 364 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 365 |
def recent_threatfox_ioc():
|
| 366 |
"""A random *current* abuse.ch ThreatFox IP indicator, so the demo chip hits live data."""
|
| 367 |
key = _env(*ABUSE_KEYS)
|
|
@@ -521,6 +544,8 @@ if not st.session_state.messages:
|
|
| 521 |
|
| 522 |
for msg in st.session_state.messages:
|
| 523 |
with st.chat_message(msg["role"], avatar=ROBOT if msg["role"] == "assistant" else None):
|
|
|
|
|
|
|
| 524 |
if msg.get("retrieved"):
|
| 525 |
with st.expander(f"🔎 RAG — record retrieved from {msg.get('source', 'source')}"):
|
| 526 |
st.code(msg["retrieved"])
|
|
@@ -535,12 +560,16 @@ if user_input:
|
|
| 535 |
with st.chat_message("assistant", avatar=ROBOT):
|
| 536 |
with st.spinner("🔎 Retrieving + analyzing…"):
|
| 537 |
prompt, retrieved, source, note = route(user_input)
|
|
|
|
| 538 |
if note:
|
| 539 |
answer, badge = note, None
|
| 540 |
else:
|
|
|
|
|
|
|
|
|
|
| 541 |
answer = generate(prompt, max_new_tokens=max_tokens)
|
| 542 |
badge = ("🛡️ No record retrieved → refused (honesty guardrail)"
|
| 543 |
if REFUSAL_HINTS.search(answer) else "✅ Grounded in the retrieved record")
|
| 544 |
-
st.session_state.messages.append({"role": "assistant", "content": answer,
|
| 545 |
-
"
|
| 546 |
st.rerun()
|
|
|
|
| 362 |
f"Targeted countries: {', '.join(otx.get('countries', [])) or 'not specified'}")
|
| 363 |
|
| 364 |
|
| 365 |
+
def ioc_summary(ioc, ioc_type):
|
| 366 |
+
"""One-line live-intel summary from the feeds — DISPLAY ONLY, not fed to the model."""
|
| 367 |
+
tf = _safe(_threatfox, ioc)
|
| 368 |
+
otx = _safe(_otx, ioc, ioc_type)
|
| 369 |
+
vt = _safe(_vt, ioc, ioc_type)
|
| 370 |
+
parts = []
|
| 371 |
+
fams = sorted(set((tf or {}).get("families", []) + (otx or {}).get("families", [])))
|
| 372 |
+
if fams:
|
| 373 |
+
parts.append("🦠 " + ", ".join(fams[:3]))
|
| 374 |
+
if tf and tf.get("threat_types"):
|
| 375 |
+
tt = tf["threat_types"][0].lower()
|
| 376 |
+
parts.append("C&C server" if any(k in tt for k in ("c&c", "command", "botnet"))
|
| 377 |
+
else "payload host" if any(k in tt for k in ("payload", "distribution"))
|
| 378 |
+
else tf["threat_types"][0])
|
| 379 |
+
if tf and tf.get("confidence"):
|
| 380 |
+
parts.append(f"ThreatFox {tf['confidence']}%")
|
| 381 |
+
if vt and vt.get("total"):
|
| 382 |
+
parts.append(f"VT {vt['malicious']}/{vt['total']}")
|
| 383 |
+
if otx and otx.get("pulse_count"):
|
| 384 |
+
parts.append(f"OTX {otx['pulse_count']} pulses")
|
| 385 |
+
return " · ".join(parts) if parts else None
|
| 386 |
+
|
| 387 |
+
|
| 388 |
def recent_threatfox_ioc():
|
| 389 |
"""A random *current* abuse.ch ThreatFox IP indicator, so the demo chip hits live data."""
|
| 390 |
key = _env(*ABUSE_KEYS)
|
|
|
|
| 544 |
|
| 545 |
for msg in st.session_state.messages:
|
| 546 |
with st.chat_message(msg["role"], avatar=ROBOT if msg["role"] == "assistant" else None):
|
| 547 |
+
if msg.get("summary"):
|
| 548 |
+
st.info(msg["summary"]) # live-intel card, straight from the feeds
|
| 549 |
if msg.get("retrieved"):
|
| 550 |
with st.expander(f"🔎 RAG — record retrieved from {msg.get('source', 'source')}"):
|
| 551 |
st.code(msg["retrieved"])
|
|
|
|
| 560 |
with st.chat_message("assistant", avatar=ROBOT):
|
| 561 |
with st.spinner("🔎 Retrieving + analyzing…"):
|
| 562 |
prompt, retrieved, source, note = route(user_input)
|
| 563 |
+
summary = None
|
| 564 |
if note:
|
| 565 |
answer, badge = note, None
|
| 566 |
else:
|
| 567 |
+
if source and source.startswith("live ThreatFox"):
|
| 568 |
+
dioc, dtype = detect_ioc(user_input)
|
| 569 |
+
summary = _safe(ioc_summary, dioc, dtype) if dioc else None
|
| 570 |
answer = generate(prompt, max_new_tokens=max_tokens)
|
| 571 |
badge = ("🛡️ No record retrieved → refused (honesty guardrail)"
|
| 572 |
if REFUSAL_HINTS.search(answer) else "✅ Grounded in the retrieved record")
|
| 573 |
+
st.session_state.messages.append({"role": "assistant", "content": answer, "retrieved": retrieved,
|
| 574 |
+
"source": source, "badge": badge, "summary": summary})
|
| 575 |
st.rerun()
|