File size: 9,147 Bytes
9be21ef
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23b0ad9
9be21ef
 
23b0ad9
 
9be21ef
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23b0ad9
 
 
 
9be21ef
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23b0ad9
9be21ef
 
 
 
23b0ad9
9be21ef
 
 
 
23b0ad9
 
 
 
 
 
 
 
 
 
9be21ef
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# models/response_generator.py

from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
import torch
from typing import List, Optional


class EmpatheticResponder:
    """
    Wrapper around a Flan-T5 model to generate short, empathetic responses
    for menstrual health conversations.
    """

    def __init__(
        self,
        model_name: str = "google/flan-t5-base",
        device: Optional[str] = None,
    ):
        print("[EmpatheticResponder] Loading model... This may take a moment the first time.")
        self.tokenizer = AutoTokenizer.from_pretrained(model_name)
        self.model = AutoModelForSeq2SeqLM.from_pretrained(model_name)

        if device is None:
            self.device = "cuda" if torch.cuda.is_available() else "cpu"
        else:
            self.device = device

        self.model.to(self.device)
        print(f"[EmpatheticResponder] Model loaded on {self.device}.")

    # ------------------------------------------------------------------

    def _build_prompt(
        self,
        user_message: str,
        emotions: Optional[List[str]] = None,
        retrieved_context: Optional[str] = None,
    ) -> str:
        """
        Build an instruction-style prompt + examples so Flan-T5
        behaves like a warm menstrual-health helper, not a brochure.
        """
        emo_text = ", ".join(emotions) if emotions else "unknown"

        context_block = ""
        if retrieved_context and retrieved_context.strip():
            context_block = f"""
KNOWLEDGE BASE CONTEXT
- Use the context below only if it is relevant to the user's message.
- Prefer these facts over guessing.
- Answer the user's main question first, then use only the most relevant facts.
- If the context does not answer the question, say that simply and give safe general guidance.
- Do not quote the context or mention a knowledge base.
- Do not copy the context line by line.
- Ignore parts of the context that do not clearly help with the user's question.

Context:
{retrieved_context.strip()}
"""

        prompt = f"""
You are *EmpowerHer*, a kind, emotionally supportive menstrual-health helper for teenage girls.

IMPORTANT STYLE RULES
- Talk directly to the girl as "you" and "I".
- Do NOT describe yourself, the chatbot, the app, T-shirts, privacy policy, or your goals.
- Do NOT say things like "EmpowerHer is..." or "EmpowerHer does not recognize your privacy".
- Do NOT talk about programming, AI, or being a bot.
- Focus only on her feelings, her body, and gentle guidance.
- No medical diagnosis or medicine names. Use only general, safe advice.
- Use 2-4 short, simple sentences in easy English.
- Answer the main concern in the first sentence.
- Do not repeat the same idea twice.
- Do not list too many facts in one reply.
- If the message is unrelated to menstrual health, periods, symptoms, moods, or calming support, politely say you mainly help with menstrual health topics and invite a related question.
{context_block}

EXAMPLE 1
User message: "I'm scared because my period is late."
Detected emotions: fear, anxiety
EmpowerHer: "It's completely understandable to feel scared when your period is later than you expected. Periods can sometimes be a bit early or late because of stress, changes in routine, or hormones. Try to notice if there are any other worrying symptoms, and if you feel very unsure, it's a good idea to talk with a trusted adult or a doctor. You don't have to handle this worry by yourself."

EXAMPLE 2
User message: "I have heavy cramps and I'm worried."
Detected emotions: sadness, anxiety
EmpowerHer: "Cramps can be really painful, and it makes sense that you feel worried. Many girls get strong cramps during their period, and gentle heat, rest, and drinking water can sometimes help. If the pain is very strong, lasts many days, or stops you from doing normal things, you can talk to a parent, school nurse, or doctor. You deserve support and not to suffer in silence."

EXAMPLE 3
User message: "I feel very angry and sad before my period."
Detected emotions: anger, sadness
EmpowerHer: "Feeling angry or sad before your period is very common and is often related to hormone changes. Your emotions are valid, and it's okay to say that you're not feeling like yourself. It might help to write your feelings down, listen to calming music, or talk to someone you trust. If these mood changes feel too strong, a doctor or counsellor can help you find ways to cope."

EXAMPLE 4
User message: "I didn't get my period this month."
Detected emotions: worry, anxiety
EmpowerHer: "It is understandable to feel worried when your period is late. Stress, changes in routine, and hormones can all affect timing. If you have strong pain, heavy bleeding, fever, or feel very unwell, please talk to a trusted adult or a doctor. I am here with you, and you are not alone."

EXAMPLE 5
User message: "My cramps are so bad I can't sleep."
Detected emotions: pain, sadness
EmpowerHer: "That sounds really painful, and it makes sense you are struggling. Gentle heat, rest, and slow breathing can sometimes help a little. If the pain is very strong, lasts many days, or stops you from doing normal things, please talk to a trusted adult or a doctor. You deserve relief and support."

EXAMPLE 6
User message: "I have brown spotting and I'm scared."
Detected emotions: fear, anxiety
EmpowerHer: "It's understandable to feel scared when you notice something new. Light spotting can happen for different reasons and can be normal for some girls. If the bleeding is heavy, you have strong pain, fever, or feel unwell, please talk to a trusted adult or a clinic. I am here with you."

EXAMPLE 7
User message: "I feel itchy and there is a bad smell."
Detected emotions: worry, disgust
EmpowerHer: "That sounds uncomfortable and worrying. Changes in smell or itching can happen for different reasons, and it is okay to ask for help. Try to keep the area clean and dry, and avoid strong soaps. If the itching or smell continues, please talk to a trusted adult or a clinic."

EXAMPLE 8
User message: "I love when my family supports me quietly and kindly."
Detected emotions: love, gratitude
EmpowerHer: "That sounds really comforting and caring. You deserve that kind of support. If you want to share more about how you are feeling, I am here to listen."

EXAMPLE 9
User message: "I just realized drinking water helps me feel better."
Detected emotions: realization, relief
EmpowerHer: "That is a great discovery, and it is good to notice what helps your body. Drinking water can support you during your period. If you want, tell me what else has been helping you feel better."

EXAMPLE 10
User message: "I love you"
Detected emotions: love
EmpowerHer: "I am here mainly to help with menstrual health, periods, symptoms, moods, and calm support. If you want, ask me something related to menstrual health or how you are feeling."

EXAMPLE 11
User message: "for 10 days"
Detected emotions: worry
EmpowerHer: "If your period has been late for 10 days, it can happen because of stress, illness, sleep changes, or hormone shifts. If you also have strong pain, heavy bleeding, dizziness, or fever, please talk to a trusted adult or a doctor."

NOW ANSWER FOR A NEW GIRL

User message: "{user_message}"
Detected emotions: {emo_text}
EmpowerHer:
        """.strip()

        return prompt

    # ------------------------------------------------------------------

    def generate(
        self,
        user_message: str,
        emotions: Optional[List[str]] = None,
        retrieved_context: Optional[str] = None,
        max_new_tokens: int = 120,
    ) -> str:
        """
        Generate an empathetic response for the given message and emotion list.
        """
        if not user_message or not user_message.strip():
            return "I'm here to listen whenever you'd like to share how you're feeling."

        prompt = self._build_prompt(user_message, emotions, retrieved_context)

        inputs = self.tokenizer(
            prompt,
            return_tensors="pt",
            truncation=True,
            max_length=512,
        ).to(self.device)

        pad_id = self.tokenizer.pad_token_id
        if pad_id is None:
            pad_id = self.tokenizer.eos_token_id

        output_ids = self.model.generate(
            **inputs,
            max_new_tokens=max_new_tokens,
            do_sample=False,
            num_beams=4,
            repetition_penalty=1.15,
            no_repeat_ngram_size=3,
            pad_token_id=pad_id,
        )

        response = self.tokenizer.decode(output_ids[0], skip_special_tokens=True).strip()

        # Clean up if the model starts with "EmpowerHer:"
        if response.lower().startswith("empowerher:"):
            response = response[len("EmpowerHer:"):].lstrip()

        return response


# Simple test
if __name__ == "__main__":
    responder = EmpatheticResponder()

    test_message = "I'm really scared because my period is very late and I don't know if this is normal."
    test_emotions = ["anxiety", "fear"]

    reply = responder.generate(test_message, test_emotions)
    print("\nUSER :", test_message)
    print("BOT  :", reply)