Hotlines / app.py
sbandwith's picture
adapt the css
ae86b01 verified
Raw
History Blame Contribute Delete
9.95 kB
import gradio as gr
from huggingface_hub import InferenceClient
from sentence_transformers import SentenceTransformer
import torch
from datetime import datetime
css = """
body, .gradio-container {
background: linear-gradient(
135deg,
#83c1ec 0%,
#a9b8ef 50%,
#c4abf2 100%
);
backdrop-filter: blur(20px);
}
.gr-block, .gr-panel, .gr-box, .gr-group {
background-color: #0a1a3d
border-radius: 12px
border: 1px solid #132a5e
}
button, .gr-button {
background-color: #7b2cbf
color: white
border-radius: 15px
transition: 0.3s;
}
button:hover, .gr-button:hover {
background-color: #9d4edd
transform: scale(1.05);
}
"""
journal_storage = [] # now holds dicts: {"category", "text", "timestamp"}
JOURNAL_CATEGORIES = [
"Daily Life", "Travel", "School", "Friends & Family",
"Gratitude", "Goals", "Feelings", "Other",
]
client = InferenceClient("Qwen/Qwen2.5-7B-Instruct")
# Open the knowledge base file in read mode with UTF-8 encoding
with open("UMATTER KNOWLEDGE BASE.txt", "r", encoding="utf-8") as file:
# Read the entire contents of thfile and store it in a variable
knowledge_base_text = file.read()
def preprocess_text(text):
# Strip extra whitespace from the beginning and the end of the text
cleaned_text = text.strip()
# Split the cleaned_text by every newline character (\n)
chunks = cleaned_text.split(". ")
# Create an empty list to store cleaned chunks
cleaned_chunks = []
# Write your for-in loop below to clean each chunk and add it to the cleaned_chunks list
for chunk in chunks:
stripped_chunk = chunk.strip()
if len(stripped_chunk) > 0:
cleaned_chunks.append(stripped_chunk)
# Return the cleaned_chunks
return cleaned_chunks
# Call the preprocess_text function and store the result in a cleaned_chunks variable
cleaned_chunks = preprocess_text(knowledge_base_text) # Complete this line
#load the pre-trained embelling model that converts text to vectors
model=SentenceTransformer('all-MiniLM-L6-v2')
def create_embeddings(text_chunks):
#convert each text chunk into vector embedding and store as a tensor
chunk_embeddings= model.encode(text_chunks, convert_to_tensor=True)
#return the chunk_embeddings
return chunk_embeddings
#call the create_embeddings function and store the result in a new chunk_embeddings variable
chunk_embeddings= create_embeddings(cleaned_chunks)
def get_top_chunks(query, chunk_embeddings, text_chunks):
# Convert the query text into a vector embedding
query_embedding = model.encode(query, convert_to_tensor=True)
# Normalize the query embedding to unit length
query_embedding_normalized = query_embedding / query_embedding.norm()
# Normalize all chunk embeddings
chunk_embeddings_normalized = chunk_embeddings / chunk_embeddings.norm(dim=1, keepdim=True)
# Calculate cosine similarity
similarities = torch.matmul(
chunk_embeddings_normalized,
query_embedding_normalized
)
# Find indices of top 3 chunks
top_indices = torch.topk(similarities, k=3).indices.tolist()
# Retrieve the top chunks
top_chunks = [text_chunks[idx] for idx in top_indices]
return top_chunks
def respond(message, history, country):
full_query = message + " " + country
context_chunks = get_top_chunks(full_query, chunk_embeddings, cleaned_chunks)
context_str = "\n".join(context_chunks)
system_prompt = f"""
You are UMatter, a mental wellness chatbot for users aged 13 to 25.
Your role is to provide support in a safe, calm and non-judgmental way.
You are not a therapist and must never diagnose mental health conditions.
When a user sends a message, first identify their emotional state from:
sadness, anger or frustration, loneliness, overwhelm, confusion, neutral.
Add a Disclaimer: *Disclaimer: This bot is NOT a therapist, it cannot understand emotions. Please seek human therapists but use this as a hub.
Use the following context if relevant:
{context_str}
and
{country}
"""
messages = [{"role": "system", "content": system_prompt}]
for turn in history:
if isinstance(turn, dict):
messages.append({"role": turn["role"], "content": turn["content"]})
else:
user_msg, bot_msg = turn
if user_msg:
messages.append({"role": "user", "content": user_msg})
if bot_msg:
messages.append({"role": "assistant", "content": bot_msg})
messages.append({"role": "user", "content": message})
response = ""
for msg in client.chat_completion(
messages,
max_tokens=512,
stream=True,
temperature=0.7,
top_p=0.9,
):
token = msg.choices[0].delta.content
if token:
response += token
yield response
def get_all_categories():
cats = set(JOURNAL_CATEGORIES)
for entry in journal_storage:
cats.add(entry["category"])
return ["All"] + sorted(cats)
def build_choices(filter_category="All"):
choices = []
for i, entry in enumerate(journal_storage):
if filter_category == "All" or entry["category"] == filter_category:
preview = entry["text"][:30].replace("\n", " ")
label = f"[{entry['category']}] {entry['timestamp']} β€” {preview}…"
choices.append((label, i))
return choices
with gr.Blocks(css=css) as demo:
gr.Image(value="UMatter.png", show_label=False, container=False, height=250)
gr.Markdown("# 🌟 UMatter - Youth Mental Health Support Hub")
with gr.Tabs():
with gr.TabItem("πŸ’¬ Support Chat"):
country_dropdown = gr.Dropdown(
choices=[
"United States",
"India",
"Canada",
"United Kingdom",
"Australia",
"Germany",
"France",
"Japan",
"Mexico",
"Brazil",
"South Korea"
],
value="United States",
label="Select Your Country"
)
gr.ChatInterface(
fn=respond,
additional_inputs=[country_dropdown],
title="UMatter Chat",
description="Talk to me about anything mental health 😁"
)
# Tab 2: Our brand new private journal space
with gr.TabItem("πŸ“– My Private Journal"):
gr.Markdown("### πŸ”’ Your Secure Personal Space")
with gr.Row():
# Left Column: Writing entries
with gr.Column(scale=2):
journal_input = gr.Textbox(
label="Write your thoughts here...",
placeholder="How was your day? What's on your mind?",
lines=10
)
category_dropdown = gr.Dropdown(
choices=JOURNAL_CATEGORIES,
value="Daily Life",
label="πŸ“‚ Category",
info="Pick one or type your own",
allow_custom_value=True
)
save_btn = gr.Button("πŸ’Ύ Save Entry", variant="primary")
status_output = gr.Markdown("") # To show "Saved successfully!"
# Right Column: Viewing past entries
with gr.Column(scale=1):
gr.Markdown("#### πŸ“š Past Reflections")
filter_dropdown = gr.Dropdown(
choices=["All"] + JOURNAL_CATEGORIES,
value="All",
label="πŸ”Ž Filter by category"
)
history_dropdown = gr.Dropdown(
choices=[],
label="Select a previous entry",
interactive=True
)
view_btn = gr.Button("πŸ” View Selected")
def save_journal_entry(text, category):
if not text.strip():
return gr.update(), gr.update(value="⚠️ Cannot save an empty entry!"), gr.update(), gr.update()
category = (category or "Other").strip() or "Other"
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M")
journal_storage.append({"category": category, "text": text.strip(), "timestamp": timestamp})
return (
gr.update(value=""),
gr.update(value=f"βœ… Entry saved under **{category}**!"),
gr.update(choices=build_choices("All"), value=None),
gr.update(choices=get_all_categories(), value="All"),
)
def filter_entries(filter_category):
return gr.update(choices=build_choices(filter_category), value=None)
def view_journal_entry(selected_index):
if selected_index is None:
return gr.update()
return gr.update(value=journal_storage[selected_index]["text"])
save_btn.click(
fn=save_journal_entry,
inputs=[journal_input, category_dropdown],
outputs=[journal_input, status_output, history_dropdown, filter_dropdown]
)
filter_dropdown.change(
fn=filter_entries,
inputs=filter_dropdown,
outputs=history_dropdown
)
view_btn.click(
fn=view_journal_entry,
inputs=history_dropdown,
outputs=journal_input
)
demo.launch(debug=True)