first_bot / app.py
indiapuig's picture
Update app.py
64d98fa verified
import gradio as gr
from huggingface_hub import InferenceClient
import torch
from sentence_transformers import SentenceTransformer
# Initialize the model client
client = InferenceClient("microsoft/phi-4")
# Load biology specification text
with open("bio_spec.txt", "r", encoding="utf-8", errors="replace") as f:
bio_spec_text = f.read()
# Preprocess text into chunks
def preprocess_text(text):
return [chunk.strip() for chunk in text.strip().split("\n") if chunk.strip()]
bio_chunks = preprocess_text(bio_spec_text)
# Load sentence transformer model and encode chunks
embedding_model = SentenceTransformer("all-MiniLM-L6-v2")
chunk_embeddings = embedding_model.encode(bio_chunks, convert_to_tensor=True)
# Retrieve the most relevant chunks
def get_top_chunks(query, chunk_embeddings, text_chunks, top_k=3):
query_embedding = embedding_model.encode(query, convert_to_tensor=True)
query_norm = torch.nn.functional.normalize(query_embedding, p=2, dim=0)
chunks_norm = torch.nn.functional.normalize(chunk_embeddings, p=2, dim=1)
similarities = torch.matmul(chunks_norm, query_norm)
top_indices = torch.topk(similarities, k=top_k).indices
return [text_chunks[i] for i in top_indices]
# Global state
chosen_topic = None
chosen_mode = None
# Gradio callbacks
def set_topic(topic):
global chosen_topic
chosen_topic = topic
return f"βœ… Great! You've chosen **{topic}**."
def set_mode(mode):
global chosen_mode
chosen_mode = mode
return f"βœ… You have selected **{mode}** mode."
# Generate system prompt based on mode
def get_system_prompt():
global chosen_mode, chosen_topic
if not chosen_topic or not chosen_mode:
return "Please select both a topic and a mode to start."
relevant_chunks = get_top_chunks(chosen_topic, chunk_embeddings, bio_chunks, top_k=4)
spec_content = "\n".join(relevant_chunks)
if chosen_mode == "exam mode":
prompt = (
f"You are now asking **GCSE Biology exam-style questions** on the topic '{chosen_topic}'. "
f"Ask one question at a time. Wait for the user to answer before giving feedback or asking the next question. "
f"Use the following specification excerpts as reference:\n{spec_content}"
)
else:
prompt = (
f"You are a helpful science tutor teaching '{chosen_topic}' in small, digestible sections. "
f"Focus on clear explanations suitable for 14-16 year olds. "
f"Use the following specification excerpts as reference:\n{spec_content}"
)
return prompt
# Chatbot response
def respond(message, history):
system_prompt = get_system_prompt()
if "Please select both" in system_prompt:
return system_prompt # Early return if topic or mode not selected
messages = [{"role": "system", "content": system_prompt}]
if history:
messages.extend(history)
messages.append({"role": "user", "content": message})
response = client.chat_completion(messages, max_tokens=300)
return response['choices'][0]['message']['content'].strip()
# Topic and mode lists
BIO_TOPICS = [
"Cell Biology",
"Organisation",
"Infection and Response",
"Bioenergetics",
"Homeostasis and Response",
"Inheritance, Variation and Evolution",
"Ecology"
]
exam_mode = ["exam mode", "learning mode"]
# Gradio interface
with gr.Blocks() as demo:
gr.Markdown("# ACE it! πŸ“š β€” GCSE Biology Tutor")
with gr.Row():
topic_dropdown = gr.Dropdown(choices=BIO_TOPICS, label="Choose a Biology Topic")
topic_button = gr.Button("Confirm Topic")
topic_output = gr.Markdown()
with gr.Row():
exam_dropdown = gr.Dropdown(choices=exam_mode, label="Which mode would you like")
exam_button = gr.Button("Confirm mode")
exam_output = gr.Markdown()
chatbot = gr.ChatInterface(respond, type="messages", title="ACE it!")
topic_button.click(set_topic, inputs=topic_dropdown, outputs=topic_output)
exam_button.click(set_mode, inputs=exam_dropdown, outputs=exam_output)
demo.launch()