Skip to content

7. Refactoring chatgpt-send and introducing chatgpt-api-key

In this section, we will refactor the chatgpt-send function. We will create a new function named chatgpt-command to encapsulate the curl command logic. Additionally, we will introduce a variable called chatgpt-api-key to store our OpenAI API key securely.

Refactoring chatgpt-send with chatgpt-command

We introduce the chatgpt-command function, which generates the curl command string. This allows us to streamline chatgpt-send by replacing the existing command code with a call to chatgpt-command.

(defun chatgpt-command ()
  "Return the curl command."
  (concat "curl https://api.openai.com/v1/chat/completions "
          "-H 'Content-Type: application/json' "
          "-H 'Authorization: Bearer sk-proj-7pQDxN...w-D40A "
          "-d @/home/tony/chatgpt-emacs/request.json"))

(defun chatgpt-send ()
  "Send the request \"Hello!\" to OpenAI."
  (interactive)
  (let ((command (chatgpt-command)))
    (make-process
     :name "chatgpt"
     :buffer (generate-new-buffer-name "chatgpt")
     :command (list "sh" "-c" command)
     :sentinel (lambda (process event) ...))))

After implementing these changes and evaluating these expressions, calling chatgpt-send command should successfully populate the buffer *chatgpt[requests]* with a new response from OpenAI, confirming that the functionality remains intact.

Introducing chatgpt-api-key to hold OpenAI API Key

In this update, we refactor the hardcoded API key previously embedded within the chatgpt-command function. Instead, we store it in a new variable, chatgpt-api-key. This approach allows for easier future modifications to the API key. And in upcoming lessons, we will explore a more secure method for storing the API key, rather than embedding it directly in the source code.

Updated Code

(defvar chatgpt-api-key "sk-proj-7pQDxN...w-D40A"
  "Variable to hold the OpenAI API key.")

(defun chatgpt-command ()
  "Construct and return the curl command for OpenAI API."
  (format
   (concat "curl https://api.openai.com/v1/chat/completions "
           "-H 'Content-Type: application/json' "
           "-H 'Authorization: Bearer %s' "
           "-d @/home/tony/chatgpt-emacs/request.json")
   chatgpt-api-key))

Testing with an Incorrect API Key

For testing purposes, we can temporarily set the chatgpt-api-key variable to an invalid key, for example, foo-api-key. When invoking the chatgpt-send command, the OpenAI API responded with an error message displayed in the *chatgpt[requests]* buffer:

{
    "error": {
        "message": "Incorrect API key provided: foo-api-key.
You can find your API key at https://platform.openai.com/acc
ount/api-keys.",
        "type": "invalid_request_error",
        "param": null,
        "code": "invalid_api_key"
    }
}

This demonstrates that the API key is validated properly by OpenAI.

Updating chatgpt-command Function Signature

Finaly, we modify the chatgpt-command function to accept the absolute path to the request.json file as an argument. This change allows for easier adjustments to the file path in the future.

(defun chatgpt-command (req-path)
  "Return the curl command."
  (format
   (concat "curl https://api.openai.com/v1/chat/completions "
           "-H 'Content-Type: application/json' "
           "-H 'Authorization: Bearer %s' "
           "-d @%s")
   chatgpt-api-key req-path))

(defun chatgpt-send ()
  "Send the request \"Hello!\" to OpenAI."
  (interactive)
  (let ((command (chatgpt-command "/home/tony/chatgpt-emacs/request.json")))
    (make-process
     :name "chatgpt"
     :buffer (generate-new-buffer-name "chatgpt")
     :command (list "sh" "-c" command)
     :sentinel (lambda (process event) ...))))

For testing, we can pass a non-existent file path, such as "/home/tony/chatgpt-emacs/request", to the chatgpt-command function in chatgpt-send. When invoking the chatgpt-send command, the curl command produced warnings, and the OpenAI API returned an error message, both of which were displayed in the *chatgpt[requests]* buffer:

Warning: Couldn't read data from file "/home/tony/chatgpt-emacs/request",
Warning: this makes an empty POST.
{
    "error": {
        "message": "We could not parse the JSON body of your request.
(HINT: This likely means you aren't using your HTTP library correctly. The
OpenAI API expects a JSON payload, but what was sent was not valid JSON.
If you have trouble figuring out how to fix this, please contact us through
our help center at help.openai.com.)",
        "type": "invalid_request_error",
        "param": null,
        "code": null
    }
}