Files
scripts/scraper/consolidate_knowledge_final.py

369 lines
13 KiB
Python
Executable File

"""
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()