Last active
October 30, 2023 21:43
-
-
Save lukestanley/fe3fcec25269b601539f3c2d72e59adb to your computer and use it in GitHub Desktop.
Browser Userscript Javascript to Stream ChatGPT messages to local server in real time
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name ChatGPT Message Sync | |
// @version 0.1 | |
// @description Sync ChatGPT messages to own server. | |
// @include https://chat.openai.com/c/* | |
// @grant GM_xmlhttpRequest | |
// ==/UserScript== | |
(function() { | |
function extractText(element) { | |
let textArray = Array.from(element.childNodes).map(node => { | |
if (node.nodeName === 'BUTTON') { | |
return ''; // Ignore button elements | |
} | |
if (node.nodeName === "#text") { | |
// No longer checking next sibling | |
return node.textContent.trim(); | |
} | |
if (node.nodeName === "SPAN" && node.parentElement.parentElement.parentElement.nodeName.toUpperCase().trim() === "PRE" ) { | |
return ''; | |
} | |
if (node.nodeName === "CODE") { | |
let lang = node.className.split('-').pop(); | |
if (lang) { // Block-level code with language specified | |
return `\`\`\`${lang}\n${node.textContent.trim()}\n\`\`\``; | |
} else { // Most likely inline code | |
return `\`${node.textContent.trim()}\``; | |
} | |
} | |
return extractText(node); | |
}); | |
return textArray.join('\n'); | |
} | |
let lastMessageString = ''; | |
function fetchMessages() { | |
const messageDivs = document.querySelectorAll('[data-testid^="conversation-turn-"]'); | |
const messages = []; | |
messageDivs.forEach((div) => { | |
const isUserMessage = div.querySelector("img") ? true : false; | |
const messageTextSection = div.querySelector(".break-words"); | |
const messageText = extractText(messageTextSection); | |
messages.push({ | |
isUser: isUserMessage, | |
text: messageText | |
}); | |
}); | |
const conversationId = window.location.pathname.split('/c/')[1]; | |
const messageString = messages.map((message) => { | |
return `${message.isUser ? 'Human' : 'Assistant'}: ${message.text}`; | |
}).join('\n'); | |
const payload = JSON.stringify({ | |
conversationId, | |
messages, | |
messageString | |
}); | |
if (lastMessageString == messageString){ | |
return; | |
} | |
lastMessageString = messageString; | |
GM_xmlhttpRequest({ | |
method: "POST", | |
url: "http://localhost:8000/chats", | |
data: payload, | |
headers: { | |
"Content-Type": "application/json" | |
} | |
}); | |
} | |
setInterval(fetchMessages, 3000); // Fetch messages every 3 seconds | |
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# To run: | |
# uvicorn chatgpt_sync_fastapi:app --reload | |
from fastapi import FastAPI, Request | |
from pydantic import BaseModel | |
import json | |
import os | |
# Create FastAPI instance | |
app = FastAPI() | |
# Create folder 'chats' if it doesn't exist | |
if not os.path.exists('chats'): | |
os.makedirs('chats') | |
# Define data model | |
class ChatData(BaseModel): | |
conversationId: str | |
messages: list | |
messageString: str | |
@app.post("/chats/") | |
async def read_root(chat_data: ChatData): | |
conversation_id = chat_data.conversationId | |
messages = chat_data.messages | |
message_string = chat_data.messageString | |
print(message_string) | |
# Save as JSON | |
with open(f'chats/{conversation_id}.json', 'w') as f: | |
json.dump(messages, f,indent=4) | |
# Save as .txt in "Human: ... Assistant: ..." format | |
with open(f'chats/{conversation_id}.txt', 'w') as f: | |
f.write(message_string) | |
return {"status": "success"} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
👏