Skip to content

Instantly share code, notes, and snippets.

@rleroi
Last active December 7, 2022 13:51
Show Gist options
  • Save rleroi/3b5667983bf0c16172f4ecd5a52a1fda to your computer and use it in GitHub Desktop.
Save rleroi/3b5667983bf0c16172f4ecd5a52a1fda to your computer and use it in GitHub Desktop.
Generate short description for Trengo with GPT3, runs on Cloudflare Workers
addEventListener("fetch", (event) => {
event.respondWith(
handleRequest(event.request).catch(
(err) => new Response(err.stack, { status: 500 })
)
);
});
const paused = false;
const environments = {
'production': {
trengoApi: 'https://app.trengo.com/api/v2/ticket_summary/',
trengoKey: 'xxx',
},
'local': {
trengoApi: 'https://ramses-trengo.eu.ngrok.io/api/v2/ticket_summary/',
trengoKey: 'xxx',
},
'staging': {
trengoApi: 'https://app-stg.trengo.eu/api/v2/ticket_summary/',
trengoKey: 'xxx',
}
};
const engine = 'text-davinci-002';
const api = `https://api.openai.com/v1/engines/${engine}/completions`;
const key = 'xxx';
const maxTokens = 1000;
const temperature = 0;
const promptPrefix = `Input:
Dear Henk,
I am cancelling my flight due to private reasons.
Kind regards,
Piet
Topic:
Flight cancelation
Input:
Hallo, ik ben mijn wachtwoord vergeten. Hoe krijg ik hem terug?
Topic:
Vergeten wachtwoord
Input:
Hello Trengo support team,
My question is about the flowbot. It generates wrong answers.
Topic:
Wrong flowbot answers
Input:`;
const promptPrefixLong = `Input:
Dear Henk,
I am cancelling my flight due to private reasons.
Kind regards,
Piet
One-sentence summary:
Flight will be canceled due to private reasons.
Input:
Hallo, ik ben mijn wachtwoord vergeten. Hoe krijg ik hem terug?
One-sentence summary:
Vraag over het terughalen van een vergeten wachtwoord.
Input:
Hello Trengo support team,
My question is about the flowbot. It generates wrong answers.
One-sentence summary:
Question regarding the flowbot that generates wrong answers.
Input:`;
/*
message_id Message ID
ticket_id Ticket ID
contact_id Contact ID
message Message content
contact_name Contact name
contact_email Contact email
*/
/**
* Many more examples available at:
* https://developers.cloudflare.com/workers/examples
* @param {Request} request
* @returns {Promise<Response>}
*/
async function handleRequest(request) {
const { pathname } = new URL(request.url);
// #### hook ####
if (pathname.startsWith("/hook")) {
if (paused) {
return new Response(JSON.stringify({'status': 'paused'}));
}
const environment = pathname.split("/")[2];
if (!environments[environment]) {
return new Response(JSON.stringify({'status': 'environment not found'}), { status: 404 });
}
const data = formDataToJson(await request.formData());
if (await SUMMARY_TICKETS.get(parseInt(data.ticket_id))) {
return new Response('Already processed');
}
let summaryShort = await getSummaryShort(data.message);
let summaryLong = await getSummaryLong(data.message);
await SUMMARY_TICKETS.put(parseInt(data.ticket_id), summaryShort + summaryLong);
const {trengoKey, trengoApi} = environments[environment];
await requestTrengo(trengoApi + data.ticket_id, trengoKey, {
'summary_short': summaryShort,
'summary_long': summaryLong,
});
console.log(environment, data.ticket_id, summaryShort);
return new Response(JSON.stringify({environment, ticketId: data.ticket_id, summaryShort}));
// #### demo ####
} else if (pathname.startsWith("/demo")) {
return await demo(request);
}
return new Response(JSON.stringify({'status': 'route not found'}), { status: 404 });
}
function formDataToJson(input) {
let output = {};
for (let [key, value] of input) {
let tmp = output[key];
if (tmp === undefined) {
output[key] = value;
} else {
output[key] = [].concat(tmp, value);
}
}
return output;
}
async function requestTrengo(endpoint, trengoKey, body = null) {
return await fetch(endpoint, {
method: 'POST',
body: JSON.stringify(body),
headers: {
'Authorization': `Bearer ${trengoKey}`,
'Content-Type': 'application/json',
},
});
}
async function getSummaryShort(text) {
text = text.replace(/(\r?\n)+/, /\n/).replace(/[^\p{L}\p{N}\s -~]/igu, '').replace(/(<([^>]+)>)/gi, "").substring(0,750);
const prompt = `${promptPrefix}
${text}
Topic:
`;
const response = await fetch(api, {
method: 'POST',
body: JSON.stringify({
prompt,
'temperature': temperature,
'max_tokens': maxTokens
}),
headers: {
'Authorization': `Bearer ${key}`,
'Content-Type': 'application/json',
},
});
const responseJson = await response.json();
return responseJson.choices[0]?.text;
}
async function getSummaryLong(text) {
text = text.replace(/(\r?\n)+/, /\n/).replace(/[^\p{L}\p{N}\s -~]/igu, '').replace(/(<([^>]+)>)/gi, "").substring(0,750);
const prompt = `${promptPrefixLong}
${text}
One-sentence summary:
`;
const response = await fetch(api, {
method: 'POST',
body: JSON.stringify({
prompt,
'temperature': temperature,
'max_tokens': maxTokens
}),
headers: {
'Authorization': `Bearer ${key}`,
'Content-Type': 'application/json',
},
});
const responseJson = await response.json();
return responseJson.choices[0]?.text;
}
async function demo(request) {
const { pathname } = new URL(request.url);
let text = pathname.split("/")[2];
text = text.replace(/(\r?\n)+/, /\n/);
const prompt = `${promptPrefix}
${text}
Topic:
`;
const response = await fetch(api, {
method: 'POST',
body: JSON.stringify({
prompt,
'temperature': temperature,
'max_tokens': maxTokens
}),
headers: {
'Authorization': `Bearer ${key}`,
'Content-Type': 'application/json',
},
});
const responseJson = await response.json();
const summaryShort = responseJson.choices[0]?.text;
return new Response(JSON.stringify({
'summary_short': summaryShort,
}));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment