hrlima commited on
Commit
d051bb2
·
verified ·
1 Parent(s): 1a42244

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +81 -126
app.py CHANGED
@@ -3,16 +3,11 @@ import json
3
  import firebase_admin
4
  from firebase_admin import credentials, firestore
5
  from flask import Flask, request, jsonify
6
- from transformers import pipeline, AutoProcessor, AutoModelForAudioClassification
7
- import torch
8
- import librosa
9
- import numpy as np
10
 
11
  app = Flask(__name__)
12
 
13
- # ============================================================
14
- # 1) CONFIGURAÇÃO FIREBASE
15
- # ============================================================
16
  try:
17
  firebase_key = os.getenv("FIREBASE_KEY")
18
  if firebase_key:
@@ -22,35 +17,19 @@ try:
22
  db = firestore.client()
23
  print("✅ Firebase conectado com sucesso.")
24
  else:
25
- print("⚠️ FIREBASE_KEY não encontrada.")
26
  except Exception as e:
27
  print(f"❌ Erro ao inicializar Firebase: {e}")
28
 
29
- # ============================================================
30
- # 2) CARREGAMENTO DO MODELO DE TEXTO (JÁ EXISTENTE)
31
- # ============================================================
32
  try:
33
  model_pipeline = pipeline("text-classification", model="pysentimiento/robertuito-emotion-analysis")
34
- print("✅ Modelo de texto carregado com sucesso!")
35
  except Exception as e:
36
- print(f"❌ Erro ao carregar modelo de texto: {e}")
37
  model_pipeline = None
38
 
39
- # ============================================================
40
- # 3) CARREGAMENTO DO MODELO DE ÁUDIO
41
- # ============================================================
42
- try:
43
- audio_processor = AutoProcessor.from_pretrained("superb/wav2vec2-base-superb-ks")
44
- audio_model = AutoModelForAudioClassification.from_pretrained("superb/wav2vec2-base-superb-ks")
45
- print("🎤 Modelo de áudio carregado com sucesso!")
46
- except Exception as e:
47
- print(f"❌ Erro ao carregar modelo de áudio: {e}")
48
- audio_processor = None
49
- audio_model = None
50
-
51
- # ============================================================
52
- # 4) MAPEAMENTO DE EMOÇÕES (TEXTO + ÁUDIO)
53
- # ============================================================
54
  emotion_labels = {
55
  "sadness": "tristeza",
56
  "joy": "alegria",
@@ -61,105 +40,77 @@ emotion_labels = {
61
  "others": "neutro"
62
  }
63
 
64
- # ============================================================
65
- # 5) SUGESTÕES
66
- # ============================================================
67
  def gerar_sugestao(emotion_pt):
68
- mensagens = {
69
- "tristeza": "Procure um momento de autocuidado, respire fundo e busque apoio.",
70
- "depressão": "Considere conversar com alguém de confiança ou buscar apoio profissional.",
71
- "alegria": "Que ótimo! Mantenha-se aproveitando esse momento positivo.",
72
- "raiva": "Afaste-se da situação e procure se acalmar antes de agir.",
73
- "ansiedade": "Tente identificar o motivo da ansiedade e respire profundamente.",
74
- "insegurança": "Ganhe confiança focando no que você pode controlar.",
75
- "neutro": "Mantenha o equilíbrio emocional e cuide de si mesmo."
 
76
  }
77
- return mensagens.get(emotion_pt, "Cuide de si mesmo e busque equilíbrio emocional.")
78
 
79
- # ============================================================
80
- # 6) FALLBACK DE PALAVRAS-CHAVE (TEXTO)
81
- # ============================================================
82
  EMOTION_KEYWORDS = {
83
- "tristeza": ["triste","desanimado","melancólico","chateado","solitário","abatido","infeliz"],
84
- "ansiedade": ["ansioso","preocupado","nervoso","tenso","inquieto","aflito"],
85
- "insegurança": ["inseguro","receoso","hesitante","duvidoso"],
86
- "raiva": ["irritado","zangado","raiva","furioso","ódio","revoltado","bravo"],
87
- "alegria": ["feliz","contente","animado","alegre","satisfeito","entusiasmado"],
88
- "depressão": ["vazio","sem esperança","desesperado","desamparado"],
89
- "neutro": ["ok","normal","tranquilo","indiferente"]
90
  }
91
 
92
- def fallback_emotion():
 
 
 
 
 
93
  return {
94
  "status": "fallback",
95
- "emotion": "neutro",
96
- "confidence": 0.3,
97
- "suggestion": gerar_sugestao("neutro"),
98
- "debug": "Fallback ativado - Sem modelo"
 
99
  }
100
 
101
- # ============================================================
102
- # 7) PROCESSAMENTO DE ÁUDIO
103
- # ============================================================
104
- def analyze_audio_file(filepath):
105
- try:
106
- # Carrega áudio com 16kHz (esperado pelo modelo)
107
- audio, sr = librosa.load(filepath, sr=16000)
108
- inputs = audio_processor(audio, sampling_rate=16000, return_tensors="pt")
109
-
110
- with torch.no_grad():
111
- outputs = audio_model(**inputs)
112
-
113
- logits = outputs.logits
114
- predicted_class_id = logits.argmax().item()
115
-
116
- label = audio_model.config.id2label[predicted_class_id]
117
-
118
- # Simplificação: considera "surprise" como "alegria"
119
- emotion = emotion_labels.get(label, "neutro")
120
-
121
- confidence = float(torch.softmax(logits, dim=1)[0][predicted_class_id].item())
122
-
123
- return {
124
- "status": "ok",
125
- "emotion": emotion,
126
- "confidence": round(confidence, 2),
127
- "probabilities": {emotion: confidence},
128
- "suggestion": gerar_sugestao(emotion)
129
- }
130
-
131
- except Exception as e:
132
- print("Erro ao processar áudio:", e)
133
- return fallback_emotion()
134
-
135
- # ============================================================
136
- # 8) ENDPOINT DE ÁUDIO – NOVO
137
- # ============================================================
138
- @app.route("/analyze-audio", methods=["POST"])
139
- def analyze_audio():
140
- try:
141
- if 'audio' not in request.files:
142
- return jsonify({"error": "Arquivo de áudio é obrigatório."}), 400
143
-
144
- file = request.files['audio']
145
- filepath = "temp_audio.wav"
146
- file.save(filepath)
147
-
148
- result = analyze_audio_file(filepath)
149
 
150
- # Remove arquivo temporário
151
- os.remove(filepath)
 
 
 
 
152
 
153
- return jsonify(result)
 
 
 
154
 
155
- except Exception as e:
156
- return jsonify({"error": str(e)}), 500
 
 
 
 
 
 
 
157
 
158
- # ============================================================
159
- # 9) ENDPOINT ORIGINAL DE TEXTO
160
- # ============================================================
161
  @app.route("/analyze", methods=["POST"])
162
- def analyze_text():
163
  try:
164
  data = request.get_json()
165
  if not data or "text" not in data:
@@ -168,32 +119,36 @@ def analyze_text():
168
  text = data["text"]
169
 
170
  if not model_pipeline:
171
- return jsonify(fallback_emotion())
172
 
173
- model_result = model_pipeline(text, return_all_scores=True)
174
- if not model_result:
175
- return jsonify(fallback_emotion())
176
 
177
- scores = {r["label"]: r["score"] for r in model_result[0]}
178
  top_label = max(scores, key=scores.get)
179
- emotion_pt = emotion_labels.get(top_label, "neutro")
180
-
181
  confidence = round(scores[top_label], 2)
 
 
 
 
 
182
 
183
- return jsonify({
184
  "status": "ok",
185
  "emotion": emotion_pt,
 
186
  "confidence": confidence,
187
- "probabilities": {emotion_pt: confidence},
188
  "suggestion": gerar_sugestao(emotion_pt)
189
- })
 
 
 
 
190
 
191
  except Exception as e:
192
  return jsonify({"error": str(e)}), 500
193
 
194
-
195
- # ============================================================
196
- # 10) INICIAR SERVIDOR
197
- # ============================================================
198
  if __name__ == "__main__":
199
  app.run(host="0.0.0.0", port=7860)
 
3
  import firebase_admin
4
  from firebase_admin import credentials, firestore
5
  from flask import Flask, request, jsonify
6
+ from transformers import pipeline
 
 
 
7
 
8
  app = Flask(__name__)
9
 
10
+ # ====== CONFIGURAÇÃO FIREBASE ======
 
 
11
  try:
12
  firebase_key = os.getenv("FIREBASE_KEY")
13
  if firebase_key:
 
17
  db = firestore.client()
18
  print("✅ Firebase conectado com sucesso.")
19
  else:
20
+ print("⚠️ FIREBASE_KEY não encontrada nos secrets do Space.")
21
  except Exception as e:
22
  print(f"❌ Erro ao inicializar Firebase: {e}")
23
 
24
+ # ====== MODELO ======
 
 
25
  try:
26
  model_pipeline = pipeline("text-classification", model="pysentimiento/robertuito-emotion-analysis")
27
+ print("✅ Modelo carregado com sucesso!")
28
  except Exception as e:
29
+ print(f"❌ Erro ao carregar modelo: {e}")
30
  model_pipeline = None
31
 
32
+ # ====== MAPEAMENTO DE EMOÇÕES ======
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  emotion_labels = {
34
  "sadness": "tristeza",
35
  "joy": "alegria",
 
40
  "others": "neutro"
41
  }
42
 
43
+ # ====== SUGESTÕES ======
 
 
44
  def gerar_sugestao(emotion_pt):
45
+ sugestoes = {
46
+ "tristeza": "Procure fazer algo que te acalme e traga conforto emocional.",
47
+ "depressão": "Você não está sozinho. Considere conversar com alguém de confiança ou buscar apoio profissional.",
48
+ "alegria": "Continue aproveitando esse momento positivo e compartilhe boas energias!",
49
+ "raiva": "Afaste-se da situação e respire antes de reagir. Canalize essa energia em algo produtivo.",
50
+ "ansiedade": "Tente identificar o que está te causando ansiedade e pequenos passos para enfrentá-la.",
51
+ "insegurança": "Analise os pontos que causam insegurança e busque soluções práticas.",
52
+ "neutro": "Mantenha o equilíbrio emocional e cuide de si mesmo.",
53
+ "desconhecido": "Emoção não identificada com precisão."
54
  }
55
+ return sugestoes.get(emotion_pt, "Mantenha o equilíbrio emocional e cuide de você mesmo.")
56
 
57
+ # ====== FALLBACK APRIMORADO COM PALAVRAS-CHAVE ======
 
 
58
  EMOTION_KEYWORDS = {
59
+ "tristeza": ["triste","desanimado","melancólico","chateado","solitário","deprimido","abatido","infeliz","desmotivado"],
60
+ "ansiedade": ["ansioso","preocupado","nervoso","tenso","inquieto","aflito","alarmado","sobrecarregado","inseguro","apreensivo"],
61
+ "insegurança": ["inseguro","incerto","receoso","hesitante","duvidoso","apreensivo","desconfiado"],
62
+ "raiva": ["irritado","zangado","raiva","furioso","ódio","revoltado","frustrado","indignado","hostil","bravo","enfurecido","irado"],
63
+ "alegria": ["feliz","animado","contente","alegre","satisfeito","entusiasmado","radiante","orgulhoso","euforia"],
64
+ "depressão": ["sem esperança","vazio","desesperado","sem vontade","cansado da vida","desamparado"],
65
+ "neutro": ["ok","normal","tranquilo","indiferente","equilibrado","estável"]
66
  }
67
 
68
+ def fallback_emotion(text):
69
+ text_lower = text.lower()
70
+ match_counts = {k: sum(1 for w in v if w in text_lower) for k, v in EMOTION_KEYWORDS.items()}
71
+ emotion = max(match_counts, key=match_counts.get)
72
+ if match_counts[emotion] == 0:
73
+ emotion = "neutro"
74
  return {
75
  "status": "fallback",
76
+ "emotion": emotion,
77
+ "emode": [emotion],
78
+ "confidence": 0.6 if match_counts[emotion] > 0 else 0.0,
79
+ "suggestion": gerar_sugestao(emotion),
80
+ "debug": "Fallback ativado"
81
  }
82
 
83
+ # ====== AJUSTE HÍBRIDO ======
84
+ def hybrid_emotion(text, result):
85
+ text_lower = text.lower()
86
+ detected = result.get("emotion", "neutro")
87
+ max_matches = 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
 
89
+ for emo, keywords in EMOTION_KEYWORDS.items():
90
+ matches = sum(2 for w in keywords if w in text_lower)
91
+ if matches > max_matches:
92
+ max_matches = matches
93
+ if emo != detected:
94
+ detected = emo
95
 
96
+ confidence = result.get("confidence", 0.0)
97
+ if detected != result.get("emotion"):
98
+ confidence = 0.7 + max_matches * 0.05
99
+ confidence = min(confidence, 1.0)
100
 
101
+ return {
102
+ "status": "ok",
103
+ "emotion": detected,
104
+ "emode": [detected],
105
+ "confidence": round(confidence, 2),
106
+ "probabilities": result.get("probabilities", {detected: 1.0}),
107
+ "suggestion": result.get("suggestion", gerar_sugestao(detected)),
108
+ "debug": result.get("debug", "Híbrido aplicado")
109
+ }
110
 
111
+ # ====== ROTA DE ANÁLISE ======
 
 
112
  @app.route("/analyze", methods=["POST"])
113
+ def analyze():
114
  try:
115
  data = request.get_json()
116
  if not data or "text" not in data:
 
119
  text = data["text"]
120
 
121
  if not model_pipeline:
122
+ return jsonify(fallback_emotion(text))
123
 
124
+ result = model_pipeline(text, return_all_scores=True)
125
+ if not result or len(result) == 0:
126
+ return jsonify(fallback_emotion(text))
127
 
128
+ scores = {r["label"]: r["score"] for r in result[0]}
129
  top_label = max(scores, key=scores.get)
 
 
130
  confidence = round(scores[top_label], 2)
131
+ emotion_pt = emotion_labels.get(top_label, "desconhecido")
132
+
133
+ # Ajuste especial para "tristeza" muito forte
134
+ if emotion_pt == "tristeza" and confidence >= 0.9:
135
+ emotion_pt = "depressão"
136
 
137
+ base_result = {
138
  "status": "ok",
139
  "emotion": emotion_pt,
140
+ "emode": [emotion_pt],
141
  "confidence": confidence,
142
+ "probabilities": {emotion_labels.get(k, k): round(v,3) for k,v in scores.items()},
143
  "suggestion": gerar_sugestao(emotion_pt)
144
+ }
145
+
146
+ # Aplica lógica híbrida com fallback de palavras-chave
147
+ final_result = hybrid_emotion(text, base_result)
148
+ return jsonify(final_result)
149
 
150
  except Exception as e:
151
  return jsonify({"error": str(e)}), 500
152
 
 
 
 
 
153
  if __name__ == "__main__":
154
  app.run(host="0.0.0.0", port=7860)