-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCustomSchema.java
More file actions
72 lines (63 loc) · 3.35 KB
/
Copy pathCustomSchema.java
File metadata and controls
72 lines (63 loc) · 3.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/*
* Custom fields on top of a preset, fields injected into every line-item row, and saving
* the combination so later calls are one argument.
*
* java -cp target/visionapi-java-1.0.0.jar examples/CustomSchema.java invoice.pdf
*/
import io.visionapi.AnalyzeRequest;
import io.visionapi.AnalyzeResponse;
import io.visionapi.ConflictException;
import io.visionapi.Row;
import io.visionapi.Schema;
import io.visionapi.VisionApi;
import java.nio.file.Path;
import java.util.Map;
public class CustomSchema {
public static void main(String[] args) {
Path path = Path.of(args.length > 0 ? args[0] : "invoice.pdf");
VisionApi vision = VisionApi.create();
Map<String, Object> schema = Schema.builder()
// Plain form: the string is the description. Descriptions are the prompt —
// the more precisely you say what you want, the better the extraction.
.field("machine_serial", "Serial number of the machine being invoiced, without the \"SN:\" prefix")
// Typed forms. Numbers come back as JSON numbers, dates as ISO YYYY-MM-DD.
.number("total_net", "Total before tax")
.bool("is_paid", "Whether the invoice is stamped or marked PAID")
.array("reference_numbers", "All reference numbers", "string")
// lineItem is reserved: these become extra columns on every row of the
// preset's line-item array. Only meaningful with a preset that has line
// items; with a bare custom schema there is nothing to inject into.
.lineItem(Schema.of("lot_number", "The lot number printed on this line, if present"))
.build();
AnalyzeResponse res = vision.analyze(AnalyzeRequest.builder()
.file(path)
.preset("invoice")
.schema(schema)
.build());
System.out.println("serial: " + res.result().field("machine_serial").asString().orElse("—"));
System.out.println("net total: " + res.result().field("total_net").asDouble().orElse(0));
System.out.println("paid: " + res.result().field("is_paid").asBoolean().orElse(false));
for (Row row : res.result().rows("line_item")) {
System.out.printf(" %s × %s = %s [lot %s]%n",
row.field("quantity").value(),
row.field("description").asString().orElse("(no description)"),
row.field("amount").value(),
row.field("lot_number").asString().orElse("—"));
}
// Save it, and the next call is schemaName("our-invoices"). The definition is
// compiled before it is stored, so an invalid schema fails here rather than on the
// first extraction that uses it.
try {
vision.createSchema("our-invoices", "invoice", schema);
System.out.println("\nsaved as \"our-invoices\"");
} catch (ConflictException e) {
vision.updateSchema("our-invoices", "invoice", schema);
System.out.println("\nupdated \"our-invoices\"");
}
AnalyzeResponse again = vision.analyze(AnalyzeRequest.builder()
.file(path)
.schemaName("our-invoices")
.build());
System.out.println("same fields via the saved schema: " + again.result().names().size());
}
}