hrlima commited on
Commit
d8142e7
·
verified ·
1 Parent(s): 7480ceb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +68 -99
app.py CHANGED
@@ -1,16 +1,16 @@
1
  import os
2
  import json
3
  import firebase_admin
4
- import requests
5
  from firebase_admin import credentials, firestore
6
  from flask import Flask, request, jsonify
7
- from huggingface_hub import InferenceClient
8
-
 
9
 
10
  app = Flask(__name__)
11
 
12
  # =============================
13
- # Inicialização do Firebase
14
  # =============================
15
  firebase_key = os.getenv("FIREBASE_KEY")
16
  if not firebase_key:
@@ -28,62 +28,43 @@ except Exception as e:
28
  db = None
29
 
30
  # =============================
31
- # Inicialização do Hugging Face
32
- # =============================
33
- HF_TOKEN = os.getenv("HF_TOKEN")
34
- if not HF_TOKEN:
35
- raise RuntimeError("❌ HF_TOKEN não encontrado nos Secrets do Space.")
36
-
37
- client = InferenceClient(token=HF_TOKEN)
38
-
39
- # =============================
40
- # Função de mapeamento de emoções
41
  # =============================
42
- def map_emotion(label, score):
43
- mapping = {
44
- "joy": "alegria",
45
- "sadness": "tristeza",
46
- "anger": "raiva",
47
- "fear": "medo",
48
- "disgust": "nojo",
49
- "surprise": "surpresa",
50
- "neutral": "neutro",
51
- }
52
-
53
- # Mapeia para português
54
- emotion_pt = mapping.get(label.lower(), "neutro")
55
-
56
- # Identifica "depressão" quando tristeza for alta
57
- if emotion_pt == "tristeza" and score >= 0.60:
58
- emotion_pt = "depressão"
59
-
60
- return emotion_pt
61
 
62
  # =============================
63
- # Sugestões baseadas na emoção
64
  # =============================
65
- def get_suggestion(emotion):
66
- suggestions = {
67
- "alegria": "Continue aproveitando esse momento positivo! 😊",
68
- "tristeza": "Tente conversar com alguém de confiança. 💬",
69
- "depressão": "Você não está sozinho. Procure apoio emocional ou profissional. 💙",
70
- "raiva": "Respire fundo e tente relaxar antes de reagir. 😤",
71
- "medo": "Procure entender o que te causa medo e fale sobre isso. 💭",
72
- "nojo": "Afaste-se do que está te incomodando e busque se acalmar. 🌿",
73
- "surpresa": "Às vezes a vida nos surpreende de formas boas e ruins — reflita com calma. 🤔",
74
- "neutro": "Você parece tranquilo no momento. 🌼",
75
- }
76
- return suggestions.get(emotion, "Cuide de você mesmo hoje. ❤️")
 
 
 
 
 
77
 
78
  # =============================
79
  # Rota de teste
80
  # =============================
81
  @app.route("/")
82
  def index():
83
- return jsonify({"status": "online", "message": "API Flask funcionando com pysentimiento!"})
84
 
85
  # =============================
86
- # Rota principal de análise
87
  # =============================
88
  @app.route("/analyze", methods=["POST"])
89
  def analyze():
@@ -93,71 +74,58 @@ def analyze():
93
  return jsonify({"error": "Campo 'text' é obrigatório"}), 400
94
 
95
  text = data["text"]
96
- print(f"\n🧠 Recebido texto para análise: {text}\n")
97
-
98
- # =============================
99
- # Chamada direta à API do Hugging Face
100
- # =============================
101
- HF_MODEL = "j-hartmann/emotion-english-portuguese"
102
- HF_URL = f"https://api-inference.huggingface.co/models/{HF_MODEL}"
103
-
104
- headers = {
105
- "Authorization": f"Bearer {HF_TOKEN}",
106
- "Content-Type": "application/json"
107
- }
108
-
109
- payload = {"inputs": text}
110
-
111
- response = requests.post(HF_URL, headers=headers, json=payload)
112
- response.raise_for_status()
113
-
114
- result_json = response.json()
115
- print(f"📩 Resposta bruta do modelo:\n{json.dumps(result_json, indent=2, ensure_ascii=False)}\n")
116
-
117
- # Alguns modelos retornam [ [ {label, score}, ... ] ]
118
- # Outros apenas [ {label, score}, ... ]
119
- if isinstance(result_json, list) and isinstance(result_json[0], list):
120
- result_json = result_json[0]
121
-
122
- if not isinstance(result_json, list) or len(result_json) == 0:
123
- raise ValueError("Resposta inesperada da API Hugging Face.")
124
-
125
- # =============================
126
- # Processamento das emoções
127
- # =============================
128
- probabilities = {}
129
- for item in result_json:
130
- label = item.get("label", "").lower()
131
- score = round(float(item.get("score", 0.0)), 4)
132
- emotion_pt = map_emotion(label, score)
133
- probabilities[emotion_pt] = score
134
-
135
- dominant_emotion = max(probabilities, key=probabilities.get)
136
- suggestion = get_suggestion(dominant_emotion)
137
-
138
  result = {
139
- "status": "ok",
140
- "emotion": dominant_emotion,
141
- "emode": list(probabilities.keys()),
142
- "probabilities": probabilities,
143
  "suggestion": suggestion,
144
  }
145
 
146
- print(f"✅ Resultado final: {json.dumps(result, indent=2, ensure_ascii=False)}\n")
147
-
148
  # Salva no Firestore
149
  if db:
150
  db.collection("emotions").add({
151
  "text": text,
152
- "emotion": dominant_emotion,
153
- "probabilities": probabilities
154
  })
155
 
156
  return jsonify(result)
157
 
158
  except Exception as e:
159
  print(f"❌ Erro detalhado na rota /analyze: {e}")
160
- return jsonify({"error": str(e)}), 500
 
 
 
 
 
 
 
 
161
 
162
  # =============================
163
  # Inicialização do servidor
@@ -166,3 +134,4 @@ if __name__ == "__main__":
166
  port = int(os.environ.get("PORT", 7860))
167
  app.run(host="0.0.0.0", port=port, debug=False)
168
 
 
 
1
  import os
2
  import json
3
  import firebase_admin
 
4
  from firebase_admin import credentials, firestore
5
  from flask import Flask, request, jsonify
6
+ from transformers import AutoTokenizer, AutoModelForSequenceClassification
7
+ import torch
8
+ import torch.nn.functional as F
9
 
10
  app = Flask(__name__)
11
 
12
  # =============================
13
+ # Inicialização segura do Firebase
14
  # =============================
15
  firebase_key = os.getenv("FIREBASE_KEY")
16
  if not firebase_key:
 
28
  db = None
29
 
30
  # =============================
31
+ # Inicialização do modelo Transformers
 
 
 
 
 
 
 
 
 
32
  # =============================
33
+ MODEL_NAME = "pysentimiento/robertuito-emotion-analysis" # modelo em espanhol
34
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
35
+ model = AutoModelForSequenceClassification.from_pretrained(MODEL_NAME)
36
+ labels = model.config.id2label # mapeia ids para rótulos de emoção
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
  # =============================
39
+ # Fallback baseado em palavras-chave
40
  # =============================
41
+ fallback_map = {
42
+ "alegria": ["feliz", "contente", "satisfeito", "alegre", "animado"],
43
+ "tristeza": ["triste", "chateado", "melancólico", "desanimado"],
44
+ "depressao": ["deprimido", "sem vontade", "desesperança", "sem energia"],
45
+ "raiva": ["irritado", "zangado", "raiva", "frustrado"],
46
+ "ansiedade": ["ansioso", "preocupado", "tenso", "estressado"],
47
+ }
48
+
49
+ def fallback_emotion(text):
50
+ lower = text.lower()
51
+ detected = []
52
+ for key, words in fallback_map.items():
53
+ if any(word in lower for word in words):
54
+ detected.append(key)
55
+ if not detected:
56
+ detected = ["tristeza"]
57
+ return detected
58
 
59
  # =============================
60
  # Rota de teste
61
  # =============================
62
  @app.route("/")
63
  def index():
64
+ return jsonify({"status": "online", "message": "API Flask funcionando no Space!"})
65
 
66
  # =============================
67
+ # Rota principal de análise de emoção
68
  # =============================
69
  @app.route("/analyze", methods=["POST"])
70
  def analyze():
 
74
  return jsonify({"error": "Campo 'text' é obrigatório"}), 400
75
 
76
  text = data["text"]
77
+ print(f"🧠 Recebido texto para análise: {text}")
78
+
79
+ # Tokenização e predição
80
+ inputs = tokenizer(text, return_tensors="pt", truncation=True)
81
+ with torch.no_grad():
82
+ outputs = model(**inputs)
83
+ probs = F.softmax(outputs.logits, dim=-1).squeeze()
84
+ prob_dict = {labels[i]: round(float(probs[i]), 4) for i in range(len(labels))}
85
+
86
+ # Escolhe emoção principal
87
+ main_emotion = max(prob_dict, key=prob_dict.get)
88
+ detected = [main_emotion]
89
+
90
+ # Se nenhuma emoção significativa (prob < 0.2), fallback
91
+ if prob_dict[main_emotion] < 0.2:
92
+ detected = fallback_emotion(text)
93
+ main_emotion = detected[0]
94
+ status = "fallback"
95
+ suggestion = "Não foi possível identificar claramente a emoção. Fallback baseado em palavras-chave."
96
+ else:
97
+ status = "ok"
98
+ suggestion = "Sugestão não disponível."
99
+
100
+ # Resultado final
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  result = {
102
+ "status": status,
103
+ "emotion": main_emotion,
104
+ "emode": detected,
105
+ "probabilities": prob_dict,
106
  "suggestion": suggestion,
107
  }
108
 
 
 
109
  # Salva no Firestore
110
  if db:
111
  db.collection("emotions").add({
112
  "text": text,
113
+ **result
 
114
  })
115
 
116
  return jsonify(result)
117
 
118
  except Exception as e:
119
  print(f"❌ Erro detalhado na rota /analyze: {e}")
120
+ detected = fallback_emotion(data.get("text", "")) if data else ["tristeza"]
121
+ return jsonify({
122
+ "status": "fallback",
123
+ "emotion": detected[0],
124
+ "emode": detected,
125
+ "probabilities": {k: 0.0 for k in fallback_map.keys()},
126
+ "suggestion": "Erro na análise. Fallback baseado em palavras-chave.",
127
+ "debug": str(e)
128
+ }), 500
129
 
130
  # =============================
131
  # Inicialização do servidor
 
134
  port = int(os.environ.get("PORT", 7860))
135
  app.run(host="0.0.0.0", port=port, debug=False)
136
 
137
+