glowguidekwk / app.py
naiyya7's picture
indentation error
4afe112 verified
Raw
History Blame Contribute Delete
22.7 kB
import os
import re
import gradio as gr
import numpy as np
import colorsys
from huggingface_hub import InferenceClient
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
# ----------------------------
# Hugging Face API Client
# ----------------------------
token = os.getenv("naiyya")
client = InferenceClient(
"Qwen/Qwen2.5-7B-Instruct",
token=token
)
# ----------------------------
# Load Embedding Model
# ----------------------------
embedding_model = SentenceTransformer(
"sentence-transformers/all-MiniLM-L6-v2"
)
# ----------------------------
# Load Knowledge Base
# ----------------------------
chunks = []
chunk_embeddings = None
try:
if os.path.exists("knowledge.txt"):
with open("knowledge.txt", "r", encoding="utf-8") as file:
knowledge_base = file.read()
chunks = [
chunk.strip()
for chunk in knowledge_base.split("\n\n")
if chunk.strip()
]
if chunks:
print(f"Loaded {len(chunks)} knowledge chunks.")
chunk_embeddings = embedding_model.encode(chunks)
else:
print("knowledge.txt exists, but no chunks were found.")
else:
print("Warning: knowledge.txt missing. Starting in pure chat mode.")
except Exception as e:
print("Knowledge base initialization error:", e)
chunks = []
chunk_embeddings = None
# ----------------------------
# Clean Model Response
# ----------------------------
def clean_response_text(content):
if content is None:
return ""
if isinstance(content, list):
text_parts = []
for item in content:
if isinstance(item, dict):
if "text" in item:
text_parts.append(str(item["text"]))
elif "content" in item:
text_parts.append(str(item["content"]))
else:
text_parts.append(str(item))
else:
text_parts.append(str(item))
text = "\n".join(text_parts)
elif isinstance(content, dict):
if "text" in content:
text = str(content["text"])
elif "content" in content:
text = str(content["content"])
else:
text = str(content)
else:
text = str(content)
# Remove weird markdown/table/code characters
text = text.replace("```", "")
text = text.replace("`", "")
text = text.replace("|", "")
text = text.replace("โ”‚", "")
text = text.replace("โ”ƒ", "")
text = text.replace("โ˜", "")
text = text.replace(">", "")
cleaned_lines = []
for line in text.splitlines():
line = line.strip()
if not line:
continue
cleaned_lines.append(line)
text = "\n".join(cleaned_lines)
# Clean extra spaces and extra line breaks
text = re.sub(r"\n{3,}", "\n\n", text)
text = re.sub(r"[ \t]+", " ", text)
return text.strip()
# ----------------------------
# RAG Semantic Search Function
# ----------------------------
def retrieve_context(query, top_k=3):
if not chunks or chunk_embeddings is None:
return ""
query_embedding = embedding_model.encode([query])
scores = cosine_similarity(
query_embedding,
chunk_embeddings
)[0]
top_indices = scores.argsort()[-top_k:][::-1]
relevant_chunks = [
chunks[i]
for i in top_indices
]
return "\n\n".join(relevant_chunks)
# ----------------------------
# Chat Function
# ----------------------------
def respond(message, history):
if history is None:
history = []
if not message or not message.strip():
return "", history
context = retrieve_context(message)
system_prompt = f"""
You are GlowGuide, an empathetic, non-judgmental AI Health and Emotional Well-being Assistant.
KNOWLEDGE BASE:
{context}
Your goal is to support the user's emotional well-being, confidence, healthy habits, and daily decision-making.
You can help with:
- Stress, anxiety, overwhelm, and emotional check-ins
- Social pressure, peer pressure, family expectations, school stress, work stress, and boundaries
- Coping strategies such as journaling, grounding, breathing, reframing, and mindfulness
- Healthy food ideas, balanced meals, high-protein meals, and healthier sweet snack options
- General wellness habits like sleep, movement, hydration, and routine-building
STRICT RULES:
1. EMOTIONAL SUPPORT
- Identify the user's feelings.
- Validate them warmly.
- Avoid sounding robotic or clinical.
2. SOCIAL PRESSURE
- Help users handle peer pressure, family pressure, school stress, work stress, social media comparison, or body-image pressure.
- Give practical scripts for setting boundaries when helpful.
3. FOOD, FITNESS, AND WEIGHT-RELATED SUPPORT
- Give balanced, realistic food suggestions.
- If the user asks for something sweet but healthy, suggest options like Greek yogurt bowls, fruit with nut butter, protein smoothies, dark chocolate with fruit, cottage cheese with fruit, or homemade protein snacks.
- If the user asks for high-protein meals, suggest simple meals with lean protein, carbs, and healthy fats.
- Do not promote crash dieting, starvation, extreme restriction, guilt around food, or unsafe weight loss.
- Do not diagnose eating disorders or give medical nutrition plans.
- Encourage balance, energy, strength, and feeling good rather than shame or perfection.
4. ACTIONABLE SOLUTIONS
- Give 2-4 practical suggestions.
- Make advice easy to try today.
- Keep responses concise and useful.
5. SAFETY
- You are not a doctor, therapist, dietitian, or emergency service.
- If the user mentions self-harm, suicide, severe distress, or immediate danger, encourage them to contact emergency services, a crisis hotline, or a trusted adult immediately.
6. RESPONSE FORMAT
- Begin with one warm validating sentence.
- Use normal plain text only.
- Use simple dash bullets if needed.
- Do not use vertical bars.
- Do not use the | character.
- Do not use blockquotes.
- Do not use code blocks.
- Do not use Markdown tables.
- Do not add decorative lines before or after the response.
- Do not output JSON, Python lists, dictionaries, brackets, or raw object formatting.
- Keep language simple, supportive, and encouraging.
"""
messages = [
{
"role": "system",
"content": system_prompt
}
]
for turn in history:
if isinstance(turn, dict):
role = turn.get("role")
content = clean_response_text(turn.get("content"))
if role in ["user", "assistant"] and content:
messages.append({
"role": role,
"content": content
})
messages.append({
"role": "user",
"content": message
})
try:
response = client.chat.completions.create(
model="Qwen/Qwen2.5-7B-Instruct",
messages=messages,
max_tokens=350,
temperature=0.7,
stream=False
)
raw_content = response.choices[0].message.content
reply = clean_response_text(raw_content)
# Final extra cleanup
reply = reply.replace("|", "")
reply = reply.replace("โ”‚", "")
reply = reply.replace("โ”ƒ", "")
reply = reply.replace("โ˜", "")
reply = reply.replace("```", "")
reply = reply.replace("`", "")
reply = reply.strip()
except Exception as e:
reply = f"Error communicating with AI: {str(e)}"
history.append({
"role": "user",
"content": message
})
history.append({
"role": "assistant",
"content": reply
})
return "", history
# ----------------------------
# Helper Functions for Tabs
# ----------------------------
def save_journal(entry, mood):
if not entry or not entry.strip():
return "Write something first, even just one sentence ๐Ÿ’œ"
if not mood:
mood = "Not selected"
return f"""
### Journal Saved Reflection ๐Ÿ’œ
**Mood:** {mood}
**Your reflection:** {entry}
**Gentle reminder:** You took a moment to check in with yourself, and that matters.
"""
def grounding_response(choice):
if choice == "5-4-3-2-1 Grounding":
return """
### 5-4-3-2-1 Grounding Exercise ๐ŸŒฟ
Name:
- 5 things you can see
- 4 things you can feel
- 3 things you can hear
- 2 things you can smell
- 1 thing you can taste
Take one slow breath after each step.
"""
if choice == "Box Breathing":
return """
### Box Breathing ๐ŸŒฌ๏ธ
Try this for 1 minute:
- Breathe in for 4 seconds
- Hold for 4 seconds
- Breathe out for 4 seconds
- Hold for 4 seconds
Repeat until your body feels a little calmer.
"""
return """
### Quick Reset โœจ
Try this:
- Put both feet on the floor
- Relax your shoulders
- Take 3 slow breaths
- Say: โ€œI am safe in this moment.โ€
"""
def fuel_response(goal):
if goal == "Sweet but Healthy":
return """
### Sweet but Healthy Ideas ๐Ÿ“
- Greek yogurt with berries and honey
- Apple slices with peanut butter
- Protein smoothie with banana and milk
- Cottage cheese with pineapple
- Dark chocolate with strawberries
- Rice cake with peanut butter and banana
Try to choose something that gives you energy and makes you feel good.
"""
if goal == "High Protein Meal":
return """
### High-Protein Meal Ideas ๐Ÿ’ช
- Chicken, rice, and avocado bowl
- Turkey wrap with fruit on the side
- Eggs with toast and berries
- Greek yogurt bowl with granola and fruit
- Tuna sandwich with a side salad
- Tofu or chicken stir-fry with rice
A balanced plate usually has protein, carbs, fats, and fiber.
"""
if goal == "Quick Snack":
return """
### Quick Balanced Snacks โšก
- String cheese with fruit
- Greek yogurt cup
- Protein bar
- Peanut butter toast
- Cottage cheese with fruit
- Trail mix
- Turkey roll-ups
Pick something easy, satisfying, and realistic.
"""
return """
### Balanced Wellness Tip ๐ŸŒฑ
Focus on food that gives you energy, helps you feel full, and supports your day. Balance matters more than perfection.
"""
# ----------------------------
# Custom CSS
# ----------------------------
custom_css = """
:root {
color-scheme: light !important;
}
body, .gradio-container, .contain, .main {
background: linear-gradient(135deg, #F4ECFF 0%, #EEF5FF 50%, #FFF0F4 100%) !important;
font-family: Arial, Helvetica, sans-serif !important;
color: #4A3E65 !important;
}
footer {
display: none !important;
}
.gradio-container {
max-width: 1100px !important;
margin: auto !important;
}
.app-header {
text-align: center;
padding: 22px 10px 26px 10px;
}
.app-header h1 {
color: #8E7AB5 !important;
font-size: 42px !important;
font-weight: 800 !important;
margin-bottom: 4px !important;
letter-spacing: -1px;
}
.app-header p {
color: #9F8DCA !important;
font-size: 18px !important;
font-weight: 600 !important;
}
.glow-card {
background: rgba(255, 255, 255, 0.96) !important;
border-radius: 28px !important;
border: 1px solid #EFE7FF !important;
padding: 24px !important;
box-shadow: 0px 12px 35px rgba(154, 126, 185, 0.13) !important;
margin-bottom: 24px !important;
}
.card-title {
color: #4E3B67 !important;
font-weight: 800 !important;
font-size: 22px !important;
margin-bottom: 6px !important;
}
.card-subtitle {
color: #7A6C99 !important;
font-size: 16px !important;
font-weight: 600 !important;
margin-bottom: 18px !important;
}
/* Better global text */
label,
span,
p,
h1,
h2,
h3,
h4,
li,
div {
font-family: Arial, Helvetica, sans-serif !important;
}
label,
.label-wrap,
.block-info,
.form label,
.wrap label {
color: #4E3B67 !important;
font-weight: 700 !important;
font-size: 16px !important;
}
.markdown,
.markdown *,
.prose,
.prose * {
color: #4A3E65 !important;
font-family: Arial, Helvetica, sans-serif !important;
}
.tab-nav button,
.tabitem,
[role="tab"] {
color: #5F4B7A !important;
font-weight: 800 !important;
font-size: 15px !important;
}
.mood-btn {
background: #FFF0F5 !important;
border: 1px solid #FFDDE8 !important;
border-radius: 18px !important;
padding: 14px 16px !important;
color: #7A5C86 !important;
font-weight: 800 !important;
font-size: 16px !important;
}
.mood-btn:hover {
transform: translateY(-3px);
background: #FFE5EF !important;
box-shadow: 0px 6px 14px rgba(255, 182, 193, 0.35) !important;
}
fieldset,
fieldset *,
.radio-group *,
.checkbox-group *,
select,
option {
color: #4A3E65 !important;
font-family: Arial, Helvetica, sans-serif !important;
font-weight: 600 !important;
}
input,
textarea,
select {
background: #FFFFFF !important;
color: #4A3E65 !important;
border-radius: 16px !important;
border: 1px solid #D8CDEA !important;
font-family: Arial, Helvetica, sans-serif !important;
font-size: 16px !important;
}
textarea::placeholder,
input::placeholder {
color: #7A6C99 !important;
opacity: 1 !important;
}
button {
font-family: Arial, Helvetica, sans-serif !important;
font-weight: 700 !important;
}
/* Chatbot readability & Pink Panel Adjustments */
#glow-chatbot {
background: #FFF0F5 !important; /* This sets the main chat container background pink */
color: #4A3E65 !important;
border-radius: 24px !important;
border: 1px solid #FFD6E8 !important;
padding: 12px !important;
}
#glow-chatbot .message,
#glow-chatbot *,
#glow-chatbot .prose,
#glow-chatbot .prose *,
#glow-chatbot p,
#glow-chatbot span,
#glow-chatbot div {
color: #4A3E65 !important;
font-weight: 500 !important;
font-family: Arial, Helvetica, sans-serif !important;
}
/* Individual message boxes are transparent so the panel's pink shines through */
#glow-chatbot [data-testid="user"],
#glow-chatbot [data-testid="bot"],
#glow-chatbot [data-testid="assistant"],
#glow-chatbot .message {
background: transparent !important;
border: none !important;
box-shadow: none !important;
}
/* Slightly darken user messages or distinct rows for minimal text readability separation */
#glow-chatbot .user {
background: rgba(255, 255, 255, 0.4) !important;
border-radius: 14px !important;
padding: 8px 12px !important;
}
#glow-chatbot blockquote,
#glow-chatbot pre,
#glow-chatbot code,
#glow-chatbot .prose blockquote,
#glow-chatbot .message blockquote {
border-left: none !important;
border-right: none !important;
border: none !important;
background: transparent !important;
padding-left: 0 !important;
margin-left: 0 !important;
box-shadow: none !important;
}
#glow-chatbot button {
color: #F9FAFB !important;
}
/* Dock cards */
.dock-card {
background: #F7FBFF !important;
border: 1px solid #DDEEFF !important;
border-radius: 22px !important;
padding: 22px !important;
text-align: center !important;
color: #5F4B7A !important;
box-shadow: 0px 6px 18px rgba(160, 180, 220, 0.12) !important;
}
.dock-card h3 {
color: #4E3B67 !important;
font-size: 18px !important;
font-weight: 800 !important;
margin-bottom: 8px !important;
}
.dock-card p {
color: #7B6E93 !important;
font-size: 14px !important;
margin: 6px 0 !important;
}
.footer-text {
text-align: center;
color: #7A6C99 !important;
font-size: 16px !important;
margin-top: 18px !important;
font-weight: 700 !important;
}
"""
# ----------------------------
# Gradio App With Tabs
# ----------------------------
with gr.Blocks(
title="GlowGuide",
theme=gr.themes.Soft(
primary_hue="purple",
secondary_hue="pink",
neutral_hue="slate"
)
) as demo:
gr.HTML("""
<div class="app-header">
<h1>โœจ GlowGuide โœจ</h1>
<p>Your light. Your pace. You matter. ๐Ÿ’œ</p>
</div>
""")
with gr.Tabs():
# Chat Tab
with gr.Tab("๐Ÿ’ฌ Chat"):
with gr.Column(elem_classes=["glow-card"]):
gr.HTML("""
<p class="card-title">Daily Check-in Moodboard โœจ</p>
<p class="card-subtitle">How are you feeling today?</p>
""")
with gr.Row():
gr.Button("โ˜€๏ธ Calm", elem_classes=["mood-btn"])
gr.Button("๐ŸŒธ Happy", elem_classes=["mood-btn"])
gr.Button("โ˜๏ธ Okay", elem_classes=["mood-btn"])
gr.Button("๐ŸŒง๏ธ Anxious", elem_classes=["mood-btn"])
gr.Button("โ›ˆ๏ธ Overwhelmed", elem_classes=["mood-btn"])
gr.HTML("""
<p style="text-align:center; font-size:14px; color:#A396C7; margin-top:10px;">
๐Ÿ’œ All feelings are valid here.
</p>
""")
with gr.Column(elem_classes=["glow-card"]):
chatbot = gr.Chatbot(
height=350,
show_label=False,
render_markdown=False,
elem_id="glow-chatbot"
)
with gr.Row():
msg_input = gr.Textbox(
placeholder="What's on your mind?",
show_label=False,
scale=9
)
submit_btn = gr.Button("โžก๏ธ", scale=1)
msg_input.submit(
fn=respond,
inputs=[msg_input, chatbot],
outputs=[msg_input, chatbot]
)
submit_btn.click(
fn=respond,
inputs=[msg_input, chatbot],
outputs=[msg_input, chatbot]
)
# Journal Tab
with gr.Tab("๐Ÿ“– Journal"):
with gr.Column(elem_classes=["glow-card"]):
gr.HTML("""
<p class="card-title">๐Ÿ“– Personalized Journal</p>
<p class="card-subtitle">Write. Reflect. Heal.</p>
""")
mood_dropdown = gr.Dropdown(
choices=["Calm", "Happy", "Okay", "Anxious", "Overwhelmed"],
label="How are you feeling?"
)
journal_entry = gr.Textbox(
label="Journal Entry",
placeholder="Today I feel...",
lines=8
)
journal_btn = gr.Button("Save Reflection ๐Ÿ’œ")
journal_output = gr.Markdown()
journal_btn.click(
fn=save_journal,
inputs=[journal_entry, mood_dropdown],
outputs=journal_output
)
# Grounding Tab
with gr.Tab("๐ŸŽฎ Grounding"):
with gr.Column(elem_classes=["glow-card"]):
gr.HTML("""
<p class="card-title">๐ŸŽฎ Grounding Games</p>
<p class="card-subtitle">Play. Breathe. Reset.</p>
""")
grounding_choice = gr.Radio(
choices=[
"5-4-3-2-1 Grounding",
"Box Breathing",
"Quick Reset"
],
label="Choose a calming exercise"
)
grounding_btn = gr.Button("Start Exercise ๐ŸŒฟ")
grounding_output = gr.Markdown()
grounding_btn.click(
fn=grounding_response,
inputs=grounding_choice,
outputs=grounding_output
)
# Healthy Fuel Tab
with gr.Tab("๐Ÿ“ Healthy Fuel"):
with gr.Column(elem_classes=["glow-card"]):
gr.HTML("""
<p class="card-title">๐Ÿ“ Healthy Fuel Ideas</p>
<p class="card-subtitle">Sweet. Protein. Balanced.</p>
""")
fuel_choice = gr.Radio(
choices=[
"Sweet but Healthy",
"High Protein Meal",
"Quick Snack",
"Balanced Wellness Tip"
],
label="What are you looking for?"
)
fuel_btn = gr.Button("Get Ideas ๐Ÿฝ๏ธ")
fuel_output = gr.Markdown()
fuel_btn.click(
fn=fuel_response,
inputs=fuel_choice,
outputs=fuel_output
)
with gr.Tab("Relaxing Games "):
with gr.Column(elem_classes=["glow-card"]):
# The Zen headers you want to keep
gr.HTML("""
<p class="card-title">Zen Draws</p>
<p class="card-subtitle">Draw. Enjoy. Relax</p>
""")
# Single-page coloring canvas completely updated for Gradio 6+
draw_pad = gr.ImageEditor(
sources=None, # Clean blank drawing canvas
canvas_size=(800, 600), # Full-page canvas space
type="numpy",
label="Coloring Page",
# Fixed: Removed the incompatible 'sizes' and 'colors' lists
brush=gr.Brush(
default_size=10,
default_color="#ff0000"
)
)
# Resources Tab
with gr.Tab("๐Ÿšจ Resources"):
with gr.Column(elem_classes=["glow-card"]):
gr.HTML("""
<p class="card-title">๐Ÿšจ Support Resources</p>
<p class="card-subtitle">You deserve support, especially when things feel heavy.</p>
""")
gr.Markdown("""
### Immediate Help
If you are in immediate danger, call emergency services right away.
### United States
- 988 Suicide & Crisis Lifeline
- Call or text 988
### Other Support Options
- Talk to a trusted adult
- Reach out to a school counselor
- Contact a mental health professional
- Message a trusted friend or family member
### Reminder
GlowGuide is an AI assistant, not a therapist, doctor, dietitian, or emergency service.
""")
gr.HTML("""
<p class="footer-text">
๐Ÿ’œ You are stronger than you think. Take it one step at a time. โœจ
</p>
""")
if __name__ == "__main__":
demo.launch(css=custom_css)