Skip to content

Commit bf178f6

Browse files
✨ add support for url input source + fix typing for SimpleField (#257)
1 parent f5cdb31 commit bf178f6

File tree

10 files changed

+161
-31
lines changed

10 files changed

+161
-31
lines changed

src/main/java/com/mindee/MindeeClientV2.java

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.mindee.http.MindeeHttpExceptionV2;
77
import com.mindee.input.LocalInputSource;
88
import com.mindee.input.LocalResponse;
9+
import com.mindee.input.URLInputSource;
910
import com.mindee.parsing.v2.ErrorResponse;
1011
import com.mindee.parsing.v2.InferenceResponse;
1112
import com.mindee.parsing.v2.JobResponse;
@@ -42,6 +43,16 @@ public JobResponse enqueueInference(
4243
return mindeeApi.reqPostInferenceEnqueue(inputSource, params);
4344
}
4445

46+
47+
/**
48+
* Enqueue a document in the asynchronous queue.
49+
*/
50+
public JobResponse enqueueInference(
51+
URLInputSource inputSource,
52+
InferenceParameters params) throws IOException {
53+
return mindeeApi.reqPostInferenceEnqueue(inputSource, params);
54+
}
55+
4556
/**
4657
* Get the status of an inference that was previously enqueued.
4758
* Can be used for polling.
@@ -78,24 +89,57 @@ public InferenceResponse enqueueAndGetInference(
7889
InferenceParameters options) throws IOException, InterruptedException {
7990

8091
validatePollingOptions(options.getPollingOptions());
92+
JobResponse job = enqueueInference(inputSource, options);
93+
return pollAndFetch(job, options);
94+
}
95+
96+
97+
98+
/**
99+
* Send a local file to an async queue, poll, and parse when complete.
100+
* @param inputSource The input source to send.
101+
* @param options The options to send along with the file.
102+
* @return an instance of {@link InferenceResponse}.
103+
* @throws IOException Throws if the file can't be accessed.
104+
* @throws InterruptedException Throws if the thread is interrupted.
105+
*/
106+
public InferenceResponse enqueueAndGetInference(
107+
URLInputSource inputSource,
108+
InferenceParameters options) throws IOException, InterruptedException {
81109

110+
validatePollingOptions(options.getPollingOptions());
82111
JobResponse job = enqueueInference(inputSource, options);
112+
return pollAndFetch(job, options);
113+
}
83114

115+
116+
/**
117+
* Common logic for polling an asynchronous job for local & url files.
118+
* @param initialJob The initial job response.
119+
* @return an instance of {@link InferenceResponse}.
120+
* @throws InterruptedException Throws if interrupted.
121+
*/
122+
private InferenceResponse pollAndFetch(JobResponse initialJob,
123+
InferenceParameters options) throws InterruptedException {
84124
Thread.sleep((long) (options.getPollingOptions().getInitialDelaySec() * 1000));
85-
JobResponse resp = job;
125+
126+
JobResponse resp = initialJob;
86127
int attempts = 0;
87128
int max = options.getPollingOptions().getMaxRetries();
129+
88130
while (attempts < max) {
89131
Thread.sleep((long) (options.getPollingOptions().getIntervalSec() * 1000));
90-
resp = getJob(job.getJob().getId());
132+
resp = getJob(initialJob.getJob().getId());
133+
91134
if (resp.getJob().getStatus().equals("Failed")) {
92-
break;
135+
attempts = max;
93136
}
94-
else if (resp.getJob().getStatus().equals("Processed")) {
137+
if (resp.getJob().getStatus().equals("Processed")) {
95138
return getInference(resp.getJob().getId());
96139
}
97140
attempts++;
98141
}
142+
99143
ErrorResponse error = resp.getJob().getError();
100144
if (error != null) {
101145
throw new MindeeHttpExceptionV2(error.getStatus(), error.getDetail());

src/main/java/com/mindee/http/MindeeApiV2.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.mindee.InferenceParameters;
44
import com.mindee.input.LocalInputSource;
5+
import com.mindee.input.URLInputSource;
56
import com.mindee.parsing.v2.InferenceResponse;
67
import com.mindee.parsing.v2.JobResponse;
78
import java.io.IOException;
@@ -11,22 +12,36 @@
1112
*/
1213
public abstract class MindeeApiV2 extends MindeeApiCommon {
1314
/**
14-
* Send a file to the prediction queue.
15+
* Send a file to the prediction queue with a local file.
16+
* @param inputSource Local input source from URL.
17+
* @param options parameters.
1518
*/
1619
public abstract JobResponse reqPostInferenceEnqueue(
1720
LocalInputSource inputSource,
1821
InferenceParameters options
1922
) throws IOException;
2023

24+
/**
25+
* Send a file to the prediction queue with a remote file.
26+
* @param inputSource Remote input source from URL.
27+
* @param options parameters.
28+
*/
29+
public abstract JobResponse reqPostInferenceEnqueue(
30+
URLInputSource inputSource,
31+
InferenceParameters options
32+
) throws IOException;
33+
2134
/**
2235
* Attempts to poll the queue.
36+
* @param jobId id of the job to get.
2337
*/
2438
public abstract JobResponse reqGetJob(
2539
String jobId
2640
);
2741

2842
/**
2943
* Retrieves the inference from a 302 redirect.
44+
* @param inferenceId ID of the inference to poll.
3045
*/
31-
abstract public InferenceResponse reqGetInference(String jobId);
46+
abstract public InferenceResponse reqGetInference(String inferenceId);
3247
}

src/main/java/com/mindee/http/MindeeHttpApiV2.java

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.mindee.MindeeException;
66
import com.mindee.MindeeSettingsV2;
77
import com.mindee.input.LocalInputSource;
8+
import com.mindee.input.URLInputSource;
89
import com.mindee.parsing.v2.CommonResponse;
910
import com.mindee.parsing.v2.ErrorResponse;
1011
import com.mindee.parsing.v2.InferenceResponse;
@@ -79,8 +80,52 @@ public JobResponse reqPostInferenceEnqueue(
7980
InferenceParameters options
8081
) {
8182
String url = this.mindeeSettings.getBaseUrl() + "/inferences/enqueue";
82-
HttpPost post = buildHttpPost(url, inputSource, options);
83+
HttpPost post = buildHttpPost(url, options);
8384

85+
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
86+
builder.setMode(HttpMultipartMode.EXTENDED);
87+
builder.addBinaryBody(
88+
"file",
89+
inputSource.getFile(),
90+
ContentType.DEFAULT_BINARY,
91+
inputSource.getFilename()
92+
);
93+
post.setEntity(buildHttpBody(builder, options));
94+
return executeEnqueue(post);
95+
}
96+
97+
98+
/**
99+
* Enqueues a doc with the POST method.
100+
*
101+
* @param inputSource Input source to send.
102+
* @param options Options to send the file along with.
103+
* @return A job response.
104+
*/
105+
@Override
106+
public JobResponse reqPostInferenceEnqueue(
107+
URLInputSource inputSource,
108+
InferenceParameters options
109+
) {
110+
String url = this.mindeeSettings.getBaseUrl() + "/inferences/enqueue";
111+
HttpPost post = buildHttpPost(url, options);
112+
113+
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
114+
builder.setMode(HttpMultipartMode.EXTENDED);
115+
builder.addTextBody(
116+
"url",
117+
inputSource.getUrl()
118+
);
119+
post.setEntity(buildHttpBody(builder, options));
120+
return executeEnqueue(post);
121+
}
122+
123+
/**
124+
* Executes an enqueue action, common to URL & local inputs.
125+
* @param post HTTP Post object.
126+
* @return a valid job response.
127+
*/
128+
private JobResponse executeEnqueue(HttpPost post) {
84129
mapper.findAndRegisterModules();
85130
try (CloseableHttpClient httpClient = httpClientBuilder.build()) {
86131
return httpClient.execute(
@@ -146,9 +191,9 @@ public JobResponse reqGetJob(
146191
}
147192

148193
@Override
149-
public InferenceResponse reqGetInference(String jobId) {
194+
public InferenceResponse reqGetInference(String inferenceId) {
150195

151-
String url = this.mindeeSettings.getBaseUrl() + "/inferences/" + jobId;
196+
String url = this.mindeeSettings.getBaseUrl() + "/inferences/" + inferenceId;
152197
HttpGet get = new HttpGet(url);
153198

154199
if (this.mindeeSettings.getApiKey().isPresent()) {
@@ -202,17 +247,9 @@ private MindeeHttpExceptionV2 getHttpError(ClassicHttpResponse response) {
202247

203248

204249
private HttpEntity buildHttpBody(
205-
LocalInputSource inputSource,
250+
MultipartEntityBuilder builder,
206251
InferenceParameters options
207252
) {
208-
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
209-
builder.setMode(HttpMultipartMode.EXTENDED);
210-
builder.addBinaryBody(
211-
"file",
212-
inputSource.getFile(),
213-
ContentType.DEFAULT_BINARY,
214-
inputSource.getFilename()
215-
);
216253

217254
if (options.getAlias() != null) {
218255
builder.addTextBody(
@@ -237,7 +274,6 @@ private HttpEntity buildHttpBody(
237274

238275
private HttpPost buildHttpPost(
239276
String url,
240-
LocalInputSource inputSource,
241277
InferenceParameters options
242278
) {
243279
HttpPost post;
@@ -255,7 +291,6 @@ private HttpPost buildHttpPost(
255291
post.setHeader(HttpHeaders.AUTHORIZATION, this.mindeeSettings.getApiKey().get());
256292
}
257293
post.setHeader(HttpHeaders.USER_AGENT, getUserAgent());
258-
post.setEntity(buildHttpBody(inputSource, options));
259294
return post;
260295
}
261296

src/main/java/com/mindee/input/URLInputSource.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
* Input source wrapper to load remote files locally.
1919
*/
2020
public class URLInputSource {
21+
@Getter
2122
private final String url;
2223
private final String username;
2324
private final String password;

src/main/java/com/mindee/parsing/v2/field/InferenceFields.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ public String toString(int indent) {
3131
} else if (fieldValue.getObjectField() != null) {
3232
strBuilder.append(fieldValue.getObjectField());
3333
} else if (fieldValue.getSimpleField() != null) {
34-
strBuilder.append(fieldValue.getSimpleField().getValue() != null ? fieldValue.getSimpleField().getValue() : "");
34+
strBuilder.append(
35+
fieldValue.getSimpleField().getValue() != null
36+
? fieldValue.getSimpleField().toString()
37+
: ""
38+
);
3539

3640
}
3741
joiner.add(strBuilder);

src/main/java/com/mindee/parsing/v2/field/SimpleField.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ public final class SimpleField extends BaseField {
2727

2828
@Override
2929
public String toString() {
30-
return value == null ? "" : value.toString();
30+
if (value == null) return "";
31+
if (value.getClass().equals(Boolean.class)) {
32+
return ((Boolean) value) ? "True" : "False";
33+
}
34+
return value.toString();
3135
}
3236
}

src/main/java/com/mindee/parsing/v2/field/SimpleFieldDeserializer.java

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,24 @@ public SimpleField deserialize(JsonParser jp, DeserializationContext ctxt) throw
2121
Object value = null;
2222

2323
if (valueNode != null && !valueNode.isNull()) {
24-
if (valueNode.isTextual()) {
25-
value = valueNode.asText();
26-
} else if (valueNode.isNumber()) {
27-
value = valueNode.doubleValue();
28-
} else if (valueNode.isBoolean()) {
29-
value = valueNode.asBoolean();
24+
switch (valueNode.getNodeType()) {
25+
case BOOLEAN:
26+
value = valueNode.booleanValue();
27+
break;
28+
29+
case NUMBER:
30+
value = valueNode.doubleValue();
31+
break;
32+
33+
case STRING:
34+
value = valueNode.textValue();
35+
break;
36+
37+
default:
38+
value = codec.treeToValue(valueNode, Object.class);
3039
}
3140
}
41+
3242
return new SimpleField(value);
3343
}
3444
}

src/test/java/com/mindee/MindeeClientV2IT.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22

33
import com.mindee.http.MindeeHttpExceptionV2;
44
import com.mindee.input.LocalInputSource;
5+
import com.mindee.input.URLInputSource;
56
import com.mindee.parsing.v2.InferenceResponse;
67
import java.io.File;
78
import java.io.IOException;
89
import org.junit.jupiter.api.*;
910
import static org.junit.jupiter.api.Assertions.*;
10-
import static org.junit.jupiter.api.Assumptions.assumeTrue;
1111

1212
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
1313
@Tag("integration")
@@ -83,6 +83,7 @@ void parseFile_filledSinglePage_mustSucceed() throws IOException, InterruptedExc
8383
);
8484
}
8585

86+
8687
@Test
8788
@DisplayName("Invalid model ID – enqueue must raise 422")
8889
void invalidModel_mustThrowError() throws IOException {
@@ -109,4 +110,20 @@ void invalidJob_mustThrowError() {
109110
assertEquals(422, ex.getStatus());
110111
assertNotNull(ex);
111112
}
113+
114+
@Test
115+
@DisplayName("URL input source - A url param should not raise errors.")
116+
void urlInputSource_mustNotRaiseErrors() throws IOException, InterruptedException {
117+
URLInputSource urlSource = URLInputSource.builder(
118+
"https://upload.wikimedia.org/wikipedia/commons/1/1d/Blank_Page.pdf"
119+
).build();
120+
121+
InferenceParameters options =
122+
InferenceParameters.builder(modelId).build();
123+
124+
InferenceResponse response = mindeeClient.enqueueAndGetInference(urlSource, options);
125+
126+
assertNotNull(response);
127+
assertNotNull(response.getInference());
128+
}
112129
}

src/test/java/com/mindee/parsing/v2/InferenceTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ void standardFieldTypes_mustExposeCorrectTypes() throws IOException {
190190
assertNotNull(inf);
191191

192192
InferenceFields root = inf.getResult().getFields();
193-
assertNotNull(root.get("field_simple").getSimpleField());
193+
assertNotNull(root.get("field_simple_string").getSimpleField());
194194
assertNotNull(root.get("field_object").getObjectField());
195195
assertNotNull(root.get("field_simple_list").getListField());
196196
assertNotNull(root.get("field_object_list").getListField());

0 commit comments

Comments
 (0)