CONTRIBUTING.md (1645, 2023-05-03)
chatgpt-down-messages.txt (9303, 2023-05-03)
client-side-js (0, 2023-05-03)
client-side-js\[Not used anymore] 113-23682f80a24dd00d.js (96679, 2023-05-03)
client-side-js\[Not used anymore] 264-13e92c51b0315184.js (17604, 2023-05-03)
fonts.txt (505, 2023-05-03)
images (0, 2023-05-03)
images\Getting-Conversation-ID.png (190939, 2023-05-03)
images\Markdown-in-code-block-rendered.gif (720444, 2023-05-03)
images\chatgpt-plus-login-link.gif (532003, 2023-05-03)
images\markdown.png (116318, 2023-05-03)
images\regenerated-response-feedback.png (7284, 2023-05-03)
markdown-support.csv (1355, 2023-05-03)
markdown-tester.txt (3985, 2023-05-03)
sample (0, 2023-05-03)
sample\chat.html (2407, 2023-05-03)
sample\conversations.json (1598, 2023-05-03)
sample\model_comparisons.json (2731, 2023-05-03)
# Everything ChatGPT
A project by [@tercmd (on Twitter)](https://twitter.com/tercmd)
![Stars for the Everything ChatGPT repo](https://img.shields.io/github/stars/terminalcommandnewsletter/everything-chatgpt?style=for-the-badge&logo=github)
Explore what happens under the hood with the ChatGPT web app. And some speculation, of course. [Contribute if you have something interesting related to ChatGPT.](./CONTRIBUTING.md)
## Table of Contents
- [Fonts (fonts.txt)](#fonts-fontstxt)
- [Application](#application)
- [Data](#data)
- [Session data](#session-data)
- [User data](#user-data)
- [User data (using ~~chat.json~~ [chatId].json)](#user-data-using-chatjson-chatidjson)
- [Model data](#model-data)
- [Disabling/Enabling "Chat History & Training"](#disablingenabling-chat-history--training)
- [Data Export](#data-export)
- [Conversation](#conversation)
- [Conversation History](#conversation-history)
- [Getting the Conversation ID](#getting-the-conversation-id)
- [Loading a Past Conversation](#loading-a-past-conversation)
- [The process of asking ChatGPT a question](#the-process-of-asking-chatgpt-a-question)
- [(Soft)Deleting a conversation](#softdeleting-a-conversation)
- [Can you revive a conversation?](#can-you-revive-a-conversation)
- [Clearing Conversations](#clearing-conversations)
- [Leaving Feedback on Messages (Thumbs Up/Thumbs Down)](#leaving-feedback-on-messages-thumbs-upthumbs-down)
- [Leaving Feedback (on Regenerated Responses)](#leaving-feedback-on-regenerated-responses)
- [Renaming Conversations](#renaming-conversations)
- [Errors](#errors)
- ["_Something went wrong, please try reloading the conversation._"](#something-went-wrong-please-try-reloading-the-conversation)
- ["_The message you submitted was too long, please reload the conversation and submit something shorter._"](#the-message-you-submitted-was-too-long-please-reload-the-conversation-and-submit-something-shorter)
- ["_Conversation not found_"](#conversation-not-found)
- [Markdown rendering](#markdown-rendering)
- [ChatGPT Plus](#chatgpt-plus)
- [GPT-4 for Free Users? (nope)](#gpt-4-for-free-users-nope)
- [Access ChatGPT when it's down](#access-chatgpt-when-its-down)
- [Rendering Markdown _inside_ a code block](#rendering-markdown-inside-a-code-block)
- [Minified client-side JS](#minified-client-side-js)
- [Statsig Feature Gates](#statsig-feature-gates)
## Fonts _([fonts.txt](./fonts.txt))_
> **Warning**
> **All fonts in the previous list are no longer accessible at the `https://chat.openai.com/fonts/[font]` endpoint. The new fonts.txt file assumes the prefix of the URLs to be `https://cdn.openai.com/common/fonts/`**
**This is a _non exhaustive_ list of fonts that come from cdn.openai.com:**
- [soehne-buch.woff2](https://cdn.openai.com/common/fonts/soehne/soehne-buch.woff2)
- [soehne-halbfett.woff2](https://cdn.openai.com/common/fonts/soehne/soehne-halbfett.woff2)
- [soehne-mono-buch.woff2](https://cdn.openai.com/common/fonts/soehne/soehne-mono-buch.woff2)
- [soehne-mono-halbfett.woff2](https://cdn.openai.com/common/fonts/soehne/soehne-mono-halbfett.woff2)
- [KaTeX_Main-Regular.woff2](https://cdn.openai.com/common/fonts/katex/KaTeX_Main-Regular.woff2) (+ Main-Bold, Main-Italic, Main-BoldItalic)
- [KaTeX_Math-Italic.woff2](https://cdn.openai.com/common/fonts/katex/KaTeX_Math-Italic.woff2) (+ Math-BoldItalic)
- [KaTeX_Size2-Regular.woff2](https://cdn.openai.com/common/fonts/katex/KaTeX_Size2-Regular.woff2) (+ Size1, Size3, Size4)
- [KaTeX_Caligraphic-Regular.woff2](https://cdn.openai.com/common/fonts/katex/KaTeX_Caligraphic-Regular.woff2) (+ Caligraphic-Bold)
**Earlier list of fonts that are no longer accessible:**
- ~~[Signifier-Regular.otf](https://chat.openai.com/fonts/Signifier-Regular.otf)~~
- ~~[Sohne-Buch.otf](https://chat.openai.com/fonts/Sohne-Buch.otf)~~
- ~~[Sohne-Halbfett.otf](https://chat.openai.com/fonts/Sohne-Halbfett.otf)~~
- ~~[SohneMono-Buch.otf](https://chat.openai.com/fonts/SohneMono-Buch.otf)~~
- ~~[SohneMono-Halbfett.otf](https://chat.openai.com/fonts/SohneMono-Halbfett.otf)~~
- ~~[KaTeX_Caligraphic-Bold.woff](https://chat.openai.com/fonts/KaTeX_Caligraphic-Bold.woff) (_Caligraphic-Regular_ for Regular font)~~
- ~~[KaTeX_Fraktur-Bold.woff](https://chat.openai.com/fonts/KaTeX_Fraktur-Bold.woff) (_Fraktur-Regular_ for Regular font)~~
- ~~[KaTeX_Main-Bold.woff](https://chat.openai.com/fonts/KaTeX_Main-Bold.woff) (_BoldItalic_, _Italic_, _Regular_ for font weights you can probably guess)~~
- ~~[KaTeX_Math-Bold.woff](https://chat.openai.com/fonts/KaTeX_Math-Bold.woff) (_BoldItalic_, _Italic_, _Regular_ for font weights you can probably guess)~~
- ~~[KaTeX_SansSerif-Bold.woff](https://chat.openai.com/fonts/KaTeX_SansSerif-Bold.woff) (_Italic_, _Regular_ for font weights you can probably guess)~~
- ~~[KaTeX_Script-Regular.woff](https://chat.openai.com/fonts/KaTeX_Script-Regular.woff)~~
- ~~[KaTeX_Size1-Regular.woff](https://chat.openai.com/fonts/KaTeX_Size1-Regular.woff) (_Size1_, _Size2_, _Size3_, _Size4_)~~
- ~~[KaTeX_Typewriter-Regular.woff](https://chat.openai.com/fonts/KaTeX_Typewriter-Regular.woff)~~
## Application
ChatGPT is a NextJS application. Server information cannot be clearly found as the entirety of chat.openai.com is routed through Cloudflare. Sentry Analytics are requested ~~for the Thumbs Up/Thumbs Down feedback the user selects for a message~~ periodically. Statsig is attempted to be loaded but CORS blocks it due to the Same Origin Policy **(actually an effect of uBlock Origin)**.
## Data
### Session data
A request can be made to `/api/auth/session` (literally, **in your browser**, however cannot work in an iframe or fetch because it doesn't have a `Access-Control-Allow-Origin` set up) to access data like the following:
```
user
|__ id: user-[redacted]
|__ name: [redacted]@[redacted].com (probably can be a user's name)
|__ email: [redacted]@[redacted].com
|__ image: https://s.gravatar.com/avatar/8cf[redacted in case of possible unique identifier]2c7?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2F[first 2 letters of name].png
|__ picture: https://s.gravatar.com/avatar/8cf[redacted in case of possible unique identifier]2c7?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2F[first 2 letters of name].png
|__ groups: []
expires: [date in the future]
accessToken: ey[redacted] (base*** "{")
```
### User data
This requires an access token (which seems to be the ~~Authorization cookie, along with other factors~~ Authorization header), so this cannot be accessed using your browser directly, but here's what we have when we make a request to `/backend-api/accounts/check`:
```
account_plan
|__ is_paid_subscription_active: false
|__ subscription_plan: chatgptfreeplan
|__ account_user_role: account-owner
|__ was_paid_customer: false
|__ has_customer_object: false
user_country: [redacted two letter country code]
features: ["system_message"]
```
(Note: false in the above does not include quotes, whereas other values are in quotes, removed in the above _schema?_)
### User data (using ~~chat.json~~ [chatId].json)
When we make a request to `/_next/data/[build ID]/c/[conversation ID].json?chatId=[conversation ID]` (can be done in the browser, cannot be done without authentication), we get a response like this:
```
pageProps:
|__ user (Object):
|____ id: user-[redacted]
|____ name: [redacted]@[redacted].com
|____ email: [redacted]@[redacted].com
|____ image: https://s.gravatar.com/avatar/8c[redacted in case of possible unique identifier]c7?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2F[first two letters of email address].png
|____ picture: https://s.gravatar.com/avatar/8c[redacted in case of possible unique identifier]c7?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2F[first two letters of email address].png
|____ groups: []
|__ serviceStatus: {}
|__ userCountry: [redacted two letter country code]
|__ geoOk: false
|__ isUserInCanPayGroup: true
|__ __N_SSP: true
```
This is the some of the same data (excluding accessToken and expires, both relevant to an access token) you get using the method in [Session data](#session-data) except you also get info about the country the user is located in and whether ChatGPT Plus is available in their location.
**EDIT:** When ChatGPT returns a message like "_We're experiencing exceptionally high demand. Please hang tight as we work on scaling our systems._", `serviceStatus` looks like this:
```
type: warning
message: We're experiencing exceptionally high demand. Please hang tight as we work on scaling our systems.
oof: true
```
I didn't make up the `oof` variable, that is actually part of the response
### Model data
What model does ChatGPT use? Well, just query `/backend-api/models`!
```
models
|__
|____ slug: text-davinci-002-render-sha
|____ max_tokens: 4097
|____ title: Turbo (Default for free users)
|____ description: The standard ChatGPT model
|____ tags: []
|____ qualitative_properties: {}
```
This means that ChatGPT can _remember context (based on what I can understand)_ for 16388 characters or 3072.75 words (or 2048.5 s).
_* Approximation according to [OpenAI help article](https://help.openai.com/en/articles/4936856-what-are-tokens-and-how-to-count-them)_
### Disabling/Enabling "Chat History & Training"
When you click your name/email address in the bottom-left corner of the screen (on desktop) > Settings > Show (next to Data Controls) > toggle next to Chat History and Training, the following happens:
First, [the list of conversations is requested](#conversation-history).
Then we make a request to the same path as [Model data](#model-data), except a query parameter is added to the URL `?history_and_training_disabled=true` or `?history_and_training_disabled=false` depending on whether the setting is disabled or enabled respectively.
Then, we request `/_next/data/[build ID]/index.json` (with the same data as [[chatId].json](#user-data-using-chatjson-chatidjson)).
### Data Export
When you use the "Export data" feature to export your data, a POST request is made to `/backend-api/accounts/data_export` with no request body and the response of `status: "queued"`.
As the name suggests, a data export is sent by email.
The data export is a `.zip` file containing `user.json`, `conversations.json`, `message_feedback.json`, `model_comparisons.json`, `chat.html`.
The data in `user.json` looks like this:
```json
{"id": "user-[redacted]", "email": "[redacted]@[redacted].com", "chatgpt_plus_user": false, "phone_number": "+[redacted]"}
```
Sample data for `model_comparisons.json` is in [sample/model_comparisons.json](./sample/model_comparisons.json)
Sample data for `message_feedback.json`:
```json
[{"message_id": "[redacted]", "conversation_id": "[conversationidwithoutdashes]", "user_id": "user-[redacted]", "rating": "thumbsUp", "content": "{\"text\": \"This is a test.\"}"}]
```
Sample data for `conversations.json` is in [sample/conversations.json](./sample/conversations.json)
`chat.html` is a page that dynamically (using client-side JS) displays entire chat history for every conversation saved using conversation data (stored in the file) similar to that from `conversations.json`. You can find a sample in [sample/chat.html](./sample/chat.html)
## Conversation
### Conversation History
Conversation history can be accessed (again, requires an access token, which seems to be the Authorization header) at `/backend-api/conversations?offset=0&limit=20` (the web interface limits it to 20 chats) which returns something like this:
```
items: []
limit: 20
offset: 0
total: 0
```
It doesn't work because ChatGPT is having some issues at the time of writing:
> "_Not seeing what you expected here? Don't worry, your conversation data is preserved! Check back soon._"
But this is probably what a person new to ChatGPT sees.
**EDIT: If you log out and log back in, history works just fine. So, here's what I see**
```
items (array)
|__ (each conversation is an object)
|____ id: [redacted conversation ID]
|____ title: [conversation title]
|____ create_time: 2023-03-09THH:MM:SS.MILLIS
|__...
total: [number of conversations] (can be greater than 20)
limit: 20
offset: 0 (can be set to a higher number and it returns the conversations after that index, starting from 0)
```
**After 20 conversations listed, the ChatGPT UI shows a `Show more` button which sends a request with `offset=20`**
### Getting the Conversation ID
Speaking of ChatGPT conversation history not being available, we can get the Conversation ID pretty easily (to someone who is familiar with DevTools, that is)
Why? Because ChatGPT forces you into a ~~/chat~~ `/` path for a new conversation, creates a conversation, **BUT DOESN'T CHANGE THE URL**. This is also helpful when chat history isn't available.
1. We get the Conversation ID using DevTools (this requires a message to be sent)
![A ChatGPT window with Firefox DevTools open. In the list of requests, a request with the conversation ID can be seen. In addition, a request to a moderations endpoint has a response containing the conversation ID, along with the user's entered text 'How can I say "MOOOOOOOOOOOOOOOOOOO" as a cow in the terminal?'](./images/Getting-Conversation-ID.png)
2. Then, we visit ~~`https://chat.openai.com/chat/
`~~ `https://chat.openai.com/c/`.
### Loading a Past Conversation
When the user clicks on a past conversation, a request is made (requiring an access token, ~~likely the cookie with other factors to ensure genuine requests~~ an Authorization header) to `/backend-api/conversation/` with a response like this:
```
title:
create_time: EPOCHEPOCH.MILLIS
mapping (Object)
|__ (Array):
|____ id:
|____ message (Object):
|______ id:
|______ author (Object):
|________ role: system (First message) | user | assistant
|________ metadata: (Empty object)
|______ create_time: EPOCHEPOCH.MILLIS
|______ content (Object):
|________ content_type: text
|________ parts: [""]
|______ end_turn: true (system) | false
|______ weight: 1.0
|______ metadata: {}
|______ recipient: all
|____ parent:
|____ children (Array):
```
### The process of asking ChatGPT a question
Let's say I ask ChatGPT a question `"What is ChatGPT?"`. First, we make a POST request to `/backend-api/conversation` with a request body like this (no response):
```
action: next
messages (Array):
|__ (Object):
|____ author (Object):
|______ role: user
|____ content (Object):
|______ content_type: text
|______ parts (Array):
|________ What is ChatGPT?
|__ id: 0c[redacted]91
|__ role: user
model: text-davinci-002-render-sha
parent_message_id: a0[redacted]7f
```
Then [we get a list of past conversations](#conversation-history) that includes one "New chat".
Then we make a request to `/backend-api/moderations` with a request body like this:
```
conversation_id: 05[redacted]2d
input: What is ChatGPT?
message_id: 0c[redacted]91
model: text-moderation-playground
```
That returns a response like this:
```
flagged: false
blocked: false
moderation_id modr-6t[redacted]Bk
```
Then we make a request to `/backend-api/conversation/gen_title/` with the request body like this:
```
message_id: c8[redacted]0e
model: text-davinci-002-render-sha
```
That gets a response like this:
```
title:
```
Then we make **another** request to `/backend-api/moderations` with a request body that includes the AI response (marked as ``) looking like this:
```
input: \nWhat is ChatGPT?\n\n
model: text-moderation-playground
conversation_id: 05[redacted]2d
message_id: c8[redacted]0e
```
That gets a response in the exact same format as the previous request made to this path.
Then [we **finally** get a list of past conversations](#conversation-history) including the proper title of the chat that appears on the sidebar.
### (Soft)Deleting a conversation
When you click Delete on a conversation, a PATCH request is made to `/backend-api/conversation/05[redacted]2d` with the body `is_visible: false` and gets a response of `success: true` back. This implies that a conversation is being soft-deleted, not deleted on their systems.
Then (not sure why), we request `/_next/data/[build ID]/index.json` (with the same data as [[chatId].json](#user-data-using-chatjson-chatidjson)).
After that, we [get the list of conversations that appear on the sidebar](#conversation-history).
### Can you revive a conversation?
I had a question after the above section - can you revive a conversation by setting the request body to `is_visible: true`? The answer is **nope**, you can't. This just returns a 404 with the response `detail: Can't load conversation 94[redacted]9b`. But if you don't [get the list of conversations again](#conversation-history), you can still access the conversations. Although, trying to get a response from ChatGPT, you get a [Conversation not found](#conversation-not-found) error.
### Clearing Conversations
I was a bit unsure if I should do this. But I looked through and did it anyway. (The below is almost a one-to-one copy of [(Soft)Deleting a conversation](#softdeleting-a-conversation), with minor changes)
When you click Delete on a conversation, a PATCH request is made to `/backend-api/conversations` (conversation**s** rather than conversatio**n/05[redacted]2d**) with the body `is_visible: false` and gets a response of `success: true` back. This implies that conversations are being soft-deleted, not deleted on their systems.
Then (not sure why), we request `/_next/data/[build ID]/index.json` (with the same data as [[chatId].json](#user-data-using-chatjson-chatidjson)).~~
After that, we [get the list of conversations that appear on the sidebar](#conversation-history).
**Something funny:** If ChatGPT history is temporarily unavailable (returning an empty response), the app shows a message. But if your ChatGPT conversation history is blank anyway, you just see a message that history is temporarily unavailable.
### Leaving Feedback on Messages (Thumbs Up/Thumbs Down)
When you click the thumbs up/thumbs down button on a message, a POST request is made to `/backend-api/conversation/message_feedback` with the request body like this:
```
conversation_id: 94[redacted]9b
message_id: 96[redacted]b7
rating: thumbsUp | thumbsDown
```
That receives a response like this:
```
message_id: 96[redacted]b7
conversation_id: 94[redacted]9b
user_id: user-[redacted]
rating: thumbsUp | thumbsDown
content: {}
```
Then, when you type feedback and click submit, a request is made to the same path with a request body like this:
```
conversation_id: 94[redacted]9b
message_id: 96[redacted]b7
rating: thumbsUp
tags: [] (for thumbsDown, an array containing any or all of these: harmful, false, not-helpful)
text:
```
With a response similar to the one above, with only the `content` field different:
```
message_id: 96[redacted]b7
conversation_id: 94[redacted]9b
user_id: user-[redacted]
rating: thumbsUp
content: '{"text": ""}' |'{"text": "This is solely for testing purposes. You can safely ignore this feedback.", "tags": ["harmful", "false", "not-helpful"]}' (This is for a thumbsDown review)
```
### Leaving Feedback (on Regenerated Responses)
When you regenerate a response, you get a feedback box like this:
![Feedback box with the text "Was this response better or worse?" abd three buttons "Better", "Worse" and "Same"](./images/regenerated-response-feedback.png)
The req ... ...