|
|
import os |
|
|
import gradio as gr |
|
|
|
|
|
|
|
|
os.environ["TOKENIZERS_PARALLELISM"] = "false" |
|
|
try: |
|
|
import torch |
|
|
try: |
|
|
torch.set_num_threads(2) |
|
|
except Exception: |
|
|
pass |
|
|
except Exception: |
|
|
pass |
|
|
|
|
|
from transformers import pipeline |
|
|
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer |
|
|
|
|
|
|
|
|
GEN_MODEL_NAME = "MBZUAI/LaMini-Flan-T5-248M" |
|
|
|
|
|
DOMAIN_INSTRUCTIONS = ( |
|
|
"You are a concise assistant about cats in ancient Egypt. " |
|
|
"Keep focus on Bastet, cat mummies, daily life, worship, and other ancient Egypt facts. " |
|
|
"If the user asks something unrelated, say briefly that you only cover those topics and suggest one." |
|
|
) |
|
|
|
|
|
HELP_TEXT = ( |
|
|
"Ask me about: Bastet • cat mummies • daily life • worship\n" |
|
|
"Type anything else to try the AI fallback." |
|
|
) |
|
|
|
|
|
|
|
|
_t2t = None |
|
|
_vader = None |
|
|
|
|
|
def get_t2t(): |
|
|
"""Lazy-load the text2text pipeline (LaMini-Flan-T5).""" |
|
|
global _t2t |
|
|
if _t2t is None: |
|
|
_t2t = pipeline( |
|
|
"text2text-generation", |
|
|
model=GEN_MODEL_NAME, |
|
|
tokenizer=GEN_MODEL_NAME |
|
|
) |
|
|
print(f"[startup] Loaded model: {GEN_MODEL_NAME}") |
|
|
return _t2t |
|
|
|
|
|
def get_vader(): |
|
|
"""Lazy-load the VADER sentiment analyzer.""" |
|
|
global _vader |
|
|
if _vader is None: |
|
|
_vader = SentimentIntensityAnalyzer() |
|
|
print("[startup] Loaded VADER sentiment analyzer") |
|
|
return _vader |
|
|
|
|
|
|
|
|
def detect_sentiment_bucket(text: str): |
|
|
""" |
|
|
Return ('neg'|'neu'|'pos', compound_score). |
|
|
Thresholds chosen for clear buckets in chat settings. |
|
|
""" |
|
|
scores = get_vader().polarity_scores(text or "") |
|
|
c = scores.get("compound", 0.0) |
|
|
if c <= -0.4: |
|
|
return "neg", c |
|
|
if c >= 0.4: |
|
|
return "pos", c |
|
|
return "neu", c |
|
|
|
|
|
def apply_tone_prefix(reply_text: str, bucket: str) -> str: |
|
|
"""Prepend a tiny tone wrapper without changing factual content.""" |
|
|
if bucket == "pos": |
|
|
prefix = "Great question! " |
|
|
elif bucket == "neg": |
|
|
prefix = "Calm down. You're being a little too negative! " |
|
|
else: |
|
|
prefix = "" |
|
|
return (prefix + (reply_text or "")).strip() |
|
|
|
|
|
|
|
|
def ai_fallback(prompt: str) -> str: |
|
|
try: |
|
|
gen = get_t2t() |
|
|
prefixed = ( |
|
|
f"{DOMAIN_INSTRUCTIONS}\n\n" |
|
|
f"User: {prompt}\n" |
|
|
f"Assistant:" |
|
|
) |
|
|
out = gen( |
|
|
prefixed, |
|
|
max_new_tokens=48, |
|
|
do_sample=False |
|
|
)[0]["generated_text"] |
|
|
return (out or "").strip() |
|
|
except Exception as e: |
|
|
print("AI fallback error:", repr(e)) |
|
|
return "AI fallback had an issue. Please try a simpler question or use the topics in 'help'." |
|
|
|
|
|
|
|
|
def reply(message, history): |
|
|
|
|
|
bucket, _score = detect_sentiment_bucket(message or "") |
|
|
|
|
|
|
|
|
msg = (message or "").strip().lower() |
|
|
if msg in {"hi", "hello", "hey"} or "help" in msg: |
|
|
base = "Hi! I share facts about cats in ancient Egypt.\n\n" + HELP_TEXT |
|
|
elif "bastet" in msg or "bast" in msg: |
|
|
base = "Bastet (later cat-headed) … major cult center at Bubastis in the Nile Delta." |
|
|
elif any(w in msg for w in ["mummy", "mummies", "mummified", "offering"]): |
|
|
base = "Millions of animal mummies (cats common), esp. Late Period (664–332 BCE)." |
|
|
elif any(w in msg for w in ["daily", "life", "pest", "mouse", "rat", "snake"]): |
|
|
base = "Cats protected grain stores; art shows them under chairs/on leashes with owners." |
|
|
elif any(w in msg for w in ["worship", "god", "goddess", "taboo"]): |
|
|
base = "People didn’t worship pet cats as gods; they revered cats via Bastet and votive offerings." |
|
|
else: |
|
|
base = ai_fallback(message) |
|
|
|
|
|
|
|
|
return apply_tone_prefix(base, bucket) |
|
|
|
|
|
|
|
|
demo = gr.ChatInterface( |
|
|
fn=reply, |
|
|
title="Cats of Ancient Egypt Chatbot" |
|
|
) |
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo.launch() |
|
|
|