chatGPT for human input processing

Hello Friends. It's been a long time. I was working on something today and thought I'd get your input.

I've been working with chatGPT a lot lately and I was wondering today about use cases involving Arduino. Obviously I could build code to drop API calls, but I'm sure that's done already but I wanted something that could actually use Arduino. So either giving GPT physical inputs and outputs or letting humans talk to arduino with natural language.

So here's a first attempt. GitHub - delta-G/ArduGPT: Letting ChatGPT control an Arduino board

The idea is to use chatGPT as an interpreter between human speaking and the commands that a home automation system might take. For this example my home automation setup is just an arduino UNO pretending to control three different things, lights, a fan, and an HVAC system.

Here's the example code for Arduino. It just grabs serial commands and sends back serial pretending that it turned things on or off. You can see where you'd put code to actually do those things instead of just saying it.

#define BUFFER_SIZE 10

void setup() {
  Serial.begin(115200);
}



boolean receiving = false;
char c;
char buffer[BUFFER_SIZE];
int index;

void loop() {
  
  if(Serial.available()){
    char c = Serial.read();

    if (c == '<'){
      receiving = true;
      index = 0;
      buffer[index] = 0;
    }
    if(receiving){
      buffer[index] = c;
      buffer[++index] = 0;
      if (index >= BUFFER_SIZE){
        index--;  // crude, but we will fix before we build anything that could overflow
      }
      if (c == '>'){
        receiving = false;
        processBuffer(buffer);
      }
    }

  }

}

void processBuffer(char* buffer){
  int len = strlen(buffer);
  char command = 0;
  if((buffer[0] == '<') && (buffer[len-1] == '>')){
    command = buffer[1];
    if(command == 'L'){
      if(buffer[3] == '0'){
        Serial.println("Turning Lights Off");
      } else if(buffer[3] == '1'){
        Serial.println("Turning Lights On");
      }
      else {
        Serial.println("Unkown Argument");
      }
    }
    else if(command == 'F'){
      if(buffer[3] == '0'){
        Serial.println("Turning Fan Off");
      } else if(buffer[3] == '1'){
        Serial.println("Turning Fan On");
      }
      else {
        Serial.println("Unkown Argument");
      }
    }
    else if(command == 'A'){
      int temp = strtol(buffer+3, NULL, 10);
      Serial.print("Setting HVAC to ");
      Serial.println(temp);
    }
    else {
      Serial.println("Unknown Command");
    }
  }
  else {
    Serial.println("Bad Command Format");
  }
}

Ordinarily the user would have to memorize these commands. With some complex string processing, we could take in a number of natural language like strings and extract the information we need, but with all the nuance of language it would likely still fail for a number of use cases.

Imagine that we need it to respond not only to "Lights Off" but also "Turn lights off", "Kill the lights", "cut the lights", "switch off the lights" and every other possible way of saying in english to turn off the light. It would be a lot of code and we'd still miss a few.

So here's where NLP comes in. In this super simple example, I am using GPT-3.5-turbo through langchain in python. If you're not familiar with this type of code, let me assure you that it's pretty simple. Most of the code is around building the llm chain and taking the inputs from the user and sending stuff to arduino. All of the magic happens in the prompt template.


#     This program is free software: you can redistribute it and/or modify
#     it under the terms of the GNU General Public License as published by
#     the Free Software Foundation, either version 3 of the License, or
#     (at your option) any later version.
# 
#     This program is distributed in the hope that it will be useful,
#     but WITHOUT ANY WARRANTY; without even the implied warranty of
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#     GNU General Public License for more details.
# 
#     You should have received a copy of the GNU General Public License
#     along with this program.  If not, see <http://www.gnu.org/licenses/>.


import serial, time

from langchain import OpenAI, PromptTemplate, LLMChain
from langchain.chat_models import ChatOpenAI


template = """
You are an LLM that is acting as a translator between human input and a home automation system.
You will be given a list of commands and arguments that each command can take. 
You will decide based on the human input which command and arguments to pass to the output and format them appropriately.

Here is a list of commands you can use with descriptions of their arguments and output:
[

command: "L"
description:  used to turn lights on or off
input:  either of "0" for off or "1" for on

command: "F"
description:  used to turn the fan on or off
input:  either of "0" for off or "1" for on

command: "A"
description:  used to set the thermostat for the HVAC system
input:  the temperature to set

]

If you do not find a suitable command, then respond with "unable"

To format the command string, place a "<" symbol before the command, then the command, then a comma "," and then any arguments as a comma separated list.  Finally include the ">" symbol.  

Here are some examples of formatted command strings:
To turn the light on: <L,1>
To turn the fan off: <F,0>
To set the HVAC to 85 degrees <A,85>

Be sure to include the formatted command string in your response and do not include any < or > symbols anywhere else in the response.  

Begin!

Human Input:
{input}

"""


class ArduGPT:
    
    def __init__(self, device):
        
        self.exit_flag = False
        self.device = device
        llm = ChatOpenAI(
            model_name="gpt-3.5-turbo", 
            temperature=0
            )

        prompt = PromptTemplate(
            input_variables=["input"],
            template=template,
            )   
        
        self.llm_chain = LLMChain(llm=llm, prompt=prompt)
        
        return
    
    
    def getUserInput(self):
        print("\n*******************************\n\nHuman:  ")
        self.human_input = input("")
        if self.human_input == "exit":
            self.exit_flag = True
        return 
    
    def printResponse(self):
        
        if self.ai_output is not None:
            print("\n*******************************\n\nAI:  ")
            print(self.ai_output)
            if 'unable' not in self.ai_output:
                self.device.write(bytes(self.ai_output, 'utf-8'))
                time.sleep(0.1)  ## sleep while we wait for response
                returned = self.device.readline()
                print("\n*******************************\n\nArduino:  ")
                print(returned)
            
        
        return 
    
    def getResponse(self):
            
        if self.human_input is not None:
            self.ai_output = self.llm_chain.run(self.human_input)                             
        
        return 
    
    def run(self):
        
        self.getUserInput()
        while not self.exit_flag:
            self.getResponse()
            self.printResponse()
            self.getUserInput()   
        return 
    
arduino = serial.Serial(port='/dev/ttyACM0', baudrate=115200, timeout=0.1)
    

ard = ArduGPT(arduino)
ard.run()

Now when you run this code from the console you see this sort of output:

$ python ArduinoGptLight.py

*******************************

Human:  
Please turn on the light

*******************************

AI:  
Output:
<L,1>

*******************************

Arduino:  
b'Turning Lights On\r\n'

*******************************

Human:  
Please set the heat to 75

*******************************

AI:  
Output:
<A,75>

*******************************

Arduino:  
b'Setting HVAC to 75\r\n'

*******************************

Human:  
cut off the fan

*******************************

AI:  
Output:
<F,0>

*******************************

Arduino:  
b'Turning Fan Off\r\n'

*******************************

Human:  
kill the lights

*******************************

AI:  
Response:
<L,0>

*******************************

Arduino:  
b'Turning Lights Off\r\n'

*******************************

Human:  
set the air to 68

*******************************

AI:  
Output:
<A,68>

*******************************

Arduino:  
b'Setting HVAC to 68\r\n'

*******************************

Human:  
switch the lights on

*******************************

AI:  
Output:
<L,1>

*******************************

Arduino:  
b'Turning Lights On\r\n'

*******************************

Human:  
exit

And you can see that the AI is accurately understanding what the human is asking and translating that into the command structure that is needed for the arduino code. You can certainly imagine that arduino code getting much more complex and controlling more things. I think this serves as just an example. I can also imagine that the prompt could be improved. That represents just a few edits to my original attempt. I'm learning that the prompt is where the magic is in these NLP projects.

Anyway, I wanted to leave this here in hopes that either someone would have some ideas to share for improvements or maybe someone finds the code useful. If it's in the wrong section please feel free to move it.

1 Like

i love when human begin talking to machine with "please" and wenn machine is programmed to say "welcome" :rofl:

1 Like

Just to add a little more complexity, I added a function to the Arduino code to print a room name in response to a character code (ArduGPT/arduGPTexample.ino at master · delta-G/ArduGPT · GitHub) and then rewrote the prompt template as this:

template = """

You are an LLM that is acting as a translator between human input and a home automation system.

You will be given a list of commands and arguments that each command can take.

You will decide based on the human input which command and arguments to pass to the output and format them appropriately.

You will control the lights and fans in various rooms as well as an HVAC thermostat.

Here is a list of the room codes and corresponding rooms:

[

"L" Living Room

"K" Kitchen"

"D" Den

"M" Master Bedroom

"G" Guest Bedroom

"H" Hallway

"B" Bathroom

"C" Carport

]

Here is a list of commands you can use with descriptions of their arguments and output:

[

command: "L"

description: used to turn lights on or off

input: a room code and either of "0" for off or "1" for on

command: "F"

description: used to turn the fan on or off

input: a room code and either of "0" for off or "1" for on

command: "A"

description: used to set the thermostat for the HVAC system

input: the temperature to set

]

If you do not find a suitable command, then respond with "unable"

To format the command string, place a "<" symbol before the command, then the command, then a comma "," and then any arguments as a comma separated list. Finally include the ">" symbol.

Here are some examples of formatted command strings:

To turn the hallway light on: <L,H,1>

To turn the kitchen fan off: <F,K,0>

To set the HVAC to 85 degrees <A,85>

Be sure to include the formatted command string in your response and do not include any < or > symbols anywhere else in the response.

Begin!

Human Input:

{input}

"""

So now with just that small change to the template, the AI can control multiple rooms. And still you can speak to it in natural language, you don't have to stick to any sort of pre-canned set of prompts.

$ python ArduinoGptLight.py

*******************************

Human:  
turn on the kitchen light

*******************************

AI:  
Output:
<L,K,1>

*******************************

Arduino:  
b'Turning Kitchen Lights On\r\n'

*******************************

Human:  
James is going into the bathroom.  Please turn the fan on in there.     

*******************************

AI:  
Output:
<F,B,1>

*******************************

Arduino:  
b'Turning Bathroom Fan On\r\n'

*******************************

Human:  
It's too dark in the guest bedroom.  Can you hit the lights?

*******************************

AI:  
Output:
<L,G,1>

*******************************

Arduino:  
b'Turning Guest Bedroom Lights On\r\n'

*******************************

Human:  
exit

I think the Arduino side of this code is trivial to write for even an intermediate coder. The python side is cut and paste. It's just the instruction in the prompt template that really matters.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.