Skip to content

Questionnaire Recommendation

The questionnaire recommendation feature is designed to provide recommendations for both new and returning users. Here are the main steps to follow

  1. Design the questionnaire, i.e the Questions, options, decision based on answer, question types (Free text/checkbox/radio),
  2. Register the Questionnaire in GAIP,
  3. Register the Mapper in GAIP
  4. Implement the questionnaire in your Application, including sending the response to GAIP

Design the questionnaire

Come up with the questions considering what information you want to collect from the users, that will help us know user more and give personalized recommendations better.

For example, for a fashion E-commerce site, helpful information could be: age, gender, style, favorite color, etc.

On the other hand, for a beverage E-commerce site, helpful information could be: user's budget, taste preference, drinking occasion, etc.

Once the plan is ready, you are ready to move to the next steps.

Registration of Questionnaire

To manage the questionnaire, few API endpoints are provided our Sandbox under the "Questionnaire" section.

Basic operations - Questionnaire

  • Creating a new questionnaire: Make a POST request to /v1/questionnaires to create a new questionnaire. The questionnaire can be divided into different sections, with at least one required.

  • Listing all questionnaires: Sending a GET request to /v1/questionnaires/list lists all the questionnaire's ID and names. A project can host multiple questionnaires that are differentiated through these IDs.

  • Viewing a questionnaire: Make a GET request to /v1/questionnaires/{questionnaire_id} to retrieve a specific questionnaire's details.

  • Updating and deleting questionnaire: Use the PUT /v1/questionnaires/{questionnaire_id} and DELETE /v1/questionnaires/{questionnaire_id} endpoints to update or remove a questionnaire respectively.

How to get a "questionnaire_id"?

If you are registering a new questionnaire, in the success response, you will see the questionnaire_id.

If you want to get the questionnaire_id of existing questionnaires, you can hit GET /v1/questionnaires/list to see all existing questionnaires and their IDs.

Example request body - Create a new Questionnaire

Let's check a short example of an E-commerce website that sells cosmetics and skin care solutions. Below is a sample request body for POST /v1/questionnaires

{
  "name": "Name of your questionnaire",
  "questions": {
    "skincare_history": {
      "q1": {
        "question": "whats your age?",
        "type": "text",
        "options": {
          "age": ""
        }
      },
      "q2": {
        "question": "whats your gender?",
        "type": "radio",
        "options": {
          "a": "male",
          "b": "female"
        }
      }
    },
    "skincare_goal": {
      "q1": {
        "question": "what is your skincare concern?",
        "type": "checkbox",
        "options": {
          "a": "acne",
          "b": "anti-aging",
          "c": "Dullness",
          "d": "Dehydrated skin"
        }
      }
    }
  }
}

Lets go through the request body:

  • name: This is the title or the name of your questionnaire. This does not effect any functionality. Purpose of this is for the the admin, to identify questionnaires and know their purpose easily.
  • questions: This section will contain all the sections, questions and answer options.

  • Inside questions, you will see skincare_history and skincare_goal. These are "sections". At least one section is necessary for a questionnaire. You can also add multiple sections if you feel necessary. Note that questions are identified by the section and question number. Meaning, the same question number (for example q1) can be in multiple sections.

  • Next, q1, q2, these are question numbers. This would be needed later when we create the mapper. They must be unique inside a section. Inside them, we have the question, type and options. More details below:

  • question: You questions goes here
  • type: Currently we support three types of question. text (expect free input from user), radio (user can select only one answer) and checkbox (user can select multiple answer).
  • options: When the type is radio or checkbox, the options must be ordered like the example above, with a, b, c, and so on. If the type is text, the options should include the key for the input, such as "age": "" in the above example.

Registration of Questionnaire Mapper

A questionnaire mapper instruct the system about decisions based on user responses against each question. In the mapper we can also define how the response will be generated, how the search will be done and more. We will go through all those functions below. Questionnaires need one mapper each.

Basic operations - Questionnaire Mapper

  • Create a new mapper: Post /v1/questionnaires/{questionnaire_id}/mapper.
  • View the existing mapper: GET /v1/questionnaires/{questionnaire_id}/mapper.
  • Update existing mappers: PUT /v1/questionnaires/{questionnaire_id}/mapper.
  • Delete existing mappers: DELETE /v1/questionnaires/{questionnaire_id}/mapper.

First lets see a full example request body of a mapper, then we will review the components one by one. For the ease of understanding, this mapper will mostly reflect the questionnaire we saw above. However there is an extra question just for example and explanation purpose.

{
  "questions": {
    "skincare_history": {
      "q1": {
        "mapper": {
          "any": {
            "age": ""
          }
        }
      },
      "q2": {
        "mapper": {
          "a": {
            "gender": "male"
          },
          "b": {
            "gender": "female"
          }
        }
      },
      "q7": {
        "mapper": {
          "~": {
            "a|b|c": {
              "exclude": [
                "Retinol"
              ]
            }
          }
        }
      }
    },
    "skincare_goal": {
      "q1": {
        "mapper": {
          "a": {
            "skincare_concern": "acne"
          },
          "b": {
            "skincare_concern": "anti-aging"
          },
          "c": {
            "skincare_concern": "Dullness"
          },
          "d": {
            "skincare_concern": "Dehydrated skin"
          }
        }
      }
    }
  },
  "exclusive": {
    "prompt_key-1": "prompt_key-2"
  },
  "prompt_sections": {
    "skincare_history": "I am {age} years old {gender}",
    "skin_type": "My skin type is {skin_type}",
    "include": "include these category {include}"
  },
  "prompt_order": [
    "skincare_history",
    "include",
    "skin_type"
  ],
  "recommend_count": 3,
  "gpt_profile": "GPT profile ID",
  "result_format": {
    "key_name": "product_categories",
    "value_must_contain": [
      "Skincare"
    ],
    "excludes": [
      "exclude_tag",
      "exclude_category"
    ],
    "required": [
      "Facewash",
      "Toner/Lotion"
    ],
    "optional": {
      "Anti-Aging": [
        "anti aging",
        "Dullness"
      ],
      "Acne care": [
        "acne"
      ]
    },
    "order_by": {
      "sale_count": "desc"
    },
    "flags": {
      "has_out_of_stock_variants": "false"
    },
    "cluster_size": 1000
  },
  "result_includes": [
    "key_name_1",
    "key_name_2"
  ],
  "top_k": 20,
  "is_keyword_enabled": true
}

Now lets go through each items

Questions

Inside a question object we map the answer of each questions for all values.

As mentioned above, questionnaire can have three types of questions

  1. Radio button: User can select a single answer,
  2. Checkbox: User can select multiple answers,
  3. Free text: User can enter string.

To add mapper for a single value, use the value key as the key for related decision objects. This approach allows you to define how the system should handle or process that value.

Example

{
  "skincare_history": {
    "q2": {
      "mapper": {
        "a": {
          "exclude": ["Retinol",  "Retinol based products"]
        }
      }
    }
  }
}

In the above example, we are targeting the question q2 of the section skincare_history. the key a represents answer selected by user. The object associated with a specifies decisions related to it—in this case, an exclude list. This list contains the values Retinol and Retinol based products, defined by the creator of the mapper. How this Exclude list is used is covered in a latter section below.

To add mapper for a combination of value (Answers with multiple selection):

  • Use | sign as or to combine more than one values for a decision in mapper.
  • Use & sign as and to combine more than one values for a decision in mapper. Example
{
  "a|b|c": {
    "exclude": ["Retinol",  "Retinol palmitate"]
  }
}

To add mapper for free-text value, use any key to add the decision rule. This can be useful for taking age, allergy information etc. Example

{
  "any": {
    "age": ""
  }
}

When a decision need to be taken if a set of value is not selected, we can use negative selection.

An example scenario.

Question: What of the following skincare you follow every day?

  • a. Cleanser
  • b. Moisturizer
  • c. Spf
  • d. Serum
  • e. Toner
  • f. Night cream
  • g. Eye cream

Decision: if cleanser, moisturizer and spf is chosen, AI will consider all products

If one of the basic step(cleanser, moisturizer, spf) is not chosen, Ai will exclude Retinol, vitamin C, vitamin C derivative , arbutin

Here we need to take a decision if cleanser, moisturizer, spf is not selected, this is a candidate for negative selection.

Rules: Use ~ as key to add negative selection decisions in a question mapper. Use value serial as usual inside the negative selection object to add decision if a value is not selected, e.g. "a": "decision" Example

{
  "q1": {
    "mapper" : {
      "a": {
        "tags": ["acne", "anti-aging"]
      },
      "~": {
        "a|b|c": {
          "exclude": ["Retinol",  "vitamin c",  "vitamin c derivative" , "arbutin"]
        },
        "d": {
          "tags": ["Retinol"]
        }
      }
    }
  }
}

Exclusivity

The integration of exclusivity in the mapper is crucial for eliminating duplicates and addressing exclusivity prerequisites.

To incorporate exclusivity, you utilize the exclusive key to append an object in the following format:

"prompt_key-1" :  "prompt_key-2"

Doing so ensures that any value present in both prompt_key-1 and prompt_key-2, within the final prompt, will be extracted exclusively from prompt_key-2.

For instance:

{
  "exclusive": {
    "exclude": "includes",
    "exclude_tag": "include_tag"
  }
}

In the above example, if a keyword exist in both list exclude and includes, then the keyword will be removed from the list includes.

prompt_sections and prompt_order

In a way, a primary goal of the questionnaire feature, is to make a good prompt for our contextual search to find the right product for the user. This section of the mapper plays a big role in generating that prompt.

First, in the prompt_sections we define the variables and the sentences. Then in the prompt_order we define the order of those sentences, which finally creates the prompt.

The prompt_sections has two constituting parts, the sentence and the variable. This are the variables we talked about before, such as excludes or exclude_tags or age or tag etc. Let's say we have a decision point to exclude products that has certain tags. We can add a prompt section named exclude_tags as follows

{
  "prompt_sections": {
    "exclude_tags": "Exclude any products that has following tags {exclude_tags}."
  }
}

And We need to add the exclude_tags in mapper wherever this decision point need to be mapped. An example mapper, like we have discussed above, would be

{
  "q1": {
    "mapper": {
      "a": {
        "exclude_tags": ["retinol", "retinol based products"]
      }
    }
  }
}

An complete example prompt_sections for a cosmetics company could be.

{
  "prompt_sections": {
    "age": "I am {age} years old.",
    "gender": "I am a {gender}.",
    "skin_type": "My skin type is {skin_type}.",
    "include_tag": "Show products that contain the tag: {include_tag}",
    "exclude_tag": "Exclude products that do contain the tag: {exclude_tag}"
  }
}

Then in the prompt_order section, decide the order of the prompts section above. You will notice that this order, might impact the result quality. Some test and trials might be required here to find the best outcome. Note that this section MUST contain all the prompts from the above section.

An example prompt order from the prompt_sections sample above sample could be:

{
  "prompt_order": [
    "age",
    "gender",
    "skin_type",
    "include_tag",
    "exclude_tag"
  ]
}

recommend_count

The recommendation of products for questionnaire/recommend is categorized. How the categories are decided is in the next section. Here in this section, we define how many products will be shown under each category. This count can also be in the API request of questionnaire/recommend. But if there is no recommend_count in that payload, this value will be used.

result_format

In this section, you can specify how the results should be categorized or grouped.

Use the key_name parameter to define the grouping criteria, such as product categories or tags.

The value_must_contain parameter specifies the required (Must have) values for key_name.

Under excludes, you can define if there are values that must be excluded. For now, it can only have keys/variables defined in the mapper. Such as, the above example exclude_tag.

Next, define the structure of the results using the required and optional parameters. The categories that are required, will always be in the result. The optional categories will only show up when the keywords are present in the prompt. Note that this required and optional parameters must have values that are under the key defined in key_name

You can optionally use order_by parameter to order you result based on certain values such as sale_count, or liked/wishlisted, top reviewed etc.

flags can be used to pass boolean values incase you want to include or exclude products based on certain attributes.

cluster_size decides the size of the cluster of items from the database that will be considered initially as result candidates. We recommend to keep it default unless you fully understand how this will impact.

result_includes

Here you can decide which product attributes you want the API response to have, such as the product price, brand, category etc.

Other search settings

Value of top_k can be set between 1-20. Higher values consider more items, potentially less relevant; lower values are stricter, considering fewer but more relevant items.

is_keyword_enabled can be true or false. Indicates if keyword search is enabled (true) or not (false).

Integration of Questionnaire Recommendation

To integrate questionnaire feature in your system, use the the endpoint POST /v1/questionnaire/recommend.

The endpoint expect the user responses in a certain format. If you have gone through the tutorial above, you know by now how the questionnaire and the mapper setup is done. Next we will see the request body for this endpoint.

Example request body

Here is an example request body for questionnaire/recommend

{
  "user_id": "a0cc6beb-2909-459b-be55-62196af78ce4",
  "member_id": "df3456tg-2909-459b-be55-62196afedf85",
  "questionnaire_id": "c8e9fd30-1d85-4bd6-929a-47cc509c5756",
  "values": {
    "section_name": {
      "q1": "c",
      "q2": "a",
      "q3": "b"
    }
  },
  "recommend_count": 3,
  "result_includes": [
    "key_name_1",
    "key_name_2"
  ],
  "top_k": 20,
  "is_keyword_enabled": true
}

Now let's review each parameter

  • user_id: Mandatory field. Represents the ID of a unique logged-out user, stored in the browser or app local storage. Used for showing and personalizing similar items.
  • member_id: Optional field. Represents the ID of a unique logged-in user, such as a phone number or email address, which can identify the user across devices. Used for showing and personalizing similar items.
  • questionnaire_id: as input. This identifier helps determine which questionnaire and mapping to refer to understand the user responses and generate the result.

Next, for parameters recommend_count, result_includes, top_k, is_keyword_enabled , the explanation and use is same as mentioned above in the mapper section. The values in the mapper will be used if this are empty in the request body of questionnaire/recommend. However if you pass this values here, this will take priority.

Reviewing Questionnaire Recommendation Logs

By utilizing the endpoint GET /v1/questionnaires/{questionnaire_id}/logs, you're able to access the log of requests dispatched to the v1/questionnaire/recommend endpoint, along with the corresponding generated responses.