Skip to content

Commit

Permalink
Add queued queries
Browse files Browse the repository at this point in the history
  • Loading branch information
joshcho committed Dec 13, 2022
1 parent 07f82c7 commit 42b053f
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 29 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.mp4
5 changes: 4 additions & 1 deletion README.org
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#+TITLE: ChatGPT.el

[[https://chat.openai.com/chat][ChatGPT]] in Emacs. [[https://www.youtube.com/watch?v=4oUrm4CnIjo][Demo]]
[[https://chat.openai.com/chat][ChatGPT]] in Emacs.

[[https://www.youtube.com/watch?v=4oUrm4CnIjo][Basic Demo]] [[https://www.youtube.com/watch?v=1LMlt5Cv4fY][Queue Demo]]

** Installation
*** Dependency
Expand Down Expand Up @@ -39,6 +41,7 @@ NOTE: The setup should happen automatically first time you query, but it's a bit
** Usage
- Press ~C-c q~ to query ChatGPT.
- Select region before ~C-c q~ to query ChatGPT by type.
- You can queue queries one after another.
- If your login is expired, M-x chatgpt-login.

** Troubleshooting
Expand Down
70 changes: 42 additions & 28 deletions chatgpt.el
Original file line number Diff line number Diff line change
Expand Up @@ -87,17 +87,15 @@ function."
(visual-line-mode 1))
(message "ChatGPT initialized."))

(defvar chatgpt-waiting-dot-timer nil
)

(defvar chatgpt-wait-timers (make-hash-table)
"Timers to update the waiting message in the ChatGPT buffer.")

;;;###autoload
(defun chatgpt-stop ()
"Stops the ChatGPT server."
(interactive)
(chatgpt--stop-wait)
(dolist (id (hash-table-keys chatgpt-wait-timers))
(chatgpt--stop-wait id))
(epc:stop-epc chatgpt-process)
(setq chatgpt-process nil)
(message "Stop ChatGPT process."))
Expand Down Expand Up @@ -126,35 +124,40 @@ function."

(defun chatgpt--clear-line ()
"Clear line in *ChatGPT*."
(assert (equal (current-buffer) (get-buffer "*ChatGPT*")))
(cl-assert (equal (current-buffer) (get-buffer "*ChatGPT*")))
(delete-region (save-excursion (beginning-of-line)
(point))
(save-excursion (end-of-line)
(point))))

(defun chatgpt--identifier-string (id)
"Identifier string corresponding to ID."
(format "[%s]" id))
(format "cg?[%s]" id))

(defun chatgpt--regex-string (id)
"Regex corresponding to ID."
(format "\\[%s\\]" id))
(format "cg\\?\\[%s\\]" id))

(defun chatgpt--goto-identifier (id)
"Go to response of ID."
(assert (equal (current-buffer) (get-buffer "*ChatGPT*")))
(cl-assert (equal (current-buffer) (get-buffer "*ChatGPT*")))
(goto-char (point-min))
(re-search-forward (chatgpt--regex-string id))
(next-line))
(forward-line))

(defun chatgpt--insert-query (query id)
"Insert QUERY with ID into *ChatGPT*."
(with-current-buffer (get-buffer-create "*ChatGPT*")
(save-excursion
(goto-char (point-max))
(insert (format "\n\n%s\n%s\n%s"
(insert (format "%s%s\n%s\n%s"
(if (= (point-min) (point))
""
"\n\n")
(propertize query 'face 'bold)
(chatgpt--identifier-string id)
(propertize
(chatgpt--identifier-string id)
'invisible t)
(if chatgpt-enable-loading-ellipsis
""
(concat "Waiting for ChatGPT...")))))))
Expand All @@ -167,11 +170,31 @@ function."
(chatgpt--clear-line)
(insert response))))

(defun chatgpt--stop-wait ()
"Stop waiting for a response."
(when chatgpt-waiting-dot-timer
(cancel-timer chatgpt-waiting-dot-timer)
(setq chatgpt-waiting-dot-timer nil)))
(defun chatgpt--add-timer (id)
"Add timer for ID to 'chatgpt-wait-timers'."
(cl-assert (null (gethash id chatgpt-wait-timers)))
(puthash id
(run-with-timer 0.5 0.5
(eval
`(lambda ()
(with-current-buffer (get-buffer-create "*ChatGPT*")
(save-excursion
(chatgpt--goto-identifier ,id)
(let ((line (thing-at-point 'line)))
(when (>= (+ (length line)
(if (eq (substring line -1) "\n")
0
1))
4)
(chatgpt--clear-line))
(insert ".")))))))
chatgpt-wait-timers))

(defun chatgpt--stop-wait (id)
"Stop waiting for a response from ID."
(when-let (timer (gethash id chatgpt-wait-timers))
(cancel-timer timer)
(remhash id chatgpt-wait-timers)))

(defvar chatgpt-id 0
"Tracks responses in the background.")
Expand All @@ -190,26 +213,17 @@ This function is intended to be called internally by the
users."
(unless chatgpt-process
(chatgpt-init))
(let ((saved-id (incf chatgpt-id)))
(let ((saved-id (cl-incf chatgpt-id)))
(chatgpt--insert-query query saved-id)
(when chatgpt-enable-loading-ellipsis
(setq chatgpt-waiting-dot-timer
(run-with-timer 0.5 0.5
(lambda ()
(with-current-buffer (get-buffer-create "*ChatGPT*")
(save-excursion
(chatgpt--goto-identifier saved-id)
(let ((line (thing-at-point 'line)))
(when (>= (length line) 3)
(chatgpt--clear-line))
(insert "."))))))))
(chatgpt--add-timer saved-id))
(when chatgpt-display-on-query
(chatgpt-display))
(deferred:$
(epc:call-deferred chatgpt-process 'query (list query))
(eval `(deferred:nextc it
(lambda (response)
(chatgpt--stop-wait)
(chatgpt--stop-wait ,saved-id)
(chatgpt--insert-response response ,saved-id)
(when chatgpt-display-on-response
(chatgpt-display))))))))
Expand Down

0 comments on commit 42b053f

Please sign in to comment.