Spaces:
Running
Running
Update ai_logic.py
Browse files- ai_logic.py +67 -107
ai_logic.py
CHANGED
@@ -16,38 +16,37 @@ VECTOR_STORE_PATH = "faiss_index_store.pkl"
|
|
16 |
PROCESSED_URLS_PATH = "processed_urls.pkl"
|
17 |
HF_TOKEN = os.getenv("HF_TOKEN")
|
18 |
if not HF_TOKEN:
|
19 |
-
raise ValueError("Token HF_TOKEN não encontrado
|
20 |
|
21 |
-
# Lista de
|
22 |
-
|
23 |
-
|
24 |
-
"
|
25 |
-
"
|
26 |
-
"Zephyr 7B (Equilibrado)": "HuggingFaceH4/zephyr-7b-beta",
|
27 |
-
|
28 |
-
# 13 Novos Modelos
|
29 |
-
"Gemma 2 9B (Google)": "google/gemma-2-9b-it",
|
30 |
-
"Llama 3 8B (Meta)": "meta-llama/Meta-Llama-3-8B-Instruct",
|
31 |
-
"Mixtral 8x7B (Mistral)": "mistralai/Mixtral-8x7B-Instruct-v0.1",
|
32 |
-
"Qwen2 7B (Alibaba)": "Qwen/Qwen2-7B-Instruct",
|
33 |
-
"Command R+ (Cohere)": "CohereForAI/c4ai-command-r-plus",
|
34 |
-
"Gemma 7B (Google)": "google/gemma-7b-it",
|
35 |
-
"Arctic (Snowflake)": "Snowflake/snowflake-arctic-instruct",
|
36 |
-
"OpenChat 3.5": "openchat/openchat-3.5-0106",
|
37 |
-
"Starling 7B (Nexus)": "Nexusflow/Starling-LM-7B-beta",
|
38 |
-
"Yi 1.5 9B (01-AI)": "01-ai/Yi-1.5-9B-Chat",
|
39 |
-
"CodeGemma 7B (Google)": "google/codegemma-7b-it",
|
40 |
-
"Heron 13B (Donako)": "Donako/heron-chat-13b",
|
41 |
-
"Stable Beluga 7B": "stabilityai/stable-beluga-7b"
|
42 |
}
|
43 |
|
44 |
-
#
|
45 |
-
|
46 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
|
48 |
# --- Gerenciamento de Sessão ---
|
49 |
user_sessions: Dict[str, Dict[str, List | Dict]] = {} # {session_id: {'conversation': [], 'user_profile': {}}}
|
50 |
-
MAX_MEMORY_LENGTH = 5
|
51 |
|
52 |
def get_session_memory_path(session_id: str) -> str:
|
53 |
"""Retorna o caminho do arquivo de memória para a sessão."""
|
@@ -96,11 +95,13 @@ def update_user_profile(session_id: str, user_message: str):
|
|
96 |
profile = user_sessions[session_id]['user_profile']
|
97 |
message_lower = user_message.lower()
|
98 |
|
|
|
99 |
if any(word in message_lower for word in ['básico', 'iniciante']):
|
100 |
profile['nivel'] = 'iniciante'
|
101 |
elif any(word in message_lower for word in ['avançado', 'complexo']):
|
102 |
profile['nivel'] = 'avançado'
|
103 |
|
|
|
104 |
topics = {
|
105 |
'java': ['java', 'classe', 'objeto'],
|
106 |
'web': ['html', 'css', 'javascript'],
|
@@ -116,7 +117,7 @@ def update_user_profile(session_id: str, user_message: str):
|
|
116 |
def get_conversation_context(session_id: str) -> str:
|
117 |
"""Gera o contexto da conversa recente."""
|
118 |
load_conversation_memory(session_id)
|
119 |
-
conversation = user_sessions[session_id]['conversation'][-4:]
|
120 |
if not conversation:
|
121 |
return ""
|
122 |
return "\n".join(f"{msg['role'].upper()}: {msg['content']}" for msg in conversation)
|
@@ -148,19 +149,18 @@ def get_all_blog_links(url: str) -> set:
|
|
148 |
"""Coleta todos os links do blog."""
|
149 |
links = {url}
|
150 |
visited = set()
|
151 |
-
|
152 |
-
|
153 |
-
current_url = queue.pop(0)
|
154 |
if current_url in visited:
|
155 |
continue
|
156 |
try:
|
157 |
-
response = requests.get(current_url, timeout=
|
158 |
soup = BeautifulSoup(response.content, 'html.parser')
|
159 |
visited.add(current_url)
|
160 |
for link in soup.find_all('a', href=True):
|
161 |
href = urljoin(url, link['href'])
|
162 |
-
if urlparse(href).netloc == urlparse(url).netloc and '/tag/' not in href and '/category/' not in href
|
163 |
-
|
164 |
except Exception as e:
|
165 |
print(f"Erro ao acessar {current_url}: {e}")
|
166 |
return visited
|
@@ -168,7 +168,7 @@ def get_all_blog_links(url: str) -> set:
|
|
168 |
def scrape_text_from_url(url: str) -> str:
|
169 |
"""Extrai texto de uma URL."""
|
170 |
try:
|
171 |
-
response = requests.get(url, timeout=
|
172 |
soup = BeautifulSoup(response.content, 'html.parser')
|
173 |
content = soup.find('article') or soup.find('main')
|
174 |
return content.get_text(separator='\n', strip=True) if content else ""
|
@@ -221,11 +221,7 @@ class HuggingFaceAPIClient:
|
|
221 |
|
222 |
def query_model(self, model_name: str, messages: List[Dict], max_tokens: int = 1000) -> str:
|
223 |
"""Faz requisição à API do Hugging Face."""
|
224 |
-
url = f"https://api-inference.huggingface.co/models/{model_name}"
|
225 |
-
# Para a nova API de chat
|
226 |
-
if "/v1/chat/completions" not in url:
|
227 |
-
url += "/v1/chat/completions"
|
228 |
-
|
229 |
payload = {
|
230 |
"model": model_name,
|
231 |
"messages": messages,
|
@@ -233,65 +229,47 @@ class HuggingFaceAPIClient:
|
|
233 |
"temperature": 0.7
|
234 |
}
|
235 |
try:
|
236 |
-
response = requests.post(url, headers=self.headers, json=payload, timeout=
|
237 |
response.raise_for_status()
|
238 |
return response.json()["choices"][0]["message"]["content"].strip()
|
239 |
-
except
|
240 |
-
|
241 |
-
print(f"Erro na requisição para o modelo {model_name}: {e}")
|
242 |
-
raise
|
243 |
-
except (KeyError, IndexError) as e:
|
244 |
-
# Captura erros na estrutura da resposta JSON
|
245 |
-
print(f"Resposta inesperada do modelo {model_name}: {response.text}")
|
246 |
-
raise
|
247 |
-
|
248 |
-
api_client = HuggingFaceAPIClient(HF_TOKEN)
|
249 |
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
"""
|
256 |
-
global MODELS, DEFAULT_MODEL
|
257 |
-
print("Verificando a disponibilidade dos modelos do Hugging Face...")
|
258 |
-
|
259 |
-
test_messages = [{"role": "user", "content": "Ping"}]
|
260 |
-
|
261 |
-
for friendly_name, model_id in CANDIDATE_MODELS.items():
|
262 |
-
print(f" - Testando: {friendly_name} ({model_id})... ", end="")
|
263 |
try:
|
264 |
-
|
265 |
-
|
266 |
-
MODELS[friendly_name] = model_id
|
267 |
-
print("✅ Disponível!")
|
268 |
except Exception:
|
269 |
-
|
270 |
-
|
271 |
-
if not MODELS:
|
272 |
-
raise RuntimeError("Nenhum dos modelos configurados está disponível no momento. Verifique seu token HF_TOKEN e a disponibilidade dos modelos.")
|
273 |
|
274 |
-
|
275 |
-
if DEFAULT_MODEL not in MODELS:
|
276 |
-
# Pega o primeiro modelo da lista de disponíveis como novo padrão
|
277 |
-
new_default_key = next(iter(MODELS))
|
278 |
-
print(f"Aviso: O modelo padrão '{DEFAULT_MODEL}' não está disponível.")
|
279 |
-
print(f"Definindo '{new_default_key}' como o novo padrão.")
|
280 |
-
DEFAULT_MODEL = new_default_key
|
281 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
282 |
|
283 |
# --- Chat Principal ---
|
284 |
-
def responder_como_aldo(session_id: str, pergunta: str, modelo: str =
|
285 |
"""Gera resposta como Dr. Aldo Henrique."""
|
286 |
-
if modelo is None:
|
287 |
-
modelo = DEFAULT_MODEL # Usa o padrão dinâmico
|
288 |
-
|
289 |
if not pergunta.strip():
|
290 |
return "Por favor, faça uma pergunta válida."
|
291 |
|
292 |
load_conversation_memory(session_id)
|
293 |
update_user_profile(session_id, pergunta)
|
294 |
|
|
|
295 |
contexto = []
|
296 |
if perfil := get_user_profile_context(session_id):
|
297 |
contexto.append(f"**Perfil do Usuário**\n{perfil}")
|
@@ -323,39 +301,21 @@ def responder_como_aldo(session_id: str, pergunta: str, modelo: str = None) -> s
|
|
323 |
]
|
324 |
|
325 |
model_name = MODELS.get(modelo, MODELS[DEFAULT_MODEL])
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
return resposta
|
330 |
-
except Exception as e:
|
331 |
-
return f"Desculpe, houve um erro ao processar sua solicitação com o modelo {modelo}. Detalhes: {e}"
|
332 |
-
|
333 |
|
334 |
# --- Inicialização ---
|
335 |
def inicializar_sistema():
|
336 |
"""Inicializa o sistema."""
|
337 |
print("Inicializando Chatbot Dr. Aldo...")
|
338 |
-
|
339 |
load_vector_store()
|
340 |
-
print("
|
341 |
-
print(f"Modelos disponíveis: {list(MODELS.keys())}")
|
342 |
-
print(f"Modelo padrão: {DEFAULT_MODEL}")
|
343 |
-
|
344 |
|
345 |
if __name__ == "__main__":
|
346 |
inicializar_sistema()
|
347 |
-
|
348 |
session_id = "teste_123"
|
349 |
-
print("
|
350 |
-
|
351 |
-
# Exemplo de pergunta
|
352 |
-
pergunta_teste = "O que é um Large Language Model (LLM) e como ele se difere da IA tradicional?"
|
353 |
-
print(f"\n[Usuário]: {pergunta_teste}")
|
354 |
-
|
355 |
-
# A função agora usa o modelo padrão que foi verificado como disponível
|
356 |
-
resposta_aldo = responder_como_aldo(session_id, pergunta_teste)
|
357 |
-
print(f"\n[Dr. Aldo]: {resposta_aldo}")
|
358 |
-
|
359 |
-
# Limpando a memória da sessão de teste
|
360 |
-
print(f"\n--- Limpando Memória ---")
|
361 |
print(clear_memory(session_id))
|
|
|
16 |
PROCESSED_URLS_PATH = "processed_urls.pkl"
|
17 |
HF_TOKEN = os.getenv("HF_TOKEN")
|
18 |
if not HF_TOKEN:
|
19 |
+
raise ValueError("Token HF_TOKEN não encontrado")
|
20 |
|
21 |
+
# Lista inicial de modelos
|
22 |
+
MODELS = {
|
23 |
+
"Mistral 7B (Mais acertivo)": "mistralai/Mistral-7B-Instruct-v0.3",
|
24 |
+
"Phi-3 Mini (Mais rápido)": "microsoft/Phi-3-mini-4k-instruct",
|
25 |
+
"Zephyr 7B (Meio Termo)": "HuggingFaceH4/zephyr-7b-beta"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
}
|
27 |
|
28 |
+
# Novos modelos para testar
|
29 |
+
NEW_MODELS_TO_TEST = [
|
30 |
+
("LLaMA 2-7B Chat", "meta-llama/Llama-2-7b-chat"),
|
31 |
+
("LLaMA 3.2-3B Instruct", "meta-llama/Llama-3.2-3B-Instruct"),
|
32 |
+
("Gemma 2B Instruct", "google/gemma-2b-it"),
|
33 |
+
("Qwen2 7B Instruct", "Qwen/Qwen2-7B-Instruct"),
|
34 |
+
("Falcon 7B Instruct", "tiiuae/falcon-7b-instruct"),
|
35 |
+
("Mixtral 8x7B Instruct", "mistralai/Mixtral-8x7B-Instruct-v0.1"),
|
36 |
+
("LLaMA 3.1-8B Instruct", "meta-llama/Llama-3.1-8B-Instruct"),
|
37 |
+
("GPT2 XL", "gpt2-xl"),
|
38 |
+
("T5 Base", "t5-base"),
|
39 |
+
("Grok 2 Mini", "xAI/grok2-mini"),
|
40 |
+
("CodeLlama 7B Instruct", "codellama/CodeLlama-7b-Instruct-hf"),
|
41 |
+
("Starling LM 7B", "HuggingFaceH4/starling-lm-7b-alpha"),
|
42 |
+
("OpenHermes 2.5 Mistral", "teknium/OpenHermes-2.5-Mistral-7B")
|
43 |
+
]
|
44 |
+
|
45 |
+
DEFAULT_MODEL = "Mistral 7B (Mais acertivo)"
|
46 |
|
47 |
# --- Gerenciamento de Sessão ---
|
48 |
user_sessions: Dict[str, Dict[str, List | Dict]] = {} # {session_id: {'conversation': [], 'user_profile': {}}}
|
49 |
+
MAX_MEMORY_LENGTH = 5 # Máximo de trocas (user + assistant)
|
50 |
|
51 |
def get_session_memory_path(session_id: str) -> str:
|
52 |
"""Retorna o caminho do arquivo de memória para a sessão."""
|
|
|
95 |
profile = user_sessions[session_id]['user_profile']
|
96 |
message_lower = user_message.lower()
|
97 |
|
98 |
+
# Atualiza nível
|
99 |
if any(word in message_lower for word in ['básico', 'iniciante']):
|
100 |
profile['nivel'] = 'iniciante'
|
101 |
elif any(word in message_lower for word in ['avançado', 'complexo']):
|
102 |
profile['nivel'] = 'avançado'
|
103 |
|
104 |
+
# Atualiza interesses
|
105 |
topics = {
|
106 |
'java': ['java', 'classe', 'objeto'],
|
107 |
'web': ['html', 'css', 'javascript'],
|
|
|
117 |
def get_conversation_context(session_id: str) -> str:
|
118 |
"""Gera o contexto da conversa recente."""
|
119 |
load_conversation_memory(session_id)
|
120 |
+
conversation = user_sessions[session_id]['conversation'][-4:] # Últimas 2 trocas
|
121 |
if not conversation:
|
122 |
return ""
|
123 |
return "\n".join(f"{msg['role'].upper()}: {msg['content']}" for msg in conversation)
|
|
|
149 |
"""Coleta todos os links do blog."""
|
150 |
links = {url}
|
151 |
visited = set()
|
152 |
+
while links:
|
153 |
+
current_url = links.pop()
|
|
|
154 |
if current_url in visited:
|
155 |
continue
|
156 |
try:
|
157 |
+
response = requests.get(current_url, timeout=500)
|
158 |
soup = BeautifulSoup(response.content, 'html.parser')
|
159 |
visited.add(current_url)
|
160 |
for link in soup.find_all('a', href=True):
|
161 |
href = urljoin(url, link['href'])
|
162 |
+
if urlparse(href).netloc == urlparse(url).netloc and '/tag/' not in href and '/category/' not in href:
|
163 |
+
links.add(href)
|
164 |
except Exception as e:
|
165 |
print(f"Erro ao acessar {current_url}: {e}")
|
166 |
return visited
|
|
|
168 |
def scrape_text_from_url(url: str) -> str:
|
169 |
"""Extrai texto de uma URL."""
|
170 |
try:
|
171 |
+
response = requests.get(url, timeout=500)
|
172 |
soup = BeautifulSoup(response.content, 'html.parser')
|
173 |
content = soup.find('article') or soup.find('main')
|
174 |
return content.get_text(separator='\n', strip=True) if content else ""
|
|
|
221 |
|
222 |
def query_model(self, model_name: str, messages: List[Dict], max_tokens: int = 1000) -> str:
|
223 |
"""Faz requisição à API do Hugging Face."""
|
224 |
+
url = f"https://api-inference.huggingface.co/models/{model_name}/v1/chat/completions"
|
|
|
|
|
|
|
|
|
225 |
payload = {
|
226 |
"model": model_name,
|
227 |
"messages": messages,
|
|
|
229 |
"temperature": 0.7
|
230 |
}
|
231 |
try:
|
232 |
+
response = requests.post(url, headers=self.headers, json=payload, timeout=10)
|
233 |
response.raise_for_status()
|
234 |
return response.json()["choices"][0]["message"]["content"].strip()
|
235 |
+
except Exception as e:
|
236 |
+
return f"Erro na API: {str(e)}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
237 |
|
238 |
+
def test_model_availability(self, model_name: str) -> bool:
|
239 |
+
"""Testa se um modelo está disponível na API do Hugging Face."""
|
240 |
+
test_messages = [
|
241 |
+
{"role": "user", "content": "Teste de disponibilidade."}
|
242 |
+
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
243 |
try:
|
244 |
+
response = self.query_model(model_name, test_messages, max_tokens=10)
|
245 |
+
return not response.startswith("Erro na API")
|
|
|
|
|
246 |
except Exception:
|
247 |
+
return False
|
|
|
|
|
|
|
248 |
|
249 |
+
api_client = HuggingFaceAPIClient(HF_TOKEN)
|
|
|
|
|
|
|
|
|
|
|
|
|
250 |
|
251 |
+
# --- Função para Testar e Atualizar Modelos ---
|
252 |
+
def test_and_update_models():
|
253 |
+
"""Testa a disponibilidade dos novos modelos e atualiza a lista MODELS."""
|
254 |
+
print("Testando disponibilidade dos novos modelos...")
|
255 |
+
for model_label, model_name in NEW_MODELS_TO_TEST:
|
256 |
+
if api_client.test_model_availability(model_name):
|
257 |
+
MODELS[model_label] = model_name
|
258 |
+
print(f"Modelo {model_label} ({model_name}) adicionado à lista.")
|
259 |
+
else:
|
260 |
+
print(f"Modelo {model_label} ({model_name}) não disponível.")
|
261 |
+
print(f"Total de modelos disponíveis: {len(MODELS)}")
|
262 |
|
263 |
# --- Chat Principal ---
|
264 |
+
def responder_como_aldo(session_id: str, pergunta: str, modelo: str = DEFAULT_MODEL) -> str:
|
265 |
"""Gera resposta como Dr. Aldo Henrique."""
|
|
|
|
|
|
|
266 |
if not pergunta.strip():
|
267 |
return "Por favor, faça uma pergunta válida."
|
268 |
|
269 |
load_conversation_memory(session_id)
|
270 |
update_user_profile(session_id, pergunta)
|
271 |
|
272 |
+
# Monta contexto
|
273 |
contexto = []
|
274 |
if perfil := get_user_profile_context(session_id):
|
275 |
contexto.append(f"**Perfil do Usuário**\n{perfil}")
|
|
|
301 |
]
|
302 |
|
303 |
model_name = MODELS.get(modelo, MODELS[DEFAULT_MODEL])
|
304 |
+
resposta = api_client.query_model(model_name, messages)
|
305 |
+
add_to_memory(session_id, pergunta, resposta)
|
306 |
+
return resposta
|
|
|
|
|
|
|
|
|
307 |
|
308 |
# --- Inicialização ---
|
309 |
def inicializar_sistema():
|
310 |
"""Inicializa o sistema."""
|
311 |
print("Inicializando Chatbot Dr. Aldo...")
|
312 |
+
test_and_update_models() # Testa e atualiza modelos disponíveis
|
313 |
load_vector_store()
|
314 |
+
print("Sistema inicializado!")
|
|
|
|
|
|
|
315 |
|
316 |
if __name__ == "__main__":
|
317 |
inicializar_sistema()
|
|
|
318 |
session_id = "teste_123"
|
319 |
+
print(responder_como_aldo(session_id, "O que é Java?"))
|
320 |
+
print(responder_como_aldo(session_id, "Mostre um exemplo de código Java."))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
321 |
print(clear_memory(session_id))
|