fatmata commited on
Commit
3b4afa3
·
verified ·
1 Parent(s): 7a138f5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +133 -73
app.py CHANGED
@@ -1,99 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
- import random
3
- from textblob import TextBlob
4
-
5
- # ========= Fonctions utilitaires =========
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
  def detect_language(text):
8
- """Détecte la langue du texte"""
9
- blob = TextBlob(text)
10
- return blob.detect_language()
11
-
12
- def translate(text, target_lang="en"):
13
- """Traduit le texte vers target_lang"""
14
- blob = TextBlob(text)
15
  try:
16
- return str(blob.translate(to=target_lang))
17
- except Exception:
18
- return text # si la traduction échoue, on garde le texte original
19
-
20
- def predict(text):
21
- """Détection simple de l'intention (recherche ou discussion)"""
22
- keywords = ["cherche", "recherche", "trouve", "information", "wikipedia", "google"]
23
- if any(word in text.lower() for word in keywords):
24
- return "recherche"
25
- return "discussion"
26
 
27
- def search_duckduckgo(query):
28
- """Simule une recherche (à remplacer par vrai moteur si besoin)"""
29
- return [f"Résultat fictif pour : {query}"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
  def classify_emotion(text):
32
- """Détection simple des émotions (fake, à remplacer par vrai modèle)"""
33
- emotions = ["joy", "sadness", "anger", "fear", "neutral"]
34
- emotion = random.choice(emotions)
35
- compound = random.randint(-100, 100)
36
- is_unacceptable = "!" in text or "stupide" in text.lower()
37
- return compound, is_unacceptable, emotion
38
-
39
- def generate_response(text):
40
- """Réponse GPT fictive remplacer par ton modèle GPT)"""
41
- responses = [
42
- "Je comprends ce que tu ressens.",
43
- "Peux-tu m’en dire plus ?",
44
- "Ça a l’air difficile, je suis là pour t’écouter.",
45
- "Merci de partager ça avec moi."
46
- ]
47
- return random.choice(responses)
48
-
49
- # ========= Fonction principale =========
50
 
51
  def classify_and_respond(text):
52
- """Pipeline complet : détection intention → émotion → réponse"""
53
  original_lang = detect_language(text)
54
  text_en = translate(text, "en")
55
 
56
- steps = []
57
  category = predict(text_en)
58
- steps.append("Intention détectée")
59
-
60
  if category == "recherche":
61
- steps.append("Recherche externe")
62
  response = search_duckduckgo(text_en)
63
- return {
64
- "response": "\n".join([translate(r, original_lang) for r in response]),
65
- "response_type": "recherche",
66
- "emotions": None,
67
- "steps": steps
68
- }
69
 
70
  compound, is_unacceptable, emotion = classify_emotion(text_en)
71
- steps.append(f"Émotion détectée : {emotion}")
72
-
73
  if is_unacceptable and abs(compound) > 50:
74
- steps.append("Message non acceptable")
75
- return {
76
- "response": translate("Je ressens beaucoup de tension dans votre message.", original_lang),
77
- "response_type": "non acceptable",
78
- "emotions": emotion,
79
- "steps": steps
80
- }
81
-
82
- steps.append("Génération GPT")
83
- gpt_response = generate_response(text_en)
84
- return {
85
- "response": translate(gpt_response, original_lang),
86
- "response_type": "gpt",
87
- "emotions": emotion,
88
- "steps": steps
89
- }
90
 
91
- # ========= Interface Gradio =========
 
92
 
 
93
  iface = gr.Interface(
94
  fn=classify_and_respond,
95
  inputs=gr.Textbox(lines=2, placeholder="Écris ton message..."),
96
- outputs="json", # 🔴 renvoie un JSON structuré pour le frontend
97
  title="PsyBot",
98
  description="Chatbot psychologue multilingue basé sur GPT + BERT + MiniBERT"
99
  )
 
1
+ Hugging Face's logo
2
+ Hugging Face
3
+ Models
4
+ Datasets
5
+ Spaces
6
+ Community
7
+ Docs
8
+ Pricing
9
+
10
+
11
+
12
+ Spaces:
13
+
14
+ fatmata
15
+ /
16
+ psybot-backende
17
+
18
+
19
+ like
20
+ 0
21
+
22
+ App
23
+ Files
24
+ Community
25
+ Settings
26
+ psybot-backende
27
+ /
28
+ app.py
29
+
30
+ fatmata's picture
31
+ fatmata
32
+ Update app.py
33
+ 5e65e37
34
+ verified
35
+ 28 minutes ago
36
+ raw
37
+
38
+ Copy download link
39
+ history
40
+ blame
41
+ edit
42
+ delete
43
+
44
+ 4.49 kB
45
  import gradio as gr
46
+ from transformers import AutoTokenizer, AutoModelForCausalLM, AutoModelForSequenceClassification
47
+ import torch
48
+ import torch.nn.functional as F
49
+ from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
50
+ from mtranslate import translate
51
+ from langdetect import detect
52
+ from duckduckgo_search import DDGS
53
+ import re
54
+
55
+ # === Nettoyage texte ===
56
+ def clean_response(text):
57
+ text = re.sub(r'<[^>]+>', '', text)
58
+ text = re.split(r'</(Bot|name|opinion|User|[a-zA-Z]*)>', text)[0]
59
+ text = re.sub(r'^\s*[,.:;-]*', '', text)
60
+ text = re.sub(r'^\s*(Psyche|Therapist|Bot|Assistant|AI):?\s*', '', text)
61
+ text = re.sub(r'\([^)]*\)', '', text)
62
+ text = re.sub(r'\[.*?\]', '', text)
63
+ text = re.sub(r'[:;=8][-~]?[)D(\\/*|]', '', text)
64
+ text = re.sub(r'\s{2,}', ' ', text).strip()
65
+ sentences = re.split(r'(?<=[.!?])\s+', text)
66
+ return " ".join(sentences[:2]).strip()
67
+
68
+ # === Charger modèles ===
69
+ MODEL_PATH = "fatmata/gpt-psybot"
70
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH, use_fast=False)
71
+ model = AutoModelForCausalLM.from_pretrained(MODEL_PATH)
72
+
73
+ BERT_MODEL_NAME = "fatmata/bert_model"
74
+ bert_tokenizer = AutoTokenizer.from_pretrained(BERT_MODEL_NAME)
75
+ bert_model = AutoModelForSequenceClassification.from_pretrained(BERT_MODEL_NAME)
76
+
77
+ CLASSIFIER_PATH = "fatmata/mini_bert"
78
+ model_c = AutoModelForSequenceClassification.from_pretrained(CLASSIFIER_PATH)
79
+ tokenizer_c = AutoTokenizer.from_pretrained(CLASSIFIER_PATH)
80
+
81
+ # === Analyse émotion ===
82
+ analyzer = SentimentIntensityAnalyzer()
83
+ GOEMOTIONS_LABELS = ["admiration","anger","approval","autre","curiosity",
84
+ "disapproval","gratitude","joy","love","neutral","sadness"]
85
+ UNACCEPTABLE_EMOTIONS = {"anger"}
86
 
87
  def detect_language(text):
 
 
 
 
 
 
 
88
  try:
89
+ detected_lang = detect(text)
90
+ return detected_lang if detected_lang in ["fr", "en", "ar"] else "en"
91
+ except:
92
+ return "en"
 
 
 
 
 
 
93
 
94
+ def search_duckduckgo(query, max_results=3):
95
+ try:
96
+ search_results = list(DDGS().text(query, max_results=max_results))
97
+ return [result["body"] for result in search_results if "body" in result] or ["Pas trouvé."]
98
+ except Exception as e:
99
+ return [f"Erreur recherche : {str(e)}"]
100
+
101
+ def generate_response(user_input):
102
+ prompt = f"User: {user_input}\nBot:"
103
+ inputs = tokenizer(prompt, return_tensors="pt")
104
+ output = model.generate(
105
+ input_ids=inputs["input_ids"],
106
+ max_new_tokens=150,
107
+ pad_token_id=tokenizer.eos_token_id,
108
+ eos_token_id=tokenizer.eos_token_id,
109
+ do_sample=True,
110
+ temperature=0.7,
111
+ top_k=50,
112
+ top_p=0.9,
113
+ repetition_penalty=1.2
114
+ )
115
+ generated_text = tokenizer.decode(output[0], skip_special_tokens=True)
116
+ return clean_response(generated_text.split("Bot:")[-1].strip())
117
 
118
  def classify_emotion(text):
119
+ sentiment_scores = analyzer.polarity_scores(text)
120
+ compound = sentiment_scores['compound'] * 100
121
+ inputs = bert_tokenizer(text, return_tensors="pt", truncation=True, padding=True, max_length=256)
122
+ with torch.no_grad():
123
+ logits = bert_model(**inputs).logits
124
+ probs = F.softmax(logits, dim=-1).squeeze().cpu().numpy()
125
+ top_emotion_index = probs.argmax()
126
+ top_emotion = GOEMOTIONS_LABELS[top_emotion_index]
127
+ return compound, top_emotion in UNACCEPTABLE_EMOTIONS, top_emotion
128
+
129
+ def predict(text):
130
+ inputs = tokenizer_c(text, return_tensors="pt", padding=True, truncation=True, max_length=512)
131
+ with torch.no_grad():
132
+ outputs = model_c(**inputs)
133
+ logits = outputs.logits
134
+ return "recherche" if torch.argmax(logits, dim=-1).item() == 1 else "GPT"
 
 
135
 
136
  def classify_and_respond(text):
 
137
  original_lang = detect_language(text)
138
  text_en = translate(text, "en")
139
 
 
140
  category = predict(text_en)
 
 
141
  if category == "recherche":
 
142
  response = search_duckduckgo(text_en)
143
+ return "\n".join([translate(r, original_lang) for r in response])
 
 
 
 
 
144
 
145
  compound, is_unacceptable, emotion = classify_emotion(text_en)
 
 
146
  if is_unacceptable and abs(compound) > 50:
147
+ return translate("Je ressens beaucoup de tension dans votre message.", original_lang)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
 
149
+ gpt_response = generate_response(text_en)
150
+ return translate(gpt_response, original_lang)
151
 
152
+ # === Interface Gradio ===
153
  iface = gr.Interface(
154
  fn=classify_and_respond,
155
  inputs=gr.Textbox(lines=2, placeholder="Écris ton message..."),
156
+ outputs="text",
157
  title="PsyBot",
158
  description="Chatbot psychologue multilingue basé sur GPT + BERT + MiniBERT"
159
  )