12. Making the response buffer pop up upon receipt
In this lesson, we will adjust the chatgpt-send and chatgpt-callback functions. The goal is to modify chatgpt-send so that it clears the prompt buffer upon sending a request, and to ensure that the *chatgpt[requests]* buffer displaying prompts and responses opens once a response is received from OpenAI.
Refactoring chatgpt-send into chatgpt-send-request¶
To implement these changes, we first refactor the chatgpt-send function into two distinct functions: chatgpt-send and chatgpt-send-request. The chatgpt-send-request function directly accepts the prompt as an argument, while the modified chatgpt-send function retrieves the prompt text from the current buffer and pass it to chatgpt-send-request.
(defun chatgpt-send-request (prompt)
"Send the request with PROMPT to OpenAI."
(let* ((req (chatgpt-request prompt))
(temporary-file-directory chatgpt-dir)
(req-dir (file-name-as-directory (make-temp-file nil t)))
(req-path (concat req-dir "request.json"))
(command (chatgpt-command req-path)))
(message "chatgpt: %s" req-dir)
(write-region (chatgpt-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)
(if (not (string= event "finished\n"))
(message "Error")
(let* ((resp (with-current-buffer (process-buffer process)
(goto-char (point-min))
(chatgpt-json-read)))
(response (map-nested-elt resp [:choices 0 :message :content]))
(resp-path (concat req-dir "response.json")))
(write-region (chatgpt-json-encode resp) nil resp-path)
(chatgpt-callback prompt response req-dir))
(kill-buffer (process-buffer process)))))))
(defun chatgpt-send ()
"Send the current prompt to OpenAI."
(interactive)
(chatgpt-send-request (buffer-string)))
Deleting The Prompt Buffer window¶
Next, we enhance the chatgpt-send function to delete the prompt buffer's contents and delete its window if more than one window is open in the Emacs frame.
We utilize erase-buffer to clear the current buffer and window-list to check the count of visible windows.
(defun chatgpt-send ()
"Send the current prompt to OpenAI."
(interactive)
(chatgpt-send-request (buffer-string))
(erase-buffer)
(when (> (length (window-list)) 1)
(delete-window)))
Here are two examples of window-list output when 1 and 2 windows are open:
(window-list)
;; (#<window 1471 on chatgpt.el>)
(window-list)
;; (#<window 1471 on chatgpt.el> #<window 1503 on *chatgpt*>)
Ensuring the Response Buffer is Displayed¶
Currently, we need to manually switch to the *chatgpt[requests]* buffer to view responses. We will modify the chatgpt-callback function to automatically display this buffer and position the latest response at the top.
By using display-buffer, we create a new window for the response buffer and, within the body of with-selected-window macro, we scroll to the last ## Response heading, ensuring it appears at the top of the view.
(defun chatgpt-callback (prompt response req-dir)
"Append PROMPT and RESPONSE to the prompt buffer with a link to REQ-DIR."
(let ((buff (get-buffer-create "*chatgpt[requests]*")))
(with-current-buffer buff
(markdown-mode)
(goto-char (point-max))
(insert "# Request\n\n"
"<!-- [](" req-dir ") -->\n\n"
"## Prompt\n\n" prompt "\n\n"
"## Response\n\n" response "\n\n"))
(with-selected-window (display-buffer buff nil)
(goto-char (point-max))
(re-search-backward "^## Response")
(recenter-top-bottom 0))))
Adding Notifications¶
Finally, we implement notifications in the echo area for when requests are sent and responses received from OpenAI.
(defun chatgpt-callback (prompt response req-dir)
"Append PROMPT and RESPONSE to the prompt buffer with a link to REQ-DIR."
(let ((buff (get-buffer-create "*chatgpt[requests]*")))
...
(message "Response received from OpenAI.")))
(defun chatgpt-send ()
"Send the current prompt to OpenAI."
(interactive)
...
(message "Request sent to OpenAI."))
This streamlined approach enhances the functionality we are implementing within our Emacs chat interface with OpenAI, facilitating improved user experience and interaction.