File size: 9,949 Bytes
d0a9c6c
 
94c17a8
 
a6d0898
 
 
 
d573b9d
ae86b01
54338b5
b5416c6
 
 
 
a9d4cd3
 
 
3f212e7
f0434c5
ae86b01
 
 
 
 
 
 
 
 
 
3f212e7
 
 
ae86b01
 
3f212e7
 
 
ae86b01
 
 
523a9dd
 
 
 
 
 
 
 
a5285cf
d0a9c6c
d3288d3
9d87ee0
b780a7e
9d87ee0
d3288d3
b780a7e
 
 
d3288d3
b780a7e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94c17a8
7458894
 
 
4bfa774
7458894
4bfa774
 
 
 
 
 
 
11044d5
 
4bfa774
11044d5
 
4bfa774
11044d5
 
4bfa774
11044d5
 
 
 
 
 
 
 
 
 
 
4bfa774
61f1871
4bfa774
88af390
792b8e2
88af390
 
 
 
ec61c05
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88af390
ec61c05
61f1871
88af390
792b8e2
88af390
792b8e2
5173860
792b8e2
5173860
 
 
 
 
88af390
61f1871
88af390
61f1871
 
 
 
 
 
 
 
 
5173860
88af390
 
 
a6d0898
 
 
 
 
 
 
 
 
 
 
 
 
 
61f1871
d573b9d
110f8a7
61f1871
308f112
61f1871
308f112
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
907f8ac
308f112
 
 
 
 
61f1871
 
 
 
 
 
 
 
 
 
 
 
a6d0898
 
 
 
 
 
 
61f1871
 
 
 
 
 
a6d0898
 
 
 
 
61f1871
 
 
 
 
 
 
bd25b5c
d7cd3e5
a6d0898
d7cd3e5
a6d0898
 
 
 
510fc4d
d7cd3e5
a6d0898
 
 
61f1871
 
a6d0898
 
 
 
 
d7cd3e5
a6d0898
308f112
6d40481
 
a6d0898
 
 
 
 
 
 
 
6d40481
d7cd3e5
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
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)