StevenMSAI's picture
Update app.py
bafbae3 verified
raw
history blame
4.26 kB
import os
import gradio as gr
# --------- CPU hygiene (nice-to-have) ----------
os.environ["TOKENIZERS_PARALLELISM"] = "false"
try:
import torch
try:
torch.set_num_threads(2) # smoother on 2 vCPUs
except Exception:
pass
except Exception:
pass
from transformers import pipeline
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
# -------- Model / bot configuration --------
GEN_MODEL_NAME = "MBZUAI/LaMini-Flan-T5-248M" # CPU-friendly text2text model
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."
)
# -------- Lazy singletons --------
_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
# -------- Helpers --------
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()
# ---- Use the LLM if the generator doesn't understand user prompt ----
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'."
# -------- Chat logic --------
def reply(message, history):
# 1) sentiment first (on the raw user text)
bucket, _score = detect_sentiment_bucket(message or "")
# 2) rules-first responses
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)
# 3) tone wrapper (content unchanged)
return apply_tone_prefix(base, bucket)
# -------- UI --------
demo = gr.ChatInterface(
fn=reply,
title="Cats of Ancient Egypt Chatbot"
)
if __name__ == "__main__":
demo.launch()