ChatGPT Emacs Integration Course

Hi there! 👋 I’m Tony Aldon a passionate Emacs and AI enthusiast.

If you want to learn how to build a ChatGPT client for Emacs integrating the OpenAI API, this course is for you!

Through 18 engaging lessons, 2.5 hours video content and a detailed PDF companion you’ll learn how to build a fully functional Emacs package from scratch and you’ll know how to use the OpenAI API.

It can help if you know a little bit of Emacs Lisp, but this is not a requirement as we’ll meticulously write, review, and comment on each line of code.

In this course, we’ll build chatgpt.el, a package that lets you send prompts to ChatGPT directly from Emacs using the OpenAI API. ️ Simply call the chatgpt command, enter your prompt in the dedicated buffer, press C-c C-c, and receive your response in an appended buffer seamlessly.

Beyond its simplicity, chatgpt.el offers these key features:


1. First Request to OpenAI Using the Chat Completion API ― 6m31s

We kick things off by sending our very first request to OpenAI using the curl command. We craft a simple JSON request, send it off, and see how ChatGPT responds. This gets us familiar with the basics of the Chat Completion API.

  1. Adding funds to Your credit balance on OpenAI Developer Platform
  2. Creating an API Key on OpenAI Developer Platform
  3. First Request to OpenAI Using the Chat Completion API

2. Chat Completion Streaming API ― 2m56s

Next, we explore how to receive responses from OpenAI as a continuous stream. Instead of waiting for the full reply, we get it in real-time chunks.

  1. Curl Request Using a JSON File
  2. Chat Completion Streaming API

3. Developer and System Messages ― 4m11s

Here, we learn how to customize our interactions by tweaking developer and system messages.

4. Assistant Messages ― 3m54s

In this lesson, we dive into using assistant messages to keep the context alive across multiple turns.

  1. Independent Requests
  2. Example Conversation
  3. Continuing the Dialogue
  4. Building Context
  5. Final Response
  6. Conclusion

5. The Basics of make-process ― 12m50s

Time to write some Emacs Lisp! Here, we introduce the make-process function to run shell commands asynchronously within Emacs.

  1. Executing Commands with make-process
  2. The Process Object
  3. Executing Commands with Pipes Using make-process
  4. Process Sentinel Overview
  5. Branching on the Event Types in the Process Sentinel
  6. Printing the Process Buffer Content in the Echo Area
  7. Redirecting Process Buffer Content to Another Buffer

6. First Request to OpenAI From Emacs Lisp ― 8m29s

Building on what we’ve learned, we now send our first OpenAI request directly from Emacs Lisp.

  1. Review of The Last Lesson
  2. Renaming The Process Name and Process Buffers
  3. Killing The Process Buffers
  4. Sending our First OpenAI Request from Emacs Lisp
  5. Defining chatgpt-send Command in chatgpt.el File

7. Refactoring chatgpt-send and Introducing chatgpt-api-key ― 6m03s

In this lesson, we refactor the chatgpt-send function for better organization and introduce a dedicated variable for our OpenAI API key.

  1. Refactoring chatgpt-send with chatgpt-command
  2. Introducing chatgpt-api-key to hold OpenAI API Key
  3. Updating chatgpt-command Function Signature

8. Making the Prompt Dynamic in Requests ― 8m32s

No more static prompts! Here, we make our requests dynamic by pulling prompts from the current buffer.

  1. Writing a JSON Object to a File
  2. Writing the OpenAI Request to a File
  3. Updating chatgpt-send
  4. Entering the Prompt from a Buffer

9. Formatting Requests and Responses in Markdown ― 9m41s

In this lesson, we learn how to parse JSON responses and format them using markdown-mode within Emacs.

  1. Parsing and Returning a JSON Object with json-read
  2. Accessing Elements in a Nested Structure with map-nested-elt
  3. Inserting the Assistant Response instead of the JSON Response
  4. Formatting with markdown-mode

10. Saving Requests to Disk ― 12m08s

Here, we set up our package to save every request and response to organized directories on disk. With timestamped files, we can easily browse through past interactions.

  1. Refactoring chatgpt-send with chatgpt-request
  2. Refactoring chatgpt-send with chatgpt-callback
  3. Saving Requests
  4. Saving Responses
  5. Refactoring chatgpt-send with chatgpt-json-encode
  6. Adding Links to Request Directories

11. The Prompt Buffer ― 16m57s

We set up the *chatgpt* buffer to enter our prompts, positioning it at the bottom of the frame. By defining chatgpt-mode, we customize this buffer’s behavior and appearance, making it the perfect spot to interact with ChatGPT seamlessly within Emacs.

  1. Displaying the Prompt Buffer with chatgpt
  2. Defining chatgpt-mode
  3. Introducing chatgpt-model Variable
  4. Mode Line of the Prompt Buffer
  5. Executing chatgpt-mode Once
  6. Creating chatgpt-dir in chatgpt-mode
  7. Defining chatgpt-mode-map keymap

12. Making the Response Buffer Pop Up Upon Receipt ― 11m22s

In this lesson, we tweak our functions so that once ChatGPT replies, the *chatgpt[requests]* buffer pops up automatically.

  1. Refactoring chatgpt-send into chatgpt-send-request
  2. Deleting The Prompt Buffer window
  3. Ensuring the Response Buffer is Displayed
  4. Adding Notifications

13. Handling API Errors ― 11m10s

Sometimes things go wrong. Here, we update our package to gracefully handle API errors from OpenAI. Whether it’s a wrong model or a connection hiccup, we catch these errors, display meaningful messages, and log them for future reference.

  1. Signaling API Errors
  2. Saving API Errors
  3. Signaling and Saving Process Errors

14. Timestamp Files ― 9m21s

In this lesson, we introduce timestamp files for each request. These little helpers will help us later to sort and manage our interactions chronologically.

  1. Purpose of Timestamp Files
  2. Writing Timestamp Files
  3. Defining the chatgpt-timestamp Function
  4. Defining the chatgpt-requests Function

15. Overview of the Ring Package ― 7m16s

Here, we explore Emacs’s built-in ring package that we’ll use later to manage our prompt history efficiently. Rings are perfect for handling recent interactions, using them will allow us to cycle through prompts effortlessly.

  1. Creating Rings and Inserting Elements
  2. Accessing Ring Elements

16. Implementing Prompt History Feature ― 17m43s

Now, we put rings into action by adding a prompt history feature. With convenient shortcuts like M-p and M-n, we’ll be able to navigate through our past prompts with ease.

  1. Binding M-p and M-n in chatgpt-mode-map
  2. Defining chatgpt-history and chatgpt-push
  3. Implementing the chatgpt-previous Command
  4. Handling Empty chatgpt-history
  5. Initializing chatgpt-history from Disk
  6. Refactoring for Clean Code

17. The Waiting Widget ― 3m56s

In this lesson, we create a simple waiting widget in the mode line that flashes while we wait for ChatGPT’s response.

18. Managing the API Key ― 4m16s

Finally, we learn how to handle our OpenAI API key securely using Emacs’s ~/.authinfo and ~/.authinfo.gpg files.

  1. Redefining the API Key Variable
  2. Modifying the chatgpt-command Function
  3. Adding the API Key to ~/.authinfo File
  4. Restarting Emacs for Changes to Take Effect
  5. Testing the Setup