Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| from huggingface_hub import InferenceClient | |
| import random | |
| import re | |
| # ✅ Allowed mental health keywords (EN + AR + transliterated Arabic) | |
| MENTAL_KEYWORDS = [ | |
| # English | |
| "depression", "depressed", "anxiety", "anxious", "panic", "stress", "sad", "lonely", | |
| "trauma", "mental", "therapy", "therapist", "counselor", "mood", "overwhelmed", "anger", | |
| "fear", "worry", "self-esteem", "confidence", "motivation", "relationship", "cope", "coping", | |
| "relax", "calm", "sleep", "emotion", "feeling", "feel", "thoughts", "help", "life", "advice", | |
| "unmotivated", "lost", "hopeless", "tired", "burnout", "cry", "hurt", "love", "breakup", | |
| "friend", "family", "alone", "heartbroken", "scared", "fearful", | |
| # Transliterated Arabic | |
| "ana", "zahqan", "daye2", "ha2t", "mota3ab", "mota3eb", "za3lan", "malo", "khalni", "mash3or", | |
| "bakhaf", "w7ed", "msh 3aref", "mash fahem", "malish", "3ayez", "ayez", "7azeen", "mdaye2", | |
| # Arabic | |
| "حزين", "تعبان", "قلق", "خايف", "وحدة", "ضيق", "توتر", "زعلان", "اكتئاب", "علاج", | |
| "مشاعر", "مضغوط", "قلقان", "وحدي", "مش مبسوط", "زهقان", "ضايق", "تعب", "مش مرتاح", | |
| ] | |
| # ✅ Off-topic keywords (EN + AR) | |
| OFF_TOPIC = [ | |
| # English | |
| "recipe", "song", "music", "lyrics", "joke", "funny", "laugh", "code", "python", "program", | |
| "game", "food", "cook", "movie", "film", "series", "sport", "football", "instagram", | |
| "tiktok", "money", "business", "crypto", "ai", "computer", | |
| # Arabic | |
| "نكتة", "ضحك", "اغنية", "اغاني", "طبخ", "اكل", "فيلم", "مسلسل", "كورة", "رياضة", | |
| "بيزنس", "فلوس", "العاب", "لعبة", "كود", "برمجة", "ذكاء اصطناعي" | |
| ] | |
| # ✅ Random natural off-topic responses | |
| OFF_TOPIC_RESPONSES = [ | |
| "I'm here to help with emotional and mental well-being. Let's focus on how you're feeling, coping, or managing your emotions today.", | |
| "I specialize in mental and emotional health conversations. Tell me what’s been on your mind lately.", | |
| "Let’s bring it back to how you’ve been feeling — I’m here to help you talk through emotions, stress, or challenges.", | |
| "My goal is to support your mental health. How have things been emotionally for you lately?", | |
| "I’m here for emotional and mental support only. What’s been bothering you recently?", | |
| "Let's focus on your thoughts and feelings — I can help you process or manage them better.", | |
| "It sounds like you might be going off-topic. Can we talk about how you’ve been feeling instead?", | |
| "Let’s keep this space focused on your emotions and well-being. What’s been heavy on your mind lately?", | |
| ] | |
| # ✅ Detect Arabic characters | |
| def contains_arabic(text: str) -> bool: | |
| return bool(re.search(r"[\u0600-\u06FF]", text)) | |
| # ✅ Function to check if input is related to mental health | |
| def is_mental_health_related(text: str) -> bool: | |
| text_lower = text.lower() | |
| has_arabic = contains_arabic(text_lower) | |
| # If message includes off-topic Arabic or English terms → block it | |
| if any(word in text_lower for word in OFF_TOPIC): | |
| return False | |
| # If it has mental-related Arabic/English → allow | |
| if any(word in text_lower for word in MENTAL_KEYWORDS): | |
| return True | |
| # If purely Arabic but not off-topic → assume emotional (allow) | |
| if has_arabic: | |
| return True | |
| # Default fallback | |
| return False | |
| # ✅ Main response function | |
| def respond( | |
| message, | |
| history: list[dict[str, str]], | |
| system_message, | |
| max_tokens, | |
| temperature, | |
| top_p, | |
| hf_token: gr.OAuthToken, | |
| ): | |
| if not is_mental_health_related(message): | |
| yield random.choice(OFF_TOPIC_RESPONSES) | |
| return | |
| locked_system_message = ( | |
| "You are a licensed mental health therapy assistant. " | |
| "You respond with empathy, emotional intelligence, and a therapeutic tone. " | |
| "Never answer questions unrelated to emotional or mental wellness, even if they are in another language." | |
| ) | |
| client = InferenceClient(token=hf_token.token, model="openai/gpt-oss-20b") | |
| messages = [{"role": "system", "content": locked_system_message}] | |
| messages.extend(history) | |
| messages.append({"role": "user", "content": message}) | |
| response = "" | |
| for message in client.chat_completion( | |
| messages, | |
| max_tokens=max_tokens, | |
| stream=True, | |
| temperature=temperature, | |
| top_p=top_p, | |
| ): | |
| choices = message.choices | |
| token = "" | |
| if len(choices) and choices[0].delta.content: | |
| token = choices[0].delta.content | |
| response += token | |
| yield response | |
| # ✅ Gradio interface setup | |
| chatbot = gr.ChatInterface( | |
| respond, | |
| type="messages", | |
| additional_inputs=[ | |
| gr.Textbox(value="You are a friendly Chatbot.", label="System message"), | |
| gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"), | |
| gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"), | |
| gr.Slider( | |
| minimum=0.1, | |
| maximum=1.0, | |
| value=0.95, | |
| step=0.05, | |
| label="Top-p (nucleus sampling)", | |
| ), | |
| ], | |
| ) | |
| with gr.Blocks() as demo: | |
| with gr.Sidebar(): | |
| gr.LoginButton() | |
| chatbot.render() | |
| if __name__ == "__main__": | |
| demo.launch() | |