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)