Skip to content

Instantly share code, notes, and snippets.

@lukestanley
Last active October 30, 2023 21:43
Show Gist options
  • Save lukestanley/fe3fcec25269b601539f3c2d72e59adb to your computer and use it in GitHub Desktop.
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
// ==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
})();
# 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"}
@Bioharzardx
Copy link

👏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment