Quickstart
- SDK Installation & Setup Guide
- Platform Quickstarts
StateSet One
- Guides
StateSet Response
- Core Concepts
- Guides
- Getting Started
- Agent Development
- Features
- Integrations
- Advanced Features
- E-commerce Workflows
StateSet Commerce
- Guides
Gorgias Ticket Quickstart
Getting started with Gorgias Ticket Embeddings
Prerequisites
Before setting up Gorgias integration, ensure you have:
Gorgias Account
- Active Gorgias account with API access
- Gorgias API credentials (client ID, client secret, refresh token)
- Admin permissions to install integrations
Vector Database
- Pinecone account and API key for vector storage
- Pinecone index created with appropriate dimensions
- Understanding of vector embeddings concepts
AI Services
- OpenAI API key for embeddings generation
- Understanding of similarity search principles
- Familiarity with RAG (Retrieval Augmented Generation)
Technical Setup
- Node.js 16+ installed
- Basic understanding of REST APIs and JavaScript
- Access to your Gorgias ticket data for testing
Quickstart Guide
This is a quickstart guide to get you up and running with the Gorgias Ticket Embeddings. This guide will walk you through the steps to get your Gorgias ticket data into Pinecone and create embeddings for each ticket.
Authentication
Gorgias Ticket Embeddings
Once you have installed the app we can create embeddings and store your Gorgias ticket data in Pinecone, you can create embeddings for each ticket. Embeddings are vector representations of your ticket data. You can use these embeddings to find similar tickets or to create a recommendation system.
Loop Through Tickets
Loop Through Gorgias Ticket Data
Create Embeddings
Create embeddings for each ticket and message, and store in Pinecone
Store Chunks of Ticket Data
Store the vector representation of the ticket data in Pinecone and associated metadata with the ticket data
// Main function to create tickets feed
const createTicketFeed = async (req, res) => {
console.log('Creating Ticket Feed');
var pinecone_index = "";
var pinecone_api_key = "";
var pinecone_namespace = "";
var shop = "";
var shopify_access_token = "";
var account = "";
try {
var client_id = ""
var client_secret = ""
async function refreshToken(account, clientId, clientSecret, refreshToken) {
const data = new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: refreshToken,
}).toString();
const config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`,
},
};
return axios.post(`https://${account}.gorgias.com/oauth/token`, `grant_type=refresh_token&refresh_token=${refreshToken}`, config)
.then((response) => {
console.log('Refresh Token Response:', response.data.access_token);
return response.data;
})
.catch((error) => {
console.error(error);
});
};
const token = await refreshToken(account, client_id, client_secret, gorgiasRefreshToken);
const limit = 5;
const maxPage = 1000;
const requestOptions = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token.access_token}`,
},
};
const viewId = 525587
const response = await fetch(`https://${account}.gorgias.com/api/tickets?limit=${limit}&viewId=${viewId}`, requestOptions);
// Get Ticket and the next cursor from response from axios call
const next_j = await response.json();
var next_token_j = next_j.meta.next_cursor;
console.log('cursor', next_token_j);
await getGorgiasTickets(next_token_j, account, limit, maxPage, token.access_token, pinecone_index, pinecone_api_key, pinecone_namespace);
} catch (error) {
console.log('Error: ', error);
return res.status(503).send({
success: false,
error: error.stack,
});
}
};
let page = 1;
// Get Shopify Products
async function getGorgiasTickets(nextPageToken, account, limit, maxPage, access_token, pinecone_index, pinecone_api_key, pinecone_namespace) {
console.log('Getting Next Tokens');
if (page <= maxPage) {
const gorgiasRequestOptions = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${access_token}`,
},
};
console.log('access_token: ', access_token);
const response = await fetch(`https://${account}.gorgias.com/api/tickets?limit=5&cursor=${nextPageToken}`, gorgiasRequestOptions);
const tickets_data = await response.json();
const tickets = tickets_data.data;
var next_token = tickets_data.meta.next_cursor;
const documents = [];
for (const item of tickets) {
try {
const id = item.id || null;
const assignee_user = item.assignee_user || null;
const channel = item.channel || null;
const closed_datetime = item.closed_datetime || null;
const created_datetime = item.created_datetime || null;
const external_id = item.external_id || null;
const language = item.language || null;
const last_message_datetime = item.last_message_datetime || null;
const last_received_message_datetime = item.last_received_message_datetime || null;
const opened_datetime = item.opened_datetime || null;
const snooze_datetime = item.snooze_datetime || null;
const status = item.status || null;
const update_datetime = item.update_datetime || null;
const via = item.via || null;
const uri = item.uri || null;
const customer_id = item.customer.id || null;
const email = item.customer.email || null;
const name = item.customer.name || null;
const firstname = item.customer.firstname || null;
const lastname = item.customer.lastname || null;
const gorgiasMessagesRequestOptions = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${access_token}`,
},
};
const messages_responses = await fetch(`https://${account}.gorgias.com/api/messages?ticket_id=${id}&limit=10`, gorgiasMessagesRequestOptions);
const messages_data = await messages_responses.json();
console.log('messages_data: ', messages_data);
const messages = messages_data.data;
if (messages.length > 0) {
for (const message of messages) {
let body_text = message.body_text || null;
const max_length = 1000;
// Check if the body text exceeds the maximum length
if (body_text && body_text.length > max_length) {
// Shorten the text and assign it back to body_text
body_text = body_text.substring(0, max_length);
// Log the shortened text
console.log("Shortened text:", body_text);
}
const message_id = message.id || null;
const channel = message.channel || null;
const created_datetime = message.created_datetime || null;
const from_agent = message.from_agent || null;
const receiver = message.receiver.name || null;
const sender = message.sender.name || null;
const subject = message.subject || null;
const ticket_id = message.ticket_id || null;
const via = message.via || null;
let metadata = {
id,
assignee_user,
channel,
closed_datetime,
created_datetime,
external_id,
language,
last_message_datetime,
last_received_message_datetime,
opened_datetime,
snooze_datetime,
status,
update_datetime,
via,
uri,
email,
customer_id,
name,
firstname,
lastname,
message_id,
body_text,
from_agent,
receiver,
sender,
subject,
ticket_id
};
const document = {
id: uuid(),
id,
metadata,
};
documents.push(document);
}
}
} catch (error) {
console.log(`Error processing item: ${JSON.stringify(item)}`);
console.log(error);
}
for (let i = 0; i < documents.length; i += DOCUMENT_UPSERT_BATCH_SIZE) {
// Split documents into batches
var batchDocuments = documents.slice(i, i + DOCUMENT_UPSERT_BATCH_SIZE);
console.log(batchDocuments);
// Convert batchDocuments to string
var batchDocumentString = JSON.stringify(batchDocuments)
// Remove commas from string
console.log(batchDocumentString);
// Create Embeddings
console.log('Looping through documents...');
const user_id = "domsteil";
// OpenAI Request Body
var raw = JSON.stringify({ "input": batchDocumentString, "model": "text-embedding-3-large", "user": user_id });
// OpenAI Request Options
var openaiRequestOptions = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': ''
},
body: raw,
redirect: 'follow'
};
// Make Callout to OpenAI to get Embeddings
console.log('Creating Embedding...');
// Make Callout to OpenAI
let embeddings_response = await fetch("https://api.openai.com/v1/embeddings", openaiRequestOptions)
// Create Pinecone Request Body
const vectors_embeddings = await embeddings_response.json();
console.log(vectors_embeddings);
// Create Pinecone Request Body
var vectors_object = { id: uuid(), values: vectors_embeddings.data[0].embedding, metadata: { "text": batchDocumentString, "user": user_id } };
console.log(vectors_object);
var raw = JSON.stringify({ "vectors": vectors_object, "namespace": pinecone_namespace });
var pineconeRequestOptions = {
method: "POST",
headers: {
"Content-Type": "application/json",
"Host": pinecone_index,
"Content-Length": 60,
"Api-Key": pinecone_api_key,
},
body: raw,
redirect: "follow",
};
// Make Callout to Pinecone
// Pinecone Upsert
console.log('Upserting Pinecone...');
let pinecone_query_response = await fetch(`/vectors/upsert`, pineconeRequestOptions)
.then(response => response.text())
.then(json => {
console.log(json);
})
.catch(error => {
console.error(error);
});
}
}
page += 1;
console.log(`On page ${page}, processing next page...`);
return getGorgiasTickets(next_token, account, limit, maxPage, access_token, pinecone_index, pinecone_api_key, pinecone_namespace);
} else {
return
}
};
Conclusion
In this guide, we walked through the steps to get your Gorgias ticket data into Pinecone and create embeddings for each ticket. You can now use these embeddings to find similar tickets or to create a recommendation system. If you have any questions or need help, please feel free to reach out to us at support@stateset.com