Ai_Bonolotaai / app.py
Lavlu118557's picture
Update app.py
0747216 verified
Raw
History Blame Contribute Delete
4.38 kB
import os
import yaml
from fuzzywuzzy import fuzz
from huggingface_hub import InferenceClient
import gradio as gr
# 🔐 Secure token from Hugging Face Secrets
API_KEY = os.getenv("HF_TOKEN")
MODEL_NAME = "meta-llama/Llama-2-7b-chat-hf"
client = InferenceClient(model=MODEL_NAME, token=API_KEY)
# 📦 Load and validate YAML dataset
def load_yaml(path="data.yaml"):
if not os.path.exists(path):
print(f"❌ YAML file not found: {path}")
return []
try:
with open(path, 'r', encoding='utf-8') as f:
data = yaml.safe_load(f)
print(f"✅ Loaded {len(data)} items from YAML")
return data
except Exception as e:
print("❌ YAML loading error:", e)
return []
qa_data = load_yaml()
# 🔍 Fuzzy match logic across qa_pairs and descriptions
def find_best_match(user_question, threshold=70):
best_score = 0
best_item = None
best_answer = None
for item in qa_data:
# Match in qa_pairs
for qa in item.get("qa_pairs", []):
for q_field in ["question_bn", "question_en"]:
question = qa.get(q_field, "")
score = fuzz.partial_ratio(user_question.lower(), question.lower())
if score > best_score and score >= threshold:
best_score = score
best_item = item
best_answer = qa.get("answer_bn") if "question_bn" in q_field else qa.get("answer_en")
# Fallback to description_bn / description_en
for field in ["description_bn", "description_en"]:
if field in item:
score = fuzz.partial_ratio(user_question.lower(), item[field].lower())
if score > best_score and score >= threshold:
best_score = score
best_item = item
best_answer = item[field]
return best_item, best_answer
# 🧠 Prompt builder with emotion and category
def build_prompt(item, user_question, answer_text):
name_en = item.get("name_en", "")
name_bn = item.get("name_bn", "")
emotion = item.get("emotion", "neutral")
category = item.get("category", "general")
prompt = f"""
You are a thoughtful, bilingual assistant. Answer clearly and briefly, like a kind human.
Context:
🔹 Name (EN): {name_en}
🔹 Name (BN): {name_bn}
🔹 Emotion: {emotion}
🔹 Category: {category}
🔹 Matched Answer: {answer_text}
User Question: {user_question}
Instructions:
- Answer in Bengali if question is in Bengali, otherwise in English.
- Keep it short, clear, and relevant.
- Reflect the emotion tag if possible.
"""
return prompt
# 🤖 Ask model
def ask_model(user_question):
item, answer_text = find_best_match(user_question)
if not item:
return "❌ কোনো মিল পাওয়া যায়নি YAML-এ"
prompt = build_prompt(item, user_question, answer_text)
try:
response = client.text_generation(prompt=prompt, max_new_tokens=150)
return response.strip()
except Exception as e:
return f"❌ Model error: {e}"
# 🔊 Voice preview logic
def get_voice_path(item):
voice_file = item.get("voice", "")
voice_path = os.path.join("media", "voice", voice_file)
return voice_path if os.path.exists(voice_path) else None
# 🎛️ Gradio UI
with gr.Blocks() as demo:
gr.Markdown("## 🧠 Emotion-aware Bengali QA Chatbot (YAML Powered)")
with gr.Row():
user_input = gr.Textbox(label="প্রশ্ন লিখুন (বাংলা বা English)", scale=3)
submit_btn = gr.Button("উত্তর দিন", scale=1)
answer_output = gr.Textbox(label="উত্তর", lines=3)
voice_output = gr.Audio(label="🔊 কণ্ঠস্বর (যদি থাকে)", interactive=False)
def full_response(user_question):
item, answer_text = find_best_match(user_question)
if not item:
return "❌ কোনো মিল পাওয়া যায়নি YAML-এ", None
prompt = build_prompt(item, user_question, answer_text)
response = client.text_generation(prompt=prompt, max_new_tokens=150).strip()
voice_path = get_voice_path(item)
return response, voice_path
submit_btn.click(fn=full_response, inputs=user_input, outputs=[answer_output, voice_output])
demo.launch()