DHEIVER commited on
Commit
3e5c67c
·
verified ·
1 Parent(s): 530192f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +239 -28
app.py CHANGED
@@ -4,6 +4,11 @@ from sentence_transformers import SentenceTransformer
4
  import numpy as np
5
  from typing import Dict, List, Tuple
6
  from textblob import TextBlob
 
 
 
 
 
7
 
8
  # Load embeddings model
9
  model = SentenceTransformer('all-MiniLM-L6-v2')
@@ -131,15 +136,66 @@ class EnhancedCoach:
131
  self.historico_respostas = []
132
  self.sessao_completa = False
133
  self.tone_history = []
 
 
 
 
 
134
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  def analisar_tom(self, texto: str) -> Tuple[str, float]:
136
  """Analisa o tom predominante na resposta usando TextBlob e padrões lexicais."""
137
  texto_lower = texto.lower()
 
 
138
  blob = TextBlob(texto)
 
 
139
  tone_scores = {}
140
  for tone, patterns in TONE_PATTERNS.items():
141
  score = sum(texto_lower.count(pattern) for pattern in patterns)
 
142
  tone_scores[tone] = score * (1 + abs(blob.sentiment.polarity))
 
 
143
  predominant_tone = max(tone_scores.items(), key=lambda x: x[1])
144
  return predominant_tone[0], predominant_tone[1]
145
 
@@ -147,9 +203,11 @@ class EnhancedCoach:
147
  """Analisa o sentimento geral da resposta."""
148
  positive_words = ["consegui", "superei", "aprendi", "melhorei", "efetivo"]
149
  negative_words = ["difícil", "desafiador", "complicado", "problema", "falha"]
 
150
  texto_lower = texto.lower()
151
  positive_count = sum(1 for word in positive_words if word in texto_lower)
152
  negative_count = sum(1 for word in negative_words if word in texto_lower)
 
153
  if positive_count > negative_count:
154
  return "positive"
155
  elif negative_count > positive_count:
@@ -167,59 +225,212 @@ class EnhancedCoach:
167
  def encontrar_melhor_resposta(self, texto_usuario: str, categoria: str) -> str:
168
  sentimento = self.analisar_sentimento(texto_usuario)
169
  acao_especifica = self.extrair_acao_especifica(texto_usuario)
 
170
  respostas_categoria = RESPOSTAS_COACH[categoria][sentimento]
171
  user_embedding = model.encode(texto_usuario)
 
172
  melhor_resposta = None
173
  maior_similaridade = -1
 
174
  for template in respostas_categoria:
175
  context_embedding = model.encode(template["context"])
176
  similaridade = np.dot(user_embedding, context_embedding)
 
177
  if similaridade > maior_similaridade:
178
  maior_similaridade = similaridade
179
  melhor_resposta = template["response"]
 
180
  return melhor_resposta.format(specific_action=acao_especifica.lower())
181
 
182
  def gerar_resposta(self, texto_usuario: str) -> str:
 
 
 
 
 
 
 
 
 
 
 
 
183
  if self.sessao_completa:
184
  self.__init__()
 
185
  if self.pergunta_atual >= len(PERGUNTAS):
186
  tempo = (datetime.now() - self.inicio).seconds // 60
187
  return self.gerar_sumario_final(tempo)
 
 
188
  tom_predominante, intensidade = self.analisar_tom(texto_usuario)
189
  self.tone_history.append(tom_predominante)
 
190
  pergunta_atual = PERGUNTAS[self.pergunta_atual]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
  self.pergunta_atual += 1
192
- self.historico_respostas.append({
193
- "pergunta": pergunta_atual["pergunta"],
194
- "resposta": texto_usuario,
195
- "sentimento": self.analisar_sentimento(texto_usuario),
196
- "tom": tom_predominante
197
- })
198
- feedback = self.encontrar_melhor_resposta(texto_usuario, pergunta_atual["categoria"])
199
- return f"Resposta analisada: {feedback}\n\nPróxima pergunta: {PERGUNTAS[self.pergunta_atual]['pergunta']}" if self.pergunta_atual < len(PERGUNTAS) else feedback
200
-
201
- def gerar_sumario_final(self, tempo_total: int) -> str:
202
- summary = [f"Tonalidade predominante da sessão: {max(set(self.tone_history), key=self.tone_history.count)}."]
203
- for resposta in self.historico_respostas:
204
- summary.append(f"- Pergunta: {resposta['pergunta']}\n Resposta: {resposta['resposta']}\n Sentimento: {resposta['sentimento']}\n Tom: {resposta['tom']}\n")
205
- summary.append(f"Tempo total da sessão: {tempo_total} minutos.")
206
- self.sessao_completa = True
207
- return "\n".join(summary)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
 
 
 
209
 
210
- # Interface Gradio
211
- coach = EnhancedCoach()
212
 
213
- def interface_chat(texto_usuario):
214
- return coach.gerar_resposta(texto_usuario)
 
 
215
 
216
- demo = gr.Interface(
217
- fn=interface_chat,
218
- inputs="text",
219
- outputs="text",
220
- title="Coaching Inteligente",
221
- description="Receba perguntas personalizadas e feedback em tempo real para desenvolvimento pessoal e profissional."
222
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
 
224
  if __name__ == "__main__":
225
- demo.launch()
 
 
4
  import numpy as np
5
  from typing import Dict, List, Tuple
6
  from textblob import TextBlob
7
+ import nltk
8
+ from nltk.tokenize import sent_tokenize
9
+
10
+ # Download required NLTK data
11
+ nltk.download('punkt')
12
 
13
  # Load embeddings model
14
  model = SentenceTransformer('all-MiniLM-L6-v2')
 
136
  self.historico_respostas = []
137
  self.sessao_completa = False
138
  self.tone_history = []
139
+ self.response_quality_metrics = []
140
+
141
+ def analyze_response_quality(self, text: str) -> Dict[str, float]:
142
+ """Analyzes response quality based on multiple dimensions."""
143
+ sentences = sent_tokenize(text)
144
 
145
+ metrics = {
146
+ "depth": self._calculate_depth(text),
147
+ "clarity": self._calculate_clarity(sentences),
148
+ "specificity": self._calculate_specificity(text),
149
+ "actionability": self._calculate_actionability(sentences)
150
+ }
151
+
152
+ self.response_quality_metrics.append(metrics)
153
+ return metrics
154
+
155
+ def _calculate_depth(self, text: str) -> float:
156
+ """Measures response depth based on length and unique word usage."""
157
+ words = text.lower().split()
158
+ unique_words = len(set(words))
159
+ return min(1.0, (len(words) * unique_words) / 1000)
160
+
161
+ def _calculate_clarity(self, sentences: List[str]) -> float:
162
+ """Measures clarity based on sentence structure."""
163
+ if not sentences:
164
+ return 0.0
165
+ avg_length = sum(len(s.split()) for s in sentences) / len(sentences)
166
+ return 1.0 if 10 <= avg_length <= 20 else 0.7
167
+
168
+ def _calculate_specificity(self, text: str) -> float:
169
+ """Measures specificity based on concrete details."""
170
+ specific_indicators = ["exemplo", "especificamente", "concretamente",
171
+ "situação", "caso", "quando", "onde", "como"]
172
+ return min(1.0, sum(text.lower().count(ind) for ind in specific_indicators) / 5)
173
+
174
+ def _calculate_actionability(self, sentences: List[str]) -> float:
175
+ """Measures actionability based on action verbs and concrete steps."""
176
+ action_verbs = ["implementar", "fazer", "criar", "desenvolver", "estabelecer",
177
+ "planejar", "executar", "medir", "avaliar"]
178
+ if not sentences:
179
+ return 0.0
180
+ actionable = sum(1 for s in sentences
181
+ if any(verb in s.lower() for verb in action_verbs))
182
+ return min(1.0, actionable / len(sentences))
183
+
184
  def analisar_tom(self, texto: str) -> Tuple[str, float]:
185
  """Analisa o tom predominante na resposta usando TextBlob e padrões lexicais."""
186
  texto_lower = texto.lower()
187
+
188
+ # Análise de sentimento com TextBlob
189
  blob = TextBlob(texto)
190
+
191
+ # Contagem de padrões de tom
192
  tone_scores = {}
193
  for tone, patterns in TONE_PATTERNS.items():
194
  score = sum(texto_lower.count(pattern) for pattern in patterns)
195
+ # Normalize with TextBlob polarity
196
  tone_scores[tone] = score * (1 + abs(blob.sentiment.polarity))
197
+
198
+ # Get predominant tone
199
  predominant_tone = max(tone_scores.items(), key=lambda x: x[1])
200
  return predominant_tone[0], predominant_tone[1]
201
 
 
203
  """Analisa o sentimento geral da resposta."""
204
  positive_words = ["consegui", "superei", "aprendi", "melhorei", "efetivo"]
205
  negative_words = ["difícil", "desafiador", "complicado", "problema", "falha"]
206
+
207
  texto_lower = texto.lower()
208
  positive_count = sum(1 for word in positive_words if word in texto_lower)
209
  negative_count = sum(1 for word in negative_words if word in texto_lower)
210
+
211
  if positive_count > negative_count:
212
  return "positive"
213
  elif negative_count > positive_count:
 
225
  def encontrar_melhor_resposta(self, texto_usuario: str, categoria: str) -> str:
226
  sentimento = self.analisar_sentimento(texto_usuario)
227
  acao_especifica = self.extrair_acao_especifica(texto_usuario)
228
+
229
  respostas_categoria = RESPOSTAS_COACH[categoria][sentimento]
230
  user_embedding = model.encode(texto_usuario)
231
+
232
  melhor_resposta = None
233
  maior_similaridade = -1
234
+
235
  for template in respostas_categoria:
236
  context_embedding = model.encode(template["context"])
237
  similaridade = np.dot(user_embedding, context_embedding)
238
+
239
  if similaridade > maior_similaridade:
240
  maior_similaridade = similaridade
241
  melhor_resposta = template["response"]
242
+
243
  return melhor_resposta.format(specific_action=acao_especifica.lower())
244
 
245
  def gerar_resposta(self, texto_usuario: str) -> str:
246
+ # First, analyze response quality
247
+ quality_metrics = self.analyze_response_quality(texto_usuario)
248
+
249
+ if quality_metrics["depth"] < 0.3 or quality_metrics["specificity"] < 0.2:
250
+ return """### Feedback Inicial 💭
251
+
252
+ Para oferecer um feedback mais valioso, poderia compartilhar mais detalhes específicos sobre sua experiência?
253
+ Alguns aspectos que enriqueceriam sua reflexão:
254
+ - Exemplos concretos da situação
255
+ - Ações específicas tomadas
256
+ - Resultados observados"""
257
+
258
  if self.sessao_completa:
259
  self.__init__()
260
+
261
  if self.pergunta_atual >= len(PERGUNTAS):
262
  tempo = (datetime.now() - self.inicio).seconds // 60
263
  return self.gerar_sumario_final(tempo)
264
+
265
+ # Analyze tone
266
  tom_predominante, intensidade = self.analisar_tom(texto_usuario)
267
  self.tone_history.append(tom_predominante)
268
+
269
  pergunta_atual = PERGUNTAS[self.pergunta_atual]
270
+ self.historico_respostas.append(texto_usuario)
271
+
272
+ feedback = self.encontrar_melhor_resposta(
273
+ texto_usuario,
274
+ pergunta_atual["categoria"]
275
+ )
276
+
277
+ # Add tone-specific insights
278
+ tom_insight = self._gerar_insight_tom(tom_predominante, intensidade)
279
+ padrao_identificado = self._analisar_padroes()
280
+
281
+ resposta = f"""### Feedback Personalizado 💭\n\n{feedback}{padrao_identificado}\n\n{tom_insight}"""
282
+ resposta += self._gerar_pontos_aprofundamento()
283
+
284
  self.pergunta_atual += 1
285
+ if self.pergunta_atual < len(PERGUNTAS):
286
+ resposta += self._gerar_proxima_pergunta()
287
+ else:
288
+ self.sessao_completa = True
289
+ tempo = (datetime.now() - self.inicio).seconds // 60
290
+ resposta += self.gerar_sumario_final(tempo)
291
+
292
+ return resposta
293
+
294
+ def _gerar_insight_tom(self, tom: str, intensidade: float) -> str:
295
+ """Gera insights baseados no tom da resposta."""
296
+ insights = {
297
+ "confiante": "Sua confiança ao abordar este tema é notável. Como você construiu esta segurança?",
298
+ "reflexivo": "Sua abordagem reflexiva traz profundidade à análise. Continue explorando diferentes perspectivas.",
299
+ "hesitante": "Percebo algumas incertezas naturais do processo. Que apoio ajudaria a fortalecer sua confiança?",
300
+ "pragmatico": "Seu foco em resultados práticos é valioso. Como você equilibra isso com visão de longo prazo?",
301
+ "emocional": "Sua conexão emocional com a liderança demonstra comprometimento genuíno."
302
+ }
303
+
304
+ if intensidade > 2:
305
+ return f"\n\n💡 {insights[tom]} Sua expressão é particularmente intensa neste aspecto."
306
+ return f"\n\n💡 {insights[tom]}"
307
+
308
+ def _analisar_padroes(self) -> str:
309
+ if len(self.historico_respostas) <= 1:
310
+ return ""
311
+
312
+ sentimento_atual = self.analisar_sentimento(self.historico_respostas[-1])
313
+ sentimento_anterior = self.analisar_sentimento(self.historico_respostas[-2])
314
+
315
+ if sentimento_atual == sentimento_anterior == "positive":
316
+ return "\n\n💡 Observo um padrão consistente de confiança em suas respostas. Continue desenvolvendo esses pontos fortes!"
317
+ elif sentimento_atual == sentimento_anterior == "improvement":
318
+ return "\n\n💡 Percebo que você está identificando áreas de desenvolvimento. Vamos focar em estratégias práticas para esses desafios."
319
+ return ""
320
+
321
+ def _gerar_pontos_aprofundamento(self) -> str:
322
+ return """#### Pontos para Aprofundamento:
323
+ 1. Como essa experiência se conecta com seus valores de liderança?
324
+ 2. Que recursos específicos você identificou como necessários?
325
+ 3. Qual seria o próximo marco de desenvolvimento nessa área?"""
326
+
327
+ def _gerar_proxima_pergunta(self) -> str:
328
+ proxima = PERGUNTAS[self.pergunta_atual]
329
+ return f"""\n\n### Próxima Reflexão: {proxima['categoria'].title()} 🎯\n\n{proxima['pergunta']}\n\nTome um momento para refletir e conectar com suas experiências..."""
330
+
331
+ def gerar_sumario_final(self, tempo: int) -> str:
332
+ # Analyze patterns in responses
333
+ sentimentos = [self.analisar_sentimento(resp) for resp in self.historico_respostas]
334
+ predominante = max(set(sentimentos), key=sentimentos.count)
335
+
336
+ # Add tone pattern analysis
337
+ tone_pattern = max(set(self.tone_history), key=self.tone_history.count)
338
+ tone_insight = f"\n\n#### Padrão de Comunicação:\nSeu estilo predominante é {tone_pattern}, o que sugere {self._interpretar_padrao_tom(tone_pattern)}"
339
+
340
+ # Analyze overall response quality metrics
341
+ avg_metrics = {
342
+ key: sum(m[key] for m in self.response_quality_metrics) / len(self.response_quality_metrics)
343
+ for key in ["depth", "clarity", "specificity", "actionability"]
344
+ }
345
+
346
+ quality_insights = "\n\n#### Insights de Qualidade das Respostas:"
347
+ if avg_metrics["depth"] > 0.7:
348
+ quality_insights += "\n- Suas reflexões demonstram profundidade significativa"
349
+ if avg_metrics["specificity"] > 0.7:
350
+ quality_insights += "\n- Você fornece exemplos concretos e detalhados"
351
+ if avg_metrics["actionability"] > 0.7:
352
+ quality_insights += "\n- Suas respostas são orientadas para ação"
353
+
354
+ if predominante == "positive":
355
+ perfil = "Você demonstra forte autoconhecimento e confiança em sua liderança."
356
+ elif predominante == "improvement":
357
+ perfil = "Você demonstra excelente capacidade de identificar oportunidades de desenvolvimento."
358
+ else:
359
+ perfil = "Você demonstra uma abordagem equilibrada entre conquistas e desafios."
360
+
361
+ return f"""
362
+ ### 🎉 Jornada de Desenvolvimento Concluída!
363
 
364
+ ⏱️ Tempo de reflexão: {tempo} minutos
365
+ 📝 Temas explorados: {len(PERGUNTAS)}
366
 
367
+ #### Perfil de Liderança Observado:
368
+ {perfil}{tone_insight}{quality_insights}
369
 
370
+ #### Recomendações Personalizadas:
371
+ 1. Implemente uma ação específica mencionada em suas reflexões esta semana
372
+ 2. Mantenha um diário de liderança focado nos temas discutidos
373
+ 3. Estabeleça checkpoints mensais para revisar seu progresso
374
 
375
+ Deseja iniciar uma nova jornada de desenvolvimento com outros temas?"""
376
+
377
+ def _interpretar_padrao_tom(self, tom: str) -> str:
378
+ """Interpreta o significado do padrão de tom predominante."""
379
+ interpretacoes = {
380
+ "confiante": "uma base sólida para influenciar e liderar equipes.",
381
+ "reflexivo": "uma capacidade valiosa de considerar múltiplas perspectivas.",
382
+ "hesitante": "uma oportunidade para fortalecer sua confiança através da prática.",
383
+ "pragmatico": "um foco valioso em resultados e implementação.",
384
+ "emocional": "uma forte conexão com o impacto humano da liderança."
385
+ }
386
+ return interpretacoes.get(tom, "um estilo único de liderança.")
387
+
388
+ def primeira_pergunta(self):
389
+ return f"""### 👋 Bem-vindo à sua Jornada de Desenvolvimento!
390
+
391
+ Vamos explorar aspectos importantes da sua liderança através de reflexões guiadas.
392
+
393
+ {PERGUNTAS[0]['pergunta']}
394
+
395
+ Tome um momento para conectar com suas experiências e compartilhe sua perspectiva..."""
396
+
397
+ def criar_interface():
398
+ coach = EnhancedCoach()
399
+
400
+ with gr.Blocks(title="Coach de Liderança") as app:
401
+ gr.Markdown("""
402
+ # 🚀 Coach de Liderança
403
+
404
+ Desenvolva sua liderança através de reflexão guiada e feedback personalizado.
405
+ """)
406
+
407
+ chat = gr.Chatbot(
408
+ value=[[None, coach.primeira_pergunta()]],
409
+ height=600,
410
+ show_label=False
411
+ )
412
+
413
+ with gr.Row():
414
+ txt = gr.Textbox(
415
+ placeholder="Compartilhe sua reflexão aqui...",
416
+ lines=4,
417
+ label="Sua Resposta"
418
+ )
419
+ btn = gr.Button("Enviar")
420
+
421
+ def responder(mensagem, historico):
422
+ if not mensagem.strip():
423
+ return "", historico
424
+
425
+ resposta = coach.gerar_resposta(mensagem)
426
+ historico.append([mensagem, resposta])
427
+ return "", historico
428
+
429
+ txt.submit(responder, [txt, chat], [txt, chat])
430
+ btn.click(responder, [txt, chat], [txt, chat])
431
+
432
+ return app
433
 
434
  if __name__ == "__main__":
435
+ app = criar_interface()
436
+ app.launch()