SDK Java per la Conversione dei File#
com.enconvert:enconvert-sdk è il client Java ufficiale per l'API EnConvert. Una sola dipendenza Maven o Gradle ti dà la conversione dei file (da URL a PDF, da DOCX a PDF, da HEIC a WebP, qualsiasi file in Markdown) più la superficie di web intelligence V2: perceive, discover, lookup, distill, ingest e watch. Richiede Java 17 o versioni successive, funziona sul java.net.http.HttpClient incluso nel JDK e porta con sé Gson come unica dipendenza di terze parti. Ogni chiamata è un semplice metodo bloccante che restituisce un record tipizzato, e le conversioni lunghe recuperano in modo trasparente dai timeout del reverse proxy effettuando il polling dello stato del job.
com.enconvert:enconvert-sdk:0.0.1 · Sorgente: conversionapi/java-sdk · Java: 17+ · Dipendenze: solo Gson
Installazione#
// build.gradle
dependencies {
implementation 'com.enconvert:enconvert-sdk:0.0.1'
}
// build.gradle.kts
dependencies {
implementation("com.enconvert:enconvert-sdk:0.0.1")
}
<!-- pom.xml -->
<dependency>
<groupId>com.enconvert</groupId>
<artifactId>enconvert-sdk</artifactId>
<version>0.0.1</version>
</dependency>
L'HTTP è gestito da java.net.http.HttpClient del JDK. L'unico artefatto di terze parti che viene incluso è Gson per il JSON, dichiarato come dipendenza api in modo che sia visibile sul tuo classpath di compilazione.
Avvio rapido#
import com.enconvert.Enconvert;
import com.enconvert.model.ConversionResult;
import com.enconvert.model.UrlToPdfOptions;
import com.enconvert.model.v2.PerceiveOptions;
import com.enconvert.model.v2.PerceiveResult;
import java.util.List;
Enconvert client = new Enconvert(System.getenv("ENCONVERT_API_KEY"));
ConversionResult pdf = client.convertUrlToPdf("https://example.com",
UrlToPdfOptions.builder().saveTo("page.pdf").build());
System.out.println(pdf.presignedUrl());
// Leggi una pagina come dovrebbe fare il tuo agente, con un punteggio di qualità allegato.
PerceiveResult page = client.v2.perceive("https://example.com",
PerceiveOptions.builder().outputs(List.of("markdown", "structured")).build());
System.out.println(page.outputs().get("markdown").url());
System.out.println(page.renderQuality()); // ad es. 0.93
Ogni classe di opzioni è un builder immutabile e ogni risposta è un record Java, quindi gli accessori si leggono come pdf.presignedUrl() e page.renderQuality(). Il client mantiene un unico HttpClient condiviso e nessuno stato mutabile per richiesta, quindi una singola istanza può essere un singleton oppure un bean Spring condiviso tra i thread. Gli snippet qui sotto omettono gli import: le classi di opzioni e i tipi di risposta stanno in com.enconvert.model (conversione) e com.enconvert.model.v2 (web intelligence), le eccezioni in com.enconvert.exceptions.
Cosa espone il client#
Enconvert porta direttamente la superficie di conversione. La superficie di web intelligence vive sul campo pubblico final client.v2, un'istanza di EnconvertV2.
| Gruppo | Metodi | Restituisce |
|---|---|---|
| URL singolo | convertUrlToPdf, convertUrlToScreenshot, convertUrlToMarkdown |
ConversionResult |
| Upload di file | convertImage, convertDocument, convertToMarkdown, convertToPdf |
ConversionResult |
| Intero sito | convertWebsiteToPdf, convertWebsiteToScreenshot |
BatchSubmission |
| Stato | getJobStatus, getBatchStatus, waitForBatch |
JobStatus, BatchStatus |
v2 perceive |
perceive, perceiveDirect, getPerceiveOperation, perceiveBatch, getPerceiveBatch, downloadPerceiveArtifact |
PerceiveResult, PerceiveDirectResult, PerceiveBatchResult |
v2 discover |
discover |
DiscoverResult |
v2 lookup |
lookup |
LookupResult |
v2 distill |
distill |
DistillResult |
v2 ingest |
ingest, ingestFiles, getIngestJob, listIngestJobs, cancelIngestJob, retryIngestWebhook, getWebhookSecret, rotateWebhookSecret |
IngestJob, IngestJobList, WebhookRetryResult, WebhookSecret |
v2 watch |
createWatcher, getWatcher, listWatchers, getWatcherSnapshots, updateWatcher, deleteWatcher |
Watcher, WatcherList, WatcherSnapshotList |
La maggior parte dei metodi ha un overload breve senza argomento di opzioni, quindi sia client.v2.perceive(url) sia client.convertUrlToPdf(url) compilano. convertImage, distill e ingest sono le eccezioni: ognuno richiede sempre il proprio oggetto di opzioni, perché servono rispettivamente il formato di destinazione, lo schema e la sorgente.
Conversione dei file#
Gli endpoint di conversione coprono 43 coppie {input}-to-{output} implementate, due endpoint con rilevamento automatico (anything-to-markdown e anything-to-pdf) e gli endpoint di rendering nel browser. Il riferimento completo dei parametri si trova in Parametri e opzioni.
convertUrlToPdf#
Esegue il rendering di qualsiasi URL pubblico in PDF.
ConversionResult result = client.convertUrlToPdf("https://example.com",
UrlToPdfOptions.builder()
.pdfOptions(PdfOptions.builder().pageSize("A4").orientation("landscape").build())
.singlePage(false)
.viewportWidth(1440)
.saveTo("report.pdf")
.build());
| Opzione | Tipo | Predefinito | Descrizione |
|---|---|---|---|
saveTo |
String |
nessuno | Percorso locale su cui scrivere il PDF. Le directory padre vengono create automaticamente. |
singlePage |
boolean |
true |
true produce una singola pagina continua. false pagina utilizzando pdfOptions.pageSize. |
pdfOptions |
PdfOptions |
nessuno | Dimensione pagina, orientamento, margini, scala, scala di grigi, intestazione, piè di pagina. Vedi Opzioni PDF. |
viewportWidth |
int |
1920 |
Larghezza del viewport del browser in pixel. |
viewportHeight |
int |
1080 |
Altezza del viewport del browser in pixel. |
loadMedia, enableScroll |
boolean |
true |
Attende immagini e video prima della cattura, e scorre dall'alto verso il basso per attivare i caricamenti lazy. |
outputFilename |
String |
auto | Sovrascrive il nome file generato. |
auth, cookies, headers |
HttpBasicAuth, List<BrowserCookie>, Map<String, String> |
nessuno | Credenziali, cookie iniettati e header di richiesta aggiuntivi per pagine protette da login. |
convertUrlToScreenshot#
Cattura un PNG di qualsiasi URL. Le stesse opzioni di viewport, media, scroll, nome file, auth, cookie e header di convertUrlToPdf, meno singlePage e pdfOptions.
client.convertUrlToScreenshot("https://example.com",
UrlToScreenshotOptions.builder().viewportWidth(1440).saveTo("screenshot.png").build());
convertUrlToMarkdown#
Estrae Markdown pulito in stile GitHub Flavored da un URL. Navigazione, footer, pubblicità e script vengono rimossi, il corpo principale dell'articolo viene mantenuto e viene anteposto un frontmatter YAML (titolo, descrizione, url, link, immagini). Stesso insieme di opzioni di convertUrlToScreenshot.
client.convertUrlToMarkdown("https://example.com/article",
UrlToMarkdownOptions.builder().saveTo("article.md").build());
convertImage#
Converte tra jpeg, png, svg, heic e webp, oppure rasterizza un PDF in JPEG.
// Da un percorso su disco
client.convertImage(Path.of("photo.heic"),
ConvertImageOptions.builder("webp").saveTo("photo.webp").build());
// Rasterizza un PDF
client.convertImage(Path.of("scan.pdf"),
ConvertImageOptions.builder("jpeg").saveTo("scan.jpeg").build());
// Da byte in memoria con un nome file esplicito
byte[] bytes = Files.readAllBytes(Path.of("photo.heic"));
client.convertImage(new FileInput(bytes, "photo.heic"),
ConvertImageOptions.builder("webp").build());
Su ogni metodo che accetta file esistono tre overload di input: java.nio.file.Path (lettura da disco), byte[] grezzi (il nome file diventa upload.bin) e com.enconvert.FileInput quando devi abbinare byte in memoria a un nome file reale. Il formato di input viene ricavato dall'estensione; il formato di output è obbligatorio.
| Opzione | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
outputFormat |
String |
Sì | Passato a ConvertImageOptions.builder(outputFormat). Uno tra jpeg, png, svg, heic, webp. Gli alias come jpg vengono normalizzati. |
saveTo |
String |
no | Percorso locale su cui scrivere il risultato. |
outputFilename |
String |
no | Sovrascrive il nome file generato. |
convertDocument#
Converte documenti e formati di dati strutturati. Il formato di output predefinito è pdf.
// da docx a pdf
client.convertDocument(Path.of("report.docx"),
ConvertDocumentOptions.builder().saveTo("report.pdf").build());
// da json a yaml
client.convertDocument(Path.of("data.json"),
ConvertDocumentOptions.builder().outputFormat("yaml").saveTo("data.yaml").build());
// da markdown a pdf con impostazioni di pagina
client.convertDocument(Path.of("README.md"),
ConvertDocumentOptions.builder()
.outputFormat("pdf")
.pdfOptions(PdfOptions.builder()
.pageSize("A4")
.margins(new PdfMargins(20.0, 20.0, 25.0, 25.0))
.build())
.saveTo("readme.pdf")
.build());
Estensioni di input riconosciute: .doc, .docx, .xls, .xlsx, .ppt, .pptx, .html, .htm, .odt, .ods, .odp, .ots, .pages, .numbers, .md, .markdown, .csv, .json, .xml, .yaml, .yml, .toml.
EPUB non ha una coppia documentale dedicata. Invia invece i file .epub a convertToPdf oppure a convertToMarkdown.
| Opzione | Tipo | Predefinito | Descrizione |
|---|---|---|---|
outputFormat |
String |
"pdf" |
Formato di destinazione. |
saveTo |
String |
nessuno | Percorso locale su cui scrivere il risultato. |
outputFilename |
String |
nessuno | Sovrascrive il nome file generato. |
pdfOptions |
PdfOptions |
nessuno | Impostazioni di pagina, rispettate quando l'output è PDF. |
Conversioni supportate#
convertImage e convertDocument validano la coppia {input}-to-{output} rispetto agli endpoint che l'API implementa davvero. Una coppia non supportata genera subito IllegalArgumentException, elencando gli output validi per quell'input, invece di pagare un round trip per una richiesta che non può riuscire.
| Input | Output |
|---|---|
json |
csv, toml, xml, yaml |
xml |
csv, json |
yaml |
json |
csv |
json, xml |
toml |
json |
markdown |
html, pdf |
html |
pdf |
doc, excel, ppt, odt, ods, odp, ots, pages, numbers |
pdf |
jpeg, png, svg, heic, webp |
tra loro, tutte le 20 coppie |
pdf |
jpeg |
La stessa tabella è interrogabile a runtime tramite com.enconvert.Formats: Formats.validOutputsFor("json") restituisce [csv, toml, xml, yaml], Formats.validOutputsFor("pdf") restituisce [jpeg] e Formats.IMPLEMENTED_CONVERSIONS contiene tutti i 43 nomi di endpoint.
convertToMarkdown#
Invia qualsiasi documento supportato a un unico endpoint con rilevamento automatico e ottieni Markdown pulito. La gerarchia delle intestazioni sopravvive, il che rende questo passaggio un primo stadio naturale per una pipeline RAG.
client.convertToMarkdown(Path.of("handbook.docx"),
ConvertToMarkdownOptions.builder().saveTo("handbook.md").build());
Accetta PDF, DOCX, PPTX, XLSX, CSV, HTML, EPUB, TXT e MD, oltre ai formati office legacy e ODF. Il formato viene rilevato lato server, quindi non c'è alcun controllo dell'estensione lato client: qualsiasi file viene caricato così com'è. Le immagini non sono supportate e vengono rifiutate con 400. Le uniche opzioni sono saveTo e outputFilename.
convertToPdf#
L'altro endpoint con rilevamento automatico: quasi qualsiasi cosa in PDF.
// da pptx a pdf
client.convertToPdf(Path.of("slides.pptx"),
ConvertToPdfOptions.builder().saveTo("slides.pdf").build());
// pdf in passthrough, convertito in scala di grigi
client.convertToPdf(Path.of("scan.pdf"),
ConvertToPdfOptions.builder()
.pdfOptions(PdfOptions.builder().grayscale(true).build())
.saveTo("scan-gray.pdf")
.build());
Accetta office, ODF, Pages, Numbers, RTF, CSV, HTML, Markdown, testo semplice, immagini raster, SVG, EPUB e un PDF esistente in passthrough. L'EPUB viene gestito qui perché non ha una coppia documentale dedicata. Le opzioni sono saveTo, outputFilename e pdfOptions.
grayscale. La geometria di pagina (dimensione pagina, larghezza e altezza, orientamento, margini, scala, intestazione, piè di pagina) viene ignorata da anything-to-pdf. Quando ti serve l'impostazione completa della pagina, passa invece da convertDocument oppure convertUrlToPdf.
Conversione di interi siti#
convertWebsiteToPdf e convertWebsiteToScreenshot individuano ogni pagina di un sito, convertono ciascuna in background e raccolgono i risultati in un unico ZIP. Entrambi sono asincroni e restituiscono un BatchSubmission. Entrambi richiedono una chiave API privata.
BatchSubmission batch = client.convertWebsiteToPdf("https://example.com",
WebsiteToPdfOptions.builder()
.crawlMode("sitemap") // "auto" (predefinito), "sitemap", "full"
.excludePatterns(List.of("/blog/tag/")) // solo in modalità full crawl
.notificationEmail("[email protected]")
.build());
System.out.println(batch.batchId() + " " + batch.urlCount() + " " + batch.discoveryMethod());
// Blocca finché il batch non esce da "processing", poi salva lo ZIP
BatchStatus status = client.waitForBatch(batch.batchId(),
WaitForBatchOptions.builder().saveTo("site.zip").build());
System.out.println(status.completed() + " of " + status.total() + " pages converted");
convertWebsiteToScreenshot funziona in modo identico e produce uno ZIP di PNG. waitForBatch esegue il polling ogni 5 secondi per impostazione predefinita, si arrende dopo 30 minuti e accetta intervalMs, timeoutMs e saveTo. In caso di timeout genera ApiException con stato 504.
Eseguire il polling dello stato da soli#
JobStatus job = client.getJobStatus("job_abc123");
if ("success".equals(job.status())) System.out.println(job.presignedUrl());
if ("failed".equals(job.status())) System.err.println(job.error());
BatchStatus batch = client.getBatchStatus("bat_abc123");
if (!"processing".equals(batch.status())) System.out.println(batch.zipDownloadUrl());
Web intelligence (V2)#
Tutto ciò che sta sotto client.v2 trasforma le pagine web in dati pronti per gli agenti. Ogni lettura porta con sé renderQuality, un punteggio da 0.0 a 1.0 che dice quanto pulitamente la pagina è stata effettivamente renderizzata. Una pagina di challenge, un cookie wall o uno shell SPA vuoto tornano con un punteggio basso e con warnings() e deductions() popolati, invece di essere spacciati per contenuto reale, così una lettura difettosa non entra mai silenziosamente nel contesto del tuo agente. Il contenuto viene comunque restituito: viene solo segnalato. Le basi del modello si trovano nella panoramica V2.
Perceive#
Esegue il rendering di un URL negli artefatti che richiedi. Riferimento dell'endpoint: Perceive.
PerceiveResult page = client.v2.perceive("https://example.com",
PerceiveOptions.builder()
.outputs(List.of("markdown", "screenshot", "structured"))
.extract(List.of("tables", "metadata"))
.waitFor("css:main")
.build());
System.out.println(page.renderQuality()); // da 0.0 a 1.0
System.out.println(page.statusCode() + " " + page.deductions()); // ad es. 200 {http_error=0.7}
System.out.println(page.outputs().get("markdown").url()); // URL firmato, 15 minuti
System.out.println(page.structured()); // forma definita dal chiamante
| Opzione | Tipo | Predefinito | Descrizione |
|---|---|---|---|
outputs |
List<String> |
["markdown", "structured"] |
Uno o più tra markdown, html_cleaned, html_raw, screenshot, screenshot_full_page, pdf, links, images, structured. |
extract |
List<String> |
nessuno | Obiettivi euristici: tables, prices, contacts, metadata, main_content, headings, structured_data, technologies, all. |
schema |
Map<String, Object> |
nessuno | Schema JSON per l'estrazione strutturata. |
waitFor, waitTimeoutMs |
String, int |
nessuno, 30000 |
Un selettore CSS, eventualmente con prefisso css:, oppure js:<expr> da attendere, con un budget da 0 a 60000 ms. |
jsCode |
String |
nessuno | JavaScript eseguito dopo la navigazione, massimo 20000 caratteri. |
viewport, mobile |
PerceiveViewport, boolean |
1920 x 1080, false |
Larghezza da 320 a 3840, altezza da 240 a 2160, oppure emulazione mobile. |
onlyMainContent |
boolean |
true |
Rimuove navigazione, header, footer e banner dei cookie dall'artefatto Markdown e dall'estrazione main_content. |
cacheMode |
String |
"enabled" |
enabled riutilizza una cache di 1 ora, bypass la salta, refresh forza un nuovo rendering. |
blockResources |
List<String> |
nessuno | Tipi di risorsa che il browser non deve caricare, per esempio image, font, script. |
pdfOptions |
PdfOptions |
nessuno | Ha effetto solo quando outputs contiene pdf. |
headers, cookies, auth |
Map, List<BrowserCookie>, HttpBasicAuth |
nessuno | Header di richiesta, cookie iniettati, credenziali HTTP Basic. |
respectRobots |
boolean |
nessuno | Rispetta le regole robots del sito. |
proxyUrl, geolocation e actionChain esistono sul builder ma non sono disponibili lato server e attualmente vengono rifiutati con 422.
Gli URL degli artefatti sono firmati per 15 minuti e vengono rifirmati a ogni lettura dell'operazione, quindi client.v2.getPerceiveOperation(page.operationId()) ti consegna link freschi. Puoi raggruppare fino a 1000 URL con un unico blocco di opzioni condiviso: i batch piccoli si completano inline, quelli più grandi tornano con stato queued, quindi vanno interrogati con il polling.
PerceiveBatchResult batch = client.v2.perceiveBatch(
List.of("https://a.example.com", "https://b.example.com"),
PerceiveBatchOptions.builder()
.outputs(List.of("markdown"))
.outputMode("zip") // "manifest" (predefinito) oppure "zip"
.build());
PerceiveBatchResult done = client.v2.getPerceiveBatch(batch.jobId());
System.out.println(done.completed() + "/" + done.total());
Salta del tutto il round trip dell'URL firmato con perceiveDirect, che restituisce in streaming i byte dell'artefatto. Richiede esattamente un output che produca artefatti (qualsiasi cosa tranne structured) e genera IllegalArgumentException prima dell'invio se ne chiedi di più o di meno:
PerceiveDirectResult direct = client.v2.perceiveDirect("https://example.com",
PerceiveOptions.builder().outputs(List.of("pdf")).build());
Files.write(Path.of(direct.filename()), direct.content());
System.out.println(direct.renderQuality() + " " + direct.contentType());
// Riscarica un artefatto archiviato di un'operazione precedente
PerceiveDirectResult stored = client.v2.downloadPerceiveArtifact(page.operationId(), "markdown");
downloadPerceiveArtifact accetta un nome di output null oppure omesso quando l'operazione ha prodotto esattamente un artefatto, altrimenti restituisce 400 elencando gli output disponibili. Una volta che l'artefatto archiviato è scaduto, restituisce 410.
Discover#
Enumera gli URL di un sito senza renderizzare nulla. Non è coinvolto alcun browser, quindi è veloce. Riferimento dell'endpoint: Discover.
DiscoverResult found = client.v2.discover("https://example.com",
DiscoverOptions.builder()
.mode("hybrid") // "sitemap", "crawl", "hybrid"
.maxUrls(200)
.maxDepth(3)
.excludePatterns(List.of("/tag/"))
.build());
System.out.println(found.total() + " urls, truncated=" + found.truncated());
found.urls().forEach(System.out::println);
| Opzione | Tipo | Predefinito | Intervallo |
|---|---|---|---|
mode |
String |
"hybrid" |
sitemap, crawl, hybrid |
maxUrls |
int |
100 |
da 1 a 1000 |
maxDepth |
int |
2 |
da 1 a 5 |
includePatterns, excludePatterns |
List<String> |
nessuno | Allowlist e denylist regex, massimo 50 ciascuna. La denylist viene applicata per seconda. |
sameDomainOnly, respectRobots |
boolean |
true, nessuno |
Resta sul dominio seed, e rispetta le regole robots del sito. |
Lookup#
Ricerca web categorizzata, con rendering automatico opzionale dei risultati migliori. Riferimento dell'endpoint: Lookup.
LookupResult search = client.v2.lookup("best static site generators",
LookupOptions.builder()
.category("web") // web, news, images, scholar, patents, maps
.numResults(10)
.country("us")
.timeFilter("month") // hour, day, week, month, year
.perceiveTop(3) // renderizza automaticamente i 3 risultati migliori
.build());
search.results().forEach(hit -> {
System.out.println(hit.position() + " " + hit.title() + " " + hit.url());
if (hit.perceive() != null) System.out.println(" quality " + hit.perceive().renderQuality());
});
Con perceiveTop maggiore di 0 (da 0 a 10, predefinito 0), gli URL dei primi N risultati vengono renderizzati tramite perceive e ogni risultato porta inline il suo PerceiveResult completo su hit.perceive(). numResults va da 1 a 100 e vale 10 per impostazione predefinita; page va da 1 a 10.
Distill#
Estrazione strutturata guidata da schema su una o più pagine. Riferimento dell'endpoint: Distill.
DistillResult extraction = client.v2.distill(
DistillOptions.builder(Map.of("products", "list of product names with their listed price"))
.urls(List.of("https://example.com/catalog"))
.cssSchema(CssSchema.builder(".product-card", List.of(
CssField.builder("name", "text").selector("h3").build(),
CssField.builder("price", "text").selector(".price").build()))
.targetField("products")
.build())
.build());
extraction.results().forEach(item ->
System.out.println(item.data() + " via " + item.extractionTier()));
Il cssSchema opzionale esegue prima un passaggio CSS gratuito; solo i campi a cui non riesce a rispondere passano al livello LLM, e item.extractionTier() riporta quale percorso ha prodotto il record (css, llm, mixed oppure none). Puoi anche individuare prima gli URL invece di elencarli:
client.v2.distill(
DistillOptions.builder(Map.of("title", "page title", "summary", "one-line summary"))
.discoverFrom(new DistillDiscoverFrom("https://example.com", "sitemap", 10))
.build());
Esattamente uno tra urls (massimo 50) e discoverFrom deve essere impostato, e schema è richiesto dalla factory del builder. Entrambe le regole vengono verificate lato client e generano IllegalArgumentException prima che parta qualsiasi richiesta.
Ingest#
Trasforma un intero sito, o un insieme di documenti caricati, in JSONL suddiviso in chunk e pronto per il RAG attraverso un'unica pipeline. Ingest è sempre asincrono. Riferimento dell'endpoint: Ingest.
// Da un sito
IngestJob job = client.v2.ingest(IngestOptions.builder()
.mode("sitemap") // "urls" (predefinito), "sitemap", "crawl"
.url("https://docs.example.com")
.maxPages(100)
.chunk(new IngestChunkOptions(512, 1)) // maxWords, sentenceOverlap
.webhookUrl("https://my.app/hooks/enconvert")
.build());
// Oppure da file caricati
IngestJob fileJob = client.v2.ingestFiles(
List.of(new FileInput(Files.readAllBytes(Path.of("handbook.pdf")), "handbook.pdf"),
new FileInput(Files.readAllBytes(Path.of("notes.docx")), "notes.docx")),
IngestFilesOptions.builder().chunk(new IngestChunkOptions(512, 1)).build());
// Esegui il polling per il JSONL
IngestJob status = client.v2.getIngestJob(job.jobId());
if ("completed".equals(status.status())) {
System.out.println(status.outputUrl() + " (" + status.totalChunks() + " chunks)");
}
client.v2.listIngestJobs(V2ListOptions.builder().limit(20).build());
client.v2.cancelIngestJob(job.jobId()); // idempotente
ingestFiles accetta PDF, DOCX, PPTX, XLSX, CSV, HTML, EPUB, TXT e MD, oltre ai formati office legacy e ODF. Il chunking usa per impostazione predefinita 512 parole (da 32 a 4000) con 1 frase di sovrapposizione (da 0 a 10). mode vale urls per impostazione predefinita, il che richiede un elenco urls non vuoto e vieta url; ogni altra modalità richiede un url seed e vieta urls. L'SDK verifica quell'abbinamento prima dell'invio.
I webhook di completamento sono firmati con HMAC. Recupera il secret e i nomi degli header che ti servono per verificare una consegna, ruotalo quando trapela e rispedisci una consegna che il tuo endpoint ha perso:
WebhookSecret secret = client.v2.getWebhookSecret();
System.out.println(secret.signatureHeader() + " " + secret.signatureScheme());
client.v2.rotateWebhookSecret(); // le vecchie firme smettono subito di essere valide
WebhookRetryResult retry = client.v2.retryIngestWebhook(job.jobId());
System.out.println(retry.delivered() + " after " + retry.attempts() + " attempts");
Watch#
Monitoraggio ricorrente delle modifiche su un URL, con notifica via email e webhook. Riferimento dell'endpoint: Watch.
Watcher watcher = client.v2.createWatcher("https://example.com/pricing",
WatchCreateOptions.builder()
.frequencyMinutes(60) // da 60 a 43200, minimo orario
.diffMode("auto") // auto, text, structured, tables, metadata
.webhookUrl("https://my.app/hooks/changes")
.notifyEmail(true)
.build());
WatcherSnapshotList history = client.v2.getWatcherSnapshots(watcher.watcherId(),
SnapshotListOptions.builder().limit(10).build());
history.snapshots().forEach(s ->
System.out.println(s.checkedAt() + " changed=" + s.hasChanges()
+ " similarity=" + s.similarity()));
client.v2.updateWatcher(watcher.watcherId(), WatcherUpdate.builder().status("paused").build());
client.v2.updateWatcher(watcher.watcherId(), WatcherUpdate.builder().webhookUrl("").build());
client.v2.deleteWatcher(watcher.watcherId()); // soft delete, idempotente
listWatchers() e getWatcher(watcherId) li rileggono. updateWatcher richiede almeno un campo e altrimenti genera IllegalArgumentException. Una stringa vuota esplicita per webhookUrl cancella il webhook, mentre lasciarlo null significa che non cambia nulla. deleteWatcher è una cancellazione soft: restituisce il watcher marcato come eliminato con stato deleted, e un watcher eliminato viene poi letto come 404.
WatcherSnapshot.changes() è testo grezzo prelevato dalla pagina monitorata. Effettuane l'escape prima di renderizzarlo in una dashboard, in un'email o in un messaggio di chat.
Opzioni PDF#
PdfOptions è condiviso da convertUrlToPdf, convertWebsiteToPdf, convertDocument, convertToPdf e PerceiveOptions.pdfOptions.
client.convertUrlToPdf("https://internal.example.com/report",
UrlToPdfOptions.builder()
.pdfOptions(PdfOptions.builder()
.pageSize("A4")
.orientation("landscape")
.margins(new PdfMargins(10.0, 10.0, 15.0, 15.0))
.scale(0.9)
.header(new PdfHeaderFooter("Quarterly Report", 15.0))
.footer(new PdfHeaderFooter("Confidential", 12.0))
.build())
.auth(new HttpBasicAuth("user", "pass"))
.cookies(List.of(BrowserCookie.builder("session", "abc123").domain("internal.example.com").build()))
.headers(Map.of("X-Tenant", "acme"))
.saveTo("report.pdf")
.build());
| Campo | Tipo | Descrizione |
|---|---|---|
pageSize |
String |
"A4", "A3", "Letter", "Legal" e simili. |
pageWidth, pageHeight |
double |
Dimensioni personalizzate. Impostati insieme, hanno la precedenza su pageSize. |
orientation |
String |
"portrait" oppure "landscape". |
margins |
PdfMargins |
Record di top, bottom, left, right. Qualsiasi campo null viene omesso. |
scale |
double |
Scala di rendering, ad esempio 0.9 per il 90 percento. |
grayscale |
boolean |
Post-elabora il PDF in scala di grigi. |
header, footer |
PdfHeaderFooter |
Record di content (massimo 2000 caratteri) e height. |
BrowserCookie richiede un nome e un valore più domain oppure url; quando domain è impostato senza path, l'API imposta path a / per impostazione predefinita. Non combinare auth con un header Authorization esplicito, perché l'API rifiuta il conflitto.
Gestione degli errori#
Ogni eccezione dell'SDK estende EnconvertException, che a sua volta estende RuntimeException, quindi nulla impone una clausola throws sui tuoi punti di chiamata. Cattura prima le sottoclassi specifiche.
try {
client.convertUrlToPdf("https://example.com");
} catch (AuthenticationException e) {
System.err.println("Invalid or missing API key");
} catch (QuotaException e) {
System.err.println("Request refused with 402: " + e.getMessage());
} catch (RateLimitException e) {
System.err.println("Too many requests, back off and retry");
} catch (ApiException e) {
System.err.println("API error [" + e.getStatusCode() + "]: " + e.getMessage());
}
| Classe | Generata per | Codice di stato |
|---|---|---|
AuthenticationException |
Chiave API mancante, non valida o non autorizzata | 401, 403 |
QuotaException |
HTTP 402 | 402 |
RateLimitException |
Troppe richieste | 429 |
ApiException |
Qualsiasi altra risposta 4xx o 5xx | il codice effettivo |
EnconvertException |
Classe base, generata anche in caso di errore di trasporto, richiesta interrotta o file di input illeggibile | nessuno |
La validazione lato client (una coppia di conversione non supportata, uno schema distill mancante, un aggiornamento watcher vuoto, il numero sbagliato di output per perceiveDirect) genera IllegalArgumentException prima che venga inviata qualsiasi richiesta. La mappa dei messaggi per le risposte del server si trova nel riferimento Codici di errore.
Recupero dei timeout#
I rendering di URL lunghi e le conversioni di documenti di grandi dimensioni possono superare il timeout del reverse proxy anche quando la conversione stessa alla fine riesce. L'SDK gestisce il caso in modo trasparente:
- Prima di ogni richiesta con URL singolo o upload di file, l'SDK genera un UUID e lo invia come
job_id. - Se la richiesta torna con 5xx, l'SDK passa al polling di
GET /v1/convert/status/{jobId}ogni 3 secondi. - Su
successrestituisce il risultato. SufailedgeneraApiExceptioncon il messaggio di errore del server. - Il limite di tempo per il polling è di 5 minuti. Superato quello, genera
ApiException(504, "Conversion timed out").
Non devi scrivere codice per questo. Se una risposta riuscita omette job_id, l'SDK reinserisce l'id che ha generato, così result.jobId() è sempre utilizzabile con getJobStatus.
convertWebsiteToPdf e convertWebsiteToScreenshot non hanno una riga per singolo job da interrogare, quindi un 5xx in quel punto significa che l'invio stesso è fallito e viene riportato direttamente. Nemmeno gli endpoint V2 usano il polling dei job: i loro flussi asincroni passano da getPerceiveBatch e getIngestJob.
Configurazione#
Enconvert client = Enconvert.builder(System.getenv("ENCONVERT_API_KEY"))
.baseUrl("https://api.enconvert.com")
.timeout(Duration.ofSeconds(300))
.build();
Sono disponibili tre costruttori come scorciatoia: new Enconvert(apiKey), new Enconvert(apiKey, baseUrl) e new Enconvert(apiKey, baseUrl, timeout).
| Opzione | Tipo | Predefinito | Descrizione |
|---|---|---|---|
apiKey |
String |
obbligatorio | Chiave API privata. Un valore null o vuoto genera IllegalArgumentException. |
baseUrl |
String |
https://api.enconvert.com |
URL base dell'API. Gli slash finali vengono rimossi. |
timeout |
Duration |
300 secondi | Applicato sia come timeout di connessione sia come timeout per singola richiesta. |
La chiave viaggia nell'header X-API-Key. Gli URL di download presigned vengono recuperati senza di essa, dato che sono già firmati. I tipi di chiave sono trattati in Autenticazione; crea e gestisci le chiavi nella dashboard.
Struttura del risultato#
Ogni conversione di un singolo file o di un singolo URL restituisce lo stesso record:
public record ConversionResult(
String presignedUrl,
String objectKey,
String filename,
Long fileSize,
Double conversionTimeSeconds,
String jobId) {}
L'URL presigned ha una durata limitata. Passa saveTo (oppure recupera l'URL tu stesso) e archivia i byte nel tuo bucket se ti servono oltre quella durata.
Gli altri record di risposta che toccherai più spesso:
| Record | Accessori principali |
|---|---|
JobStatus |
status() (processing, success, failed), presignedUrl(), objectKey(), error() |
BatchStatus |
status(), total(), completed(), failed(), inProgress(), zipDownloadUrl(), items() |
PerceiveResult |
operationId(), renderQuality(), statusCode(), deductions(), outputs(), structured(), cacheHit(), warnings() |
V2OutputArtifact |
url(), objectKey(), sizeBytes(), contentType(), expiresIn() |
PerceiveDirectResult |
content(), contentType(), filename(), renderQuality(), contentHash() |
IngestJob |
jobId(), status(), pagesProcessed(), totalChunks(), outputUrl(), webhookDelivered() |
Watcher |
watcherId(), status(), frequencyMinutes(), checksCount(), nextCheckAt(), lastChangeAt() |
I campi la cui forma è definita dalla tua richiesta (structured, data, trackFields, changes degli snapshot) sono esposti come JsonObject di Gson e passano intatti. Le enumerazioni con valori stringa restano String invece di diventare costanti enum Java, così un valore API più recente non rompe mai la deserializzazione su una build più vecchia dell'SDK. com.enconvert.model.v2.V2Enums contiene ogni valore accettato come costante a prova di refuso.
Sorgente e problemi#
- Maven Central:
com.enconvert:enconvert-sdk:0.0.1 - GitHub: conversionapi/java-sdk
- Licenza: MIT
- Altri client: tutti gli SDK · riferimento degli endpoint · prezzi
Domande frequenti#
Come converto i file in Java con una dipendenza Maven?#
Aggiungi com.enconvert:enconvert-sdk:0.0.1 al tuo pom.xml oppure al build.gradle, costruisci un client con new Enconvert(System.getenv("ENCONVERT_API_KEY")) e chiama un metodo tipizzato come convertUrlToPdf, convertImage, convertDocument oppure convertToPdf. Passa saveTo sul builder delle opzioni per scrivere l'output direttamente su disco invece di gestire tu stesso l'URL presigned.
Come converto un URL in PDF in Java?#
Chiama client.convertUrlToPdf(url, UrlToPdfOptions.builder().saveTo("page.pdf").build()). Imposta singlePage(false) per paginare usando pdfOptions.pageSize invece di produrre una singola pagina continua, e passa auth, cookies oppure headers per una pagina protetta da login.
Come converto DOCX in PDF in Java?#
Chiama client.convertDocument(Path.of("report.docx"), ConvertDocumentOptions.builder().saveTo("report.pdf").build()). Il formato di output predefinito è pdf, quindi imposti outputFormat solo quando vuoi qualcos'altro, per esempio yaml da un input .json. Per i formati senza una coppia dedicata, come EPUB o RTF, usa convertToPdf.
Come converto HEIC in WebP in Java?#
Chiama client.convertImage(Path.of("photo.heic"), ConvertImageOptions.builder("webp").saveTo("photo.webp").build()). Il formato di input viene ricavato dall'estensione del file e il formato di output è l'argomento obbligatorio del builder. jpeg, png, svg, heic e webp si convertono tutti tra loro, e pdf viene rasterizzato in jpeg. Su questo client non esiste un metodo di compressione sul posto.
Come estraggo una pagina web in Markdown pulito da Java?#
Ci sono due strade. client.convertUrlToMarkdown(url, ...) restituisce Markdown in stile GitHub Flavored con frontmatter YAML come file scaricabile. client.v2.perceive(url, PerceiveOptions.builder().outputs(List.of("markdown")).build()) restituisce lo stesso contenuto come artefatto pronto per gli agenti, con un punteggio renderQuality, opzioni di estrazione e controllo della cache. Usa perceive quando una lettura difettosa deve essere rilevabile invece che silenziosa.
Che cos'è renderQuality e perché ogni lettura ne ha uno?#
renderQuality è un punteggio da 0.0 a 1.0 associato a ogni rendering V2. Un punteggio alto significa che la pagina è stata renderizzata in modo pulito; un punteggio basso significa che qualcosa si è messo in mezzo, per esempio una challenge anti-bot, un cookie wall, una schermata di login, una pagina di errore HTTP o uno shell SPA vuoto. Il contenuto viene comunque restituito, con warnings() e deductions() popolati, così la tua pipeline può scartare o ripetere la lettura invece di dare in pasto a un modello una pagina di challenge come se fosse l'articolo.
Come trasformo un sito di documentazione in chunk pronti per il RAG in Java?#
Chiama client.v2.ingest(IngestOptions.builder().mode("sitemap").url("https://docs.example.com").maxPages(100).chunk(new IngestChunkOptions(512, 1)).build()). Il job è asincrono, quindi puoi interrogare getIngestJob(jobId) finché lo stato non è completed e leggere outputUrl() per il JSONL, oppure impostare webhookUrl e verificare la firma HMAC con il secret restituito da getWebhookSecret(). Per documenti locali invece di un sito, usa ingestFiles.
Come gestisce l'SDK le conversioni che superano il timeout del proxy?#
Prima di ogni richiesta con URL singolo o upload di file genera un UUID e lo invia come job_id. Se la richiesta restituisce 5xx, interroga GET /v1/convert/status/{jobId} ogni 3 secondi finché il job non riporta success oppure failed, con un limite di 5 minuti oltre il quale genera ApiException(504, "Conversion timed out"). Gli invii batch di interi siti sono esclusi, perché non hanno una riga per singolo job da interrogare.
Quale versione di Java richiede l'SDK e che cosa porta con sé?#
Java 17 o versioni successive. L'HTTP passa dal java.net.http.HttpClient del JDK, e Gson è l'unico artefatto di terze parti sul classpath. Le risposte sono record Java, quindi uno switch moderno o un pattern match su di esse funziona come previsto. Il client è thread safe: tieni una sola istanza e condividila.