Documentation
How to extract information from Purchase Order using SoceTonAI Script OCRΒΆ
In this guide, Iβll show how to use SoceTonAI Script OCR to automatically extract key information from a Purchase Order. We begin by collecting the API credentials from soceton.com, then create a YAML script that instructs the OCR engine to read the information we need (YAML is provided at the end of this document). Finally, we send a read request to api.soceton.com to retrieve the structured output.
YAML that I am using for this requestΒΆ
document_type: PurchaseOrder
description: "Extract key information from Purchase Order using OCR"
development: true
return_ocr_output: false
return_full_text: false
fields:
- name: supplier_name
label: "Supplier Name"
find:
type: text
keywords:
- keyword: "Supplier"
index: 1
next_keyword_position: [ 1, -1, 1, 10 ]
- keyword: "Name"
next_keyword_position: [ 1, -1, 1, 3 ]
- keyword: ":"
position_of_value: [1, -1, 8, 18]
words: 5
debug: false
returns:
- keywords
- words
- position
- name: address
label: "Address"
find:
type: text
keywords:
- keyword: "Address"
index: 0
next_keyword_position: [ 1, -1, 1, 3 ]
- keyword: ":"
position_of_value: [1, -1, 7, 35]
words: 10
debug: false
returns:
- keywords
- words
- position
- name: contact
label: "Contact"
find:
type: text
keywords:
- keyword: "Contact"
index: 0
next_keyword_position: [ 1, -1, 1, 3 ]
- keyword: ":"
position_of_value: [1, -1, 7, 30]
words: 10
debug: false
returns:
- keywords
- words
- position
- name: email
label: "Email"
find:
type: text
keywords:
- keyword: "Email"
index: 1
next_keyword_position: [ 1, -1, 1, 3 ]
- keyword: ":"
position_of_value: [1, -1, 5, 30]
words: 2
debug: false
returns:
- keywords
- words
- position
- name: ship_to
label: "Ship To"
find:
type: text
keywords:
- keyword: "Ship"
index: 1
next_keyword_position: [ 1, -1, 1, 10 ]
- keyword: "To"
position_of_value: [5, 0.5, -1, 15]
debug: false
returns:
- keywords
- words
- position
- name: shipping_method
label: "Shipping Method"
find:
type: text
keywords:
- keyword: "Shipping"
index: 1
next_keyword_position: [ 1, -1, 1, 10 ]
- keyword: "Method"
position_of_value: [5, 0.5, -1, 15]
debug: false
returns:
- keywords
- words
- position
- name: subtotal
label: "Subtotal"
find:
type: text
keywords:
- keyword: "Subtotal"
index: 0
position_of_value: [1, -1, 30, 130]
words: 10
debug: false
returns:
- keywords
- words
- position
- name: total
label: "Total"
find:
type: text
keywords:
- keyword: "Total"
index: 1
next_keyword_position: [ 1, -1, 1, 10 ]
- keyword: "Amount"
position_of_value: [1, -1, 30, 130]
words: 10
debug: false
returns:
- keywords
- words
- position
The imageΒΆ
InΒ [1]:
from PIL import Image
img = Image.open("dummies/images/purchase-order_0.jpg")
img = img.convert("RGB")
img
Out[1]:
Sending the requestΒΆ
InΒ [2]:
import requests
import json
from config import SOCETONAI_API_SECRET, SOCETONAI_API_KEY
def generate_result(url, image_path, rules_path, headers):
data = {}
files = {
"doc": open(image_path, "rb"),
"rules": open(rules_path, "r", encoding="utf-8")
}
response = requests.post(url, data=data, headers=headers, files=files)
return response
result = generate_result(
"https://api.soceton.com/script-ocr/read",
"dummies/images/purchase-order_0.jpg",
"dummies/ymls/purchase-order_0.yml", {
"X-API-KEY": SOCETONAI_API_KEY,
"X-API-SECRET": SOCETONAI_API_SECRET
})
result = result.json()
values = {}
for k in result["result"].keys():
try:
values[k] = result["result"][k]["value"]
except Exception as e:
print(k, ":", e)
print(json.dumps(values, indent=4))
{
"supplier_name": "Demo Supplies Ltd.",
"address": "45 Vendor Park , Sampletown , ST 12345",
"contact": "Sarah Carter",
"email": "sales@demosupplies.com",
"ship_to": "Example Company Warehouse 800 Logistics Road Cityville , CA 90001",
"shipping_method": "Standard Ground Freight",
"subtotal": "$ 470.00",
"total": "$ 533.50"
}
Annotating the result on the image (Optional)ΒΆ
Keywords are in green, value positions are in blue, and value words are in red.
InΒ [3]:
import numpy as np
import cv2
w, h = img.size
img_copy = np.asarray(img).copy()
def annotate_value(key):
try:
thickness = 2
color = (0, 0, 255)
position = result["result"][key]["position"]
top, left, bottom, right = int(position["top"] * h), int(position["left"] * w), int(position["bottom"] * h), int(position["right"] * w)
cv2.rectangle(img_copy, (left, top), (right, bottom), color, thickness)
except Exception as e:
print(e)
try:
thickness = 2
color = (0, 255, 0)
for keyword in result["result"][key]["keywords"]:
y1, x1, y2, x2 = int(keyword["y1"] * h), int(keyword["x1"] * w), int(keyword["y2"] * h), int(keyword["x2"] * w)
cv2.rectangle(img_copy, (x1, y1), (x2, y2), color, thickness)
except Exception as e:
print(e)
try:
thickness = 2
color = (255, 0, 0)
for word in result["result"][key]["words"]:
y1, x1, y2, x2 = int(word["y1"] * h), int(word["x1"] * w), int(word["y2"] * h), int(word["x2"] * w)
cv2.rectangle(img_copy, (x1, y1), (x2, y2), color, thickness)
except Exception as e:
print(e)
for k in result["result"].keys():
annotate_value(k)
Image.fromarray(img_copy)
Out[3]:
Printing the valuesΒΆ
InΒ [4]:
print(json.dumps(result, indent=4))
{
"success": true,
"result": {
"supplier_name": {
"value": "Demo Supplies Ltd.",
"keywords": [
{
"page_idx": 0,
"block_idx": 2,
"line_idx": 0,
"word_idx": 0,
"value": "Supplier",
"confidence": 0.992863953113556,
"x1": 0.0889292196007259,
"y1": 0.1710132535271483,
"x2": 0.1923774954627949,
"y2": 0.1799914493373236
},
{
"page_idx": 0,
"block_idx": 2,
"line_idx": 0,
"word_idx": 1,
"value": "Name",
"confidence": 0.9911816120147704,
"x1": 0.0889292196007259,
"y1": 0.1710132535271483,
"x2": 0.1923774954627949,
"y2": 0.1799914493373236
},
{
"page_idx": 0,
"block_idx": 2,
"line_idx": 0,
"word_idx": 2,
"value": ":",
"confidence": 0.9818905591964722,
"x1": 0.0889292196007259,
"y1": 0.1710132535271483,
"x2": 0.1923774954627949,
"y2": 0.1799914493373236
}
],
"words": [
{
"page_idx": 0,
"block_idx": 2,
"line_idx": 0,
"word_idx": 3,
"value": "Demo",
"confidence": 0.9921081066131592,
"x1": 0.1966122202056866,
"y1": 0.1710132535271483,
"x2": 0.234724742891712,
"y2": 0.1799914493373236
},
{
"page_idx": 0,
"block_idx": 2,
"line_idx": 0,
"word_idx": 4,
"value": "Supplies",
"confidence": 0.9878383874893188,
"x1": 0.2383545069570478,
"y1": 0.1710132535271483,
"x2": 0.2921960072595281,
"y2": 0.1799914493373236
},
{
"page_idx": 0,
"block_idx": 2,
"line_idx": 0,
"word_idx": 5,
"value": "Ltd.",
"confidence": 0.9791396260261536,
"x1": 0.2958257713248639,
"y1": 0.1710132535271483,
"x2": 0.3188142770719903,
"y2": 0.1799914493373236
}
],
"position": {
"top": 0.16203505771697302,
"left": 0.1923774954627949,
"bottom": 0.1889696451474989,
"right": 0.4251361161524501
}
},
"address": {
"value": "45 Vendor Park , Sampletown , ST 12345",
"keywords": [
{
"page_idx": 0,
"block_idx": 3,
"line_idx": 0,
"word_idx": 0,
"value": "Address",
"confidence": 0.9923474788665771,
"x1": 0.0883242589231699,
"y1": 0.1992304403591278,
"x2": 0.147005444646098,
"y2": 0.2082086361693031
},
{
"page_idx": 0,
"block_idx": 3,
"line_idx": 0,
"word_idx": 1,
"value": ":",
"confidence": 0.9671363830566406,
"x1": 0.0883242589231699,
"y1": 0.1992304403591278,
"x2": 0.147005444646098,
"y2": 0.2082086361693031
}
],
"words": [
{
"page_idx": 0,
"block_idx": 3,
"line_idx": 0,
"word_idx": 2,
"value": "45",
"confidence": 0.980510711669922,
"x1": 0.1500302480338778,
"y1": 0.1992304403591278,
"x2": 0.1657592256503327,
"y2": 0.2082086361693031
},
{
"page_idx": 0,
"block_idx": 3,
"line_idx": 0,
"word_idx": 3,
"value": "Vendor",
"confidence": 0.9761548042297364,
"x1": 0.1693889897156685,
"y1": 0.1992304403591278,
"x2": 0.2159709618874773,
"y2": 0.2082086361693031
},
{
"page_idx": 0,
"block_idx": 3,
"line_idx": 0,
"word_idx": 4,
"value": "Park",
"confidence": 0.985521912574768,
"x1": 0.219600725952813,
"y1": 0.1992304403591278,
"x2": 0.248638838475499,
"y2": 0.2082086361693031
},
{
"page_idx": 0,
"block_idx": 3,
"line_idx": 0,
"word_idx": 5,
"value": ",",
"confidence": 0.9645378589630128,
"x1": 0.2480338777979431,
"y1": 0.1992304403591278,
"x2": 0.2516636418632789,
"y2": 0.2082086361693031
},
{
"page_idx": 0,
"block_idx": 3,
"line_idx": 0,
"word_idx": 6,
"value": "Sampletown",
"confidence": 0.9914188385009766,
"x1": 0.2546884452510586,
"y1": 0.1992304403591278,
"x2": 0.3333333333333333,
"y2": 0.2082086361693031
},
{
"page_idx": 0,
"block_idx": 3,
"line_idx": 0,
"word_idx": 7,
"value": ",",
"confidence": 0.9761770963668824,
"x1": 0.3339382940108893,
"y1": 0.1992304403591278,
"x2": 0.337568058076225,
"y2": 0.2082086361693031
},
{
"page_idx": 0,
"block_idx": 3,
"line_idx": 0,
"word_idx": 8,
"value": "ST",
"confidence": 0.9615680575370787,
"x1": 0.3405928614640048,
"y1": 0.1992304403591278,
"x2": 0.3563218390804598,
"y2": 0.2082086361693031
},
{
"page_idx": 0,
"block_idx": 3,
"line_idx": 0,
"word_idx": 9,
"value": "12345",
"confidence": 0.985495388507843,
"x1": 0.3605565638233515,
"y1": 0.1992304403591278,
"x2": 0.3992740471869328,
"y2": 0.2082086361693031
}
],
"position": {
"top": 0.19025224454895248,
"left": 0.147005444646098,
"bottom": 0.2171868319794784,
"right": 0.4404113732607385
}
},
"contact": {
"value": "Sarah Carter",
"keywords": [
{
"page_idx": 0,
"block_idx": 7,
"line_idx": 0,
"word_idx": 0,
"value": "Contact",
"confidence": 0.9897594451904296,
"x1": 0.5849969751966122,
"y1": 0.1714407866609662,
"x2": 0.6412583182093164,
"y2": 0.1782813168020521
},
{
"page_idx": 0,
"block_idx": 7,
"line_idx": 0,
"word_idx": 1,
"value": ":",
"confidence": 0.9786970019340516,
"x1": 0.5849969751966122,
"y1": 0.1714407866609662,
"x2": 0.6412583182093164,
"y2": 0.1782813168020521
}
],
"words": [
{
"page_idx": 0,
"block_idx": 7,
"line_idx": 0,
"word_idx": 2,
"value": "Sarah",
"confidence": 0.9808996319770812,
"x1": 0.6448880822746521,
"y1": 0.1714407866609662,
"x2": 0.6811857229280097,
"y2": 0.1782813168020521
},
{
"page_idx": 0,
"block_idx": 7,
"line_idx": 0,
"word_idx": 3,
"value": "Carter",
"confidence": 0.9819870591163636,
"x1": 0.6854204476709014,
"y1": 0.1714407866609662,
"x2": 0.7253478523895946,
"y2": 0.1782813168020521
}
],
"position": {
"top": 0.16460025651988033,
"left": 0.6412583182093164,
"bottom": 0.18512184694313796,
"right": 0.8823783596923347
}
},
"email": {
"value": "sales@demosupplies.com",
"keywords": [
{
"page_idx": 0,
"block_idx": 8,
"line_idx": 0,
"word_idx": 0,
"value": "Email",
"confidence": 0.990318238735199,
"x1": 0.5856019358741682,
"y1": 0.1988029072253099,
"x2": 0.6267392619479734,
"y2": 0.2077811030354852
},
{
"page_idx": 0,
"block_idx": 8,
"line_idx": 0,
"word_idx": 1,
"value": ":",
"confidence": 0.9710260629653932,
"x1": 0.5856019358741682,
"y1": 0.1988029072253099,
"x2": 0.6267392619479734,
"y2": 0.2077811030354852
}
],
"words": [
{
"page_idx": 0,
"block_idx": 8,
"line_idx": 0,
"word_idx": 2,
"value": "sales@demosupplies.com",
"confidence": 0.9856069087982178,
"x1": 0.6297640653357531,
"y1": 0.198375374091492,
"x2": 0.7931034482758621,
"y2": 0.2086361693031209
}
],
"position": {
"top": 0.18982471141513463,
"left": 0.6267392619479734,
"bottom": 0.21675929884566048,
"right": 0.8735632183908043
}
},
"ship_to": {
"value": "Example Company Warehouse 800 Logistics Road Cityville , CA 90001",
"keywords": [
{
"page_idx": 0,
"block_idx": 10,
"line_idx": 0,
"word_idx": 0,
"value": "Ship",
"confidence": 0.9646687507629396,
"x1": 0.087719298245614,
"y1": 0.2667806755023514,
"x2": 0.1373260738052026,
"y2": 0.2770414707139803
},
{
"page_idx": 0,
"block_idx": 10,
"line_idx": 0,
"word_idx": 1,
"value": "To",
"confidence": 0.9752541780471802,
"x1": 0.087719298245614,
"y1": 0.2667806755023514,
"x2": 0.1373260738052026,
"y2": 0.2770414707139803
}
],
"words": [
{
"page_idx": 0,
"block_idx": 11,
"line_idx": 0,
"word_idx": 0,
"value": "Example",
"confidence": 0.9866663217544556,
"x1": 0.0889292196007259,
"y1": 0.281316802052159,
"x2": 0.1421657592256503,
"y2": 0.2907225309961522
},
{
"page_idx": 0,
"block_idx": 11,
"line_idx": 0,
"word_idx": 1,
"value": "Company",
"confidence": 0.988459289073944,
"x1": 0.146400483968542,
"y1": 0.2808892689183411,
"x2": 0.2075015124016939,
"y2": 0.2902949978623343
},
{
"page_idx": 0,
"block_idx": 11,
"line_idx": 0,
"word_idx": 2,
"value": "Warehouse",
"confidence": 0.9911454916000366,
"x1": 0.2093163944343617,
"y1": 0.2804617357845233,
"x2": 0.2831215970961887,
"y2": 0.2898674647285164
},
{
"page_idx": 0,
"block_idx": 11,
"line_idx": 1,
"word_idx": 0,
"value": "800",
"confidence": 0.9908189177513124,
"x1": 0.0889292196007259,
"y1": 0.2949978623343309,
"x2": 0.1113127646702964,
"y2": 0.3039760581445062
},
{
"page_idx": 0,
"block_idx": 11,
"line_idx": 1,
"word_idx": 1,
"value": "Logistics",
"confidence": 0.991817593574524,
"x1": 0.1161524500907441,
"y1": 0.294570329200513,
"x2": 0.1687840290381125,
"y2": 0.3039760581445062
},
{
"page_idx": 0,
"block_idx": 11,
"line_idx": 1,
"word_idx": 2,
"value": "Road",
"confidence": 0.964534342288971,
"x1": 0.1736237144585602,
"y1": 0.294570329200513,
"x2": 0.205686630369026,
"y2": 0.3031209918768704
},
{
"page_idx": 0,
"block_idx": 12,
"line_idx": 0,
"word_idx": 0,
"value": "Cityville",
"confidence": 0.987163543701172,
"x1": 0.0883242589231699,
"y1": 0.307823856348867,
"x2": 0.1379310344827586,
"y2": 0.3180846515604959
},
{
"page_idx": 0,
"block_idx": 12,
"line_idx": 0,
"word_idx": 1,
"value": ",",
"confidence": 0.9850828647613524,
"x1": 0.1367211131276467,
"y1": 0.3082513894826849,
"x2": 0.1403508771929824,
"y2": 0.3172295852928602
},
{
"page_idx": 0,
"block_idx": 12,
"line_idx": 0,
"word_idx": 2,
"value": "CA",
"confidence": 0.9867199659347534,
"x1": 0.1445856019358741,
"y1": 0.3073963232150491,
"x2": 0.160919540229885,
"y2": 0.3168020521590423
},
{
"page_idx": 0,
"block_idx": 12,
"line_idx": 0,
"word_idx": 3,
"value": "90001",
"confidence": 0.9905341267585754,
"x1": 0.1651542649727767,
"y1": 0.3069687900812313,
"x2": 0.2026618269812462,
"y2": 0.3168020521590423
}
],
"position": {
"top": 0.27191107310816587,
"left": 0.07531760435571686,
"bottom": 0.3283454467721246,
"right": 0.32335148215365983
}
},
"shipping_method": {
"value": "Standard Ground Freight",
"keywords": [
{
"page_idx": 0,
"block_idx": 13,
"line_idx": 0,
"word_idx": 0,
"value": "Shipping",
"confidence": 0.9659917950630188,
"x1": 0.5462794918330308,
"y1": 0.2659256092347157,
"x2": 0.6612220205686631,
"y2": 0.2774690038477982
},
{
"page_idx": 0,
"block_idx": 13,
"line_idx": 0,
"word_idx": 1,
"value": "Method",
"confidence": 0.9945361614227296,
"x1": 0.5462794918330308,
"y1": 0.2659256092347157,
"x2": 0.6612220205686631,
"y2": 0.2774690038477982
}
],
"words": [
{
"page_idx": 0,
"block_idx": 13,
"line_idx": 0,
"word_idx": 3,
"value": "Standard",
"confidence": 0.9717828035354614,
"x1": 0.5468844525105868,
"y1": 0.2800342026507054,
"x2": 0.604355716878403,
"y2": 0.2894399315946986
},
{
"page_idx": 0,
"block_idx": 13,
"line_idx": 0,
"word_idx": 4,
"value": "Ground",
"confidence": 0.9413880705833436,
"x1": 0.6085904416212946,
"y1": 0.2804617357845233,
"x2": 0.6575922565033273,
"y2": 0.2898674647285164
},
{
"page_idx": 0,
"block_idx": 13,
"line_idx": 0,
"word_idx": 5,
"value": "Freight",
"confidence": 0.9889384508132936,
"x1": 0.6612220205686631,
"y1": 0.2808892689183411,
"x2": 0.7078039927404719,
"y2": 0.2902949978623343
}
],
"position": {
"top": 0.27169730654125696,
"left": 0.5319116757410768,
"bottom": 0.3351859769132108,
"right": 0.8767392619479736
}
},
"subtotal": {
"value": "$ 470.00",
"keywords": [
{
"page_idx": 0,
"block_idx": 38,
"line_idx": 0,
"word_idx": 0,
"value": "Subtotal",
"confidence": 0.9847946763038636,
"x1": 0.0889292196007259,
"y1": 0.5438221462163317,
"x2": 0.145795523290986,
"y2": 0.5506626763574177
}
],
"words": [
{
"page_idx": 0,
"block_idx": 43,
"line_idx": 0,
"word_idx": 0,
"value": "$",
"confidence": 0.9743773937225342,
"x1": 0.8596491228070176,
"y1": 0.5438221462163317,
"x2": 0.8663036902601331,
"y2": 0.5506626763574177
},
{
"page_idx": 0,
"block_idx": 43,
"line_idx": 0,
"word_idx": 1,
"value": "470.00",
"confidence": 0.991793930530548,
"x1": 0.8663036902601331,
"y1": 0.5438221462163317,
"x2": 0.9086509376890504,
"y2": 0.5506626763574177
}
],
"position": {
"top": 0.5369816160752457,
"left": 0.30217785843920125,
"bottom": 0.5575032064985037,
"right": 1.0698729582577124
}
},
"total": {
"value": "$ 533.50",
"keywords": [
{
"page_idx": 0,
"block_idx": 41,
"line_idx": 0,
"word_idx": 0,
"value": "Total",
"confidence": 0.9869607090950012,
"x1": 0.0883242589231699,
"y1": 0.6280461735784524,
"x2": 0.1820931639443436,
"y2": 0.6344591705857204
},
{
"page_idx": 0,
"block_idx": 41,
"line_idx": 0,
"word_idx": 1,
"value": "Amount",
"confidence": 0.9918040037155152,
"x1": 0.0883242589231699,
"y1": 0.6280461735784524,
"x2": 0.1820931639443436,
"y2": 0.6344591705857204
}
],
"words": [
{
"page_idx": 0,
"block_idx": 46,
"line_idx": 0,
"word_idx": 0,
"value": "$",
"confidence": 0.975541651248932,
"x1": 0.8584392014519057,
"y1": 0.6280461735784524,
"x2": 0.8650937689050212,
"y2": 0.6344591705857204
},
{
"page_idx": 0,
"block_idx": 46,
"line_idx": 0,
"word_idx": 1,
"value": "533.50",
"confidence": 0.99092298746109,
"x1": 0.8656987295825771,
"y1": 0.6271911073108166,
"x2": 0.9080459770114944,
"y2": 0.6344591705857204
}
],
"position": {
"top": 0.6216331765711843,
"left": 0.6509376890502121,
"bottom": 0.6408721675929885,
"right": 2.6200846944948597
}
}
}
}