Skip to content

xenodium/chatgpt-shell

Repository files navigation

👉 Support this work via GitHub Sponsors

https://melpa.org/packages/chatgpt-shell-badge.svg

chatgpt-shell

ChatGPT and DALL-E Emacs shells + Org Babel.

Includes shell-maker, a way to create shells for any service (local or cloud).

Support this effort

If you’re finding chatgpt-shell useful, consider ✨sponsoring✨.

chatgpt-shell is in development. Please report issues or send pull requests for improvements.

Like this package? Tell me about it đź’™

Finding it useful? Like the package? I’d love to hear from you. Get in touch (Mastodon / Twitter / Reddit / Email).

Shell usage

Insert to current buffer

Install

  • Load (require 'chatgpt-shell)
  • Load (require 'dall-e-shell)

MELPA

If using use-package, you can install with :ensure t.

(use-package chatgpt-shell
  :ensure t
  :custom
  ((chatgpt-shell-openai-key
    (lambda ()
      (auth-source-pass-get 'secret "openai-key")))))

Straight

chatgpt-shell depends on shell-maker. This dependency is resolved without issues on MELPA but seems to run into issues with straight. I’m not familiar with straight but users have reported the following to work.

(use-package shell-maker
  :straight (:host github :repo "xenodium/chatgpt-shell" :files ("shell-maker.el")))

(use-package chatgpt-shell
  :requires shell-maker
  :straight (:host github :repo "xenodium/chatgpt-shell" :files ("chatgpt-shell.el")))

If you have a better straight solution, please send a pull request or open an issue with a suggestion.

Read on for setting your OpenAI key in other ways.

Set OpenAI key

You’ll first need to get a key from OpenAI.

ChatGPT key

As function

;; 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")))

Manually

M-x set-variable chatgpt-shell-openai-key

As variable

(setq chatgpt-shell-openai-key "my key")

As an ENV variable

(setq chatgpt-shell-openai-key (getenv "OPENAI_API_KEY"))

DALL-E key

Same as ChatGPT, but use dall-e-shell-openai-key variable.

ChatGPT through proxy service

If you use ChatGPT through proxy service “https://api.chatgpt.domain.com”, set options like the following:

(use-package chatgpt-shell
  :ensure t
  :custom
  ((chatgpt-shell-api-url-base "https://api.chatgpt.domain.com")
   (chatgpt-shell-openai-key
    (lambda ()
      ;; Here the openai-key should be the proxy service key.
      (auth-source-pass-get 'secret "openai-key")))))

If your proxy service API path is not OpenAI ChatGPT default path like ”/v1/chat/completions”, then you can customize option chatgpt-shell-api-url-path.

Using ChatGPT through HTTP(S) proxy

Behind the scenes chatgpt-shell uses curl to send requests to the openai server. If you use ChatGPT through a HTTP proxy (for example you are in a corporate network and a HTTP proxy shields the corporate network from the internet), you need to tell curl to use the proxy via the curl option -x http://your_proxy. One way to do this is to set the proxy url via the customizable variable chatgpt-shell-additional-curl-options. If you set this variable via the Emacs Customize interface you should insert two separate items -x and http://your_proxy. See the curl manpage for more details and further options.

Using ChatGPT through Azure OpenAI Service

Endpoint: https://{your-resource-name}.openai.azure.com/openai/deployments/{deployment-id}/chat/completions?api-version={api-version}

Configure the following variables:

(setq chatgpt-shell-api-url-base "https://{your-resource-name}.openai.azure.com")
(setq chatgpt-shell-api-url-path "/openai/deployments/{deployment-id}/chat/completions?api-version={api-version}")
(setq chatgpt-shell-auth-header (lambda () (format "api-key: %s" (chatgpt-shell-openai-key))))

Launch

Launch with M-x chatgpt-shell or dall-e-shell.

Clear buffer

Type clear as a prompt.

ChatGPT> clear

Alternatively, use either M-x chatgpt-shell-clear-buffer or M-x comint-clear-buffer.

Saving and restoring (experimental)

Save with M-x shell-maker-save-session-transcript and restore with M-x chatgpt-shell-restore-session-from-transcript.

Streaming

chatgpt-shell can either wait until the entire response is received before displaying, or it can progressively display as chunks arrive (streaming).

Streaming is enabled by default. (setq chatgpt-shell-streaming nil) to disable it.

chatgpt-shell customizations

Custom variableDescription
chatgpt-shell-display-functionFunction to display the shell. Set to `display-buffer’ or custom function.
chatgpt-shell-model-versionsThe list of ChatGPT OpenAI models to swap from.
chatgpt-shell-system-promptThe system prompt `chatgpt-shell-system-prompts’ index.
chatgpt-shell-default-promptsList of default prompts to choose from.
chatgpt-shell-read-string-functionFunction to read strings from user.
chatgpt-shell-model-temperatureWhat sampling temperature to use, between 0 and 2, or nil.
chatgpt-shell-transmitted-context-lengthControls the amount of context provided to chatGPT.
chatgpt-shell-system-promptsList of system prompts to choose from.
chatgpt-shell-streamingWhether or not to stream ChatGPT responses (show chunks as they arrive).
chatgpt-shell-prompt-header-refactor-codePrompt header of `refactor-code`.
chatgpt-shell-auth-headerFunction to generate the request’s `Authorization’ header string.
chatgpt-shell-prompt-header-whats-wrong-with-last-commandPrompt header of `whats-wrong-with-last-command`.
chatgpt-shell-prompt-header-write-git-commitPrompt header of `git-commit`.
chatgpt-shell-loggingLogging disabled by default (slows things down).
chatgpt-shell-prompt-query-response-styleDetermines the prompt style when invoking from other buffers.
chatgpt-shell-root-pathRoot path location to store internal shell files.
chatgpt-shell-prompt-header-proofread-regionPromt header of `proofread-region`.
chatgpt-shell-model-versionThe active ChatGPT OpenAI model index.
chatgpt-shell-source-block-actionsBlock actions for known languages.
chatgpt-shell-prompt-header-eshell-summarize-last-command-outputPrompt header of `eshell-summarize-last-command-output`.
chatgpt-shell-welcome-functionFunction returning welcome message or nil for no message.
chatgpt-shell-api-url-pathOpenAI API’s URL path.
chatgpt-shell-additional-curl-optionsAdditional options for `curl’ command.
chatgpt-shell-openai-keyOpenAI key as a string or a function that loads and returns it.
chatgpt-shell-after-command-functionsAbnormal hook (i.e. with parameters) invoked after each command.
chatgpt-shell-prompt-header-describe-codePrompt header of `describe-code`.
chatgpt-shell-api-url-baseOpenAI API’s base URL.
chatgpt-shell-babel-headersAdditional headers to make babel blocks work.
chatgpt-shell-highlight-blocksWhether or not to highlight source blocks.
chatgpt-shell-language-mappingMaps external language names to Emacs names.
chatgpt-shell-prompt-header-generate-unit-testPrompt header of `generate-unit-test`.
chatgpt-shell-request-timeoutHow long to wait for a request to time out in seconds.

There are more. Browse via M-x set-variable

chatgpt-shell-display-function (with custom function)

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.

chatgpt-shell commands

BindingCommandDescription
chatgpt-shellStart a ChatGPT shell interactive command.
chatgpt-shell-rename-block-at-pointRename block at point (perhaps a different language).
C-M-hchatgpt-shell-mark-at-point-dwimMark source block if at point. Mark all output otherwise.
C-<up> or M-pchatgpt-shell-previous-inputCycle backwards through input history, saving input.
chatgpt-shell-execute-babel-block-action-at-pointExecute block as org babel.
chatgpt-shell-eshell-whats-wrong-with-last-commandAsk ChatGPT what’s wrong with the last eshell command.
C-c C-pchatgpt-shell-previous-itemGo to previous item.
chatgpt-shell-set-as-primary-shellSet as primary shell when there are multiple sessions.
chatgpt-shell-refresh-renderingRefresh markdown rendering by re-applying to entire buffer.
chatgpt-shell-explain-codeDescribe code from region using ChatGPT.
chatgpt-shell-rename-bufferRename current shell buffer.
chatgpt-shell-write-git-commitWrite commit from region using ChatGPT.
chatgpt-shell-promptMake a ChatGPT request from the minibuffer.
chatgpt-shell-remove-block-overlaysRemove block overlays. Handy for renaming blocks.
chatgpt-shell-system-prompts-menuChatGPT
chatgpt-shell-proofread-regionProofread English from region using ChatGPT.
M-rchatgpt-shell-search-historySearch previous input history.
chatgpt-shell-send-and-review-regionSend region to ChatGPT, review before submitting.
C-<down> or M-nchatgpt-shell-next-inputCycle forwards through input history.
chatgpt-shell-eshell-summarize-last-command-outputAsk ChatGPT to summarize the last command output.
chatgpt-shell-prompt-appending-kill-ringMake a ChatGPT request from the minibuffer appending kill ring.
chatgpt-shell-describe-codeDescribe code from region using ChatGPT.
chatgpt-shell-modeMajor mode for ChatGPT shell.
C-c C-vchatgpt-shell-swap-model-versionSwap model version from `chatgpt-shell-model-versions’.
chatgpt-shell-previous-source-blockMove point to previous source block.
chatgpt-shell-refactor-codeRefactor code from region using ChatGPT.
S-<return>chatgpt-shell-newlineInsert a newline, and move to left margin of the new line.
C-c C-schatgpt-shell-swap-system-promptSwap system prompt from `chatgpt-shell-system-prompts’.
C-x C-schatgpt-shell-save-session-transcriptSave shell transcript to file.
C-c M-ochatgpt-shell-clear-bufferClear the comint buffer.
chatgpt-shell-load-awesome-promptsLoad `chatgpt-shell-system-prompts’ from awesome-chatgpt-prompts.
RETchatgpt-shell-submitSubmit current input.
C-c C-nchatgpt-shell-next-itemGo to next item.
chatgpt-shell-describe-imageRequest OpenAI to describe image.
chatgpt-shell-execute-block-action-at-pointExecute block at point.
chatgpt-shell-view-at-pointView prompt and output at point in a separate buffer.
chatgpt-shell-send-regionSend region to ChatGPT.
chatgpt-shell-restore-session-from-transcriptRestore session from transcript.
chatgpt-shell-generate-unit-testGenerate unit-test for the code from region using ChatGPT.
C-c C-echatgpt-shell-prompt-composeCompose and send prompt (kbd “C-c C-c”) from a dedicated buffer.
chatgpt-shell-next-source-blockMove point to previous source block.
C-c C-cchatgpt-shell-ctrl-c-ctrl-cIf point in source block, execute it. Otherwise interrupt.
chatgpt-shell-interruptInterrupt `chatgpt-shell’ from any buffer.

Browse all available via M-x.

Feature requests

  • Please go through this README to see if the feature is already supported.
  • Need custom behaviour? Check out existing issues/feature requests. You may find solutions in discussions.

Reporting bugs

Setup isn’t working?

Please share the entire snippet you’ve used to set chatgpt-shell up (but redact your key). Share any errors you encountered. Read on for sharing additional details.

Found runtime/elisp errors?

Please enable M-x toggle-debug-on-error, reproduce the error, and share the stack trace.

Found unexpected behaviour?

Please enable logging (setq chatgpt-shell-logging t) and share the content of the *chatgpt-log* buffer in the bug report.

Babel issues?

Please also share the entire org snippet.

dall-e-shell customizations

Custom variableDescription
dall-e-shell-welcome-functionFunction returning welcome message or nil for no message.
dall-e-shell-openai-keyOpenAI key as a string or a function that loads and returns it.
dall-e-shell-image-sizeThe default size of the requested image as a string.
dall-e-shell-read-string-functionFunction to read strings from user.
dall-e-shell-request-timeoutHow long to wait for a request to time out.
dall-e-shell-model-versionThe used DALL-E OpenAI model. For Dall-E 3, use “dall-e-3”.
dall-e-shell-display-functionFunction to display the shell. Set to `display-buffer’ or custom function.
dall-e-shell-model-versionsThe list of Dall-E OpenAI models to swap from.
dall-e-shell-additional-curl-optionsAdditional options for `curl’ command.
dall-e-shell-image-output-directoryOutput directory for the generated image.
dall-e-shell-image-qualityImage quality: `standard’ or `hd’ (DALL-E 3 only feature).

dall-e-shell commands

C-<up> or M-pdall-e-shell-previous-inputCycle backwards through input history, saving input.
dall-e-shellStart a DALL-E shell.
dall-e-shell-insert-image-from-region-descriptionGenerate and insert an image using current region as description.
dall-e-shell-interruptInterrupt `dall-e-shell’ from any buffer.
S-<return>dall-e-shell-newlineInsert a newline, and move to left margin of the new line.
RETdall-e-shell-submitSubmit current input.
C-x C-sdall-e-shell-save-session-transcriptSave shell transcript to file.
C-c C-vdall-e-shell-swap-model-versionSwap model version from `dall-e-shell-model-versions’.
dall-e-shell-modeMajor mode for DALL-E shell.
C-<down> or M-ndall-e-shell-next-inputCycle forwards through input history.
M-rdall-e-shell-search-historySearch previous input history.
dall-e-shell-rename-bufferRename current shell buffer.

ChatGPT org babel

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?

:version

Use :version to specify “gpt-4”, “gpt-3.5-turbo”, or something else.

#+begin_src chatgpt-shell :version "gpt-4"
 Hello
#+end_src

#+RESULTS:
Hello! How can I help you today?

:system

Use :system to set the system prompt.

#+begin_src chatgpt-shell :system "always respond like a pirate"
  hello
#+end_src

#+RESULTS:
Ahoy there, me hearty! How be ye today?

:temperature

Use :temperature to set the temperature parameter.

#+begin_src chatgpt-shell :temperature 0.3
  hello
#+end_src

:context

Use :context t to include all prior context in current buffer.

#+begin_src chatgpt-shell
  tell me a random day of the week
#+end_src

#+RESULTS:
Wednesday

#+begin_src chatgpt-shell :system "always respond like a pirate"
  hello
#+end_src

#+RESULTS:
Ahoy there, me hearty! How be ye today?

#+begin_src chatgpt-shell :context t
  what was the day you told me and what greeting?
#+end_src

#+RESULTS:
The day I told you was Wednesday, and the greeting I used was "Ahoy there, me hearty! How be ye today?"

If you’d like to cherrypick which blocks are part of a given context, add :context CONTEXT-NAME to each block where CONTEXT-NAME is any string. When this form is used only source blocks with same CONTEXT-NAME will be included as opposed to every previous block when using :context t.

The example below shows how two different contexts can be interleaved.

#+begin_src chatgpt-shell :context shakespeare :system "alway speak like shakespeare"
How do you do?
#+end_src

#+RESULTS:
How dost thou fare?

#+begin_src chatgpt-shell :context robot :system "always speak like a sci fi movie robot"
How do you do?
#+end_src

#+RESULTS:
Greetings, human. I am functioning at optimal capacity. How may I assist you in your endeavors today?

#+begin_src chatgpt-shell :context shakespeare
What did you call me?
#+end_src

#+RESULTS:
Mine apologies if mine words hath caused confusion. I merely addressed thee as 'sir' or 'madam', a term of respect in the language of the Bard. Pray, how may I assist thee further?

DALL-E org babel

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]]

:version

Use :version to set the model, for example: “dall-e-3”.

:results

For DALL-E 3, use :results both to also output the revised prompt.

shell-maker

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))

Support my work

👉 Find my work useful? Support this work via GitHub Sponsors or buy my iOS apps.

My other utilities, packages, apps, writing…

Contributors

Made with contrib.rocks.

About

ChatGPT and DALL-E Emacs shells + Org babel 🦄 + a shell maker for other providers

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published