Spaces:
Sleeping
Sleeping
Upload 3 files
Browse files- app.py +70 -0
- rag.py +143 -0
- requirements.txt +9 -0
app.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
from rag import get_best_answer
|
| 3 |
+
|
| 4 |
+
# Custom CSS for the interface
|
| 5 |
+
css = """
|
| 6 |
+
#chatbot {
|
| 7 |
+
height: 350px;
|
| 8 |
+
overflow: auto;
|
| 9 |
+
border-radius: 10px;
|
| 10 |
+
border: 1px solid #e0e0e0;
|
| 11 |
+
}
|
| 12 |
+
.textbox {
|
| 13 |
+
border-radius: 20px !important;
|
| 14 |
+
padding: 12px 20px !important;
|
| 15 |
+
}
|
| 16 |
+
.btn-column {
|
| 17 |
+
display: flex;
|
| 18 |
+
flex-direction: column;
|
| 19 |
+
gap: 10px;
|
| 20 |
+
}
|
| 21 |
+
"""
|
| 22 |
+
|
| 23 |
+
def create_interface():
|
| 24 |
+
with gr.Blocks(css=css, theme="soft") as demo:
|
| 25 |
+
gr.Markdown("""
|
| 26 |
+
<h1 style='text-align: center;'>University of Education Lahore Chatbot</h1>
|
| 27 |
+
<p style='text-align: center;'>Official AI Assistant for University Information</p>
|
| 28 |
+
""")
|
| 29 |
+
|
| 30 |
+
# Define the chat interface
|
| 31 |
+
chatbot = gr.Chatbot(elem_id="chatbot")
|
| 32 |
+
examples = [
|
| 33 |
+
"What are the admission requirements?",
|
| 34 |
+
"How can I contact the administration?",
|
| 35 |
+
"What programs are offered?"
|
| 36 |
+
]
|
| 37 |
+
|
| 38 |
+
with gr.Row():
|
| 39 |
+
message = gr.Textbox(
|
| 40 |
+
label="Type your question here",
|
| 41 |
+
placeholder="Ask about admissions, programs, or university services...",
|
| 42 |
+
elem_classes="textbox",
|
| 43 |
+
scale=4
|
| 44 |
+
)
|
| 45 |
+
with gr.Column(scale=1, elem_classes="btn-column"):
|
| 46 |
+
submit_button = gr.Button("↩️ Enter")
|
| 47 |
+
reset_button = gr.Button("🗑️ Reset Chat")
|
| 48 |
+
|
| 49 |
+
# Set up both Enter key and button to trigger the response
|
| 50 |
+
def respond(message, chat_history):
|
| 51 |
+
bot_message = get_best_answer(message)
|
| 52 |
+
chat_history.append((message, bot_message))
|
| 53 |
+
return "", chat_history
|
| 54 |
+
|
| 55 |
+
message.submit(respond, [message, chatbot], [message, chatbot])
|
| 56 |
+
submit_button.click(respond, [message, chatbot], [message, chatbot])
|
| 57 |
+
|
| 58 |
+
# Reset button to clear history
|
| 59 |
+
def reset_conversation():
|
| 60 |
+
return []
|
| 61 |
+
|
| 62 |
+
reset_button.click(reset_conversation, [], [chatbot])
|
| 63 |
+
|
| 64 |
+
gr.Examples(examples, inputs=message)
|
| 65 |
+
|
| 66 |
+
return demo
|
| 67 |
+
|
| 68 |
+
if __name__ == "__main__":
|
| 69 |
+
demo = create_interface()
|
| 70 |
+
demo.launch()
|
rag.py
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
from sentence_transformers import SentenceTransformer, util
|
| 3 |
+
from groq import Groq
|
| 4 |
+
from datetime import datetime
|
| 5 |
+
import os
|
| 6 |
+
import pandas as pd
|
| 7 |
+
from datasets import load_dataset, Dataset
|
| 8 |
+
from dotenv import load_dotenv
|
| 9 |
+
import random
|
| 10 |
+
import glob
|
| 11 |
+
|
| 12 |
+
# Load environment variables
|
| 13 |
+
load_dotenv()
|
| 14 |
+
|
| 15 |
+
# Initialize Groq client
|
| 16 |
+
groq_client = Groq(api_key=os.getenv("GROQ_API_KEY"))
|
| 17 |
+
|
| 18 |
+
# Load similarity model
|
| 19 |
+
similarity_model = SentenceTransformer('paraphrase-MiniLM-L6-v2')
|
| 20 |
+
|
| 21 |
+
# Config
|
| 22 |
+
HF_DATASET_REPO = "midrees2806/unmatched_queries"
|
| 23 |
+
HF_TOKEN = os.getenv("HF_TOKEN")
|
| 24 |
+
|
| 25 |
+
# Greeting list
|
| 26 |
+
GREETINGS = [
|
| 27 |
+
"hi", "hello", "hey", "good morning", "good afternoon", "good evening",
|
| 28 |
+
"assalam o alaikum", "salam", "aoa", "hi there",
|
| 29 |
+
"hey there", "greetings"
|
| 30 |
+
]
|
| 31 |
+
|
| 32 |
+
# Fixed rephrased unmatched query responses
|
| 33 |
+
UNMATCHED_RESPONSES = [
|
| 34 |
+
"Thank you for your query. We’ve forwarded it to our support team and it will be added soon. In the meantime, you can visit the University of Education official website or reach out via the contact details below.\n\n📞 +92-42-99262231-33\n✉️ info@ue.edu.pk\n🌐 https://ue.edu.pk",
|
| 35 |
+
"We’ve noted your question and it’s in queue for inclusion. For now, please check the University of Education website or contact the administration directly.\n\n📞 +92-42-99262231-33\n✉️ info@ue.edu.pk\n🌐 https://ue.edu.pk",
|
| 36 |
+
"Your query has been recorded. We’ll update the system with relevant information shortly. Meanwhile, you can visit UE's official site or reach out using the details below:\n\n📞 +92-42-99262231-33\n✉️ info@ue.edu.pk\n🌐 https://ue.edu.pk",
|
| 37 |
+
"We appreciate your question. It has been forwarded for further processing. Until it’s available here, feel free to visit the official UE website or use the contact options:\n\n📞 +92-42-99262231-33\n✉️ info@ue.edu.pk\n🌐 https://ue.edu.pk"
|
| 38 |
+
]
|
| 39 |
+
|
| 40 |
+
# Load multiple JSON datasets
|
| 41 |
+
dataset = []
|
| 42 |
+
try:
|
| 43 |
+
json_files = glob.glob('datasets/*.json')
|
| 44 |
+
for file_path in json_files:
|
| 45 |
+
with open(file_path, 'r', encoding='utf-8') as f:
|
| 46 |
+
data = json.load(f)
|
| 47 |
+
if isinstance(data, list):
|
| 48 |
+
for item in data:
|
| 49 |
+
if isinstance(item, dict) and 'Question' in item and 'Answer' in item:
|
| 50 |
+
dataset.append(item)
|
| 51 |
+
else:
|
| 52 |
+
print(f"Invalid entry in {file_path}: {item}")
|
| 53 |
+
else:
|
| 54 |
+
print(f"File {file_path} does not contain a list.")
|
| 55 |
+
except Exception as e:
|
| 56 |
+
print(f"Error loading datasets: {e}")
|
| 57 |
+
|
| 58 |
+
# Precompute embeddings
|
| 59 |
+
dataset_questions = [item.get("Question", "").lower().strip() for item in dataset]
|
| 60 |
+
dataset_answers = [item.get("Answer", "") for item in dataset]
|
| 61 |
+
dataset_embeddings = similarity_model.encode(dataset_questions, convert_to_tensor=True)
|
| 62 |
+
|
| 63 |
+
# Save unmatched queries to Hugging Face
|
| 64 |
+
def manage_unmatched_queries(query: str):
|
| 65 |
+
try:
|
| 66 |
+
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
| 67 |
+
try:
|
| 68 |
+
ds = load_dataset(HF_DATASET_REPO, token=HF_TOKEN)
|
| 69 |
+
df = ds["train"].to_pandas()
|
| 70 |
+
except:
|
| 71 |
+
df = pd.DataFrame(columns=["Query", "Timestamp", "Processed"])
|
| 72 |
+
if query not in df["Query"].values:
|
| 73 |
+
new_entry = {"Query": query, "Timestamp": timestamp, "Processed": False}
|
| 74 |
+
df = pd.concat([df, pd.DataFrame([new_entry])], ignore_index=True)
|
| 75 |
+
updated_ds = Dataset.from_pandas(df)
|
| 76 |
+
updated_ds.push_to_hub(HF_DATASET_REPO, token=HF_TOKEN)
|
| 77 |
+
except Exception as e:
|
| 78 |
+
print(f"Failed to save query: {e}")
|
| 79 |
+
|
| 80 |
+
# Query Groq LLM
|
| 81 |
+
def query_groq_llm(prompt, model_name="llama3-70b-8192"):
|
| 82 |
+
try:
|
| 83 |
+
chat_completion = groq_client.chat.completions.create(
|
| 84 |
+
messages=[{
|
| 85 |
+
"role": "user",
|
| 86 |
+
"content": prompt
|
| 87 |
+
}],
|
| 88 |
+
model=model_name,
|
| 89 |
+
temperature=0.7,
|
| 90 |
+
max_tokens=500
|
| 91 |
+
)
|
| 92 |
+
return chat_completion.choices[0].message.content.strip()
|
| 93 |
+
except Exception as e:
|
| 94 |
+
print(f"Error querying Groq API: {e}")
|
| 95 |
+
return ""
|
| 96 |
+
|
| 97 |
+
# Main logic function to be called from Gradio
|
| 98 |
+
def get_best_answer(user_input):
|
| 99 |
+
if not user_input.strip():
|
| 100 |
+
return "Please enter a valid question."
|
| 101 |
+
|
| 102 |
+
user_input_lower = user_input.lower().strip()
|
| 103 |
+
|
| 104 |
+
if len(user_input_lower.split()) < 3 and not any(greet in user_input_lower for greet in GREETINGS):
|
| 105 |
+
return "Please ask your question properly with at least 3 words."
|
| 106 |
+
|
| 107 |
+
if any(keyword in user_input_lower for keyword in ["fee structure", "fees structure", "semester fees", "semester fee"]):
|
| 108 |
+
return (
|
| 109 |
+
"💰 For the most complete and up-to-date fee details for your program at the University of Education Lahore, please visit the official fee structure page.\n"
|
| 110 |
+
"This webpage offers a detailed overview of the fee structure, providing you with essential information to support your academic journey at our institution.\n"
|
| 111 |
+
"🔗 https://drive.google.com/file/d/1B30FKoP6GrkS9pQk10PWKCwcjco5E9Cc/view"
|
| 112 |
+
)
|
| 113 |
+
|
| 114 |
+
user_embedding = similarity_model.encode(user_input_lower, convert_to_tensor=True)
|
| 115 |
+
similarities = util.pytorch_cos_sim(user_embedding, dataset_embeddings)[0]
|
| 116 |
+
best_match_idx = similarities.argmax().item()
|
| 117 |
+
best_score = similarities[best_match_idx].item()
|
| 118 |
+
|
| 119 |
+
if best_score < 0.65:
|
| 120 |
+
manage_unmatched_queries(user_input)
|
| 121 |
+
return random.choice(UNMATCHED_RESPONSES)
|
| 122 |
+
|
| 123 |
+
original_answer = dataset_answers[best_match_idx]
|
| 124 |
+
prompt = f"""Name is UOE AI Assistant! You are an official assistant for the University of Education Lahore.
|
| 125 |
+
Rephrase the following official answer clearly and professionally.
|
| 126 |
+
Use structured formatting (like headings, bullet points, or numbered lists) where appropriate.
|
| 127 |
+
DO NOT add any new or extra information. ONLY rephrase and improve the clarity and formatting of the original answer.
|
| 128 |
+
### Question:
|
| 129 |
+
{user_input}
|
| 130 |
+
### Original Answer:
|
| 131 |
+
{original_answer}
|
| 132 |
+
### Rephrased Answer:
|
| 133 |
+
"""
|
| 134 |
+
|
| 135 |
+
llm_response = query_groq_llm(prompt)
|
| 136 |
+
|
| 137 |
+
if llm_response:
|
| 138 |
+
for marker in ["Improved Answer:", "Official Answer:", "Rephrased Answer:"]:
|
| 139 |
+
if marker in llm_response:
|
| 140 |
+
return llm_response.split(marker)[-1].strip()
|
| 141 |
+
return llm_response
|
| 142 |
+
else:
|
| 143 |
+
return dataset_answers[best_match_idx]
|
requirements.txt
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
sentence-transformers
|
| 2 |
+
groq
|
| 3 |
+
gradio
|
| 4 |
+
pillow
|
| 5 |
+
requests
|
| 6 |
+
numpy
|
| 7 |
+
python-dotenv
|
| 8 |
+
datasets
|
| 9 |
+
pandas
|