diff --git a/package-lock.json b/package-lock.json index 8f85770..6b4a2fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,6 @@ "": { "name": "chatgpt-on-hindi-google-extension", "dependencies": { - "@esbuild/win32-x64": "^0.20.2", "@geist-ui/core": "^2.3.8", "@geist-ui/icons": "^1.0.2", "@primer/octicons-react": "^17.9.0", @@ -19,6 +18,7 @@ "github-markdown-css": "^5.1.0", "i18next-browser-languagedetector": "^7.0.1", "inter-ui": "^3.19.3", + "llm-playground-chain": "^0.0.6", "lodash-es": "^4.17.21", "ofetch": "^1.0.1", "preact": "^10.11.3", @@ -65,8 +65,9 @@ "webextension-polyfill": "^0.10.0" }, "engines": { - "node": ">=16.15.0 <17.0.0", - "npm": ">=8.19.4 <9.0.0" + "node": ">=18.17.1 <19.0.0", + "npm": ">=9.6.7 <10.0.0", + "pnpm": ">=9.6.7" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -425,20 +426,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", - "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", - "cpu": [ - "x64" - ], - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@eslint/eslintrc": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.0.tgz", @@ -3930,6 +3917,27 @@ "node": ">=8" } }, + "node_modules/llm-playground-chain": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/llm-playground-chain/-/llm-playground-chain-0.0.6.tgz", + "integrity": "sha512-NqRv/0Io7A2Z+3AjjqJK3me9AKjzXngeXKklQDC97DtOanqmYrlGD4GyWvDloBi7Jpm8G99djuY3sMBbfDlLLA==", + "dependencies": { + "buffer": "^6.0.3", + "dayjs": "^1.11.9", + "eventsource-parser": "^1.0.0", + "expiry-map": "^2.0.0", + "lodash-es": "^4.17.21", + "rollup-plugin-includepaths": "^0.2.4", + "uuid": "^9.0.0", + "webextension-polyfill": "^0.10.0", + "websocket-as-promised": "^2.0.1" + }, + "engines": { + "node": ">=18.17.1 <19.0.0", + "npm": ">=9.6.7 <10.0.0", + "pnpm": ">=8.15.5" + } + }, "node_modules/loader-utils": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", @@ -5870,6 +5878,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rollup-plugin-includepaths": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/rollup-plugin-includepaths/-/rollup-plugin-includepaths-0.2.4.tgz", + "integrity": "sha512-iZen+XKVExeCzk7jeSZPJKL7B67slZNr8GXSC5ROBXtDGXDBH8wdjMfdNW5hf9kPt+tHyIvWh3wlE9bPrZL24g==" + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -6832,8 +6845,7 @@ "node_modules/webextension-polyfill": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.10.0.tgz", - "integrity": "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==", - "dev": true + "integrity": "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==" }, "node_modules/websocket-as-promised": { "version": "2.0.1", @@ -7313,11 +7325,6 @@ "dev": true, "optional": true }, - "@esbuild/win32-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", - "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==" - }, "@eslint/eslintrc": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.0.tgz", @@ -9810,6 +9817,22 @@ } } }, + "llm-playground-chain": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/llm-playground-chain/-/llm-playground-chain-0.0.6.tgz", + "integrity": "sha512-NqRv/0Io7A2Z+3AjjqJK3me9AKjzXngeXKklQDC97DtOanqmYrlGD4GyWvDloBi7Jpm8G99djuY3sMBbfDlLLA==", + "requires": { + "buffer": "^6.0.3", + "dayjs": "^1.11.9", + "eventsource-parser": "^1.0.0", + "expiry-map": "^2.0.0", + "lodash-es": "^4.17.21", + "rollup-plugin-includepaths": "^0.2.4", + "uuid": "^9.0.0", + "webextension-polyfill": "^0.10.0", + "websocket-as-promised": "^2.0.1" + } + }, "loader-utils": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", @@ -11061,6 +11084,11 @@ "glob": "^7.1.3" } }, + "rollup-plugin-includepaths": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/rollup-plugin-includepaths/-/rollup-plugin-includepaths-0.2.4.tgz", + "integrity": "sha512-iZen+XKVExeCzk7jeSZPJKL7B67slZNr8GXSC5ROBXtDGXDBH8wdjMfdNW5hf9kPt+tHyIvWh3wlE9bPrZL24g==" + }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -11728,8 +11756,7 @@ "webextension-polyfill": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.10.0.tgz", - "integrity": "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==", - "dev": true + "integrity": "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==" }, "websocket-as-promised": { "version": "2.0.1", diff --git a/package.json b/package.json index 33834d9..891aedd 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,6 @@ "watch": "chokidar src -c 'npm run build'" }, "dependencies": { - "@esbuild/win32-x64": "^0.20.2", "@geist-ui/core": "^2.3.8", "@geist-ui/icons": "^1.0.2", "@primer/octicons-react": "^17.9.0", @@ -22,6 +21,7 @@ "github-markdown-css": "^5.1.0", "i18next-browser-languagedetector": "^7.0.1", "inter-ui": "^3.19.3", + "llm-playground-chain": "^0.0.6", "lodash-es": "^4.17.21", "ofetch": "^1.0.1", "preact": "^10.11.3", @@ -74,7 +74,8 @@ ] }, "engines": { - "node": ">=16.15.0 <17.0.0", - "npm": ">=8.19.4 <9.0.0" + "node": ">=18.17.1 <19.0.0", + "pnpm": ">=9.6.7", + "npm": ">=9.6.7 <10.0.0" } } diff --git a/src/background/index.ts b/src/background/index.ts index e99a572..da80ab7 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -2,7 +2,8 @@ import Browser from 'webextension-polyfill' import { getChatGPTChatIds, getProviderConfigs, ProviderType } from '../config' // import { BARDProvider, sendMessageFeedbackBard } from './providers/bard' import { isDate } from '../utils/parse' -import { ChatGPTProvider, getChatGPTAccessToken, sendMessageFeedback } from './providers/chatgpt' +// import { ChatGPTProvider, getChatGPTAccessToken, sendMessageFeedback } from './providers/chatgpt' +import { ChatGPTProvider, getChatGPTAccessToken, sendMessageFeedback } from 'llm-playground-chain' import { OpenAIProvider } from './providers/openai' import { Provider } from './types' diff --git a/src/background/providers/bard.ts b/src/background/providers/bard.ts index 77d8373..ebe30be 100644 --- a/src/background/providers/bard.ts +++ b/src/background/providers/bard.ts @@ -28,7 +28,7 @@ export class ChatError extends Error { } // async function request(token: string, method: string, path: string, data?: unknown) { -// return fetch(`https://chat.openai.com/backend-api${path}`, { +// return fetch(`https://chatgpt.com/backend-api${path}`, { // method, // headers: { // 'Content-Type': 'application/json', @@ -60,7 +60,7 @@ const cache = new ExpiryMap(10 * 1000) // if (cache.get(KEY_ACCESS_TOKEN)) { // return cache.get(KEY_ACCESS_TOKEN) // } -// const resp = await fetch('https://chat.openai.com/api/auth/session') +// const resp = await fetch('https://chatgpt.com/api/auth/session') // if (resp.status === 403) { // throw new Error('CLOUDFLARE') // } @@ -95,7 +95,7 @@ export class BARDProvider implements Provider { private async parseBartResponse(resp: string) { const data = JSON.parse(resp.split('\n')[3]) const payload = JSON.parse(data[0][2]) - console.log("payload", payload) + console.log('payload', payload) if (!payload) { throw new ChatError( 'Failed to access Bard, make sure you are logged in at https://bard.google.com', diff --git a/src/background/providers/chatgpt.ts b/src/background/providers/chatgpt.ts index b38babc..bc2838b 100644 --- a/src/background/providers/chatgpt.ts +++ b/src/background/providers/chatgpt.ts @@ -1,474 +1,474 @@ -import { Buffer } from 'buffer' -import dayjs from 'dayjs' -import { createParser } from 'eventsource-parser' -import ExpiryMap from 'expiry-map' -import { v4 as uuidv4 } from 'uuid' -import Browser from 'webextension-polyfill' -import WebSocketAsPromised from 'websocket-as-promised' -import { parseSSEResponse, parseSSEResponse3 } from '~utils/sse' -import { ADAY, APPSHORTNAME, HALFHOUR } from '../../utils/consts' -import { fetchSSE } from '../fetch-sse' -import { GenerateAnswerParams, Provider } from '../types' -dayjs().format() - -async function request(token: string, method: string, path: string, data?: unknown) { - return fetch(`https://chat.openai.com/backend-api${path}`, { - method, - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${token}`, - }, - body: data === undefined ? undefined : JSON.stringify(data), - }) -} - -function removeCitations(text: string) { - return text.replaceAll(/\u3010\d+\u2020source\u3011/g, '') -} - -const getConversationTitle = (bigtext: string) => { - let ret = bigtext.split('\n', 1)[0] - ret = ret.split('.', 1)[0] - ret = APPSHORTNAME + ':' + ret.split(':')[1].trim() - console.log('getConversationTitle:', ret) - return ret -} - -const countWords = (text) => { - return text.trim().split(/\s+/).length -} - -async function getChatgptwssIsOpenFlag() { - const { chatgptwssIsOpenFlag = false } = await Browser.storage.sync.get('chatgptwssIsOpenFlag') - return chatgptwssIsOpenFlag -} - -async function setChatgptwssIsOpenFlag(isOpen: boolean) { - const { chatgptwssIsOpenFlag = false } = await Browser.storage.sync.get('chatgptwssIsOpenFlag') - Browser.storage.sync.set({ chatgptwssIsOpenFlag: isOpen }) - return chatgptwssIsOpenFlag -} - -async function request_new( - token: string, - method: string, - path: string, - data?: unknown, - callback?: unknown, -) { - return fetch(`https://chat.openai.com/backend-api${path}`, { - method, - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${token}`, - }, - body: data === undefined ? undefined : JSON.stringify(data), - }) - .then(function (response) { - console.log('fetch', token != null, method, path, 'response', response) - return response.json() - }) - .then(function (data) { - console.log('response data', data) - if (callback) callback(token, data) - }) - .catch((error) => { - console.error('fetch', token, method, path, 'error', error) - }) -} - -export async function sendMessageFeedback(token: string, data: unknown) { - await request(token, 'POST', '/conversation/message_feedback', data) -} - -export async function setConversationProperty( - token: string, - conversationId: string, - propertyObject: object, -) { - await request(token, 'PATCH', `/conversation/${conversationId}`, propertyObject) -} - -const browsertabIdConversationIdMap = new Map() -const windowIdConversationIdMap = new Map() - -function deleteRecentConversations(token, data) { - const now = dayjs() - const startTime = dayjs(performance.timeOrigin) - console.log('startTime', startTime) - const convs = data.items - console.log('convs', convs) - for (let i = 0; i < convs.length; i++) { - const conv_i_time = dayjs(convs[i].create_time) - console.log( - 'conv' + i, - convs[i].id, - conv_i_time, - conv_i_time - startTime, - now - conv_i_time, - now - conv_i_time < ADAY, - ) - if ( - HALFHOUR < now - conv_i_time && - now - conv_i_time < ADAY && - convs[i].title.indexOf(APPSHORTNAME + ':') != -1 - ) { - setTimeout(function () { - console.log('Deleting', token != null, convs[i].id) - setConversationProperty(token, convs[i].id, { is_visible: false }) - const cloneBTCMap = new Map(browsertabIdConversationIdMap) - cloneBTCMap.forEach((ConversationId, tabId, map) => { - console.log('Looking for', ConversationId, tabId, 'in', map) - if (ConversationId == convs[i].id) { - console.log('Deleting ', ConversationId, tabId, 'from', map) - browsertabIdConversationIdMap.delete(tabid) - console.log( - 'browsertabIdConversationIdMap after Deleting ', - browsertabIdConversationIdMap, - ) - } - }) - const cloneWCMap = new Map(windowIdConversationIdMap) - cloneWCMap.forEach((conversationIdsConcatinated, windowId, map) => { - console.log('Looking for', conversationIdsConcatinated, windowId, 'in', map) - if (conversationIdsConcatinated.indexOf(convs[i].id) != -1) { - console.log('Deleting ', convs[i].id, windowId, 'from', map) - conversationIdsConcatinated = conversationIdsConcatinated.replace(convs[i].id, '') - conversationIdsConcatinated = conversationIdsConcatinated.replace(',,', ',') - windowIdConversationIdMap.set(windowid, conversationIdsConcatinated) - console.log('windowIdConversationIdMap after Deleting ', windowIdConversationIdMap) - } - }) - }, i * 1000) - } - } -} - -const KEY_ACCESS_TOKEN = 'accessToken' - -const cache = new ExpiryMap(10 * 1000) - -export async function getChatGPTAccessToken(): Promise { - if (cache.get(KEY_ACCESS_TOKEN)) { - return cache.get(KEY_ACCESS_TOKEN) - } - const resp = await fetch('https://chat.openai.com/api/auth/session') - if (resp.status === 403) { - throw new Error('CLOUDFLARE') - } - const data = await resp.json().catch(() => ({})) - if (!data.accessToken) { - throw new Error('UNAUTHORIZED') - } - cache.set(KEY_ACCESS_TOKEN, data.accessToken) - return data.accessToken -} - -export class ChatGPTProvider implements Provider { - constructor(private token: string) { - this.token = token - //Brute: - request_new( - token, - 'GET', - '/conversations?offset=0&limit=100&order=updated', - undefined, - deleteRecentConversations, - ) - } - - private async fetchModels(): Promise< - { slug: string; title: string; description: string; max_tokens: number }[] - > { - const resp = await request(this.token, 'GET', '/models').then((r) => r.json()) - return resp.models - } - - private async getModelName(): Promise { - try { - const models = await this.fetchModels() - return models[0].slug - } catch (err) { - console.error(err) - return 'text-davinci-002-render' - } - } - - private renameConversationTitle(convId: string, params: SendMessageParams) { - const titl: string = getConversationTitle(params.prompt) - console.log('renameConversationTitle:', this.token, convId, titl) - setConversationProperty(this.token, convId, { title: titl }) - } - - async getChatRequirementsToken(params: SendMessageParams) { - const resp = await fetch('https://chat.openai.com/backend-api/sentinel/chat-requirements', { - method: 'POST', - signal: params.signal, - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${this.token}`, - conversation_mode_kind: 'primary_assistant', - }, - body: JSON.stringify({ - conversation_mode_kind: 'primary_assistant', - }), - }) - console.log('getChatRequirements:resp:', resp) - let retToken = '' - await parseSSEResponse3(resp, (message: any) => { - console.log('getChatRequirements:message:', message) - retToken = message.token - }) - console.log('retToken:', retToken) - return retToken - } - - async registerWSS(params: GenerateAnswerParams) { - const resp = await fetch('https://chat.openai.com/backend-api/register-websocket', { - method: 'POST', - signal: params.signal, - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${this.token}`, - }, - body: void 0, - }) - return resp - } - - async setupWSS(params: GenerateAnswerParams, regResp: any) { - console.log('ChatGPTProvider:setupWSS:regResp', regResp) - let jj - await parseSSEResponse(regResp, (message) => { - console.log('ChatGPTProvider:setupWSS:parseSSEResponse:message', message) - jj = JSON.parse(message) - }) - console.log('ChatGPTProvider:jj', jj) - if (jj) { - const wsAddress = jj['wss_url'] - const wsp: WebSocketAsPromised = new WebSocketAsPromised(wsAddress, { - createWebSocket: (url) => { - const ws = new WebSocket(wsAddress, [ - 'Sec-Websocket-Protocol', - 'json.reliable.webpubsub.azure.v1', - ]) - ws.binaryType = 'arraybuffer' - return ws - }, - }) - console.log('ChatGPTProvider:setupWebsocket:wsp', wsp) - - const openListener = async () => { - console.log('ChatGPTProvider:setupWSSopenListener::wsp.onOpen') - await setChatgptwssIsOpenFlag(true) - } - - let next_check_seqid = Math.round(Math.random() * 50) - let lastSendTextLen = 0 - const messageListener = (message: any) => { - // console.log('ChatGPTProvider:setupWebsocket:wsp.onMessage:', message) - const jjws = JSON.parse(message) - console.log('ChatGPTProvider:setupWSS:messageListener:jjws:', jjws) - const rawMessage = jjws['data'] ? jjws['data']['body'] : '' - console.log('ChatGPTProvider:setupWSS:wsp.onMessage:rawMessage:', rawMessage) - const b64decodedMessage = Buffer.from(rawMessage, 'base64') - const finalMessageStr = b64decodedMessage.toString() - console.log('ChatGPTProvider:setupWebsocket:wsp.onMessage:finalMessage:', finalMessageStr) - - const parser = createParser((parent_message) => { - console.log('ChatGPTProvider:setupWSS:createParser:parent_message', parent_message) //event=`{data:'{}',event:undefine,id=undefined,type='event'}` - let data - try { - if ((parent_message['data' as keyof typeof parent_message] as string) === '[DONE]') { - console.log('ChatGPTProvider:setupWSS:createParser:returning DONE to frontend2') - params.onEvent({ type: 'done' }) - wsp.close() - return - } else if (parent_message['data' as keyof typeof parent_message]) { - data = JSON.parse(parent_message['data' as keyof typeof parent_message]) - console.log('ChatGPTProvider:setupWSS:createParser:data', data) - } - } catch (err) { - console.log('ChatGPTProvider:setupWSS:createParser:Error', err) - params.onEvent({ type: 'error', message: (err as any)?.message }) - wsp.close() - return - } - const content = data?.message?.content as ResponseContent | undefined - if (!content) { - console.log('ChatGPTProvider:returning DONE to frontend3') - params.onEvent({ type: 'done' }) - wsp.close() - return - } - let text: string - if (content.content_type === 'text') { - text = content.parts[0] - // text = removeCitations(text) - } else if (content.content_type === 'code') { - text = '_' + content.text + '_' - } else { - console.log('ChatGPTProvider:returning DONE to frontend4') - params.onEvent({ type: 'done' }) - wsp.close() - return - } - if (text) { - if (data.message?.author?.role == 'assistant') { - if (params.prompt.indexOf('search query:') !== -1) { - // this.renameConversationTitle(data.conversation_id, params) - } - console.debug( - 'ChatGPTProvider:generateAnswerBySSE:answer:text(setupWSS:messageListener):', - text, - ) - params.onEvent({ - type: 'answer', - data: { - text, - messageId: data.message.id, - parentMessageId: data.parent_message_id, - conversationId: data.conversation_id, - }, - }) - } - } - }) - // if (finalMessageStr.length - lastSendTextLen > 40) - parser.feed(finalMessageStr) - lastSendTextLen = finalMessageStr.length - - const sequenceId = jjws['sequenceId'] - console.log('ChatGPTProvider:doSendMessage:sequenceId:', sequenceId) - if (sequenceId === next_check_seqid) { - const t = { - type: 'sequenceAck', - sequenceId: next_check_seqid, - } - if (wsp.isOpened) { - wsp.send(JSON.stringify(t)) - next_check_seqid += Math.round(Math.random() * 50) - } else { - console.log('ChatGPTProvider:doSendMessage:WebSocket is not open:wsp, t:', wsp, t) - } - } - } - wsp.removeAllListeners() - wsp.close() - wsp.onOpen.addListener(openListener) - wsp.onMessage.addListener(messageListener) - wsp.onClose.removeListener(messageListener) - wsp.open().catch(async (e) => { - console.log('ChatGPTProvider:doSendMessage:open:showError:Error caught while opening ws', e) - wsp.removeAllListeners() - wsp.close() - await setChatgptwssIsOpenFlag(false) - params.onEvent({ type: 'error', message: (e as any)?.message }) - }) - } - } - - async generateAnswer(params: GenerateAnswerParams) { - console.log('chatgpt', params.arkoseToken) - let conversationId: string | undefined - - const countWords = (text) => { - return text.trim().split(/\s+/).length - } - - const getConversationTitle = (bigtext: string) => { - let ret = bigtext.split('\n', 1)[0] - ret = ret.split('.', 1)[0] - ret = APPSHORTNAME + ':' + ret.split(':')[1].trim() - console.log('getConversationTitle:', ret) - return ret - } - - const cleanup = () => { - if (conversationId) { - // setConversationProperty(this.token, conversationId, { is_visible: false }) - } - } - - const regResp = await this.registerWSS(params) - await this.setupWSS(params, regResp) // Since params change WSS have to be setup up every time - - const modelName = await this.getModelName() - const chatRequirementsToken = await this.getChatRequirementsToken(params) - console.debug('Using model:', modelName) - - await fetchSSE('https://chat.openai.com/backend-api/conversation', { - method: 'POST', - signal: params.signal, - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${this.token}`, - 'Openai-Sentinel-Arkose-Token': params.arkoseToken, - 'Openai-Sentinel-Chat-Requirements-Token': chatRequirementsToken, - }, - body: JSON.stringify({ - action: 'next', - messages: [ - { - id: uuidv4(), - role: 'user', - content: { - content_type: 'text', - parts: [params.prompt], - }, - }, - ], - model: modelName, - parent_message_id: params.parentMessageId || uuidv4(), - conversation_id: params.conversationId, - arkose_token: params.arkoseToken, - conversation_mode: { - kind: 'primary_assistant', - }, - history_and_training_disabled: !1, - force_paragen: !1, - force_rate_limit: !1, - suggestions: [], - // websocket_request_id://TODO:still working without it - }), - onMessage(message: string) { - console.debug('sse message', message) - if (message === '[DONE]') { - params.onEvent({ type: 'done' }) - cleanup() - return - } - let data - try { - data = JSON.parse(message) - } catch (err) { - console.error(err) - return - } - const text = data.message?.content?.parts?.[0] - if (text) { - if (data.message?.author?.role == 'assistant') { - if (params.prompt.indexOf('search query:') !== -1) { - // this.renameConversationTitle(data.conversation_id) - } - } - conversationId = data.conversation_id - console.debug( - 'ChatGPTProvider:generateAnswer:answer:text(setupWSS:messageListener):', - text, - ) - params.onEvent({ - type: 'answer', - data: { - text, - messageId: data.message.id, - parentMessageId: data.parent_message_id, - conversationId: data.conversation_id, - }, - }) - } - }, - }) - return { cleanup } - } -} +// import { Buffer } from 'buffer' +// import dayjs from 'dayjs' +// import { createParser } from 'eventsource-parser' +// import ExpiryMap from 'expiry-map' +// import { v4 as uuidv4 } from 'uuid' +// import Browser from 'webextension-polyfill' +// import WebSocketAsPromised from 'websocket-as-promised' +// import { parseSSEResponse, parseSSEResponse3 } from '~utils/sse' +// import { ADAY, APPSHORTNAME, HALFHOUR } from '../../utils/consts' +// import { fetchSSE } from '../fetch-sse' +// import { GenerateAnswerParams, Provider } from '../types' +// dayjs().format() + +// async function request(token: string, method: string, path: string, data?: unknown) { +// return fetch(`https://chatgpt.com/backend-api${path}`, { +// method, +// headers: { +// 'Content-Type': 'application/json', +// Authorization: `Bearer ${token}`, +// }, +// body: data === undefined ? undefined : JSON.stringify(data), +// }) +// } + +// function removeCitations(text: string) { +// return text.replaceAll(/\u3010\d+\u2020source\u3011/g, '') +// } + +// const getConversationTitle = (bigtext: string) => { +// let ret = bigtext.split('\n', 1)[0] +// ret = ret.split('.', 1)[0] +// ret = APPSHORTNAME + ':' + ret.split(':')[1].trim() +// console.log('getConversationTitle:', ret) +// return ret +// } + +// const countWords = (text) => { +// return text.trim().split(/\s+/).length +// } + +// async function getChatgptwssIsOpenFlag() { +// const { chatgptwssIsOpenFlag = false } = await Browser.storage.sync.get('chatgptwssIsOpenFlag') +// return chatgptwssIsOpenFlag +// } + +// async function setChatgptwssIsOpenFlag(isOpen: boolean) { +// const { chatgptwssIsOpenFlag = false } = await Browser.storage.sync.get('chatgptwssIsOpenFlag') +// Browser.storage.sync.set({ chatgptwssIsOpenFlag: isOpen }) +// return chatgptwssIsOpenFlag +// } + +// async function request_new( +// token: string, +// method: string, +// path: string, +// data?: unknown, +// callback?: unknown, +// ) { +// return fetch(`https://chatgpt.com/backend-api${path}`, { +// method, +// headers: { +// 'Content-Type': 'application/json', +// Authorization: `Bearer ${token}`, +// }, +// body: data === undefined ? undefined : JSON.stringify(data), +// }) +// .then(function (response) { +// console.log('fetch', token != null, method, path, 'response', response) +// return response.json() +// }) +// .then(function (data) { +// console.log('response data', data) +// if (callback) callback(token, data) +// }) +// .catch((error) => { +// console.error('fetch', token, method, path, 'error', error) +// }) +// } + +// export async function sendMessageFeedback(token: string, data: unknown) { +// await request(token, 'POST', '/conversation/message_feedback', data) +// } + +// export async function setConversationProperty( +// token: string, +// conversationId: string, +// propertyObject: object, +// ) { +// await request(token, 'PATCH', `/conversation/${conversationId}`, propertyObject) +// } + +// const browsertabIdConversationIdMap = new Map() +// const windowIdConversationIdMap = new Map() + +// function deleteRecentConversations(token, data) { +// const now = dayjs() +// const startTime = dayjs(performance.timeOrigin) +// console.log('startTime', startTime) +// const convs = data.items +// console.log('convs', convs) +// for (let i = 0; i < convs.length; i++) { +// const conv_i_time = dayjs(convs[i].create_time) +// console.log( +// 'conv' + i, +// convs[i].id, +// conv_i_time, +// conv_i_time - startTime, +// now - conv_i_time, +// now - conv_i_time < ADAY, +// ) +// if ( +// HALFHOUR < now - conv_i_time && +// now - conv_i_time < ADAY && +// convs[i].title.indexOf(APPSHORTNAME + ':') != -1 +// ) { +// setTimeout(function () { +// console.log('Deleting', token != null, convs[i].id) +// setConversationProperty(token, convs[i].id, { is_visible: false }) +// const cloneBTCMap = new Map(browsertabIdConversationIdMap) +// cloneBTCMap.forEach((ConversationId, tabId, map) => { +// console.log('Looking for', ConversationId, tabId, 'in', map) +// if (ConversationId == convs[i].id) { +// console.log('Deleting ', ConversationId, tabId, 'from', map) +// browsertabIdConversationIdMap.delete(tabid) +// console.log( +// 'browsertabIdConversationIdMap after Deleting ', +// browsertabIdConversationIdMap, +// ) +// } +// }) +// const cloneWCMap = new Map(windowIdConversationIdMap) +// cloneWCMap.forEach((conversationIdsConcatinated, windowId, map) => { +// console.log('Looking for', conversationIdsConcatinated, windowId, 'in', map) +// if (conversationIdsConcatinated.indexOf(convs[i].id) != -1) { +// console.log('Deleting ', convs[i].id, windowId, 'from', map) +// conversationIdsConcatinated = conversationIdsConcatinated.replace(convs[i].id, '') +// conversationIdsConcatinated = conversationIdsConcatinated.replace(',,', ',') +// windowIdConversationIdMap.set(windowid, conversationIdsConcatinated) +// console.log('windowIdConversationIdMap after Deleting ', windowIdConversationIdMap) +// } +// }) +// }, i * 1000) +// } +// } +// } + +// const KEY_ACCESS_TOKEN = 'accessToken' + +// const cache = new ExpiryMap(10 * 1000) + +// export async function getChatGPTAccessToken(): Promise { +// if (cache.get(KEY_ACCESS_TOKEN)) { +// return cache.get(KEY_ACCESS_TOKEN) +// } +// const resp = await fetch('https://chatgpt.com/api/auth/session') +// if (resp.status === 403) { +// throw new Error('CLOUDFLARE') +// } +// const data = await resp.json().catch(() => ({})) +// if (!data.accessToken) { +// throw new Error('UNAUTHORIZED') +// } +// cache.set(KEY_ACCESS_TOKEN, data.accessToken) +// return data.accessToken +// } + +// export class ChatGPTProvider implements Provider { +// constructor(private token: string) { +// this.token = token +// //Brute: +// request_new( +// token, +// 'GET', +// '/conversations?offset=0&limit=100&order=updated', +// undefined, +// deleteRecentConversations, +// ) +// } + +// private async fetchModels(): Promise< +// { slug: string; title: string; description: string; max_tokens: number }[] +// > { +// const resp = await request(this.token, 'GET', '/models').then((r) => r.json()) +// return resp.models +// } + +// private async getModelName(): Promise { +// try { +// const models = await this.fetchModels() +// return models[0].slug +// } catch (err) { +// console.error(err) +// return 'text-davinci-002-render' +// } +// } + +// private renameConversationTitle(convId: string, params: SendMessageParams) { +// const titl: string = getConversationTitle(params.prompt) +// console.log('renameConversationTitle:', this.token, convId, titl) +// setConversationProperty(this.token, convId, { title: titl }) +// } + +// async getChatRequirementsToken(params: SendMessageParams) { +// const resp = await fetch('https://chatgpt.com/backend-api/sentinel/chat-requirements', { +// method: 'POST', +// signal: params.signal, +// headers: { +// 'Content-Type': 'application/json', +// Authorization: `Bearer ${this.token}`, +// conversation_mode_kind: 'primary_assistant', +// }, +// body: JSON.stringify({ +// conversation_mode_kind: 'primary_assistant', +// }), +// }) +// console.log('getChatRequirements:resp:', resp) +// let retToken = '' +// await parseSSEResponse3(resp, (message: any) => { +// console.log('getChatRequirements:message:', message) +// retToken = message.token +// }) +// console.log('retToken:', retToken) +// return retToken +// } + +// async registerWSS(params: GenerateAnswerParams) { +// const resp = await fetch('https://chatgpt.com/backend-api/register-websocket', { +// method: 'POST', +// signal: params.signal, +// headers: { +// 'Content-Type': 'application/json', +// Authorization: `Bearer ${this.token}`, +// }, +// body: void 0, +// }) +// return resp +// } + +// async setupWSS(params: GenerateAnswerParams, regResp: any) { +// console.log('ChatGPTProvider:setupWSS:regResp', regResp) +// let jj +// await parseSSEResponse(regResp, (message) => { +// console.log('ChatGPTProvider:setupWSS:parseSSEResponse:message', message) +// jj = JSON.parse(message) +// }) +// console.log('ChatGPTProvider:jj', jj) +// if (jj) { +// const wsAddress = jj['wss_url'] +// const wsp: WebSocketAsPromised = new WebSocketAsPromised(wsAddress, { +// createWebSocket: (url) => { +// const ws = new WebSocket(wsAddress, [ +// 'Sec-Websocket-Protocol', +// 'json.reliable.webpubsub.azure.v1', +// ]) +// ws.binaryType = 'arraybuffer' +// return ws +// }, +// }) +// console.log('ChatGPTProvider:setupWebsocket:wsp', wsp) + +// const openListener = async () => { +// console.log('ChatGPTProvider:setupWSSopenListener::wsp.onOpen') +// await setChatgptwssIsOpenFlag(true) +// } + +// let next_check_seqid = Math.round(Math.random() * 50) +// let lastSendTextLen = 0 +// const messageListener = (message: any) => { +// // console.log('ChatGPTProvider:setupWebsocket:wsp.onMessage:', message) +// const jjws = JSON.parse(message) +// console.log('ChatGPTProvider:setupWSS:messageListener:jjws:', jjws) +// const rawMessage = jjws['data'] ? jjws['data']['body'] : '' +// console.log('ChatGPTProvider:setupWSS:wsp.onMessage:rawMessage:', rawMessage) +// const b64decodedMessage = Buffer.from(rawMessage, 'base64') +// const finalMessageStr = b64decodedMessage.toString() +// console.log('ChatGPTProvider:setupWebsocket:wsp.onMessage:finalMessage:', finalMessageStr) + +// const parser = createParser((parent_message) => { +// console.log('ChatGPTProvider:setupWSS:createParser:parent_message', parent_message) //event=`{data:'{}',event:undefine,id=undefined,type='event'}` +// let data +// try { +// if ((parent_message['data' as keyof typeof parent_message] as string) === '[DONE]') { +// console.log('ChatGPTProvider:setupWSS:createParser:returning DONE to frontend2') +// params.onEvent({ type: 'done' }) +// wsp.close() +// return +// } else if (parent_message['data' as keyof typeof parent_message]) { +// data = JSON.parse(parent_message['data' as keyof typeof parent_message]) +// console.log('ChatGPTProvider:setupWSS:createParser:data', data) +// } +// } catch (err) { +// console.log('ChatGPTProvider:setupWSS:createParser:Error', err) +// params.onEvent({ type: 'error', message: (err as any)?.message }) +// wsp.close() +// return +// } +// const content = data?.message?.content as ResponseContent | undefined +// if (!content) { +// console.log('ChatGPTProvider:returning DONE to frontend3') +// params.onEvent({ type: 'done' }) +// wsp.close() +// return +// } +// let text: string +// if (content.content_type === 'text') { +// text = content.parts[0] +// // text = removeCitations(text) +// } else if (content.content_type === 'code') { +// text = '_' + content.text + '_' +// } else { +// console.log('ChatGPTProvider:returning DONE to frontend4') +// params.onEvent({ type: 'done' }) +// wsp.close() +// return +// } +// if (text) { +// if (data.message?.author?.role == 'assistant') { +// if (params.prompt.indexOf('search query:') !== -1) { +// // this.renameConversationTitle(data.conversation_id, params) +// } +// console.debug( +// 'ChatGPTProvider:generateAnswerBySSE:answer:text(setupWSS:messageListener):', +// text, +// ) +// params.onEvent({ +// type: 'answer', +// data: { +// text, +// messageId: data.message.id, +// parentMessageId: data.parent_message_id, +// conversationId: data.conversation_id, +// }, +// }) +// } +// } +// }) +// // if (finalMessageStr.length - lastSendTextLen > 40) +// parser.feed(finalMessageStr) +// lastSendTextLen = finalMessageStr.length + +// const sequenceId = jjws['sequenceId'] +// console.log('ChatGPTProvider:doSendMessage:sequenceId:', sequenceId) +// if (sequenceId === next_check_seqid) { +// const t = { +// type: 'sequenceAck', +// sequenceId: next_check_seqid, +// } +// if (wsp.isOpened) { +// wsp.send(JSON.stringify(t)) +// next_check_seqid += Math.round(Math.random() * 50) +// } else { +// console.log('ChatGPTProvider:doSendMessage:WebSocket is not open:wsp, t:', wsp, t) +// } +// } +// } +// wsp.removeAllListeners() +// wsp.close() +// wsp.onOpen.addListener(openListener) +// wsp.onMessage.addListener(messageListener) +// wsp.onClose.removeListener(messageListener) +// wsp.open().catch(async (e) => { +// console.log('ChatGPTProvider:doSendMessage:open:showError:Error caught while opening ws', e) +// wsp.removeAllListeners() +// wsp.close() +// await setChatgptwssIsOpenFlag(false) +// params.onEvent({ type: 'error', message: (e as any)?.message }) +// }) +// } +// } + +// async generateAnswer(params: GenerateAnswerParams) { +// console.log('chatgpt', params.arkoseToken) +// let conversationId: string | undefined + +// const countWords = (text) => { +// return text.trim().split(/\s+/).length +// } + +// const getConversationTitle = (bigtext: string) => { +// let ret = bigtext.split('\n', 1)[0] +// ret = ret.split('.', 1)[0] +// ret = APPSHORTNAME + ':' + ret.split(':')[1].trim() +// console.log('getConversationTitle:', ret) +// return ret +// } + +// const cleanup = () => { +// if (conversationId) { +// // setConversationProperty(this.token, conversationId, { is_visible: false }) +// } +// } + +// const regResp = await this.registerWSS(params) +// await this.setupWSS(params, regResp) // Since params change WSS have to be setup up every time + +// const modelName = await this.getModelName() +// const chatRequirementsToken = await this.getChatRequirementsToken(params) +// console.debug('Using model:', modelName) + +// await fetchSSE('https://chatgpt.com/backend-api/conversation', { +// method: 'POST', +// signal: params.signal, +// headers: { +// 'Content-Type': 'application/json', +// Authorization: `Bearer ${this.token}`, +// 'Openai-Sentinel-Arkose-Token': params.arkoseToken, +// 'Openai-Sentinel-Chat-Requirements-Token': chatRequirementsToken, +// }, +// body: JSON.stringify({ +// action: 'next', +// messages: [ +// { +// id: uuidv4(), +// role: 'user', +// content: { +// content_type: 'text', +// parts: [params.prompt], +// }, +// }, +// ], +// model: modelName, +// parent_message_id: params.parentMessageId || uuidv4(), +// conversation_id: params.conversationId, +// arkose_token: params.arkoseToken, +// conversation_mode: { +// kind: 'primary_assistant', +// }, +// history_and_training_disabled: !1, +// force_paragen: !1, +// force_rate_limit: !1, +// suggestions: [], +// // websocket_request_id://TODO:still working without it +// }), +// onMessage(message: string) { +// console.debug('sse message', message) +// if (message === '[DONE]') { +// params.onEvent({ type: 'done' }) +// cleanup() +// return +// } +// let data +// try { +// data = JSON.parse(message) +// } catch (err) { +// console.error(err) +// return +// } +// const text = data.message?.content?.parts?.[0] +// if (text) { +// if (data.message?.author?.role == 'assistant') { +// if (params.prompt.indexOf('search query:') !== -1) { +// // this.renameConversationTitle(data.conversation_id) +// } +// } +// conversationId = data.conversation_id +// console.debug( +// 'ChatGPTProvider:generateAnswer:answer:text(setupWSS:messageListener):', +// text, +// ) +// params.onEvent({ +// type: 'answer', +// data: { +// text, +// messageId: data.message.id, +// parentMessageId: data.parent_message_id, +// conversationId: data.conversation_id, +// }, +// }) +// } +// }, +// }) +// return { cleanup } +// } +// } diff --git a/src/background/providers/chatgpt_new.ts b/src/background/providers/chatgpt_new.ts index 6e401c3..44be19d 100644 --- a/src/background/providers/chatgpt_new.ts +++ b/src/background/providers/chatgpt_new.ts @@ -1,435 +1,435 @@ -import dayjs from 'dayjs' -import ExpiryMap from 'expiry-map' -import { v4 as uuidv4 } from 'uuid' -import Browser from 'webextension-polyfill' -import { ADAY, APPSHORTNAME, HALFHOUR } from '../../utils/consts' -import { isDate } from '../../utils/parse' -import { fetchSSE } from '../fetch-sse' -import { GenerateAnswerParams, Provider } from '../types' -dayjs().format() +// import dayjs from 'dayjs' +// import ExpiryMap from 'expiry-map' +// import { v4 as uuidv4 } from 'uuid' +// import Browser from 'webextension-polyfill' +// import { ADAY, APPSHORTNAME, HALFHOUR } from '../../utils/consts' +// import { isDate } from '../../utils/parse' +// import { fetchSSE } from '../fetch-sse' +// import { GenerateAnswerParams, Provider } from '../types' +// dayjs().format() -async function request( - token: string, - method: string, - path: string, - data?: unknown, - callback?: unknown, -) { - return fetch(`https://chat.openai.com/backend-api${path}`, { - method, - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${token}`, - }, - body: data === undefined ? undefined : JSON.stringify(data), - }) - .then(function (response) { - console.log('fetch', token != null, method, path, 'response', response) - return response.json() - }) - .then(function (data) { - console.log('response data', data) - if (callback) callback(token, data) - }) - .catch((error) => { - console.error('fetch', token, method, path, 'error', error) - }) -} +// async function request( +// token: string, +// method: string, +// path: string, +// data?: unknown, +// callback?: unknown, +// ) { +// return fetch(`https://chatgpt.com/backend-api${path}`, { +// method, +// headers: { +// 'Content-Type': 'application/json', +// Authorization: `Bearer ${token}`, +// }, +// body: data === undefined ? undefined : JSON.stringify(data), +// }) +// .then(function (response) { +// console.log('fetch', token != null, method, path, 'response', response) +// return response.json() +// }) +// .then(function (data) { +// console.log('response data', data) +// if (callback) callback(token, data) +// }) +// .catch((error) => { +// console.error('fetch', token, method, path, 'error', error) +// }) +// } -export async function sendMessageFeedback(token: string, data: unknown) { - await request(token, 'POST', '/conversation/message_feedback', data) -} +// export async function sendMessageFeedback(token: string, data: unknown) { +// await request(token, 'POST', '/conversation/message_feedback', data) +// } -export async function setConversationProperty( - token: string, - conversationId: string, - propertyObject: object, -) { - await request(token, 'PATCH', `/conversation/${conversationId}`, propertyObject) -} -const browsertabIdConversationIdMap = new Map() -const windowIdConversationIdMap = new Map() +// export async function setConversationProperty( +// token: string, +// conversationId: string, +// propertyObject: object, +// ) { +// await request(token, 'PATCH', `/conversation/${conversationId}`, propertyObject) +// } +// const browsertabIdConversationIdMap = new Map() +// const windowIdConversationIdMap = new Map() -function deleteRecentConversations(token, data) { - const now = dayjs() - const startTime = dayjs(performance.timeOrigin) - console.log('startTime', startTime) - const convs = data.items - console.log('convs', convs) - for (let i = 0; i < convs.length; i++) { - const conv_i_time = dayjs(convs[i].create_time) - console.log( - 'conv' + i, - convs[i].id, - conv_i_time, - conv_i_time - startTime, - now - conv_i_time, - now - conv_i_time < ADAY, - ) - if ( - HALFHOUR < now - conv_i_time && - now - conv_i_time < ADAY && - convs[i].title.indexOf(APPSHORTNAME + ':') != -1 - ) { - setTimeout(function () { - console.log('Deleting', token != null, convs[i].id) - setConversationProperty(token, convs[i].id, { is_visible: false }) - const cloneBTCMap = new Map(browsertabIdConversationIdMap) - cloneBTCMap.forEach((ConversationId, tabId, map) => { - console.log('Looking for', ConversationId, tabId, 'in', map) - if (ConversationId == convs[i].id) { - console.log('Deleting ', ConversationId, tabId, 'from', map) - browsertabIdConversationIdMap.delete(tabid) - console.log( - 'browsertabIdConversationIdMap after Deleting ', - browsertabIdConversationIdMap, - ) - } - }) - const cloneWCMap = new Map(windowIdConversationIdMap) - cloneWCMap.forEach((conversationIdsConcatinated, windowId, map) => { - console.log('Looking for', conversationIdsConcatinated, windowId, 'in', map) - if (conversationIdsConcatinated.indexOf(convs[i].id) != -1) { - console.log('Deleting ', convs[i].id, windowId, 'from', map) - conversationIdsConcatinated = conversationIdsConcatinated.replace(convs[i].id, '') - conversationIdsConcatinated = conversationIdsConcatinated.replace(',,', ',') - windowIdConversationIdMap.set(windowid, conversationIdsConcatinated) - console.log('windowIdConversationIdMap after Deleting ', windowIdConversationIdMap) - } - }) - }, i * 1000) - } - } -} +// function deleteRecentConversations(token, data) { +// const now = dayjs() +// const startTime = dayjs(performance.timeOrigin) +// console.log('startTime', startTime) +// const convs = data.items +// console.log('convs', convs) +// for (let i = 0; i < convs.length; i++) { +// const conv_i_time = dayjs(convs[i].create_time) +// console.log( +// 'conv' + i, +// convs[i].id, +// conv_i_time, +// conv_i_time - startTime, +// now - conv_i_time, +// now - conv_i_time < ADAY, +// ) +// if ( +// HALFHOUR < now - conv_i_time && +// now - conv_i_time < ADAY && +// convs[i].title.indexOf(APPSHORTNAME + ':') != -1 +// ) { +// setTimeout(function () { +// console.log('Deleting', token != null, convs[i].id) +// setConversationProperty(token, convs[i].id, { is_visible: false }) +// const cloneBTCMap = new Map(browsertabIdConversationIdMap) +// cloneBTCMap.forEach((ConversationId, tabId, map) => { +// console.log('Looking for', ConversationId, tabId, 'in', map) +// if (ConversationId == convs[i].id) { +// console.log('Deleting ', ConversationId, tabId, 'from', map) +// browsertabIdConversationIdMap.delete(tabid) +// console.log( +// 'browsertabIdConversationIdMap after Deleting ', +// browsertabIdConversationIdMap, +// ) +// } +// }) +// const cloneWCMap = new Map(windowIdConversationIdMap) +// cloneWCMap.forEach((conversationIdsConcatinated, windowId, map) => { +// console.log('Looking for', conversationIdsConcatinated, windowId, 'in', map) +// if (conversationIdsConcatinated.indexOf(convs[i].id) != -1) { +// console.log('Deleting ', convs[i].id, windowId, 'from', map) +// conversationIdsConcatinated = conversationIdsConcatinated.replace(convs[i].id, '') +// conversationIdsConcatinated = conversationIdsConcatinated.replace(',,', ',') +// windowIdConversationIdMap.set(windowid, conversationIdsConcatinated) +// console.log('windowIdConversationIdMap after Deleting ', windowIdConversationIdMap) +// } +// }) +// }, i * 1000) +// } +// } +// } -const KEY_ACCESS_TOKEN = 'accessToken' +// const KEY_ACCESS_TOKEN = 'accessToken' -const cache = new ExpiryMap(10 * 1000) +// const cache = new ExpiryMap(10 * 1000) -export async function getChatGPTAccessToken(): Promise { - if (cache.get(KEY_ACCESS_TOKEN)) { - return cache.get(KEY_ACCESS_TOKEN) - } - const resp = await fetch('https://chat.openai.com/api/auth/session') - if (resp.status === 403) { - throw new Error('CLOUDFLARE') - } - const data = await resp.json().catch(() => ({})) - if (!data.accessToken) { - throw new Error('UNAUTHORIZED') - } - cache.set(KEY_ACCESS_TOKEN, data.accessToken) - return data.accessToken -} +// export async function getChatGPTAccessToken(): Promise { +// if (cache.get(KEY_ACCESS_TOKEN)) { +// return cache.get(KEY_ACCESS_TOKEN) +// } +// const resp = await fetch('https://chatgpt.com/api/auth/session') +// if (resp.status === 403) { +// throw new Error('CLOUDFLARE') +// } +// const data = await resp.json().catch(() => ({})) +// if (!data.accessToken) { +// throw new Error('UNAUTHORIZED') +// } +// cache.set(KEY_ACCESS_TOKEN, data.accessToken) +// return data.accessToken +// } -export class ChatGPTProvider implements Provider { - constructor(private token: string) { - this.token = token - Browser.tabs.onRemoved.addListener(function (tabid, removed) { - console.log('tab closed', tabid, removed) - const delConversationId = browsertabIdConversationIdMap.get(tabid) - console.log('delete conversation', delConversationId) - if (delConversationId) { - console.log('deleting conversation', delConversationId, 'token=', token) - try { - setConversationProperty(token, delConversationId, { is_visible: false }) - browsertabIdConversationIdMap.delete(tabid) - console.log('deleted conversation', delConversationId) - } catch (e) { - console.error( - 'deletion of conversation', - delConversationId, - 'token=', - token, - 'failed with error', - e, - ) - } - } +// export class ChatGPTProvider implements Provider { +// constructor(private token: string) { +// this.token = token +// Browser.tabs.onRemoved.addListener(function (tabid, removed) { +// console.log('tab closed', tabid, removed) +// const delConversationId = browsertabIdConversationIdMap.get(tabid) +// console.log('delete conversation', delConversationId) +// if (delConversationId) { +// console.log('deleting conversation', delConversationId, 'token=', token) +// try { +// setConversationProperty(token, delConversationId, { is_visible: false }) +// browsertabIdConversationIdMap.delete(tabid) +// console.log('deleted conversation', delConversationId) +// } catch (e) { +// console.error( +// 'deletion of conversation', +// delConversationId, +// 'token=', +// token, +// 'failed with error', +// e, +// ) +// } +// } - //Brute: - request( - token, - 'GET', - '/conversations?offset=0&limit=100&order=updated', - undefined, - deleteRecentConversations, - ) - }) +// //Brute: +// request( +// token, +// 'GET', +// '/conversations?offset=0&limit=100&order=updated', +// undefined, +// deleteRecentConversations, +// ) +// }) - Browser.windows.onRemoved.addListener(function (windowid) { - console.log('window closed', windowid) - let delConversationIdsConcatinated = windowIdConversationIdMap.get(windowid) - console.log('delete delConversationIdsConcatinated', delConversationIdsConcatinated) - if (delConversationIdsConcatinated) { - const delConversationIdsArray = delConversationIdsConcatinated.split(',') - for (let i = 0; i < delConversationIdsArray.length; i++) { - console.log('deleting conversation', delConversationIdsArray[i], 'token=', token) - try { - setConversationProperty(token, delConversationIdsArray[i], { is_visible: false }) - delConversationIdsConcatinated = delConversationIdsConcatinated.replace( - delConversationIdsArray[i], - '', - ) - delConversationIdsConcatinated = delConversationIdsConcatinated.replace(',,', ',') - windowIdConversationIdMap.set(windowid, delConversationIdsConcatinated) - console.log('deleted conversation:', delConversationIdsArray[i]) - } catch (e) { - console.error( - 'deletion of conversation', - delConversationId, - 'token=', - token, - 'failed with error', - e, - ) - } - } - if ( - windowIdConversationIdMap.get(windowid) == '' || - windowIdConversationIdMap.get(windowid) == ',' - ) { - windowIdConversationIdMap.delete(windowid) - console.log('deleted all conversations:', delConversationIdsArray) - } - } - }) - } +// Browser.windows.onRemoved.addListener(function (windowid) { +// console.log('window closed', windowid) +// let delConversationIdsConcatinated = windowIdConversationIdMap.get(windowid) +// console.log('delete delConversationIdsConcatinated', delConversationIdsConcatinated) +// if (delConversationIdsConcatinated) { +// const delConversationIdsArray = delConversationIdsConcatinated.split(',') +// for (let i = 0; i < delConversationIdsArray.length; i++) { +// console.log('deleting conversation', delConversationIdsArray[i], 'token=', token) +// try { +// setConversationProperty(token, delConversationIdsArray[i], { is_visible: false }) +// delConversationIdsConcatinated = delConversationIdsConcatinated.replace( +// delConversationIdsArray[i], +// '', +// ) +// delConversationIdsConcatinated = delConversationIdsConcatinated.replace(',,', ',') +// windowIdConversationIdMap.set(windowid, delConversationIdsConcatinated) +// console.log('deleted conversation:', delConversationIdsArray[i]) +// } catch (e) { +// console.error( +// 'deletion of conversation', +// delConversationId, +// 'token=', +// token, +// 'failed with error', +// e, +// ) +// } +// } +// if ( +// windowIdConversationIdMap.get(windowid) == '' || +// windowIdConversationIdMap.get(windowid) == ',' +// ) { +// windowIdConversationIdMap.delete(windowid) +// console.log('deleted all conversations:', delConversationIdsArray) +// } +// } +// }) +// } - private async fetchModels(): Promise< - { slug: string; title: string; description: string; max_tokens: number }[] - > { - const resp = await request(this.token, 'GET', '/models').then((r) => r.json()) - return resp.models - } +// private async fetchModels(): Promise< +// { slug: string; title: string; description: string; max_tokens: number }[] +// > { +// const resp = await request(this.token, 'GET', '/models').then((r) => r.json()) +// return resp.models +// } - private async getModelName(): Promise { - try { - const models = await this.fetchModels() - return models[0].slug - } catch (err) { - console.error(err) - return 'text-davinci-002-render' - } - } +// private async getModelName(): Promise { +// try { +// const models = await this.fetchModels() +// return models[0].slug +// } catch (err) { +// console.error(err) +// return 'text-davinci-002-render' +// } +// } - async generateAnswer(params: GenerateAnswerParams) { - let conversationId: string | undefined +// async generateAnswer(params: GenerateAnswerParams) { +// let conversationId: string | undefined - const countWords = (text) => { - return text.trim().split(/\s+/).length - } +// const countWords = (text) => { +// return text.trim().split(/\s+/).length +// } - const rememberConversationTab = (convId: string) => { - Browser.tabs.query({ active: true, lastFocusedWindow: true }).then(async (tabs) => { - console.log('tabs:', tabs) - for (let i = 0; i < tabs.length; i++) { - if (tabs[i].active == true) { - const oldConvId = browsertabIdConversationIdMap.get(tabs[i].id) - if (oldConvId && oldConvId != convId) { - console.log( - 'Already this tab has some conversationId.', - oldConvId, - 'We have to delete that conversationTab first', - ) - try { - setConversationProperty(this.token, oldConvId, { is_visible: false }) - } catch (e) { - console.log('Deletion of ', oldConvId, ' failed with error', e) - } - } - browsertabIdConversationIdMap.set(tabs[i].id, convId) - } - } - console.log( - 'rememberConversationTab:browsertabIdConversationIdMap:', - browsertabIdConversationIdMap, - ) - }) - } +// const rememberConversationTab = (convId: string) => { +// Browser.tabs.query({ active: true, lastFocusedWindow: true }).then(async (tabs) => { +// console.log('tabs:', tabs) +// for (let i = 0; i < tabs.length; i++) { +// if (tabs[i].active == true) { +// const oldConvId = browsertabIdConversationIdMap.get(tabs[i].id) +// if (oldConvId && oldConvId != convId) { +// console.log( +// 'Already this tab has some conversationId.', +// oldConvId, +// 'We have to delete that conversationTab first', +// ) +// try { +// setConversationProperty(this.token, oldConvId, { is_visible: false }) +// } catch (e) { +// console.log('Deletion of ', oldConvId, ' failed with error', e) +// } +// } +// browsertabIdConversationIdMap.set(tabs[i].id, convId) +// } +// } +// console.log( +// 'rememberConversationTab:browsertabIdConversationIdMap:', +// browsertabIdConversationIdMap, +// ) +// }) +// } - const rememberConversationWindow = (convId: string) => { - Browser.windows.getAll({}).then(async (windows) => { - console.log('windows:', windows) - for (let i = 0; i < windows.length; i++) { - if (windows[i].focused == true) { - const alreadyConversationIdsInWindow = windowIdConversationIdMap.get(windows[i].id) - if (alreadyConversationIdsInWindow) { - if (alreadyConversationIdsInWindow.indexOf(convId) == -1) - windowIdConversationIdMap.set( - windows[i].id, - alreadyConversationIdsInWindow + ',' + convId, - ) - } else { - windowIdConversationIdMap.set(windows[i].id, convId) - } - } - } - console.log( - 'rememberConversationWindow:windowIdConversationIdMap:', - windowIdConversationIdMap, - ) - }) - } +// const rememberConversationWindow = (convId: string) => { +// Browser.windows.getAll({}).then(async (windows) => { +// console.log('windows:', windows) +// for (let i = 0; i < windows.length; i++) { +// if (windows[i].focused == true) { +// const alreadyConversationIdsInWindow = windowIdConversationIdMap.get(windows[i].id) +// if (alreadyConversationIdsInWindow) { +// if (alreadyConversationIdsInWindow.indexOf(convId) == -1) +// windowIdConversationIdMap.set( +// windows[i].id, +// alreadyConversationIdsInWindow + ',' + convId, +// ) +// } else { +// windowIdConversationIdMap.set(windows[i].id, convId) +// } +// } +// } +// console.log( +// 'rememberConversationWindow:windowIdConversationIdMap:', +// windowIdConversationIdMap, +// ) +// }) +// } - const getConversationTitle = (bigtext: string) => { - let ret = bigtext.split('\n', 1)[0] - ret = ret.split('.', 1)[0] - ret = APPSHORTNAME + ':' + ret.split(':')[1].trim() - console.log('getConversationTitle:', ret) - return ret - } +// const getConversationTitle = (bigtext: string) => { +// let ret = bigtext.split('\n', 1)[0] +// ret = ret.split('.', 1)[0] +// ret = APPSHORTNAME + ':' + ret.split(':')[1].trim() +// console.log('getConversationTitle:', ret) +// return ret +// } - const renameConversationTitle = (convId: string) => { - const titl: string = getConversationTitle(params.prompt) - console.log('renameConversationTitle:', this.token, convId, titl) - setConversationProperty(this.token, convId, { title: titl }) - } +// const renameConversationTitle = (convId: string) => { +// const titl: string = getConversationTitle(params.prompt) +// console.log('renameConversationTitle:', this.token, convId, titl) +// setConversationProperty(this.token, convId, { title: titl }) +// } - const cleanup = () => { - if (conversationId) { - setConversationProperty(this.token, conversationId, { is_visible: false }) - } - } +// const cleanup = () => { +// if (conversationId) { +// setConversationProperty(this.token, conversationId, { is_visible: false }) +// } +// } - const modelName = await this.getModelName() - console.log('Using model:', modelName, params.conversationId, params.parentMessageId) +// const modelName = await this.getModelName() +// console.log('Using model:', modelName, params.conversationId, params.parentMessageId) - const callfetchSSE = async (conversationId: string, with_conversation_id: bool) => { - try { - await fetchSSE('https://chat.openai.com/backend-api/conversation', { - method: 'POST', - signal: params.signal, - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${this.token}`, - }, - body: JSON.stringify({ - action: 'next', - messages: [ - { - id: uuidv4(), - role: 'user', - content: { - content_type: 'text', - parts: [params.prompt], - }, - }, - ], - model: modelName, - parent_message_id: params.parentMessageId || uuidv4(), - conversation_id: with_conversation_id ? params.conversationId : undefined, - arkose_token: params.arkoseToken, - }), - onMessage(message) { - console.debug('sse message', message) - if (message === '[DONE]') { - params.onEvent({ type: 'done' }) - return - } - let data - try { - data = JSON.parse(message) - } catch (err) { - if (isDate(message)) { - console.log("known error, It's date", message) - } else { - console.log(err) - console.log(message) - } - return - } - console.debug('sse message.message', data.message) - console.log('sse message.conversation_id:', data.conversation_id) - const text = data.message?.content?.parts?.[0] + '✏' - if (text) { - if (countWords(text) == 1 && data.message.author.role == 'assistant') { - if ( - data.conversation_id && - ((conversationId && conversationId != data.conversation_id) || - conversationId == null) - ) { - if (params.prompt.indexOf('search query:') !== -1) { - renameConversationTitle(data.conversation_id) - } - } - rememberConversationTab(data.conversation_id) - rememberConversationWindow(data.conversation_id) - } - if (data.message.author.role == 'assistant') { - conversationId = data.conversation_id - params.onEvent({ - type: 'answer', - data: { - text, - messageId: data.message.id, - conversationId: data.conversation_id, - parentMessageId: data.parent_message_id, - }, - }) - } - } - }, - }) - } catch (e) { - if (e.message.indexOf('Only one message at a time') != -1) { - console.log('known error, Only one message at a time', e.message) - params.onEvent({ - type: 'error', - data: { - error: - 'Only one message at a time. Please reload the page once the active message completes', - conversationId: conversationId, - }, - }) - } else if (e.message.indexOf('ve reached our limit of messages per hour') != -1) { - console.log('known error, Reached our limit of messages per hour', e.message) - params.onEvent({ - type: 'error', - data: { - error: 'You have reached our limit of messages per hour. Please try again later', - conversationId: conversationId, - }, - }) - } else { - console.error(e.message) - if (e.message.indexOf('conversation_not_found') != -1) { - throw new Error(e.message) - } - } - } - } +// const callfetchSSE = async (conversationId: string, with_conversation_id: bool) => { +// try { +// await fetchSSE('https://chatgpt.com/backend-api/conversation', { +// method: 'POST', +// signal: params.signal, +// headers: { +// 'Content-Type': 'application/json', +// Authorization: `Bearer ${this.token}`, +// }, +// body: JSON.stringify({ +// action: 'next', +// messages: [ +// { +// id: uuidv4(), +// role: 'user', +// content: { +// content_type: 'text', +// parts: [params.prompt], +// }, +// }, +// ], +// model: modelName, +// parent_message_id: params.parentMessageId || uuidv4(), +// conversation_id: with_conversation_id ? params.conversationId : undefined, +// arkose_token: params.arkoseToken, +// }), +// onMessage(message) { +// console.debug('sse message', message) +// if (message === '[DONE]') { +// params.onEvent({ type: 'done' }) +// return +// } +// let data +// try { +// data = JSON.parse(message) +// } catch (err) { +// if (isDate(message)) { +// console.log("known error, It's date", message) +// } else { +// console.log(err) +// console.log(message) +// } +// return +// } +// console.debug('sse message.message', data.message) +// console.log('sse message.conversation_id:', data.conversation_id) +// const text = data.message?.content?.parts?.[0] + '✏' +// if (text) { +// if (countWords(text) == 1 && data.message.author.role == 'assistant') { +// if ( +// data.conversation_id && +// ((conversationId && conversationId != data.conversation_id) || +// conversationId == null) +// ) { +// if (params.prompt.indexOf('search query:') !== -1) { +// renameConversationTitle(data.conversation_id) +// } +// } +// rememberConversationTab(data.conversation_id) +// rememberConversationWindow(data.conversation_id) +// } +// if (data.message.author.role == 'assistant') { +// conversationId = data.conversation_id +// params.onEvent({ +// type: 'answer', +// data: { +// text, +// messageId: data.message.id, +// conversationId: data.conversation_id, +// parentMessageId: data.parent_message_id, +// }, +// }) +// } +// } +// }, +// }) +// } catch (e) { +// if (e.message.indexOf('Only one message at a time') != -1) { +// console.log('known error, Only one message at a time', e.message) +// params.onEvent({ +// type: 'error', +// data: { +// error: +// 'Only one message at a time. Please reload the page once the active message completes', +// conversationId: conversationId, +// }, +// }) +// } else if (e.message.indexOf('ve reached our limit of messages per hour') != -1) { +// console.log('known error, Reached our limit of messages per hour', e.message) +// params.onEvent({ +// type: 'error', +// data: { +// error: 'You have reached our limit of messages per hour. Please try again later', +// conversationId: conversationId, +// }, +// }) +// } else { +// console.error(e.message) +// if (e.message.indexOf('conversation_not_found') != -1) { +// throw new Error(e.message) +// } +// } +// } +// } - let retry_due_to_conversation_not_found: bool = false - callfetchSSE(conversationId, true) - .then((r) => { - console.log(r) - }) - .catch((e) => { - console.log(e) - console.error(e.message) - if (e.message.indexOf('conversation_not_found') !== -1) { - retry_due_to_conversation_not_found = true - console.log('Lets retry_due_to_conversation_not_found') - } - if (retry_due_to_conversation_not_found) { - cleanup() - callfetchSSE(conversationId, false) - .then((r) => { - console.log(r) - retry_due_to_conversation_not_found = false - }) - .catch((e) => { - console.log(e) - console.error(e.message) - if (e.message.indexOf('conversation_not_found') !== -1) { - retry_due_to_conversation_not_found = true - console.log('Its still conversation_not_found') - } - }) - } - }) +// let retry_due_to_conversation_not_found: bool = false +// callfetchSSE(conversationId, true) +// .then((r) => { +// console.log(r) +// }) +// .catch((e) => { +// console.log(e) +// console.error(e.message) +// if (e.message.indexOf('conversation_not_found') !== -1) { +// retry_due_to_conversation_not_found = true +// console.log('Lets retry_due_to_conversation_not_found') +// } +// if (retry_due_to_conversation_not_found) { +// cleanup() +// callfetchSSE(conversationId, false) +// .then((r) => { +// console.log(r) +// retry_due_to_conversation_not_found = false +// }) +// .catch((e) => { +// console.log(e) +// console.error(e.message) +// if (e.message.indexOf('conversation_not_found') !== -1) { +// retry_due_to_conversation_not_found = true +// console.log('Its still conversation_not_found') +// } +// }) +// } +// }) - return { cleanup } - } -} +// return { cleanup } +// } +// } diff --git a/src/content-script/ChatGPTQuery.tsx b/src/content-script/ChatGPTQuery.tsx index 68c1c2d..9531282 100644 --- a/src/content-script/ChatGPTQuery.tsx +++ b/src/content-script/ChatGPTQuery.tsx @@ -349,7 +349,7 @@ function ChatGPTQuery(props: Props) { return (

Please login and pass Cloudflare check at{' '} - + chat.openai.com {retry > 0 && diff --git a/src/manifest.json b/src/manifest.json index b8c2718..4c0ea98 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -10,7 +10,11 @@ "48": "logo.png", "128": "logo.png" }, - "host_permissions": ["https://*.openai.com/", "https://*.google.com/"], + "host_permissions": [ + "https://*.openai.com/", + "https://*.chatgpt.com/", + "https://*.google.com/" + ], "permissions": ["storage"], "background": { "service_worker": "background.js" diff --git a/src/manifest.v2.json b/src/manifest.v2.json index 4330b46..a70b9c9 100644 --- a/src/manifest.v2.json +++ b/src/manifest.v2.json @@ -10,7 +10,12 @@ "48": "logo.png", "128": "logo.png" }, - "permissions": ["storage", "https://*.openai.com/", "https://*.google.com/"], + "permissions": [ + "storage", + "https://*.openai.com/", + "https://*.chatgpt.com/", + "https://*.google.com/" + ], "background": { "scripts": ["background.js"] }, diff --git a/src/popup/App.tsx b/src/popup/App.tsx index f8a1c67..b77b2e7 100644 --- a/src/popup/App.tsx +++ b/src/popup/App.tsx @@ -55,13 +55,13 @@ function App() { ) } if (accessTokenQuery.data) { - return