SDK Ruby per la Conversione dei File#
enconvert è la gem Ruby ufficiale per l'API EnConvert. Converte URL, immagini e documenti attraverso 43 endpoint di conversione implementati, ed espone un secondo namespace, client.v2, che legge le pagine web live in Markdown, JSON, screenshot e PDF pronti per gli agenti. Ogni lettura V2 porta con sé un punteggio render_quality, così una pagina bloccata o uno shell SPA vuoto non passano mai per contenuto reale. La gem richiede Ruby 3.0+ e non ha dipendenze a runtime, costruita su net/http, json e securerandom della libreria standard. Le risposte tornano come Struct con reader in snake_case.
enconvert · Sorgente: conversionapi/ruby-sdk · Ruby: 3.0.0 o versioni successive · Dipendenze a runtime: nessuna
Installazione#
gem install enconvert
Oppure aggiungila al tuo Gemfile:
gem "enconvert"
bundle install
Avvio rapido#
require "enconvert"
client = Enconvert::Client.new(api_key: ENV.fetch("ENCONVERT_API_KEY"))
# Converte una pagina live in PDF e la trasmette su disco.
result = client.convert_url_to_pdf("https://example.com", save_to: "page.pdf")
puts result.presigned_url
# Legge la stessa pagina come dovrebbe fare un agente, con un punteggio di qualità allegato.
op = client.v2.perceive("https://example.com", outputs: %w[markdown structured])
puts op.outputs["markdown"].url, op.render_quality # ad es. 0.93
La gem è solo lato server. La tua chiave API privata deve restare sul server, quindi leggila da una variabile d'ambiente o da un secret manager e non spedirla mai a un browser o a un binario mobile.
Cosa espone il client#
Enconvert::Client porta direttamente la superficie di conversione dei file, e l'intera superficie di web intelligence pende da client.v2.
| Gruppo | Metodi | Restituisce |
|---|---|---|
| URL singolo | convert_url_to_pdf, convert_url_to_screenshot, convert_url_to_markdown |
ConversionResult |
| File caricato | convert_image, convert_document, convert_to_markdown, convert_to_pdf |
ConversionResult |
| Batch di un intero sito | convert_website_to_pdf, convert_website_to_screenshot |
BatchSubmission |
| Stato e polling | get_job_status, get_batch_status, wait_for_batch |
JobStatus, BatchStatus |
| Web intelligence | client.v2.*, 23 metodi su sei funzionalità |
Struct V2 |
| Helper sui formati | Enconvert.valid_outputs_for, Enconvert::IMPLEMENTED_CONVERSIONS |
Array, Set |
Ogni tipo di risposta è una Struct creata con keyword_init: true, quindi leggi i campi come normali metodi: result.presigned_url, op.render_quality, job.total_chunks.
Conversione dei file#
convert_url_to_pdf#
Esegue il rendering di qualsiasi URL pubblico in PDF.
result = client.convert_url_to_pdf(
"https://example.com",
single_page: false,
pdf_options: { page_size: "A4", orientation: "landscape" },
viewport_width: 1440,
save_to: "report.pdf"
)
puts result.filename, result.file_size
| Opzione | Tipo | Predefinito | Descrizione |
|---|---|---|---|
save_to |
String |
nil |
Percorso locale su cui scaricare il PDF. Le directory padre vengono create automaticamente. |
single_page |
Boolean |
true |
true produce una singola pagina continua. false pagina utilizzando pdf_options[:page_size]. |
pdf_options |
Hash |
nil |
Geometria di pagina. Vedi Opzioni PDF. |
viewport_width |
Integer |
1920 |
Larghezza del viewport del browser in pixel. |
viewport_height |
Integer |
1080 |
Altezza del viewport del browser in pixel. |
load_media |
Boolean |
true |
Attende immagini e video prima della cattura. |
enable_scroll |
Boolean |
true |
Scorre dall'alto verso il basso perché scattino i caricamenti lazy. |
output_filename |
String |
nil |
Sovrascrive il nome file generato. |
auth |
Hash |
nil |
Credenziali HTTP basic, per esempio { username: "user", password: "pass" }. |
cookies, headers |
Array, Hash |
nil |
Cookie da impostare e header di richiesta aggiuntivi. Tutti e tre i campi di accesso al browser passano inalterati. |
auth con un header Authorization. L'API rifiuta il conflitto, quindi scegli l'uno o l'altro.
convert_url_to_screenshot#
Cattura un PNG a pagina intera di qualsiasi URL.
client.convert_url_to_screenshot("https://example.com", viewport_width: 1440, save_to: "shot.png")
Accetta le stesse opzioni di viewport, media, scroll, nome file e accesso al browser di convert_url_to_pdf. Non accetta single_page né pdf_options.
convert_url_to_markdown#
Estrae Markdown pulito in stile GitHub-Flavored da qualsiasi URL. Il convertitore rimuove navigazione, footer, pubblicità e script, mantiene il corpo principale dell'articolo e antepone un frontmatter YAML con titolo, descrizione, url, link e immagini.
client.convert_url_to_markdown("https://example.com/article", save_to: "article.md")
Utile per alimentare una pipeline RAG, importare contenuti di terze parti in un CMS o costruire un corpus di addestramento.
convert_image#
Converte tra jpeg, png, svg, heic e webp in qualsiasi direzione, oppure rasterizza un PDF in JPEG.
# Da un percorso su disco.
client.convert_image("photo.heic", output_format: "webp", save_to: "photo.webp")
# Da byte che hai già in mano.
bytes = File.binread("photo.heic")
client.convert_image({ data: bytes, filename: "photo.heic" }, output_format: "webp", save_to: "photo.webp")
# Rasterizza la prima pagina di un PDF.
client.convert_image("invoice.pdf", output_format: "jpeg", save_to: "invoice.jpg")
Il formato di input viene ricavato dall'estensione del nome file, quindi qui non si può usare un IO grezzo privo di nome file. Passa invece un percorso oppure un Hash { data:, filename: }.
| Opzione | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
output_format |
String |
Sì | Formato di destinazione. Gli alias jpg, yml, htm e md vengono normalizzati automaticamente. |
save_to |
String |
No | Percorso locale su cui scaricare il risultato. |
output_filename |
String |
No | Sovrascrive il nome file generato. |
convert_document#
Converte documenti e formati di dati. output_format vale "pdf" per impostazione predefinita.
# da docx a pdf
client.convert_document("report.docx", save_to: "report.pdf")
# da json a yaml
client.convert_document("data.json", output_format: "yaml", save_to: "data.yaml")
# da markdown a pdf con impostazioni di pagina personalizzate
client.convert_document(
"README.md",
output_format: "pdf",
pdf_options: { page_size: "A4", margins: { top: 20, bottom: 20, left: 25, right: 25 } },
save_to: "readme.pdf"
)
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 convert_to_pdf oppure a convert_to_markdown.
| Opzione | Tipo | Predefinito | Descrizione |
|---|---|---|---|
output_format |
String |
"pdf" |
Formato di destinazione. |
save_to |
String |
nil |
Percorso locale su cui scaricare il risultato. |
output_filename |
String |
nil |
Sovrascrive il nome file generato. |
pdf_options |
Hash |
nil |
Impostazioni di pagina, rispettate quando l'output è PDF. |
convert_to_markdown#
Converte in Markdown pulito un file caricato di quasi qualsiasi formato documentale. Il formato viene rilevato sul server.
client.convert_to_markdown("handbook.docx", save_to: "handbook.md")
Input accettati: PDF, DOCX, PPTX, XLSX, CSV, HTML, EPUB, TXT e MD, oltre ai formati office legacy e ODF. Le immagini non sono supportate su questo endpoint.
L'output è un unico file .md strutturato per intestazioni, il che lo rende un buon mattone per l'ingestion RAG: un chunker semantico può suddividere sulla gerarchia di intestazioni del documento invece che su conteggi arbitrari di caratteri. Le uniche opzioni sono save_to: e output_filename:.
convert_to_pdf#
Converte in PDF un file caricato di quasi qualsiasi formato.
# da pptx a pdf
client.convert_to_pdf("slides.pptx", save_to: "slides.pdf")
# pdf in passthrough, normalizzato in scala di grigi
client.convert_to_pdf("scan.pdf", pdf_options: { grayscale: true }, save_to: "gray.pdf")
Input accettati: office, ODF, Pages, Numbers, RTF, CSV, HTML, Markdown, testo semplice, immagini raster, SVG, EPUB, oppure un PDF esistente che viene passato in passthrough e normalizzato.
pdf_options[:grayscale]. Gli altri campi di geometria di pagina vengono ignorati su questo endpoint. Quando ti serve il controllo completo su dimensione pagina, orientamento e margini, usa convert_document oppure convert_url_to_pdf.
Le opzioni sono save_to:, output_filename: e pdf_options: (solo grayscale).
convert_website_to_pdf e convert_website_to_screenshot#
Individua ogni pagina di un sito web, converte ciascuna in background e raccoglie i risultati in un unico ZIP. Entrambi i metodi sono asincroni e restituiscono subito un BatchSubmission.
batch = client.convert_website_to_pdf(
"https://example.com",
crawl_mode: "sitemap",
exclude_patterns: ["/tag/"],
notification_email: "[email protected]"
)
status = client.wait_for_batch(batch.batch_id, save_to: "site.zip")
puts "#{status.completed} of #{status.total} pages converted"
status.items.each { |item| puts "#{item.status}\t#{item.source_url}" }
convert_website_to_screenshot funziona in modo identico e produce uno ZIP di PNG.
| Opzione | Tipo | Descrizione |
|---|---|---|
crawl_mode |
String |
Come vengono individuate le pagine, per esempio "sitemap". |
include_patterns, exclude_patterns |
Array |
Sottoponi al crawl, oppure salta, solo gli URL che corrispondono a questi pattern. |
notification_email |
String |
Indirizzo email da avvisare quando il batch termina. |
callback_url |
String |
Webhook chiamato al completamento. |
output_filename |
String |
Sovrascrive il nome file ZIP generato. |
viewport_width, viewport_height, load_media, enable_scroll |
Integer, Boolean |
Comportamento di rendering per pagina. Inviati solo quando li imposti, altrimenti il gateway applica i propri valori predefiniti. |
auth, cookies, headers |
Hash, Array, Hash |
Accesso del browser alle pagine protette. |
single_page, pdf_options |
Boolean, Hash |
Solo per i batch PDF. |
wait_for_batch(batch_id, interval: 5, timeout: 1800, save_to: nil) esegue il polling finché il batch non esce da "processing", poi restituisce il BatchStatus finale. Con save_to scarica anche lo ZIP. Genera Enconvert::APIError con stato 504 quando viene raggiunto il timeout, e con stato 500 quando un batch termina senza uno ZIP da salvare.
get_job_status#
Interroga un singolo job di conversione tramite id.
status = client.get_job_status("job_abc123")
case status.status
when "success" then puts status.presigned_url
when "failed" then warn status.error
else puts "still processing"
end
Restituisce un JobStatus con status, presigned_url, object_key ed error. Raramente devi chiamarlo tu stesso, perché l'SDK lo interroga già per tuo conto. Vedi Recupero dei timeout.
Conversioni supportate#
La gem porta con sé la tabella completa degli endpoint {input}-to-{output} implementati e valida ogni coppia localmente, quindi una coppia non supportata genera Enconvert::Error prima che una richiesta lasci il tuo processo.
Enconvert.valid_outputs_for("json") # => ["csv", "toml", "xml", "yaml"]
Enconvert.valid_outputs_for("pdf") # => ["jpeg"]
Enconvert::IMPLEMENTED_CONVERSIONS.size # => 43
| 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 |
Sono 43 endpoint: 13 di testo strutturato, 9 documentali e 21 di conversione immagini.
Web intelligence (V2)#
client.v2 trasforma le pagine web live in dati pronti per gli agenti: rendering, enumerazione, ricerca, estrazione, ingestion e monitoraggio. Ogni rendering porta con sé render_quality, un punteggio da 0.0 a 1.0 associato a ogni lettura. Un punteggio basso significa che la pagina non è stata renderizzata in modo pulito, tipicamente una pagina di challenge, un cookie wall, un blocco di login o uno shell JavaScript vuoto. Il contenuto viene comunque restituito, ma segnalato, insieme a un array warnings e a un Hash deductions che dice quali controlli sono scattati. Leggi il punteggio prima di mettere il contenuto da qualche parte, e una lettura difettosa non entrerà mai silenziosamente nel contesto del tuo agente.
Tutti gli endpoint V2 richiedono una chiave API privata. Vedi la panoramica V2 per il riferimento a livello di endpoint.
Perceive#
Esegue il rendering di un URL negli artefatti che richiedi. perceive è sincrono e restituisce l'operazione completata con gli URL degli artefatti appena firmati.
op = client.v2.perceive(
"https://example.com",
outputs: %w[markdown screenshot structured],
extract: %w[tables metadata],
only_main_content: true
)
puts op.operation_id, op.render_quality # "per_...", poi da 0.0 a 1.0
puts op.outputs["markdown"].url # URL firmato dell'artefatto
puts op.outputs["markdown"].expires_in # secondi prima che smetta di funzionare
puts op.structured, op.warnings.inspect # Hash Ruby semplice, poi Array di String
Rifirma in qualsiasi momento gli URL degli artefatti di un'operazione precedente:
again = client.v2.get_perceive_operation(op.operation_id)
Puoi percepire fino a 1000 URL con un unico blocco di opzioni condiviso. I batch piccoli girano inline e tornano completati. Quelli più grandi tornano con stato "queued", quindi interrogali tramite job_id:
batch = client.v2.perceive_batch(
["https://a.example.com", "https://b.example.com"],
outputs: %w[markdown],
output_mode: "zip"
)
done = client.v2.get_perceive_batch(batch.job_id)
puts "#{done.completed}/#{done.total} complete, #{done.failed} failed"
puts done.zip&.url
Salta del tutto il round trip dell'URL firmato con perceive_direct, dove il corpo della risposta HTTP è l'artefatto stesso:
direct = client.v2.perceive_direct("https://example.com", outputs: %w[markdown])
puts direct.filename, direct.content_type, direct.content.bytesize
File.binwrite("page.md", direct.content)
# Riscarica un artefatto archiviato di un'operazione precedente.
raw = client.v2.download_perceive_artifact(op.operation_id, output: "markdown")
perceive_direct richiede esattamente un output che produca artefatti e altrimenti genera Enconvert::Error localmente. structured può viaggiare insieme, perché resta inline lato server e non viene mai trasmesso in streaming. download_perceive_artifact prende un output: opzionale, che puoi omettere quando l'operazione ha prodotto esattamente un artefatto e devi indicare quando ne ha prodotti più di uno, e restituisce 410 quando un artefatto ha superato la sua finestra di conservazione.
| Opzione | Tipo | Descrizione |
|---|---|---|
outputs |
Array |
Uno o più tra markdown, html_cleaned, html_raw, screenshot, screenshot_full_page, pdf, links, images, structured. Lato server il valore predefinito è ["markdown", "structured"]. |
extract |
Array |
Uno o più tra tables, prices, contacts, metadata, main_content, headings, structured_data, technologies, all. |
schema |
Hash |
Descrizioni dei campi per l'estrazione strutturata. |
wait_for, wait_timeout_ms |
String, Integer |
Selettore CSS da attendere prima della cattura, e il limite su quell'attesa. |
js_code |
String |
JavaScript da eseguire nella pagina prima della cattura. |
viewport, mobile |
Hash, Boolean |
Dimensioni del viewport, e se renderizzare con un profilo mobile. |
headers, cookies, auth |
Hash, Array, Hash |
Accesso del browser alle pagine protette. |
proxy_url |
String |
Instrada il rendering attraverso il tuo proxy. |
geolocation |
Hash |
Geolocalizzazione simulata per il contesto del browser. |
action_chain |
Array |
Click, scroll e input programmati prima della cattura. |
cache_mode |
String |
enabled, bypass oppure refresh. |
pdf_options |
Hash |
Geometria di pagina quando pdf è tra gli output. |
block_resources |
Array |
Tipi di risorsa da bloccare, per esempio image, font, script. |
respect_robots |
Boolean |
Rispetta robots.txt. |
only_main_content |
Boolean |
Rimuove navigazione ed elementi ripetuti dall'output Markdown. |
direct_download |
Boolean |
Accettato solo da perceive. perceive_batch lo rifiuta. |
La semantica completa dei parametri si trova in Perceive e in Parametri e opzioni.
Discover#
Enumera gli URL di un sito senza renderizzare nulla. Non è coinvolto alcun browser, quindi è veloce ed economico.
found = client.v2.discover(
"https://example.com",
mode: "hybrid", # "sitemap", "crawl" oppure "hybrid"
max_urls: 200,
max_depth: 3,
exclude_patterns: ["/tag/"],
same_domain_only: true,
respect_robots: true
)
puts found.total, found.urls.first(10)
puts found.truncated # true quando max_urls ha limitato il risultato
puts found.sources.inspect # da dove proviene ciascun URL
Vedi Discover per il comportamento modalità per modalità.
Lookup#
Esegue una ricerca web categorizzata e, facoltativamente, percepisce i risultati migliori nella stessa chiamata.
search = client.v2.lookup(
"best static site generators",
category: "web", # web, news, images, scholar, patents, maps
num_results: 10,
time_filter: "month", # hour, day, week, month, year
perceive_top: 3
)
search.results.each do |hit|
puts hit.position, hit.title, hit.url
puts hit.perceive&.render_quality # presente per i risultati percepiti automaticamente
end
puts search.answer_box.inspect, search.knowledge_graph.inspect
Con perceive_top: 3, i primi tre URL dei risultati vengono renderizzati e portano inline un PerceiveResult completo su hit.perceive. I loro id di operazione sono raccolti anche in search.perceive_operation_ids. Altro in Lookup.
Distill#
Estrazione strutturata guidata da schema. Fornisci esattamente uno tra urls: e discover_from:, e schema: è sempre obbligatorio. Se sbagli, l'SDK genera Enconvert::Error localmente.
extraction = client.v2.distill(
urls: ["https://example.com/pricing"],
schema: { plans: "list of plan names with monthly prices" },
css_schema: {
base_selector: ".plan-card",
fields: [
{ name: "name", type: "text", selector: "h3" },
{ name: "price", type: "text", selector: ".price" }
]
}
)
item = extraction.results.first
puts item.data.inspect
puts item.extraction_tier # "css", "llm", "mixed" oppure "none"
puts item.fields_from_css, item.fields_from_llm
Il css_schema opzionale viene eseguito per primo e risponde a tutto ciò che può con i soli selettori. Solo i campi che non riesce a coprire passano al livello del modello linguistico, ed è per questo che fields_from_css e fields_from_llm vengono riportati separatamente.
Individua ed estrai in un'unica chiamata:
client.v2.distill(
discover_from: { url: "https://example.com", mode: "sitemap", max_pages: 10 },
schema: { title: "page title", summary: "one-line summary" }
)
I tipi di campo CSS sono text, attribute, html, regex, nested, list e nested_list. Gli elenchi di campi annidati vengono serializzati in modo ricorsivo. Vedi Distill.
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.
job = client.v2.ingest(
mode: "sitemap", # urls, sitemap, crawl
url: "https://docs.example.com",
max_pages: 100,
chunk: { max_words: 512, sentence_overlap: 1 },
webhook_url: "https://my.app/hooks/enconvert"
)
status = client.v2.get_ingest_job(job.job_id)
puts status.status # queued, discovering, processing, completed, failed, canceled
puts status.pages_processed, status.total_chunks
puts status.output_url if status.status == "completed" # JSONL
La modalità "urls" prende un elenco urls: e rifiuta url:. Ogni altra modalità prende un url: seed e rifiuta urls:. Entrambe le regole vengono applicate localmente prima che la richiesta venga inviata.
Carica file invece di fare il crawl:
file_job = client.v2.ingest_files(
["handbook.pdf", "notes.docx"],
chunk: { max_words: 512, sentence_overlap: 1 }
)
ingest_files accetta PDF, DOCX, PPTX, XLSX, CSV, HTML, EPUB, TXT e MD, oltre ai formati office legacy e ODF. Ogni voce può essere un percorso, un oggetto simile a un IO oppure un Hash { data:, filename: }.
Gestisci i job e la consegna dei webhook:
list = client.v2.list_ingest_jobs(limit: 20)
list.jobs.each { |j| puts "#{j.job_id}\t#{j.status}\t#{j.total_chunks}" }
puts list.has_more
client.v2.cancel_ingest_job(job.job_id) # idempotente
secret = client.v2.get_webhook_secret
puts secret.secret, secret.signature_header, secret.timestamp_header,
secret.signature_scheme, secret.replay_tolerance_seconds
client.v2.rotate_webhook_secret # le vecchie firme smettono subito di essere valide
client.v2.retry_ingest_webhook(job.job_id) # rispedisce il webhook di un job completato
retry_ingest_webhook restituisce un WebhookRetryResult con delivered, attempts, status_code e detail. Risponde 409 quando il job non è completato e 400 quando il job non ha alcun webhook configurato. Vedi Ingest.
Watch#
Rifà il rendering di un URL a cadenza fissa e ti avvisa quando cambia.
watcher = client.v2.create_watcher(
"https://example.com/pricing",
frequency_minutes: 60, # minimo orario
diff_mode: "auto", # auto, text, structured, tables, metadata
webhook_url: "https://my.app/hooks/changes",
notify_email: true
)
puts watcher.watcher_id, watcher.next_check_at
history = client.v2.get_watcher_snapshots(watcher.watcher_id, limit: 10)
history.snapshots.each do |snap|
puts snap.checked_at, snap.has_changes, snap.similarity, snap.change_count, snap.changes.inspect
end
client.v2.list_watchers(limit: 20)
client.v2.get_watcher(watcher.watcher_id)
client.v2.update_watcher(watcher.watcher_id, status: "paused")
client.v2.update_watcher(watcher.watcher_id, webhook_url: "") # cancella il webhook
client.v2.delete_watcher(watcher.watcher_id) # soft delete, idempotente
update_watcher genera Enconvert::Error se lo chiami senza campi da aggiornare. delete_watcher restituisce il watcher marcato come eliminato con stato "deleted", e un watcher eliminato viene riletto come 404. Semantica completa in Watch.
Opzioni PDF#
pdf_options è un semplice Hash con chiavi simbolo, accettato da convert_url_to_pdf, convert_website_to_pdf, convert_document, convert_to_pdf (solo grayscale) e client.v2.perceive quando pdf è tra gli output. Sul filo vengono inviate solo le chiavi che imposti.
client.convert_url_to_pdf(
"https://example.com",
pdf_options: { page_size: "A4", orientation: "landscape", scale: 0.9,
margins: { top: 10, bottom: 10, left: 15, right: 15 } },
save_to: "report.pdf"
)
| Chiave | Tipo | Descrizione |
|---|---|---|
page_size |
String |
"A4", "A3", "Letter", "Legal" e simili. |
page_width |
Number |
Larghezza di pagina esplicita, in alternativa a page_size. |
page_height |
Number |
Altezza di pagina esplicita. |
orientation |
String |
"portrait" oppure "landscape". |
margins |
Hash |
{ top:, bottom:, left:, right: }, tutti opzionali. |
scale |
Number |
Scala di rendering, per esempio 0.9 per il 90 percento. |
grayscale |
Boolean |
Post-elabora il PDF in scala di grigi. |
header |
Hash |
Testo dell'intestazione per regione di pagina. |
footer |
Hash |
Testo del piè di pagina per regione di pagina. |
Gestione degli errori#
Ogni errore è un Enconvert::Error oppure una delle sue sottoclassi, quindi le clausole rescue possono essere ampie o strette quanto vuoi. Gli errori di validazione lato client, come una coppia di conversione non supportata o uno schema mancante, generano la classe base Enconvert::Error prima che venga effettuata qualsiasi richiesta HTTP.
begin
client.v2.perceive("https://example.com")
rescue Enconvert::AuthenticationError
warn "Invalid or missing API key"
rescue Enconvert::QuotaError
warn "Request was rejected with 402"
rescue Enconvert::RateLimitError
warn "Too many requests, back off and retry"
rescue Enconvert::APIError => e
warn "API error [#{e.status_code}]: #{e.message}"
rescue Enconvert::Error => e
warn "Client-side validation failed: #{e.message}"
end
| Classe | Generata per | Codice di stato |
|---|---|---|
Enconvert::AuthenticationError |
Chiave API non valida, mancante o revocata | 401, 403 |
Enconvert::QuotaError |
Generata su HTTP 402 | 402 |
Enconvert::RateLimitError |
Troppe richieste | 429 |
Enconvert::APIError |
Qualsiasi altra risposta da 400 in su | il codice effettivo |
Enconvert::Error |
Classe base, più tutti gli errori di validazione locali | nessuno |
APIError#status_code ti dà lo stato HTTP, e il messaggio viene preso dal campo detail oppure error del corpo della risposta quando il corpo è JSON. La mappa completa dei messaggi si trova in Codici di errore.
Recupero dei timeout#
Un rendering lungo da URL a PDF o la conversione di un documento di grandi dimensioni possono superare il timeout del reverse proxy anche quando la conversione stessa riesce sul server. L'SDK recupera la situazione in modo trasparente, senza codice da parte tua.
- Prima di ogni richiesta di conversione il client genera un job id di 32 caratteri e lo invia come
job_idnel corpo o nel form multipart. - Se la richiesta torna con uno stato pari o superiore a 500, il client passa a interrogare
GET /v1/convert/status/{job_id}ogni 3 secondi. Un404mentre la riga del job è ancora in scrittura viene ignorato e il polling continua. - Non appena il job risulta
success, il risultato viene restituito. Non appena risultafailed, viene generatoEnconvert::APIErrorcon stato500e il messaggio di errore del server. - Il limite di tempo per il polling è di 300 secondi. Superato quello, il client genera
Enconvert::APIErrorcon stato504e il messaggioConversion timed out.
Il job_id generato dal client viene anche unito a ogni risposta riuscita, quindi result.job_id è sempre popolato e più tardi puoi interrogare get_job_status tu stesso, se vuoi.
convert_website_to_pdf e convert_website_to_screenshot non creano una riga per singolo job, quindi lì un 5xx significa che l'invio stesso è fallito e viene riportato subito invece di essere interrogato.
Configurazione#
client = Enconvert::Client.new(
api_key: ENV.fetch("ENCONVERT_API_KEY"),
timeout: 300,
base_url: "https://api.enconvert.com"
)
| Opzione | Tipo | Predefinito | Descrizione |
|---|---|---|---|
api_key |
String |
obbligatorio | La tua chiave API privata. Un valore nil o vuoto genera Enconvert::Error alla costruzione. |
timeout |
Integer |
300 |
Timeout di apertura e lettura in secondi, applicato a ogni richiesta. |
base_url |
String |
"https://api.enconvert.com" |
URL base dell'API. Gli slash finali vengono rimossi. Sovrascrivilo per un gateway self-hosted. |
Le richieste si autenticano con l'header X-API-Key. Quando passi save_to, il download aggira deliberatamente quell'header, perché l'URL presigned dello storage non deve ricevere la tua chiave API.
Struttura del risultato#
Ogni conversione di un singolo file e di una singola pagina restituisce un Enconvert::ConversionResult:
result = client.convert_document("report.docx", save_to: "report.pdf")
result.presigned_url # URL firmato per l'output convertito
result.object_key # chiave dell'oggetto nello storage
result.filename # nome file lato server
result.file_size # byte, oppure nil
result.conversion_time_seconds # secondi, oppure nil
result.job_id # sempre popolato dal client
Le altre Struct V1 sono JobStatus (status, presigned_url, object_key, error), BatchSubmission (batch_id, status, url_count, total_discovered, discovery_method, output_format), BatchStatus (batch_id, status, total, completed, failed, in_progress, output_mode, zip_download_url, items) e BatchItem (source_url, status, download_url, output_file_size, duration).
Sul lato V2, PerceiveResult è quella da conoscere:
op.operation_id # "per_..."
op.status # queued, processing, completed, failed
op.url, op.url_final, op.content_hash
op.render_quality, op.cache_hit # da 0.0 a 1.0 (oppure nil), e se proviene dalla cache
op.outputs # Hash di nome => V2OutputArtifact
op.structured, op.extraction_tier # Hash (oppure nil), e come è stato estratto
op.tokens.input, op.tokens.output, op.cost_cents, op.duration_ms
op.error, op.warnings # String oppure nil, e Array di String
op.status_code # stato HTTP a monte della pagina
op.deductions, op.options_echo # perché render_quality è calato, e le opzioni usate
Un V2OutputArtifact porta url, object_key, size_bytes, content_type ed expires_in (900 secondi per impostazione predefinita), quindi gli URL firmati degli artefatti hanno vita breve. Rifirmali con get_perceive_operation, oppure scarica i byte con download_perceive_artifact. I payload forniti dall'utente, come schemi, dati estratti, campi monitorati e voci di diff, passano intatti come semplici Hash Ruby.
Anche gli URL presigned delle conversioni V1 sono temporanei. Passa save_to quando vuoi i byte su disco, oppure copiali nel tuo bucket per un'archiviazione permanente.
Sorgente e problemi#
- RubyGems: enconvert
- GitHub: conversionapi/ruby-sdk
- Ruby: 3.0.0 o versioni successive, nessuna dipendenza a runtime
- Licenza: MIT
- Altri linguaggi: Tutti gli SDK
- Riferimento API: Panoramica degli endpoint, Autenticazione
Domande frequenti#
Come converto i file in Ruby con una gem?#
Esegui gem install enconvert, costruisci un client con Enconvert::Client.new(api_key: ENV.fetch("ENCONVERT_API_KEY")) e chiama un metodo come convert_document, convert_image oppure convert_url_to_pdf. Passa save_to: e l'SDK scarica per te il risultato su quel percorso, creando le directory padre se servono.
Come converto DOCX in PDF in Ruby?#
client.convert_document("report.docx", save_to: "report.pdf"). Il formato di output predefinito è "pdf", quindi ti serve output_format: solo quando vuoi qualcos'altro. La stessa chiamata funziona per .doc, .xls, .xlsx, .ppt, .pptx, .odt, .ods, .odp, .ots, .pages e .numbers.
Come converto un URL in PDF in Ruby?#
client.convert_url_to_pdf("https://example.com", save_to: "page.pdf"). Imposta single_page: false per paginare invece di produrre una singola pagina continua, e passa pdf_options: per dimensione pagina, orientamento, margini e scala. Per una pagina protetta da HTTP basic auth, aggiungi auth: { username: ..., password: ... }.
Come converto HEIC in WebP in Ruby?#
client.convert_image("photo.heic", output_format: "webp", save_to: "photo.webp"). Il formato di input viene ricavato dall'estensione del nome file, e la gem converte liberamente tra jpeg, png, svg, heic e webp. Rasterizza anche un PDF in JPEG con output_format: "jpeg".
Come estraggo una pagina web in Markdown da Ruby?#
Ci sono due opzioni. client.convert_url_to_markdown(url, save_to: "article.md") ti dà Markdown pulito in stile GitHub-Flavored con frontmatter YAML. client.v2.perceive(url, outputs: %w[markdown]) ti dà lo stesso contenuto più un punteggio render_quality, gli avvisi e l'estrazione strutturata opzionale, che è ciò che ti serve quando a leggere il risultato sarà un agente.
Che cosa significa render_quality e perché dovrei controllarlo?#
È un punteggio da 0.0 a 1.0 associato a ogni lettura V2, che riflette quanto pulitamente la pagina è stata effettivamente renderizzata. Una pagina di challenge, un cookie wall, un blocco di login, una pagina di errore HTTP o uno shell JavaScript vuoto ottengono tutti un punteggio basso. Il contenuto viene comunque restituito così puoi ispezionarlo, con warnings e deductions a spiegare il punteggio. Usalo come filtro prima di archiviare il testo o darlo in pasto a un modello.
L'SDK Ruby riprova quando una conversione lunga va in timeout?#
Sì. Ogni richiesta di conversione porta con sé un job_id generato dal client e, se la richiesta fallisce con uno stato pari o superiore a 500, l'SDK interroga GET /v1/convert/status/{job_id} ogni 3 secondi per un massimo di 300 secondi. Restituisce il risultato una volta che il job riesce e genera Enconvert::APIError con stato 504 se il limite scade. Gli invii batch di interi siti sono esclusi, perché non hanno una riga per singolo job.
Che cosa succede se chiedo una coppia di conversione che l'API non implementa?#
La gem genera Enconvert::Error localmente, prima di qualsiasi chiamata di rete, e il messaggio elenca gli output validi per quell'input. Puoi controllare tu stesso la stessa tabella con Enconvert.valid_outputs_for("json"), che restituisce ["csv", "toml", "xml", "yaml"].
Posso usare la gem enconvert dentro Rails o in un background job?#
Sì, e un background job è il posto giusto per usarla. La gem è puro net/http senza dipendenze a runtime e senza stato globale, quindi un'istanza di Enconvert::Client si può costruire per singolo job oppure memoizzare per processo. Le conversioni lunghe bloccano il thread chiamante fino al timeout configurato, che vale 300 secondi per impostazione predefinita, quindi tienile fuori dal ciclo di una richiesta web.
Quali versioni di Ruby supporta l'SDK?#
Ruby 3.0.0 e versioni successive, come dichiarato da required_ruby_version nella gemspec. Non ci sono dipendenze gem a runtime, quindi si installa in qualsiasi gruppo Bundler senza trascinarsi dietro un albero di dipendenze.
Come verifico la firma di un webhook di ingest?#
Chiama client.v2.get_webhook_secret, che crea il secret di firma del progetto al primo utilizzo e lo restituisce insieme a signature_header, timestamp_header, signature_scheme e replay_tolerance_seconds. Calcola l'HMAC sul corpo consegnato e confrontalo con l'header della firma. Usa rotate_webhook_secret per invalidare il vecchio secret, e retry_ingest_webhook(job_id) per rispedire la notifica di un job completato.