github xberg-io/xberg v1.2.3

latest releases: packages/go/v1.2.3, packages/go/v1/v1.2.3
9 hours ago

Added

  • (ocr): the registry reports each backend's declared languages. list_ocr_backends() returned
    only names, so a caller validating an OCR language against the installed backends had to maintain
    a second language table of its own. list_ocr_backend_capabilities() returns one
    OcrBackendCapabilities record per registered backend — its name and the languages it reports —
    ordered by backend name. An empty supported_languages means the backend does not enumerate its
    languages, not that it supports none, so ocr_backend_supports_language() is provided for
    callers that need a decision rather than a list. (GH#1643)
  • (ocr): mixed-page PDF extraction reports one coordinate frame per OCR'd page. Public
    ocr_elements carry the OCR backend's raster coordinates, but the per-page processed raster size
    lived only in the page-local result and was discarded before the elements reached the final
    document. A multi-page consumer was left with the document-level
    ocr_processed_image_width/ocr_processed_image_height, which is not authoritative for pages of
    differing size, preprocessing, or rotation, and so could not normalize a box safely.
    metadata.additional.ocr_page_coordinate_frames now carries one record per OCR page that has
    public elements — page_number, width, height, unit: "pixel", origin: "top_left" — ordered
    by page number and joined to an element through the element's own page_number. No record is
    emitted for a page whose raster dimensions are absent or invalid. (GH#1645)
  • (ner): Rust callers can share xberg's process-wide GLiNER backend cache.
    text::ner::gline::get_or_init_backend performs model initialization on Tokio's blocking pool,
    returns the same Arc for the same model and thread budget, and leaves failed initializations
    retryable.
  • (pdf): every hierarchy page now advertises the coordinate frame its boxes live in. Hierarchy
    bounding boxes are emitted in raw PDF user space, but nothing named that space, so a consumer
    could not tell whether a box needed translating by a non-zero MediaBox origin or rotating for a
    page's /Rotate. metadata.additional.pdf_page_coordinate_frames now carries one record per
    page that has hierarchy blocks — page_number, origin_x/origin_y (the MediaBox llx/lly,
    which may be non-zero and negative), width/height, unit: "point",
    origin: "bottom_left", and clockwise_rotation — ordered by page number. width/height are
    the MediaBox extent and are deliberately not swapped for a 90/270 rotation, because they
    describe raw user space rather than the displayed frame; this is the opposite convention to
    ocr_page_coordinate_frames, which reports an already-rotated raster, so the two must not be
    assumed to agree for the same page. A page is omitted entirely, rather than reported with a
    default, when its /Rotate is present but not a valid multiple of 90 or its MediaBox yields no
    usable extent. (GH#1653, GH#1654)

Fixed

  • (ocr): an isolated blank quantity cell in an invoice table can be recovered from its own
    pixels.
    A table whose QTY column has strong integer support — at least two recognized
    whole-number quantities — but exactly one blank cell now gets a single targeted retry that
    re-reads only that cell's bounded pixel region in single-line segmentation mode. The retry never
    derives a quantity from a price or total column, and any table outside this narrow shape takes
    the existing fast path unchanged. A header split across two words (UNIT/PRICE,
    LINE/TOTAL) is also reassembled into one header cell when the fragment sits nearer a
    data-supported column than any standalone column of its own. This OCR quality change ships
    without a corpus-wide A/B measurement.
  • (reranker): a cancelled rerank_async no longer releases its concurrency permit while its
    inference is still running.
    The permit was held by the awaiting future rather than by the
    spawn_blocking task, and a blocking task cannot be cancelled — dropping its handle merely
    detaches it. A caller that timed out or dropped therefore returned the permit immediately while the
    model load and inference it was bounding continued, so repeated abandoned calls could exceed the
    configured reranker concurrency and keep several models resident after every caller had returned.
    (GH#1641)
  • (embeddings, transcription): the same cancelled-permit leak fixed above for the reranker is now
    fixed for embed_texts_async and audio/video transcription.
    Both bound a spawn_blocking
    inference call with a concurrency permit held by the awaiting future rather than by the blocking
    task, so a caller that dropped its future released the permit while the ONNX embedding batch or
    Whisper inference it was bounding kept running. Transcription is timeout-wrapped by default
    (transcription.timeout_ms), so an expiry there was a live, designed-in path to the same
    concurrency breach, not a hypothetical one. (GH#1641)
  • (pdf): a wrapped numbered heading set in a heading-size font no longer loses its second line.
    follows_section's two continuation exemptions only recognized a wrap via a hanging indent or via
    matching right edges, both of which a no-indent heading's short last line fails by construction. A
    third exemption, heading_continuation_at_margin, now recognizes a wrap by measuring the heading's
    own line against the width of the body column beneath it, the same signal the paragraph-merge pass
    already uses for a body-sized heading. Independently, the paragraph-gap detector could still cut a
    continuation these exemptions accepted, because a heading's own line pitch legitimately exceeds the
    body's and was read as a blank-line break; the gap check is now suppressed at exactly the boundary a
    continuation exemption already accepted. (GH#1650)
  • (packaging): the Helm chart is published again. The chart publish was gated such that a failed
    Docker build leg skipped it entirely, while the container images themselves published and the
    release still reported success. No chart was published for 1.1.4, 1.1.5, 1.2.0, 1.2.1 or 1.2.2, so
    helm install --version <current> could not resolve. The chart for 1.2.2 has been published
    retroactively, and a release now fails loudly if its chart is missing rather than shipping without
    one.
  • (node): a JavaScript plugin registered through the Node binding now actually runs. Every
    generated Node trait bridge -- OcrBackend, PostProcessor, Validator, Renderer,
    TokenizerBackend and the rest -- was structurally unable to call back into JavaScript. It
    invoked the JS callable directly from whatever Tokio worker thread the pipeline happened to be
    on, with no N-API handle scope; it never awaited a returned promise, so an async method's
    result was the string "[object Promise]"; and it coerced whatever came back to a string before
    parsing it as JSON, which fails for a plain object as well. The published .d.ts had always
    declared the working contract (processImage(imageBytes: Uint8Array): Promise<ExtractedDocument>),
    so no plugin could have been written against the shipped behaviour. Bridges now hold a
    ThreadsafeFunction created on the JS thread, await the reply through call_async_catch (a JS
    throw surfaces as a plugin error instead of aborting the process), and decode the value without
    the string round-trip. A handle reference that would otherwise be released off its owning JS
    thread is leaked rather than freed, since freeing it there corrupts the V8 heap. (GH#1636)

Changed

  • (pdf): a page whose MediaBox is not rooted at the origin no longer reports the wrong page
    size.
    The native engine's per-page text result took its width and height from the MediaBox
    upper-right corner instead of its extent, so a page with MediaBox [10 -100 622 692] reported
    622x692 rather than the true 612x792. That figure feeds hierarchy reading-order computation, so
    a non-zero MediaBox origin could mis-order content, not merely mis-scale it. Pages rooted at
    (0, 0) — the overwhelming majority — are unaffected, since the two expressions agree there.
    (GH#1653)

  • Upgraded the crawlberg dependency to 1.7.0 (from 1.6.4). xberg re-exports crawlberg's
    crawl types -- CrawlConfig, MapResult, SitemapUrl -- so the pin is part of this crate's
    public surface. 1.7.0 makes no Rust API changes; its breaking changes are confined to
    crawlberg's own Java and Swift bindings, which xberg does not consume.

Zig

Add to your build.zig.zon:

.dependencies = .{
    .xberg-zig = .{\n        .url = \"https://github.com/xberg-io/xberg/releases/download/v1.2.3/xberg-zig-v1.2.3.tar.gz\",\n        .hash = \"xberg-1.2.3-iV1GrgLORRm2zXRsxaZHWV8cdrQNfPRQsQCDMrPmDJrM\",\n    },\n},\n```\n

Don't miss a new xberg release

NewReleases is sending notifications on new releases.