This how-to focuses on an innovative method to optimize user interaction within your chat applications, employing OpenAI's sophisticated language model, ChatGPT, to summarize chat messages.
In today's rapidly evolving digital landscape, one key priority for application developers is enhancing user engagement. A step change in achieving this within chat applications is the summarization of missed messages. As users frequently find themselves time-constrained, providing a quick overview of missed conversations can significantly improve the user experience.
To bridge this gap effectively, we will integrate ChatGPT with PubNub's real-time chat capabilities using PubNub Functions. This integration aims to summarise any missed chat messages that have accumulated since the user last interacted with your chat application.
We’ll review step-by-step on seamlessly incorporating AI-powered message summarization features into your chat applications without disrupting existing functionalities. By employing such advanced features, your application can provide more efficient and involved personal interactions, thus substantially boosting user engagement.
Building a Chat Application with AI Features
Before you can start building AI features you need a chat app to combine them with. We've put together a basic chat app that you can use a template for following this how-to. This chat app is based on our 'Chat in 10 Lines of Code' demo.
Create a new directory (call it whatever you'd like) and create two empty files: 'index.html' and 'style.css'.
In 'style.css' add the following code:
.flex-container {
display: flex;
}
.flex-child {
flex: 1;
}
.code-block {
display: none;
font-size: small;
}
.flex-child:first-child {
flex: 2;
margin-right: 10px;
margin-top:9px;
background-color: rgb(249, 249, 249);
flex-direction:column;
max-height: 510px;
height:510px;
overflow:auto;
}
@media (min-width: 768px) {
.code-block {
display: block;
}
}
html * {
font-family: 'Poppins';
}
input {
width: 100%;
padding: 6px 15px 6px 15px;
box-sizing: border-box;
border-radius: 12px;
font-size: medium;
}
h1 {
margin: 0;
}
.messageYou {
width: 90%;
padding: 6px 20px;
margin: 8px;
background-color: #c2d3e9;
border-style: solid;
border-color: black;
border-width: 2px;
box-sizing: border-box;
border-top-left-radius: 20px;
border-bottom-right-radius: 20px;
border-bottom-left-radius: 20px;
float: right;
}
.messageThem {
width: 90%;
padding: 6px 20px;
margin: 8px;
background-color: #f3f3f3;
border-style: solid;
border-color: black;
border-width: 2px;
box-sizing: border-box;
border-bottom-left-radius: 20px;
border-top-right-radius: 20px;
border-bottom-right-radius: 20px;
float: left;
}
.youText {
float: right;
}
.messageTime {
font-size: x-small;
float: right;
}
In 'index.html' add the following code
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="./style.css" />
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet" />
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="icon" type="image/png" href="icon.png">
<title>JavaScript Chat Demo | PubNub</title>
<!-- Code syntax highlighting -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/styles/default.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js"></script>
</head>
<body>
<H1>Summarize Chat Messages With AI. Powered by PubNub</H1>
<div class="flex-container">
<div id="outputDiv" class="flex-child">
</div>
</div>
<input id="input" placeholder="Type your message and press enter" />
<!-- Create a chat app with the PubNub SDK (count ;)-->
<script src="https://cdn.pubnub.com/sdk/javascript/pubnub.7.2.0.min.js"></script>
<script>
var id = 'user_' + Math.random();
(function () {
var pubnub = new PubNub({publishKey: 'YOUR_PUB_KEY_HERE', subscribeKey: 'YOUR_SUB_KEY_HERE', userId: id}); // Your PubNub keys here. Get them from https://dashboard.pubnub.com.
var box = document.getElementById("outputDiv"), input = document.getElementById("input"), channel = '10chat';
pubnub.subscribe({channels: [channel]}); // Subscribe to a channel.
pubnub.addListener({
message: function (m) {
box.innerHTML += newRow(m.message, m.publisher);
box.scrollTop = box.scrollHeight;
}
});
input.addEventListener('keypress', function (e) {
(e.keyCode || e.charCode) === 13 && input.value != "" && pubnub.publish({ // Publish new message when enter is pressed.
channel: channel, message: input.value, x: (input.value = '')
});
});
})();
// End of chat built with PubNub SDK.
hljs.highlightAll();
function newRow(m, publisher) {
var date = "<br><span class='messageTime'>" + new Date().toLocaleString() + "</span>";
var you = "";
var messageClass = "messageThem";
var message = ('' + m).replace(/[<>]/g, '');
if (id === publisher) {
you = "<span class='youText'> (You)</span>";
messageClass = "messageYou"
}
return "<div class='" + messageClass + "'>" + message + you + date + "</div>"
}
</script>
</body>
</html>
These two files will serve as our core chat application that we will build on. Before you open 'index.html' in your browser, you'll need to configure your PubNub API keys.
Login to your PubNub Admin Dashboard. Go to "Apps" in the left side menu. Then click "Create New App" in the top right. Fill out the required details. Click on the new app keyset you created.
Replace 'YOUR_PUB_KEY_HERE' and 'YOUR_SUB_KEY_HERE' with your PubNub API Keys.
Scroll down to the 'Configuration' section. Enable 'Message Persistence' and then save the changes. You'll need Message Persistence to empower ChatGPT to summarize missed messages.
Open 'index.html' in your browser to try out your basic chat app. Next, lets add our AI text summarization feature.
Knowing when the chat app is inactive
Before we can pass the messages to ChatGPT to summarize you'll need to get the count of messages received since the page was last active. This is easy to do by listening for 'visibilitychange' events on the document.
First, you'll need to create two more variables at the beginning of the script for the chat application. This will be used to know the current page state and keep a count of unread messages.
Change the first line in the script to look like this:
var active = true, unreadCount = 0, id = 'user_' + Math.random();
Next, increment the unreadCount as messages are received if the page is not active. The newRow() function formats your chat messages and is a good place to increment the counter as messages are displayed. Modify the newRow() function to look like this:
function newRow(m, publisher) {
var date = "<br><span class='messageTime'>" + new Date().toLocaleString() + "</span>";
var you = "";
var messageClass = "messageThem";
var message = ('' + m).replace(/[<>]/g, '');
if (id === publisher) {
you = "<span class='youText'> (You)</span>";
messageClass = "messageYou"
} else { // If inactive and receiving messages keep up with the count of missed messages.
if (!active) {
unreadCount++;
}
}
return "<div class='" + messageClass + "'>" + message + you + date + "</div>"
}
Last, you'll need to listen for 'visibilitychange' events to reset the count and request summarization from a PubNub Function when the user returns. Add this at the end of the script:
// Use this code to determine when the page is active and inactive.
document.addEventListener('visibilitychange', function (event) {
if (document.hidden) {
active = false;
unreadCount = 0; // Reset to count missed message while the page is not visible.
} else {
active = true;
if (unreadCount > 0) {
alert("You missed "+unreadCount+" messages while you were away.");
//Ask ChatGPT to summarize missed messages.
}
}
Summarize Chat Messages with ChatGPT and PubNub Functions
Now we are ready to summarize chat messages with ChatGPT.
Return to your PubNub Admin Dashboard. Go to "Apps" in the left side menu. Click on your app and then your app's API keys. Now to to "Functions" in the left side menu.
Click "Create New Module". Enter the name as "Chat Summarizer" and a module description. Click "Create".
Click "Create New Function". Enter the name as "Summarize" and set the type to "On Request". Set the URL path to be "summarize-chat-gpt".
Click "My Secrets" in the left side menu. Create a secret with the name "OPENAI_API_KEY" and the value should be your OpenAI API Key.
Add the following function code to the editor:
//
// Import Modules
//
const pubnub = require('pubnub');
const xhr = require('xhr');
const vault = require('vault');
//
// Request Event Handler (Main)
//
export default (request, response) => {
// Natural language request input for AI model
let missedMessagesCount = request.body;
let messagesChannel = "10chat";
//
// Get API Key for OpenAI
// Key is populated via Vault Secret Manager
//
let OPENAI_API_KEY = null;
function getOpenaiApiKey() {
// Use cached key
if (OPENAI_API_KEY) {
return new Promise(resolve => resolve(OPENAI_API_KEY));
}
// Fetch key from vault
return vault.get("OPENAI_API_KEY").then(apikey => {
OPENAI_API_KEY = apikey;
return new Promise(resolve => resolve(OPENAI_API_KEY));
});
}
//
// Get the Last Message from a Channel
//
function getMessageHistory(channel) {
return pubnub.history({
channel: channel, // Change the channel to where you want to publish missed messages summary.
count: parseInt(missedMessagesCount),
});
}
getMessageHistory.instructions = {
"name": "getMessageHistory",
"description": "Get messages that were sent to a channel. ",
"parameters": {
"type": "object",
"properties": {
"channel": {
"type": "string",
"description": "The channel name to get missed messages from.",
},
},
"required": ["channel"],
}
};
//
// API Call to OpenAI asking the AI to run functions if it thinks it needs to
//
function openAI(naturalCommand, messages) {
// Generate Function Instructions for the AI
const functions = [getMessageHistory].map(fn => fn.instructions);
const url = 'https://api.openai.com/v1/chat/completions';
let msgs = messages || [{"role": "user", "content": naturalCommand}];
const http_options = {
'method': 'POST',
'headers': {
"Content-Type": "application/json",
"Authorization": `Bearer ${OPENAI_API_KEY}`,
},
'body': JSON.stringify({
"model": "gpt-3.5-turbo-0613",
"messages": msgs,
"functions": functions,
"function_call": "auto",
}),
};
return xhr.fetch(url, http_options)
.then((resp) => {
const body = JSON.parse(resp.body);
const function_call = body.choices[0].finish_reason === "function_call";
const message = body.choices[0].message;
// Call function and resend to OpenAI the result
if (function_call) {
return handelFunctionCalls(message).then(result => {
msgs.push(message);
msgs.push({
"role": "function",
"name": message.function_call.name,
"content": JSON.stringify(result),
});
return openAI(naturalCommand, msgs);
});
}
// Send status update about completed task
const content = message.content;
return new Promise(resolve => resolve(content));
})
.catch((err) => {
return new Promise((_, reject) => reject(err));
});
}
//
// Handel Function Calls from OpenAI Requests
//
function handelFunctionCalls(message) {
let args = JSON.parse(message.function_call.arguments);
switch (message.function_call.name) {
case "getMessageHistory":
return getMessageHistory(args.channel);
break;
}
}
// Ask AI to make decisions and provide progress updates
return getOpenaiApiKey().then(apikey => {
return openAI("Provide subject and context about missed messages in a group chat channel named '"+messagesChannel+"'. Do not repeat the channel name "+messagesChannel+" in your response. Call the channel 'channel'. Start each message with 'Here is what you missed while you were away: ' Respond with the result only. Do not list messages you retrieve in the result from the getMissedMessages function. Do not repeat messages you retrieve in the result from the getMissedMessages function. Only provide the context or subject about the missed messages you retrieve from the getMissedMessages function. Do not exceed 3 sentences.").then(aiResponse => {
console.log("OPENAI TASK RESULT:", aiResponse);
//return response.send(aiResponse);
return pubnub.publish({
channel: messagesChannel,
message: aiResponse,
});
});
});
};
Click "Save" and then "Start Module".
You'll make a post request to this PubNub function to ask ChatGPT to use Message Persistence to summarize the missed messages.
Copy the URI path by clicking "Copy URI".
Go back to your index.html file and replace "//Ask ChatGPT to summarize missed messages." with this code:
if (unreadCount > 1) { // Summarize if there has been more than one message received while the user was away.
var xhr = new XMLHttpRequest();
xhr.open("POST", 'YOUR_FUNCTIONS_URI', true); // Summarize missed messages using PubNub Functions and ChatGPT
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
xhr.send(unreadCount);
alert("You missed "+unreadCount+" messages while you were away.");
}
Replace 'YOUR_FUNCTIONS_URI' with the URI path you copied from your PubNub Function.
Open index.html in at least two browser windows. In one window send a few chat messages. Switch back to the other browser window and you should get an alert of the number of missed messages followed by a new summary message published by the PubNub Function you created. Try altering the ChatGPT prompt at the bottom of the Function code to adjust results to best fit your application.
Need more help with building with AI services and PubNub? Get in touch with our team and let's discuss all the possibilities.