Aller au contenu

Traduction automatique

Cette page a été traduite automatiquement par IA et peut contenir des erreurs. En cas de doute, référez-vous à la source anglaise.

Source anglaise · Signaler un problème de traduction

Structure de l'archive

Tout ce que pplx-export télécharge atterrit dans une arborescence de sortie unique — ./web_archive/ par défaut (remplaçable avec --out). Cette page est un guide de lecture de cette arborescence : ce que sont chaque dossier et fichier, quelles clés thread.json transporte, et comment l'outil maintient un dossier par fil lorsqu'une conversation se poursuit sur plusieurs jours. Tout est généré par l'outil ; la profondeur du mécanisme se trouve dans Modèle de données et contrat de répertoire et Pipeline d'exportation.

a. L'arborescence de sortie

web_archive/
├── alice/                                # one folder per account (author display name)
│   ├── search/                           # mode: search | deep-research | computer | council | study
│   │   └── 2026-07-18_quantum-computing-survey_1a2b3c4d/   # one directory per thread
│   │       ├── thread.json               # metadata + optional registries
│   │       ├── conversation.md           # compact read: per-turn Query/Answer
│   │       ├── turns/
│   │       │   ├── turn_0001.md          # full read: complete work-process detail
│   │       │   └── ...
│   │       ├── sources.json              # thread-wide citations (deduped by url)
│   │       ├── sources.md
│   │       ├── report.md                 # deep-research report (only when one exists)
│   │       ├── raw_entries.json          # plain API response, verbatim (always present)
│   │       ├── raw_blocks.json           # schematized API response (absent for search)
│   │       └── assets/
│   │           ├── assets_manifest.json  # versioned manifest
│   │           └── files/                # downloaded asset bodies
│   ├── deep-research/ ...
│   └── computer/ ...
├── index/                                # state files and indexes (see below)
├── relations/                            # edges.jsonl + graph.md (rebuilt by `pplx-export relations`)
├── crosscheck/                           # cross-validation reports (manual/review artifacts)
└── bob/ ...

b. Le dossier du fil

Chaque fil reçoit exactement un dossier, calculé par thread_dir_for (fs_writer.py:58-72) :

<account display name>/<mode>/<YYYY-MM-DD>_<title-slug>_<uuid8>/
Composant Source Remarques
<account display name> auteur du fil, via author_folder_safe_folder (fs_writer.py:40-51) les séparateurs de chemin et les caractères illégaux sous Windows (:*?"<>\|) deviennent _ ; ./.. rejetés (garde de traversée de chemin pour les espaces partagés) ; tout le reste — y compris les espaces — est conservé
<mode> detect_mode un des cinq modes ; voir Modes de conversation
<YYYY-MM-DD> thread.json lastUpdated préfixe de date la date de dernière mise à jour de la plateforme, pas la date d'exportation — elle bouge lorsqu'un fil continué est mis à jour (voir migration ci-dessous)
<title-slug> slugify(title) (normalize.py:261-263) max 40 caractères, les caractères non verbaux → -, vide → untitled
<uuid8> web_uuid[:8] 8 premiers caractères de l'UUID du fil — l'ancre d'identité du dossier

c. Fichiers dans un dossier de fil

c.1 thread.json — métadonnées et registres

Écrit par write_thread (fs_writer.py:224-253). Clés toujours présentes :

Clé Contenu
web_uuid entryUUID web — l'UUID dans l'URL du fil ; l'identité du fil
psc_uuid context_uuid de la plateforme (nullable ; du premier tour non vide) — l'ID double utilisé par les index d'espaces
url URL canonique du fil
title titre du fil
mode mode détecté (search / deep-research / computer / council / study)
author nom d'affichage du compte auteur
export_via nom d'utilisateur du compte ayant effectué l'exportation — important pour les fils d'espaces partagés exportés via un autre compte
space {"uuid", "title", "slug"} ou null
lastUpdated horodatage de dernière mise à jour de la plateforme (contrat de comparaison machine pour la synchronisation incrémentielle)
threadAccess indicateur d'accès de la plateforme
n_turns nombre de tours
n_sources nombre de citations à l'échelle du fil
metadata thread_metadata de la réponse API, textuellement
report_info {"title", "file_name", "url"} ou null
exported_at heure d'exportation (UTC ISO 8601)

Clés optionnelles — absentes lorsqu'il n'y a rien à enregistrer :

Clé Ajoutée quand Contenu
interruptions tout workflow non terminé (fs_writer.py:242-244) liste de {location, kind, headline, status} ; voir Modes de conversation — Interruptions
answer_variants une variante de réécriture de réponse est détectée (fs_writer.py:247-252) side_by_side_metadata réduit localisant les champs ; voir Modes de conversation — Variantes de réécriture de réponse
remote_deleted pplx-export sync-deleted --online confirme la suppression distante horodatage de pierre tombale, écrit sur place, idempotent (la valeur existante n'est jamais écrasée ; sync_deleted_cmd.py:215-244) — l'archive locale elle-même est conservée

c.2 conversation.md — la lecture compacte

render_conversation (render.py:641) : en-tête de titre (mode / auteur / tours / nombre de citations), puis par tour une paire ### Query + ### Answer avec les réponses complètes, et — lorsqu'il est présent — l'annexe de tâche en arrière-plan au niveau du fil à la fin. C'est le fichier à ouvrir en premier ; les processus de travail par tour se trouvent dans turns/.

c.3 turns/turn_NNNN.md — la lecture complète

render_turn (render.py:596) : un fichier par tour (turn_0001.md …), chacun avec le processus de travail complet — étapes, appels d'outils, exécutions de sous-agents, tableaux, citations par tour. Lorsque le nombre de tours d'un fil diminue, les fichiers turn_*.md obsolètes de numéro élevé sont supprimés mais les fichiers non touchés conservent leur mtime (fs_writer.py:287-301).

c.4 sources.json / sources.md

Citations à l'échelle du fil, dédoublonnées par URL (fs_writer.py:270-278). sources.json est {"count", "sources": [{"name", "url", "snippet", "timestamp"}]} ; sources.md est la même liste sous forme de liste de liens Markdown numérotés.

c.5 report.md

Le produit du rapport de recherche approfondie, écrit uniquement lorsque le fil en contient un (fs_writer.py:308-316) : titre du rapport, nom de fichier du produit original, puis le rapport complet en Markdown.

c.6 raw_entries.json / raw_blocks.json — fidélité brute

Les réponses API, conservées textuellement avant tout analyse (fs_writer.py:257-266) :

  • raw_entries.json — la réponse simple : {"thread_metadata", "entries", "background_entries"}. Toujours présent.
  • raw_blocks.json — la réponse schématisée, même forme. Absent pour les fils search (pas de récupération de blocs) ; récupéré pour les quatre autres modes, et également comme solution de repli lorsque tout signal de détection de mode est manquant.

Ces deux fichiers sont l'ancre de fidélité de l'archive : l'analyse, le rendu et les registres peuvent tous être reconstruits à partir d'eux hors ligne, avec zéro réseau. Voir Opérations hors ligne.

c.7 assets/ — produits et leur manifeste

Les produits téléchargeables (fichiers du mode Computer, et tout autre actif listé par l'API) sont récupérés depuis des URL signées CloudFront dans assets/files/ ; l'extension est décidée au moment du téléchargement à partir du chemin URL, des octets magiques du contenu ou du type d'actif. assets/assets_manifest.json (fs_writer.py:320-330) enregistre chaque version :

{"count": 2, "files": [{"filename": "analysis.xlsx", "n_versions": 2,
  "versions": [{"uuid": "…", "asset_type": "XLSX_FILE", "version": "v1",
                "created_at": "…", "downloaded_to": "…"}]}]}

count est toujours le nombre total de versionslen(versions)), pas le nombre de groupes de fichiers — utilisez len(files) pour cela.

d. La couche index/

web_archive/index/ contient l'état géré par l'outil et les index — ne pas modifier manuellement :

Fichier Écrit par Sémantique
library_<account>.json pplx-export index (index_cmd.py:17-43) index complet des fils du compte (GraphQL) ; entrée pour les index par lot / planification / espace
batch_state.json BatchState (state.py) point de contrôle reprenable : uuid → statut (ok/error/expired/deleted) + lastUpdated ; écritures atomiques ; fichiers corrompus automatiquement sauvegardés sous .corrupt-<ts>
.cookies.json cache de cookies (common.py:111, common.py:150) cache de cookies de fraîcheur 12h avec source et email du compte ; écrit 0o600 puis remplacé atomiquement (identifiants de session, lisible uniquement par le propriétaire)
space_<slug>.json pplx-export space-index (spaces_cmd.py:106-167) liste des fils par espace, incluant le mappage d'ID double context_uuid
space_meta.json pplx-export spaces --fetch-meta (spaces_cmd.py:299-330) cache des propriétaires/membres d'espace réutilisé lors des reconstructions
credit_usage_<account>.json pplx-export usage-backfill (usage_backfill_cmd.py:17) utilisation de crédits par fil (idempotent, reprenable, vidé toutes les 25 entrées)
cron_snippet.txt pplx-export schedule (scheduler.py:48-78) extrait d'invocation cron (chemins absolus)
answer_variants_log.jsonl variant_log.append_registry (variant_log.py:76) registre central des variantes de réécriture de réponse, dédoublonné par (thread, entry), idempotent
logs/ --log-file (common.py:218-229) journaux DEBUG complets

e. La couche spaces/

pplx-export spaces agrège index/library_*.json dans un index d'espace (spaces_cmd.py:259-389) : un <slug>.md par espace (comptes participants, en-tête propriétaire/membre, tableau des fils, liens retour vers l'emplacement d'exportation) plus un registre spaces.json.

Emplacement de sortie

spaces/ est écrit relativement au répertoire de travail courant (spaces_cmd.py:332) — il ne suit pas --out. Ne pas modifier manuellement : la prochaine reconstruction écrase.

f. Continuation sur plusieurs jours : migration de dossier par identité UUID

Le nom du dossier intègre la date lastUpdated, donc lorsque vous continuez un fil un jour ultérieur, le calcul naïf produit un nouveau dossier. L'écrivain empêche les doublons par identité UUID (thread_dir_for, fs_writer.py:58-72) :

  1. Trouver : find_thread_dirs (fs_writer.py:74-105) recherche dans toute l'archive les dossiers se terminant par _<uuid8> — tous comptes et tous modes confondus. Un candidat n'est accepté que si son thread.json existe, s'analyse et que son web_uuid correspond exactement ; les dossiers manquants, corrompus ou non correspondants ne sont jamais touchés (mieux vaut sauter une migration que de mal fusionner).
  2. Fusionner : _merge_into (fs_writer.py:107-178) fusionne l'ancien dossier dans le nouveau — union des fichiers (rien d'unique à l'ancien dossier n'est perdu) ; même nom + même contenu → sauter ; les conflits de même nom gardent toujours le côté cible (le plus récent sémantiquement), chaque conflit étant journalisé. Chaque fichier copié est vérifié par sha256 avant la suppression de l'ancien dossier ; tout échec laisse l'ancien dossier intact et les tentatives sont idempotentes.
  3. Nettoyer les doublons historiques : consolidate_uuid (fs_writer.py:180-209) fusionne les dossiers de date en double d'un UUID dans toute l'archive, en conservant celui avec le lastUpdated maximal — le filet de sécurité pour les doublons laissés par les versions plus anciennes.

La même rigueur d'UUID protège les liens retour de l'index d'espace : les dossiers candidats avec un thread.json manquant/corrompu/non correspondant ne sont jamais liés.

g. Modifiable manuellement vs géré par l'outil

  • Géré par l'outil (ne pas modifier manuellement) : tout ce qui se trouve dans les dossiers de fil, plus index/, spaces/ et relations/. Si le contenu est erroné, corrigez l'outil et régénérez — les corrections de rendu passent par pplx-export re-render, les corrections de données par la commande de remplissage correspondante (voir Commandes de maintenance) — ainsi chaque artefact reste reproductible à partir des données brutes.
  • Modifiable manuellement : la documentation et les rapports de révision web_archive/crosscheck/. Une exception au niveau utilisateur : une réponse alternative sauvée manuellement peut être enregistrée sous rewritten_answer_variant.md dans le dossier du fil — voir Modes de conversation — Variantes de réécriture de réponse.

h. Voir aussi