DHEIVER commited on
Commit
c5d1eea
·
verified ·
1 Parent(s): 64014ce

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +196 -116
app.py CHANGED
@@ -1,111 +1,202 @@
1
  import gradio as gr
2
  import numpy as np
3
- from typing import List, Dict
4
  import logging
5
  import re
6
- from datetime import datetime
 
 
 
 
 
 
 
 
7
 
8
  logging.basicConfig(level=logging.INFO)
9
  logger = logging.getLogger(__name__)
10
 
11
- class SistemaPontuacao:
 
 
 
 
 
 
12
  def __init__(self):
13
- self.pontos = 0
14
- self.nivel = 1
15
- self.conquistas = set()
16
- self.streak_diaria = 0
17
- self.ultima_interacao = None
 
 
 
 
 
 
 
 
 
18
 
19
- def calcular_nivel(self) -> int:
20
- return 1 + self.pontos // 100
21
-
22
- def adicionar_pontos(self, quantidade: int):
23
- self.pontos += quantidade
24
- novo_nivel = self.calcular_nivel()
25
- if novo_nivel > self.nivel:
26
- self.nivel = novo_nivel
27
- return True
28
- return False
29
-
30
- def registrar_interacao(self):
31
- hoje = datetime.now().date()
32
- if self.ultima_interacao is None:
33
- self.streak_diaria = 1
34
- elif (hoje - self.ultima_interacao).days == 1:
35
- self.streak_diaria += 1
36
- elif (hoje - self.ultima_interacao).days > 1:
37
- self.streak_diaria = 1
38
- self.ultima_interacao = hoje
 
 
 
 
 
 
 
 
39
 
40
- def verificar_conquistas(self) -> List[str]:
41
- novas_conquistas = []
42
- todas_conquistas = {
43
- "Iniciante": "Fez sua primeira pergunta",
44
- "Estudioso": "Alcançou nível 5",
45
- "Dedicado": "Manteve streak de 7 dias",
46
- "Sábio": "Acumulou 1000 pontos",
47
- "Perseverante": "Fez 50 perguntas"
48
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
50
- for titulo, descricao in todas_conquistas.items():
51
- if titulo not in self.conquistas:
52
- if (
53
- (titulo == "Iniciante" and self.pontos > 0) or
54
- (titulo == "Estudioso" and self.nivel >= 5) or
55
- (titulo == "Dedicado" and self.streak_diaria >= 7) or
56
- (titulo == "Sábio" and self.pontos >= 1000)
57
- ):
58
- self.conquistas.add(titulo)
59
- novas_conquistas.append(f"🏆 Nova Conquista: {titulo} - {descricao}")
60
 
61
- return novas_conquistas
 
62
 
63
  class AssistenteBiblico:
64
  def __init__(self):
65
  self.dados_biblia = self.carregar_dados_biblia()
66
  self.prompts_tematicos = self.carregar_prompts()
67
- self.sistema_pontuacao = SistemaPontuacao()
 
 
68
 
69
- # [Manter os métodos existentes: carregar_dados_biblia, carregar_prompts, buscar_versiculos]
70
-
71
- def gerar_resposta(self, pergunta: str) -> str:
 
 
 
 
 
 
 
72
  try:
73
- # Registrar interação e adicionar pontos base
74
- self.sistema_pontuacao.registrar_interacao()
75
- pontos_ganhos = 10 # Pontos base por pergunta
76
-
77
- versiculos = self.buscar_versiculos(pergunta)
78
- if not versiculos:
79
- return "Desculpe, não encontrei versículos específicos para sua pergunta. Tente reformular ou escolher outro tema."
80
 
81
- # Adicionar pontos extras baseado na qualidade da pergunta
82
- pontos_ganhos += len(versiculos) * 5 # Pontos extras por versículo relevante
83
- subiu_nivel = self.sistema_pontuacao.adicionar_pontos(pontos_ganhos)
84
 
85
- # Construir resposta com elementos gamificados
86
- resposta = "📖 Encontrei estes versículos para sua situação:\n\n"
87
 
88
- for versiculo in versiculos:
89
- resposta += f" {versiculo['referencia']}\n"
90
- resposta += f"{versiculo['texto']}\n\n"
 
 
 
 
 
91
 
92
- # Adicionar informações de progresso
93
- resposta += "\n🎮 Seu Progresso:\n"
94
- resposta += f"✨ Pontos: {self.sistema_pontuacao.pontos} (+{pontos_ganhos})\n"
95
- resposta += f"📊 Nível: {self.sistema_pontuacao.nivel}\n"
96
- resposta += f"🔥 Streak Diária: {self.sistema_pontuacao.streak_diaria} dias\n"
97
 
98
- if subiu_nivel:
99
- resposta += f"\n🎉 PARABÉNS! Você alcançou o nível {self.sistema_pontuacao.nivel}!\n"
100
 
101
- # Verificar e adicionar novas conquistas
102
- novas_conquistas = self.sistema_pontuacao.verificar_conquistas()
103
- if novas_conquistas:
104
- resposta += "\n" + "\n".join(novas_conquistas) + "\n"
 
 
 
 
105
 
106
- topicos = set(sum([v['topicos'] for v in versiculos], []))
107
- if topicos:
108
- resposta += f"\n🏷️ Tópicos relacionados: {', '.join(topicos)}\n"
 
 
 
109
 
110
  resposta += "\n💭 Reflita sobre estas palavras e busque orientação pastoral se necessário."
111
 
@@ -118,6 +209,11 @@ class AssistenteBiblico:
118
  def criar_interface():
119
  assistente = AssistenteBiblico()
120
 
 
 
 
 
 
121
  def processar_prompt(prompt: str, historico: List) -> List:
122
  try:
123
  resposta = assistente.gerar_resposta(prompt)
@@ -126,59 +222,43 @@ def criar_interface():
126
  logger.error(f"Erro: {str(e)}")
127
  return historico + [(prompt, "Desculpe, ocorreu um erro.")]
128
 
129
- with gr.Blocks(title="Assistente Bíblico Gamificado") as demo:
130
  gr.HTML("""
131
  <div style="text-align: center; padding: 20px; background-color: #f0f8ff; border-radius: 10px;">
132
- <h1 style="color: #2c3e50;">🎮 Conselheiro Bíblico - Jornada da Sabedoria</h1>
133
- <p style="color: #34495e;">Explore a Palavra de Deus, ganhe pontos e conquistas em sua jornada espiritual</p>
134
  </div>
135
  """)
136
 
137
  with gr.Row():
138
  with gr.Column(scale=2):
139
- chatbot = gr.Chatbot(
140
- height=500,
141
- label="Sua Jornada de Aprendizado"
142
- )
143
 
144
  with gr.Row():
145
  msg = gr.Textbox(
146
  show_label=False,
147
- placeholder="Digite sua dúvida ou escolha uma missão ao lado...",
148
  scale=8
149
  )
150
- limpar = gr.Button("🔄 Nova Jornada", scale=1)
151
-
152
- with gr.Column(scale=1):
153
- gr.Markdown("### 🎯 Missões Disponíveis")
154
 
155
- for categoria, dados in assistente.prompts_tematicos.items():
156
- with gr.Accordion(dados["título"], open=False):
157
- for prompt in dados["prompts"]:
158
- btn = gr.Button(f"📜 {prompt}")
159
- btn.click(
160
- fn=processar_prompt,
161
- inputs=[gr.Textbox(value=prompt, visible=False), chatbot],
162
- outputs=[chatbot]
163
- )
164
-
165
- gr.Markdown("""
166
- ### 🏆 Sistema de Progresso
167
- - Ganhe pontos ao fazer perguntas
168
- - Suba de nível a cada 100 pontos
169
- - Mantenha sua streak diária
170
- - Desbloqueie conquistas especiais
171
 
172
- ### 💫 Conquistas
173
- - 🎓 Iniciante: Faça sua primeira pergunta
174
- - 📚 Estudioso: Alcance nível 5
175
- - Dedicado: Mantenha streak de 7 dias
176
- - 🎯 Sábio: Acumule 1000 pontos
177
- - 🏅 Perseverante: Faça 50 perguntas
178
- """)
179
 
180
  msg.submit(processar_prompt, [msg, chatbot], [chatbot])
181
  limpar.click(lambda: [], None, chatbot, queue=False)
 
182
 
183
  return demo
184
 
 
1
  import gradio as gr
2
  import numpy as np
3
+ from typing import List, Dict, Optional
4
  import logging
5
  import re
6
+ import requests
7
+ from bs4 import BeautifulSoup
8
+ from sentence_transformers import SentenceTransformer
9
+ import torch
10
+ from urllib.parse import urlparse
11
+ import numpy as np
12
+ from dataclasses import dataclass
13
+ import json
14
+ import os
15
 
16
  logging.basicConfig(level=logging.INFO)
17
  logger = logging.getLogger(__name__)
18
 
19
+ @dataclass
20
+ class TextChunk:
21
+ text: str
22
+ source_url: str
23
+ embedding: Optional[np.ndarray] = None
24
+
25
+ class WebScraper:
26
  def __init__(self):
27
+ self.headers = {
28
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
29
+ }
30
+
31
+ def is_valid_url(self, url: str) -> bool:
32
+ try:
33
+ result = urlparse(url)
34
+ return all([result.scheme, result.netloc])
35
+ except:
36
+ return False
37
+
38
+ def scrape_text(self, url: str) -> str:
39
+ if not self.is_valid_url(url):
40
+ raise ValueError(f"Invalid URL: {url}")
41
 
42
+ try:
43
+ response = requests.get(url, headers=self.headers, timeout=10)
44
+ response.raise_for_status()
45
+
46
+ soup = BeautifulSoup(response.text, 'html.parser')
47
+
48
+ # Remove script and style elements
49
+ for script in soup(["script", "style"]):
50
+ script.decompose()
51
+
52
+ text = soup.get_text(separator=' ', strip=True)
53
+
54
+ # Clean up whitespace
55
+ text = re.sub(r'\s+', ' ', text)
56
+ return text
57
+
58
+ except Exception as e:
59
+ logger.error(f"Error scraping {url}: {str(e)}")
60
+ return ""
61
+
62
+ class TextChunker:
63
+ def __init__(self, chunk_size: int = 500, overlap: int = 50):
64
+ self.chunk_size = chunk_size
65
+ self.overlap = overlap
66
+
67
+ def chunk_text(self, text: str, source_url: str) -> List[TextChunk]:
68
+ words = text.split()
69
+ chunks = []
70
 
71
+ for i in range(0, len(words), self.chunk_size - self.overlap):
72
+ chunk_words = words[i:i + self.chunk_size]
73
+ chunk_text = ' '.join(chunk_words)
74
+ chunks.append(TextChunk(text=chunk_text, source_url=source_url))
75
+
76
+ return chunks
77
+
78
+ class VectorStore:
79
+ def __init__(self, model_name: str = 'all-MiniLM-L6-v2'):
80
+ self.model = SentenceTransformer(model_name)
81
+ self.chunks: List[TextChunk] = []
82
+ self.cache_file = "vector_store_cache.json"
83
+ self.load_cache()
84
+
85
+ def load_cache(self):
86
+ if os.path.exists(self.cache_file):
87
+ try:
88
+ with open(self.cache_file, 'r', encoding='utf-8') as f:
89
+ data = json.load(f)
90
+ self.chunks = [
91
+ TextChunk(
92
+ text=item['text'],
93
+ source_url=item['source_url'],
94
+ embedding=np.array(item['embedding']) if item['embedding'] else None
95
+ )
96
+ for item in data
97
+ ]
98
+ logger.info(f"Loaded {len(self.chunks)} chunks from cache")
99
+ except Exception as e:
100
+ logger.error(f"Error loading cache: {str(e)}")
101
+
102
+ def save_cache(self):
103
+ try:
104
+ data = [
105
+ {
106
+ 'text': chunk.text,
107
+ 'source_url': chunk.source_url,
108
+ 'embedding': chunk.embedding.tolist() if chunk.embedding is not None else None
109
+ }
110
+ for chunk in self.chunks
111
+ ]
112
+ with open(self.cache_file, 'w', encoding='utf-8') as f:
113
+ json.dump(data, f)
114
+ logger.info(f"Saved {len(self.chunks)} chunks to cache")
115
+ except Exception as e:
116
+ logger.error(f"Error saving cache: {str(e)}")
117
+
118
+ def add_chunks(self, chunks: List[TextChunk]):
119
+ for chunk in chunks:
120
+ if chunk.embedding is None:
121
+ chunk.embedding = self.model.encode(chunk.text)
122
+ self.chunks.extend(chunks)
123
+ self.save_cache()
124
+
125
+ def search(self, query: str, k: int = 3) -> List[TextChunk]:
126
+ query_embedding = self.model.encode(query)
127
 
128
+ similarities = []
129
+ for chunk in self.chunks:
130
+ if chunk.embedding is not None:
131
+ similarity = np.dot(query_embedding, chunk.embedding) / (
132
+ np.linalg.norm(query_embedding) * np.linalg.norm(chunk.embedding)
133
+ )
134
+ similarities.append((similarity, chunk))
 
 
 
135
 
136
+ similarities.sort(reverse=True)
137
+ return [chunk for _, chunk in similarities[:k]]
138
 
139
  class AssistenteBiblico:
140
  def __init__(self):
141
  self.dados_biblia = self.carregar_dados_biblia()
142
  self.prompts_tematicos = self.carregar_prompts()
143
+ self.scraper = WebScraper()
144
+ self.chunker = TextChunker()
145
+ self.vector_store = VectorStore()
146
 
147
+ def carregar_dados_biblia(self) -> List[Dict]:
148
+ # [Previous Bible data loading code remains the same]
149
+ return [] # Simplified for example
150
+
151
+ def carregar_prompts(self) -> Dict:
152
+ # [Previous prompts loading code remains the same]
153
+ return {} # Simplified for example
154
+
155
+ def adicionar_fonte_web(self, url: str) -> bool:
156
+ """Add content from a web URL to the knowledge base"""
157
  try:
158
+ # Scrape the content
159
+ text = self.scraper.scrape_text(url)
160
+ if not text:
161
+ return False
162
+
163
+ # Chunk the text
164
+ chunks = self.chunker.chunk_text(text, url)
165
 
166
+ # Add to vector store
167
+ self.vector_store.add_chunks(chunks)
 
168
 
169
+ return True
 
170
 
171
+ except Exception as e:
172
+ logger.error(f"Error adding web source: {str(e)}")
173
+ return False
174
+
175
+ def gerar_resposta(self, pergunta: str) -> str:
176
+ try:
177
+ # Get relevant chunks from vector store
178
+ chunks_relevantes = self.vector_store.search(pergunta)
179
 
180
+ # Get relevant Bible verses
181
+ versiculos = self.buscar_versiculos(pergunta)
 
 
 
182
 
183
+ resposta = "📖 Encontrei estas informações relevantes:\n\n"
 
184
 
185
+ # Add relevant chunks from web sources
186
+ if chunks_relevantes:
187
+ resposta += "🌐 De fontes complementares:\n"
188
+ for chunk in chunks_relevantes:
189
+ # Add a brief excerpt from the chunk
190
+ excerpt = chunk.text[:200] + "..."
191
+ resposta += f"- {excerpt}\n"
192
+ resposta += f" Fonte: {chunk.source_url}\n\n"
193
 
194
+ # Add Bible verses
195
+ if versiculos:
196
+ resposta += "✝️ Versículos bíblicos relacionados:\n"
197
+ for versiculo in versiculos:
198
+ resposta += f"➤ {versiculo['referencia']}\n"
199
+ resposta += f"{versiculo['texto']}\n\n"
200
 
201
  resposta += "\n💭 Reflita sobre estas palavras e busque orientação pastoral se necessário."
202
 
 
209
  def criar_interface():
210
  assistente = AssistenteBiblico()
211
 
212
+ def adicionar_fonte(url: str) -> str:
213
+ if assistente.adicionar_fonte_web(url):
214
+ return f"✅ Fonte adicionada com sucesso: {url}"
215
+ return f"❌ Erro ao adicionar fonte: {url}"
216
+
217
  def processar_prompt(prompt: str, historico: List) -> List:
218
  try:
219
  resposta = assistente.gerar_resposta(prompt)
 
222
  logger.error(f"Erro: {str(e)}")
223
  return historico + [(prompt, "Desculpe, ocorreu um erro.")]
224
 
225
+ with gr.Blocks(title="Assistente Bíblico") as demo:
226
  gr.HTML("""
227
  <div style="text-align: center; padding: 20px; background-color: #f0f8ff; border-radius: 10px;">
228
+ <h1 style="color: #2c3e50;">🙏 Conselheiro Bíblico</h1>
229
+ <p style="color: #34495e;">Encontre orientação e conforto na Palavra de Deus e recursos complementares</p>
230
  </div>
231
  """)
232
 
233
  with gr.Row():
234
  with gr.Column(scale=2):
235
+ chatbot = gr.Chatbot(height=500, label="Conversa")
 
 
 
236
 
237
  with gr.Row():
238
  msg = gr.Textbox(
239
  show_label=False,
240
+ placeholder="Digite sua dúvida ou escolha uma sugestão ao lado...",
241
  scale=8
242
  )
243
+ limpar = gr.Button("🔄 Recomeçar", scale=1)
 
 
 
244
 
245
+ with gr.Row():
246
+ url_input = gr.Textbox(
247
+ label="Adicionar fonte de conhecimento (URL)",
248
+ placeholder="https://exemplo.com/artigo-cristao",
249
+ scale=8
250
+ )
251
+ add_source = gr.Button("➕ Adicionar", scale=1)
 
 
 
 
 
 
 
 
 
252
 
253
+ fonte_status = gr.Textbox(label="Status da fonte", interactive=False)
254
+
255
+ with gr.Column(scale=1):
256
+ gr.Markdown("### 📚 Temas para Explorar")
257
+ # [Rest of the interface code remains the same]
 
 
258
 
259
  msg.submit(processar_prompt, [msg, chatbot], [chatbot])
260
  limpar.click(lambda: [], None, chatbot, queue=False)
261
+ add_source.click(adicionar_fonte, url_input, fonte_status)
262
 
263
  return demo
264