In this tutorial, we’ll explore how to create an interactive chatbot on Arduino IDE’s serial monitor using an ESP32 board and OpenAI’s GPT 3.5 API via HTTP request. By combining the versatility of ESP32 with the advanced AI capabilities of OpenAI, you can create a chatbot that can respond to user queries and engage in meaningful conversations. Before we begin, make sure you have the following:
- ESP32 based development board
- Computer with Arduino IDE installed and required latest libraries installed
- OpenAI API key (Sign up at OpenAI and obtain your API key)
- Access to a Wi-Fi network (home router or mobile hotspot)
In our IBM Watson IoT tutorials, we have shared a bunch of Arduino sketches for ESP32 which utilizes HTTP request
(instead of MQTT) – github.com/AbhishekGhosh/WROOM-ESP32-IBM-Watson-IoT-Example. This project is quite similar to projects such as send request on button press. You have to install the essential libraries: WiFi WiFiClientSecure, and ArduinoJson.
Understanding the OpenAPI Chat Completion Creation API Request
The OpenAI API provides a straightforward way to interact with its natural language processing capabilities using HTTP requests. The Chat Completion Creation API allows you to generate responses to given prompts. Before making the request, ensure you have curl installed on your system (that is usually installed on Linux). You’ll also need your OpenAI API key, which you can obtain by signing up for an account on the OpenAI platform.
---
The Chat Completion Creation API endpoint is https://api.openai.com/v1/chat/completions. Earlier, it was https://api.openai.com/v1/completions. Please note that difference.
When making a request, you need to provide your API key in the headers and the prompt for which you want a completion in the JSON payload. Here’s how you can structure the curl command:
1 2 3 4 5 6 7 8 9 10 11 12 | curl https://api.openai.com/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_OPENAI_API_KEY" \ -d '{ "model": "gpt-3.5-turbo", "messages": [ { "role": "user", "content": "YOUR_PROMPT_HERE" } ] }' |
Replace YOUR_OPENAI_API_KEY with your actual OpenAI API key, and replace YOUR_PROMPT_HERE with the prompt for which you want a completion. You can also specify additional parameters in the payload, such as the max_tokens to control the length of the generated completion.
Notice the parameter "role": "user".
user is the individual initiating the conversation and interacting with the AI model. Users ask questions, provide prompts, or engage in dialogue with the system to seek information, assistance, or entertainment.
Other roles are assistant and system.
The assistant role is fulfilled by the AI model itself, such as GPT-3 in this case. The Assistant interprets the User’s input, generates responses, and provides relevant information or assistance based on the context of the conversation. It aims to understand and fulfil the User’s requests to the best of its abilities.
The system role encompasses any additional components or functionalities that support the conversation but are not directly involved in generating responses. This could include interfaces, databases, or other software components that facilitate the interaction between the User and the Assistant. The System role ensures smooth communication between the User and the Assistant and may handle tasks such as input/output processing, context management, or result presentation.
The above cURL command gives me this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | { "id": "chatcmpl-9IJ0L9gu9Qb51dVk9qGbNabAvwmQ6", "object": "chat.completion", "created": 1714149985, "model": "gpt-3.5-turbo-0125", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "OpenAI is an artificial intelligence research lab and company focused on advancing digital intelligence in a way that benefits all of humanity. It was founded in December 2015 by Elon Musk, Sam Altman, Greg Brockman, Ilya Sutskever, John Schulman, and Wojciech Zaremba. \n\nThe main goal of OpenAI is to ensure that artificial general intelligence (AGI) will be developed in a way that is safe, friendly, and aligned with human values. They conduct research in a wide range of areas, including natural language processing, computer vision, reinforcement learning, robotics, and more.\n\nOpenAI has developed several high-profile AI models, including GPT-3, a powerful language model capable of generating human-like text, and DALL-E, a model capable of generating images from textual prompts. They also release their research and tools as open-source to encourage collaboration and advancement in the field of AI.\n\nIn addition to their research efforts, OpenAI also works on policy and advocacy to promote the responsible development and deployment of AI technology. They have published several papers and guidelines on ethical AI, transparency, and algorithmic fairness.\n\nOverall, OpenAI is at the forefront of AI research and development, striving to create advanced AI systems that benefit society as a whole." }, "logprobs": null, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 12, "completion_tokens": 260, "total_tokens": 272 }, "system_fingerprint": "fp_3b956da36b" } |
So it’s working. Unless you get the typical peculiar content, your request has something wrong.
I have tested various Arduino libraries to connect with OpenAI, and all of them used text-davinci-003 as the model and eventually, they were returning 404 error. That returned me this:
1 2 3 4 5 6 7 8 | { "error": { "message": "The model `text-davinci-003` has been deprecated, learn more here: https://platform.openai.com/docs/deprecations", "type": "invalid_request_error", "param": null, "code": "model_not_found" } } |
Execute the curl command in the terminal we have shown above to test the logic.
Final Sketch to Build Interactive Chatbot with ESP32 Arduino and OpenAI
I studied & tried a lot of sketches for this purpose. Except MarcoCiau’s esp32_gpt_chatbot project nothing worked for me. I have slightly modified his sketch (translated to English & added an LED indicator).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | #include <WiFi.h> #include <WiFiClientSecure.h> #include <ArduinoJson.h> // edit these three lines const char* ssid = "YOUR-SSID-HERE"; const char* password = "YOUR-HOTSPOT-PASSWORD"; const char* api_key = "OPENAI API KEY HERE"; // stop editing const char* host = "api.openai.com"; const int httpsPort = 443; const char ledPin = 2; WiFiClientSecure httpClient; /* Function to connect to WiFi */ void connectToWiFi(); /* Function to make HTTP request*/ bool sendHTTPRequest(String prompt, String *result); /* Function to pass user prompt and send it to OpenAI API*/ String getGptResponse(String prompt, bool parseMsg = true); void setup() { Serial.begin(115200); connectToWiFi(); } void loop() { if (Serial.available() > 0) { String prompt = Serial.readStringUntil('\n'); prompt.trim(); Serial.print("ESP32 > "); Serial.println(prompt); String response = getGptResponse(prompt); Serial.println("ChatGPT > " + response); delay(3000); } delay(10); } void connectToWiFi() { WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi..."); } Serial.println("Successful WiFi connection"); } bool sendHTTPRequest(String prompt, String *result) { if (WiFi.status() != WL_CONNECTED) { Serial.println("ERROR: Device not connected to WiFi"); return false; } // Connect to OpenAI API URL httpClient.setInsecure(); if (!httpClient.connect(host, httpsPort)) { Serial.println("Failed to connect with OpenAI API"); return false; } // Build Payload String payload = "{\"model\": \"gpt-3.5-turbo\",\"messages\": [{\"role\": \"user\", \"content\": \"" + prompt + "\"}]}"; Serial.println(payload); // Build HTTP Request String request = "POST /v1/chat/completions HTTP/1.1\r\n"; request += "Host: " + String(host) + "\r\n"; request += "Authorization: Bearer " + String(api_key) + "\r\n"; request += "Content-Type: application/json\r\n"; request += "Content-Length: " + String(payload.length()) + "\r\n"; request += "Connection: close\r\n"; request += "\r\n" + payload + "\r\n"; // Send HTTP Request httpClient.print(request); // LED function digitalWrite(ledPin, HIGH); delay(1000); digitalWrite(ledPin, LOW); delay(1000); // Get Response String response = ""; while (httpClient.connected()) { if (httpClient.available()) { response += httpClient.readStringUntil('\n'); response += String("\r\n"); } } httpClient.stop(); // Parse HTTP Response Code int responseCode = 0; if (response.indexOf(" ") != -1) { // If the first space is found responseCode = response.substring(response.indexOf(" ") + 1, response.indexOf(" ") + 4).toInt(); // Get the characters following the first space and convert to integer } if (responseCode != 200) { Serial.println("The procedure has failed. Info:" + String(response)); return false; } // Get JSON Body int start = response.indexOf("{"); int end = response.lastIndexOf("}"); String jsonBody = response.substring(start, end + 1); if (jsonBody.length() > 0) { *result = jsonBody; return true; } Serial.println("Error: Unable to read the information"); return false; } String getGptResponse(String prompt, bool parseMsg) { String resultStr; bool result = sendHTTPRequest(prompt, &resultStr); if (!result) return "Error : sendHTTPRequest"; if (!parseMsg) return resultStr; DynamicJsonDocument doc(resultStr.length() + 200); DeserializationError error = deserializeJson(doc, resultStr.c_str()); if (error) { return "[ERR] deserializeJson() failed: " + String(error.f_str()); } const char *_content = doc["choices"][0]["message"]["content"]; return String(_content); } |
I have kept this sketch on as a GitHub repository.
Upload the code to your ESP32 via Arduino IDE. You’ll probably need to press the reset button of ESP32 once. 
If you type your prompt on the Arduino serial monitor and hit enter, you’ll get a response from the OpenAPI server.
You can add a keyboard and display to make the thing independent of Arduino IDE’s serial monitor. There are not many possibilities with C++, Arduino IDE and a small space of ESP32. We can utilize the full power of OpenAI from ESP32 using another server and live reloading of code to make things “intelligent”.
Tagged With how to use ai in esp32