diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index b58b603f..00000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100644 index a55e7a17..00000000 --- a/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index 03d9549e..00000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml deleted file mode 100644 index d23208fb..00000000 --- a/.idea/jsLibraryMappings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/markdown.xml b/.idea/markdown.xml deleted file mode 100644 index f6d2542c..00000000 --- a/.idea/markdown.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index d3e40546..00000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/node-chatgpt-api.iml b/.idea/node-chatgpt-api.iml deleted file mode 100644 index 0c8867d7..00000000 --- a/.idea/node-chatgpt-api.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7f..00000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index fbd21f2d..e2a803be 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,7 @@ This section will elaborate the parameters that are specific to Bing Chat that a - `useUserSuffixMessage`: Adds a message by the user reading `Continue the message in the current Context` which will prevent the moderation filter to trigger for user messages, but may confuse the AI - `plugins`: Enables the plugins in the array with the value `true`. See the `#resolvePlugins` method in the `BingAIClient.js` class for valid plugins - `persona`: Enables a Microsoft custom GPT. See the `#resolvePersona` method in the `BingAIClient.js` class for valid personas +- `accountType`: The type of account the cookie is associated with. Valid values are `free` and `pro`. Defaults to `free` if not set. # ChatGPT API diff --git a/bin/server.js b/bin/server.js index de86693d..86e24904 100755 --- a/bin/server.js +++ b/bin/server.js @@ -120,6 +120,7 @@ server.post('/conversation', async (request, reply) => { useUserSuffixMessage, plugins, persona, + accountType, } = body; const messageOptions = { conversationId: body.conversationId ? body.conversationId.toString() : undefined, @@ -140,6 +141,7 @@ server.post('/conversation', async (request, reply) => { ...(clientToUseForMessage === 'bing' && { useUserSuffixMessage }), ...(clientToUseForMessage === 'bing' && { plugins }), ...(clientToUseForMessage === 'bing' && { persona }), + ...(clientToUseForMessage === 'bing' && { accountType }), onProgress, abortController, }; diff --git a/package-lock.json b/package-lock.json index c30686e7..af911706 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1309,9 +1309,9 @@ } }, "node_modules/eslint-config-airbnb-base/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -4371,9 +4371,9 @@ "dev": true }, "node_modules/undici": { - "version": "5.25.4", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.25.4.tgz", - "integrity": "sha512-450yJxT29qKMf3aoudzFpIciqpx6Pji3hEWaXqXmanbXF58LTAGCKxcJjxMXWu3iG+Mudgo3ZUfDB6YDFd/dAw==", + "version": "5.28.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.2.tgz", + "integrity": "sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==", "dependencies": { "@fastify/busboy": "^2.0.0" }, @@ -5505,9 +5505,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -7660,9 +7660,9 @@ "dev": true }, "undici": { - "version": "5.25.4", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.25.4.tgz", - "integrity": "sha512-450yJxT29qKMf3aoudzFpIciqpx6Pji3hEWaXqXmanbXF58LTAGCKxcJjxMXWu3iG+Mudgo3ZUfDB6YDFd/dAw==", + "version": "5.28.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.2.tgz", + "integrity": "sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==", "requires": { "@fastify/busboy": "^2.0.0" } diff --git a/src/BingAIClient.js b/src/BingAIClient.js index 5a46c8f4..569e022c 100644 --- a/src/BingAIClient.js +++ b/src/BingAIClient.js @@ -68,6 +68,7 @@ export default class BingAIClient { conversationSignature, clientId, plugins, + accountType, systemMessage, } = opts; systemMessage = systemMessage || this.options.systemMessage; @@ -173,7 +174,8 @@ export default class BingAIClient { const imageBase64 = imageURL ? await BingAIClient.getBase64FromImageUrl(imageURL) : opts?.imageBase64; const imageUploadResult = imageBase64 ? await this.uploadImage(imageBase64) : undefined; const noSearch = plugins?.search === false ? 'nosearchall' : undefined; - plugins = await BingAIClient.#resolvePlugins(plugins); + plugins = BingAIClient.#resolvePlugins(plugins); + accountType = BingAIClient.#resolveAccountType(accountType); const webSocketParameters = { message, invocationId, @@ -188,6 +190,7 @@ export default class BingAIClient { useUserSuffixMessage: opts.useUserSuffixMessage, noSearch, persona, + accountType, }; const ws = await this.#createWebSocketConnection(conversationSignature); @@ -379,13 +382,14 @@ export default class BingAIClient { useUserSuffixMessage, noSearch, persona, + accountType, } = webSocketParameters; const imageBaseURL = 'https://www.bing.com/images/blob?bcid='; const pluginIds = plugins.map(plugin => ({ id: plugin.id, category: 1 })).filter(Boolean); const pluginOptionSets = plugins.map(plugin => plugin.optionSet).filter(Boolean); const personaString = this.#resolvePersona(persona); - const tone = this.#resolveTone(toneStyle); + const tone = this.#resolveTone(toneStyle, accountType); let userMessageSuffix; if (useUserSuffixMessage === true) { @@ -440,9 +444,9 @@ export default class BingAIClient { isStartOfSession: invocationId === 0, message: { ...imageUploadResult - && { imageUrl: `${imageBaseURL}${imageUploadResult.blobId}` }, + && { imageUrl: `${imageBaseURL}${imageUploadResult.blobId}` }, ...imageUploadResult - && { originalImageUrl: `${imageBaseURL}${imageUploadResult.blobId}` }, + && { originalImageUrl: `${imageBaseURL}${imageUploadResult.blobId}` }, author: 'user', text: useUserSuffixMessage ? userMessageSuffix : message, messageType: 'Chat', @@ -464,6 +468,25 @@ export default class BingAIClient { return userWebsocketRequest; } + /** + * Resolves the accountType and returns the string to use for further usage. + * @param {String} accountType String description of account type. + * @returns {String} The resolved account type to use. + */ + static #resolveAccountType(accountType) { + let resolvedAccountType; + switch (accountType) { + case 'pro': + resolvedAccountType = 'pro'; + break; + case 'free': + default: + resolvedAccountType = 'free'; + } + + return resolvedAccountType; + } + /** * This method converts persona names from simple names to technical names. * @param {String | undefined} persona Simple name of the persona to use. @@ -499,7 +522,7 @@ export default class BingAIClient { * @param {Object} plugins Object containing the plugins to use as strings. * @returns {Object[]} The resolved array of plugin objects that can be used later. */ - static async #resolvePlugins(plugins) { + static #resolvePlugins(plugins) { const pluginLookup = { codeInterpreter: { optionSet: 'codeint', @@ -552,20 +575,24 @@ export default class BingAIClient { /** * This method converts toneStyles from simple names to technical names. * @param {String | undefined} toneStyle Simple name of the tone to use. + * @param {String} accountType Account type which influences modes. * @returns {String} Technical name of the tone to use. */ - static #resolveTone(toneStyle) { + static #resolveTone(toneStyle, accountType) { let tone; - if (toneStyle === 'creative') { - tone = 'CreativeClassic'; - } else if (toneStyle === 'turbo') { - tone = 'Creative'; - } else if (toneStyle === 'precise') { - tone = 'Precise'; - } else if (toneStyle === 'balanced') { - tone = 'Balanced'; - } else { - tone = 'CreativeClassic'; + switch (toneStyle) { + case 'turbo': + tone = 'Creative'; + break; + case 'precise': + tone = 'Precise'; + break; + case 'balanced': + tone = 'Balanced'; + break; + case 'creative': + default: + tone = accountType === 'pro' ? 'CreativeClassic' : 'Creative'; } return tone; @@ -625,7 +652,7 @@ export default class BingAIClient { return; } if (messages[0]?.contentType === 'IMAGE') { - // You will never get a message of this type without 'gencontentv3' being on. + // You will never get a message of this type without 'gencontentv3' being on. bicIframe = this.bic.genImageIframeSsr( messages[0].text, messages[0].messageId, @@ -718,12 +745,12 @@ export default class BingAIClient { // The moderation filter triggered, so just return the text we have so far if ( opts.jailbreakConversationId - && ( - stopTokenFound - || event.item.messages[0].topicChangerText - || event.item.messages[0].offense === 'OffenseTrigger' - || (event.item.messages.length > 1 && event.item.messages[1].contentOrigin === 'Apology') - ) + && ( + stopTokenFound + || event.item.messages[0].topicChangerText + || event.item.messages[0].offense === 'OffenseTrigger' + || (event.item.messages.length > 1 && event.item.messages[1].contentOrigin === 'Apology') + ) ) { if (!replySoFar) { replySoFar = 'I need some time to process your message. Please wait a moment.'; @@ -734,7 +761,7 @@ export default class BingAIClient { delete eventMessage.suggestedResponses; } if (bicIframe) { - // the last messages will be a image creation event if bicIframe is present. + // the last messages will be a image creation event if bicIframe is present. let i = messages.length - 1; while (eventMessage?.contentType === 'IMAGE' && i > 0) { eventMessage = messages[i -= 1]; @@ -751,7 +778,7 @@ export default class BingAIClient { } } if ((opts.showSuggestions === false || opts.useBase64 === true) - && eventMessage.suggestedResponses) { + && eventMessage.suggestedResponses) { delete eventMessage.suggestedResponses; } resolve({ @@ -762,7 +789,7 @@ export default class BingAIClient { return; } case 7: { - // [{"type":7,"error":"Connection closed with an error.","allowReconnect":true}] + // [{"type":7,"error":"Connection closed with an error.","allowReconnect":true}] clearTimeout(messageTimeout); this.constructor.cleanupWebSocketConnection(ws); reject(new Error(event.error || 'Connection closed with an error.'));