TeahReichenbaum commited on
Commit
59275d1
·
verified ·
1 Parent(s): 7b3d523

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +177 -85
app.py CHANGED
@@ -1,11 +1,29 @@
1
  import gradio as gr
2
- from datetime import datetime
3
  from huggingface_hub import InferenceClient
4
  import os
5
- # Replace with your actual Hugging Face token
6
- os.environ["HF_TOKEN"] = "your_huggingface_token_here"
7
- client = InferenceClient("google/gemma-2b-it")
8
- # Prompt
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  cycle_ai_prompt = """
10
  Cycle-Aware Wellness AI Coach (Strict Enforcement Version)
11
  ==========================================================
@@ -17,7 +35,7 @@ You may *only* respond to questions related to:
17
  - Cycle-based fitness and wellness programming
18
  - Contraceptive methods and reproductive health education
19
  - Hormonal syndromes or life stages (PCOS, PMDD, menopause, irregular cycles, etc.)
20
- If the user asks something unrelated (e.g., fixing a car, meal prep, unrelated illnesses, tech support), immediately respond with the following message:
21
  "I'm here to help with cycle-based fitness and contraceptive wellness. That question’s outside my scope, but I’d love to support you with anything related to your body, cycle, or health goals!"
22
  You must *never* attempt to answer off-topic requests, even if the user insists or rephrases. Always redirect the conversation back to wellness, hormones, fitness, or reproductive health.
23
  Style and Voice Guidelines:
@@ -27,92 +45,166 @@ Style and Voice Guidelines:
27
  - Validate the user’s experience before offering guidance (e.g., “That makes total sense—your energy might be shifting in this phase”).
28
  - Encourage autonomy by offering options, not orders.
29
  - Connect advice to real-life impact: how the cycle affects energy, mood, and performance.
30
- Core Support Areas (Scope You *Do* Cover):
31
- ------------------------------------------
32
- 1. Cycle-Based Training:
33
- - Explain hormonal phases (Menstrual, Follicular, Ovulation, Luteal).
34
- - Suggest workouts aligned to the user’s cycle and fitness level.
35
- - Adjust for users on birth control, with hormone conditions, or in life stages like menopause or postpartum.
36
- 2. Contraceptive Education:
37
- - Educate on birth control methods (pill, IUD, implant, etc.).
38
- - Explain how contraception affects workouts, mood, metabolism.
39
- - Support users interested in natural tracking or switching methods.
40
- 3. Wellness Support:
41
- - Help with stress, motivation, sleep, inflammation, and hormone-related fatigue or soreness.
42
- - Normalize fluctuations and setbacks.
43
- - Offer encouragement when users feel overwhelmed, bloated, or inconsistent.
44
  Final Boundary Rule:
45
  --------------------
46
- Strictly decline all unrelated questions. Your only purpose is cycle-aware fitness and reproductive wellness coaching. Do not give general medical, tech, cooking, legal, or life advice.
47
  """
48
- # Determine the current cycle phase
49
- def calculate_cycle_phase(start_date, end_date):
50
- today = datetime.today().date()
51
- start = datetime.strptime(start_date, "%Y-%m-%d").date()
52
- end = datetime.strptime(end_date, "%Y-%m-%d").date()
53
- cycle_length = 28
54
- days_since_start = (today - start).days
55
- if days_since_start < 0:
56
- return ":warning: Your entered period start date is in the future."
57
- day_in_cycle = days_since_start % cycle_length
58
- if day_in_cycle <= (end - start).days:
59
- return "Menstrual phase :drop_of_blood:"
60
- elif day_in_cycle <= 13:
61
- return "Follicular phase :seedling:"
62
- elif day_in_cycle <= 16:
63
- return "Ovulation phase :dizzy:"
64
- elif day_in_cycle <= 28:
65
- return "Luteal phase :full_moon:"
66
- else:
67
- return "Unknown phase :question:"
68
- # Profile dictionary
69
- user_profile = {"name": "", "age": "", "level": "", "period_start": "", "period_end": ""}
70
- # Update profile info
71
- def save_user_profile(name, age, level, period_start, period_end):
72
- user_profile.update({
73
- "name": name,
74
- "age": age,
75
- "level": level,
76
- "period_start": period_start,
77
- "period_end": period_end
78
- })
79
- phase = calculate_cycle_phase(period_start, period_end)
80
- return f":wave: Hello {name}! Based on your last period, you're currently in the **{phase}**."
81
- # Chat function
82
- def respond(message, chat_history):
83
- if not isinstance(chat_history, list):
84
- chat_history = []
85
- # Construct prompt
86
  messages = [{"role": "system", "content": cycle_ai_prompt}]
87
- for turn in chat_history:
88
- if isinstance(turn, list) and len(turn) == 2:
89
- messages.append({"role": "user", "content": turn[0]})
90
- messages.append({"role": "assistant", "content": turn[1]})
91
  messages.append({"role": "user", "content": message})
 
 
 
 
 
 
 
 
 
 
92
  try:
93
- result = client.chat_completion(messages=messages, temperature=0.2, max_tokens=500)
94
- reply = result["choices"][0]["message"]["content"].strip()
95
  except Exception as e:
96
- reply = f":warning: There was an error: {str(e)}"
97
- chat_history.append([message, reply])
98
- return chat_history, chat_history
99
- # Interface
100
- with gr.Blocks() as app:
101
- gr.Markdown("# 🩷 Menstrual Cycle Chatbot")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  with gr.Row():
103
  with gr.Column(scale=1):
104
- gr.Markdown("### :woman_standing: Your Info")
105
- name = gr.Textbox(label="Name")
106
- age = gr.Textbox(label="Age")
107
- level = gr.Dropdown(choices=["Beginner", "Intermediate", "Expert"], label="Experience Level")
108
- start_date = gr.Textbox(label="Period Start Date (YYYY-MM-DD)")
109
- end_date = gr.Textbox(label="Period End Date (YYYY-MM-DD)")
110
- save_btn = gr.Button("Save Profile")
111
- profile_out = gr.Markdown()
 
112
  with gr.Column(scale=2):
113
- chatbot = gr.Chatbot(label="Cycle Support Chat", value=[], height=400)
114
- user_msg = gr.Textbox(placeholder="Ask me anything about your cycle…", show_label=False)
115
- send_btn = gr.Button("Send")
116
- save_btn.click(save_user_profile, inputs=[name, age, level, start_date, end_date], outputs=profile_out)
117
- send_btn.click(respond, inputs=[user_msg, chatbot], outputs=[chatbot, chatbot])
118
- app.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
 
2
  from huggingface_hub import InferenceClient
3
  import os
4
+ from sentence_transformers import SentenceTransformer
5
+ import torch
6
+ import numpy as np
7
+ from datetime import datetime, timedelta
8
+
9
+ # Load knowledge base
10
+ with open("knowledge.txt", "r", encoding="utf-8") as f:
11
+ knowledge_text = f.read()
12
+ chunks = [chunk.strip() for chunk in knowledge_text.split("\n\n") if chunk.strip()]
13
+ embedder = SentenceTransformer('all-MiniLM-L6-v2')
14
+ chunk_embeddings = embedder.encode(chunks, convert_to_tensor=True)
15
+
16
+ def get_relevant_context(query, top_k=3):
17
+ query_embedding = embedder.encode(query, convert_to_tensor=True)
18
+ query_embedding = query_embedding / query_embedding.norm()
19
+ norm_chunk_embeddings = chunk_embeddings / chunk_embeddings.norm(dim=1, keepdim=True)
20
+ similarities = torch.matmul(norm_chunk_embeddings, query_embedding)
21
+ top_k_indices = torch.topk(similarities, k=top_k).indices.cpu().numpy()
22
+ context = "\n\n".join([chunks[i]] for i in top_k_indices)
23
+ return context
24
+
25
+ client = InferenceClient("google/gemma-2-2b-it")
26
+
27
  cycle_ai_prompt = """
28
  Cycle-Aware Wellness AI Coach (Strict Enforcement Version)
29
  ==========================================================
 
35
  - Cycle-based fitness and wellness programming
36
  - Contraceptive methods and reproductive health education
37
  - Hormonal syndromes or life stages (PCOS, PMDD, menopause, irregular cycles, etc.)
38
+ If the user asks something unrelated (e.g., fixing a car, meal prep, unrelated illnesses, tech support), immediately respond with:
39
  "I'm here to help with cycle-based fitness and contraceptive wellness. That question’s outside my scope, but I’d love to support you with anything related to your body, cycle, or health goals!"
40
  You must *never* attempt to answer off-topic requests, even if the user insists or rephrases. Always redirect the conversation back to wellness, hormones, fitness, or reproductive health.
41
  Style and Voice Guidelines:
 
45
  - Validate the user’s experience before offering guidance (e.g., “That makes total sense—your energy might be shifting in this phase”).
46
  - Encourage autonomy by offering options, not orders.
47
  - Connect advice to real-life impact: how the cycle affects energy, mood, and performance.
48
+ When the user asks about workouts, always ask a follow-up:
49
+ "What kind of equipment or space do you have access to—like a gym, home weights, or just bodyweight? I’ll tailor a workout for you based on that!"
 
 
 
 
 
 
 
 
 
 
 
 
50
  Final Boundary Rule:
51
  --------------------
52
+ Strictly decline all unrelated questions. Your only purpose is cycle-aware fitness and reproductive wellness coaching. Do not give general medical, tech, cooking, legal, or life advice.
53
  """
54
+
55
+ def determine_cycle_phase(start_date_str):
56
+ try:
57
+ start_date = datetime.strptime(start_date_str, "%Y-%m-%d")
58
+ days_since = (datetime.now() - start_date).days % 28
59
+ if days_since < 5:
60
+ return "Menstrual Phase", "💗 Time to rest and recover. Gentle movement like stretching or walking is great."
61
+ elif days_since < 13:
62
+ return "Follicular Phase", "💪 Your energy’s building—go for strength training or cardio!"
63
+ elif days_since < 16:
64
+ return "Ovulation Phase", "🔥 Peak power! Try high-intensity workouts or social activities."
65
+ else:
66
+ return "Luteal Phase", "🌙 Wind down. Opt for lighter training, yoga, or bodyweight exercises."
67
+ except:
68
+ return "Unknown Phase", "Couldn't parse the date. Please use YYYY-MM-DD."
69
+
70
+ def respond(message, history):
71
+ if not isinstance(history, list):
72
+ history = []
73
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  messages = [{"role": "system", "content": cycle_ai_prompt}]
75
+ for entry in history:
76
+ if isinstance(entry, dict):
77
+ messages.append(entry)
 
78
  messages.append({"role": "user", "content": message})
79
+
80
+ response = client.chat_completion(
81
+ messages,
82
+ max_tokens=500,
83
+ temperature=0.1
84
+ )
85
+
86
+ print("DEBUG RESPONSE:", response) # <-- Add this to inspect
87
+
88
+ # Now adapt based on actual response
89
  try:
90
+ assistant_reply = response['choices'][0]['message']['content'].strip()
 
91
  except Exception as e:
92
+ assistant_reply = f"⚠️ There was an error processing the response: {e}"
93
+
94
+ new_history = history + [
95
+ {"role": "user", "content": message},
96
+ {"role": "assistant", "content": assistant_reply}
97
+ ]
98
+ return new_history, new_history, ""
99
+
100
+ def update_chatbot(user_message, history):
101
+ return respond(user_message, history)
102
+
103
+ def set_user_info(name, age, level, period_start_date, period_end_date):
104
+ phase, tip = determine_cycle_phase(period_start_date)
105
+ greeting = f"Hi {name}! I'm here to help you with cycle-aware fitness and wellness.\n\nYou’re {age} years old, training at a {level.lower()} level, and your last period started on {period_start_date} and ended on {period_end_date}.\n\nRight now, you’re likely in your **{phase}**. {tip} 💞\n\nAsk me anything about your body, cycle, or contraceptive health!"
106
+ return name, [{"role": "assistant", "content": greeting}]
107
+
108
+ def button_click(question, history):
109
+ new_history, updated_history, _ = respond(question, history)
110
+ return new_history, updated_history
111
+
112
+ with gr.Blocks(
113
+ css="""
114
+ .gradio-container {
115
+ background: linear-gradient(135deg, #F6D365 0%, #FDA085 50%, #FF8FA0 100%);
116
+ font-family: 'Quicksand', sans-serif;
117
+ }
118
+ .message.user {
119
+ background-color: lightpink;
120
+ border-radius: 20px;
121
+ padding: 10px;
122
+ margin: 5px;
123
+ max-width: 75%;
124
+ align-self: flex-end;
125
+ }
126
+ .message.bot {
127
+ background-color: #FFE4D1;
128
+ border-radius: 20px;
129
+ padding: 10px;
130
+ margin: 5px;
131
+ max-width: 75%;
132
+ align-self: flex-start;
133
+ }
134
+ .chat-interface {
135
+ background-color: peachpuff;
136
+ border-radius: 12px;
137
+ padding: 15px;
138
+ box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
139
+ }
140
+ #banner-image {
141
+ background-color: transparent;
142
+ margin-bottom: -100px;
143
+ margin-top: -100px;
144
+ }
145
+ """,
146
+ theme=gr.themes.Soft(
147
+ primary_hue="pink",
148
+ secondary_hue="orange",
149
+ neutral_hue="yellow",
150
+ spacing_size="lg",
151
+ radius_size="lg",
152
+ font=[gr.themes.GoogleFont("Quicksand"), "sans-serif"],
153
+ font_mono=[gr.themes.GoogleFont("IBM Plex Mono"), "monospace"]
154
+ )
155
+ ) as demo:
156
+ gr.Image(
157
+ value="Untitled design.png",
158
+ show_label=False,
159
+ show_share_button = False,
160
+ show_download_button = False,
161
+ elem_id="banner-image")
162
+
163
+ name_state = gr.State("")
164
+ chat_history = gr.State([])
165
+
166
  with gr.Row():
167
  with gr.Column(scale=1):
168
+ gr.Markdown("### Tell me about yourself")
169
+ name_input = gr.Textbox(label="Name", placeholder="Your name…")
170
+ age_input = gr.Textbox(label="Age", placeholder="Your age…")
171
+ level_input = gr.Dropdown(choices=["Beginner", "Intermediate", "Expert"], label="Training Level")
172
+ period_start_input = gr.Textbox(label="Last Period Start Date", placeholder="YYYY-MM-DD")
173
+ period_end_input = gr.Textbox(label="Last Period End Date", placeholder="YYYY-MM-DD")
174
+ set_btn = gr.Button("Set Info")
175
+ gr.Markdown("_After the greeting appears, start chatting →_")
176
+
177
  with gr.Column(scale=2):
178
+ chatbot = gr.Chatbot(label="Chat", type="messages")
179
+ user_text = gr.Textbox(placeholder="Ask me something…", label="")
180
+ with gr.Row():
181
+ workout_btn = gr.Button("Prompt: Workouts")
182
+ contraceptive_btn = gr.Button("Prompt: Contraceptives")
183
+
184
+ set_btn.click(
185
+ fn=set_user_info,
186
+ inputs=[name_input, age_input, level_input, period_start_input, period_end_input],
187
+ outputs=[name_state, chatbot],
188
+ show_progress=False,
189
+ )
190
+
191
+ user_text.submit(
192
+ fn=update_chatbot,
193
+ inputs=[user_text, chat_history],
194
+ outputs=[chatbot, chat_history, user_text]
195
+ )
196
+
197
+ workout_btn.click(
198
+ fn=lambda history: button_click("What workout routine would you recommend based on my cycle phase?", history),
199
+ inputs=[chat_history],
200
+ outputs=[chatbot, chat_history]
201
+ )
202
+
203
+ contraceptive_btn.click(
204
+ fn=lambda history: button_click("Can you explain the different contraceptive options and their benefits?", history),
205
+ inputs=[chat_history],
206
+ outputs=[chatbot, chat_history]
207
+ )
208
+
209
+ if __name__ == '__main__':
210
+ demo.launch()