A quick article on my adaptation of some code posted by Poorvik Palanikumar on the Zoho Community Forums to connect a ZohoCliq to the OpenAI API and ChatGPT... Note that I have another article for those who want to integrate ChatGPT with ZohoZIA.
Why?
Previously, I would edit the message handlers of a Cliq Bot I created but it would only understand the questions I have programmed it to and respond with the responses I programmed it to answer with. Any variations of the questions it did not understand, it would return a response similar to Siri or Ask Google where it includes the keywords in a "Search the web..." task.
ChatGPT by OpenAI is viral at the time of print
How?
The basics of setting this up would be to setup a bot in ZohoCliq and then to edit either a message handler or participation handler. As for the usage, simply ask the Cliq Bot a question and it will forward the query and respond with the response from the OpenAI API.
Setup a Zoho Cliq bot
- Login to ZohoCliq
- Click on your profile picture
- Select "Bots & Tools"
- Click on "Create Bot" (or "Edit Handlers" on an existing bot)
- Fill in the details then edit the Handlers.
- For demo purposes, edit the code for the "Message Handler"
Get an OpenAI API Key
- Login to OpenAI
- Browse to https://platform.openai.com/account/api-keys
- Click on "Create a new key"
- Copy & paste into a text editor for use in the code below
Edit the Message Handler code
ChatGTP 3.5 Turbo
// // initialize m_Response = Map(); l_Messages = List(); v_Message = message.trim(); // // if the message contains a question mark, send it to OpenAI if(v_Message.contains("?")) { v_Question = v_Message; // // Need to add your own OpenAI token here v_Token = "sk-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; // // build header of request m_Header = Map(); m_Header.put("Authorization","Bearer " + v_Token); m_Header.put("Content-Type","application/json"); // // build params of request m_Params = Map(); m_Params.put("model", "gpt-3.5-turbo"); m_Message = Map(); m_Message.put("role", "user"); m_Message.put("content", v_Question); l_Messages.add(m_Message); m_Params.put("messages", l_Messages); // // https://platform.openai.com/docs/api-reference/chat/create m_Params.put("temperature", 0.8); m_Params.put("n", 1); m_Params.put("max_tokens", 256); m_Params.put("presence_penalty", 0); m_Params.put("frequency_penalty", 0); // // send request to chatgpt openai r_ChatGPTResponse = invokeurl [ url :"https://api.openai.com/v1/chat/completions" type :POST parameters:m_Params.toString() headers:m_Header detailed:true ]; if(r_ChatGPTResponse.get("responseCode") == 200) { // // retrieve the answer in text l_Choices = r_ChatGPTResponse.get("responseText").get("choices"); for each m_Choice in l_Choices { if(!isnull(m_Choice.get("message"))) { if(m_Choice.get("message").get("role")=="assistant") { // // add the answer text to the response map m_Response.put("text",m_Choice.get("message").get("content")); break; } } } } else { // store in response text m_Response.put("text","I don't know. Consider doing a Google search."); } } // // output return m_Response;
- //
- // initialize
- m_Response = Map();
- l_Messages = List();
- v_Message = message.trim();
- //
- // if the message contains a question mark, send it to OpenAI
- if(v_Message.contains("?"))
- {
- v_Question = v_Message;
- //
- // Need to add your own OpenAI token here
- v_Token = "sk-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- //
- // build header of request
- m_Header = Map();
- m_Header.put("Authorization","Bearer " + v_Token);
- m_Header.put("Content-Type","application/json");
- //
- // build params of request
- m_Params = Map();
- m_Params.put("model", "gpt-3.5-turbo");
- m_Message = Map();
- m_Message.put("role", "user");
- m_Message.put("content", v_Question);
- l_Messages.add(m_Message);
- m_Params.put("messages", l_Messages);
- //
- // https://platform.openai.com/docs/api-reference/chat/create
- m_Params.put("temperature", 0.8);
- m_Params.put("n", 1);
- m_Params.put("max_tokens", 256);
- m_Params.put("presence_penalty", 0);
- m_Params.put("frequency_penalty", 0);
- //
- // send request to chatgpt openai
- r_ChatGPTResponse = invokeUrl
- [
- url :"https://api.openai.com/v1/chat/completions"
- type :POST
- parameters:m_Params.toString()
- headers:m_Header
- detailed:true
- ];
- if(r_ChatGPTResponse.get("responseCode") == 200)
- {
- //
- // retrieve the answer in text
- l_Choices = r_ChatGPTResponse.get("responseText").get("choices");
- for each m_Choice in l_Choices
- {
- if(!isnull(m_Choice.get("message")))
- {
- if(m_Choice.get("message").get("role")=="assistant")
- {
- //
- // add the answer text to the response map
- m_Response.put("text",m_Choice.get("message").get("content"));
- break;
- }
- }
- }
- }
- else
- {
- // store in response text
- m_Response.put("text","I don't know. Consider doing a Google search.");
- }
- }
- //
- // output
- return m_Response;
Text-Davinci-003: (preceded ChatGPT API)
// // initialize m_Response = Map(); v_Answer = ""; v_Message = message.trim(); // // if the message contains a question mark, send it to OpenAI if(v_Message.contains("?")) { v_Question = v_Message; // // Need to add your own OpenAI token v_Token = "sk-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; // // build header of request m_Header = Map(); m_Header.put("Authorization","Bearer " + v_Token); m_Header.put("Content-Type","application/json"); // // build params of request m_Params = Map(); m_Params.put("model", "text-davinci-003"); m_Params.put("prompt", v_Question); m_Params.put("temperature", 0.9); m_Params.put("max_tokens", 256); m_Params.put("top_p", 1); m_Params.put("frequency_penalty", 0); m_Params.put("presence_penalty", 0); m_Params.put("stop", {" Human:"," AI:"}); // // send request to chatgpt openai r_ChatGPTResponse = invokeurl [ url :"https://api.openai.com/v1/completions" type :POST parameters:m_Params.toString() headers:m_Header detailed:true ]; if(r_ChatGPTResponse.get("responseCode") == 200) { // retrieve the answer in text v_Answer = r_ChatGPTResponse.get("responseText").get("choices").getJSON("text"); } else if(r_ChatGPTResponse.get("responseCode") == 429) { // store in response text v_Answer = "I dont have any knowledge in this. Please ask me something else"; } } else if (v_Message.containsIgnoreCase("Hi") || v_Message.containsIgnoreCase("Hello") || v_Message.containsIgnoreCase("Hey")) { // store in response text v_Answer = "Hi " + user.get("first_name") + "!\nMy name is JoelBot and I am currently connected to the OpenAI API. I can try and answer any question you end with a question mark. Try me out!"; } // // add the answer text to the response map m_Response.put("text", v_Answer); // // output return m_Response;
- //
- // initialize
- m_Response = Map();
- v_Answer = "";
- v_Message = message.trim();
- //
- // if the message contains a question mark, send it to OpenAI
- if(v_Message.contains("?"))
- {
- v_Question = v_Message;
- //
- // Need to add your own OpenAI token
- v_Token = "sk-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- //
- // build header of request
- m_Header = Map();
- m_Header.put("Authorization","Bearer " + v_Token);
- m_Header.put("Content-Type","application/json");
- //
- // build params of request
- m_Params = Map();
- m_Params.put("model", "text-davinci-003");
- m_Params.put("prompt", v_Question);
- m_Params.put("temperature", 0.9);
- m_Params.put("max_tokens", 256);
- m_Params.put("top_p", 1);
- m_Params.put("frequency_penalty", 0);
- m_Params.put("presence_penalty", 0);
- m_Params.put("stop", {" Human:"," AI:"});
- //
- // send request to chatgpt openai
- r_ChatGPTResponse = invokeUrl
- [
- url :"https://api.openai.com/v1/completions"
- type :POST
- parameters:m_Params.toString()
- headers:m_Header
- detailed:true
- ];
- if(r_ChatGPTResponse.get("responseCode") == 200)
- {
- // retrieve the answer in text
- v_Answer = r_ChatGPTResponse.get("responseText").get("choices").getJSON("text");
- }
- else if(r_ChatGPTResponse.get("responseCode") == 429)
- {
- // store in response text
- v_Answer = "I dont have any knowledge in this. Please ask me something else";
- }
- }
- else if (v_Message.containsIgnoreCase("Hi") || v_Message.containsIgnoreCase("Hello") || v_Message.containsIgnoreCase("Hey"))
- {
- // store in response text
- v_Answer = "Hi " + user.get("first_name") + "!\nMy name is JoelBot and I am currently connected to the OpenAI API. I can try and answer any question you end with a question mark. Try me out!";
- }
- //
- // add the answer text to the response map
- m_Response.put("text", v_Answer);
- //
- // output
- return m_Response;
Even in test mode or simply starting a Cliq conversation will now yield something like the following:
Additional
- For every chat message, the OpenAI ChatGPT forgets what the context of the conversation was about: Well we can populate the list of messages so that there is a conversation trail for the OpenAI ChatGPT to build on:
copyraw
// // initialize m_Response = Map(); v_Message = message.trim(); l_Messages = List(); v_ChatID = ifnull(chat.getJSON("id"),0); // // get conversations from last 10 minutes v_MinutesAgo = 10; v_FromTime = zoho.currenttime.subMinutes(v_MinutesAgo).toLong(); v_TillTime = zoho.currenttime.toLong() / 1000; // // by default gets last 100 messages (doesn't return anything if no parameters specified) v_Endpoint = "https://cliq.zoho.eu/api/v2/chats/"+v_ChatID + "/messages?fromtime=" + v_FromTime + "&limit=50"; r_ChatDetails = invokeurl [ url: v_Endpoint type: GET connection: "ab_cliq" ]; // // let's build up the conversation thread if(!isnull(r_ChatDetails.get("data"))) { for each r_MessageData in r_ChatDetails.get("data") { v_Role = "user"; if(!isnull(r_MessageData.get("message_source"))) { v_UserType = r_MessageData.get("message_source").get("type"); v_Role = if(v_UserType=="bot", "assistant", "user"); } if(!isnull(r_MessageData.get("content"))) { v_Content = r_MessageData.get("content").get("text"); } // m_Message = Map(); m_Message.put("role",v_Role); m_Message.put("content",v_Content); l_Messages.add(m_Message); } }
- //
- // initialize
- m_Response = Map();
- v_Message = message.trim();
- l_Messages = List();
- v_ChatID = ifnull(chat.getJSON("id"),0);
- //
- // get conversations from last 10 minutes
- v_MinutesAgo = 10;
- v_FromTime = zoho.currenttime.subMinutes(v_MinutesAgo).toLong();
- v_TillTime = zoho.currenttime.toLong() / 1000;
- //
- // by default gets last 100 messages (doesn't return anything if no parameters specified)
- v_Endpoint = "https://cliq.zoho.eu/api/v2/chats/"+v_ChatID + "/messages?fromtime=" + v_FromTime + "&limit=50";
- r_ChatDetails = invokeUrl
- [
- url: v_Endpoint
- type: GET
- connection: "ab_cliq"
- ];
- //
- // let's build up the conversation thread
- if(!isnull(r_ChatDetails.get("data")))
- {
- for each r_MessageData in r_ChatDetails.get("data")
- {
- v_Role = "user";
- if(!isnull(r_MessageData.get("message_source")))
- {
- v_UserType = r_MessageData.get("message_source").get("type");
- v_Role = if(v_UserType=="bot", "assistant", "user");
- }
- if(!isnull(r_MessageData.get("content")))
- {
- v_Content = r_MessageData.get("content").get("text");
- }
- //
- m_Message = Map();
- m_Message.put("role",v_Role);
- m_Message.put("content",v_Content);
- l_Messages.add(m_Message);
- }
- }
The one to rule them all
So I've been asked here and on the forums as well for the full query that includes making ChatGPT keep the context of the conversation along with new cliqs:
// // initialize m_Response = Map(); v_Message = message.trim(); v_ChatID = ifnull(chat.getJSON("id"),0); // // get conversations from last 5 minutes v_MinutesAgo = 10; v_FromTime = zoho.currenttime.subMinutes(v_MinutesAgo).toLong(); v_TillTime = zoho.currenttime.toLong() / 1000; // // by default gets last 100 messages (doesn't return anything if no parameters specified) v_Endpoint = "https://cliq.zoho.eu/api/v2/chats/" + v_ChatID + "/messages?fromtime=" + v_FromTime + "&limit=50"; r_ChatDetails = invokeurl [ url :v_Endpoint type :GET connection:"ab_cliq" ]; // // let's build up the conversation thread l_Messages = List(); if(!isnull(r_ChatDetails.get("data"))) { for each r_MessageData in r_ChatDetails.get("data") { v_Role = "user"; if(!isnull(r_MessageData.get("message_source"))) { v_UserType = r_MessageData.get("message_source").get("type"); v_Role = if(v_UserType == "bot","assistant","user"); } if(!isnull(r_MessageData.get("content"))) { v_Content = r_MessageData.get("content").get("text"); } // m_Message = Map(); m_Message.put("role",v_Role); m_Message.put("content",v_Content); l_Messages.add(m_Message); } } // // if the message is not blank, send it to OpenAI if(!isBlank(v_Message)) { v_Question = v_Message; // // Need to add openAI token here v_Token = "sk-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; // // build header of request m_Header = Map(); m_Header.put("Authorization","Bearer " + v_Token); m_Header.put("Content-Type","application/json"); // // build params of request m_Params = Map(); m_Params.put("model","gpt-3.5-turbo"); // // add latest message to conversation thread m_Message = Map(); m_Message.put("role","user"); m_Message.put("content",v_Question); l_Messages.add(m_Message); m_Params.put("messages",l_Messages); // // https://platform.openai.com/docs/api-reference/chat/create m_Params.put("temperature",0.8); m_Params.put("n",1); m_Params.put("max_tokens",256); m_Params.put("presence_penalty",0); m_Params.put("frequency_penalty",0); // // send request to chatgpt openai r_ChatGPTResponse = invokeurl [ url :"https://api.openai.com/v1/chat/completions" type :POST parameters:m_Params.toString() headers:m_Header detailed:true ]; if(r_ChatGPTResponse.get("responseCode") == 200) { // // retrieve the answer in text l_Choices = r_ChatGPTResponse.get("responseText").get("choices"); for each m_Choice in l_Choices { if(!isnull(m_Choice.get("message"))) { if(m_Choice.get("message").get("role") == "assistant") { // // add the answer text to the response map m_Response.put("text",m_Choice.get("message").get("content")); //break; } } } } else if(r_ChatGPTResponse.get("responseCode") == 429) { // catch all v_Response = "I don't know. Would you like me to Google: [" + v_Message + "](https://www.google.com/search?q=" + zoho.encryption.urlEncode(v_Message) + ")?"; m_Response = {"text":v_Response }; } } return m_Response;
- //
- // initialize
- m_Response = Map();
- v_Message = message.trim();
- v_ChatID = ifnull(chat.getJSON("id"),0);
- //
- // get conversations from last 5 minutes
- v_MinutesAgo = 10;
- v_FromTime = zoho.currenttime.subMinutes(v_MinutesAgo).toLong();
- v_TillTime = zoho.currenttime.toLong() / 1000;
- //
- // by default gets last 100 messages (doesn't return anything if no parameters specified)
- v_Endpoint = "https://cliq.zoho.eu/api/v2/chats/" + v_ChatID + "/messages?fromtime=" + v_FromTime + "&limit=50";
- r_ChatDetails = invokeUrl
- [
- url :v_Endpoint
- type :GET
- connection:"ab_cliq"
- ];
- //
- // let's build up the conversation thread
- l_Messages = List();
- if(!isnull(r_ChatDetails.get("data")))
- {
- for each r_MessageData in r_ChatDetails.get("data")
- {
- v_Role = "user";
- if(!isnull(r_MessageData.get("message_source")))
- {
- v_UserType = r_MessageData.get("message_source").get("type");
- v_Role = if(v_UserType == "bot","assistant","user");
- }
- if(!isnull(r_MessageData.get("content")))
- {
- v_Content = r_MessageData.get("content").get("text");
- }
- //
- m_Message = Map();
- m_Message.put("role",v_Role);
- m_Message.put("content",v_Content);
- l_Messages.add(m_Message);
- }
- }
- //
- // if the message is not blank, send it to OpenAI
- if(!isBlank(v_Message))
- {
- v_Question = v_Message;
- //
- // Need to add openAI token here
- v_Token = "sk-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- //
- // build header of request
- m_Header = Map();
- m_Header.put("Authorization","Bearer " + v_Token);
- m_Header.put("Content-Type","application/json");
- //
- // build params of request
- m_Params = Map();
- m_Params.put("model","gpt-3.5-turbo");
- //
- // add latest message to conversation thread
- m_Message = Map();
- m_Message.put("role","user");
- m_Message.put("content",v_Question);
- l_Messages.add(m_Message);
- m_Params.put("messages",l_Messages);
- //
- // https://platform.openai.com/docs/api-reference/chat/create
- m_Params.put("temperature",0.8);
- m_Params.put("n",1);
- m_Params.put("max_tokens",256);
- m_Params.put("presence_penalty",0);
- m_Params.put("frequency_penalty",0);
- //
- // send request to chatgpt openai
- r_ChatGPTResponse = invokeUrl
- [
- url :"https://api.openai.com/v1/chat/completions"
- type :POST
- parameters:m_Params.toString()
- headers:m_Header
- detailed:true
- ];
- if(r_ChatGPTResponse.get("responseCode") == 200)
- {
- //
- // retrieve the answer in text
- l_Choices = r_ChatGPTResponse.get("responseText").get("choices");
- for each m_Choice in l_Choices
- {
- if(!isnull(m_Choice.get("message")))
- {
- if(m_Choice.get("message").get("role") == "assistant")
- {
- //
- // add the answer text to the response map
- m_Response.put("text",m_Choice.get("message").get("content"));
- //break;
- }
- }
- }
- }
- else if(r_ChatGPTResponse.get("responseCode") == 429)
- {
- // catch all
- v_Response = "I don't know. Would you like me to Google: [" + v_Message + "](https://www.google.com/search?q=" + zoho.encryption.urlEncode(v_Message) + ")?";
- m_Response = {"text":v_Response };
- }
- }
- return m_Response;
Error(s) Encountered:
- Exceeded Quote Limit: Try generating a new API key (aka Secret). If you need a paid plan, then you can access this by logging into OpenAI and browsing to https://platform.openai.com/account/billing/overview. At time of print, the paid plan is a pay as you go or pay as you use.
Previous Models/Versions
Based on the documentation: In the above code, you would change the model value to one of the following
code-davinci-002 (optimized for code-completion tasks) text-davinci-002 text-davinci-003 gpt-3.5-turbo (optimized for chat at 1/10th the cost of text-davinci-003) gpt-4 gpt-4-32k (up to 4x the context length)
- code-davinci-002 (optimized for code-completion tasks)
- text-davinci-002
- text-davinci-003
- gpt-3.5-turbo (optimized for chat at 1/10th the cost of text-davinci-003)
- gpt-4
- gpt-4-32k (up to 4x the context length)
Source(s):
- OpenAI - Documentation - API Reference - Making Requests
- OpenAI Account - API keys
- OpenAI Documentation - Create chat completion
- Zoho Community > Zoho Cliq > Configure ChatGPT in Zoho Cliq (Poorvik Palanikumar)
- Zoho Cliq - Message Object