""" consolidate_knowledge_final.py - Consolidação FINAL CTF Knowledge Base Consolida: - Batch 1 + Batch 2: 268 casos (já consolidados anteriormente) - Batch 3: Casos extraídos de triumphexp - Reddit: Casos extraídos de r/Autoupholstery + r/upholstery Gera: - CTF_Knowledge_Base_FINAL_Consolidated.json (todos os casos) - CTF_Knowledge_Base_FINAL_Statistics.json (estatísticas detalhadas) - CTF_Knowledge_Base_FINAL_Report.md (relatório executivo) Author: Descomplicar® Crescimento Digital Link: https://descomplicar.pt Copyright: 2025 Descomplicar® """ import json import os from pathlib import Path from collections import defaultdict, Counter from datetime import datetime import re # Configuração INPUT_DIR = "/media/ealmeida/Dados/GDrive/Cloud/Clientes_360/CTF_Carstuff/KB/Scrapper/sites/knowledge_base_final" OUTPUT_DIR = "/media/ealmeida/Dados/GDrive/Cloud/Clientes_360/CTF_Carstuff/KB/Scrapper/sites" OUTPUT_FILE = "CTF_Knowledge_Base_FINAL_Consolidated.json" STATS_FILE = "CTF_Knowledge_Base_FINAL_Statistics.json" REPORT_FILE = "CTF_Knowledge_Base_FINAL_Report.md" def extract_site_name(filename): """Extrair nome do site do nome do ficheiro.""" match = re.match(r'knowledge_(.+?)[\._]\d+\.json', filename) if match: return match.group(1) return "unknown" def detect_batch(site_name, filename): """Detectar batch baseado no nome do site/ficheiro.""" if 'triumphexp' in site_name.lower(): return 'batch3' elif 'reddit' in filename.lower(): return 'reddit' else: # Batch 1 + 2 (sites conhecidos) batch1_sites = ['thehogring', 'mgexp', 'relicate', 'vansairforce'] if any(site in site_name.lower() for site in batch1_sites): return 'batch1' else: return 'batch2' def load_all_cases(): """Carregar todos os casos de todos os ficheiros JSON.""" input_path = Path(INPUT_DIR) all_cases = [] batch_stats = defaultdict(lambda: {"cases": 0, "files": 0}) site_stats = defaultdict(lambda: {"cases": 0, "files": 0}) category_stats = Counter() material_stats = Counter() keyword_stats = Counter() severidade_stats = Counter() print(f"📂 A ler ficheiros de: {INPUT_DIR}") json_files = sorted(input_path.glob("knowledge_*.json")) total_files = len(json_files) print(f"📊 Encontrados {total_files} ficheiros JSON\n") for idx, json_file in enumerate(json_files, 1): try: with open(json_file, 'r', encoding='utf-8') as f: data = json.load(f) site_name = extract_site_name(json_file.name) batch = detect_batch(site_name, json_file.name) site_stats[site_name]["files"] += 1 batch_stats[batch]["files"] += 1 # Extrair casos completos casos = data.get("casos_completos", []) for caso in casos: # Adicionar metadados do ficheiro ao caso enhanced_caso = { **caso, "metadata": { "batch": batch, "site_origem": site_name, "ficheiro_origem": json_file.name, "categoria_aplicacao": data.get("categoria_aplicacao", ""), "tipo_conteudo": data.get("tipo_conteudo", ""), "nivel_expertise": data.get("nivel_expertise", ""), "keywords_tecnicas": data.get("keywords_tecnicas", []), "materiais_principais": data.get("materiais_discutidos", {}).get("principais", []) } } all_cases.append(enhanced_caso) site_stats[site_name]["cases"] += 1 batch_stats[batch]["cases"] += 1 # Estatísticas agregadas if data.get("categoria_aplicacao"): category_stats[data["categoria_aplicacao"]] += 1 for material in data.get("materiais_discutidos", {}).get("principais", []): material_stats[material] += 1 for keyword in data.get("keywords_tecnicas", []): keyword_stats[keyword] += 1 # Severidade sev = caso.get("problema", {}).get("severidade", "unknown") severidade_stats[sev] += 1 if (idx % 50 == 0) or (idx == total_files): print(f" Progresso: {idx}/{total_files} ({idx/total_files*100:.1f}%) - {len(all_cases)} casos extraídos") except Exception as e: print(f"⚠️ Erro ao processar {json_file.name}: {e}") continue return all_cases, dict(batch_stats), dict(site_stats), dict(category_stats), dict(material_stats), dict(keyword_stats), dict(severidade_stats) def generate_statistics(cases, batch_stats, site_stats, category_stats, material_stats, keyword_stats, severidade_stats): """Gerar estatísticas detalhadas.""" # Top materiais e keywords top_materiais = dict(Counter(material_stats).most_common(20)) top_keywords = dict(Counter(keyword_stats).most_common(30)) # Casos por site (ordenado) site_stats_sorted = dict(sorted( site_stats.items(), key=lambda x: x[1]["cases"], reverse=True )) # Casos por batch (ordenado) batch_stats_sorted = dict(sorted( batch_stats.items(), key=lambda x: x[1]["cases"], reverse=True )) statistics = { "metadata": { "generated_at": datetime.now().isoformat(), "description": "Consolidação FINAL - Batches 1+2+3 + Reddit", "total_files_processed": sum(s["files"] for s in site_stats.values()), "total_cases_extracted": len(cases) }, "distribution": { "by_batch": batch_stats_sorted, "by_site": site_stats_sorted, "by_category": dict(category_stats), "by_severidade": dict(severidade_stats) }, "top_elements": { "materiais": top_materiais, "keywords_tecnicas": top_keywords } } return statistics def generate_markdown_report(stats, cases): """Gerar relatório em Markdown.""" total_cases = stats["metadata"]["total_cases_extracted"] total_files = stats["metadata"]["total_files_processed"] report = f"""# 🎯 CTF KNOWLEDGE BASE - CONSOLIDAÇÃO FINAL **Generated**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} **Description**: Consolidação COMPLETA - Batches 1+2+3 + Reddit **Author**: Descomplicar® Crescimento Digital --- ## 📊 RESUMO EXECUTIVO - **Total Ficheiros Processados**: {total_files} - **Total Casos Extraídos**: {total_cases} - **Taxa Média**: {total_cases/total_files:.2f} casos por ficheiro --- ## 📈 DISTRIBUIÇÃO POR BATCH | Batch | Ficheiros | Casos | Casos/Ficheiro | |-------|-----------|-------|----------------| """ for batch, data in stats["distribution"]["by_batch"].items(): files = data["files"] cases_count = data["cases"] avg = cases_count / files if files > 0 else 0 report += f"| **{batch}** | {files} | {cases_count} | {avg:.2f} |\n" report += f"\n**TOTAL** | {total_files} | {total_cases} | {total_cases/total_files:.2f} |\n" report += """ --- ## 🏷️ DISTRIBUIÇÃO POR CATEGORIA | Categoria | Casos | % | |-----------|-------|---| """ for cat, count in sorted(stats["distribution"]["by_category"].items(), key=lambda x: x[1], reverse=True): pct = (count / total_cases) * 100 report += f"| {cat} | {count} | {pct:.1f}% |\n" report += """ --- ## ⚠️ DISTRIBUIÇÃO POR SEVERIDADE | Severidade | Casos | % | |------------|-------|---| """ for sev, count in sorted(stats["distribution"]["by_severidade"].items(), key=lambda x: x[1], reverse=True): pct = (count / total_cases) * 100 report += f"| {sev} | {count} | {pct:.1f}% |\n" report += """ --- ## 🧰 TOP 20 MATERIAIS MAIS MENCIONADOS | Material | Menções | |----------|---------| """ for mat, count in list(stats["top_elements"]["materiais"].items())[:20]: report += f"| {mat} | {count} |\n" report += """ --- ## 🔍 TOP 30 KEYWORDS TÉCNICAS | Keyword | Ocorrências | |---------|-------------| """ for kw, count in list(stats["top_elements"]["keywords_tecnicas"].items())[:30]: report += f"| {kw} | {count} |\n" report += """ --- ## 📈 TOP 15 SITES POR VOLUME | Site | Ficheiros | Casos | Média | |------|-----------|-------|-------| """ for site, data in list(stats["distribution"]["by_site"].items())[:15]: files = data["files"] cases_count = data["cases"] avg = cases_count / files if files > 0 else 0 report += f"| `{site}` | {files} | {cases_count} | {avg:.2f} |\n" report += """ --- ## 🎯 PRÓXIMAS AÇÕES 1. ✅ **Consolidação FINAL Concluída**: {total_cases} casos totais 2. 🚀 **Deploy para Sistema**: Importar para CTF Knowledge Base system 3. 📊 **Análise Qualidade**: Review manual de casos de alta prioridade 4. 🔄 **Manutenção**: Atualizações periódicas com novos casos --- **© 2025 Descomplicar® - Crescimento Digital** **Link**: https://descomplicar.pt """.replace("{total_cases}", str(total_cases)) return report def main(): """Função principal.""" print("═══════════════════════════════════════════════════════════") print(" CTF KNOWLEDGE BASE - CONSOLIDAÇÃO FINAL") print(" Batches 1+2+3 + Reddit") print(" Descomplicar® Crescimento Digital") print("═══════════════════════════════════════════════════════════") print() # 1. Carregar todos os casos print("📖 Passo 1: A carregar casos de TODOS os ficheiros...") cases, batch_stats, site_stats, category_stats, material_stats, keyword_stats, severidade_stats = load_all_cases() print(f"✅ Carregados {len(cases)} casos de {sum(s['files'] for s in site_stats.values())} ficheiros\n") # 2. Gerar estatísticas print("📊 Passo 2: A gerar estatísticas...") statistics = generate_statistics(cases, batch_stats, site_stats, category_stats, material_stats, keyword_stats, severidade_stats) print("✅ Estatísticas geradas\n") # 3. Criar ficheiro consolidado print("💾 Passo 3: A guardar ficheiro consolidado...") consolidated = { "metadata": { "generated_at": datetime.now().isoformat(), "description": "Knowledge Base FINAL - Batches 1+2+3 + Reddit Completos", "version": "FINAL-1.0", "author": "Descomplicar® Crescimento Digital", "total_cases": len(cases), "total_files": statistics["metadata"]["total_files_processed"] }, "statistics": statistics, "cases": cases } output_path = Path(OUTPUT_DIR) / OUTPUT_FILE with open(output_path, 'w', encoding='utf-8') as f: json.dump(consolidated, f, ensure_ascii=False, indent=2) print(f"✅ Guardado: {output_path}\n") # 4. Guardar estatísticas separadas print("📊 Passo 4: A guardar ficheiro de estatísticas...") stats_path = Path(OUTPUT_DIR) / STATS_FILE with open(stats_path, 'w', encoding='utf-8') as f: json.dump(statistics, f, ensure_ascii=False, indent=2) print(f"✅ Guardado: {stats_path}\n") # 5. Gerar relatório Markdown print("📝 Passo 5: A gerar relatório Markdown...") report = generate_markdown_report(statistics, cases) report_path = Path(OUTPUT_DIR) / REPORT_FILE with open(report_path, 'w', encoding='utf-8') as f: f.write(report) print(f"✅ Guardado: {report_path}\n") # Resumo final print("═══════════════════════════════════════════════════════════") print(" CONSOLIDAÇÃO FINAL CONCLUÍDA COM SUCESSO") print("═══════════════════════════════════════════════════════════") print() print(f"🎯 Casos TOTAIS consolidados: {len(cases)}") print() print("📊 Distribuição por Batch:") for batch, data in sorted(statistics["distribution"]["by_batch"].items(), key=lambda x: x[1]["cases"], reverse=True): print(f" - {batch}: {data['cases']} casos ({data['files']} ficheiros)") print() print("📄 Ficheiros gerados:") print(f" 1. {OUTPUT_FILE} - Knowledge Base FINAL completa") print(f" 2. {STATS_FILE} - Estatísticas detalhadas") print(f" 3. {REPORT_FILE} - Relatório executivo") print() if __name__ == "__main__": main()