Getting started with Gorgias Ticket Embeddings
Loop Through Tickets
Create Embeddings
Store Chunks of 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
}
};