adough commited on
Commit
ed7dc4f
·
verified ·
1 Parent(s): 06da9af

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +101 -179
app.py CHANGED
@@ -1,47 +1,25 @@
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
  ==========================================================
30
  Mission:
31
  --------
32
  You are a compassionate and knowledgeable wellness coach who specializes in fitness aligned with the menstrual cycle and evidence-based contraceptive education. Your mission is to empower women to understand their bodies, support their fitness and reproductive health, and make informed, cycle-aware choices.
33
-
34
  You may *only* respond to questions related to:
35
  - Menstrual cycles and hormonal phases
36
  - Cycle-based fitness and wellness programming
37
  - Contraceptive methods and reproductive health education
38
  - Hormonal syndromes or life stages (PCOS, PMDD, menopause, irregular cycles, etc.)
39
-
40
- If the user asks something unrelated (e.g., fixing a car, meal prep, unrelated illnesses, tech support), immediately respond with:
41
  "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!"
42
-
43
  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.
44
-
45
  Style and Voice Guidelines:
46
  ---------------------------
47
  - Speak like a friendly, knowledgeable older sister who’s also a certified personal trainer and women’s health educator.
@@ -49,170 +27,114 @@ Style and Voice Guidelines:
49
  - Validate the user’s experience before offering guidance (e.g., “That makes total sense—your energy might be shifting in this phase”).
50
  - Encourage autonomy by offering options, not orders.
51
  - Connect advice to real-life impact: how the cycle affects energy, mood, and performance.
52
-
53
- When the user asks about workouts, always ask a follow-up:
54
- "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!"
55
-
 
 
 
 
 
 
 
 
 
 
56
  Final Boundary Rule:
57
  --------------------
58
  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.
59
  """
60
-
61
- def determine_cycle_phase(start_date_str):
62
- try:
63
- start_date = datetime.strptime(start_date_str, "%Y-%m-%d")
64
- days_since = (datetime.now() - start_date).days % 28
65
- if days_since < 5:
66
- return "Menstrual Phase", "💗 Time to rest and recover. Gentle movement like stretching or walking is great."
67
- elif days_since < 13:
68
- return "Follicular Phase", "💪 Your energy’s building—go for strength training or cardio!"
69
- elif days_since < 16:
70
- return "Ovulation Phase", "🔥 Peak power! Try high-intensity workouts or social activities."
71
- else:
72
- return "Luteal Phase", "🌙 Wind down. Opt for lighter training, yoga, or bodyweight exercises."
73
- except:
74
- return "Unknown Phase", "Couldn't parse the date. Please use YYYY-MM-DD."
75
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  def respond(message, history):
77
  if not isinstance(history, list):
78
  history = []
79
-
80
  messages = [{"role": "system", "content": cycle_ai_prompt}]
81
- for entry in history:
82
- if isinstance(entry, dict):
83
- messages.append(entry)
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  messages.append({"role": "user", "content": message})
85
-
86
- response = client.chat_completion(
87
- messages,
88
- max_tokens=500,
89
- temperature=0.1
90
- )
91
-
92
- print("DEBUG RESPONSE:", response) # <-- Add this to inspect
93
-
94
- # Now adapt based on actual response
95
  try:
96
- assistant_reply = response['choices'][0]['message']['content'].strip()
 
97
  except Exception as e:
98
- assistant_reply = f"⚠️ There was an error processing the response: {e}"
99
-
100
- new_history = history + [
101
- {"role": "user", "content": message},
102
- {"role": "assistant", "content": assistant_reply}
103
- ]
104
- return new_history, new_history, ""
105
-
106
- def update_chatbot(user_message, history):
107
- return respond(user_message, history)
108
-
109
- def set_user_info(name, age, level, period_start_date, period_end_date):
110
- phase, tip = determine_cycle_phase(period_start_date)
111
- 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!"
112
- return name, [{"role": "assistant", "content": greeting}]
113
-
114
- def button_click(question, history):
115
- new_history, updated_history, _ = respond(question, history)
116
- return new_history, updated_history
117
-
118
- with gr.Blocks(
119
- css="""
120
- .gradio-container {
121
- background: linear-gradient(135deg, #F6D365 0%, #FDA085 50%, #FF8FA0 100%);
122
- font-family: 'Quicksand', sans-serif;
123
- }
124
- .message.user {
125
- background-color: lightpink;
126
- border-radius: 20px;
127
- padding: 10px;
128
- margin: 5px;
129
- max-width: 75%;
130
- align-self: flex-end;
131
- }
132
- .message.bot {
133
- background-color: #FFE4D1;
134
- border-radius: 20px;
135
- padding: 10px;
136
- margin: 5px;
137
- max-width: 75%;
138
- align-self: flex-start;
139
- }
140
- .chat-interface {
141
- background-color: peachpuff;
142
- border-radius: 12px;
143
- padding: 15px;
144
- box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
145
- }
146
-
147
- #banner-image {
148
- background-color: transparent;
149
- margin-bottom: -100px;
150
- margin-top: -100px;
151
-
152
- }
153
- """,
154
- theme=gr.themes.Soft(
155
- primary_hue="pink",
156
- secondary_hue="orange",
157
- neutral_hue="yellow",
158
- spacing_size="lg",
159
- radius_size="lg",
160
- font=[gr.themes.GoogleFont("Quicksand"), "sans-serif"],
161
- font_mono=[gr.themes.GoogleFont("IBM Plex Mono"), "monospace"]
162
- )
163
- ) as demo:
164
- gr.Image(
165
- value="Untitled design.png",
166
- show_label=False,
167
- show_share_button = False,
168
- show_download_button = False,
169
- elem_id="banner-image")
170
-
171
- name_state = gr.State("")
172
- chat_history = gr.State([])
173
-
174
  with gr.Row():
175
  with gr.Column(scale=1):
176
- gr.Markdown("### Tell me about yourself")
177
- name_input = gr.Textbox(label="Name", placeholder="Your name…")
178
- age_input = gr.Textbox(label="Age", placeholder="Your age…")
179
- level_input = gr.Dropdown(choices=["Beginner", "Intermediate", "Expert"], label="Training Level")
180
- period_start_input = gr.Textbox(label="Last Period Start Date", placeholder="YYYY-MM-DD")
181
- period_end_input = gr.Textbox(label="Last Period End Date", placeholder="YYYY-MM-DD")
182
- set_btn = gr.Button("Set Info")
183
- gr.Markdown("_After the greeting appears, start chatting →_")
184
-
185
  with gr.Column(scale=2):
186
- chatbot = gr.Chatbot(label="Chat", type="messages")
187
- user_text = gr.Textbox(placeholder="Ask me something…", label="")
188
- with gr.Row():
189
- workout_btn = gr.Button("Prompt: Workouts")
190
- contraceptive_btn = gr.Button("Prompt: Contraceptives")
191
-
192
- set_btn.click(
193
- fn=set_user_info,
194
- inputs=[name_input, age_input, level_input, period_start_input, period_end_input],
195
- outputs=[name_state, chatbot],
196
- show_progress=False,
197
- )
198
-
199
- user_text.submit(
200
- fn=update_chatbot,
201
- inputs=[user_text, chat_history],
202
- outputs=[chatbot, chat_history, user_text]
203
- )
204
-
205
- workout_btn.click(
206
- fn=lambda history: button_click("What workout routine would you recommend based on my cycle phase?", history),
207
- inputs=[chat_history],
208
- outputs=[chatbot, chat_history]
209
  )
210
-
211
- contraceptive_btn.click(
212
- fn=lambda history: button_click("Can you explain the different contraceptive options and their benefits?", history),
213
- inputs=[chat_history],
214
- outputs=[chatbot, chat_history]
215
  )
216
-
217
- if __name__ == '__main__':
218
- demo.launch()
 
1
  import gradio as gr
2
+ from datetime import datetime
3
  from huggingface_hub import InferenceClient
4
  import os
5
+ # Set your Hugging Face token and model
6
+ os.environ["HF_TOKEN"] = "your_huggingface_token_here"
7
+ client = InferenceClient("google/gemma-2b-it")
8
+ # System prompt for the assistant
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  cycle_ai_prompt = """
10
  Cycle-Aware Wellness AI Coach (Strict Enforcement Version)
11
  ==========================================================
12
  Mission:
13
  --------
14
  You are a compassionate and knowledgeable wellness coach who specializes in fitness aligned with the menstrual cycle and evidence-based contraceptive education. Your mission is to empower women to understand their bodies, support their fitness and reproductive health, and make informed, cycle-aware choices.
 
15
  You may *only* respond to questions related to:
16
  - Menstrual cycles and hormonal phases
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:
24
  ---------------------------
25
  - Speak like a friendly, knowledgeable older sister who’s also a certified personal trainer and women’s health educator.
 
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
+ # Global variables to persist across chats
49
+ user_profile = {}
50
+ chat_history = []
51
+ # Calculate cycle phase
52
+ def calculate_cycle_phase(start_date, end_date):
53
+ today = datetime.today().date()
54
+ start = datetime.strptime(start_date, "%Y-%m-%d").date()
55
+ end = datetime.strptime(end_date, "%Y-%m-%d").date()
56
+ cycle_length = 28 # Average cycle
57
+ days_since_start = (today - start).days
58
+ if days_since_start < 0:
59
+ return ":warning: Your entered period start date is in the future."
60
+ day_in_cycle = days_since_start % cycle_length
61
+ period_length = (end - start).days
62
+ if day_in_cycle <= period_length:
63
+ return "Menstrual phase :drop_of_blood:"
64
+ elif day_in_cycle <= 13:
65
+ return "Follicular phase :seedling:"
66
+ elif day_in_cycle <= 16:
67
+ return "Ovulation phase :dizzy:"
68
+ else:
69
+ return "Luteal phase :full_moon:"
70
+ # Save user 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
+ welcome = f":wave: Hi {name}! Based on your last period, you're currently in the **{phase}**.\n\nHow can I support your wellness today?"
81
+ return welcome
82
+ # Main chatbot function
83
  def respond(message, history):
84
  if not isinstance(history, list):
85
  history = []
86
+ # Build conversation with system + chat history
87
  messages = [{"role": "system", "content": cycle_ai_prompt}]
88
+ # Append user profile to context as assistant message
89
+ if user_profile:
90
+ profile_intro = (
91
+ f"User Info:\n"
92
+ f"- Name: {user_profile.get('name')}\n"
93
+ f"- Age: {user_profile.get('age')}\n"
94
+ f"- Experience Level: {user_profile.get('level')}\n"
95
+ f"- Period Start: {user_profile.get('period_start')}\n"
96
+ f"- Period End: {user_profile.get('period_end')}\n"
97
+ f"- Current Phase: {calculate_cycle_phase(user_profile.get('period_start'), user_profile.get('period_end'))}"
98
+ )
99
+ messages.append({"role": "assistant", "content": profile_intro})
100
+ for turn in history:
101
+ if isinstance(turn, list) and len(turn) == 2:
102
+ messages.append({"role": "user", "content": turn[0]})
103
+ messages.append({"role": "assistant", "content": turn[1]})
104
  messages.append({"role": "user", "content": message})
105
+ # Get response from model
 
 
 
 
 
 
 
 
 
106
  try:
107
+ response = client.chat_completion(messages=messages, max_tokens=500, temperature=0.5)
108
+ assistant_reply = response["choices"][0]["message"]["content"].strip()
109
  except Exception as e:
110
+ assistant_reply = f":warning: Something went wrong: {e}"
111
+ history.append((message, assistant_reply))
112
+ return history, ""
113
+ # Gradio UI
114
+ with gr.Blocks() as app:
115
+ gr.Markdown("# 🩷 Menstrual Cycle & Wellness Chatbot")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  with gr.Row():
117
  with gr.Column(scale=1):
118
+ gr.Markdown("### :woman_standing: Your Profile")
119
+ name = gr.Textbox(label="Name")
120
+ age = gr.Textbox(label="Age")
121
+ level = gr.Dropdown(["Beginner", "Intermediate", "Expert"], label="Experience Level")
122
+ period_start = gr.Textbox(label="Period Start Date (YYYY-MM-DD)")
123
+ period_end = gr.Textbox(label="Period End Date (YYYY-MM-DD)")
124
+ save_btn = gr.Button("Save Profile")
125
+ profile_output = gr.Markdown()
 
126
  with gr.Column(scale=2):
127
+ chatbot = gr.Chatbot(label="Cycle Chat").style(height=400)
128
+ user_msg = gr.Textbox(placeholder="Ask about your workouts, cycle, birth control, etc…")
129
+ send_btn = gr.Button("Send")
130
+ save_btn.click(
131
+ fn=save_user_profile,
132
+ inputs=[name, age, level, period_start, period_end],
133
+ outputs=profile_output
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  )
135
+ send_btn.click(
136
+ fn=respond,
137
+ inputs=[user_msg, chatbot],
138
+ outputs=[chatbot, user_msg]
 
139
  )
140
+ app.launch()