8. Making the Prompt Dynamic in Requests
In this lesson, we will enhance the chatgpt-send function to facilitate sending requests with prompts entered in a buffer.
Writing a JSON Object to a File¶
In the following sections, we will learn how to create a request.json file containing the JSON request sent to OpenAI.
First, we ensure to require the built-in json package:
Next, we use the json-encode function to encode an Emacs Lisp object into a JSON string:
We Utilize the write-region function to write the JSON string to a file:
This will create the file /home/tony/chatgpt-emacs/request-1.json containing:
Writing the OpenAI Request to a File¶
We generate the following JSON request
from Emacs Lisp. We bind it to a variable req, and write it to disk using json-encode and write-region:
(let ((req `(:model "gpt-4o"
:messages ,(vector `(:role "user" :content "Hello!")))))
(write-region (json-encode req)
nil "/home/tony/chatgpt-emacs/request-1.json"))
Evaluating this expression updates the file /home/tony/chatgpt-emacs/request-1.json with:
To pretty-print the JSON request, we set json-encoding-pretty-print to t:
(let ((json-encoding-pretty-print t)
(req `(:model "gpt-4o"
:messages ,(vector `(:role "user" :content "Hello!")))))
(write-region (json-encode req)
nil "/home/tony/chatgpt-emacs/request-1.json"))
Evaluating this expression yields the contents:
We can further enhance our code's flexibility by allowing prompts to change. Let's set prompt to "foo bar baz":
(let* ((json-encoding-pretty-print t)
(prompt "foo bar baz")
(req `(:model "gpt-4o"
:messages ,(vector `(:role "user" :content ,prompt)))))
(write-region (json-encode req)
nil "/home/tony/chatgpt-emacs/request-1.json"))
This writes the following to /home/tony/chatgpt-emacs/request-1.json:
Lastly, we introduce req-path to replace the hard-coded file path:
(let* ((json-encoding-pretty-print t)
(prompt "Hello!")
(req `(:model "gpt-4o"
:messages ,(vector `(:role "user" :content ,prompt))))
(req-path "/home/tony/chatgpt-emacs/request-1.json"))
(write-region (json-encode req) nil req-path))
Evaluating this will again result in the file being updated to:
Updating chatgpt-send¶
Now we can integrate the above functionality into chatgpt-send:
(defun chatgpt-send ()
"Send a request to OpenAI."
(interactive)
(let* ((json-encoding-pretty-print t)
(prompt "Hello!")
(req `(:model "gpt-4o"
:messages ,(vector `(:role "user" :content ,prompt))))
(req-path "/home/tony/chatgpt-emacs/request.json")
(command (chatgpt-command req-path)))
(write-region (json-encode req) nil req-path)
(make-process
:name "chatgpt"
:buffer (generate-new-buffer-name "chatgpt")
:command (list "sh" "-c" command)
:sentinel (lambda (process event) ...))))
After redefining chatgpt-send, calling it sends the JSON request in /home/tony/chatgpt-emacs/request.json to OpenAI, resulting in the following response in the *chatgpt[requests]* buffer:
{
"id": "chatcmpl-B5v9nIsqd7sclUBOXJjrsXugrTWs1",
"object": "chat.completion",
"created": 1740751051,
"model": "gpt-4o-2024-08-06",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Hi there! How can I assist you today?",
"refusal": null
},
...
}
],
...
}
Entering the Prompt from a Buffer¶
Finally, we modify chatgpt-send to use the current buffer content as the prompt. We replace the hardcoded prompt "Hello!" with a call to buffer-string:
(defun chatgpt-send ()
"Send a request to OpenAI."
(interactive)
(let* ((json-encoding-pretty-print t)
(prompt (buffer-string))
(req `(:model "gpt-4o"
:messages ,(vector `(:role "user" :content ,prompt))))
(req-path "/home/tony/chatgpt-emacs/request.json")
(command (chatgpt-command req-path)))
(write-region (json-encode req) nil req-path)
(make-process
:name "chatgpt"
:buffer (generate-new-buffer-name "chatgpt")
:command (list "sh" "-c" command)
:sentinel ...)))
Now, in a new buffer named *chatgpt*, if we enter the prompt I'm hungry and call chatgpt-send, we received the following response from OpenAI:
{
"id": "chatcmpl-B5vaCM7XPe9sCdfeE0iNDjU0RiMuf",
"object": "chat.completion",
"created": 1740752688,
"model": "gpt-4o-2024-08-06",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "What are you in the mood for? I can suggest
recipes, snacks, or nearby restaurants if you let me know your
preferences!",
"refusal": null
},
...
}
],
...
}
By following these steps, we have successfully made the prompt dynamic, enhancing the functionality of chatgpt-send.