Skip to content

Commit 315eec7

Browse files
committed
feat: Add Async support
Signed-off-by: Andrea Cosentino <[email protected]>
1 parent d3239d3 commit 315eec7

File tree

8 files changed

+476
-1
lines changed

8 files changed

+476
-1
lines changed

docling-serve/docling-serve-api/src/main/java/ai/docling/serve/api/DoclingServeApi.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,58 @@
11
package ai.docling.serve.api;
22

3+
import ai.docling.serve.api.async.response.ConversionStatus;
4+
import ai.docling.serve.api.async.response.TaskResponse;
5+
import ai.docling.serve.api.convert.request.ConvertDocumentRequest;
6+
import ai.docling.serve.api.convert.response.ConvertDocumentResponse;
7+
38
/**
49
* Docling Serve API interface.
510
*/
611
public interface DoclingServeApi
712
extends DoclingServeHealthApi, DoclingServeConvertApi, DoclingServeChunkApi, DoclingServeClearApi, DoclingServeTaskApi {
13+
/**
14+
* Initiates an asynchronous conversion of the provided document source(s).
15+
*
16+
* <p>This method starts a background conversion task and immediately returns a task ID
17+
* that can be used to poll the status and retrieve results when the conversion completes.
18+
*
19+
* @param request the {@link ConvertDocumentRequest} containing the source(s) and conversion options.
20+
* @return a {@link TaskResponse} containing the task ID for tracking the async operation.
21+
*/
22+
TaskResponse convertSourceAsync(ConvertDocumentRequest request);
23+
24+
/**
25+
* Checks the status of an asynchronous conversion task.
26+
*
27+
* @param taskId the task ID returned from {@link #convertSourceAsync(ConvertDocumentRequest)}
28+
* @return a {@link ConversionStatus} object with the current status of the task
29+
*/
30+
ConversionStatus checkConversionStatus(String taskId);
31+
32+
/**
33+
* Retrieves the result of a completed asynchronous conversion task.
34+
*
35+
* @param taskId the task ID returned from {@link #convertSourceAsync(ConvertDocumentRequest)}
36+
* @return a {@link ConvertDocumentResponse} containing the conversion result
37+
*/
38+
ConvertDocumentResponse getConversionResult(String taskId);
39+
40+
/**
41+
* Initiates an asynchronous conversion and waits for it to complete by polling.
42+
*
43+
* <p>This is a convenience method that combines {@link #convertSourceAsync(ConvertDocumentRequest)},
44+
* status polling via {@link #checkConversionStatus(String)}, and result retrieval via
45+
* {@link #getConversionResult(String)} into a single operation.
46+
*
47+
* <p>The method will poll the task status at the configured interval until the task completes,
48+
* fails, or the configured timeout is reached.
49+
*
50+
* @param request the {@link ConvertDocumentRequest} containing the source(s) and conversion options.
51+
* @return a {@link ConvertDocumentResponse} containing the processed document data
52+
* @throws RuntimeException if the conversion fails, times out, or is interrupted
53+
*/
54+
ConvertDocumentResponse convertSourceAsyncAndWait(ConvertDocumentRequest request);
55+
856
/**
957
* Creates and returns a builder instance capable of constructing a duplicate or modified
1058
* version of the current API instance. The builder provides a customizable way to adjust
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package ai.docling.serve.api.async.response;
2+
3+
import org.jspecify.annotations.Nullable;
4+
5+
import com.fasterxml.jackson.annotation.JsonInclude;
6+
7+
/**
8+
* Represents the status of an asynchronous document conversion task.
9+
*
10+
* <p>This class contains information about the current state of an async conversion,
11+
* including the task ID, current status, result (if completed), error message (if failed),
12+
* and optional progress information.
13+
*
14+
* <p>Serialization uses {@link JsonInclude.Include#NON_EMPTY} so nulls and empty strings
15+
* are omitted from JSON.</p>
16+
*/
17+
@JsonInclude(JsonInclude.Include.NON_EMPTY)
18+
@tools.jackson.databind.annotation.JsonDeserialize(builder = ConversionStatus.Builder.class)
19+
@lombok.extern.jackson.Jacksonized
20+
@lombok.Builder(toBuilder = true)
21+
@lombok.Getter
22+
@lombok.ToString
23+
public class ConversionStatus {
24+
25+
/**
26+
* Enum representing the possible states of a conversion task.
27+
*/
28+
public enum Status {
29+
/** Task is waiting to be processed */
30+
PENDING,
31+
/** Task is currently being processed */
32+
IN_PROGRESS,
33+
/** Task has completed successfully */
34+
COMPLETED,
35+
/** Task has failed */
36+
FAILED,
37+
/** Task status is unknown */
38+
UNKNOWN
39+
}
40+
41+
private String taskId;
42+
43+
private Status status;
44+
45+
@Nullable
46+
private String result;
47+
48+
@Nullable
49+
private String errorMessage;
50+
51+
@Nullable
52+
private Integer progress;
53+
54+
/**
55+
* Checks if the conversion has completed successfully.
56+
*
57+
* @return true if status is COMPLETED, false otherwise
58+
*/
59+
public boolean isCompleted() {
60+
return status == Status.COMPLETED;
61+
}
62+
63+
/**
64+
* Checks if the conversion has failed.
65+
*
66+
* @return true if status is FAILED, false otherwise
67+
*/
68+
public boolean isFailed() {
69+
return status == Status.FAILED;
70+
}
71+
72+
/**
73+
* Checks if the conversion is still in progress.
74+
*
75+
* @return true if status is IN_PROGRESS or PENDING, false otherwise
76+
*/
77+
public boolean isInProgress() {
78+
return status == Status.IN_PROGRESS || status == Status.PENDING;
79+
}
80+
81+
@tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "")
82+
public static class Builder { }
83+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package ai.docling.serve.api.async.response;
2+
3+
import org.jspecify.annotations.Nullable;
4+
5+
import com.fasterxml.jackson.annotation.JsonInclude;
6+
import com.fasterxml.jackson.annotation.JsonProperty;
7+
8+
/**
9+
* Response from polling the status of an asynchronous conversion task.
10+
*
11+
* <p>This class contains the current status of the task as returned by the server.
12+
*
13+
* <p>Serialization uses {@link JsonInclude.Include#NON_EMPTY} so nulls and empty strings
14+
* are omitted from JSON.</p>
15+
*/
16+
@JsonInclude(JsonInclude.Include.NON_EMPTY)
17+
@tools.jackson.databind.annotation.JsonDeserialize(builder = StatusResponse.Builder.class)
18+
@lombok.extern.jackson.Jacksonized
19+
@lombok.Builder(toBuilder = true)
20+
@lombok.Getter
21+
@lombok.ToString
22+
public class StatusResponse {
23+
@JsonProperty("task_id")
24+
@Nullable
25+
private String taskId;
26+
27+
@JsonProperty("task_status")
28+
@Nullable
29+
private String taskStatus;
30+
31+
@JsonProperty("task_position")
32+
@Nullable
33+
private Integer taskPosition;
34+
35+
@JsonProperty("task_meta")
36+
@Nullable
37+
private TaskMeta taskMeta;
38+
39+
/**
40+
* Metadata about the task, including error information if the task failed.
41+
*/
42+
@JsonInclude(JsonInclude.Include.NON_EMPTY)
43+
@tools.jackson.databind.annotation.JsonDeserialize(builder = TaskMeta.Builder.class)
44+
@lombok.extern.jackson.Jacksonized
45+
@lombok.Builder(toBuilder = true)
46+
@lombok.Getter
47+
@lombok.ToString
48+
public static class TaskMeta {
49+
@JsonProperty("error")
50+
@Nullable
51+
private String error;
52+
53+
@tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "")
54+
public static class Builder { }
55+
}
56+
57+
@tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "")
58+
public static class Builder { }
59+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package ai.docling.serve.api.async.response;
2+
3+
import com.fasterxml.jackson.annotation.JsonInclude;
4+
import com.fasterxml.jackson.annotation.JsonProperty;
5+
6+
/**
7+
* Response from initiating an asynchronous conversion task.
8+
*
9+
* <p>This class contains the task ID returned by the server when starting
10+
* an async conversion operation.
11+
*
12+
* <p>Serialization uses {@link JsonInclude.Include#NON_EMPTY} so nulls and empty strings
13+
* are omitted from JSON.</p>
14+
*/
15+
@JsonInclude(JsonInclude.Include.NON_EMPTY)
16+
@tools.jackson.databind.annotation.JsonDeserialize(builder = TaskResponse.Builder.class)
17+
@lombok.extern.jackson.Jacksonized
18+
@lombok.Builder(toBuilder = true)
19+
@lombok.Getter
20+
@lombok.ToString
21+
public class TaskResponse {
22+
@JsonProperty("task_id")
23+
private String taskId;
24+
25+
@tools.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "")
26+
public static class Builder { }
27+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/**
2+
* Response models for asynchronous document conversion operations.
3+
*
4+
* <p>This package contains the response classes used when working with
5+
* async conversion endpoints in the Docling Serve API.
6+
*/
7+
package ai.docling.serve.api.async.response;

docling-serve/docling-serve-api/src/main/java/module-info.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
// Auth
1818
exports ai.docling.serve.api.auth;
1919

20+
// Async API
21+
exports ai.docling.serve.api.async.response;
22+
2023
// Chunking API
2124
exports ai.docling.serve.api.chunk.request;
2225
exports ai.docling.serve.api.chunk.request.options;

0 commit comments

Comments
 (0)