DHEIVER commited on
Commit
8f911dc
1 Parent(s): 596442f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +147 -160
app.py CHANGED
@@ -43,7 +43,6 @@ class BiblicalExample:
43
  """Extract meaningful keywords from question and response."""
44
  text = f"{self.question} {self.base_response}"
45
  words = text.lower().split()
46
- # Remove common Portuguese stop words
47
  stop_words = {'a', 'o', 'e', 'de', 'do', 'da', 'em', 'para', 'com', 'um', 'uma'}
48
  keywords = [word for word in words if len(word) > 3 and word not in stop_words]
49
  return list(set(keywords))
@@ -51,15 +50,12 @@ class BiblicalExample:
51
  class TextProcessor:
52
  @staticmethod
53
  def normalize_text(text: str) -> str:
54
- """Normalize text by removing special characters and extra spaces."""
55
  text = re.sub(r'[^\w\s]', ' ', text)
56
  text = ' '.join(text.lower().split())
57
  return text
58
 
59
  @staticmethod
60
  def extract_main_concepts(text: str) -> List[str]:
61
- """Extract main concepts from text using basic NLP techniques."""
62
- # Remove common words and keep meaningful terms
63
  stop_words = {'a', 'o', 'e', 'de', 'do', 'da', 'em', 'para', 'com', 'um', 'uma', 'que', 'como'}
64
  words = TextProcessor.normalize_text(text).split()
65
  concepts = [word for word in words if word not in stop_words and len(word) > 3]
@@ -73,13 +69,11 @@ class ResponseValidator:
73
  self.concept_match_threshold = 0.25
74
 
75
  def calculate_text_similarity(self, text1: str, text2: str) -> float:
76
- """Calculate text similarity using SequenceMatcher."""
77
  normalized_text1 = self.text_processor.normalize_text(text1)
78
  normalized_text2 = self.text_processor.normalize_text(text2)
79
  return SequenceMatcher(None, normalized_text1, normalized_text2).ratio()
80
 
81
  def calculate_keyword_similarity(self, text1: str, text2: str) -> float:
82
- """Calculate keyword similarity between texts."""
83
  keywords1 = set(self.text_processor.extract_main_concepts(text1))
84
  keywords2 = set(self.text_processor.extract_main_concepts(text2))
85
  if not keywords1 or not keywords2:
@@ -87,7 +81,6 @@ class ResponseValidator:
87
  return len(keywords1.intersection(keywords2)) / len(keywords1.union(keywords2))
88
 
89
  def calculate_concept_similarity(self, question: str, example: BiblicalExample) -> float:
90
- """Calculate concept similarity between question and example."""
91
  question_concepts = set(self.text_processor.extract_main_concepts(question))
92
  example_concepts = set(example.keywords)
93
  if not question_concepts or not example_concepts:
@@ -95,12 +88,10 @@ class ResponseValidator:
95
  return len(question_concepts.intersection(example_concepts)) / len(question_concepts.union(example_concepts))
96
 
97
  def validate_response(self, question: str, example: BiblicalExample) -> Tuple[bool, Dict[str, float]]:
98
- """Validate response relevance using multiple metrics."""
99
  text_similarity = self.calculate_text_similarity(question, example.question)
100
  keyword_similarity = self.calculate_keyword_similarity(question, example.question)
101
  concept_similarity = self.calculate_concept_similarity(question, example)
102
 
103
- # Calculate weighted score
104
  weights = {'text': 0.4, 'keyword': 0.3, 'concept': 0.3}
105
  total_score = (
106
  text_similarity * weights['text'] +
@@ -143,102 +134,142 @@ class SapienciaBiblica:
143
  logger.error(f"Erro ao carregar modelo: {str(e)}")
144
  raise
145
 
146
- def get_default_examples_dict(self) -> Dict[str, List[BiblicalExample]]:
147
- return {
148
- "casamento": [
149
- BiblicalExample(
150
- question="Como melhorar a comunicação no casamento?",
151
- passage="Efésios 4:29",
152
- text="Não saia da vossa boca nenhuma palavra torpe, mas só a que for boa para promover a edificação, para que dê graça aos que a ouvem.",
153
- base_response="A comunicação efetiva no casamento requer sabedoria, paciência e amor. A Bíblia nos ensina a usar palavras que edificam e não destroem.",
154
- application="Pratique escuta ativa, escolha momentos adequados para conversas importantes, e sempre fale com amor e respeito.",
155
- sentiment="supportive",
156
- theme="casamento"
157
- ),
158
- BiblicalExample(
159
- question="Como lidar com conflitos no casamento?",
160
- passage="Efésios 4:26-27",
161
- text="Irai-vos e não pequeis; não se ponha o sol sobre a vossa ira. Não deis lugar ao diabo.",
162
- base_response="Os conflitos são naturais, mas devem ser resolvidos com sabedoria e amor, sem deixar que a raiva tome conta.",
163
- application="Resolva os conflitos no mesmo dia, pratique o perdão e busque entender o ponto de vista do cônjuge.",
164
- sentiment="instructive",
165
- theme="casamento"
166
- )
167
- ],
168
- "familia": [
169
- BiblicalExample(
170
- question="Como educar filhos segundo a Bíblia?",
171
- passage="Provérbios 22:6",
172
- text="Instrui o menino no caminho em que deve andar, e até quando envelhecer não se desviará dele.",
173
- base_response="A educação dos filhos deve ser baseada em princípios bíblicos, com amor, disciplina e exemplo.",
174
- application="Estabeleça rotinas de devocional em família, seja exemplo de caráter e aplique disciplina com amor.",
175
- sentiment="instructive",
176
- theme="familia"
177
- )
178
- ],
179
- "vida_espiritual": [
180
- BiblicalExample(
181
- question="Como desenvolver uma vida de oração?",
182
- passage="1 Tessalonicenses 5:17",
183
- text="Orai sem cessar.",
184
- base_response="A vida de oração se desenvolve através da prática constante e sincera.",
185
- application="Reserve um tempo diário para oração, mantenha um diário de oração e pratique a gratidão.",
186
- sentiment="spiritual",
187
- theme="vida_espiritual"
188
- )
189
- ],
190
- "trabalho": [
191
- BiblicalExample(
192
- question="Como ter integridade no trabalho?",
193
- passage="Colossenses 3:23",
194
- text="E tudo quanto fizerdes, fazei-o de coração, como ao Senhor.",
195
- base_response="A integridade no trabalho significa fazer o melhor possível, como se trabalhássemos diretamente para Deus.",
196
- application="Seja honesto, pontual e dedicado em suas responsabilidades profissionais.",
197
- sentiment="professional",
198
- theme="trabalho"
199
- )
200
- ],
201
- "relacionamentos": [
202
- BiblicalExample(
203
- question="Como construir amizades verdadeiras?",
204
- passage="Provérbios 17:17",
205
- text="Em todo tempo ama o amigo, e na angústia nasce o irmão.",
206
- base_response="Amizades verdadeiras são construídas com amor, lealdade e presença constante.",
207
- application="Seja presente, demonstre interesse genuíno e apoie seus amigos nos momentos difíceis.",
208
- sentiment="friendly",
209
- theme="relacionamentos"
210
- )
211
- ],
212
- "geral": [
213
- BiblicalExample(
214
- question="Como encontrar paz em tempos difíceis?",
215
- passage="João 14:27",
216
- text="Deixo-vos a paz, a minha paz vos dou; não vo-la dou como o mundo a dá. Não se turbe o vosso coração, nem se atemorize.",
217
- base_response="A verdadeira paz vem de Deus e permanece mesmo em meio às tribulações.",
218
- application="Mantenha seu foco em Deus, pratique a gratidão e confie em Suas promessas.",
219
- sentiment="comforting",
220
- theme="geral"
221
- ),
222
- BiblicalExample(
223
- question="Como tomar decisões sábias?",
224
- passage="Tiago 1:5",
225
- text="E, se algum de vós tem falta de sabedoria, peça-a a Deus, que a todos dá liberalmente.",
226
- base_response="A sabedoria verdadeira vem de Deus e está disponível para todos que a pedem com fé.",
227
- application="Ore pedindo sabedoria, busque conselho de pessoas piedosas e avalie as decisões à luz da Palavra.",
228
- sentiment="instructive",
229
- theme="geral"
230
- ),
231
- BiblicalExample(
232
- question="Como vencer o medo?",
233
- passage="2 Timóteo 1:7",
234
- text="Porque Deus não nos deu espírito de covardia, mas de poder, de amor e de moderação.",
235
- base_response="O medo não vem de Deus, que nos dá poder, amor e equilíbrio para enfrentar desafios.",
236
- application="Identifique seus medos, ore sobre eles e confie no poder de Deus.",
237
- sentiment="encouraging",
238
- theme="geral"
239
- )
240
- ]
241
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  def find_best_theme(self, question: str) -> str:
243
  """Find the most relevant theme for the question."""
244
  question = question.lower()
@@ -253,16 +284,23 @@ class SapienciaBiblica:
253
  max_matches = 0
254
  best_theme = "geral"
255
 
 
256
  for theme, keywords in theme_keywords.items():
257
  matches = sum(1 for keyword in keywords if keyword in question)
258
- if matches > max_matches:
259
- max_matches = matches
 
 
 
 
 
 
260
  best_theme = theme
261
 
262
  return best_theme
263
 
264
  def find_best_example(self, question: str, theme: str) -> Tuple[Optional[BiblicalExample], Dict[str, float]]:
265
- """Find the most relevant example and return validation metrics."""
266
  examples = self.biblical_examples.get(theme, self.biblical_examples["geral"])
267
  best_score = 0
268
  best_example = None
@@ -278,32 +316,6 @@ class SapienciaBiblica:
278
 
279
  return best_example, best_metrics
280
 
281
- def get_unique_response(self, question: str, theme: str = None) -> Tuple[str, Dict, str]:
282
- """Get a validated response for the given question."""
283
- if not question.strip():
284
- return "Por favor, faça uma pergunta específica.", {}, self.format_history()
285
-
286
- if not theme or theme not in self.biblical_examples:
287
- theme = self.find_best_theme(question)
288
-
289
- best_example, validation_metrics = self.find_best_example(question, theme)
290
-
291
- if not best_example:
292
- response = self.generate_fallback_response(question, theme)
293
- metadata = {
294
- "theme": theme,
295
- "status": "no_matching_example",
296
- "validation_metrics": validation_metrics
297
- }
298
- return response, metadata, self.format_history()
299
-
300
- sentiment = self.analyze_sentiment(question)
301
- response = self.format_response(best_example, sentiment)
302
- metadata = self.create_metadata(best_example, theme, validation_metrics)
303
- history = self.save_to_history(question, theme, response, metadata)
304
-
305
- return response, metadata, history
306
-
307
  def analyze_sentiment(self, text: str) -> str:
308
  """Analyze the sentiment of the input text."""
309
  positive_words = {'alegria', 'esperança', 'paz', 'amor', 'gratidão', 'feliz', 'bem'}
@@ -315,31 +327,8 @@ class SapienciaBiblica:
315
 
316
  return 'positive' if pos_count > neg_count else 'negative' if neg_count > pos_count else 'neutral'
317
 
318
- def format_response(self, example: BiblicalExample, sentiment: str) -> str:
319
- """Format the response with appropriate introduction based on sentiment."""
320
- intro = {
321
- 'positive': "Que bom que você está buscando orientação! ",
322
- 'negative': "Entendo seu momento e estou aqui para ajudar. ",
323
- 'neutral': "Agradeço sua busca por sabedoria. "
324
- }
325
-
326
- return f"""
327
- 🌟 Orientação Personalizada:
328
- {intro[sentiment]}{example.base_response}
329
-
330
- 📖 Passagem Bíblica:
331
- {example.passage}: {example.text}
332
-
333
- ✨ Aplicação Prática:
334
- {example.application}
335
-
336
- 🙏 Observação:
337
- Esta orientação é baseada em princípios bíblicos. Para questões específicas,
338
- considere consultar sua liderança espiritual local.
339
- """
340
-
341
  def generate_fallback_response(self, question: str, theme: str) -> str:
342
- """Generate a thoughtful fallback response when no good match is found."""
343
  theme_verses = {
344
  "casamento": ("Efésios 5:25", "Maridos, amai vossas mulheres, como também Cristo amou a igreja..."),
345
  "familia": ("Salmos 127:3", "Eis que os filhos são herança do Senhor..."),
@@ -495,15 +484,13 @@ def create_interface():
495
  interactive=False
496
  )
497
 
498
- # Configure examples with cache directory
499
  gr.Examples(
500
  examples=counselor.get_examples_for_interface(),
501
  inputs=[theme, question],
502
  outputs=[answer_output, metadata_output, history_output],
503
  fn=counselor.get_unique_response,
504
  label="📝 Exemplos de Perguntas",
505
- examples_per_page=5,
506
- cache_examples=True # This is valid for Examples component
507
  )
508
 
509
  submit_btn.click(
 
43
  """Extract meaningful keywords from question and response."""
44
  text = f"{self.question} {self.base_response}"
45
  words = text.lower().split()
 
46
  stop_words = {'a', 'o', 'e', 'de', 'do', 'da', 'em', 'para', 'com', 'um', 'uma'}
47
  keywords = [word for word in words if len(word) > 3 and word not in stop_words]
48
  return list(set(keywords))
 
50
  class TextProcessor:
51
  @staticmethod
52
  def normalize_text(text: str) -> str:
 
53
  text = re.sub(r'[^\w\s]', ' ', text)
54
  text = ' '.join(text.lower().split())
55
  return text
56
 
57
  @staticmethod
58
  def extract_main_concepts(text: str) -> List[str]:
 
 
59
  stop_words = {'a', 'o', 'e', 'de', 'do', 'da', 'em', 'para', 'com', 'um', 'uma', 'que', 'como'}
60
  words = TextProcessor.normalize_text(text).split()
61
  concepts = [word for word in words if word not in stop_words and len(word) > 3]
 
69
  self.concept_match_threshold = 0.25
70
 
71
  def calculate_text_similarity(self, text1: str, text2: str) -> float:
 
72
  normalized_text1 = self.text_processor.normalize_text(text1)
73
  normalized_text2 = self.text_processor.normalize_text(text2)
74
  return SequenceMatcher(None, normalized_text1, normalized_text2).ratio()
75
 
76
  def calculate_keyword_similarity(self, text1: str, text2: str) -> float:
 
77
  keywords1 = set(self.text_processor.extract_main_concepts(text1))
78
  keywords2 = set(self.text_processor.extract_main_concepts(text2))
79
  if not keywords1 or not keywords2:
 
81
  return len(keywords1.intersection(keywords2)) / len(keywords1.union(keywords2))
82
 
83
  def calculate_concept_similarity(self, question: str, example: BiblicalExample) -> float:
 
84
  question_concepts = set(self.text_processor.extract_main_concepts(question))
85
  example_concepts = set(example.keywords)
86
  if not question_concepts or not example_concepts:
 
88
  return len(question_concepts.intersection(example_concepts)) / len(question_concepts.union(example_concepts))
89
 
90
  def validate_response(self, question: str, example: BiblicalExample) -> Tuple[bool, Dict[str, float]]:
 
91
  text_similarity = self.calculate_text_similarity(question, example.question)
92
  keyword_similarity = self.calculate_keyword_similarity(question, example.question)
93
  concept_similarity = self.calculate_concept_similarity(question, example)
94
 
 
95
  weights = {'text': 0.4, 'keyword': 0.3, 'concept': 0.3}
96
  total_score = (
97
  text_similarity * weights['text'] +
 
134
  logger.error(f"Erro ao carregar modelo: {str(e)}")
135
  raise
136
 
137
+ def get_unique_response(self, question: str, theme: str = None) -> Tuple[str, Dict, str]:
138
+ """Generate a unique response for each question."""
139
+ if not question.strip():
140
+ return "Por favor, faça uma pergunta específica.", {}, self.format_history()
141
+
142
+ if not theme or theme not in self.biblical_examples:
143
+ theme = self.find_best_theme(question)
144
+
145
+ try:
146
+ # Encontrar exemplo base mais relevante
147
+ best_example, validation_metrics = self.find_best_example(question, theme)
148
+
149
+ if not best_example:
150
+ return self.generate_fallback_response(question, theme), {
151
+ "theme": theme,
152
+ "status": "no_matching_example"
153
+ }, self.format_history()
154
+
155
+ # Gerar resposta personalizada usando BERT
156
+ context = f"{best_example.text} {best_example.application}"
157
+ inputs = self.tokenizer(
158
+ question,
159
+ context,
160
+ return_tensors="pt",
161
+ max_length=512,
162
+ truncation=True,
163
+ padding=True
164
+ ).to(self.device)
165
+
166
+ # Obter resposta do modelo
167
+ with torch.no_grad():
168
+ outputs = self.model(**inputs)
169
+ start_scores = outputs.start_logits
170
+ end_scores = outputs.end_logits
171
+
172
+ start_idx = torch.argmax(start_scores)
173
+ end_idx = torch.argmax(end_scores)
174
+
175
+ # Extrair resposta gerada
176
+ answer_tokens = inputs["input_ids"][0][start_idx:end_idx + 1]
177
+ generated_answer = self.tokenizer.decode(answer_tokens)
178
+
179
+ # Gerar reflexão específica
180
+ reflection = self.generate_specific_reflection(question, best_example)
181
+
182
+ # Formatar resposta final
183
+ sentiment = self.analyze_sentiment(question)
184
+ final_response = self.format_customized_response(
185
+ question=question,
186
+ generated_answer=generated_answer,
187
+ reflection=reflection,
188
+ example=best_example,
189
+ sentiment=sentiment
190
+ )
191
+
192
+ # Preparar metadata
193
+ metadata = self.create_metadata(best_example, theme, validation_metrics)
194
+ metadata.update({
195
+ "response_type": "generated",
196
+ "generation_success": True
197
+ })
198
+
199
+ # Salvar no histórico
200
+ history = self.save_to_history(question, theme, final_response, metadata)
201
+
202
+ return final_response, metadata, history
203
+
204
+ except Exception as e:
205
+ logger.error(f"Erro na geração de resposta: {str(e)}")
206
+ return self.generate_fallback_response(question, theme), {
207
+ "theme": theme,
208
+ "status": "generation_error"
209
+ }, self.format_history()
210
+
211
+ def format_customized_response(self, question: str, generated_answer: str, reflection: str,
212
+ example: BiblicalExample, sentiment: str) -> str:
213
+ """Format a unique response with generated content and biblical guidance."""
214
+ intro = {
215
+ 'positive': "Que bom que você está buscando orientação! ",
216
+ 'negative': "Entendo seu momento e estou aqui para ajudar. ",
217
+ 'neutral': "Agradeço sua busca por sabedoria. "
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  }
219
+
220
+ # Limpar e validar a resposta gerada
221
+ generated_answer = generated_answer.strip()
222
+ if len(generated_answer) < 10: # Resposta muito curta, usar base
223
+ generated_answer = example.base_response
224
+
225
+ return f"""
226
+ 🌟 Orientação Personalizada:
227
+ {intro[sentiment]}{generated_answer}
228
+
229
+ 📖 Passagem Bíblica:
230
+ {example.passage}: {example.text}
231
+
232
+ ✨ Aplicação Prática:
233
+ {example.application}
234
+
235
+ 💭 Reflexão Específica para Sua Situação:
236
+ {reflection}
237
+
238
+ 🙏 Observação:
239
+ Esta orientação é baseada em princípios bíblicos. Para questões específicas,
240
+ considere consultar sua liderança espiritual local.
241
+ """
242
+
243
+ def generate_specific_reflection(self, question: str, example: BiblicalExample) -> str:
244
+ """Generate a specific reflection based on the question and biblical context."""
245
+ try:
246
+ context = f"{question} {example.text} {example.application}"
247
+
248
+ inputs = self.tokenizer(
249
+ "Como aplicar este princípio bíblico nesta situação específica?",
250
+ context,
251
+ return_tensors="pt",
252
+ max_length=512,
253
+ truncation=True
254
+ ).to(self.device)
255
+
256
+ with torch.no_grad():
257
+ outputs = self.model(**inputs)
258
+ start_idx = torch.argmax(outputs.start_logits)
259
+ end_idx = torch.argmax(outputs.end_logits)
260
+
261
+ tokens = self.tokenizer.convert_ids_to_tokens(inputs["input_ids"][0][start_idx:end_idx+1])
262
+ reflection = self.tokenizer.convert_tokens_to_string(tokens)
263
+
264
+ if len(reflection.strip()) < 10:
265
+ return "Aplique estes princípios bíblicos em sua situação específica, buscando sabedoria em oração."
266
+
267
+ return reflection.strip()
268
+
269
+ except Exception as e:
270
+ logger.error(f"Erro ao gerar reflexão: {str(e)}")
271
+ return "Reflita sobre como aplicar estes princípios em sua vida, buscando a direção de Deus."
272
+
273
  def find_best_theme(self, question: str) -> str:
274
  """Find the most relevant theme for the question."""
275
  question = question.lower()
 
284
  max_matches = 0
285
  best_theme = "geral"
286
 
287
+ # Analisar similaridade com cada tema
288
  for theme, keywords in theme_keywords.items():
289
  matches = sum(1 for keyword in keywords if keyword in question)
290
+ similarity_score = self.validator.calculate_text_similarity(
291
+ question,
292
+ ' '.join(keywords)
293
+ )
294
+
295
+ total_score = matches + (similarity_score * 2)
296
+ if total_score > max_matches:
297
+ max_matches = total_score
298
  best_theme = theme
299
 
300
  return best_theme
301
 
302
  def find_best_example(self, question: str, theme: str) -> Tuple[Optional[BiblicalExample], Dict[str, float]]:
303
+ """Find the most relevant example and validation metrics."""
304
  examples = self.biblical_examples.get(theme, self.biblical_examples["geral"])
305
  best_score = 0
306
  best_example = None
 
316
 
317
  return best_example, best_metrics
318
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
319
  def analyze_sentiment(self, text: str) -> str:
320
  """Analyze the sentiment of the input text."""
321
  positive_words = {'alegria', 'esperança', 'paz', 'amor', 'gratidão', 'feliz', 'bem'}
 
327
 
328
  return 'positive' if pos_count > neg_count else 'negative' if neg_count > pos_count else 'neutral'
329
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
330
  def generate_fallback_response(self, question: str, theme: str) -> str:
331
+ """Generate a thoughtful fallback response."""
332
  theme_verses = {
333
  "casamento": ("Efésios 5:25", "Maridos, amai vossas mulheres, como também Cristo amou a igreja..."),
334
  "familia": ("Salmos 127:3", "Eis que os filhos são herança do Senhor..."),
 
484
  interactive=False
485
  )
486
 
 
487
  gr.Examples(
488
  examples=counselor.get_examples_for_interface(),
489
  inputs=[theme, question],
490
  outputs=[answer_output, metadata_output, history_output],
491
  fn=counselor.get_unique_response,
492
  label="📝 Exemplos de Perguntas",
493
+ examples_per_page=5
 
494
  )
495
 
496
  submit_btn.click(