Download evaluate_rag_colab.py from Madras1/AetherMap: direct link, hf CLI and curl.
- Browser
- Download file 8.84 kB
-
https://huggingface.co/spaces/Madras1/AetherMap/resolve/main/evaluate_rag_colab.py
- Command line
-
hf download hf://spaces/Madras1/AetherMap/evaluate_rag_colab.py
-
curl -L -o evaluate_rag_colab.py https://huggingface.co/spaces/Madras1/AetherMap/resolve/main/evaluate_rag_colab.py
8.84 kB
| # ============================================================================== | |
| # AetherMap RAG Evaluation v3 - OpenRouter Edition | |
| # Usa OpenRouter ao invΓ©s de Groq para evitar rate limits | |
| # ============================================================================== | |
| # %% | |
| # CΓ©lula 1: InstalaΓ§Γ£o | |
| # !pip install requests pandas openai -q | |
| # %% | |
| # CΓ©lula 2: Imports | |
| import os | |
| import json | |
| import requests | |
| import pandas as pd | |
| import numpy as np | |
| from typing import List, Dict, Any, Tuple | |
| from dataclasses import dataclass, field | |
| import tempfile | |
| import time | |
| import random | |
| from openai import OpenAI | |
| # Configurar API Key | |
| OPENROUTER_API_KEY = "sk-or-v1-..." # π Sua key OpenRouter | |
| API_URL = "https://madras1-aethermap.hf.space" | |
| # %% | |
| # CΓ©lula 3: Cliente OpenRouter | |
| client = OpenAI( | |
| base_url="https://openrouter.ai/api/v1", | |
| api_key=OPENROUTER_API_KEY, | |
| ) | |
| # Modelos gratuitos do OpenRouter | |
| QUERY_GENERATOR_MODEL = "meta-llama/llama-3.1-8b-instruct:free" | |
| EVALUATOR_MODEL = "google/gemini-2.0-flash-exp:free" | |
| # Rate limiting mais leve (OpenRouter Γ© mais generoso) | |
| DELAY_BETWEEN_CALLS = 1.5 # Segundos entre chamadas | |
| print(f"π€ Gerador: {QUERY_GENERATOR_MODEL}") | |
| print(f"π§ββοΈ Avaliador: {EVALUATOR_MODEL}") | |
| # %% | |
| # CΓ©lula 4: FunΓ§Γ΅es | |
| def call_llm(messages: List[Dict], model: str, max_tokens: int = 1000) -> str: | |
| """Chama OpenRouter API.""" | |
| time.sleep(DELAY_BETWEEN_CALLS) | |
| try: | |
| completion = client.chat.completions.create( | |
| model=model, | |
| messages=messages, | |
| max_tokens=max_tokens, | |
| temperature=0.3, | |
| ) | |
| return completion.choices[0].message.content.strip() | |
| except Exception as e: | |
| print(f" β οΈ Erro LLM: {e}") | |
| time.sleep(5) # Esperar se der erro | |
| return "" | |
| def gerar_queries(documentos: List[str], n_queries: int = 5) -> List[Dict[str, str]]: | |
| """Gera perguntas baseadas nos documentos.""" | |
| # Limitar tamanho para nΓ£o estourar contexto | |
| docs_text = "\n---\n".join([doc[:400] for doc in documentos[:3]]) | |
| prompt = f"""Gere {n_queries} perguntas que podem ser respondidas com estes documentos. | |
| Para cada pergunta, dΓͺ tambΓ©m a resposta correta. | |
| DOCUMENTOS: | |
| {docs_text} | |
| Retorne APENAS JSON: | |
| [{{"pergunta": "...", "resposta": "..."}}]""" | |
| response = call_llm( | |
| [{"role": "user", "content": prompt}], | |
| QUERY_GENERATOR_MODEL, | |
| max_tokens=1000 | |
| ) | |
| try: | |
| if "[" in response: | |
| json_start = response.index("[") | |
| json_end = response.rindex("]") + 1 | |
| return json.loads(response[json_start:json_end])[:n_queries] | |
| except: | |
| pass | |
| return [] | |
| def avaliar_resposta(pergunta: str, resposta_rag: str, resposta_esperada: str) -> Dict[str, float]: | |
| """Avalia resposta do RAG.""" | |
| prompt = f"""Avalie a resposta do sistema comparando com a esperada. | |
| PERGUNTA: {pergunta} | |
| RESPOSTA ESPERADA: {resposta_esperada} | |
| RESPOSTA DO SISTEMA: {resposta_rag[:800]} | |
| DΓͺ uma nota de 0 a 1 para: | |
| - correcao: informaΓ§Γ£o estΓ‘ correta? | |
| - completude: resposta estΓ‘ completa? | |
| Retorne APENAS JSON: {{"correcao": X.X, "completude": X.X}}""" | |
| response = call_llm( | |
| [{"role": "user", "content": prompt}], | |
| EVALUATOR_MODEL, | |
| max_tokens=200 | |
| ) | |
| try: | |
| if "{" in response: | |
| json_start = response.index("{") | |
| json_end = response.rindex("}") + 1 | |
| result = json.loads(response[json_start:json_end]) | |
| return { | |
| "correcao": float(result.get("correcao", 0.5)), | |
| "completude": float(result.get("completude", 0.5)) | |
| } | |
| except: | |
| pass | |
| return {"correcao": 0.5, "completude": 0.5} | |
| # %% | |
| # CΓ©lula 5: Classe do avaliador | |
| class RAGEvaluator: | |
| def __init__(self, api_url: str = API_URL): | |
| self.api_url = api_url.rstrip("/") | |
| print("β Avaliador OpenRouter inicializado!") | |
| def load_dataset(self, file_path: str, text_col: str, label_col: str): | |
| with open(file_path, 'r', encoding='utf-8') as f: | |
| sep = ';' if ';' in f.readline() else ',' | |
| df = pd.read_csv(file_path, sep=sep) | |
| print(f"π {len(df)} linhas carregadas") | |
| splits = {} | |
| for label in sorted(df[label_col].unique()): | |
| splits[int(label)] = df[df[label_col] == label] | |
| print(f" Label {label}: {len(splits[int(label)])}") | |
| return splits | |
| def upload(self, df_subset, text_col: str, n_samples: int = 200): | |
| sample = df_subset.sample(n=min(n_samples, len(df_subset)), random_state=42) | |
| sample_docs = sample[text_col].tolist()[:10] | |
| with tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False, encoding='utf-8') as f: | |
| sample.to_csv(f, index=False) | |
| temp_path = f.name | |
| print(f" π€ Upload {len(sample)} docs...") | |
| with open(temp_path, "rb") as f: | |
| response = requests.post( | |
| f"{self.api_url}/process/", | |
| files={"file": ("data.csv", f)}, | |
| data={"n_samples": n_samples, "text_column": text_col, "fast_mode": "true"} | |
| ) | |
| os.unlink(temp_path) | |
| if response.status_code != 200: | |
| print(f" β {response.text[:100]}") | |
| return None, [] | |
| result = response.json() | |
| print(f" β Job: {result['job_id']}") | |
| return result['job_id'], sample_docs | |
| def search(self, job_id: str, query: str) -> str: | |
| response = requests.post( | |
| f"{self.api_url}/search/", | |
| data={"query": query, "job_id": job_id} | |
| ) | |
| if response.status_code != 200: | |
| return "Erro" | |
| return response.json().get("summary", "") | |
| def evaluate_label(self, job_id: str, docs: List[str], label: int, n_queries: int = 3): | |
| print(f"\nπ LABEL {label}") | |
| # Gerar queries | |
| queries = gerar_queries(docs, n_queries) | |
| if not queries: | |
| return {"error": "Falha queries", "label": label} | |
| print(f" {len(queries)} queries geradas") | |
| # Testar | |
| scores = [] | |
| for i, q in enumerate(queries): | |
| pergunta = q.get("pergunta", q.get("question", "")) | |
| esperada = q.get("resposta", q.get("answer", q.get("resposta_esperada", ""))) | |
| print(f" [{i+1}] {pergunta[:40]}...") | |
| # RAG responde | |
| resposta = self.search(job_id, pergunta) | |
| # Avaliar | |
| aval = avaliar_resposta(pergunta, resposta, esperada) | |
| scores.append((aval["correcao"] + aval["completude"]) / 2) | |
| emoji = "β" if scores[-1] >= 0.5 else "β" | |
| print(f" {emoji} {aval['correcao']:.2f} / {aval['completude']:.2f}") | |
| return { | |
| "label": label, | |
| "score": float(np.mean(scores)), | |
| "std": float(np.std(scores)), | |
| "n": len(scores) | |
| } | |
| def run(self, file_path: str, text_col: str = "texto", | |
| label_col: str = "label_qualidade", | |
| samples: int = 200, queries: int = 3): | |
| print("="*50) | |
| print("π AETHERMAP RAG EVAL v3 (OpenRouter)") | |
| print("="*50) | |
| splits = self.load_dataset(file_path, text_col, label_col) | |
| results = {} | |
| for label, df_subset in splits.items(): | |
| job_id, docs = self.upload(df_subset, text_col, samples) | |
| if not job_id: | |
| results[label] = {"error": "Upload falhou"} | |
| continue | |
| time.sleep(3) | |
| results[label] = self.evaluate_label(job_id, docs, label, queries) | |
| # Resultado | |
| print("\n" + "="*50) | |
| print("π RESULTADO FINAL") | |
| print("="*50) | |
| for label, data in sorted(results.items()): | |
| if "error" in data: | |
| print(f"Label {label}: β {data['error']}") | |
| else: | |
| emoji = "β " if data['score'] >= 0.6 else "π‘" if data['score'] >= 0.4 else "π΄" | |
| print(f"Label {label}: {data['score']:.3f} Β±{data['std']:.2f} {emoji}") | |
| return results | |
| # %% | |
| # Executar | |
| evaluator = RAGEvaluator() | |
| # %% | |
| resultados = evaluator.run( | |
| file_path="dataset_unificado_72k.csv", | |
| text_col="texto", | |
| label_col="label_qualidade", | |
| samples=200, # Menos samples | |
| queries=3 # Menos queries | |
| ) | |