Artificial Intelligence Tickets with 果冻视频 and OpenAI

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.
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.
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.
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.
Once our data is imported, we can edit the schema and values with a spreadsheet-like experience in 果冻视频鈥檚 Data section.
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.
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.
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.
Then, we鈥檒l add a JSON column and call it Ticket Translation.
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.
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.
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.
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.
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.
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 }}.
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.
And we can see that ChatGPT is returning 鈥渁ccount鈥 which is the appropriate category for a password reset ticket.
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.
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.
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.
And we can see that OpenAI has correctly identified German as the original language and translated our submission into English.
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.
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
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.
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.
We鈥檒l then add an OpenAI action with the following prompt.
Translate the following response from English into {{ trigger.fields.language }}
{{ trigger.fields.comment }}
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.
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.
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.
We then need to choose a form type. We want to create a new row.
When we鈥檙e asked to choose an access role, we鈥檒l leave this set to the default option, Basic.
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.
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.
Under Styles, we鈥檒l also set our Button Position to Top.
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.
Then, under our Save Row button action, we鈥檒l bind this new column to {{ Current User._id }}.
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.
Eventually, we鈥檙e going to display this form in a modal UI, so we鈥檒l also add a Close Screen Modal action.
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.
And we鈥檒l check that this works in our Data section.
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.
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 }}.
Now, we can only see the records that are associated with our user account.
Next, we鈥檒l tidy up our table by deselecting any columns that are lower priority.
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.
We鈥檒l then add a Navigate To action, point this at our form screen, and select the option to use a modal.
We鈥檒l also set our button鈥檚 display text to something more descriptive.
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.
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.
We鈥檒l start by repeating the process of reducing the display columns, and then we鈥檒l delete the Create New button entirely.
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.
We鈥檒l then set our Table block to the output of our Data Provider.
And we鈥檒l add our Dynamic FIlter alongside our Heading, pointing it at our Data Provider.
Now, we can use this to create custom filtering expressions in our app鈥檚 front end.
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.
We鈥檒l then update our title.
Next, we鈥檒l select the Disabled option on all form fields except for Status, Category, Priority, and Comments.
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.
Now, we can see each of the individual fields that make up our form.
Select the Title field and open the conditions drawer.
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.
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.
We鈥檒l also repeat this process for the description field.
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;
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 }}.
We鈥檒l publish and open our app to confirm this works by adding a comment to our ticket in English.
And back on our service user screen, we can see that our comment has been translated back into the original ticket language.
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.
Here鈥檚 how this should look.
Next, under Screen, we鈥檒l head to Theme and select Midnight.
While we鈥檙e here, we鈥檒l also update our default accent colors to match the 果冻视频 brand.
When we鈥檙e happy, we鈥檒l hit Publish one final time to push our app live.
Here鈥檚 a reminder of what our finished artificial intelligence ticketing system looks like.
果冻视频 is the open-source, low-code platform that empowers IT teams to turn data into action.
Check out our features overview to learn more.