SDK Python de conversion de fichiers#

enconvert est le client Python officiel de l'API EnConvert : un seul pip install, une seule clé API, et des méthodes typées pour convertir des fichiers et pour lire le web en direct. Il tourne sur Python 3.9 ou plus récent avec une seule dépendance runtime, requests, et embarque des annotations de type en ligne ainsi qu'un marqueur py.typed pour que mypy et Pyright voient tout. Le client a deux surfaces. Douze méthodes de conversion couvrent 43 paires {input}-to-{output}, plus URL vers PDF, capture d'écran et Markdown. L'espace de noms client.v2 ajoute la web intelligence : perceive, discover, lookup, distill, ingest et watch.

PyPI : enconvert · Source : conversionapi/python-sdk · Python : 3.9+ · Dépendance runtime : requests>=2.28 · Licence : MIT

Installation#

pip install enconvert

uv add enconvert et poetry add enconvert fonctionnent de la même façon. requests est la seule dépendance runtime, et les stubs de types sont livrés dans la wheel : il n'y a donc aucun package types- à aller chercher.


Démarrage rapide#

Lisez une page comme votre agent devrait le faire, avec un score de qualité attaché, puis convertissez un fichier local via le même client.

import os

from enconvert import Enconvert

client = Enconvert(api_key=os.environ["ENCONVERT_API_KEY"])

op = client.v2.perceive("https://example.com", outputs=["markdown", "structured"])
print(op.outputs["markdown"].url, op.render_quality)

print(client.convert_to_pdf("report.docx", save_to="report.pdf").presigned_url)

Toutes les méthodes sont synchrones et bloquantes. Le SDK est exclusivement côté serveur : il s'authentifie avec une clé API privée, alors ne le livrez jamais à l'intérieur d'un client desktop, mobile ou navigateur. Récupérez une clé depuis votre tableau de bord, et consultez Authentification pour comprendre la portée des clés.


Ce que le client expose#

Enconvert constitue toute la surface publique. Les méthodes de conversion sont accrochées directement au client ; tout ce qui touche au web vit sous client.v2.

Méthode de conversion Endpoint Renvoie
convert_url_to_pdf(url, ...) POST /v1/convert/url-to-pdf ConversionResult
convert_url_to_screenshot(url, ...) POST /v1/convert/url-to-screenshot ConversionResult
convert_url_to_markdown(url, ...) POST /v1/convert/url-to-markdown ConversionResult
convert_image(file, output_format=...) POST /v1/convert/{input}-to-{output} ConversionResult
convert_document(file, ...) POST /v1/convert/{input}-to-{output} ConversionResult
convert_to_markdown(file, ...) POST /v1/convert/anything-to-markdown ConversionResult
convert_to_pdf(file, ...) POST /v1/convert/anything-to-pdf ConversionResult
convert_website_to_pdf(url, ...) POST /v1/convert/website-to-pdf BatchSubmission
convert_website_to_screenshot(url, ...) POST /v1/convert/website-to-screenshot BatchSubmission
get_job_status(job_id) GET /v1/convert/status/{job_id} JobStatus
get_batch_status(batch_id) GET /v1/convert/batch/{batch_id} BatchStatus
wait_for_batch(batch_id, ...) GET /v1/convert/batch/{batch_id} (interrogé) BatchStatus
Capacité client.v2 Méthodes Renvoie
Perceive perceive, perceive_direct, get_perceive_operation, download_perceive_artifact, perceive_batch, get_perceive_batch PerceiveResult, PerceiveDirectResult, PerceiveBatchResult
Discover, Lookup, Distill discover, lookup, distill DiscoverResult, LookupResult, DistillResult
Ingest ingest, ingest_files, list_ingest_jobs, get_ingest_job, cancel_ingest_job, retry_ingest_webhook, get_webhook_secret, rotate_webhook_secret IngestJob, IngestJobList, WebhookSecret, WebhookRetryResult
Watch create_watcher, list_watchers, get_watcher, get_watcher_snapshots, update_watcher, delete_watcher Watcher, WatcherList, WatcherSnapshotList

Tous les arguments qui suivent le premier argument positionnel sont nommés uniquement, en snake_case, et facultatifs sauf indication contraire dans un tableau. Les résultats sont des dataclasses figées : construisez donc une nouvelle instance plutôt que d'en muter une. Les formes REST se trouvent dans la vue d'ensemble des endpoints.


Conversion de fichiers#

Chaque méthode de conversion accepte save_to (un str ou un os.PathLike ; le résultat y est écrit en flux et les répertoires parents sont créés) et output_filename (remplace le nom généré). Les deux sont omis des tableaux ci-dessous.

convert_url_to_pdf#

Rendez en PDF n'importe quelle URL accessible.

result = client.convert_url_to_pdf(
    "https://example.com", single_page=False, viewport_width=1440, save_to="report.pdf"
)
print(result.presigned_url, result.file_size)
Option Type Défaut Description
single_page bool True True donne une seule page continue. False pagine en utilisant pdf_options.page_size.
pdf_options PdfOptions -- Format de page, orientation, marges, échelle, niveaux de gris, en-tête, pied de page. Voir Options PDF.
viewport_width / viewport_height int 1920 / 1080 Taille de la fenêtre du navigateur, en pixels.

load_media et enable_scroll valent tous deux True par défaut : le premier attend les images et les vidéos, le second fait défiler de haut en bas pour que les chargements différés se déclenchent. Trois options supplémentaires permettent d'atteindre des pages derrière une porte : auth (HttpBasicAuth), cookies (list[BrowserCookie]) et headers (dict[str, str]).

Ne combinez pas auth avec un en-tête Authorization. L'API rejette le conflit plutôt que de deviner quelle authentification l'emporte. Choisissez-en une.

convert_url_to_screenshot#

Capturez un PNG de n'importe quelle URL.

client.convert_url_to_screenshot("https://example.com", viewport_width=1440, save_to="shot.png")

Accepte les mêmes options de fenêtre, de médias, de défilement, de nom de fichier et d'accès navigateur que convert_url_to_pdf, sans single_page ni pdf_options.


convert_url_to_markdown#

Extrayez du Markdown GitHub-Flavored propre depuis une URL. La navigation, les pieds de page, les publicités et les scripts sont supprimés, le corps principal de l'article est conservé, et un frontmatter YAML avec titre, description, url, liens et images est ajouté en tête.

client.convert_url_to_markdown("https://example.com/article", save_to="article.md")

Même jeu d'options que convert_url_to_screenshot. Quand vous voulez en plus un score de qualité, les métadonnées de la page ou une extraction structurée sur la même lecture, utilisez plutôt v2.perceive.


convert_image#

Convertissez entre jpeg, png, svg, heic et webp, ou rastérisez un PDF en JPEG. Le format d'entrée vient de l'extension du nom de fichier.

client.convert_image("photo.heic", output_format="webp", save_to="photo.webp")
client.convert_image("scan.pdf", output_format="jpeg", save_to="scan.jpeg")

output_format est obligatoire et doit valoir jpeg, png, svg, heic ou webp ; les alias jpg, yml, htm et md sont normalisés pour vous. file accepte une chaîne de chemin, un os.PathLike, des bytes bruts, ou un wrapper FileData(data, filename). Les bytes bruts ne portent aucun nom de fichier et sont téléversés sous upload.bin : préférez donc FileData chaque fois que l'extension compte.

from pathlib import Path

from enconvert import FileData

blob = FileData(data=Path("photo.heic").read_bytes(), filename="photo.heic")
client.convert_image(blob, output_format="webp", save_to="photo.webp")

convert_document#

Convertissez des documents et des formats de données. output_format vaut "pdf" par défaut, et pdf_options est pris en compte lorsque la sortie est un PDF.

from enconvert import PdfMargins, PdfOptions

client.convert_document("report.docx", save_to="report.pdf")
client.convert_document("data.json", output_format="yaml", save_to="data.yaml")
client.convert_document(
    "README.md", pdf_options=PdfOptions(page_size="A4", margins=PdfMargins(top=20)), save_to="r.pdf"
)

Entrées prises en charge : .doc, .docx, .xls, .xlsx, .ppt, .pptx, .html, .htm, .odt, .ods, .odp, .ots, .pages, .numbers, .md, .markdown, .csv, .json, .xml, .yaml, .yml, .toml.

EPUB n'a pas de paire de document dédiée. Faites passer les .epub par convert_to_pdf ou convert_to_markdown.


convert_to_markdown#

Détectez automatiquement un document téléversé côté serveur et récupérez du Markdown propre. C'est la brique d'ingestion RAG pour un fichier unique.

client.convert_to_markdown("handbook.docx", save_to="handbook.md")

Entrées acceptées : PDF, DOCX, PPTX, XLSX, CSV, HTML, EPUB, TXT et MD, ainsi que les formats bureautiques anciens et ODF. Les images ne sont pas prises en charge ici, et l'endpoint n'accepte aucune option PDF. Pour un site entier plutôt qu'un seul fichier, utilisez v2.ingest.


convert_to_pdf#

Détectez automatiquement un fichier téléversé côté serveur et récupérez un PDF.

from enconvert import PdfOptions

client.convert_to_pdf("slides.pptx", save_to="slides.pdf")
client.convert_to_pdf("scan.pdf", pdf_options=PdfOptions(grayscale=True), save_to="gray.pdf")

Entrées acceptées : bureautique, ODF, Pages, Numbers, RTF, CSV, HTML, Markdown, texte brut, images matricielles, SVG, EPUB, et un PDF existant transmis tel quel. Comme une entrée .pdf est transmise telle quelle, cette méthode fait aussi office de normaliseur en niveaux de gris.

Seul pdf_options.grayscale est pris en compte sur cet endpoint. Les autres champs de géométrie de page sont ignorés ici. Quand vous avez besoin d'une vraie mise en page, faites passer le fichier par convert_document ou convert_url_to_pdf.

convert_website_to_pdf et convert_website_to_screenshot#

Découvrez chaque page d'un site, convertissez-les toutes en arrière-plan, et récupérez un seul ZIP. Les deux méthodes sont asynchrones par conception et renvoient immédiatement un BatchSubmission.

batch = client.convert_website_to_pdf(
    "https://example.com", crawl_mode="sitemap", exclude_patterns=["/blog/tag/"]
)
print(batch.batch_id, batch.url_count, batch.discovery_method)

status = client.wait_for_batch(batch.batch_id, save_to="site.zip")
print(status.completed, "of", status.total, "pages converted")

for item in client.get_batch_status(batch.batch_id).items:
    print(item.source_url, item.status, item.download_url)
Option Type Défaut Description
crawl_mode "auto" \| "sitemap" \| "full" défaut serveur sitemap lit uniquement sitemap.xml. full ajoute un crawl en largeur d'abord. auto choisit le mode le plus élevé disponible pour la clé.
include_patterns / exclude_patterns list[str] -- Conserve ou écarte les URL par fragment de chemin. Les exclusions ne s'appliquent qu'en mode crawl complet.
notification_email / callback_url str -- Adresse à prévenir par e-mail, et webhook à appeler, quand le lot se termine.
single_page bool défaut serveur PDF uniquement.
pdf_options PdfOptions -- PDF uniquement. Voir Options PDF.

Les options de rendu par page s'appliquent aussi à chaque URL découverte : viewport_width, viewport_height, load_media, enable_scroll, auth, cookies et headers. Tout ce qui reste non défini conserve la valeur par défaut de la passerelle.

wait_for_batch accepte interval_seconds (défaut 5.0), timeout_seconds (défaut 1800.0) et save_to. Il lève APIError(504, ...) si le lot est toujours en traitement une fois l'échéance passée.


Paires de conversion prises en charge#

Le SDK embarque une copie de la carte des conversions de la passerelle et rejette localement une paire non implémentée, avant tout aller-retour réseau, en nommant dans le message les sorties valides pour cette entrée.

Entrée Sorties
json csv, toml, xml, yaml
xml csv, json
yaml, toml json
csv json, xml
markdown html, pdf
html pdf
doc, excel, ppt, odt, ods, odp, ots, pages, numbers pdf
jpeg, png, svg, heic, webp les unes vers les autres, les 20 paires
pdf jpeg

Cela fait 43 paires implémentées. Vérifiez-les par programme :

from enconvert import IMPLEMENTED_CONVERSIONS, valid_outputs_for

valid_outputs_for("json")                  # ['csv', 'toml', 'xml', 'yaml']
"heic-to-webp" in IMPLEMENTED_CONVERSIONS  # True

La référence complète des paramètres vit dans Paramètres et options.


Web intelligence (V2)#

Chaque lecture V2 porte render_quality, un flottant de 0.0 à 1.0 qui dit avec quelle honnêteté la page s'est rendue. Un écran de défi, un mur de cookies, une porte de connexion, une page d'erreur HTTP ou une coquille vide d'application monopage revient avec un score bas, une table deductions nommant ce qui s'est déclenché, et une liste warnings. Le contenu est tout de même renvoyé, simplement signalé : une mauvaise lecture n'entre donc jamais discrètement dans le contexte de votre agent. Traitez le score comme une porte et vérifiez-le avant d'utiliser le texte. PerceiveResult, PerceiveDirectResult, DistillItem, LookupItem.perceive et WatcherSnapshot l'exposent tous. Les concepts se trouvent dans la vue d'ensemble V2.

Perceive#

Rendez une URL sous forme d'artefacts prêts pour un agent. Synchrone : l'appel renvoie l'opération terminée avec des URL d'artefacts signées.

op = client.v2.perceive(
    "https://example.com",
    outputs=["markdown", "screenshot", "structured"],
    extract=["tables", "metadata"],
    only_main_content=True,
)

print(op.render_quality)            # de 0.0 à 1.0
print(op.status_code)               # statut HTTP de la page elle-même
print(op.deductions)                # par ex. {"login_wall": 0.65}
print(op.outputs["markdown"].url)   # URL signée, 15 minutes
print(op.structured)

if (op.render_quality or 0) < 0.6:
    print("Low-confidence read:", op.warnings)
Option Type Défaut Description
outputs list[str] ["markdown", "structured"] Au choix parmi markdown, html_cleaned, html_raw, screenshot, screenshot_full_page, pdf, links, images, structured.
extract list[str] -- Au choix parmi tables, prices, contacts, metadata, main_content, headings, structured_data, technologies, all.
wait_for str -- Sélecteur CSS à attendre avant la capture.
viewport PerceiveViewport 1920 x 1080 width de 320 à 3840, height de 240 à 2160.
cache_mode "enabled" \| "bypass" \| "refresh" défaut serveur Réutilise, ignore ou réécrit le rendu mis en cache.
block_resources list[str] -- Au choix parmi image, media, font, stylesheet, script, xhr, fetch, websocket, manifest, other.
only_main_content bool défaut serveur Supprime la navigation, les en-têtes, les pieds de page et les autres habillages de la page dans le contenu extrait.
direct_download bool False Renvoie les octets bruts au lieu d'une URL signée. Accepté par perceive uniquement ; l'endpoint de lot le rejette.

Également acceptés : schema (dict, un schéma d'extraction libre transmis intact), js_code (str, exécuté dans la page avant la capture), wait_timeout_ms (int), headers (dict[str, str]), cookies (list[BrowserCookie]), auth (HttpBasicAuth), proxy_url (str), geolocation (dict), action_chain (list[dict] d'étapes scriptées de clic, de saisie et de défilement), pdf_options (PdfOptions, appliqué à la sortie pdf), mobile (bool) et respect_robots (bool). perceive_batch prend le jeu identique, sauf direct_download.

Les URL d'artefacts sont resignées à chaque lecture : appelez donc client.v2.get_perceive_operation(op.operation_id) pour en obtenir une fraîche, plutôt que de mettre la chaîne en cache.

Octets bruts, sans aller-retour par URL signée. perceive_direct force direct_download et vous remet l'artefact lui-même, avec les métadonnées lues dans les en-têtes de la réponse.

direct = client.v2.perceive_direct("https://example.com", outputs=["markdown"])
print(direct.filename, direct.content_type, len(direct.content), direct.render_quality)

raw = client.v2.download_perceive_artifact(op.operation_id, output="markdown")

perceive_direct exige exactement une sortie produisant un artefact parmi markdown, html_cleaned, html_raw, screenshot, screenshot_full_page, pdf, links et images. structured peut accompagner la demande mais reste en ligne côté serveur ; passez autre chose et le SDK lève EnconvertError avant d'envoyer la requête. Sur download_perceive_artifact, output peut être omis lorsque l'opération n'a produit qu'un seul artefact, et un artefact sorti de sa fenêtre de rétention répond 410.

Lots. Jusqu'à 1000 URL partagent un seul bloc d'options. Les petits lots se terminent en ligne ; les plus gros reviennent avec le statut "queued", alors interrogez l'identifiant de tâche.

batch = client.v2.perceive_batch(
    ["https://a.example.com", "https://b.example.com"], outputs=["markdown"], output_mode="zip"
)

done = client.v2.get_perceive_batch(batch.job_id)
print(done.status, done.completed, done.failed, done.pending)
for item in done.items:
    print(item.url, item.render_quality)

output_mode vaut "manifest" (défaut) ou "zip" ; quand il vaut "zip", le bundle terminé se trouve sur done.zip.url. Détails dans Perceive.

Discover#

Énumérez les URL d'un site sans aucun rendu navigateur, ce qui en fait la première étape peu coûteuse avant de percevoir quoi que ce soit.

found = client.v2.discover(
    "https://example.com", mode="hybrid", max_urls=200, exclude_patterns=["/tag/"]
)
print(found.total, found.truncated, found.sources)
Option Type Défaut Description
mode "sitemap" \| "crawl" \| "hybrid" défaut serveur Analyse du sitemap, crawl HTTP, ou les deux fusionnés et dédupliqués.
max_urls / max_depth int défaut serveur Plafond d'URL renvoyées (truncated vaut True s'il en existait davantage), et profondeur de crawl depuis l'URL de départ.
same_domain_only bool défaut serveur Reste sur l'hôte de départ.
respect_robots bool défaut serveur Respecte robots.txt.

include_patterns et exclude_patterns (tous deux list[str]) filtrent l'ensemble de résultats. DiscoverResult.sources contient les décomptes bruts par source avant déduplication, par exemple {"sitemap": 42, "crawl": 30}. Pour aller plus loin : Discover.

Lookup#

Lancez une recherche web catégorisée, en rendant éventuellement les meilleurs résultats dans le même appel.

search = client.v2.lookup(
    "best static site generators", category="web", num_results=10, perceive_top=3
)

for hit in search.results:
    quality = hit.perceive.render_quality if hit.perceive else None
    print(hit.position, hit.title, hit.url, quality)
Option Type Défaut Description
category "web" \| "news" \| "images" \| "scholar" \| "patents" \| "maps" défaut serveur Verticale de recherche.
time_filter "hour" \| "day" \| "week" \| "month" \| "year" -- Fenêtre de fraîcheur.
num_results / page int défaut serveur Résultats par page, et numéro de page en base 1.
perceive_top int 0 Rend automatiquement les N premières URL de résultats. Chacune arrive avec son PerceiveResult complet sur hit.perceive.

Également acceptés : country (str), locale (str), location (str) pour les requêtes sensibles à la géographie, et autocorrect (bool). LookupResult porte answer_box, knowledge_graph, perceive_operation_ids et perceive_top, ce dernier indiquant combien de résultats ont réellement été rendus, ce qui peut être inférieur à ce que vous avez demandé. Référence dans Lookup.

Distill#

Extraction structurée pilotée par schéma sur une ou plusieurs pages. Fournissez exactement l'un de urls ou discover_from ; schema est toujours obligatoire. Les deux règles sont appliquées côté client et lèvent EnconvertError avant qu'une requête ne parte.

from enconvert import CssField, CssSchema

extraction = client.v2.distill(
    urls=["https://example.com/pricing"],
    schema={"plans": "list of plan names with monthly prices"},
    css_schema=CssSchema(
        base_selector=".plan-card",
        fields=[
            CssField(name="name", type="text", selector="h3"),
            CssField(name="price", type="text", selector=".price"),
        ],
        target_field="plans",
    ),
)

for item in extraction.results:
    print(item.url, item.extraction_tier, item.fields_from_css, item.fields_from_llm, item.data)

Le css_schema facultatif s'exécute en premier et répond à tout ce que les sélecteurs peuvent atteindre. Seuls les champs qu'il manque escaladent vers le niveau modèle de langage, et extraction_tier sur chaque élément indique quel chemin a été emprunté : css, llm, mixed ou none.

Découvrir et extraire en un seul appel :

from enconvert import DistillDiscoverFrom

client.v2.distill(
    discover_from=DistillDiscoverFrom(url="https://example.com", mode="sitemap", max_pages=10),
    schema={"title": "page title"},
)
Option Type Défaut Description
schema dict -- (obligatoire) Forme de sortie que vous voulez récupérer, transmise intacte.
urls list[str] -- Liste de pages explicite. Mutuellement exclusive avec discover_from.
discover_from DistillDiscoverFrom -- url, mode facultatif, max_pages facultatif (de 1 à 50, défaut 10).
css_schema CssSchema -- Passe de sélecteurs exécutée avant tout appel au modèle.

Également acceptés : wait_for (str), wait_timeout_ms (int), headers (dict[str, str]), cookies (list[BrowserCookie]) et respect_robots (bool). CssField prend en charge les types text, attribute, html, regex, nested, list et nested_list, avec les options attribute, pattern, default, transform (lowercase, uppercase, strip) et des fields imbriqués jusqu'à cinq niveaux de profondeur. Voir Distill.

Ingest#

Transformez un site entier, une liste d'URL explicite, ou un lot de documents téléversés en JSONL découpé et prêt pour le RAG. Ingest est toujours asynchrone.

import time

from enconvert import IngestChunkOptions

job = client.v2.ingest(
    mode="sitemap",
    url="https://docs.example.com",
    max_pages=100,
    chunk=IngestChunkOptions(max_words=512, sentence_overlap=1),
    webhook_url="https://my.app/hooks/enconvert",
)

status = client.v2.get_ingest_job(job.job_id)
while status.status in ("queued", "discovering", "processing"):
    time.sleep(10)
    status = client.v2.get_ingest_job(job.job_id)

print(status.status, status.pages_processed, status.total_chunks, status.output_url)

Les fichiers téléversés suivent le même cycle de vie de tâche sous le mode files. PDF, DOCX, PPTX, XLSX, CSV, HTML, EPUB, TXT et MD, ainsi que les formats bureautiques anciens et ODF sont acceptés, et chaque entrée peut être un chemin, un os.PathLike, des bytes bruts ou un FileData.

file_job = client.v2.ingest_files(["handbook.pdf", "notes.docx"])
Option Type Défaut Description
mode "urls" \| "sitemap" \| "crawl" \| "files" "urls" urls a besoin d'une liste urls non vide et rejette url. Tous les autres modes ont besoin d'une url de départ et rejettent urls.
url / urls str / list[str] -- URL de départ pour sitemap et crawl, ou la liste de pages explicite pour le mode urls.
max_pages int défaut serveur Plafond de pages ingérées.
chunk IngestChunkOptions -- max_words de 32 à 4000, défaut 512. sentence_overlap de 0 à 10, défaut 1. Associez-le à webhook_url (str), appelé dès que la tâche atteint un état terminal.

Les options de forme de crawl et de rendu sont acceptées elles aussi : max_depth, same_domain_only, include_patterns, exclude_patterns, respect_robots, wait_for et wait_timeout_ms. ingest_files ne prend que chunk et webhook_url.

for summary in client.v2.list_ingest_jobs(limit=20).jobs:
    print(summary.job_id, summary.status, summary.total_chunks)

client.v2.cancel_ingest_job(job.job_id)
client.v2.retry_ingest_webhook(job.job_id)

secret = client.v2.get_webhook_secret()
print(secret.signature_header, secret.signature_scheme, secret.replay_tolerance_seconds)
client.v2.rotate_webhook_secret()

cancel_ingest_job est idempotent ; annuler une tâche déjà terminale la renvoie inchangée. retry_ingest_webhook répond 409 quand la tâche n'est pas terminée et 400 quand aucun webhook n'était configuré. rotate_webhook_secret invalide immédiatement le secret précédent. Couverture plus approfondie dans Ingest.

Watch#

Refaites le rendu d'une URL à une cadence fixe et faites-vous prévenir quand elle change.

watcher = client.v2.create_watcher(
    "https://example.com/pricing",
    frequency_minutes=60,
    diff_mode="auto",
    webhook_url="https://my.app/hooks/changes",
    notify_email=True,
)

for snap in client.v2.get_watcher_snapshots(watcher.watcher_id, limit=10).snapshots:
    print(snap.checked_at, snap.has_changes, snap.similarity, snap.change_count)

client.v2.list_watchers(limit=20)
client.v2.update_watcher(watcher.watcher_id, status="paused")
client.v2.update_watcher(watcher.watcher_id, webhook_url="")
client.v2.delete_watcher(watcher.watcher_id)
Option Type Défaut Description
frequency_minutes int défaut serveur Intervalle entre deux vérifications. L'heure est le plancher.
diff_mode "auto" \| "text" \| "structured" \| "tables" \| "metadata" défaut serveur Quelle couche de la page le moteur de diff compare.
track_fields dict -- Champs nommés à suivre, transmis intacts.
webhook_url str -- Appelé à chaque changement détecté.
notify_email bool défaut serveur Envoie les notifications de changement par e-mail.

update_watcher a besoin d'au moins un champ et lève EnconvertError sinon ; status accepte "active" ou "paused", et un webhook_url vide efface le webhook. delete_watcher est une suppression douce et idempotente qui renvoie l'observateur marqué supprimé avec le statut "deleted", après quoi l'observateur répond 404.

Les diffs d'instantanés portent du contenu de page non fiable. Les dicts de WatcherSnapshot.changes viennent directement du site surveillé. Échappez-les avant de les afficher en HTML, dans un corps d'e-mail ou dans un message de chat.

Le moteur de diff et les charges utiles de notification sont documentés dans Watch.


Options PDF#

PdfOptions est une dataclass figée partagée par convert_url_to_pdf, convert_website_to_pdf, convert_document, convert_to_pdf et la famille v2.perceive.

from enconvert import BrowserCookie, HttpBasicAuth, PdfHeaderFooter, PdfMargins, PdfOptions

client.convert_url_to_pdf(
    "https://internal.example.com/report",
    pdf_options=PdfOptions(
        page_size="A4",
        orientation="landscape",
        margins=PdfMargins(top=10, bottom=10, left=15, right=15),
        scale=0.9,
        header=PdfHeaderFooter(content="Quarterly Report", height=15),
        footer=PdfHeaderFooter(content="Confidential", height=12),
    ),
    auth=HttpBasicAuth(username="user", password="pass"),
    cookies=[BrowserCookie(name="session", value="abc123", domain="internal.example.com")],
    save_to="report.pdf",
)
Champ Type Description
page_size str "A4", "A3", "Letter", "Legal", et compagnie.
page_width / page_height float Géométrie de page personnalisée. Ensemble, ils remplacent page_size.
orientation "portrait" \| "landscape" Portrait par défaut.
margins PdfMargins top, bottom, left, right, tous facultatifs.
scale float Échelle de rendu, par exemple 0.9 pour 90 pour cent.
grayscale bool Post-traite le PDF en niveaux de gris.
header PdfHeaderFooter content (jusqu'à 2000 caractères) et height.
footer PdfHeaderFooter content (jusqu'à 2000 caractères) et height.

BrowserCookie prend name, value, et soit domain, soit url, plus les champs facultatifs path, expires, http_only, secure et same_site ("Strict", "Lax", "None"). Le SDK mappe http_only et same_site sur leurs clés camelCase de transport pour vous.


Gestion des erreurs#

Les erreurs sont des classes d'exception : attrapez-les donc avec except. Ordonnez les gestionnaires du spécifique au général : AuthenticationError, QuotaError et RateLimitError héritent tous de APIError, qui hérite de EnconvertError.

from enconvert import APIError, AuthenticationError, EnconvertError, QuotaError, RateLimitError

try:
    op = client.v2.perceive("https://example.com")
except AuthenticationError:
    print("Invalid or missing API key. Check ENCONVERT_API_KEY.")
except QuotaError as e:
    print(f"402 from the API: {e.message}")
except RateLimitError:
    print("Too many requests. Back off and retry.")
except APIError as e:
    print(f"API error [{e.status_code}]: {e.message}")
except EnconvertError as e:
    print(f"Rejected before the request was sent: {e}")
Classe Levée sur Code de statut
AuthenticationError Clé invalide, manquante ou révoquée 401, 403
QuotaError HTTP 402 402
RateLimitError Trop de requêtes 429
APIError Toute autre 4xx ou 5xx le code réel
EnconvertError Classe de base, et validation côté client qui n'atteint jamais le réseau --

APIError porte status_code et message, et son str() se lit [404] Not found. Les levées côté client que vous pouvez rencontrer : une api_key vide, une extension de fichier non prise en charge, une paire de conversion non implémentée, un appel distill avec les deux ou aucun de urls et discover_from, une incohérence entre le mode et les arguments d'ingest, une charge utile update_watcher vide, et une liste de sorties perceive_direct qui ne se résout pas à exactement un artefact. La table complète des messages se trouve dans Codes d'erreur.


Récupération après timeout#

Les conversions longues d'URL et de documents peuvent survivre à un timeout du reverse proxy même quand le serveur termine la tâche. Le SDK Python récupère de façon transparente :

  1. Avant chaque conversion de fichier unique ou d'URL unique, le SDK génère une chaîne hexadécimale UUID4 et l'envoie comme job_id.
  2. Si cette requête revient en 5xx, le SDK bascule sur l'interrogation de GET /v1/convert/status/{job_id} toutes les 3 secondes. Un 404 à cet endroit signifie que la ligne de la tâche n'est pas encore écrite, donc l'interrogation continue.
  3. Sur success le SDK renvoie le résultat comme si de rien n'était ; sur failed il lève APIError(500, ...) avec le message d'erreur du serveur ; et passé l'échéance d'interrogation de 300 secondes, il lève APIError(504, "Conversion timed out").

Vous n'écrivez aucun code pour cela. Quand une réponse arrive par le chemin de récupération, ConversionResult.job_id est renseigné pour que vous puissiez la corréler dans vos logs.

Deux exceptions. convert_website_to_pdf et convert_website_to_screenshot se retirent de ce mécanisme, parce qu'une soumission de site n'a pas de ligne de tâche propre : une 5xx signifie donc que la soumission elle-même a échoué et remonte directement. Les endpoints V2 ne sont pas interrogés non plus ; utilisez leurs propres identifiants de tâche avec get_perceive_batch ou get_ingest_job.


Configuration#

client = Enconvert(
    api_key=os.environ["ENCONVERT_API_KEY"], timeout=300.0, base_url="https://api.enconvert.com"
)
Option Type Défaut Description
api_key str -- (obligatoire) Clé API privée. Une valeur vide lève EnconvertError à la construction.
timeout float 300.0 Timeout par requête en secondes, appliqué à chaque appel, téléversements compris.
base_url str https://api.enconvert.com URL de base de l'API. Les barres obliques finales sont supprimées.

Le client conserve une requests.Session : les connexions sont donc mutualisées entre les appels ; réutilisez un seul client au lieu d'en construire un par requête. Votre clé voyage dans l'en-tête X-API-Key, et les téléchargements save_to attaquent l'URL de stockage signée par un simple GET non authentifié écrit sur le disque par blocs de 64 Ko : la clé ne quitte donc jamais l'hôte de l'API.

N'écrivez jamais la clé API en dur. Lisez-la depuis une variable d'environnement ou votre gestionnaire de secrets, et gardez-la côté serveur. Quiconque détient votre clé privée peut lancer des traitements sur votre projet.

Forme du résultat#

Les méthodes de conversion renvoient un ConversionResult figé :

@dataclass(frozen=True)
class ConversionResult:
    presigned_url: str
    object_key: str
    filename: str
    file_size: int | None = None
    conversion_time_seconds: float | None = None
    job_id: str | None = None

L'URL pré-signée est de courte durée de vie. Passez save_to, ou récupérez l'URL vous-même, et stockez les octets dans votre propre bucket quand vous avez besoin d'un accès durable.

Type Renvoyé par Champs clés
JobStatus get_job_status status (processing, success, failed), presigned_url, object_key, error
BatchSubmission, BatchStatus convert_website_to_*, get_batch_status, wait_for_batch batch_id, status, url_count, total, completed, failed, discovery_method, zip_download_url, items
PerceiveResult v2.perceive, v2.get_perceive_operation operation_id, render_quality, status_code, deductions, outputs, structured, warnings, cache_hit
PerceiveDirectResult v2.perceive_direct, v2.download_perceive_artifact content (octets bruts), content_type, filename, render_quality, source_status_code
IngestJob v2.ingest, v2.ingest_files, v2.get_ingest_job job_id, status, mode, pages_processed, total_chunks, output_url, error_message
Watcher les méthodes watch de v2 watcher_id, status, frequency_minutes, diff_mode, checks_count, next_check_at, last_change_at

Les URL d'artefacts V2 sont signées pour 15 minutes et resignées à chaque lecture de l'opération : appelez donc get_perceive_operation plutôt que de mettre une chaîne d'URL en cache.


Source et tickets#


Questions fréquentes#

Comment convertir des fichiers en Python ?#

Lancez pip install enconvert, construisez un client avec Enconvert(api_key=os.environ["ENCONVERT_API_KEY"]), et appelez une méthode typée comme convert_document, convert_image, convert_to_pdf ou convert_to_markdown. Passez save_to="out.pdf" et le SDK écrit le fichier terminé en flux directement sur le disque, au lieu de vous remettre une URL à aller chercher vous-même.

Comment convertir une URL en PDF en Python ?#

Appelez client.convert_url_to_pdf("https://example.com", save_to="page.pdf"). Définissez single_page=False plus pdf_options=PdfOptions(page_size="A4") pour une sortie paginée, et ajustez viewport_width, load_media ou enable_scroll quand une page a besoin d'un canevas plus large ou d'images chargées en différé.

Comment convertir du DOCX en PDF en Python ?#

Soit client.convert_document("report.docx", save_to="report.pdf"), puisque output_format vaut déjà "pdf" par défaut, soit client.convert_to_pdf("report.docx", save_to="report.pdf") quand vous voulez la détection automatique du format côté serveur. Le même appel gère XLSX, PPTX, ODT, ODS, ODP, OTS, Pages et Numbers.

Comment convertir du HEIC en WebP en Python ?#

client.convert_image("photo.heic", output_format="webp", save_to="photo.webp"). Le format d'entrée vient de l'extension du nom de fichier, et jpeg, png, svg, heic et webp se convertissent tous les uns vers les autres. Vous travaillez en mémoire plutôt que sur disque ? Enveloppez les octets dans FileData(data=blob, filename="photo.heic") pour que l'extension survive.

Comment récupérer une page web en Markdown propre avec Python ?#

Utilisez client.v2.perceive(url, outputs=["markdown"]) et lisez op.outputs["markdown"].url, ou client.v2.perceive_direct(url, outputs=["markdown"]) pour récupérer les octets dans le corps de la réponse. Ajoutez only_main_content=True pour écarter la navigation et les pieds de page. Pour une conversion simple, sans scoring ni extraction, convert_url_to_markdown est l'appel le plus léger.

Que signifie render_quality, et quand faut-il réessayer une page ?#

C'est un flottant de 0.0 à 1.0 sur chaque lecture V2 qui dit avec quelle honnêteté la page s'est rendue. Un écran de défi, un mur de cookies, une porte de connexion, une page d'erreur HTTP ou une coquille vide d'application monopage obtiennent un score bas et nomment ce qui s'est déclenché dans deductions, avec le détail dans warnings et le statut HTTP propre à la page dans status_code. Servez-vous-en comme d'une porte : traitez un score bas comme un signal pour réessayer avec cache_mode="refresh", un sélecteur wait_for que seul le vrai contenu satisfait, ou des cookies différents, plutôt que de donner le texte à votre modèle.

Comment transformer un site de documentation entier en chunks RAG avec Python ?#

Appelez client.v2.ingest(mode="sitemap", url="https://docs.example.com", max_pages=100, chunk=IngestChunkOptions(max_words=512, sentence_overlap=1)). La tâche est asynchrone : interrogez donc get_ingest_job(job_id) jusqu'à ce que le statut quitte queued, discovering et processing, ou passez webhook_url et attendez d'être appelé. Le JSONL terminé se trouve à output_url. Pour des documents locaux plutôt qu'un site, ingest_files exécute le même pipeline.

Le SDK Python prend-il en charge asyncio ?#

Pas nativement. Toutes les méthodes sont synchrones et construites sur requests. Dans une application asynchrone, enveloppez les appels dans await asyncio.to_thread(client.convert_to_pdf, "report.docx") ou confiez-les à un concurrent.futures.ThreadPoolExecutor pour que la boucle d'événements continue de tourner. Le client peut être partagé entre threads sans risque, car il détient une requests.Session mutualisée.

Comment le SDK survit-il à un timeout de proxy sur une conversion longue ?#

Chaque conversion de fichier unique et d'URL unique envoie un job_id généré. Si la requête renvoie une 5xx, le SDK interroge GET /v1/convert/status/{job_id} toutes les 3 secondes pendant un maximum de 300 secondes, renvoie normalement dès que la tâche rapporte success, lève APIError(500, ...) si elle rapporte failed, et lève APIError(504, "Conversion timed out") si l'échéance est dépassée. Les soumissions de lots de sites sautent ce chemin, puisqu'un échec à cet endroit signifie que la soumission elle-même n'a pas abouti.