143 lines
5.6 KiB
Bash
Executable File
143 lines
5.6 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# graphify.sh — Roda o graphify sobre o código-fonte deste projeto (G-ART / fcp-mcp-server).
|
|
#
|
|
# Uso:
|
|
# ./admin/graphify.sh # analisa o código real (server.py + fcpxml/)
|
|
# ./admin/graphify.sh <caminho> # analisa outro caminho
|
|
#
|
|
# Requer: graphify instalado (pip install graphifyy / uv tool install graphifyy)
|
|
|
|
set -euo pipefail
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
cd "$ROOT_DIR"
|
|
|
|
# Caminho padrão: pasta code/ (analisa server.py + fcpxml/). Pode ser sobrescrito por $1.
|
|
INPUT_PATH="${1:-$ROOT_DIR/code}"
|
|
|
|
if [ ! -e "$INPUT_PATH" ]; then
|
|
echo "ERRO: caminho não encontrado: $INPUT_PATH" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "==> Graphify em: $INPUT_PATH"
|
|
|
|
# Detecta interpretador Python que possui o pacote graphify.
|
|
PYTHON=""
|
|
if command -v uv >/dev/null 2>&1; then
|
|
PYTHON="$(uv tool run --from graphifyy python -c 'import sys; print(sys.executable)' 2>/dev/null || true)"
|
|
fi
|
|
if [ -z "$PYTHON" ]; then
|
|
PYTHON="$(command -v python3 || command -v python)"
|
|
fi
|
|
|
|
if ! "$PYTHON" -c "import graphify" 2>/dev/null; then
|
|
echo "==> Instalando graphifyy..."
|
|
if command -v uv >/dev/null 2>&1; then
|
|
uv tool install --upgrade graphifyy
|
|
PYTHON="$(uv tool run --from graphifyy python -c 'import sys; print(sys.executable)')"
|
|
else
|
|
"$PYTHON" -m pip install graphifyy
|
|
fi
|
|
fi
|
|
|
|
mkdir -p graphify-out
|
|
"$PYTHON" -c "import sys; open('graphify-out/.graphify_python','w').write(sys.executable)"
|
|
|
|
# Detecta arquivos do corpus.
|
|
echo "==> Detectando arquivos..."
|
|
"$PYTHON" -c "
|
|
import json, sys
|
|
from graphify.detect import detect
|
|
from pathlib import Path
|
|
print(json.dumps(detect(Path('$INPUT_PATH')), ensure_ascii=False))
|
|
" > graphify-out/.graphify_detect.json
|
|
|
|
# Extração estrutural (AST) — código, sem LLM.
|
|
echo "==> Extração estrutural (AST)..."
|
|
"$PYTHON" -c "
|
|
import json, sys
|
|
from pathlib import Path
|
|
from graphify.extract import collect_files, extract
|
|
detect = json.loads(Path('graphify-out/.graphify_detect.json').read_text(encoding='utf-8'))
|
|
code_files = []
|
|
for f in detect.get('files', {}).get('code', []):
|
|
p = Path(f)
|
|
code_files.extend(collect_files(p) if p.is_dir() else [p])
|
|
if code_files:
|
|
result = extract(code_files, cache_root=Path('$INPUT_PATH'))
|
|
else:
|
|
result = {'nodes': [], 'edges': [], 'input_tokens': 0, 'output_tokens': 0}
|
|
Path('graphify-out/.graphify_ast.json').write_text(json.dumps(result, indent=2, ensure_ascii=False), encoding='utf-8')
|
|
print(f'AST: {len(result[\"nodes\"])} nodes, {len(result[\"edges\"])} edges')
|
|
"
|
|
|
|
# Corpus só de código -> semântica vazia; caso contrário o usuário roda via /graphify.
|
|
"$PYTHON" -c "
|
|
import json
|
|
from pathlib import Path
|
|
Path('graphify-out/.graphify_semantic.json').write_text(json.dumps({'nodes': [], 'edges': [], 'hyperedges': [], 'input_tokens': 0, 'output_tokens': 0}), encoding='utf-8')
|
|
"
|
|
|
|
# Merge AST + semântica.
|
|
"$PYTHON" -c "
|
|
import json
|
|
from pathlib import Path
|
|
ast = json.loads(Path('graphify-out/.graphify_ast.json').read_text(encoding='utf-8'))
|
|
sem = json.loads(Path('graphify-out/.graphify_semantic.json').read_text(encoding='utf-8'))
|
|
seen = {n['id'] for n in ast['nodes']}
|
|
merged_nodes = list(ast['nodes'])
|
|
for n in sem['nodes']:
|
|
if n['id'] not in seen:
|
|
merged_nodes.append(n); seen.add(n['id'])
|
|
merged = {'nodes': merged_nodes, 'edges': ast['edges'] + sem['edges'],
|
|
'hyperedges': sem.get('hyperedges', []),
|
|
'input_tokens': sem.get('input_tokens', 0), 'output_tokens': sem.get('output_tokens', 0)}
|
|
Path('graphify-out/.graphify_extract.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding='utf-8')
|
|
print(f'Merged: {len(merged_nodes)} nodes, {len(merged[\"edges\"])} edges')
|
|
"
|
|
|
|
# Build + cluster + report.
|
|
echo "==> Construindo grafo e clusters..."
|
|
"$PYTHON" -c "
|
|
import json
|
|
from pathlib import Path
|
|
from graphify.build import build_from_json
|
|
from graphify.cluster import cluster, score_all
|
|
from graphify.analyze import god_nodes, surprising_connections, suggest_questions
|
|
from graphify.report import generate
|
|
from graphify.export import to_json
|
|
extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding='utf-8'))
|
|
detection = json.loads(Path('graphify-out/.graphify_detect.json').read_text(encoding='utf-8'))
|
|
G = build_from_json(extraction, root='$INPUT_PATH', directed=False)
|
|
if G.number_of_nodes() == 0:
|
|
print('ERRO: grafo vazio - nenhum nó extraído.'); raise SystemExit(1)
|
|
communities = cluster(G)
|
|
cohesion = score_all(G, communities)
|
|
gods = god_nodes(G)
|
|
surprises = surprising_connections(G, communities)
|
|
labels = {cid: 'Community ' + str(cid) for cid in communities}
|
|
questions = suggest_questions(G, communities, labels)
|
|
tokens = {'input': extraction.get('input_tokens', 0), 'output': extraction.get('output_tokens', 0)}
|
|
wrote = to_json(G, communities, 'graphify-out/graph.json')
|
|
if not wrote:
|
|
print('ERRO: recusou encolher graph.json (#479).'); raise SystemExit(1)
|
|
report = generate(G, communities, cohesion, labels, gods, surprises, detection, tokens, '$INPUT_PATH', suggested_questions=questions)
|
|
Path('graphify-out/GRAPH_REPORT.md').write_text(report, encoding='utf-8')
|
|
Path('graphify-out/.graphify_labels.json').write_text(json.dumps({str(k): v for k, v in labels.items()}), encoding='utf-8')
|
|
print(f'Grafo: {G.number_of_nodes()} nós, {G.number_of_edges()} arestas, {len(communities)} comunidades')
|
|
"
|
|
|
|
# HTML interativo.
|
|
echo "==> Exportando HTML..."
|
|
"$PYTHON" -m graphify export html || graphify export html 2>/dev/null || true
|
|
|
|
echo
|
|
echo "Concluído. Saídas em:"
|
|
echo " $(pwd)/graphify-out/graph.html"
|
|
echo " $(pwd)/graphify-out/GRAPH_REPORT.md"
|
|
echo " $(pwd)/graphify-out/graph.json"
|
|
echo
|
|
read -n 1 -s -r -p "Pressione qualquer tecla para fechar..." || true
|