mirror of
https://github.com/Alkatrazz24/Funk-lab.git
synced 2026-07-08 06:24:42 +02:00
feat(hermes-auto-improve): remplacer API urllib par gh CLI pour les PR
Plus besoin de GITHUB_TOKEN dans le vault ni dans le service systemd. gh auth login root une seule fois sur s01 suffit. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
4e0b683cbd
commit
cf2c8ecc81
2 changed files with 252 additions and 124 deletions
|
|
@ -1,4 +1,18 @@
|
||||||
---
|
---
|
||||||
|
- name: Add GitHub CLI repo
|
||||||
|
ansible.builtin.yum_repository:
|
||||||
|
name: gh-cli
|
||||||
|
description: GitHub CLI
|
||||||
|
baseurl: https://cli.github.com/packages/rpm
|
||||||
|
gpgkey: https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x23F3D4EA75716059
|
||||||
|
gpgcheck: true
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
- name: Install gh CLI
|
||||||
|
ansible.builtin.dnf:
|
||||||
|
name: gh
|
||||||
|
state: present
|
||||||
|
|
||||||
- name: Create state directory
|
- name: Create state directory
|
||||||
ansible.builtin.file:
|
ansible.builtin.file:
|
||||||
path: "{{ hermes_auto_improve_state_dir }}"
|
path: "{{ hermes_auto_improve_state_dir }}"
|
||||||
|
|
|
||||||
|
|
@ -1,80 +1,89 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
hermes-auto-improve — Analyse les docs admin/ avec Hermes.
|
hermes-doc-worker — Hermes analyse admin/, écrit ses rapports dans
|
||||||
Génère des rapports d'amélioration dans la feature branch, ré-ingère dans Qdrant.
|
admin/hermes/builtin/ et push dans sa branche hermes/daily-work.
|
||||||
|
Ré-ingère tout admin/ dans Qdrant à chaque run.
|
||||||
|
|
||||||
Usage :
|
Modes :
|
||||||
python3 auto-improve.py [--all] [--subdir ia] [--dry-run]
|
(défaut) : analyse un batch de fichiers, écrit rapport, push, ré-ingère
|
||||||
|
--daily-pr : crée une PR hermes/daily-work → main sur GitHub + retourne l'URL
|
||||||
|
--dry-run : analyse sans écrire ni push
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
REPO_DIR = Path("/srv/data/lab/Funk-lab")
|
REPO_DIR = Path("/srv/data/lab/Funk-lab")
|
||||||
BRANCH = "feature/hermes-auto-improve"
|
BRANCH = "hermes/daily-work"
|
||||||
ADMIN_DIR = REPO_DIR / "admin"
|
ADMIN_DIR = REPO_DIR / "admin"
|
||||||
REPORTS_DIR = REPO_DIR / "tools/hermes-auto-improve/reports"
|
BUILTIN_DIR = REPO_DIR / "admin" / "hermes" / "builtin"
|
||||||
|
RAG_DOCS = Path("/srv/data/rag/docs")
|
||||||
STATE_FILE = Path("/var/lib/hermes-auto-improve/state.json")
|
STATE_FILE = Path("/var/lib/hermes-auto-improve/state.json")
|
||||||
MAX_FILES = 6 # fichiers par run (sans --all)
|
MAX_FILES = 5 # fichiers analysés par run
|
||||||
|
|
||||||
HERMES_CMD = [
|
|
||||||
"sudo", "-i", "-u", "hermes", "bash", "-c",
|
|
||||||
'HERMES_HOME=/srv/data/hermes hermes --profile funk-ai -z "{prompt}"'
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def git(args: list, check=False) -> subprocess.CompletedProcess:
|
# ── Git helpers ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def git(args: list) -> subprocess.CompletedProcess:
|
||||||
return subprocess.run(
|
return subprocess.run(
|
||||||
["git", "-C", str(REPO_DIR)] + args,
|
["git", "-C", str(REPO_DIR)] + args,
|
||||||
capture_output=True, text=True, check=check
|
capture_output=True, text=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def ask_hermes(prompt: str) -> str:
|
def git_sync():
|
||||||
safe = prompt.replace("'", "'\\''").replace('"', '\\"')
|
"""S'assure qu'on est sur hermes/daily-work à jour."""
|
||||||
cmd = [
|
git(["fetch", "origin"])
|
||||||
"sudo", "-i", "-u", "hermes", "bash", "-c",
|
r = git(["checkout", BRANCH])
|
||||||
f'HERMES_HOME=/srv/data/hermes hermes --profile funk-ai -z "{safe}"'
|
if r.returncode != 0:
|
||||||
]
|
git(["checkout", "-b", BRANCH, f"origin/{BRANCH}"])
|
||||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=180)
|
git(["pull", "--rebase", "origin", BRANCH])
|
||||||
return result.stdout.strip()
|
|
||||||
|
|
||||||
|
|
||||||
|
# ── Hermes ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def ask_hermes(prompt: str) -> str:
|
||||||
|
safe = prompt.replace("'", "'\\''")
|
||||||
|
cmd = [
|
||||||
|
"sudo", "-i", "-u", "hermes", "bash", "-c",
|
||||||
|
f'HERMES_HOME=/srv/data/hermes hermes --profile funk-ai -z \'{safe}\''
|
||||||
|
]
|
||||||
|
r = subprocess.run(cmd, capture_output=True, text=True, timeout=180)
|
||||||
|
return r.stdout.strip()
|
||||||
|
|
||||||
|
|
||||||
|
# ── Analyse d'un fichier ─────────────────────────────────────────
|
||||||
|
|
||||||
def analyze_file(fpath: Path) -> dict:
|
def analyze_file(fpath: Path) -> dict:
|
||||||
rel = str(fpath.relative_to(REPO_DIR))
|
rel = str(fpath.relative_to(REPO_DIR))
|
||||||
content = fpath.read_text(encoding="utf-8")
|
content = fpath.read_text(encoding="utf-8", errors="replace")
|
||||||
|
|
||||||
prompt = f"""Tu es l'agent d'analyse du homelab Funk. Analyse ce fichier de documentation :
|
prompt = f"""Tu es l'agent de documentation du homelab Funk.
|
||||||
|
Analyse ce fichier de documentation et produis un rapport structuré.
|
||||||
|
|
||||||
Fichier : {rel}
|
Fichier : {rel}
|
||||||
---
|
---
|
||||||
{content[:4000]}
|
{content[:4000]}
|
||||||
---
|
---
|
||||||
|
|
||||||
Réponds en JSON strict (pas de markdown) :
|
Réponds UNIQUEMENT en JSON valide (aucun texte avant ou après) :
|
||||||
{{
|
{{
|
||||||
"status": "ok" | "à_améliorer",
|
"fichier": "{rel}",
|
||||||
"score": 1-10,
|
"statut": "ok" | "à_jour" | "obsolète" | "incomplet" | "erreur",
|
||||||
"problèmes": ["liste des problèmes concrets"],
|
"score_qualité": 1-10,
|
||||||
"améliorations": ["liste des améliorations prioritaires"],
|
"résumé": "une phrase sur l'état de ce document",
|
||||||
"contenu_amélioré": "contenu markdown complet si status=à_améliorer, sinon null"
|
"problèmes": ["liste des problèmes concrets trouvés"],
|
||||||
}}
|
"suggestions": ["liste des améliorations prioritaires"],
|
||||||
|
"état_réel": "ce que tu sais de l'état actuel de ce composant dans Funk (ou null)"
|
||||||
Critères d'évaluation :
|
}}"""
|
||||||
- Informations obsolètes ou incorrectes par rapport à l'état actuel du homelab
|
|
||||||
- Sections manquantes importantes pour un ops
|
|
||||||
- Commandes ou chemins érronés
|
|
||||||
- Documentation incomplète pour reproduire une procédure
|
|
||||||
|
|
||||||
Si le document est à jour et complet, mettre status=ok et contenu_amélioré=null."""
|
|
||||||
|
|
||||||
raw = ask_hermes(prompt)
|
raw = ask_hermes(prompt)
|
||||||
|
|
||||||
# Extraire le JSON de la réponse Hermes (qui peut contenir du texte autour)
|
|
||||||
try:
|
try:
|
||||||
start = raw.find("{")
|
start = raw.find("{")
|
||||||
end = raw.rfind("}") + 1
|
end = raw.rfind("}") + 1
|
||||||
|
|
@ -84,19 +93,84 @@ Si le document est à jour et complet, mettre status=ok et contenu_amélioré=nu
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"status": "erreur",
|
"fichier": rel,
|
||||||
"score": 0,
|
"statut": "erreur_parse",
|
||||||
"problèmes": ["Hermes n'a pas retourné de JSON valide"],
|
"score_qualité": 0,
|
||||||
"améliorations": [],
|
"résumé": "Hermes n'a pas retourné de JSON valide",
|
||||||
"contenu_amélioré": None,
|
"problèmes": [],
|
||||||
"raw_response": raw[:500]
|
"suggestions": [],
|
||||||
|
"état_réel": None,
|
||||||
|
"_raw": raw[:300]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ── Ré-ingestion Qdrant ──────────────────────────────────────────
|
||||||
|
|
||||||
|
def rag_ingest() -> str:
|
||||||
|
# Sync admin/ du clone vers /srv/data/rag/docs/
|
||||||
|
subprocess.run(
|
||||||
|
["rsync", "-a", "--delete",
|
||||||
|
str(ADMIN_DIR) + "/",
|
||||||
|
str(RAG_DOCS) + "/"],
|
||||||
|
check=True
|
||||||
|
)
|
||||||
|
r = subprocess.run(
|
||||||
|
["/usr/local/bin/rag-ingest"],
|
||||||
|
capture_output=True, text=True, timeout=300
|
||||||
|
)
|
||||||
|
return (r.stdout + r.stderr).strip()[-300:]
|
||||||
|
|
||||||
|
|
||||||
|
# ── Créer la PR GitHub ───────────────────────────────────────────
|
||||||
|
|
||||||
|
def create_github_pr(summary: str) -> dict:
|
||||||
|
today = datetime.now().strftime("%Y-%m-%d")
|
||||||
|
diff = git(["diff", "--stat", "origin/main...HEAD"])
|
||||||
|
stats = diff.stdout.strip() or "Aucune modification depuis main"
|
||||||
|
|
||||||
|
body = f"""## Rapport quotidien Hermes — {today}
|
||||||
|
|
||||||
|
Ce Pull Request est créé automatiquement par Hermes à 22h.
|
||||||
|
|
||||||
|
### Ce que Hermes a fait aujourd'hui
|
||||||
|
{summary}
|
||||||
|
|
||||||
|
### Diff depuis main
|
||||||
|
```
|
||||||
|
{stats[:2000]}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Comment reviewer
|
||||||
|
1. Vérifier les rapports dans `admin/hermes/builtin/`
|
||||||
|
2. Merger si tout semble correct, ou fermer pour recommencer demain
|
||||||
|
|
||||||
|
> Généré par `hermes-doc-worker` · branche `{BRANCH}`
|
||||||
|
"""
|
||||||
|
|
||||||
|
r = subprocess.run(
|
||||||
|
[
|
||||||
|
"gh", "pr", "create",
|
||||||
|
"--title", f"[Hermes] Rapport documentation — {today}",
|
||||||
|
"--body", body,
|
||||||
|
"--head", BRANCH,
|
||||||
|
"--base", "main",
|
||||||
|
"--repo", "Alkatrazz24/Funk-lab",
|
||||||
|
],
|
||||||
|
capture_output=True, text=True, timeout=30,
|
||||||
|
cwd=str(REPO_DIR),
|
||||||
|
)
|
||||||
|
if r.returncode == 0:
|
||||||
|
pr_url = r.stdout.strip()
|
||||||
|
return {"html_url": pr_url, "title": f"[Hermes] Rapport documentation — {today}"}
|
||||||
|
return {"error": r.stderr.strip() or "gh pr create a échoué"}
|
||||||
|
|
||||||
|
|
||||||
|
# ── Main ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
def load_state() -> dict:
|
def load_state() -> dict:
|
||||||
if STATE_FILE.exists():
|
if STATE_FILE.exists():
|
||||||
return json.loads(STATE_FILE.read_text())
|
return json.loads(STATE_FILE.read_text())
|
||||||
return {"processed": [], "last_run": None}
|
return {"processed": [], "runs_today": 0, "last_run": None}
|
||||||
|
|
||||||
|
|
||||||
def save_state(state: dict):
|
def save_state(state: dict):
|
||||||
|
|
@ -106,116 +180,156 @@ def save_state(state: dict):
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("--all", action="store_true", help="Traiter tous les fichiers")
|
parser.add_argument("--daily-pr", action="store_true", help="Créer PR GitHub + résumé journalier")
|
||||||
parser.add_argument("--subdir", default=None, help="Sous-dossier admin/ à analyser (ex: ia, k8s)")
|
parser.add_argument("--dry-run", action="store_true", help="Analyser sans écrire ni push")
|
||||||
parser.add_argument("--dry-run", action="store_true", help="Analyser sans commit ni push")
|
parser.add_argument("--subdir", default=None, help="Sous-dossier admin/ (ex: ia, k8s)")
|
||||||
parser.add_argument("--reset", action="store_true", help="Réinitialiser l'état (retraiter tous les fichiers)")
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# ── Sync branche ────────────────────────────────────────────
|
now = datetime.now()
|
||||||
git(["fetch", "origin"])
|
run_ts = now.strftime("%Y-%m-%d_%H-%M")
|
||||||
checkout = git(["checkout", BRANCH])
|
today = now.strftime("%Y-%m-%d")
|
||||||
if checkout.returncode != 0:
|
|
||||||
git(["checkout", "-b", BRANCH, f"origin/{BRANCH}"])
|
|
||||||
git(["pull", "origin", BRANCH])
|
|
||||||
|
|
||||||
# ── Sélection des fichiers ───────────────────────────────────
|
# ── Sync branche ─────────────────────────────────────────────
|
||||||
scan_root = ADMIN_DIR / args.subdir if args.subdir else ADMIN_DIR
|
if not args.dry_run:
|
||||||
all_files = sorted(scan_root.rglob("*.md"))
|
git_sync()
|
||||||
|
|
||||||
state = load_state()
|
state = load_state()
|
||||||
if args.reset:
|
|
||||||
state["processed"] = []
|
|
||||||
|
|
||||||
todo = [f for f in all_files if str(f) not in state["processed"]]
|
# ── Mode PR journalier ────────────────────────────────────────
|
||||||
|
if args.daily_pr:
|
||||||
|
# Résumé des runs du jour
|
||||||
|
builtin_today = sorted(BUILTIN_DIR.glob(f"{today}_*.md")) if BUILTIN_DIR.exists() else []
|
||||||
|
summary_parts = []
|
||||||
|
for rpt in builtin_today[-5:]:
|
||||||
|
summary_parts.append(rpt.read_text()[:500])
|
||||||
|
daily_summary = "\n\n---\n\n".join(summary_parts) or "Aucun rapport généré aujourd'hui."
|
||||||
|
|
||||||
|
pr = create_github_pr(daily_summary)
|
||||||
|
result = {
|
||||||
|
"action": "daily_pr",
|
||||||
|
"pr_url": pr.get("html_url", ""),
|
||||||
|
"pr_number": pr.get("number", 0),
|
||||||
|
"pr_title": pr.get("title", ""),
|
||||||
|
"reports_today": len(builtin_today),
|
||||||
|
"error": pr.get("error", "")
|
||||||
|
}
|
||||||
|
print(json.dumps(result, indent=2, ensure_ascii=False))
|
||||||
|
return
|
||||||
|
|
||||||
|
# ── Sélection des fichiers à analyser ─────────────────────────
|
||||||
|
scan_root = ADMIN_DIR / args.subdir if args.subdir else ADMIN_DIR
|
||||||
|
all_md = [
|
||||||
|
f for f in sorted(scan_root.rglob("*.md"))
|
||||||
|
if "hermes/builtin" not in str(f) # ne pas analyser ses propres rapports
|
||||||
|
]
|
||||||
|
|
||||||
|
# Rotation : reprend là où il s'est arrêté
|
||||||
|
todo = [f for f in all_md if str(f) not in state["processed"]]
|
||||||
if not todo:
|
if not todo:
|
||||||
state["processed"] = []
|
state["processed"] = []
|
||||||
todo = all_files
|
todo = all_md
|
||||||
|
|
||||||
batch = todo if args.all else todo[:MAX_FILES]
|
batch = todo[:MAX_FILES]
|
||||||
|
|
||||||
# ── Analyse ──────────────────────────────────────────────────
|
|
||||||
run_ts = datetime.now().strftime("%Y-%m-%d_%H-%M")
|
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
|
# ── Analyse ───────────────────────────────────────────────────
|
||||||
for fpath in batch:
|
for fpath in batch:
|
||||||
rel = str(fpath.relative_to(REPO_DIR))
|
rel = str(fpath.relative_to(REPO_DIR))
|
||||||
print(f" → Analyse : {rel}", flush=True)
|
print(f" → {rel}", flush=True)
|
||||||
|
|
||||||
analysis = analyze_file(fpath)
|
analysis = analyze_file(fpath)
|
||||||
analysis["file"] = rel
|
|
||||||
results.append(analysis)
|
results.append(analysis)
|
||||||
|
|
||||||
# Appliquer les améliorations si Hermes en a proposé
|
|
||||||
if analysis.get("status") == "à_améliorer" and analysis.get("contenu_amélioré"):
|
|
||||||
if not args.dry_run:
|
|
||||||
fpath.write_text(analysis["contenu_amélioré"], encoding="utf-8")
|
|
||||||
print(f" ✓ Améliorations appliquées (score: {analysis.get('score', '?')}/10)", flush=True)
|
|
||||||
elif analysis.get("status") == "ok":
|
|
||||||
print(f" ✓ OK (score: {analysis.get('score', '?')}/10)", flush=True)
|
|
||||||
else:
|
|
||||||
print(f" ⚠ {analysis.get('status', '?')}", flush=True)
|
|
||||||
|
|
||||||
state["processed"].append(str(fpath))
|
state["processed"].append(str(fpath))
|
||||||
|
print(f" {analysis.get('statut','?')} — {analysis.get('score_qualité','?')}/10", flush=True)
|
||||||
|
|
||||||
save_state(state)
|
save_state(state)
|
||||||
|
|
||||||
# ── Rapport ──────────────────────────────────────────────────
|
if not results:
|
||||||
REPORTS_DIR.mkdir(parents=True, exist_ok=True)
|
print(json.dumps({"error": "aucun fichier à analyser"}))
|
||||||
report_file = REPORTS_DIR / f"{run_ts}.json"
|
return
|
||||||
report_file.write_text(
|
|
||||||
json.dumps({"run": run_ts, "results": results}, indent=2, ensure_ascii=False)
|
|
||||||
)
|
|
||||||
|
|
||||||
improved = [r["file"] for r in results if r.get("status") == "à_améliorer" and r.get("contenu_amélioré")]
|
# ── Écriture du rapport dans admin/hermes/builtin/ ────────────
|
||||||
|
BUILTIN_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
report_path = BUILTIN_DIR / f"{run_ts}.md"
|
||||||
|
|
||||||
|
lines = [f"# Rapport Hermes — {run_ts}\n"]
|
||||||
|
lines += [f"> Branche : `{BRANCH}` · Fichiers analysés : {len(results)}\n"]
|
||||||
|
lines += ["\n---\n"]
|
||||||
|
|
||||||
|
ok_count = sum(1 for r in results if r.get("statut") in ("ok", "à_jour"))
|
||||||
|
bad_count = len(results) - ok_count
|
||||||
|
|
||||||
|
lines += [f"## Résumé\n",
|
||||||
|
f"- ✅ À jour : {ok_count}\n",
|
||||||
|
f"- ⚠️ À améliorer : {bad_count}\n\n"]
|
||||||
|
|
||||||
|
for r in results:
|
||||||
|
icon = "✅" if r.get("statut") in ("ok", "à_jour") else "⚠️"
|
||||||
|
lines.append(f"## {icon} `{r['fichier']}` — {r.get('score_qualité', '?')}/10\n\n")
|
||||||
|
lines.append(f"**Statut** : {r.get('statut', '?')} \n")
|
||||||
|
lines.append(f"**Résumé** : {r.get('résumé', '')} \n\n")
|
||||||
|
|
||||||
|
if r.get("problèmes"):
|
||||||
|
lines.append("**Problèmes :**\n")
|
||||||
|
for p in r["problèmes"]:
|
||||||
|
lines.append(f"- {p}\n")
|
||||||
|
lines.append("\n")
|
||||||
|
|
||||||
|
if r.get("suggestions"):
|
||||||
|
lines.append("**Suggestions :**\n")
|
||||||
|
for s in r["suggestions"]:
|
||||||
|
lines.append(f"- {s}\n")
|
||||||
|
lines.append("\n")
|
||||||
|
|
||||||
|
if r.get("état_réel"):
|
||||||
|
lines.append(f"**État réel connu de Hermes :** \n{r['état_réel']}\n\n")
|
||||||
|
|
||||||
|
lines.append("---\n\n")
|
||||||
|
|
||||||
# ── Commit + push ────────────────────────────────────────────
|
|
||||||
if not args.dry_run:
|
if not args.dry_run:
|
||||||
git(["add", str(report_file.relative_to(REPO_DIR))])
|
report_path.write_text("".join(lines), encoding="utf-8")
|
||||||
for f in improved:
|
print(f"\n✓ Rapport : {report_path.relative_to(REPO_DIR)}", flush=True)
|
||||||
git(["add", f])
|
|
||||||
|
# ── Commit + push ─────────────────────────────────────────────
|
||||||
|
if not args.dry_run:
|
||||||
|
git(["add", str(report_path.relative_to(REPO_DIR))])
|
||||||
|
|
||||||
if git(["diff", "--cached", "--quiet"]).returncode != 0:
|
if git(["diff", "--cached", "--quiet"]).returncode != 0:
|
||||||
msg_files = f"\n\nFichiers améliorés :\n" + "\n".join(f" - {f}" for f in improved) if improved else ""
|
|
||||||
git(["commit", "-m",
|
git(["commit", "-m",
|
||||||
f"docs(auto): analyse Hermes {run_ts}{msg_files}\n\n"
|
f"docs(hermes): rapport analyse {run_ts} — {len(results)} fichiers\n\n"
|
||||||
f"Co-Authored-By: Hermes <hermes@funk.lab>"])
|
f"Analysés : {', '.join(r['fichier'].split('/')[-1] for r in results)}\n"
|
||||||
|
f"À améliorer : {bad_count}/{len(results)}\n\n"
|
||||||
|
"Co-Authored-By: Hermes <hermes@funk.lab>"])
|
||||||
git(["push", "origin", BRANCH])
|
git(["push", "origin", BRANCH])
|
||||||
print(f"\n✓ Commit + push → {BRANCH}", flush=True)
|
print(f"✓ Push → {BRANCH}", flush=True)
|
||||||
|
|
||||||
# ── Ré-ingestion Qdrant ──────────────────────────────────
|
# ── Ré-ingestion Qdrant (toujours) ────────────────────────
|
||||||
if improved:
|
print("\n⏳ Qdrant re-ingest...", flush=True)
|
||||||
print("\n⏳ Ré-ingestion Qdrant...", flush=True)
|
ingest_out = rag_ingest()
|
||||||
ingest = subprocess.run(
|
print(f" {ingest_out}", flush=True)
|
||||||
["/usr/local/bin/rag-ingest"],
|
|
||||||
capture_output=True, text=True, timeout=300
|
|
||||||
)
|
|
||||||
print(f" {ingest.stdout.strip()[-200:] if ingest.stdout else 'OK'}", flush=True)
|
|
||||||
|
|
||||||
# ── Résumé JSON (lu par n8n) ─────────────────────────────────
|
# ── Résumé JSON pour n8n ─────────────────────────────────────
|
||||||
summary = {
|
summary = {
|
||||||
"run": run_ts,
|
"run": run_ts,
|
||||||
"branch": BRANCH,
|
"branch": BRANCH,
|
||||||
"analyzed": len(results),
|
"analyzed": len(results),
|
||||||
"improved": len(improved),
|
"ok": ok_count,
|
||||||
"ok": len([r for r in results if r.get("status") == "ok"]),
|
"issues": bad_count,
|
||||||
"errors": len([r for r in results if r.get("status") == "erreur"]),
|
"dry_run": args.dry_run,
|
||||||
"files_improved": improved,
|
"report": str(report_path.relative_to(REPO_DIR)) if not args.dry_run else None,
|
||||||
"dry_run": args.dry_run,
|
"details": [
|
||||||
"details": [
|
|
||||||
{
|
{
|
||||||
"file": r["file"],
|
"file": r["fichier"],
|
||||||
"status": r.get("status"),
|
"statut": r.get("statut"),
|
||||||
"score": r.get("score"),
|
"score": r.get("score_qualité"),
|
||||||
"issues": r.get("problèmes", []),
|
"résumé": r.get("résumé", ""),
|
||||||
"suggestions": r.get("améliorations", [])
|
|
||||||
}
|
}
|
||||||
for r in results
|
for r in results
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
print("\n" + json.dumps(summary, indent=2, ensure_ascii=False))
|
print("\n" + json.dumps(summary, indent=2, ensure_ascii=False))
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
sys.exit(main())
|
main()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue