Skip to content

Commit e6d326b

Browse files
✨ add support for Mindee Client V2 (#251)
1 parent f9fa1c6 commit e6d326b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+2197
-92
lines changed

.github/workflows/pull-request.yml

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,29 @@ name: Pull Request
33
on:
44
pull_request:
55

6+
permissions:
7+
contents: read
8+
pull-requests: read
9+
610
jobs:
711
static_analysis:
8-
uses: mindee/mindee-api-java/.github/workflows/_static-analysis.yml@main
12+
uses: ./.github/workflows/_static-analysis.yml
913
build:
10-
uses: mindee/mindee-api-java/.github/workflows/_build.yml@main
14+
uses: ./.github/workflows/_build.yml
1115
needs: static_analysis
1216
secrets: inherit
1317
codeql:
14-
uses: mindee/mindee-api-java/.github/workflows/_codeql.yml@main
18+
uses: ./.github/workflows/_codeql.yml
1519
needs: build
20+
permissions:
21+
contents: read
22+
actions: read
23+
security-events: write
1624
test_integrations:
17-
uses: mindee/mindee-api-java/.github/workflows/_test-integrations.yml@main
25+
uses: ./.github/workflows/_test-integrations.yml
1826
needs: build
1927
secrets: inherit
2028
test_code_samples:
21-
uses: mindee/mindee-api-java/.github/workflows/_test-code-samples.yml@main
29+
uses: ./.github/workflows/_test-code-samples.yml
2230
needs: build
2331
secrets: inherit

README.md

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -207,29 +207,6 @@ public class SimpleMindeeClient {
207207
}
208208
```
209209

210-
211-
## Further Reading
212-
Complete details on the working of the library are available in the following guides:
213-
214-
* [Getting started](https://developers.mindee.com/docs/java-ocr-getting-started)
215-
* [Java Generated APIs](https://developers.mindee.com/docs/java-generated-ocr)
216-
* [Java Custom APIs (API Builder - Deprecated)](https://developers.mindee.com/docs/java-api-builder)
217-
* [Java Invoice OCR](https://developers.mindee.com/docs/java-invoice-ocr)
218-
* [Java Receipt OCR](https://developers.mindee.com/docs/java-receipt-ocr)
219-
* [Java Financial Document OCR](https://developers.mindee.com/docs/java-financial-document-ocr)
220-
* [Java Passport OCR](https://developers.mindee.com/docs/java-passport-ocr)
221-
* [Java Resume OCR](https://developers.mindee.com/docs/java-resume-ocr)
222-
* [Java International Id OCR](https://developers.mindee.com/docs/java-international-id-ocr)
223-
* [Java FR Bank Account Detail OCR](https://developers.mindee.com/docs/java-fr-bank-account-details-ocr)
224-
* [Java FR Carte Grise OCR](https://developers.mindee.com/docs/java-fr-carte-grise-ocr)
225-
* [Java FR Health Card OCR](https://developers.mindee.com/docs/java-fr-health-card-ocr)
226-
* [Java FR ID Card OCR](https://developers.mindee.com/docs/java-fr-carte-nationale-didentite-ocr)
227-
* [Java US Bank Check OCR](https://developers.mindee.com/docs/java-us-bank-check-ocr)
228-
* [Java Barcode Reader API](https://developers.mindee.com/docs/java-barcode-reader-ocr)
229-
* [Java Cropper API](https://developers.mindee.com/docs/java-cropper-ocr)
230-
* [Java Invoice Splitter API](https://developers.mindee.com/docs/java-invoice-splitter-ocr)
231-
* [Java Multi Receipts Detector API](https://developers.mindee.com/docs/java-multi-receipts-detector-ocr)
232-
233210
You can view the source code on [GitHub](https://github.com/mindee/mindee-api-java).
234211

235212
You can also take a look at the

docs/code_samples/default_v2.txt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import com.mindee.MindeeClientV2;
2+
import com.mindee.InferenceParameters;
3+
import com.mindee.input.LocalInputSource;
4+
import com.mindee.parsing.v2.InferenceResponse;
5+
import java.io.File;
6+
import java.io.IOException;
7+
8+
public class SimpleMindeeClient {
9+
10+
public static void main(String[] args) throws IOException, InterruptedException {
11+
String apiKey = "MY_API_KEY";
12+
String filePath = "/path/to/the/file.ext";
13+
String modelId = "MY_MODEL_ID";
14+
15+
// Init a new client
16+
MindeeClientV2 mindeeClient = new MindeeClientV2(apiKey);
17+
18+
// Load a file from disk
19+
LocalInputSource inputSource = new LocalInputSource(new File(filePath));
20+
21+
// Prepare the enqueueing options
22+
// Note: modelId is mandatory.
23+
InferenceParameters options = InferenceParameters.builder(modelId).build();
24+
25+
// Parse the file
26+
InferenceResponse response = mindeeClient.enqueueAndGetInference(
27+
inputSource,
28+
options
29+
);
30+
31+
// Print a summary of the response
32+
System.out.println(response.getInference().toString());
33+
}
34+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package com.mindee;
2+
3+
import com.mindee.input.PageOptions;
4+
import java.util.Collections;
5+
import java.util.List;
6+
import java.util.Objects;
7+
import lombok.Data;
8+
import lombok.Getter;
9+
10+
/**
11+
* Options to pass when calling methods using the API V2.
12+
*/
13+
@Getter
14+
@Data
15+
public final class InferenceParameters {
16+
/**
17+
* ID of the model (required).
18+
*/
19+
private final String modelId;
20+
/**
21+
* Enables Retrieval-Augmented Generation (optional, default: {@code false}).
22+
*/
23+
private final boolean rag;
24+
/**
25+
* Optional alias for the file.
26+
*/
27+
private final String alias;
28+
/**
29+
* IDs of webhooks to propagate the API response to (may be empty).
30+
*/
31+
private final List<String> webhookIds;
32+
/*
33+
* Asynchronous polling options.
34+
*/
35+
private final AsyncPollingOptions pollingOptions;
36+
37+
/**
38+
* Create a new builder.
39+
*
40+
* @param modelId the mandatory model identifier
41+
* @return a fresh {@link Builder}
42+
*/
43+
public static Builder builder(String modelId) {
44+
return new Builder(modelId);
45+
}
46+
47+
/**
48+
* Fluent builder for {@link InferenceParameters}.
49+
*/
50+
public static final class Builder {
51+
52+
private final String modelId;
53+
private boolean rag = false;
54+
private String alias;
55+
private List<String> webhookIds = Collections.emptyList();
56+
private AsyncPollingOptions pollingOptions = AsyncPollingOptions.builder().build();
57+
58+
private Builder(String modelId) {
59+
this.modelId = Objects.requireNonNull(modelId, "modelId must not be null");
60+
}
61+
62+
/** Enable / disable Retrieval-Augmented Generation. */
63+
public Builder rag(boolean rag) {
64+
this.rag = rag;
65+
return this;
66+
}
67+
68+
/** Set an alias for the uploaded document. */
69+
public Builder alias(String alias) {
70+
this.alias = alias;
71+
return this;
72+
}
73+
74+
/** Provide IDs of webhooks to forward the API response to. */
75+
public Builder webhookIds(List<String> webhookIds) {
76+
this.webhookIds = webhookIds;
77+
return this;
78+
}
79+
80+
81+
public Builder pollingOptions(AsyncPollingOptions pollingOptions) {
82+
this.pollingOptions = pollingOptions;
83+
return this;
84+
}
85+
86+
/** Build an immutable {@link InferenceParameters} instance. */
87+
public InferenceParameters build() {
88+
return new InferenceParameters(
89+
modelId,
90+
rag,
91+
alias,
92+
webhookIds,
93+
pollingOptions
94+
);
95+
}
96+
}
97+
}

src/main/java/com/mindee/MindeeClient.java

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
*/
2828
public class MindeeClient {
2929

30+
protected PdfOperation pdfOperation;
3031
private final MindeeApi mindeeApi;
31-
private final PdfOperation pdfOperation;
3232

3333
/**
3434
* Create a default MindeeClient.
@@ -120,6 +120,28 @@ public <T extends Inference> AsyncPredictResponse<T> enqueue(
120120
null);
121121
}
122122

123+
/**
124+
* Retrieves the file after applying page operations to it.
125+
* @param localInputSource Local input source to apply operations to.
126+
* @param pageOptions Options to apply.
127+
* @return A byte array of the file after applying page operations.
128+
* @throws IOException Throws if the file can't be accessed.
129+
*/
130+
protected byte[] getSplitFile(
131+
LocalInputSource localInputSource,
132+
PageOptions pageOptions
133+
) throws IOException {
134+
byte[] splitFile;
135+
if (pageOptions == null || !localInputSource.isPdf()) {
136+
splitFile = localInputSource.getFile();
137+
} else {
138+
splitFile = pdfOperation.split(
139+
new SplitQuery(localInputSource.getFile(), pageOptions)
140+
).getFile();
141+
}
142+
return splitFile;
143+
}
144+
123145
/**
124146
* Send a local file to an async queue.
125147
* @param <T> Type of inference.
@@ -1124,19 +1146,4 @@ public <T extends Inference> AsyncPredictResponse<T> loadPrediction(
11241146
return objectMapper.readValue(localResponse.getFile(), parametricType);
11251147
}
11261148

1127-
private byte[] getSplitFile(
1128-
LocalInputSource localInputSource,
1129-
PageOptions pageOptions
1130-
) throws IOException {
1131-
byte[] splitFile;
1132-
if (pageOptions == null || !localInputSource.isPdf()) {
1133-
splitFile = localInputSource.getFile();
1134-
} else {
1135-
splitFile = pdfOperation.split(
1136-
new SplitQuery(localInputSource.getFile(), pageOptions)
1137-
).getFile();
1138-
}
1139-
return splitFile;
1140-
}
1141-
11421149
}
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package com.mindee;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import com.mindee.http.MindeeApiV2;
5+
import com.mindee.http.MindeeHttpApiV2;
6+
import com.mindee.http.MindeeHttpExceptionV2;
7+
import com.mindee.input.LocalInputSource;
8+
import com.mindee.input.LocalResponse;
9+
import com.mindee.parsing.v2.ErrorResponse;
10+
import com.mindee.parsing.v2.InferenceResponse;
11+
import com.mindee.parsing.v2.JobResponse;
12+
import java.io.IOException;
13+
14+
/**
15+
* Entry point for the Mindee **V2** API features.
16+
*/
17+
public class MindeeClientV2 {
18+
private final MindeeApiV2 mindeeApi;
19+
20+
/** Uses an API-key read from the environment variables. */
21+
public MindeeClientV2() {
22+
this(createDefaultApiV2(""));
23+
}
24+
25+
/** Uses the supplied API-key. */
26+
public MindeeClientV2(String apiKey) {
27+
this(createDefaultApiV2(apiKey));
28+
}
29+
30+
31+
/** Inject both a PDF implementation and a HTTP implementation. */
32+
public MindeeClientV2(MindeeApiV2 mindeeApi) {
33+
this.mindeeApi = mindeeApi;
34+
}
35+
36+
/**
37+
* Enqueue a document in the asynchronous queue.
38+
*/
39+
public JobResponse enqueueInference(
40+
LocalInputSource inputSource,
41+
InferenceParameters params) throws IOException {
42+
return mindeeApi.reqPostInferenceEnqueue(inputSource, params);
43+
}
44+
45+
/**
46+
* Get the status of an inference that was previously enqueued.
47+
* Can be used for polling.
48+
*/
49+
public JobResponse getJob(String jobId) {
50+
if (jobId == null || jobId.trim().isEmpty()) {
51+
throw new IllegalArgumentException("jobId must not be null or blank.");
52+
}
53+
return mindeeApi.reqGetJob(jobId);
54+
}
55+
56+
/**
57+
* Get the result of an inference that was previously enqueued.
58+
* The inference will only be available after it has finished processing.
59+
*/
60+
public InferenceResponse getInference(String inferenceId) {
61+
if (inferenceId == null || inferenceId.trim().isEmpty()) {
62+
throw new IllegalArgumentException("inferenceId must not be null or blank.");
63+
}
64+
65+
return mindeeApi.reqGetInference(inferenceId);
66+
}
67+
68+
/**
69+
* Send a local file to an async queue, poll, and parse when complete.
70+
* @param inputSource The input source to send.
71+
* @param options The options to send along with the file.
72+
* @return an instance of {@link InferenceResponse}.
73+
* @throws IOException Throws if the file can't be accessed.
74+
* @throws InterruptedException Throws if the thread is interrupted.
75+
*/
76+
public InferenceResponse enqueueAndGetInference(
77+
LocalInputSource inputSource,
78+
InferenceParameters options) throws IOException, InterruptedException {
79+
80+
validatePollingOptions(options.getPollingOptions());
81+
82+
JobResponse job = enqueueInference(inputSource, options);
83+
84+
Thread.sleep((long) (options.getPollingOptions().getInitialDelaySec() * 1000));
85+
JobResponse resp = job;
86+
int attempts = 0;
87+
int max = options.getPollingOptions().getMaxRetries();
88+
while (attempts < max) {
89+
Thread.sleep((long) (options.getPollingOptions().getIntervalSec() * 1000));
90+
resp = getJob(job.getJob().getId());
91+
if (resp.getJob().getStatus().equals("Failed")) {
92+
break;
93+
}
94+
else if (resp.getJob().getStatus().equals("Processed")) {
95+
return getInference(resp.getJob().getId());
96+
}
97+
attempts++;
98+
}
99+
ErrorResponse error = resp.getJob().getError();
100+
if (error != null) {
101+
throw new MindeeHttpExceptionV2(error.getStatus(), error.getDetail());
102+
}
103+
throw new RuntimeException("Max retries exceeded (" + max + ").");
104+
}
105+
106+
/**
107+
* Deserialize a webhook payload (or any saved response) into an
108+
* {@link InferenceResponse}.
109+
*/
110+
public InferenceResponse loadInference(LocalResponse localResponse) throws IOException {
111+
ObjectMapper mapper = new ObjectMapper().findAndRegisterModules();
112+
InferenceResponse model =
113+
mapper.readValue(localResponse.getFile(), InferenceResponse.class);
114+
model.setRawResponse(localResponse.toString());
115+
return model;
116+
}
117+
118+
private static MindeeApiV2 createDefaultApiV2(String apiKey) {
119+
MindeeSettingsV2 settings = apiKey == null || apiKey.trim().isEmpty()
120+
? new MindeeSettingsV2()
121+
: new MindeeSettingsV2(apiKey);
122+
return MindeeHttpApiV2.builder()
123+
.mindeeSettings(settings)
124+
.build();
125+
}
126+
127+
private static void validatePollingOptions(AsyncPollingOptions p) {
128+
if (p.getInitialDelaySec() < 1) {
129+
throw new IllegalArgumentException("Initial delay must be ≥ 1 s");
130+
}
131+
if (p.getIntervalSec() < 1) {
132+
throw new IllegalArgumentException("Interval must be ≥ 1 s");
133+
}
134+
if (p.getMaxRetries() < 2) {
135+
throw new IllegalArgumentException("Max retries must be ≥ 2");
136+
}
137+
}
138+
}

0 commit comments

Comments
 (0)