👉 Support this work via GitHub Sponsors
ChatGPT and DALL-E Emacs shells + Org Babel.
Includes shell-maker
, a way to create shells for any service (local or cloud).
This is very much an experimental proof of concept, possibly incomplete, or maybe with some rough edges. Pull requests with improvements or fixes totally welcome.
- Load
(require 'chatgpt-shell)
- Load
(require 'dall-e-shell)
You’ll first need to get a key from OpenAI.
;; if you are using the "pass" password manager
(setq chatgpt-shell-openai-key
(lambda ()
;; (auth-source-pass-get 'secret "openai-key") ; alternative using pass support in auth-sources
(nth 0 (process-lines "pass" "show" "openai-key"))))
;; or if using auth-sources, e.g., so the file ~/.authinfo has this line:
;; machine api.openai.com password OPENAI_KEY
(setq chatgpt-shell-openai-key
(auth-source-pick-first-password :host "api.openai.com"))
;; or same as previous but lazy loaded (prevents unexpected passphrase prompt)
(setq chatgpt-shell-openai-key
(lambda ()
(auth-source-pick-first-password :host "api.openai.com")))
M-x set-variable chatgpt-shell-openai-key
(setq chatgpt-shell-openai-key "my key")
Same as ChatGPT, but use dall-e-shell-openai-key
variable.
Launch with M-x chatgpt-shell
or dall-e-shell
.
Type clear
as a prompt.
ChatGPT> clear
Alternatively, use either M-x chatgpt-shell-clear-buffer
or M-x comint-clear-buffer
.
Save with M-x shell-maker-save-session-transcript
and restore with M-x chatgpt-shell-restore-session-from-transcript
.
chatgpt-shell
can either wait until the entire response is received before displaying, or it can progressively display as chunks arrive (streaming).
(setq chatgpt-shell-chatgpt-streaming nil)
to disable streaming. Streaming is enabled by default.
M-x chatgpt-shell-explain-code
There are other functions to act on region. Browse all available via M-x
.
Load (require 'ob-chatgpt-shell)
and invoke (ob-chatgpt-shell-setup)
.
#+begin_src chatgpt-shell
Hello
#+end_src
#+RESULTS:
: Hi there! How can I assist you today?
Load (require 'ob-dall-e-shell)
and invoke (ob-dall-e-shell-setup)
.
#+begin_src dall-e-shell
Pretty clouds
#+end_src
#+RESULTS:
[[file:/var/folders/m7/ky091cp56d5g68nyhl4y7frc0000gn/T/1680644778.png]]
chatgpt-shell-default-prompts | List of prompts to choose from in the minibuffer. |
chatgpt-shell-model-version | The used ChatGPT OpenAI model. |
chatgpt-shell-streaming | Whether or not to stream ChatGPT responses (experimental). |
chatgpt-shell-system-prompt | The system message helps set the behavior of the assistant. |
chatgpt-shell-language-mapping | Maps external language names to Emacs names. |
chatgpt-shell-model-temperature | What sampling temperature to use, between 0 and 2, or nil. |
chatgpt-shell-openai-key | OpenAI key as a string or a function that loads and returns it. |
chatgpt-shell-request-timeout | How long to wait for a request to time out. |
chatgpt-shell-display-function | Function to display new shell. Can be set to `display-buffer’ or custom function. |
chatgpt-shell-read-string-function | Function to read strings from user. |
chatgpt-shell-on-response-function | Function to automatically execute after last command output. |
dall-e-shell-openai-key | OpenAI key as a string or a function that loads and returns it. |
dall-e-image-size | The default size of the requested image as a string. |
dall-e-model-version | The used DALL-E OpenAI model. |
There are more. Browse via M-x set-variable
If you’d prefer your own custom display function,
(setq chatgpt-shell-display-function #'my/chatgpt-shell-frame)
(defun my/chatgpt-shell-frame (bname)
(let ((cur-f (selected-frame))
(f (my/find-or-make-frame "chatgpt")))
(select-frame-by-name "chatgpt")
(pop-to-buffer-same-window bname)
(set-frame-position f (/ (display-pixel-width) 2) 0)
(set-frame-height f (frame-height cur-f))
(set-frame-width f (frame-width cur-f) 1)))
(defun my/find-or-make-frame (fname)
(condition-case
nil
(select-frame-by-name fname)
(error (make-frame `((name . ,fname))))))
Thanks to tuhdo for the custom display function.
dall-e-shell | Start a DALL-E shell. |
chatgpt-shell | Start a ChatGPT shell. |
chatgpt-shell-prompt | Make a ChatGPT request from the minibuffer. |
chatgpt-shell-describe-code | Describe code from region using ChatGPT. |
chatgpt-shell-eshell-summarize-last-command-output | Ask ChatGPT to summarize the last command output. |
chatgpt-shell-eshell-whats-wrong-with-last-command | Ask ChatGPT what’s wrong with the last eshell command. |
chatgpt-shell-mark-output | Mark last or current output. |
chatgpt-shell-restore-session-from-transcript | Restore session from transcript. |
chatgpt-shell-save-session-transcript | Save shell transcript to file. |
chatgpt-shell-send-and-review-region | Send region to ChatGPT, review before submitting. |
chatgpt-shell-send-region | Send region to ChatGPT. |
There are more. Browse all available via M-x
.
There are currently two shell implementations (ChatGPT and DALL-E). Other services (local or cloud) can be brought to Emacs as shells. shell-maker
can help with that.
shell-maker
is a convenience wrapper around comint mode.
Both chatgpt-shell
and dall-e-shell
use shell-maker
, but a basic implementation of a new shell looks as follows:
(require 'shell-maker)
(defvar greeter-shell--config
(make-shell-maker-config
:name "Greeter"
:execute-command
(lambda (command _history callback error-callback)
(funcall callback
(format "Hello \"%s\"" command)
nil))))
(defun greeter-shell ()
"Start a Greeter shell."
(interactive)
(shell-maker-start greeter-shell--config))