Spaces:
Running
Running
Update ai_logic.py
Browse files- ai_logic.py +178 -47
ai_logic.py
CHANGED
@@ -27,38 +27,25 @@ MODELS = {
|
|
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", "
|
42 |
("OpenHermes 2.5 Mistral", "teknium/OpenHermes-2.5-Mistral-7B"),
|
43 |
-
("Gemma 2B Instruct (Leve e Eficaz)", "google/gemma-2b-it"),
|
44 |
-
("Qwen2 7B Instruct (Versátil)", "Qwen/Qwen2-7B-Instruct"),
|
45 |
-
("OpenHermes 2.5 Mistral (Para Chat)", "teknium/OpenHermes-2.5-Mistral-7B"),
|
46 |
-
("LLaMA 2-7B Chat (Requer aceitação de licença Meta)", "meta-llama/Llama-2-7b-chat"),
|
47 |
-
("LLaMA 3.1-8B Instruct (Requer aceitação de licença Meta)", "meta-llama/Llama-3.1-8B-Instruct"),
|
48 |
-
("Mistral 7B (Mais assertivo)", "mistralai/Mistral-7B-Instruct-v0.3"),
|
49 |
-
("Phi-3 Mini (Mais rápido)", "microsoft/Phi-3-mini-4k-instruct"),
|
50 |
-
("Zephyr 7B (Meio termo)", "HuggingFaceH4/zephyr-7b-beta"),
|
51 |
("Gemma 7B Instruct", "google/gemma-7b-it"),
|
52 |
("Qwen 2.5-7B Instruct", "Qwen/Qwen2.5-7B-Instruct"),
|
53 |
-
("
|
54 |
-
("Dream 7B Instruct", "Dream-org/Dream-v0-Instruct-7B"),
|
55 |
-
("OLMo 7B Instruct", "allenai/OLMo-7B-Instruct")
|
56 |
]
|
57 |
DEFAULT_MODEL = "Mistral 7B (Mais acertivo)"
|
58 |
|
59 |
# --- Gerenciamento de Sessão ---
|
60 |
-
user_sessions: Dict[str, Dict[str, List | Dict]] = {}
|
61 |
-
MAX_MEMORY_LENGTH = 5
|
62 |
|
63 |
def get_session_memory_path(session_id: str) -> str:
|
64 |
"""Retorna o caminho do arquivo de memória para a sessão."""
|
@@ -107,13 +94,11 @@ def update_user_profile(session_id: str, user_message: str):
|
|
107 |
profile = user_sessions[session_id]['user_profile']
|
108 |
message_lower = user_message.lower()
|
109 |
|
110 |
-
# Atualiza nível
|
111 |
if any(word in message_lower for word in ['básico', 'iniciante']):
|
112 |
profile['nivel'] = 'iniciante'
|
113 |
elif any(word in message_lower for word in ['avançado', 'complexo']):
|
114 |
profile['nivel'] = 'avançado'
|
115 |
|
116 |
-
# Atualiza interesses
|
117 |
topics = {
|
118 |
'java': ['java', 'classe', 'objeto'],
|
119 |
'web': ['html', 'css', 'javascript'],
|
@@ -129,7 +114,7 @@ def update_user_profile(session_id: str, user_message: str):
|
|
129 |
def get_conversation_context(session_id: str) -> str:
|
130 |
"""Gera o contexto da conversa recente."""
|
131 |
load_conversation_memory(session_id)
|
132 |
-
conversation = user_sessions[session_id]['conversation'][-4:]
|
133 |
if not conversation:
|
134 |
return ""
|
135 |
return "\n".join(f"{msg['role'].upper()}: {msg['content']}" for msg in conversation)
|
@@ -231,34 +216,141 @@ class HuggingFaceAPIClient:
|
|
231 |
def __init__(self, token: str):
|
232 |
self.headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
233 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
234 |
def query_model(self, model_name: str, messages: List[Dict], max_tokens: int = 1000) -> str:
|
235 |
-
"""Faz requisição
|
236 |
-
|
|
|
|
|
|
|
237 |
payload = {
|
238 |
-
"
|
239 |
-
"
|
240 |
-
|
241 |
-
|
|
|
|
|
|
|
242 |
}
|
|
|
243 |
try:
|
244 |
-
response = requests.post(url, headers=self.headers, json=payload, timeout=
|
245 |
response.raise_for_status()
|
246 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
247 |
except requests.exceptions.HTTPError as http_err:
|
248 |
return f"Erro HTTP: {http_err.response.status_code} - {http_err.response.text}"
|
249 |
except requests.exceptions.RequestException as e:
|
250 |
return f"Erro na requisição: {str(e)}"
|
251 |
|
252 |
-
def
|
253 |
-
"""
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
262 |
|
263 |
api_client = HuggingFaceAPIClient(HF_TOKEN)
|
264 |
|
@@ -266,28 +358,61 @@ api_client = HuggingFaceAPIClient(HF_TOKEN)
|
|
266 |
def test_and_update_models():
|
267 |
"""Testa a disponibilidade dos novos modelos e atualiza a lista MODELS."""
|
268 |
print("Testando disponibilidade dos novos modelos...")
|
|
|
|
|
|
|
269 |
available_models = []
|
270 |
unavailable_models = []
|
271 |
|
272 |
for model_label, model_name in NEW_MODELS_TO_TEST:
|
273 |
is_available, message = api_client.test_model_availability(model_name)
|
|
|
274 |
if is_available:
|
275 |
MODELS[model_label] = model_name
|
276 |
available_models.append((model_label, model_name, message))
|
|
|
277 |
else:
|
278 |
unavailable_models.append((model_label, model_name, message))
|
279 |
-
|
280 |
-
|
281 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
282 |
if available_models:
|
283 |
-
print("\
|
284 |
for label, name, msg in available_models:
|
285 |
-
print(f"- {label}
|
|
|
|
|
|
|
|
|
286 |
if unavailable_models:
|
287 |
-
print("\
|
288 |
for label, name, msg in unavailable_models:
|
289 |
-
print(f"- {label}
|
290 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
291 |
|
292 |
# --- Chat Principal ---
|
293 |
def responder_como_aldo(session_id: str, pergunta: str, modelo: str = DEFAULT_MODEL) -> str:
|
@@ -344,7 +469,13 @@ def inicializar_sistema():
|
|
344 |
|
345 |
if __name__ == "__main__":
|
346 |
inicializar_sistema()
|
|
|
347 |
session_id = "teste_123"
|
|
|
|
|
|
|
348 |
print(responder_como_aldo(session_id, "O que é Java?"))
|
|
|
349 |
print(responder_como_aldo(session_id, "Mostre um exemplo de código Java."))
|
|
|
350 |
print(clear_memory(session_id))
|
|
|
27 |
|
28 |
# Novos modelos para testar
|
29 |
NEW_MODELS_TO_TEST = [
|
30 |
+
("LLaMA 2-7B Chat", "meta-llama/Llama-2-7b-chat-hf"),
|
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 |
("CodeLlama 7B Instruct", "codellama/CodeLlama-7b-Instruct-hf"),
|
38 |
+
("Starling LM 7B", "berkeley-nest/Starling-LM-7B-alpha"),
|
39 |
("OpenHermes 2.5 Mistral", "teknium/OpenHermes-2.5-Mistral-7B"),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
("Gemma 7B Instruct", "google/gemma-7b-it"),
|
41 |
("Qwen 2.5-7B Instruct", "Qwen/Qwen2.5-7B-Instruct"),
|
42 |
+
("OLMo 7B Instruct", "allenai/OLMo-7B-Instruct-hf")
|
|
|
|
|
43 |
]
|
44 |
DEFAULT_MODEL = "Mistral 7B (Mais acertivo)"
|
45 |
|
46 |
# --- Gerenciamento de Sessão ---
|
47 |
+
user_sessions: Dict[str, Dict[str, List | Dict]] = {}
|
48 |
+
MAX_MEMORY_LENGTH = 5
|
49 |
|
50 |
def get_session_memory_path(session_id: str) -> str:
|
51 |
"""Retorna o caminho do arquivo de memória para a sessão."""
|
|
|
94 |
profile = user_sessions[session_id]['user_profile']
|
95 |
message_lower = user_message.lower()
|
96 |
|
|
|
97 |
if any(word in message_lower for word in ['básico', 'iniciante']):
|
98 |
profile['nivel'] = 'iniciante'
|
99 |
elif any(word in message_lower for word in ['avançado', 'complexo']):
|
100 |
profile['nivel'] = 'avançado'
|
101 |
|
|
|
102 |
topics = {
|
103 |
'java': ['java', 'classe', 'objeto'],
|
104 |
'web': ['html', 'css', 'javascript'],
|
|
|
114 |
def get_conversation_context(session_id: str) -> str:
|
115 |
"""Gera o contexto da conversa recente."""
|
116 |
load_conversation_memory(session_id)
|
117 |
+
conversation = user_sessions[session_id]['conversation'][-4:]
|
118 |
if not conversation:
|
119 |
return ""
|
120 |
return "\n".join(f"{msg['role'].upper()}: {msg['content']}" for msg in conversation)
|
|
|
216 |
def __init__(self, token: str):
|
217 |
self.headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
|
218 |
|
219 |
+
def check_model_info(self, model_name: str) -> Tuple[bool, str]:
|
220 |
+
"""Verifica informações do modelo via API do Hugging Face."""
|
221 |
+
url = f"https://huggingface.co/api/models/{model_name}"
|
222 |
+
try:
|
223 |
+
response = requests.get(url, headers=self.headers, timeout=10)
|
224 |
+
if response.status_code == 200:
|
225 |
+
model_info = response.json()
|
226 |
+
# Verifica se o modelo não está desabilitado
|
227 |
+
if model_info.get('disabled', False):
|
228 |
+
return False, "Modelo desabilitado"
|
229 |
+
# Verifica se requer aprovação
|
230 |
+
if model_info.get('gated', False):
|
231 |
+
return False, "Modelo requer aprovação/aceite de licença"
|
232 |
+
return True, "Modelo disponível"
|
233 |
+
elif response.status_code == 404:
|
234 |
+
return False, "Modelo não encontrado"
|
235 |
+
else:
|
236 |
+
return False, f"Erro HTTP {response.status_code}"
|
237 |
+
except requests.exceptions.RequestException as e:
|
238 |
+
return False, f"Erro na requisição: {str(e)}"
|
239 |
+
|
240 |
+
def test_model_inference(self, model_name: str) -> Tuple[bool, str]:
|
241 |
+
"""Testa se o modelo está disponível para inferência."""
|
242 |
+
# Primeiro, tenta o endpoint de text-generation (mais comum)
|
243 |
+
url = f"https://api-inference.huggingface.co/models/{model_name}"
|
244 |
+
test_payload = {
|
245 |
+
"inputs": "Teste de disponibilidade do modelo.",
|
246 |
+
"parameters": {
|
247 |
+
"max_new_tokens": 10,
|
248 |
+
"temperature": 0.1,
|
249 |
+
"return_full_text": False
|
250 |
+
}
|
251 |
+
}
|
252 |
+
|
253 |
+
try:
|
254 |
+
response = requests.post(url, headers=self.headers, json=test_payload, timeout=30)
|
255 |
+
|
256 |
+
if response.status_code == 200:
|
257 |
+
result = response.json()
|
258 |
+
if isinstance(result, list) and len(result) > 0:
|
259 |
+
return True, "Modelo disponível para inferência"
|
260 |
+
elif isinstance(result, dict) and 'error' not in result:
|
261 |
+
return True, "Modelo disponível para inferência"
|
262 |
+
else:
|
263 |
+
return False, f"Resposta inesperada: {result}"
|
264 |
+
|
265 |
+
elif response.status_code == 503:
|
266 |
+
return False, "Modelo está carregando (503)"
|
267 |
+
elif response.status_code == 400:
|
268 |
+
error_msg = response.json().get('error', 'Erro 400')
|
269 |
+
if 'loading' in error_msg.lower():
|
270 |
+
return False, "Modelo está carregando"
|
271 |
+
return False, f"Erro 400: {error_msg}"
|
272 |
+
elif response.status_code == 401:
|
273 |
+
return False, "Token inválido ou sem permissão"
|
274 |
+
elif response.status_code == 404:
|
275 |
+
return False, "Modelo não encontrado"
|
276 |
+
else:
|
277 |
+
return False, f"Erro HTTP {response.status_code}: {response.text}"
|
278 |
+
|
279 |
+
except requests.exceptions.Timeout:
|
280 |
+
return False, "Timeout na requisição"
|
281 |
+
except requests.exceptions.RequestException as e:
|
282 |
+
return False, f"Erro na requisição: {str(e)}"
|
283 |
+
|
284 |
+
def test_model_availability(self, model_name: str) -> Tuple[bool, str]:
|
285 |
+
"""Testa se um modelo está disponível, combinando verificação de info e inferência."""
|
286 |
+
print(f"Testando modelo: {model_name}")
|
287 |
+
|
288 |
+
# Primeiro verifica as informações do modelo
|
289 |
+
info_available, info_msg = self.check_model_info(model_name)
|
290 |
+
if not info_available:
|
291 |
+
return False, f"Info check failed: {info_msg}"
|
292 |
+
|
293 |
+
print(f" ✓ Info check: {info_msg}")
|
294 |
+
|
295 |
+
# Em seguida testa a inferência
|
296 |
+
inference_available, inference_msg = self.test_model_inference(model_name)
|
297 |
+
|
298 |
+
if inference_available:
|
299 |
+
print(f" ✓ Inference check: {inference_msg}")
|
300 |
+
return True, f"Disponível - {info_msg}"
|
301 |
+
else:
|
302 |
+
print(f" ✗ Inference check: {inference_msg}")
|
303 |
+
return False, f"Não disponível para inferência: {inference_msg}"
|
304 |
+
|
305 |
def query_model(self, model_name: str, messages: List[Dict], max_tokens: int = 1000) -> str:
|
306 |
+
"""Faz requisição ao modelo usando text-generation."""
|
307 |
+
# Converte mensagens para prompt simples
|
308 |
+
prompt = self._convert_messages_to_prompt(messages)
|
309 |
+
|
310 |
+
url = f"https://api-inference.huggingface.co/models/{model_name}"
|
311 |
payload = {
|
312 |
+
"inputs": prompt,
|
313 |
+
"parameters": {
|
314 |
+
"max_new_tokens": max_tokens,
|
315 |
+
"temperature": 0.7,
|
316 |
+
"do_sample": True,
|
317 |
+
"return_full_text": False
|
318 |
+
}
|
319 |
}
|
320 |
+
|
321 |
try:
|
322 |
+
response = requests.post(url, headers=self.headers, json=payload, timeout=60)
|
323 |
response.raise_for_status()
|
324 |
+
|
325 |
+
result = response.json()
|
326 |
+
if isinstance(result, list) and len(result) > 0:
|
327 |
+
return result[0].get('generated_text', '').strip()
|
328 |
+
elif isinstance(result, dict) and 'generated_text' in result:
|
329 |
+
return result['generated_text'].strip()
|
330 |
+
else:
|
331 |
+
return f"Formato de resposta inesperado: {result}"
|
332 |
+
|
333 |
except requests.exceptions.HTTPError as http_err:
|
334 |
return f"Erro HTTP: {http_err.response.status_code} - {http_err.response.text}"
|
335 |
except requests.exceptions.RequestException as e:
|
336 |
return f"Erro na requisição: {str(e)}"
|
337 |
|
338 |
+
def _convert_messages_to_prompt(self, messages: List[Dict]) -> str:
|
339 |
+
"""Converte mensagens do formato chat para prompt simples."""
|
340 |
+
prompt_parts = []
|
341 |
+
for msg in messages:
|
342 |
+
role = msg['role']
|
343 |
+
content = msg['content']
|
344 |
+
|
345 |
+
if role == 'system':
|
346 |
+
prompt_parts.append(f"Sistema: {content}")
|
347 |
+
elif role == 'user':
|
348 |
+
prompt_parts.append(f"Usuário: {content}")
|
349 |
+
elif role == 'assistant':
|
350 |
+
prompt_parts.append(f"Assistente: {content}")
|
351 |
+
|
352 |
+
prompt_parts.append("Assistente:")
|
353 |
+
return "\n\n".join(prompt_parts)
|
354 |
|
355 |
api_client = HuggingFaceAPIClient(HF_TOKEN)
|
356 |
|
|
|
358 |
def test_and_update_models():
|
359 |
"""Testa a disponibilidade dos novos modelos e atualiza a lista MODELS."""
|
360 |
print("Testando disponibilidade dos novos modelos...")
|
361 |
+
print(f"Token HF disponível: {'Sim' if HF_TOKEN else 'Não'}")
|
362 |
+
print("-" * 60)
|
363 |
+
|
364 |
available_models = []
|
365 |
unavailable_models = []
|
366 |
|
367 |
for model_label, model_name in NEW_MODELS_TO_TEST:
|
368 |
is_available, message = api_client.test_model_availability(model_name)
|
369 |
+
|
370 |
if is_available:
|
371 |
MODELS[model_label] = model_name
|
372 |
available_models.append((model_label, model_name, message))
|
373 |
+
print(f"✓ {model_label}")
|
374 |
else:
|
375 |
unavailable_models.append((model_label, model_name, message))
|
376 |
+
print(f"✗ {model_label} - {message}")
|
377 |
+
|
378 |
+
# Pequena pausa para evitar rate limiting
|
379 |
+
time.sleep(1)
|
380 |
+
|
381 |
+
# Exibir resultados finais
|
382 |
+
print("\n" + "=" * 60)
|
383 |
+
print("RESULTADOS DA VALIDAÇÃO:")
|
384 |
+
print("=" * 60)
|
385 |
+
|
386 |
if available_models:
|
387 |
+
print(f"\n✓ MODELOS DISPONÍVEIS ({len(available_models)}):")
|
388 |
for label, name, msg in available_models:
|
389 |
+
print(f" - {label}")
|
390 |
+
print(f" {name}")
|
391 |
+
print(f" Status: {msg}")
|
392 |
+
print()
|
393 |
+
|
394 |
if unavailable_models:
|
395 |
+
print(f"\n✗ MODELOS NÃO DISPONÍVEIS ({len(unavailable_models)}):")
|
396 |
for label, name, msg in unavailable_models:
|
397 |
+
print(f" - {label}")
|
398 |
+
print(f" {name}")
|
399 |
+
print(f" Motivo: {msg}")
|
400 |
+
print()
|
401 |
+
|
402 |
+
print(f"TOTAL DE MODELOS DISPONÍVEIS: {len(MODELS)}")
|
403 |
+
print("=" * 60)
|
404 |
+
|
405 |
+
# Salva a lista atualizada de modelos
|
406 |
+
save_updated_models()
|
407 |
+
|
408 |
+
def save_updated_models():
|
409 |
+
"""Salva a lista atualizada de modelos em um arquivo."""
|
410 |
+
try:
|
411 |
+
with open("models_available.json", "w", encoding="utf-8") as f:
|
412 |
+
json.dump(MODELS, f, ensure_ascii=False, indent=2)
|
413 |
+
print("Lista de modelos disponíveis salva em 'models_available.json'")
|
414 |
+
except Exception as e:
|
415 |
+
print(f"Erro ao salvar lista de modelos: {e}")
|
416 |
|
417 |
# --- Chat Principal ---
|
418 |
def responder_como_aldo(session_id: str, pergunta: str, modelo: str = DEFAULT_MODEL) -> str:
|
|
|
469 |
|
470 |
if __name__ == "__main__":
|
471 |
inicializar_sistema()
|
472 |
+
# Teste básico
|
473 |
session_id = "teste_123"
|
474 |
+
print("\n" + "="*50)
|
475 |
+
print("TESTE DO CHATBOT:")
|
476 |
+
print("="*50)
|
477 |
print(responder_como_aldo(session_id, "O que é Java?"))
|
478 |
+
print("\n" + "-"*50)
|
479 |
print(responder_como_aldo(session_id, "Mostre um exemplo de código Java."))
|
480 |
+
print("\n" + "-"*50)
|
481 |
print(clear_memory(session_id))
|