<- All posts

Artificial Intelligence Tickets with 果冻视频 and OpenAI

Ronan McQuillan
19 min read Jun 26, 2024

Ticketing systems are some of the most common internal tools there are. They鈥檙e central to all kinds of ITSM, HR, finance, ops, and other workflows. However, they can also introduce huge amounts of tedious admin work.

This includes basic tasks like categorizing and prioritizing issues, assigning tasks, directing users to self-service resources, and handling communications.

Today, we鈥檙e checking out how we can use artificial intelligence to drive more efficient ticketing workflows.

Specifically, we鈥檙e going to see how 果冻视频鈥檚 OpenAI integration makes it a breeze to build advanced, custom AI-assisted ticketing tools.

By the end of this guide, you鈥檒l have a fully functional solution that you can modify to your specific requirements.

Let鈥檚 start with the basics.

What is an AI ticketing system?

Ticketing systems allow users to submit information about requests, issues, incidents, bugs, or cases.

Service desk colleagues can then view, manage, and respond to tickets.

The idea is to create a centralized platform for receiving and handling service requests according to consistent rules and processes.

This supports a whole range of related workflows. This includes data collection, categorizing and routing issues, prioritizing tickets, scheduling tickets, communicating with stakeholders, and recording outcomes.

An AI ticketing system uses artificial intelligence to assist with these with the goal of providing faster, more effective resolutions to service users. This could be user-facing tasks, such as recommending knowledge base articles or even providing a chatbot.

Alternatively, we might leverage AI for back-end tasks, like categorizing tickets or routing them to relevant service agents.

Check out our round-up of the top ServiceNow alternatives to learn more.

Why use AI for ticketing?

So, how does artificial intelligence improve our ticketing workflows?

We can think about this at two levels. The first is efficiency. That is, we can use AI to perform many tasks that would otherwise require our service agents鈥 attention. In turn, this means we can provide faster resolutions with lower labor costs.

The second is service quality.

In addition to providing faster responses, AI-powered ticketing can be leveraged to improve outcomes. For instance, providing highly personalized responses at scale or using insights to predict future service needs.

That leads us to鈥

What are we building?

We鈥檙e building a powerful artificial intelligence ticketing system for handling ITSM requests. The goal is to empower users to submit tickets using natural language. We鈥檒l then use OpenAI to categorize and prioritize submissions.

That way, users have a fast, easy way to input ticket data. We鈥檙e even going to add translation capabilities to provide multilingual ticketing.

We鈥檙e using 果冻视频 to build our UIs, data layer, and automation rules. We鈥檒l start by using our low-code database to set up a data model for our ticketing system.

We鈥檒l then use the dedicated OpenAI integration in our automation builder to create prompts based on our users鈥 submissions to categorize, translate, and, if required, translate our tickets.

Then, we鈥檙e going to build interfaces for service users and service desk colleagues to submit, view, and manage tickets, leveraging 果冻视频鈥檚 autogenerated CRUD UIs and built-in role-based access control.

Here鈥檚 what our artificial intelligence ticketing system will look like when we鈥檙e done.

You might also enjoy our guide to open-source help desk software .

Let鈥檚 start building.

Building an AI ticketing system in 5 steps

The first thing you鈥檒l want to do is sign up for a free 果冻视频 account to start building as many apps as you want. We offer a cloud-based product, but today we鈥檙e going to use a self-hosted instance so that we can access the OpenAI integration.

Join 200,000 teams building workflow apps with 果冻视频

We鈥檒l start by creating a new application. We can import an existing app dump or use one of 果冻视频鈥檚 pre-built templates, but today, we鈥檙e going to start from scratch.

When we choose this option, we鈥檒l be prompted to give our app a name that will also be used to generate a URL slug.

We鈥檒l call ours AI Ticketing System.

Artificial Intelligence Tickets

1. Setting up our ticketing data

Once we鈥檝e done this, we鈥檒l be prompted to choose a data source for our application. 果冻视频 offers dedicated connectors for querying relational databases, NoSQL tools, data warehouses, spreadsheets, APIs, and more.

果冻视频 acts as a proxy to query external data sources without storing them in our platform.

Data Sources

However, we鈥檙e going to import a CSV into 果冻视频DB. When we choose this option, we鈥檙e prompted to give our data table a name and select a file to upload. We鈥檙e going to call our table Tickets.

Table

Here鈥檚 the we鈥檙e using.

When we upload this, we鈥檒l be prompted to configure the data types of each individual column. Some of our columns can be left as the default option of Text, but we鈥檒l need to make the following changes:

  • Description - Long-Form Text,
  • Status - Options,
  • Priority - Options,
  • Date Created - Date,
  • Date Updated - Date,
  • Category - Options,
  • Comments - Long-Form Text,
  • Translated Comments - Long Form Text.

Here鈥檚 what this should look like.

Import

Once our data is imported, we can edit the schema and values with a spreadsheet-like experience in 果冻视频鈥檚 Data section.

Database

Before we move on, we need to make a few more minor tweaks.

A second ago, we set three of our columns to the Options type. However, for this to work, we need to set the available options for each.

We can do this by hitting Edit Column.

Options

The options we鈥檙e setting for each column are:

  • Status - Open, Closed, In-Progress,
  • Priority - High, Medium, Low,
  • Category - Hardware, Software, Network, Security, Account, Service Request, Other.

Ticket Category

Adding translation columns

The last change we鈥檙e going to make to our data model is adding a couple of extra columns that will allow us to handle multi-lingual ticketing.

First, we鈥檒l use the plus icon to add a new column with the Boolean type and call it Translated.

Translation

Then, we鈥檒l add a JSON column and call it Ticket Translation.

JSON

We鈥檒l need to define the schema of the JSON objects we鈥檙e going to store. Hit Open Schema Editor and we鈥檒l add two strings called Title and Description.

Schema

And that鈥檚 our data model ready to go.

2. Connecting to OpenAI

Next, we can start building our AI-driven ticketing logic. 果冻视频 offers a dedicated integration for the OpenAI API, making it easy to send prompts from directly within our platform.

In order to utilize this, you鈥檒l need to add your API key as an environment variable within your 果冻视频 installation.

Check out our to learn more.

Creating an automation

Head to the Automation section. Here, we鈥檒l create a new rule and call it New Ticket. We have a choice of several triggers, including user actions, webhooks, database events, and chron expressions.

Today, we鈥檙e going to choose App Action.

Create Automation

We can set our trigger to accept arguments whenever it鈥檚 initiated. We鈥檙e going to set three variables called rowID, title, and description. Later, we鈥檒l bind these to corresponding values from a given row in our database from our UI.

Trigger

You might also like our guide to web application development .

Writing prompts

Next, we鈥檒l hit the plus icon to add an automation action and choose OpenAI.

Automation Step

This action block offers two fields: Prompt, where we can write our ChatGPT prompt, and Model, where we can choose a specific LLM. We鈥檙e leaving our Model set to the default option of GPT-3.5 Turbo.

Artificial Intelligence Tickets

Before we start writing our prompt, let鈥檚 remind ourselves what we want ChatGPT to do.

Based on the Title and Description that users submit within their tickets, we want to assign the Category, Priority, and Language attributes. If the ticket is submitted in a language other than English, we鈥檒l also populate the Translated Ticket JSON object and set Translated to true.

We want our response to provide this information as a JSON blob so that we can use it later in our automation run.

Start by hitting the lightning bolt icon beside Prompt to open the bindings drawer. Here, we can access all of the data our action is exposed to, including the arguments that were passed to our trigger.

The first thing we want to do in our prompt is provide the Title and Description, and give context to what these are using the following statement:

The following text is the title and description field from an IT ticket: Title: {{ trigger.fields.title }}, Description: {{ trigger.fields.description }}.

Prompt

We鈥檒l then add a statement to translate the ticket if it鈥檚 not already in English.

The following text is the title and description field from an IT ticket: Title: {{ trigger.fields.title }}, Description: {{ trigger.fields.description }}.

If a ticket is submitted in a language other than English, translate it to English before proceeding.

The first attribute we want to set is our ticket鈥檚 category. We鈥檒l do this by providing the same options that we defined in our data model earlier.

The following text is the title and description field from an IT ticket: Title: {{ trigger.fields.title }}, Description: {{ trigger.fields.description }}.

If a ticket is submitted in a language other than English, translate it to English before proceeding.

Use this to decide if the ticket's category should be Hardware, Software, Security, Network, Account, Service Request, or Other.

Of course, we could provide more detailed logic for how to choose the category, but for demo purposes, we鈥檒l keep it simple.

Hit Save, and we鈥檒l test what we have so far by providing the information from one of our existing rows.

Test

And we can see that ChatGPT is returning 鈥渁ccount鈥 which is the appropriate category for a password reset ticket.

Response

We can carry on making adjustments to our prompt and testing the responses as necessary.

We鈥檒l also add a statement with some basic logic on setting a priority level.

The following text is the title and description field from an IT ticket: Title: {{ trigger.fields.title }}, Description: {{ trigger.fields.description }}.

If a ticket is submitted in a language other than English, translate it to English before proceeding.

Use this to decide if the ticket's category should be Hardware, Software, Security, Network, Account, Service Request, or Other.

Also, provide a priority based on how many employees it is likely to affect - High, Medium, or Low.

And again, we鈥檒l test this out.

Response

However, our response now includes the rationale for why a particular priority level was chosen. We don鈥檛 want this, so we鈥檒l need to add a statement on how to format our response.

The following text is the title and description field from an IT ticket: Title: {{ trigger.fields.title }}, Description: {{ trigger.fields.description }}.

If a ticket is submitted in a language other than English, translate it to English before proceeding.

Use this to decide if the ticket's category should be Hardware, Software, Security, Network, Account, Service Request, or Other.

Also, provide a priority based on how many employees it is likely to affect - High, Medium, or Low.

Response should be parsable key/value pairs.

Here鈥檚 what our new response looks like.

Response Object

Lastly, we鈥檙e going to add a statement to provide the English version of the submitted Title and Description, the original language, and a boolean value for whether or not the submission was translated.

The following text is the title and description field from an IT ticket: Title: {{ trigger.fields.title }}, Description: {{ trigger.fields.description }}.

If a ticket is submitted in a language other than English, translate it to English before proceeding.

Use this to decide if the ticket's category should be Hardware, Software, Security, Network, Account, Service Request, or Other.

Also, provide a priority based on how many employees it is likely to affect - High, Medium, or Low.

When a ticket is translated, return the title and description as translatedTitle and translatedDescription. Provide a boolean value for whether or not the original ticket was translated. Call this translated. Also, return the original language and call it language.

The response should be parsable key/value pairs.

Now, we鈥檒l test this out with a non-English submission.

German

And we can see that OpenAI has correctly identified German as the original language and translated our submission into English.

Artificial Intelligence Tickets

Assigning values based on our response

Once we鈥檙e happy with our prompt, we need to add an action that will add the values it generated to the original row in our tickets table. We鈥檒l do this by adding an Update Row action and setting the Row ID setting to the corresponding value from our trigger.

Update Row

We need to assign values to the Priority, Category, Ticket Translation, Translated, and Language fields, based on the response from our ChatGPT prompt.

The easiest way to do this is using the JSON.parse() JavaScript method to access the individual values. Start by hitting the lightning bolt icon next to the priority field and selecting JavaScript. Here, we鈥檒l add the following code.

1var jsonString = $("steps.1.response")
2
3var ticketObject = JSON.parse(jsonString);
4
5// Access individual values
6
7var priority = ticketObject.priority;
8
9return priority

JavaScript

We鈥檒l use very similar code for our remaining fields. Here鈥檚 what this will look like for our Category.

1var jsonString = $("steps.1.response")
2
3var ticketObject = JSON.parse(jsonString);
4
5// Access individual values
6
7var category = ticketObject.category;
8
9return category

Language:

1var jsonString = $("steps.1.response")
2
3var ticketObject = JSON.parse(jsonString);
4
5// Access individual values
6
7var language = ticketObject.language;
8
9return language

Translated:

1var jsonString = $("steps.1.response")
2
3var ticketObject = JSON.parse(jsonString);
4
5// Access individual values
6
7var translated = ticketObject.translated;
8
9return translated

And Ticket Translation:

 1const jsonString = $("steps.1.response");
 2
 3// Parse the JSON string into a JavaScript object
 4
 5const ticketObject = JSON.parse(jsonString);
 6
 7const translatedTitle = ticketObject.translatedTitle;
 8
 9const translatedDescription = ticketObject.translatedDescription;
10
11// Create a JSON object directly
12
13const jsonObject = {
14
15  Title: translatedTitle,
16
17  Description: translatedDescription
18
19};
20
21// Return the jsonObject
22
23return jsonObject

We鈥檒l then test this out with the data from one of our real rows and confirm that it has executed as expected.

Automation Test

Translating comments

We鈥檙e going to add a second automation rule that will handle translations for comments from our service agents.

Our data model contains a column called Comments, where service agents can submit extra information about the tickets, and one called Translated Comments, where we can provide these in the ticket鈥檚 original language.

We鈥檒l start by creating a new rule called Translate Comments, again using an App Action Trigger. We鈥檒l set our trigger arguments to rowId, language, and comment.

Trigger

We鈥檒l then add an OpenAI action with the following prompt.

Translate the following response from English into {{ trigger.fields.language }}

{{ trigger.fields.comment }}

Prompt

Then, we鈥檒l add an update row action, setting our Row ID to {{ trigger.fields.rowID }} and our Translated Comments to {{ steps.1.response }}.

As ever, we can test this to confirm that it worked.

Translation

3. Building a ticketing form

Now, we鈥檙e ready to start building user interfaces for our artificial intelligence ticketing system.

Head to the Design tab, and we鈥檒l be shown a few options for how we want to create our first screen, including several options for autogenerating layouts based on connected data tables.

New Screen

The first thing we want to build is a screen where service users can submit tickets. So, we鈥檙e going to select the Form layout. We鈥檒l then be asked which data table we want to point this at, although our app only has one table anyway.

Table

We then need to choose a form type. We want to create a new row.

New Row

When we鈥檙e asked to choose an access role, we鈥檒l leave this set to the default option, Basic.

RBAC

The Form layout generated a working data collection form based on the schema of whichever table we select.

Here鈥檚 what this looks like out of the box.

Form

However, we don鈥檛 need to display form fields for most of our table鈥檚 columns. We鈥檙e going to start by deselecting everything except Title and Description using the sliders on the right-hand side.

We鈥檒l also replace our form Title with something more descriptive.

Ticketing Form

Under Styles, we鈥檒l also set our Button Position to Top.

Button Position

Lastly, since our form UI only offers subset of our tables fields, we鈥檒l need to populate the rest of these automatically. Some of these can be added by triggering our New Ticket automation, but the rest will need to be added manually.

Start by opening the actions drawer for our Save button. Under the Save Row action, we鈥檒l hit the Add Column button to populate values for the Status and Date Created fields. We鈥檒l set Status to Open and Date Created to the following JavaScript expression.

1var date = new Date();
2
3return date;

However, we also want to add a record of who created the ticket. Back in the Data section, we鈥檒l add a Single User column called Created By. This will link rows in our Tickets table to 果冻视频鈥檚 internal Users table.

User Column

Then, under our Save Row button action, we鈥檒l bind this new column to {{ Current User._id }}.

Created By

Next, we鈥檒l add a button action to trigger our New Ticket automation. We鈥檒l use bindings to set the rowID to the _id of the row we just saved and the title and description to the corresponding values from our form.

Trigger Automation

Eventually, we鈥檙e going to display this form in a modal UI, so we鈥檒l also add a Close Screen Modal action.

Close Modal

Lastly, we鈥檒l publish our app and submit a row of data to confirm that our form behaves as expected.

Note that automations won鈥檛 run in our app preview, only in the live application.

AI Ticketing System

And we鈥檒l check that this works in our Data section.

Database

Viewing previous submissions

Next, we鈥檙e going to add a screen where service users can view their ticket submissions. Start by hitting the plus icon to add a new screen. This time, we鈥檙e choosing the option for a table with detailed side-panels.

Again, we鈥檒l choose our Tickets table and leave the access role set to Basic. This will output a working CRUD UI based on our table鈥檚 schema.

CRUD Screen

However, as we said a second ago, we only want to display tickets that were created by the current user. So, we鈥檒l add a filtering expression on our Table Block component, setting the Created By attribute to {{ Current User.globalId }}.

Filter

Now, we can only see the records that are associated with our user account.

Filtered Table

Next, we鈥檒l tidy up our table by deselecting any columns that are lower priority.

Configure Columns

Currently, if a user hits the Create Row button, it will open a form in a side panel. However, we just created a custom form that we want to display in a modal UI. We鈥檒l start by opening the actions drawer for our button and deleting the existing action with the X icon.

Side Panel

We鈥檒l then add a Navigate To action, point this at our form screen, and select the option to use a modal.

Navigate to

We鈥檒l also set our button鈥檚 display text to something more descriptive.

new ticket

Lastly, we can access a side panel for editing entries by clicking on any of our table鈥檚 rows. We鈥檙e going to make a few tweaks to this. Specifically, we鈥檒l set the Type to View, update our Title, and deselect any fields that aren鈥檛 relevant to service users.

Form

That鈥檚 it for our service user screens.

4. Adding admin screens

Next, we want to add an equivalent screen where service desk colleagues can view and respond to all tickets.

We鈥檒l start by adding another screen with the same Table layout, only this time we鈥檒l set our minimum access role to Power.

RBAC

We鈥檒l start by repeating the process of reducing the display columns, and then we鈥檒l delete the Create New button entirely.

crud

Adding searchability and filtering

Next, we want to make it easy for service agents to find specific tickets. To do this, we鈥檒l use a component called a Dynamic Filter, which allows users to set complex filtering expressions from the front end.

To do this, we鈥檒l first need to add a component called a Data Provider. This accepts a data source and exposes other components on the screen to it. We鈥檙e setting ours to our Tickets table.

data provider

We鈥檒l then set our Table block to the output of our Data Provider.

Filtering

And we鈥檒l add our Dynamic FIlter alongside our Heading, pointing it at our Data Provider.

Dynamic filter

Now, we can use this to create custom filtering expressions in our app鈥檚 front end.

filtering

Updating our edit form

Lastly, we鈥檙e going to make some key changes to the edit form on this screen, too.

Specifically, we want to make some fields editable while others will be read-only. We鈥檙e also going to use 果冻视频鈥檚 custom conditionality rules to display the translated submission for non-English tickets instead of the original values.

We鈥檒l start by editing our Edit Row Form block to hide the Translated Comments, Translated Ticket.Title, and Translated Ticket.Description fields.

Form

We鈥檒l then update our title.

Artificial Intelligence Tickets

Next, we鈥檒l select the Disabled option on all form fields except for Status, Category, Priority, and Comments.

Disabled

Now, our service desk colleagues will be able to edit certain fields but only view others.

The last piece of functionality we want to add is dynamically displaying either the original ticket submission or the translated version, depending on which language it was submitted in.

The easiest way to do this is to start by ejecting our Form Block exposing its underlying components.

Eject

Now, we can see each of the individual fields that make up our form.

Component Tree

Select the Title field and open the conditions drawer.

conditions

Here, we can create rules to hide, display, or update the native settings of our components based on any of the data they鈥檙e exposed to.

To start, we鈥檒l create a rule that updates the Field component to Ticket Translation.Title when {{ Repeater.Tickets.Translated }} equals True.

Condition

Then, we鈥檒l add a second rule that updates the Label setting to Title (Translated From {{ Repeated.Tickets.Language }}) when the same condition is met.

Conditions

We鈥檒l also repeat this process for the description field.

Description

To wrap up, we鈥檙e going to make a couple of tweaks to our Save button actions, just like we did before. Specifically, we want to populate the Date Updated value and trigger our Translate Comments automation.

So, we鈥檒l start by opening the Save Row action and hitting Add Column. Just like we did earlier, we鈥檙e going to set Date Updated to the following JavaScript.

1var date = new Date();
2
3return date;

Date

Then, we鈥檒l add a Trigger Automation action pointed at our Translate Comments rule. We鈥檒l bind the rowID argument to {{ Repeater.Tickets._id }}, the language to {{ Repeater.Tickets.Language }}, and the comment to {{ Form.Fields.Comments }}.

ARguments

We鈥檒l publish and open our app to confirm this works by adding a comment to our ticket in English.

Comment

And back on our service user screen, we can see that our comment has been translated back into the original ticket language.

Translation

5. Design tweaks and publishing

From a functional point of view, our artificial intelligence ticketing system is ready to go.

However, before we push it live for users, we鈥檙e going to make a few final design adjustments.

First of all, each group of users can only really access a single screen. So, we can remove the links from our nav bar.

To do this, head to Navigation and remove each individual link using the X icon.

Nav

Here鈥檚 how this should look.

Nav

Next, under Screen, we鈥檒l head to Theme and select Midnight.

Theme

While we鈥檙e here, we鈥檒l also update our default accent colors to match the 果冻视频 brand.

Button Color

When we鈥檙e happy, we鈥檒l hit Publish one final time to push our app live.

Publish

Here鈥檚 a reminder of what our finished artificial intelligence ticketing system looks like.

Artificial Intelligence Tickets

果冻视频 is the open-source, low-code platform that empowers IT teams to turn data into action.

Check out our features overview to learn more.