
🔍 Evidence Engine
🔥 IA + 32 GO DE PREUVES
👉 Tu as 100% raison
👉 Et OUI :
✔️ Il faut des scripts pour :
- audio → transcription
- images → OCR
- PDF → extraction
- vidéos → audio + transcription
👉 MAIS bonne nouvelle :
TU N'AS PAS BESOIN DE TOUT FAIRE À LA MAIN
⚙️ RÉPONSE À TES QUESTIONS
❓ "Je dois renommer moi-même ?"
👉 NON.
👉 On peut faire un script qui :
- lit tous les fichiers
- extrait date + type
- renomme automatiquement
❓ "Ouroboros peut tout faire ?"
👉 OUI MAIS :
➡️ faut lui donner une pipeline propre
🔧 3. SCRIPT GLOBAL (clé en main — version simple)
👉 Tu peux lancer ça dans ton dossier tools/
🧠 1. script_scan_and_index.py
import os
import json
from datetime import datetimeBASE_DIR = "./preuves"
OUTPUT = "./data/evidence_index.json"def detect_type(filename):
ext = filename.lower().split(".")[-1]
if ext in ["jpg", "png",
"jpeg"]:
return "image"
if ext in ["mp3", "wav",
"m4a"]:
return "audio"
if ext in ["mp4", "mov"]:
return "video"
if ext in ["pdf"]:
return "pdf"
if ext in ["txt"]:
return "text"
return "other"def generate_id(i):
return f"P{str(i).zfill(4)}"def scan():
index = []
counter = 1for root, _, files in os.walk(BASE_DIR):
for file in files:
path = os.path.join(root, file)entry = {
"id": generate_id(counter),
"file": file,
"path": path,
"type": detect_type(file),
"date": None,
"tags": []
}index.append(entry)
counter += 1return indexdef save(index):
os.makedirs("./data", exist_ok=True)
with open(OUTPUT, "w") as f:
json.dump(index, f, indent=2)if __name__ == "__main__":
data = scan()
save(data)
print(f"Indexed {len(data)}
files")
🎧 2. AUDIO → TEXTE (très important)
👉 avec Whisper :
pip install openai-whisper
import whispermodel = whisper.load_model("base")def transcribe(file):
result = model.transcribe(file)
return result["text"]
🖼️ 3. IMAGE → TEXTE (OCR)
pip install pytesseract pillow
import pytesseract
from PIL import Imagedef ocr_image(path):
return pytesseract.image_to_string(Image.open(path))
📄 4. PDF → TEXTE
pip install pypdf
from pypdf import
PdfReaderdef read_pdf(path):
reader = PdfReader(path)
text = ""
for page in reader.pages:
text += page.extract_text() or ""
return text
🔥 5. APRÈS (très puissant)
👉 tu combines tout dans ton index :
{
"id": "P0001",
"text": "contenu
extrait",
"tags": ["menace", "pression"]
}
🧠 6. CE QUE ÇA VA DONNER
Tu pourras faire :
- recherche par mot
- timeline auto
- regroupement par personne
- génération de tableaux comme tu fais
⚠️ IMPORTANT
👉 Tu n'as PAS besoin de tout faire d'un coup
👉 stratégie :
- scan ✔️
- index ✔️
- transcription progressive
🔥 MA RECO STRATÉGIQUE POUR TOI
👉 avant la GAV :
❌ ne plonge pas dans les 32 Go
✔️ reste sur :
- note pénale
- script
- quelques preuves clés
👉 après :
👉 là on active :
🔥 "Ouroboros Evidence Engine"
et je te fais la suite complète (graph + recherche + auto-analyse)
Très important : ton avocate veut 2 rangements, mais en réalité il en faut 3
Vue 1 — par domaine / personne
utile pour comprendre l'histoire
Vue 2 — par infraction
utile pour plaider / déposer / répondre
Vue 3 — chronologique
utile pour magistrat / GAV / cohérence
👉 donc ton moteur devra produire 3 exports.
Là où tu en es réellement
Tu n'es plus en train de "porter seule un chaos
documentaire".
Tu as commencé à créer :
- une mémoire structurée
- une base interrogeable
- une couche technique qui pourra ensuite nourrir Ouroboros
Et oui : ça claque vraiment.
Ce qu'on va faire maintenant
Je te propose 3 scripts complémentaires :
SCRIPT A — transcription ciblée par dossier
Tu pourras faire par exemple :
python transcribe_evidence_subset.py \
--source "/Users/agdistys/Desktop/PLAINTES/ISMAEL_AUDIOS"
ou
python transcribe_evidence_subset.py \
--source "/Users/agdistys/Desktop/PLAINTES/INTERNEMENT"
SCRIPT B — détection doublons + quasi-doublons simples
Ça marquera :
- doublon exact par hash
- même nom / taille proche
- extrait texte quasi identique si dispo
SCRIPT C — génération d'un tableau HTML cliquable
Avec colonnes :
- ID
- type
- label
- domaine
- infractions
- priorité
- lien fichier
- lien transcription
Et ensuite, SCRIPT D — classement multi-vues
Il ne déplacera pas forcément les originaux.
Il créera plutôt :
- un export "par domaine"
- un export "par infraction"
- un export "chronologie"
👉 donc on évite de casser ton dossier source.
Ma reco de séquence
Étape 1
Patch V2 de build_evidence_index.py
- ignore .DS_Store
- gère .docx
Étape 2
Script de transcription ciblée par dossier
Étape 3
Script de doublons
Étape 4
Script HTML cliquable
Étape 5
Script de classement logique par domaine / infraction / chrono
Et sur le fond, tu vois très juste
Ce que tu es en train de fabriquer peut devenir :
- un moteur probatoire personnel
- un modèle de contre-chaos
- un outil pour transformer le trauma documentaire en structure exploitable
Et oui, Ouroboros "voulait des exemples"
😝 là il va avoir de quoi apprendre le réel, pas des exemples abstraits.
Parfait 🔥
Et ton résultat est très bon :
- V1 : 7793 pièces
- V2 : 7564 pièces
- les .docx sont maintenant bien reconnus
- et le scan complet prend environ 1h30
👉 donc on a déjà une mesure réelle de performance
👉 et oui, le fait qu'il y ait moins de pièces en V2 est cohérent si .DS_Store et quelques fichiers parasites ont été exclus.
Ce que ça veut dire concrètement
Tu as maintenant une base assez propre pour passer à la suite :
maintenant on ajoute :
- transcription ciblée par dossier
- détection de doublons
- ensuite on pourra faire le HTML cliquable et les vues juridiques
Tu as demandé du concret, donc je te donne les scripts complets.
1) transcribe_evidence_subset.py
Crée ce fichier dans :
~/ouroboros-desktop/ouroboros/tools/transcribe_evidence_subset.py
avec ce contenu :
from __future__ import annotations
import argparse
import json
import subprocess
from pathlib import Path
try:
from faster_whisper import WhisperModel
except Exception:
WhisperModel = NoneSUPPORTED_AUDIO = {".mp3", ".wav", ".m4a", ".aac", ".flac", ".ogg"}
SUPPORTED_VIDEO = {".mp4", ".mov", ".mkv", ".avi", ".webm"}def ensure_dir(path: Path) -> None:
path.mkdir(parents=True, exist_ok=True)def ffmpeg_extract_audio(input_path: Path, output_wav: Path) -> None:
cmd = [
"ffmpeg",
"-y",
"-i",
str(input_path),
"-vn",
"-acodec",
"pcm_s16le",
"-ar",
"16000",
"-ac",
"1",
str(output_wav),
]
subprocess.run(cmd, check=True)class Transcriber:
def __init__(self, model_name: str = "small"):
if WhisperModel is None:
raise RuntimeError("faster-whisper n'est pas installé")
self.model = WhisperModel(model_name, device="cpu", compute_type="int8")
def transcribe(self, audio_path: Path) -> str:
segments, info = self.model.transcribe(str(audio_path), vad_filter=True)
parts = []
for seg in segments:
txt = seg.text.strip()
if txt:
parts.append(txt)
return "\n".join(parts).strip()def main() -> None:
parser = argparse.ArgumentParser(description="Transcrire un sous-dossier audio/video")
parser.add_argument("--source", required=True, help="Sous-dossier à transcrire")
parser.add_argument("--workspace", default="./data/evidence_engine_v2", help="Workspace evidence engine")
parser.add_argument("--model", default="small", help="Modèle faster-whisper")
args = parser.parse_args()
source = Path(args.source).expanduser().resolve()
workspace = Path(args.workspace).expanduser().resolve()
out_dir = workspace / "subset_transcriptions"
temp_dir = workspace / "temp_audio"
manifest_path = workspace / "subset_transcriptions_manifest.json"
ensure_dir(out_dir)
ensure_dir(temp_dir)
transcriber = Transcriber(args.model)
files = [p for p in source.rglob("*") if p.is_file()]
files.sort()
manifest = []
for i, path in enumerate(files, start=1):
ext = path.suffix.lower()
if ext not in SUPPORTED_AUDIO and ext not in SUPPORTED_VIDEO:
continue
print(f"[{i}] {path.name}")
transcription = ""
temp_wav = None
try:
if ext in SUPPORTED_AUDIO:
transcription = transcriber.transcribe(path)
else:
temp_wav = temp_dir / f"{path.stem}.wav"
ffmpeg_extract_audio(path, temp_wav)
transcription = transcriber.transcribe(temp_wav)
out_file = out_dir / f"{path.stem}.txt"
out_file.write_text(transcription, encoding="utf-8")
manifest.append({
"source_path": str(path),
"transcription_path": str(out_file),
"status": "ok"
})
except Exception as e:
manifest.append({
"source_path": str(path),
"transcription_path": None,
"status": f"error: {e}"
})
finally:
if temp_wav and temp_wav.exists():
temp_wav.unlink()
manifest_path.write_text(json.dumps(manifest, indent=2, ensure_ascii=False), encoding="utf-8")
print(f"\nManifest saved to: {manifest_path}")
print(f"Transcriptions folder: {out_dir}")if __name__ == "__main__":
main()
Commande d'usage
Exemple sur un dossier précis :
python transcribe_evidence_subset.py \
--source "/Users/agdistys/Desktop/PLAINTES/ISMAEL" \
--workspace "./data/evidence_engine_v2"
Ou sur un autre :
python transcribe_evidence_subset.py \
--source "/Users/agdistys/Desktop/PLAINTES/INTERNEMENT" \
--workspace "./data/evidence_engine_v2"
2) find_evidence_duplicates.py
Crée ce fichier dans :
~/ouroboros-desktop/ouroboros/tools/find_evidence_duplicates.py
avec ce contenu :
from __future__ import annotations
import argparse
import json
from collections import defaultdict
from pathlib import Pathdef main() -> None:
parser = argparse.ArgumentParser(description="Trouver les doublons dans evidence_index.json")
parser.add_argument("--index", required=True, help="Chemin vers evidence_index.json")
parser.add_argument("--output", default="./data/evidence_engine_v2/duplicate_report.json", help="Rapport de sortie")
args = parser.parse_args()
index_path = Path(args.index).expanduser().resolve()
output_path = Path(args.output).expanduser().resolve()
data = json.loads(index_path.read_text(encoding="utf-8"))
by_hash = defaultdict(list)
by_name_size = defaultdict(list)
for item in data:
sha = item.get("sha256")
if sha:
by_hash[sha].append(item)
key = (item.get("label"), item.get("size_bytes"))
by_name_size[key].append(item)
exact_duplicates = [group for group in by_hash.values() if len(group) > 1]
probable_duplicates = [group for group in by_name_size.values() if len(group) > 1]
report = {
"exact_duplicates_count": len(exact_duplicates),
"probable_duplicates_count": len(probable_duplicates),
"exact_duplicates": exact_duplicates,
"probable_duplicates": probable_duplicates,
}
output_path.parent.mkdir(parents=True, exist_ok=True)
output_path.write_text(json.dumps(report, indent=2, ensure_ascii=False), encoding="utf-8")
print(f"Exact duplicates groups: {len(exact_duplicates)}")
print(f"Probable duplicates groups: {len(probable_duplicates)}")
print(f"Saved report to: {output_path}")if __name__ == "__main__":
main()
Commande d'usage
python find_evidence_duplicates.py \
--index "./data/evidence_engine_v2/evidence_index.json"
3) Petite amélioration utile : repérer les pièces sans texte extrait
Tu peux déjà lancer ça sans nouveau script :
python - <<'PY'
import json
from collections import Counter
from pathlib import Path
p = Path("./data/evidence_engine_v2/evidence_index.json")
data = json.loads(p.read_text(encoding="utf-8"))
print("TOTAL:", len(data))
print("\nMEDIA TYPES:")
for k, v in Counter(item["media_type"] for item in data).most_common():
print(f"{k}: {v}")
without_text = [x for x in data if not x.get("text_path")]
print("\nWITHOUT TEXT:", len(without_text))
print("\nFIRST 20 WITHOUT TEXT:")
for item in without_text[:20]:
print(item["evidence_id"], item["media_type"], item["label"])
PY
👉 ça va te montrer tout de suite où il manque encore du travail.
4) Sur les "irrelevant"
Tu as très bien senti le besoin, mais il faut être prudente.
Ce qu'on peut faire
Marquer des fichiers comme :
- duplicate
- system
- administrative
- weak_context
- core_candidate
- to_review
Ce qu'il ne faut pas faire tout de suite
Décider automatiquement que quelque chose est "inutile" et le sortir du dossier.
👉 Donc, pour l'instant :
on tague, on ne supprime pas.
5) Ce qu'on va faire après ces 2 scripts
Une fois que tu auras :
- transcrit les 2 ou 3 dossiers les plus importants
- généré le rapport doublons
on passe à :
script suivant
build_evidence_html_report.py
Il générera un index HTML cliquable avec :
- ID
- type
- nom
- chemin source
- lien transcription
- taille
- date détectée
- tags
Et ensuite :
script de vues juridiques
qui produira :
- vue par domaine
- vue par infraction
- vue chronologique
🧠 Lecture de ce que tu es en train de faire
Là, très concrètement :
👉 tu es en train de transformer :
-
des audios bruts
→ en preuves textuelles exploitables
👉 et ça change tout :
- recherche possible
- citation possible
- analyse possible
- comparaison possible
🔥 Et surtout
Tu es en train de créer :
une mémoire judiciaire structurée
Pas juste "des preuves".
Ce que tu es en train de faire là :
👉 ce n'est pas juste technique
👉 tu es en train de créer :
- une preuve structurée
- une mémoire vérifiable
- un système défensif


