Interacting with Document Converter Services using Python

Document Converter Services (DCS) is a highly versatile system that can be integrated with various environments. Python, a widely adopted programming language, is often used both independently and within Jupyter Notebooks to interact with DCS.

Setting up

The Python examples mentioned in this guide uses the Zeep library, which simplifies working with WSDL in Python. For more information, refer to the Zeep documentation.

Accessing the WSDL

There is no straightforward method for consuming the published Nutrient Web Services Description Language (WSDL) for DCS.

To begin, open a PowerShell terminal (Tools > Command Line > PowerShell).

Although instructions typically reference python, it currently works when using py.exe:

py.exe -mzeep http://localhost:<port_number>/Muhimbi.DocumentConverter.WebService/?WSDL

Note the namespace prefixes in the WSDL. These are necessary when working with factory objects, as demonstrated in the data structures section further down in this guide.

Retrieving configuration details

The example below demonstrates how to call the web service to retrieve configuration details:

# Import the zeep library to access WSDL
import zeep

print("Test WSDL")

#Service URL
service_url = "http://localhost:41734/Muhimbi.DocumentConverter.WebService/"
# WSDL URL
wsdl_url = service_url+"?WSDL"

# Create the header structure
header = zeep.xsd.Element(
    "Header",
    zeep.xsd.ComplexType(
        [
            zeep.xsd.Element(
                "{http://www.w3.org/2005/08/addressing}Action", zeep.xsd.String()
            ),
            zeep.xsd.Element(
                "{http://www.w3.org/2005/08/addressing}To", zeep.xsd.String()
            ),
        ]
    ),
)

# Create a header object
header_value = header(Action=service_url,To=service_url)
#create client object using the header
client = zeep.Client(wsdl=wsdl_url)

# Get the configuration information from the server
result = client.service.GetConfiguration()

# Print the returned data
print(result)
print("Done")

Data structures

DCS operations often require complex parameters. You can construct these parameters using the client.type_factory method, along with the appropriate WSDL prefix:

# Create client
client = zeep.Client(wsdl=wsdl_url)
# Create a factory type to construct objects with the suffix ns2 (see the WSDL)
factory = client.type_factory("ns2")
# Create a DiagnosticRequestItem with the property ConverterName set to a converter type
request_item = factory.DiagnosticRequestItem(ConverterName = "WordProcessing")

Retrieving diagnostic status

The following example retrieves the diagnostic status for the WordProcessing converter:

import zeep
from array import array
print("Get diagnostic for a converter")
#Service URL
service_url = "http://localhost:41734/Muhimbi.DocumentConverter.WebService/"
# WSDL URL
wsdl_url = service_url+"?WSDL"

# Construct the header
header = zeep.xsd.Element(
    "Header",
    zeep.xsd.ComplexType(
        [
            zeep.xsd.Element(
                "{http://www.w3.org/2005/08/addressing}Action", zeep.xsd.String()
            ),
            zeep.xsd.Element(
                "{http://www.w3.org/2005/08/addressing}To", zeep.xsd.String()
            ),
        ]
    ),
)
# Create a heading object
header_value = header(Action=service_url,To=service_url)
# Create client
client = zeep.Client(wsdl=wsdl_url)
# Create a factory type to construct objects with the suffix ns2 (see the WSDL)
factory = client.type_factory("ns2")
# Create a DiagnosticRequestItem with the property ConverterName set to a converter type
request_item = factory.DiagnosticRequestItem(ConverterName = "WordProcessing")
# Create an array of DiagnosticRequestItem objects (in this case just one)
request_items = factory.ArrayOfDiagnosticRequestItem(request_item)
# Call the DCS GetDiagnostics operation with the selected conversion type
result = client.service.GetDiagnostics(request_items)

print(result)
print("Done")

Output:

wordprocessing-output

Extracting key-value pairs from a PDF

To extract key-value pairs from a PDF, start by identifying the. ExtractKeyValuePairs web service method name. You can locate it in the WSDL file:

ns1:ExtractKeyValuePairs(sourceFile: xsd:base64Binary, openOptions: ns2:OpenOptions, extractKeyValuePairsSettings: ns2:KVPSettings)

This method uses the ns1 prefix and takes the following three parameters:

  • sourceFilexsd:base64Binary

  • openOptionsns2:OpenOptions

  • extractKeyValuePairsSettingsns2:KVPSettings

Important things to note

  • The sourceFile parameter expects a W3 XML schema Base64-encoded binary representation of the document. The subsequent parameters, openOptions and extractKeyValuePairsSettings, are custom Nutrient (formerly Muhimbi) types. Instantiation of these types necessitates a factory generated using the ns2 prefix, as defined within the WSDL document. Examination of the WSDL will reveal the constituent properties of these Nutrient types.

  • The openOptions type presents a straightforward structure, requiring minimal configuration through its fundamental properties: file name and extension.

  • Conversely, the KVPSettings type encompasses several complex properties; however, the KVPFormat property is the sole mandatory attribute for this operation.

  • Due to the ns3 prefix associated with the KVPFormat type, a distinct factory instance, specific to this namespace, will be required for its creation.

factory2 = client.type_factory("ns3")
KVPOutputFormat = factory2.KVPOutputFormat(1)

Sample code:

import zeep
import base64
import lxml.etree as etree

print("Get Key-Value Pairs for a file")
#Service URL
service_url = "http://localhost:41734/Muhimbi.DocumentConverter.WebService/"
# WSDL URL
wsdl_url = service_url+"?WSDL"

# Construct the header
header = zeep.xsd.Element(
    "Header",
    zeep.xsd.ComplexType(
        [
            zeep.xsd.Element(
                "{http://www.w3.org/2005/08/addressing}Action", zeep.xsd.String()
            ),
            zeep.xsd.Element(
                "{http://www.w3.org/2005/08/addressing}To", zeep.xsd.String()
            ),
        ]
    ),
)
# Create a heading object
header_value = header(Action=service_url,To=service_url)
# Create client
client = zeep.Client(wsdl=wsdl_url)
# Create a factory type to construct objects with the suffix ns2 (see the WSDL)
factory = client.type_factory("ns2")
# Create a factory type to construct objects with the suffix ns3 (see the WSDL)
factory2 = client.type_factory("ns3")

# Create the OpenOptions object with the minimum settings
open_options = factory.OpenOptions(OriginalFileName = "Three-in-one invoice.pdf", FileExtension = "pdf")

# Create the KVP Output Format object
KVPOutputFormat = factory2.KVPOutputFormat("XML")
# Create the expected keys string
expectedKeys = "[{\"expectedKey\":\"Name\",\"synonyms\":[\"name\"]},{\"expectedKey\":\"grand total\",\"synonyms\":[\"total\"]},{\"expectedKey\":\"invoice number\",\"synonyms\":[\"invoice no\"]}]"
# Create the KVP Settings object
KVPSettings = factory.KVPSettings(OCRLanguage = "eng", KVPFormat = KVPOutputFormat, DPI = 300, ExpectedKeys = expectedKeys)

# Load the source file as a Base64 string
with open("Three-in-one invoice.pdf", "rb") as image_file:
    encoded_string = base64.b64encode(image_file.read()).decode('utf-8')

# Call the ExtractKeyValuePairs method of the service with the required parameters
result = client.service.ExtractKeyValuePairs(encoded_string, open_options, KVPSettings)

# Load the result XML into an lxml etree object
tree = etree.fromstring(result)

# Find all the KVPData elements
kvpData = tree.xpath('/ArrayOfKVPData/KVPData')
# For each KVPData element
for x in kvpData:
    # Get the key and value elements' text
    key = x.xpath('Key')[0].text
    value = x.xpath('Value')[0].text
    # Print the key and value
    print(key, ' - ', value)

print("Done")

Output:

extractkvp-output

References