""" extract_reddit_only.py - Extração EXCLUSIVA Reddit Processa apenas os 2 ficheiros Reddit: - reddit_Autoupholstery_1762438195.md - reddit_upholstery_1762438227.md Modelo: google/gemini-2.5-flash-lite Author: Descomplicar® Crescimento Digital Link: https://descomplicar.pt Copyright: 2025 Descomplicar® """ import os import json import requests from pathlib import Path from typing import Dict, Optional from dotenv import load_dotenv import time from datetime import datetime load_dotenv() # Configurações INPUT_DIR = "/media/ealmeida/Dados/GDrive/Cloud/Clientes_360/CTF_Carstuff/KB/Scrapper/sites/output_md" OUTPUT_DIR = "/media/ealmeida/Dados/GDrive/Cloud/Clientes_360/CTF_Carstuff/KB/Scrapper/sites/knowledge_base_final" API_KEY = os.getenv("OPENROUTER_API_KEY") # Ficheiros Reddit específicos REDDIT_FILES = [ "reddit_Autoupholstery_1762438195.md", "reddit_upholstery_1762438227.md" ] class RedditKnowledgeExtractor: def __init__(self): self.api_key = API_KEY self.api_url = "https://openrouter.ai/api/v1/chat/completions" self.model = "google/gemini-2.5-flash-lite" self.stats = {'total': 0, 'processados': 0, 'relevantes': 0, 'erros': 0} # Prompt otimizado para Reddit self.extraction_prompt = """ És um especialista em estofamento automotivo, náutico, ferroviário e aeronáutico. ⚠️ CRITÉRIO CRÍTICO DE RELEVÂNCIA: O conteúdo SÓ É RELEVANTE se contiver o fluxo COMPLETO: PROBLEMA → SOLUÇÃO → RESULTADO Se o texto apenas descreve problemas SEM as suas soluções, retorna: {"relevante": false} IGNORAR COMPLETAMENTE: - Comentários genéricos ("obrigado", "bom post", "upvote") - Conversas off-topic - Problemas mencionados sem soluções correspondentes - Links sem contexto - Discussões sem conclusão técnica EXTRAIR APENAS SE EXISTIR FLUXO COMPLETO: 1. **Problema técnico específico** identificado claramente 2. **Solução prática** aplicada ou recomendada para esse problema 3. **Resultado obtido** ou esperado (se mencionado) FORMATO JSON DE SAÍDA: { "relevante": true/false, "categoria_aplicacao": "automovel|automovel-classico|mobiliario|nautica|ferroviaria|aeronautica|geral", "tipo_conteudo": "problema-tecnico|tutorial|caso-pratico|comparacao-materiais", "casos_completos": [ { "problema": { "descricao": "Problema específico identificado", "contexto": "Tipo de veículo/aplicação/situação", "severidade": "baixa|media|alta" }, "solucao": { "material_usado": "Material específico aplicado", "tecnica": "Técnica ou método usado", "passos": "Passos principais (se mencionados)" }, "resultado": { "obtido": "Resultado concreto alcançado", "qualidade": "Avaliação da solução" } } ], "materiais_discutidos": { "principais": ["materiais eficazes mencionados"], "nao_recomendados": ["materiais que falharam ou são evitados"] }, "keywords_tecnicas": ["termos", "tecnicos", "relevantes"], "aplicabilidade": ["tipos de veículos/situações"], "nivel_expertise": "iniciante|intermedio|avancado" } ⚠️ IMPORTANTE: - Se o texto só menciona problemas sem soluções: {"relevante": false} - Se menciona soluções sem contexto de problema: {"relevante": false} - Apenas CASOS COMPLETOS com problema→solução→resultado devem ser extraídos. """ def extract_knowledge(self, content: str) -> Optional[Dict]: """Extrai conhecimento via OpenRouter API.""" headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json", "HTTP-Referer": "https://descomplicar.pt", "X-Title": "CTF Reddit Knowledge Extractor" } payload = { "model": self.model, "messages": [ { "role": "system", "content": self.extraction_prompt }, { "role": "user", "content": f"Analisa este conteúdo Reddit e extrai conhecimento técnico:\n\n{content[:15000]}" } ], "temperature": 0.3, "max_tokens": 2500, "response_format": {"type": "json_object"} } try: response = requests.post(self.api_url, headers=headers, json=payload, timeout=90) response.raise_for_status() result = response.json() content_text = result['choices'][0]['message']['content'] # Parse JSON knowledge = json.loads(content_text) return knowledge except Exception as e: print(f"⚠️ Erro API: {e}") return None def process_file(self, filename: str): """Processa um ficheiro Reddit MD.""" filepath = Path(INPUT_DIR) / filename if not filepath.exists(): print(f" ❌ Ficheiro não encontrado: {filepath}") self.stats['erros'] += 1 return print(f"\n📄 A processar: {filename}") self.stats['total'] += 1 try: with open(filepath, 'r', encoding='utf-8') as f: content = f.read() # Validação básica if len(content) < 500: print(f" ⏭️ Ficheiro muito pequeno (<500 chars), ignorado") return # Extração via API print(f" 🔄 A enviar para API... ({len(content)} caracteres)") knowledge = self.extract_knowledge(content) if not knowledge: print(f" ❌ Erro ao extrair conhecimento") self.stats['erros'] += 1 return # Verificar relevância if not knowledge.get('relevante', False): print(f" ⏭️ Conteúdo não relevante (sem problema→solução)") return # Verificar casos completos casos = knowledge.get('casos_completos', []) if not casos or len(casos) == 0: print(f" ⏭️ Sem casos completos extraídos") return # Guardar JSON stem = filepath.stem # reddit_Autoupholstery_1762438195 output_file = Path(OUTPUT_DIR) / f"knowledge_{stem}.json" with open(output_file, 'w', encoding='utf-8') as f: json.dump(knowledge, f, ensure_ascii=False, indent=2) print(f" ✅ Extraído: {len(casos)} casos completos → knowledge_{stem}.json") self.stats['processados'] += 1 self.stats['relevantes'] += 1 # Rate limiting time.sleep(2) except Exception as e: print(f" ❌ Erro ao processar: {e}") self.stats['erros'] += 1 def run(self): """Executa extração Reddit.""" print("═══════════════════════════════════════════════════════════") print(" EXTRAÇÃO REDDIT - Knowledge Base CTF") print(" Modelo: google/gemini-2.5-flash-lite") print(" Descomplicar® Crescimento Digital") print("═══════════════════════════════════════════════════════════") print() # Criar output dir se não existir Path(OUTPUT_DIR).mkdir(parents=True, exist_ok=True) print(f"📂 Input: {INPUT_DIR}") print(f"📂 Output: {OUTPUT_DIR}") print(f"📊 Ficheiros a processar: {len(REDDIT_FILES)}\n") for filename in REDDIT_FILES: self.process_file(filename) # Resumo final print("\n═══════════════════════════════════════════════════════════") print(" EXTRAÇÃO REDDIT CONCLUÍDA") print("═══════════════════════════════════════════════════════════") print() print("📊 ESTATÍSTICAS:") print(f" Total ficheiros: {self.stats['total']}") print(f" Processados com sucesso: {self.stats['processados']}") print(f" Relevantes: {self.stats['relevantes']}") print(f" Erros: {self.stats['erros']}") print() if self.stats['relevantes'] > 0: print(f"✅ Extraídos {self.stats['relevantes']} ficheiros com casos completos") else: print("⚠️ Nenhum caso relevante extraído") print(f"📁 Ficheiros guardados em: {OUTPUT_DIR}") print() if __name__ == "__main__": extractor = RedditKnowledgeExtractor() extractor.run()