From 69b3edc52c104bef2ad8d1fbecda195bf22ed2ca Mon Sep 17 00:00:00 2001 From: Daniel Avila Date: Wed, 8 Mar 2023 19:47:23 -0500 Subject: [PATCH] feat: sydney is functional --- api/app/bingai.js | 2 +- api/app/chatgpt-browser.js | 3 +- api/app/index.js | 2 + api/app/sydney.js | 34 ++++++++ api/models/Conversation.js | 3 + api/package-lock.json | 14 ++-- api/package.json | 2 +- api/server/routes/ask.js | 3 +- api/server/routes/askBing.js | 6 +- api/server/routes/askSydney.js | 77 +++++++++++++++++++ .../components/Conversations/Conversation.jsx | 4 +- client/src/components/Conversations/index.jsx | 1 + client/src/components/Main/TextChat.jsx | 11 ++- client/src/store/convoSlice.js | 1 + client/src/store/modelSlice.js | 16 ++-- 15 files changed, 157 insertions(+), 22 deletions(-) create mode 100644 api/app/sydney.js create mode 100644 api/server/routes/askSydney.js diff --git a/api/app/bingai.js b/api/app/bingai.js index e33278b9a2..dff3958294 100644 --- a/api/app/bingai.js +++ b/api/app/bingai.js @@ -10,7 +10,7 @@ const askBing = async ({ text, progressCallback, convo }) => { // If the above doesn't work, provide all your cookies as a string instead // cookies: '', debug: false, - store: new KeyvFile({ filename: './data/cache.json' }) + cache: new KeyvFile({ filename: './data/cache.json' }) }); let options = { diff --git a/api/app/chatgpt-browser.js b/api/app/chatgpt-browser.js index c6debc0d91..442d2a731d 100644 --- a/api/app/chatgpt-browser.js +++ b/api/app/chatgpt-browser.js @@ -5,7 +5,8 @@ const clientOptions = { // Warning: This will expose your access token to a third party. Consider the risks before using this. reverseProxyUrl: 'https://chatgpt.duti.tech/api/conversation', // Access token from https://chat.openai.com/api/auth/session - accessToken: process.env.CHATGPT_TOKEN + accessToken: process.env.CHATGPT_TOKEN, + // debug: true }; const browserClient = async ({ text, progressCallback, convo }) => { diff --git a/api/app/index.js b/api/app/index.js index 53d4d594b9..a1d0088d9b 100644 --- a/api/app/index.js +++ b/api/app/index.js @@ -2,6 +2,7 @@ const { askClient } = require('./chatgpt-client'); const { browserClient } = require('./chatgpt-browser'); const customClient = require('./chatgpt-custom'); const { askBing } = require('./bingai'); +const { askSydney } = require('./sydney'); const titleConvo = require('./titleConvo'); const detectCode = require('./detectCode'); @@ -10,6 +11,7 @@ module.exports = { browserClient, customClient, askBing, + askSydney, titleConvo, detectCode }; \ No newline at end of file diff --git a/api/app/sydney.js b/api/app/sydney.js new file mode 100644 index 0000000000..a599128640 --- /dev/null +++ b/api/app/sydney.js @@ -0,0 +1,34 @@ +require('dotenv').config(); +const { KeyvFile } = require('keyv-file'); + +const askSydney = async ({ text, progressCallback, convo }) => { + const { BingAIClient } = (await import('@waylaidwanderer/chatgpt-api')); + + const sydneyClient = new BingAIClient({ + // "_U" cookie from bing.com + userToken: process.env.BING_TOKEN, + // If the above doesn't work, provide all your cookies as a string instead + // cookies: '', + debug: false, + cache: new KeyvFile({ filename: './data/cache.json' }) + }); + + let options = { + jailbreakConversationId: true, + onProgress: async (partialRes) => await progressCallback(partialRes), + }; + + if (convo) { + options = { ...options, ...convo }; + } + + const res = await sydneyClient.sendMessage(text, options + ); + + return res; + + // for reference: + // https://github.com/waylaidwanderer/node-chatgpt-api/blob/main/demos/use-bing-client.js +}; + +module.exports = { askSydney }; diff --git a/api/models/Conversation.js b/api/models/Conversation.js index dfe4761a32..97cb8eaad1 100644 --- a/api/models/Conversation.js +++ b/api/models/Conversation.js @@ -15,6 +15,9 @@ const convoSchema = mongoose.Schema({ type: String, default: 'New conversation' }, + jailbreakConversationId: { + type: String + }, conversationSignature: { type: String }, diff --git a/api/package-lock.json b/api/package-lock.json index 9a247820c1..ebad132167 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@keyv/mongo": "^2.1.8", "@vscode/vscode-languagedetection": "^1.0.22", - "@waylaidwanderer/chatgpt-api": "^1.15.1", + "@waylaidwanderer/chatgpt-api": "^1.28.0", "cors": "^2.8.5", "dotenv": "^16.0.3", "express": "^4.18.2", @@ -1492,9 +1492,9 @@ } }, "node_modules/@waylaidwanderer/chatgpt-api": { - "version": "1.26.1", - "resolved": "https://registry.npmjs.org/@waylaidwanderer/chatgpt-api/-/chatgpt-api-1.26.1.tgz", - "integrity": "sha512-cv9NqC0owO2EGCkVg4VQO0lcA5pDgv2VJrBE/0P6En27/v0gIC+7MedowX3htIUi4GLDkgyyDDDimst2i8ReMw==", + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@waylaidwanderer/chatgpt-api/-/chatgpt-api-1.28.0.tgz", + "integrity": "sha512-753dc/Eaf+1XmSXrLu+99LR4N+ACL7fQyA7GlsUXjRVXcH+m/iDqqXrU+o1JKGy84VlNKokAvq3oy9LVunKCIw==", "dependencies": { "@dqbd/tiktoken": "^0.4.0", "@fastify/cors": "^8.2.0", @@ -5781,9 +5781,9 @@ "integrity": "sha512-rQ/BgMyLuIXSmbA0MSkIPHtcOw14QkeDbAq19sjvaS9LTRr905yij0S8lsyqN5JgOsbtIx7pAcyOxFMzPmqhZQ==" }, "@waylaidwanderer/chatgpt-api": { - "version": "1.26.1", - "resolved": "https://registry.npmjs.org/@waylaidwanderer/chatgpt-api/-/chatgpt-api-1.26.1.tgz", - "integrity": "sha512-cv9NqC0owO2EGCkVg4VQO0lcA5pDgv2VJrBE/0P6En27/v0gIC+7MedowX3htIUi4GLDkgyyDDDimst2i8ReMw==", + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@waylaidwanderer/chatgpt-api/-/chatgpt-api-1.28.0.tgz", + "integrity": "sha512-753dc/Eaf+1XmSXrLu+99LR4N+ACL7fQyA7GlsUXjRVXcH+m/iDqqXrU+o1JKGy84VlNKokAvq3oy9LVunKCIw==", "requires": { "@dqbd/tiktoken": "^0.4.0", "@fastify/cors": "^8.2.0", diff --git a/api/package.json b/api/package.json index 6e38f1f117..74c420c8e5 100644 --- a/api/package.json +++ b/api/package.json @@ -21,7 +21,7 @@ "dependencies": { "@keyv/mongo": "^2.1.8", "@vscode/vscode-languagedetection": "^1.0.22", - "@waylaidwanderer/chatgpt-api": "^1.15.1", + "@waylaidwanderer/chatgpt-api": "^1.28.0", "cors": "^2.8.5", "dotenv": "^16.0.3", "express": "^4.18.2", diff --git a/api/server/routes/ask.js b/api/server/routes/ask.js index ea515c6c75..883be12737 100644 --- a/api/server/routes/ask.js +++ b/api/server/routes/ask.js @@ -2,6 +2,7 @@ const express = require('express'); const crypto = require('crypto'); const router = express.Router(); const askBing = require('./askBing'); +const askSydney = require('./askSydney'); const { titleConvo, askClient, @@ -12,7 +13,7 @@ const { const { getConvo, saveMessage, deleteMessages, saveConvo } = require('../../models'); const { handleError, sendMessage } = require('./handlers'); -router.use('/bing', askBing); +router.use('/bing', askSydney); router.post('/', async (req, res) => { let { model, text, parentMessageId, conversationId, chatGptLabel, promptPrefix } = req.body; diff --git a/api/server/routes/askBing.js b/api/server/routes/askBing.js index 3787e3fb9e..7b3ab74a53 100644 --- a/api/server/routes/askBing.js +++ b/api/server/routes/askBing.js @@ -48,7 +48,11 @@ router.post('/', async (req, res) => { await saveMessage(userMessage); if (!convo.conversationSignature) { - response.title = await titleConvo(text, response.response, model); + response.title = await titleConvo({ + model, + message: text, + response: JSON.stringify(response.response) + }); } response.text = response.response; diff --git a/api/server/routes/askSydney.js b/api/server/routes/askSydney.js new file mode 100644 index 0000000000..8dbf287f8f --- /dev/null +++ b/api/server/routes/askSydney.js @@ -0,0 +1,77 @@ +const express = require('express'); +const crypto = require('crypto'); +const router = express.Router(); +const { titleConvo, askSydney } = require('../../app/'); +const { saveMessage, deleteMessages, saveConvo } = require('../../models'); +const { handleError, sendMessage } = require('./handlers'); + +router.post('/', async (req, res) => { + const { model, text, ...convo } = req.body; + if (!text.trim().includes(' ') && text.length < 5) { + return handleError(res, 'Prompt empty or too short'); + } + + const userMessageId = crypto.randomUUID(); + let userMessage = { id: userMessageId, sender: 'User', text }; + + console.log('ask log', { model, ...userMessage, ...convo }); + + res.writeHead(200, { + Connection: 'keep-alive', + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache, no-transform', + 'Access-Control-Allow-Origin': '*', + 'X-Accel-Buffering': 'no' + }); + + try { + let tokens = ''; + const progressCallback = async (partial) => { + tokens += partial === text ? '' : partial; + // tokens = appendCode(tokens); + sendMessage(res, { text: tokens, message: true }); + }; + + let response = await askSydney({ + text, + progressCallback, + convo + }); + + console.log('CLIENT RESPONSE'); + console.dir(response, { depth: null }); + + userMessage.conversationSignature = + convo.conversationSignature || response.conversationSignature; + userMessage.conversationId = convo.conversationId || response.conversationId; + userMessage.invocationId = response.invocationId; + userMessage.jailbreakConversationId = convo.jailbreakConversationId || response.jailbreakConversationId; + await saveMessage(userMessage); + + if (!convo.conversationSignature) { + response.title = await titleConvo({ + model, + message: text, + response: JSON.stringify(response.response) + }); + } + + response.text = response.response; + response.id = response.details.messageId; + response.suggestions = + response.details.suggestedResponses && + response.details.suggestedResponses.map((s) => s.text); + response.sender = model; + response.final = true; + await saveMessage(response); + await saveConvo(response); + sendMessage(res, response); + res.end(); + } catch (error) { + console.log(error); + await deleteMessages({ id: userMessageId }); + handleError(res, error.message); + } +}); + +module.exports = router; diff --git a/client/src/components/Conversations/Conversation.jsx b/client/src/components/Conversations/Conversation.jsx index a887867c8b..cd4b61f916 100644 --- a/client/src/components/Conversations/Conversation.jsx +++ b/client/src/components/Conversations/Conversation.jsx @@ -34,11 +34,12 @@ export default function Conversation({ const convo = { title, error: false, conversationId: id, chatGptLabel, promptPrefix }; if (bingData) { - const { conversationSignature, clientId, invocationId } = bingData; + const { conversationSignature, jailbreakConversationId, clientId, invocationId } = bingData; dispatch( setConversation({ ...convo, parentMessageId: null, + jailbreakConversationId, conversationSignature, clientId, invocationId @@ -49,6 +50,7 @@ export default function Conversation({ setConversation({ ...convo, parentMessageId, + jailbreakConversationId: null, conversationSignature: null, clientId: null, invocationId: null diff --git a/client/src/components/Conversations/index.jsx b/client/src/components/Conversations/index.jsx index f265a97483..ab49d68b75 100644 --- a/client/src/components/Conversations/index.jsx +++ b/client/src/components/Conversations/index.jsx @@ -14,6 +14,7 @@ export default function Conversations({ conversations, conversationId, showMore conversations.map((convo) => { const bingData = convo.conversationSignature ? { + jailbreakConversationId: convo.jailbreakConversationId, conversationSignature: convo.conversationSignature, clientId: convo.clientId, invocationId: convo.invocationId diff --git a/client/src/components/Main/TextChat.jsx b/client/src/components/Main/TextChat.jsx index 34c49750b9..7701885b4c 100644 --- a/client/src/components/Main/TextChat.jsx +++ b/client/src/components/Main/TextChat.jsx @@ -57,6 +57,7 @@ export default function TextChat({ messages }) { title, conversationId, parentMessageId: id, + jailbreakConversationId: null, conversationSignature: null, clientId: null, invocationId: null, @@ -69,10 +70,18 @@ export default function TextChat({ messages }) { convo.conversationId === null && convo.invocationId === null ) { - const { title, conversationSignature, clientId, conversationId, invocationId } = data; + const { + title, + jailbreakConversationId, + conversationSignature, + clientId, + conversationId, + invocationId + } = data; dispatch( setConversation({ title, + jailbreakConversationId, conversationSignature, clientId, conversationId, diff --git a/client/src/store/convoSlice.js b/client/src/store/convoSlice.js index d2294e5bba..6d10c58265 100644 --- a/client/src/store/convoSlice.js +++ b/client/src/store/convoSlice.js @@ -5,6 +5,7 @@ const initialState = { title: 'ChatGPT Clone', conversationId: null, parentMessageId: null, + jailbreakConversationId: null, conversationSignature: null, clientId: null, invocationId: null, diff --git a/client/src/store/modelSlice.js b/client/src/store/modelSlice.js index 801f0955d8..bc4a1e9b94 100644 --- a/client/src/store/modelSlice.js +++ b/client/src/store/modelSlice.js @@ -16,16 +16,16 @@ const initialState = { _id: '2', name: 'BingAI', value: 'bingai' - } - // { - // _id: '3', - // name: 'ChatGPT', - // value: 'chatgptBrowser' - // } + }, + { + _id: '3', + name: 'ChatGPT', + value: 'chatgptBrowser' + }, ], modelMap: {}, - // initial: { chatgpt: true, chatgptCustom: true, bingai: true, chatgptBrowser: true } - initial: { chatgpt: true, chatgptCustom: true, bingai: true, } + initial: { chatgpt: true, chatgptCustom: true, bingai: true, chatgptBrowser: true } + // initial: { chatgpt: true, chatgptCustom: true, bingai: true, } }; const currentSlice = createSlice({