Grand offers GPT models through WebSockets for realtime response.
Here are a few concepts you should know for using Grand via WebSockets:
/socket/create
endpoint.JSON
format.Here's how you can connect to Grand via WebSocket. Use our /socket/create
endpoint to get a WebSocket connection url
. Afterwards, you can simply connect like this:
const connection = new WebSocket(url)
// listen to the response from Grand
connection.onmessage = (msg) => {
try {
let message = JSON.parse(msg.data)
console.log('from Grand:', message)
} catch (error) { // probably due to some network issues
console.log('JSON parsing error:', error)
}
}
Send stringified JSON data as a request. Following is the expected schema:
{
"action": "<from actions list>",
"request": "<request body>"
}
At the moment, Grand supports following actions through WebSockets:
action: 'generate'
action: 'playbook-use'
Making a request through a socket connection is as simple as sending JSON data through connection.send
method. Here's an example of generating text:
connection.send(JSON.stringify({
action: "generate",
request: {
stop: ".", // required
creativity: 40, // required
text: "Grand API is fast, easy and" // required
}
}))
👋🏼 request
expects the same parameters as listed on the Server APIs page. For example, when using generate
action, you can pass the parameters as listed here.
Grand will keep streaming the next words/tokens until the stop
is found or max
limit is reached. As mentioned above, the response will also be in the JSON format. From our onmessage
listener above, we'll get something like this in the parsed
variable:
{
ok: true, // if the response is valid and not an error
done: false, // if the response is finished
id: "19eeff4e", // request id
data: {
text: " secure" // next word/token
}
}
A new message is sent for each word/token. A standard practice is to keep using the data.text
property unless you find done
to be true
, or ok
to be false
.
Folowing errors are expected from a WebSocket connection. When ok
is false
, following error strings are expected in reason
property. Errors not listed below will be related to the related action. The reason
property should be self-explanatory in that case.
Error | Explanation |
---|---|
connection_unknown | The URL you're trying to connect with is invalid. Get a new one from /socket/create endpoint. |
connection_expired | The connection has expired, start a new one by creating a new URL. |
connection_closing | This error is sent right before Grand closes a connection. When you receive this error, reconnect with a fresh connection URL. |
error_unknown | An error occurred at Grand's end. Trying again should fix. If you keep getting this error, please reach out to us. |
GPT-J is one of the best models for generating text, among other things. We already have a GPT-J API for conventional request/response usage, this guide will cover using GPT-J model for text generation over WebSockets. If you don't already know, here's a quick refresher on using WebSocket.
WebSockets provide asynchronous form of communication, which means we send and receive data differently than the regular, synchronous, HTTP requests.
Common HTTP request example:
fetch(url, request).then(response => {
// do something with the response
})
WebSocket request example:
const connection = new WebSocket(url)
// first add a listener
connection.onmessage = (response) => {
// do something with the response
}
// then
connection.send(request)
To get started, first thing we're going to need is a URL for WebSocket connection. We'll send a POST
request to the /socket/create endpoint to get that.
You can use a tool like Insomnia or Postman but we'll just cURL
it for the guide.
/socket/create
needs credential headers so it must always be called from a secure environment, e.g: A back-end servercurl -XPOST -H 'x-auth-key: YOUR KEY' -H 'x-auth-secret: YOUR SECRET' -H "Content-type: application/json" -d '{}' 'http://api.grand.app/socket/create'
The response will look something like this:{
"ok": true,
"ttl": 3600,
"id": "vf93jf001",
"url": "wss://api.grand.app/connect/6W3TjJFKID8290mnTLo/vf93jf001"
}
What we care about is the url
property in that response. Once we have it, we can use it to connect to Grand WebSocket server:
// use the URL from /socket/create response.
const connection = new WebSocket(response.url)
// Important:
// We need to start listening as soon as possible
// connection errors will also be received here
connection.onmessage = (msg) => {
try {
let message = JSON.parse(msg.data)
console.log('from Grand:', message)
} catch (error) { // probably due to some network issues
console.log('JSON parsing error:', error)
}
}
In the above code can be used on the client-side to connect.
As you can see, we've added a onmessage
listener to receive messages from Grand. We're using try/catch
because of the JSON parsing; Grand will always return JSON data but sometimes, due to a network issue or something, it may not be and JSON.parse
will throw an error.
We'll also add a couple of other listeners to keep track of the connection state:
// keep track of the connection
let isConnected = false
connection.onopen = () => {
isConnected = true
console.log('connection opened')
}
connection.onerror = (error) => {
isConnected = false
console.log('connection closed due to an error', error)
}
connection.onclose = () => {
isConnected = false
console.log('connection closed')
}
With the listeners in place, we're ready to start sending some requests. We'll send a generate
request for open-ended text generation.
const requestBody = {
action: "generate", // it could also be 'playbook-use'
request: {
stop: ".", // when to stop the generation
creativity: 40, // how creative should the response be
text: "Grand API is fast, easy and" // initial text
}
}
if (isConnected) {
connection.send(JSON.stringify(requestBody)) // stringify is important here
} else {
console.log('No connection found')
}
When ready, Grand will start sending data back and we'll get that in onmessage
listener. We can change the listener a little bit to read the text that Grand is generating for us:
function handleMessage (message) {
// check if the message is an error or a valid response
if (!message.ok) {
console.log('Error from Grand:', message.reason)
if (['connection_expired', 'connection_closing'].includes(message.reason)) {
// get a new connection URL
console.log('connection expired')
}
return
}
// the text being sent by Grand in realtime
console.log(message.data.text)
// if done = true, there'll be no more messages for this request
if (message.done) {
console.log('Response finished!')
}
}
connection.onmessage = (msg) => {
try {
let message = JSON.parse(msg.data)
handleMessage(message)
} catch (error) { // probably due to some network issues
console.log('JSON parsing error:', error)
}
}
The comments in the code above are self-explanatory but just to summarize:
.ok
property; if false
, check .reason
property too. If it's connection_expired
or connection_closing
, get the connection URL again..data.text
if everything is fine.done
property is true
. If so, response is finished for that perticular request.We hope this guide will help you implement Grand into your application. If you face any issues or have some question, please feel free to reach out to us through chat.