Skip to content

Commit 55a4fd1

Browse files
:sparkled: add support for url input source + fix typing for SimpleField
1 parent f5cdb31 commit 55a4fd1

10 files changed

Lines changed: 156 additions & 27 deletions

File tree

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

Lines changed: 49 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,58 @@ 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+
8196

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 {
109+
110+
validatePollingOptions(options.getPollingOptions());
82111
JobResponse job = enqueueInference(inputSource, options);
112+
return pollAndFetch(job, options);
113+
}
114+
83115

116+
/**
117+
* Common logic for polling an asynchronous job until it is either processed
118+
* successfully or fails / times out.
119+
* @param initialJob The initial job response.
120+
* @return an instance of {@link InferenceResponse}.
121+
* @throws InterruptedException Throws if the thread is interrupted.
122+
*/
123+
private InferenceResponse pollAndFetch(JobResponse initialJob,
124+
InferenceParameters options) throws InterruptedException {
84125
Thread.sleep((long) (options.getPollingOptions().getInitialDelaySec() * 1000));
85-
JobResponse resp = job;
126+
127+
JobResponse resp = initialJob;
86128
int attempts = 0;
87129
int max = options.getPollingOptions().getMaxRetries();
130+
88131
while (attempts < max) {
89132
Thread.sleep((long) (options.getPollingOptions().getIntervalSec() * 1000));
90-
resp = getJob(job.getJob().getId());
133+
resp = getJob(initialJob.getJob().getId());
134+
91135
if (resp.getJob().getStatus().equals("Failed")) {
92-
break;
136+
attempts = max;
93137
}
94-
else if (resp.getJob().getStatus().equals("Processed")) {
138+
if (resp.getJob().getStatus().equals("Processed")) {
95139
return getInference(resp.getJob().getId());
96140
}
97141
attempts++;
98142
}
143+
99144
ErrorResponse error = resp.getJob().getError();
100145
if (error != null) {
101146
throw new MindeeHttpExceptionV2(error.getStatus(), error.getDetail());

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

Lines changed: 10 additions & 1 deletion
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,13 +12,21 @@
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.
1516
*/
1617
public abstract JobResponse reqPostInferenceEnqueue(
1718
LocalInputSource inputSource,
1819
InferenceParameters options
1920
) throws IOException;
2021

22+
/**
23+
* Send a file to the prediction queue with a remote file.
24+
*/
25+
public abstract JobResponse reqPostInferenceEnqueue(
26+
URLInputSource inputSource,
27+
InferenceParameters options
28+
) throws IOException;
29+
2130
/**
2231
* Attempts to poll the queue.
2332
*/

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

Lines changed: 47 additions & 12 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(
@@ -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: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
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;
7+
68
import java.io.File;
79
import java.io.IOException;
10+
811
import org.junit.jupiter.api.*;
12+
913
import static org.junit.jupiter.api.Assertions.*;
1014
import static org.junit.jupiter.api.Assumptions.assumeTrue;
1115

@@ -83,6 +87,7 @@ void parseFile_filledSinglePage_mustSucceed() throws IOException, InterruptedExc
8387
);
8488
}
8589

90+
8691
@Test
8792
@DisplayName("Invalid model ID – enqueue must raise 422")
8893
void invalidModel_mustThrowError() throws IOException {
@@ -109,4 +114,20 @@ void invalidJob_mustThrowError() {
109114
assertEquals(422, ex.getStatus());
110115
assertNotNull(ex);
111116
}
117+
118+
@Test
119+
@DisplayName("URL input source - A url param should not raise errors.")
120+
void urlInputSource_mustNotRaiseErrors() throws IOException, InterruptedException {
121+
URLInputSource urlSource = URLInputSource.builder(
122+
"https://upload.wikimedia.org/wikipedia/commons/1/1d/Blank_Page.pdf"
123+
).build();
124+
125+
InferenceParameters options =
126+
InferenceParameters.builder(modelId).build();
127+
128+
InferenceResponse response = mindeeClient.enqueueAndGetInference(urlSource, options);
129+
130+
assertNotNull(response);
131+
assertNotNull(response.getInference());
132+
}
112133
}

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)