Skip to content

How to Implement a Qanary Component using Python Qanary Helpers

Aleksandr Perevalov edited this page May 31, 2021 · 5 revisions

Qanary is a methodology following the idea of a lean architecture of Question Answering systems and easy reuse of Question Answering services (c.f., see the publication for details). We call these services Qanary components (see this repository for a collection of freely available components).

Note, that you have to split your Question Answering system into separated components representing the steps of the process you would like to perform. Typically, each component is located within one folder.

Steps

Step 1: Preparation

We will use the Python package qanary_helpers which is a great contribution of Aleksandr Perevalov to ease the implementation of custom Qanary components.

Install qanary_helpers library via:

pip install qanary-helpers

Step 2: Create the required files

For the "Hello world example" create a file named component.py in your working directory. Then, fill the file with the following code (pay attention to the TODO comments):

import os
from datetime import datetime
from flask import Flask, request, jsonify
from qanary_helpers.registration import Registration
from qanary_helpers.registrator import Registrator
from qanary_helpers.qanary_queries import insert_into_triplestore, get_text_question_in_graph

# TODO: may be changed to other config type (e.g. parsing a json file)
SPRING_BOOT_ADMIN_URL = os.environ['SPRING_BOOT_ADMIN_URL']    
SPRING_BOOT_ADMIN_USERNAME = os.environ['SPRING_BOOT_ADMIN_USERNAME']
SPRING_BOOT_ADMIN_PASSWORD = os.environ['SPRING_BOOT_ADMIN_PASSWORD']
SERVICE_HOST = os.environ['SERVICE_HOST']
SERVICE_PORT = os.environ['SERVICE_PORT']
SERVICE_NAME_COMPONENT = os.environ['SERVICE_NAME_COMPONENT']
SERVICE_DESCRIPTION_COMPONENT = os.environ['SERVICE_DESCRIPTION_COMPONENT']
URL_COMPONENT = f"http://{SERVICE_HOST}:{SERVICE_PORT}"

app = Flask(__name__)


@app.route("/annotatequestion", methods=["POST"])
def qanary_service():
    triplestore_endpoint_url = request.json["values"]["urn:qanary#endpoint"]
    triplestore_ingraph_uuid = request.json["values"]["urn:qanary#inGraph"]
    
    question_text = get_text_question_in_graph(triplestore_endpoint_url, triplestore_ingraph_uuid)

    # Start TODO: configure your business logic here and adjust the sparql query
    result = "Hello World"

    SPARQLquery = """
                    PREFIX qa: <http://www.wdaqua.eu/qa#>
                    PREFIX oa: <http://www.w3.org/ns/openannotation/core/>
                    PREFIX dbo: <http://dbpedia.org/ontology/>
                    INSERT {{
                    GRAPH <{uuid}> {{
                        ?a oa:annotationText "{annotation_text}" .
                        ?a oa:annotatedBy <urn:qanary:{component}> .
                        ?a oa:annotatedAt ?time .
                        }}
                    }}
                    WHERE {{
                        BIND (IRI(str(RAND())) AS ?a) .
                        BIND (now() as ?time) 
                    }}
                """.format(
                    uuid=triplestore_ingraph_uuid,
                    component=SERVICE_NAME_COMPONENT.replace(" ", "-"),
                    annotation_text=result)

    insert_into_triplestore(triplestore_endpoint_url,
                            SPARQLquery)  # inserting new data to the triplestore
    # End TODO

    return jsonify(request.get_json())


@app.route("/health", methods=["GET"])
def health():
    return "alive"


if __name__ == "__main__":
    metadata = {
        "start": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        "description": SERVICE_DESCRIPTION_COMPONENT,
        "written in": "Python"
    }

    registration = Registration(
        name=SERVICE_NAME_COMPONENT,
        serviceUrl=f"{URL_COMPONENT}",
        healthUrl=f"{URL_COMPONENT}/health",
        metadata=metadata
    )

    reg_thread = Registrator(SPRING_BOOT_ADMIN_URL, SPRING_BOOT_ADMIN_USERNAME,
                            SPRING_BOOT_ADMIN_PASSWORD, registration)
    reg_thread.setDaemon(True)
    reg_thread.start()

    app.run(host='0.0.0.0', port=SERVICE_PORT, debug=True)

As you may see, several environment variables has to be set before the script execution:

  • SPRING_BOOT_ADMIN_URL -- URL of the Qanary pipeline (see Step 1 and Step 2 of the tutorial)
  • SPRING_BOOT_ADMIN_USERNAME -- the admin username of the Qanary pipeline
  • SPRING_BOOT_ADMIN_PASSWORD -- the admin password of the Qanary pipeline
  • SERVICE_HOST -- the host of your component without protocol prefix (e.g. http://). It has to be visible to the Qanary pipeline
  • SERVICE_PORT -- the port of your component (has to be visible to the Qanary pipeline)
  • SERVICE_NAME_COMPONENT -- the name of your component
  • SERVICE_DESCRIPTION_COMPONENT -- the description of your component

You may also change the configuration via environment variables to any configuration that you want (e.g. via a json file).

Step 3: Run the application

To run the component, simply execute python component.py in your terminal. If the component registration was successful, a corresponding message will appear in the output. Go to the admin panel of the Qanary Pipeline (e.g., http://webengineering.ins.hs-anhalt.de:43740/#/applications) to see your component's status.

Examples

Please see also the following example for a real-world Qanary component driven by qanary_helpers: https://github.com/WDAqua/Qanary-question-answering-components/tree/master/qanary_component-Python-QC-EAT-classifier

Clone this wiki locally