Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ switch(result.getResponseType()) {
case ResponseType.IN_BODY -> // Response is InBodyConvertDocumentResponse
case ResponseType.ZIP_ARCHIVE -> // Response is ZipArchiveConvertDocumentResponse
case ResponseType.PRE_SIGNED_URL -> // Response is PreSignedUrlConvertDocumentResponse
case ResponseType.PRE_SIGNED_URL_RESPONSE -> // Response is PreSignedUrlConvertResponse (with per-document artifact download URLs)
}
```
More [usage information](https://docling-project.github.io/docling-java) is available in the docs.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package ai.docling.serve.api.convert.request.target;

import com.fasterxml.jackson.annotation.JsonInclude;

/**
* Target for delivering the converted document via server-managed presigned URLs.
*
* <p>This is a concrete implementation of {@link Target}, where the {@code Kind} is set to
* {@link Kind#PRESIGNED_URL}. The docling-serve instance uploads each output artifact to its
* own configured object storage bucket and returns time-limited presigned GET URLs in the
* response.
*
* <p>Available in docling-serve {@code v1.22.0} and later.
*
* <p>Uses JSON serialization annotations to include only non-empty fields in the output.
*
* <p>This class overrides {@link Object#toString()} for a string representation of the instance.
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@tools.jackson.databind.annotation.JsonDeserialize(builder = PresignedUrlTarget.Builder.class)
@lombok.extern.jackson.Jacksonized
@lombok.Builder(toBuilder = true)
@lombok.Getter
@lombok.ToString
public final class PresignedUrlTarget extends Target {

Comment thread
edeandrea marked this conversation as resolved.
/**
* Builder for creating {@link PresignedUrlTarget} instances.
* Generated by Lombok's {@code @Builder} annotation.
*/
@tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "")
public static class Builder { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
* Represents an abstract target for defining where and how the converted document should be delivered.
*
* <p>The {@link Target} class is a sealed type that is extended by specific concrete implementations:
* {@link InBodyTarget}, {@link PutTarget}, {@link S3Target}, and {@link ZipTarget}. These implementations specify different
* delivery methods, such as including the document in the response body, sending it to a specified URI, or
* zipping it for inclusion in the response.
* {@link InBodyTarget}, {@link PresignedUrlTarget}, {@link PutTarget}, {@link S3Target}, and
* {@link ZipTarget}. These implementations specify different delivery methods, such as
* including the document in the response body, sending it to a specified URI, zipping it for
* inclusion in the response, or returning server-managed presigned URLs that point at the
* docling-serve operator's object storage.
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonTypeInfo(
Expand All @@ -22,15 +24,17 @@
)
@JsonSubTypes({
@Type(value = InBodyTarget.class, name = "inbody"),
@Type(value = PresignedUrlTarget.class, name = "presigned_url"),
@Type(value = PutTarget.class, name = "put"),
@Type(value = ZipTarget.class, name = "zip"),
@Type(value = S3Target.class, name = "s3")
})
@lombok.Getter
@lombok.ToString
public abstract sealed class Target permits InBodyTarget, PutTarget, S3Target, ZipTarget {
public abstract sealed class Target permits InBodyTarget, PresignedUrlTarget, PutTarget, S3Target, ZipTarget {
enum Kind {
@JsonProperty("inbody") INBODY,
@JsonProperty("presigned_url") PRESIGNED_URL,
@JsonProperty("put") PUT,
@JsonProperty("zip") ZIP,
@JsonProperty("s3") S3
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package ai.docling.serve.api.convert.response;

import java.net.URI;
import java.time.Instant;

import org.jspecify.annotations.Nullable;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

import ai.docling.serve.api.serialization.Jackson2InstantDeserializer;
import ai.docling.serve.api.serialization.Jackson2InstantSerializer;
import ai.docling.serve.api.serialization.Jackson3InstantDeserializer;
import ai.docling.serve.api.serialization.Jackson3InstantSerializer;

/**
* Represents a reference to a single output artifact returned as a presigned URL.
*
* <p>Serialization uses {@link JsonInclude.Include#NON_EMPTY}, so nulls and empty
* fields are omitted from JSON output.</p>
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@tools.jackson.databind.annotation.JsonDeserialize(builder = ArtifactRef.Builder.class)
@lombok.extern.jackson.Jacksonized
@lombok.Builder(toBuilder = true)
@lombok.Getter
@lombok.ToString
public class ArtifactRef {

/**
* Export format of the artifact.
*
* @param artifactType the artifact type
* @return the artifact type
*/
@JsonProperty("artifact_type")
@lombok.NonNull
private ArtifactType artifactType;

/**
* MIME type of the artifact content.
*
* @param mimeType the MIME type
* @return the MIME type
*/
@JsonProperty("mime_type")
@lombok.NonNull
private String mimeType;

/**
* Presigned URL used to download the artifact.
*
* @param uri the presigned URL
* @return the presigned URL
*/
@JsonProperty("uri")
@lombok.NonNull
private URI uri;

/**
* Instant at which the presigned URL signature stops being valid.
*
* @param urlExpiresAt the expiry timestamp
* @return the expiry timestamp
*/
@JsonProperty("url_expires_at")
@JsonSerialize(using = Jackson2InstantSerializer.class)
@JsonDeserialize(using = Jackson2InstantDeserializer.class)
@tools.jackson.databind.annotation.JsonSerialize(using = Jackson3InstantSerializer.class)
@tools.jackson.databind.annotation.JsonDeserialize(using = Jackson3InstantDeserializer.class)
@Nullable
private Instant urlExpiresAt;

/**
* Builder for creating {@link ArtifactRef} instances.
* Generated by Lombok's {@code @Builder} annotation.
*
* <p>Builder methods:
* <ul>
* <li>{@code artifactType(ArtifactType)} - Set the artifact type</li>
* <li>{@code mimeType(String)} - Set the MIME type</li>
* <li>{@code uri(URI)} - Set the presigned URL</li>
* <li>{@code urlExpiresAt(Instant)} - Set the expiry timestamp</li>
* </ul>
*/
@tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "")
public static class Builder { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package ai.docling.serve.api.convert.response;

import com.fasterxml.jackson.annotation.JsonProperty;

/**
* Represents the output format of a converted-document artifact.
*
* <ul>
* <li>{@code JSON}: Serialized {@code DoclingDocument} JSON.</li>
* <li>{@code HTML}: HTML rendering of the document.</li>
* <li>{@code MARKDOWN}: Markdown rendering of the document.</li>
* <li>{@code TEXT}: Plain-text rendering of the document.</li>
* <li>{@code DOCTAGS}: DocTags rendering of the document.</li>
* <li>{@code RESOURCE_BUNDLE}: ZIP archive containing extracted images and supporting resources.</li>
* </ul>
*/
public enum ArtifactType {
@JsonProperty("json") JSON,
@JsonProperty("html") HTML,
@JsonProperty("markdown") MARKDOWN,
@JsonProperty("text") TEXT,
@JsonProperty("doctags") DOCTAGS,
@JsonProperty("resource_bundle") RESOURCE_BUNDLE;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package ai.docling.serve.api.convert.response;

import com.fasterxml.jackson.annotation.JsonProperty;

/**
* Represents the possible conversion outcomes for a document.
*
* <ul>
* <li>{@code PENDING}: Indicates that the conversion has not yet started.</li>
* <li>{@code STARTED}: Indicates that the conversion is currently in progress.</li>
* <li>{@code SUCCESS}: Indicates that all pages of the document were converted.</li>
* <li>{@code PARTIAL_SUCCESS}: Indicates that some pages were converted and others failed.</li>
* <li>{@code FAILURE}: Indicates that the document could not be converted.</li>
* <li>{@code SKIPPED}: Indicates that the document was rejected at admission.</li>
* </ul>
*/
public enum ConversionStatus {
@JsonProperty("pending") PENDING,
@JsonProperty("started") STARTED,
@JsonProperty("success") SUCCESS,
@JsonProperty("partial_success") PARTIAL_SUCCESS,
@JsonProperty("failure") FAILURE,
@JsonProperty("skipped") SKIPPED;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,24 @@

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

import ai.docling.serve.api.serialization.Jackson2ConvertDocumentResponseDeserializer;
import ai.docling.serve.api.serialization.Jackson3ConvertDocumentResponseDeserializer;

/**
* Abstract response returned by the Convert API for a single conversion request.
*
* <p>Deserialization uses explicit custom deserializers that dispatch to the correct
* concrete subtype based on distinguishing JSON fields.</p>
*
* <p>Serialization uses {@link JsonInclude.Include#NON_EMPTY}, so nulls and empty
* collections/strings are omitted from JSON output.</p>
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonTypeInfo(
use = JsonTypeInfo.Id.DEDUCTION
)
@JsonSubTypes({
@JsonSubTypes.Type(InBodyConvertDocumentResponse.class),
@JsonSubTypes.Type(PreSignedUrlConvertDocumentResponse.class),
@JsonSubTypes.Type(ZipArchiveConvertDocumentResponse.class)
})
@com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = Jackson2ConvertDocumentResponseDeserializer.class)
@tools.jackson.databind.annotation.JsonDeserialize(using = Jackson3ConvertDocumentResponseDeserializer.class)
Comment thread
edeandrea marked this conversation as resolved.
public abstract sealed class ConvertDocumentResponse permits InBodyConvertDocumentResponse, PreSignedUrlConvertDocumentResponse,
ZipArchiveConvertDocumentResponse {
PreSignedUrlConvertResponse, ZipArchiveConvertDocumentResponse {
/**
* Type of response
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package ai.docling.serve.api.convert.response;

import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.Nulls;

/**
* Represents the conversion outcome and artifact references for a single source document.
*
* <p>Serialization uses {@link JsonInclude.Include#NON_EMPTY}, so nulls and empty
* collections are omitted from JSON output.</p>
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@tools.jackson.databind.annotation.JsonDeserialize(builder = DocumentArtifactItem.Builder.class)
@lombok.extern.jackson.Jacksonized
@lombok.Builder(toBuilder = true)
@lombok.Getter
@lombok.ToString
public class DocumentArtifactItem {

/**
* Zero-based index of the source document within the originating task.
*
* @param sourceIndex the source index
* @return the source index
*/
@JsonProperty("source_index")
private Integer sourceIndex;
Comment thread
edeandrea marked this conversation as resolved.

/**
* Canonical identifier of the source document.
*
* @param sourceUri the source URI
* @return the source URI
*/
@JsonProperty("source_uri")
@lombok.NonNull
private String sourceUri;

/**
* Filename used as the stem of each output artifact.
*
* @param filename the source filename
* @return the source filename
*/
@JsonProperty("filename")
@lombok.NonNull
private String filename;

/**
* Terminal conversion outcome for this document.
*
* @param status the conversion status
* @return the conversion status
*/
@JsonProperty("status")
@lombok.NonNull
private ConversionStatus status;

/**
* Errors encountered while converting this document.
*
* @param errors the list of errors
* @return the list of errors
*/
@JsonProperty("errors")
@JsonSetter(nulls = Nulls.AS_EMPTY)
@lombok.Singular
private List<ErrorItem> errors;

/**
* Per-stage timing breakdown keyed by stage name.
*
* @param timings the timings map
* @return the timings map
*/
@JsonProperty("timings")
@JsonSetter(nulls = Nulls.AS_EMPTY)
@lombok.Singular
private Map<String, ProfilingItem> timings;

/**
* Presigned URLs for each requested output format.
*
* @param artifacts the list of artifact references
* @return the list of artifact references
*/
@JsonProperty("artifacts")
@JsonSetter(nulls = Nulls.AS_EMPTY)
@lombok.Singular
private List<ArtifactRef> artifacts;

/**
* Builder for creating {@link DocumentArtifactItem} instances.
* Generated by Lombok's {@code @Builder} annotation.
*
* <p>Builder methods:
* <ul>
* <li>{@code sourceIndex(Integer)} - Set the source index</li>
* <li>{@code sourceUri(String)} - Set the source URI</li>
* <li>{@code filename(String)} - Set the source filename</li>
* <li>{@code status(ConversionStatus)} - Set the conversion status</li>
* <li>{@code errors(List<ErrorItem>)} - Set the list of errors</li>
* <li>{@code error(ErrorItem)} - Add a single error (use with @Singular)</li>
* <li>{@code timings(Map<String, ProfilingItem>)} - Set the timings map</li>
* <li>{@code timing(String, ProfilingItem)} - Add a single timing entry (use with @Singular)</li>
* <li>{@code artifacts(List<ArtifactRef>)} - Set the list of artifact references</li>
* <li>{@code artifact(ArtifactRef)} - Add a single artifact reference (use with @Singular)</li>
* </ul>
*/
@tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "")
public static class Builder { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ public final class PreSignedUrlConvertDocumentResponse extends ConvertDocumentRe
@JsonProperty("num_succeeded")
private Integer numSucceeded;

/**
* Number of partial successes
*
* @param numPartiallySucceeded the number of partial successes
* @return the number of partial successes
*/
@JsonProperty("num_partially_succeeded")
private Integer numPartiallySucceeded;
Comment thread
edeandrea marked this conversation as resolved.

/**
* Number of failed conversions
*
Expand All @@ -84,6 +93,7 @@ public ResponseType getResponseType() {
* <li>{@code processingTime(Double)} - Set the total processing time in seconds</li>
* <li>{@code numConverted(Integer)} - Set the number of attempted conversions</li>
* <li>{@code numSucceeded(Integer)} - Set the number of successful conversions</li>
* <li>{@code numPartiallySucceeded(Integer)} - Set the number of partial successes</li>
* <li>{@code numFailed(Integer)} - Set the number of failed conversions</li>
* </ul>
*/
Expand Down
Loading
Loading