Qualitative Feedback Analysis (QFA) API.
Synopsis: a dockerized python API to analyze qualitative feedback.
Powered by open-source language models. Uses Poetry for dependency management.
- Prepare a kobo form as follows:
- add one question of type
text
, whose content will be classified. Example:feedback
. - add up to three cascading select questions of type
select_one
which will determine how the text will be classified. Example:type
,category
,code
. - fill in the possible choices in the
choices
sheet of the form exactly as explained here; these choices will be used as labels for the classification. - upload and deploy the form.
- add one question of type
Tip
The text will be classified according to the labels
of the choices. A few tips to improve the accuracy of the classification:
- Phrase the label as if explaining to a 10-year-old. This helps the classification model grasp the core idea without unnecessary complexity.
- The model cannot possibly know all humanitarian acronyms, so make sure to spell them out. Example: use
Water, Sanitation and Hygiene
instead ofWASH
, orRed Crescent
instead ofRC
. - Avoid using ambiguous labels and be specific. Example: use
distribution of non-food items
anddistribution of cash
instead ofrelief
andcash
. - The more choices you provide, the less accurate the classification will be. Keep the number of choices as low as possible.
- Try to use three synonyms when defining a label, for extra clarity. Example: use
misinformation, fake news and made-up stories
instead of onlymisinformation
.
- Register a new Kobo REST Service and configure it as follows:
- insert as
Endpoint URL
https://qfa-api.azurewebsites.net/classify-text
- add the following headers under
Custom HTTP Headers
:- under
Name
insertAPI-KEY
and underValue
insert the QFA API key (see Bitwarden). - under
Name
insertsource-text
and underValue
insert the name of the text question to be classified. Example:feedback
. - under
Name
insertsource-name
and underValue
insertkobo
. - under
Name
insertsource-origin
and underValue
insert the ID of the form (see where to find it). - under
Name
insertsource-authorization
and underValue
insert your Kobo token (see how to get one). - under
Name
insertsource-level1
and underValue
insert the name of the first of the cascading select questions. Example:type
. - under
Name
insertsource-level2
and underValue
insert the name of the second of the cascading select questions. Example:category
. - under
Name
insertsource-level3
and underValue
insert the name of the third of the cascading select questions. Example:code
. - [OPTIONAL] under
Name
inserttranslate
and underValue
inserttrue
, if you are using a language other than English; this will translate the text to English before classifying it (the results will still be in the original language, as specified in the classification schema).
- under
- insert as
That's it. Your submissions will be automatically classified in a few seconds. Happy qualitative feedback analysis!

- It is not possible to use repeating groups in Kobo forms and repeatedly submit the classification request to QFA. If it is needed to copy/paste data from a previous form into another multiple forms, one could look at how to use dynamic data attachments instead.
- It is not possible to edit an already submitted Kobo form and then re-submit with the goal of classifying again. Kobo does not allow the REST service to be triggered twice for the same submission.
Prerequisite: EspoCRM with Advanced Pack installed.
- Prepare EspoCRM as follows:
- Create or select one entity which will be classified, e.g.
Feedback
. - Create or select one field of type
Text
, whose content will be classified, e.g.feedbackText
. Tip: enableAudited
so that changes can be traced. - Create or select up to three entities which will determine how the text will be classified, e.g.
Type
,Category
,Code
. The records' names will be used as labels for the classification. - Link these three entities to the entity that will be classified, by creating a relationship of type
Many-to-One
for each of them. - Create a new role with
Read
permissions overType
,Category
,Code
, and assign this role to a new API user.
- Create or select one entity which will be classified, e.g.
Important
The classification schema is strictly hierarchical: each record of a low-level entity must be related to a record of
a high-level entity, e.g. each record of Category
must be related to a record of Type
, and each record of
Code
must be related to a record of Category
.
- Classification can then be performed automatically via Flowchart, using a Task with two Actions:
Send HTTP Request
to the QFA API
Request Type
POST
URL
https://qfa-api.azurewebsites.net/classify-text
Headers
API-KEY: <QFA API key>
source-name: espocrm
source-origin: <your EspoCRM instance URL>
source-authorization: <your EspoCRM API key>
source-level1: Type
source-level2: Category
source-level3: Code
[OPTIONAL] translate: true
Payload
{
"text": "{$feedbackText}",
}
Execute Formula Script
to save results to
typeId = json\retrieve($_lastHttpResponseBody, 'TypeId');
categoryId = json\retrieve($_lastHttpResponseBody, 'CategoryId');
codeId = json\retrieve($_lastHttpResponseBody, 'CodeId');
See the docs.
cp example.env .env
and edit the provided ENV-variables accordingly.
pip install poetry
poetry install --no-root
uvicorn main:app --reload