Skip to content

Org babel extension for Chat Assistant APIs such as ChatGPT

License

Notifications You must be signed in to change notification settings

tyler-dodge/org-assistant

Repository files navigation

org-assistant.el - License MELPA Version

Org babel extension for Chat Assistant APIs


org-assistant provides support for accessing chat APIs such as ChatGPT in the context of an org notebook.

example

Installation

Org-assistant is available on MELPA

M-x package-install [RET] org-assistant [RET]

Usage

It provides a function named org-assistant that serves as entrypoint for displaying an org assistant buffer. Also, it can be used in any org file by using a src block like #+BEGIN_SRC assistant or #+BEGIN_SRC ?.

The API Key is looked up via org-assistant-auth-function, which has meen tested using the MacOS Keychain. Alternatively, org-assistant-auth-function can be a string and directly set to your API key.

(setq org-assistant-auth-function "<YOUR_API_KEY>")

Calling org-assistant interactively will generate an org-assistant buffer for you. It can be set to a keybinding for quick use like below:

(global-set-key (kbd "C-x C-o") #'org-assistant)

Conversation Evaluation Rules

  • The org tree is traversed up in order to generate the message list when sending information to the chat endpoint.
  • It will only use messages from the branch of the tree that the block that initiated the request is in.
  • It does not include example blocks or source blocks that appear later in the org buffer than the initiating block.
  • noweb support is enabled for all blocks in the conversation based on the initiating block having the :noweb flag set.
  • Example blocks are treated as being responses from the assistant by default if they occur after user messages.
  • If the example block is before any user source block, they are treated as system messages to the assistant instead.

See org-babel-execute:assistant for more details.

Example

* Chat User Question
#+BEGIN_SRC ?
Hi
#+END_SRC

AI Response
#+BEGIN_SRC assistant :sender assistant
Hello! How can I assist you today?
#+END_SRC

When the output is set to png file, the image generation APIs are called instead.

* Image Generation User Question
#+BEGIN_SRC ? :file sphere.png
Generate a sphere
#+END_SRC

AI Response
#+RESULTS:
file:sphere.png

You can introspect the sent conversation using the :echo flag.

* Branching Echo
#+BEGIN_SRC ?
This is the user.  Repeat verbatim only: "This is the system"
#+END_SRC

#+RESULTS:
#+BEGIN_SRC assistant :sender assistant
"This is the system"
#+END_SRC

** Branch A
#+BEGIN_SRC ? :echo
Response A
#+END_SRC

#+RESULTS:
#+BEGIN_SRC assistant :sender assistant
(user . "This is the user.  Repeat verbatim only: \"This is the system\"")
(assistant . "\"This is the system\"")
(user . "Response A")
#+END_SRC

** Branch B
#+BEGIN_SRC ? :echo
Response B
#+END_SRC

#+RESULTS:
#+BEGIN_SRC assistant :sender assistant
(user . "This is the user.  Repeat verbatim only: \"This is the system\"")
(assistant . "\"This is the system\"")
(user . "Response B")
#+END_SRC

Comparison With Other AI Packages

  • org-ai.el is focused more on runtime interaction with AI
  • org-assistant.el is focused more on reproducible sessions via org babel
  • org-assistant.el supports branching conversations
  • org-assistant.el is not meant to be used downstream as a library for AI endpoint interactions.
  • In org-assistant.el, all interaction is async using org-babel, which allows for notebook style prompt development
  • In org-ai.el, interaction is synchronous and inline, which is better for in-editor use cases
  • org-ai.el supports a lot of other AI use cases like text to speech

Feel free to add a pull request detailing the differences if there is a package I missed

Commands

org-assistant-setup

Set up optional libraries like ‘markdown-mode’ to work with ‘org-assistant’.

If ‘markdown-mode’ is available, it will be used.

org-assistant

Prompt the user for an initial prompt for the assistant.

Then display a window with the buffer containing the response.

org-assistant--execute-curl-shell-command-request

Execute a curl shell command for ‘org-assistant’. URL is the endpoint called from ‘org-assistant’. METHOD is the Http method used in the request. REQUEST-ID is the request id, used for debugging purposes. BUFFER is the buffer that the process should output to HEADERS are the headers to send in the request BODY is a JSON object encoded as a string.

(fn &key URL METHOD REQUEST-ID BUFFER HEADERS BODY)

org-babel-execute:assistant

Execute an ‘org-assistant’ in an org-babel context.

PARAMS is used to enable noweb mode. If :echo is set, return the conversation that would be sent to the endpoint instead of evaluating.

If :list-models is set, the ‘org-assistant-models-endpoint’ will be called instead.

:params can be set to a list like ’((max_tokens . 1) (stop . "stop")).

See https://platform.openai.com/docs/api-reference/chat/create for parameters.

TEXT must be empty if :list-models is set.

This is intended to be called via org babel in a src block with Ctrl-C Ctrl-C like:

#+BEGIN_SRC assistant
Hi
#+END_SRC

The response from the assistant will be in the example block following:

#+BEGIN_SRC assistant :sender assistant
Response
#+END_SRC

All of the messages that are in the same branch of the org tree are included in the request to the assistant.

* Question
#+BEGIN_SRC assistant
Hi
#+END_SRC

#+BEGIN_SRC assistant :sender assistant
Response
#+END_SRC

#+BEGIN_SRC assistant
What’s up?
#+END_SRC

Running babel on the second assistant block will send the conversation:

User: Hi
Assistant: Response
User: What’s up?

Running babel on the first assistant block will only include the messages before it:

User: Hi

Only messages in the same branch will be included:

* Question
#+BEGIN_SRC assistant
Hi
#+END_SRC

#+BEGIN_SRC assistant :sender assistant
Response
#+END_SRC
** Branch A
#+BEGIN_SRC assistant
Branch A
#+END_SRC

#+BEGIN_SRC assistant :sender assistant
Branch A Response
#+END_SRC

** Branch B
#+BEGIN_SRC assistant
Branch B
#+END_SRC

#+BEGIN_SRC assistant :sender assistant
Branch B Response
#+END_SRC

If you ran Ctrl-C Ctrl-C on Branch B’s src block the conversation sent to the endpoint would be:

User: Hi
Assistant: Response
User: Branch B
Assistant: Branch B Response

‘org-assistant’ also supports image generation. If the :file attribute is set, the image API will be used.

The following is an example of using the image endpoint:

#+BEGIN_SRC assistant :file output.png
An image of the GNU mascot
#+END_SRC

org-babel-execute:?

See ‘org-babel-execute:assistant’.

ARGS is routed as is.

org-assistant-explain-function

Ask the assistant to explain the function at point.

org-assistant-write-docstring

Ask the assistant to generate a docstring for the function at point.

Customization

Known keys are: temperature top_p n stream stop max-tokens presence-penalty frequency-penalty logit-bias user Should be a alist like '((max_tokens . 10) (user . "emacs")).

This can be overriden on a per-src block basis by specifying the :params argument.

See https://platform.openai.com/docs/api-reference/chat/create for reference.

#+BEGIN_SRC assistant :params '((max_tokens . 10) (user . "emacs"))
Hi
#+END_SRC

Known allowed keys are: size user Should be a alist like '((size . "1024x1024") (user . "emacs")).

This can be overriden on a per-src block basis by specifying the :params argument.

See https://platform.openai.com/docs/api-reference/chat/create for reference.

#+BEGIN_SRC assistant :params '((max_tokens . 10) (user . "emacs"))
Hi
#+END_SRC

Contributing

Contributions welcome, but forking preferred. I plan to actively maintain this, but I will be prioritizing features that impact me first.

I'll look at most pull requests eventually, but there is no SLA on those being accepted.

Also, I will only respond to pull requests on a case by case basis. I have no obligation to comment on, justify not accepting, or accept any given pull request. Feel free to start a fork that has more support in that area.

If there's a great pull request that I'm slow on accepting, feel free to fork and rename the project.