diff --git a/api/server/routes/ask/askBingAI.js b/api/server/routes/ask/askBingAI.js index c8d1fd0755..6a1fe8d770 100644 --- a/api/server/routes/ask/askBingAI.js +++ b/api/server/routes/ask/askBingAI.js @@ -35,21 +35,21 @@ router.post('/', async (req, res) => { let endpointOption = {}; if (req.body?.jailbreak) endpointOption = { - jailbreak: req.body?.jailbreak || false, - jailbreakConversationId: req.body?.jailbreakConversationId || null, - systemMessage: req.body?.systemMessage || null, - context: req.body?.context || null, - toneStyle: req.body?.toneStyle || 'fast' + jailbreak: req.body?.jailbreak ?? false, + jailbreakConversationId: req.body?.jailbreakConversationId ?? null, + systemMessage: req.body?.systemMessage ?? null, + context: req.body?.context ?? null, + toneStyle: req.body?.toneStyle ?? 'fast' }; else endpointOption = { - jailbreak: req.body?.jailbreak || false, - systemMessage: req.body?.systemMessage || null, - context: req.body?.context || null, - conversationSignature: req.body?.conversationSignature || null, - clientId: req.body?.clientId || null, - invocationId: req.body?.invocationId || null, - toneStyle: req.body?.toneStyle || 'fast' + jailbreak: req.body?.jailbreak ?? false, + systemMessage: req.body?.systemMessage ?? null, + context: req.body?.context ?? null, + conversationSignature: req.body?.conversationSignature ?? null, + clientId: req.body?.clientId ?? null, + invocationId: req.body?.invocationId ?? null, + toneStyle: req.body?.toneStyle ?? 'fast' }; console.log('ask log', { @@ -122,31 +122,23 @@ const ask = async ({ console.log('BING RESPONSE', response); + const newConversationId = endpointOption?.jailbreak + ? response.jailbreakConversationId + : response.conversationId || conversationId; + const newUserMassageId = response.parentMessageId || userMessageId; + const newResponseMessageId = response.parentMessageId || response.details.requestId || userMessageId; + // STEP1 generate response message response.text = response.response || response.details.spokenText || '**Bing refused to answer.**'; let responseMessage = { + conversationId: newConversationId, + messageId: newResponseMessageId, + parentMessageId: overrideParentMessageId || newUserMassageId, + sender: endpointOption?.jailbreak ? 'Sydney' : 'BingAI', text: await handleText(response, true), - suggestions: - response.details.suggestedResponses && response.details.suggestedResponses.map(s => s.text), - jailbreak: endpointOption?.jailbreak + suggestions: response.details.suggestedResponses && response.details.suggestedResponses.map(s => s.text) }; - // // response.text = await handleText(response, true); - // response.suggestions = - // response.details.suggestedResponses && response.details.suggestedResponses.map(s => s.text); - - if (endpointOption?.jailbreak) { - responseMessage.conversationId = response.jailbreakConversationId; - responseMessage.messageId = response.messageId || response.details.messageId; - responseMessage.parentMessageId = overrideParentMessageId || response.parentMessageId || userMessageId; - responseMessage.sender = 'Sydney'; - } else { - responseMessage.conversationId = response.conversationId; - responseMessage.messageId = response.messageId || response.details.messageId; - responseMessage.parentMessageId = - overrideParentMessageId || response.parentMessageId || response.details.requestId || userMessageId; - responseMessage.sender = 'BingAI'; - } await saveMessage(responseMessage); @@ -159,14 +151,22 @@ const ask = async ({ // Attition: the api will also create new conversationId while using invalid userMessage.parentMessageId, // but in this situation, don't change the conversationId, but create new convo. - let conversationUpdate = { conversationId, endpoint: 'bingAI' }; - if (conversationId != responseMessage.conversationId && isNewConversation) - conversationUpdate = { - ...conversationUpdate, - conversationId: conversationId, - newConversationId: responseMessage.conversationId || conversationId - }; - conversationId = responseMessage.conversationId || conversationId; + let conversationUpdate = { conversationId: newConversationId, endpoint: 'bingAI' }; + if (conversationId != newConversationId) + if (isNewConversation) { + // change the conversationId to new one + conversationUpdate = { + ...conversationUpdate, + conversationId: conversationId, + newConversationId: newConversationId + }; + } else { + // create new conversation + conversationUpdate = { + ...conversationUpdate, + ...endpointOption + }; + } if (endpointOption?.jailbreak) { conversationUpdate.jailbreak = true; @@ -179,17 +179,16 @@ const ask = async ({ } await saveConvo(req?.session?.user?.username, conversationUpdate); + conversationId = newConversationId; // STEP3 update the user message - userMessage.conversationId = conversationId; - userMessage.messageId = responseMessage.parentMessageId; + userMessage.conversationId = newConversationId; + userMessage.messageId = newUserMassageId; // If response has parentMessageId, the fake userMessage.messageId should be updated to the real one. - if (!overrideParentMessageId) { - const oldUserMessageId = userMessageId; - await saveMessage({ ...userMessage, messageId: oldUserMessageId, newMessageId: userMessage.messageId }); - } - userMessageId = userMessage.messageId; + if (!overrideParentMessageId) + await saveMessage({ ...userMessage, messageId: userMessageId, newMessageId: newUserMassageId }); + userMessageId = newUserMassageId; sendMessage(res, { title: await getConvoTitle(req?.session?.user?.username, conversationId), diff --git a/api/server/routes/ask/askChatGPTBrowser.js b/api/server/routes/ask/askChatGPTBrowser.js index 77968d8597..4592ab98b4 100644 --- a/api/server/routes/ask/askChatGPTBrowser.js +++ b/api/server/routes/ask/askChatGPTBrowser.js @@ -33,7 +33,7 @@ router.post('/', async (req, res) => { // build endpoint option const endpointOption = { - model: req.body?.model || 'text-davinci-002-render-sha' + model: req.body?.model ?? 'text-davinci-002-render-sha' }; const availableModels = getChatGPTBrowserModels(); @@ -106,13 +106,17 @@ const ask = async ({ console.log('CLIENT RESPONSE', response); + const newConversationId = response.conversationId || conversationId; + const newUserMassageId = response.parentMessageId || userMessageId; + const newResponseMessageId = response.messageId; + // STEP1 generate response message response.text = response.response || '**ChatGPT refused to answer.**'; let responseMessage = { - conversationId: response.conversationId, - messageId: response.messageId, - parentMessageId: overrideParentMessageId || response.parentMessageId || userMessageId, + conversationId: newConversationId, + messageId: newResponseMessageId, + parentMessageId: overrideParentMessageId || newUserMassageId, text: await handleText(response), sender: endpointOption?.chatGptLabel || 'ChatGPT' }; @@ -122,27 +126,34 @@ const ask = async ({ // STEP2 update the conversation // First update conversationId if needed - let conversationUpdate = { conversationId, endpoint: 'chatGPTBrowser' }; - if (conversationId != responseMessage.conversationId && isNewConversation) - conversationUpdate = { - ...conversationUpdate, - conversationId: conversationId, - newConversationId: responseMessage.conversationId || conversationId - }; - conversationId = responseMessage.conversationId || conversationId; + let conversationUpdate = { conversationId: newConversationId, endpoint: 'chatGPTBrowser' }; + if (conversationId != newConversationId) + if (isNewConversation) { + // change the conversationId to new one + conversationUpdate = { + ...conversationUpdate, + conversationId: conversationId, + newConversationId: newConversationId + }; + } else { + // create new conversation + conversationUpdate = { + ...conversationUpdate, + ...endpointOption + }; + } await saveConvo(req?.session?.user?.username, conversationUpdate); + conversationId = newConversationId; // STEP3 update the user message - userMessage.conversationId = conversationId; - userMessage.messageId = responseMessage.parentMessageId; + userMessage.conversationId = newConversationId; + userMessage.messageId = newUserMassageId; // If response has parentMessageId, the fake userMessage.messageId should be updated to the real one. - if (!overrideParentMessageId) { - const oldUserMessageId = userMessageId; - await saveMessage({ ...userMessage, messageId: oldUserMessageId, newMessageId: userMessage.messageId }); - } - userMessageId = userMessage.messageId; + if (!overrideParentMessageId) + await saveMessage({ ...userMessage, messageId: userMessageId, newMessageId: newUserMassageId }); + userMessageId = newUserMassageId; sendMessage(res, { title: await getConvoTitle(req?.session?.user?.username, conversationId), diff --git a/api/server/routes/ask/askOpenAI.js b/api/server/routes/ask/askOpenAI.js index e44a059090..9c5d121639 100644 --- a/api/server/routes/ask/askOpenAI.js +++ b/api/server/routes/ask/askOpenAI.js @@ -19,6 +19,7 @@ router.post('/', async (req, res) => { // build user message const conversationId = oldConversationId || crypto.randomUUID(); + const isNewConversation = !oldConversationId; const userMessageId = crypto.randomUUID(); const userParentMessageId = parentMessageId || '00000000-0000-0000-0000-000000000000'; const userMessage = { @@ -32,13 +33,13 @@ router.post('/', async (req, res) => { // build endpoint option const endpointOption = { - model: req.body?.model || 'gpt-3.5-turbo', - chatGptLabel: req.body?.chatGptLabel || null, - promptPrefix: req.body?.promptPrefix || null, - temperature: req.body?.temperature || 1, - top_p: req.body?.top_p || 1, - presence_penalty: req.body?.presence_penalty || 0, - frequency_penalty: req.body?.frequency_penalty || 0 + model: req.body?.model ?? 'gpt-3.5-turbo', + chatGptLabel: req.body?.chatGptLabel ?? null, + promptPrefix: req.body?.promptPrefix ?? null, + temperature: req.body?.temperature ?? 1, + top_p: req.body?.top_p ?? 1, + presence_penalty: req.body?.presence_penalty ?? 0, + frequency_penalty: req.body?.frequency_penalty ?? 0 }; const availableModels = getOpenAIModels(); @@ -63,6 +64,7 @@ router.post('/', async (req, res) => { // eslint-disable-next-line no-use-before-define return await ask({ + isNewConversation, userMessage, endpointOption, conversationId, @@ -74,6 +76,7 @@ router.post('/', async (req, res) => { }); const ask = async ({ + isNewConversation, userMessage, endpointOption, conversationId, @@ -84,8 +87,6 @@ const ask = async ({ }) => { let { text, parentMessageId: userParentMessageId, messageId: userMessageId } = userMessage; - const client = askClient; - res.writeHead(200, { Connection: 'keep-alive', 'Content-Type': 'text/event-stream', @@ -100,7 +101,7 @@ const ask = async ({ const progressCallback = createOnProgress(); const abortController = new AbortController(); res.on('close', () => abortController.abort()); - let response = await client({ + let response = await askClient({ text, parentMessageId: userParentMessageId, conversationId, @@ -115,13 +116,17 @@ const ask = async ({ console.log('CLIENT RESPONSE', response); + const newConversationId = response.conversationId || conversationId; + const newUserMassageId = response.parentMessageId || userMessageId; + const newResponseMessageId = response.messageId; + // STEP1 generate response message response.text = response.response || '**ChatGPT refused to answer.**'; let responseMessage = { - conversationId: response.conversationId, - messageId: response.messageId, - parentMessageId: overrideParentMessageId || userMessageId, + conversationId: newConversationId, + messageId: newResponseMessageId, + parentMessageId: overrideParentMessageId || newUserMassageId, text: await handleText(response), sender: endpointOption?.chatGptLabel || 'ChatGPT' }; @@ -129,21 +134,34 @@ const ask = async ({ await saveMessage(responseMessage); // STEP2 update the conversation - conversationId = responseMessage.conversationId || conversationId; - // it seems openAI will not change the conversationId. - // let conversationUpdate = { conversationId, endpoint: 'openAI' }; - // await saveConvo(req?.session?.user?.username, conversationUpdate); + let conversationUpdate = { conversationId: newConversationId, endpoint: 'openAI' }; + if (conversationId != newConversationId) + if (isNewConversation) { + // change the conversationId to new one + conversationUpdate = { + ...conversationUpdate, + conversationId: conversationId, + newConversationId: newConversationId + }; + } else { + // create new conversation + conversationUpdate = { + ...conversationUpdate, + ...endpointOption + }; + } + + await saveConvo(req?.session?.user?.username, conversationUpdate); + conversationId = newConversationId; // STEP3 update the user message - userMessage.conversationId = conversationId; - userMessage.messageId = responseMessage.parentMessageId; + userMessage.conversationId = newConversationId; + userMessage.messageId = newUserMassageId; // If response has parentMessageId, the fake userMessage.messageId should be updated to the real one. - if (!overrideParentMessageId) { - const oldUserMessageId = userMessageId; - await saveMessage({ ...userMessage, messageId: oldUserMessageId, newMessageId: userMessage.messageId }); - } - userMessageId = userMessage.messageId; + if (!overrideParentMessageId) + await saveMessage({ ...userMessage, messageId: userMessageId, newMessageId: newUserMassageId }); + userMessageId = newUserMassageId; sendMessage(res, { title: await getConvoTitle(req?.session?.user?.username, conversationId), diff --git a/client/package-lock.json b/client/package-lock.json index c6e98e5742..8db0845566 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -28,8 +28,11 @@ "clsx": "^1.2.1", "copy-to-clipboard": "^3.3.3", "crypto-browserify": "^3.12.0", + "downloadjs": "^1.4.7", "esbuild": "0.17.15", "export-from-json": "^1.7.2", + "filenamify": "^5.1.1", + "html2canvas": "^1.4.1", "lodash": "^4.17.21", "lucide-react": "^0.113.0", "rc-input-number": "^7.4.2", @@ -53,6 +56,7 @@ "tailwindcss-animate": "^1.0.5", "tailwindcss-radix": "^2.8.0", "url": "^0.11.0", + "use-react-screenshot": "github:danny-avila/use-react-screenshot#master", "uuidv4": "^6.2.13" }, "devDependencies": { @@ -2316,321 +2320,6 @@ "node": ">=10.0.0" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.15.tgz", - "integrity": "sha512-sRSOVlLawAktpMvDyJIkdLI/c/kdRTOqo8t6ImVxg8yT7LQDUYV5Rp2FKeEosLr6ZCja9UjYAzyRSxGteSJPYg==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.15.tgz", - "integrity": "sha512-0kOB6Y7Br3KDVgHeg8PRcvfLkq+AccreK///B4Z6fNZGr/tNHX0z2VywCc7PTeWp+bPvjA5WMvNXltHw5QjAIA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.15.tgz", - "integrity": "sha512-MzDqnNajQZ63YkaUWVl9uuhcWyEyh69HGpMIrf+acR4otMkfLJ4sUCxqwbCyPGicE9dVlrysI3lMcDBjGiBBcQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.15.tgz", - "integrity": "sha512-7siLjBc88Z4+6qkMDxPT2juf2e8SJxmsbNVKFY2ifWCDT72v5YJz9arlvBw5oB4W/e61H1+HDB/jnu8nNg0rLA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.15.tgz", - "integrity": "sha512-NbImBas2rXwYI52BOKTW342Tm3LTeVlaOQ4QPZ7XuWNKiO226DisFk/RyPk3T0CKZkKMuU69yOvlapJEmax7cg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.15.tgz", - "integrity": "sha512-Xk9xMDjBVG6CfgoqlVczHAdJnCs0/oeFOspFap5NkYAmRCT2qTn1vJWA2f419iMtsHSLm+O8B6SLV/HlY5cYKg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.15.tgz", - "integrity": "sha512-3TWAnnEOdclvb2pnfsTWtdwthPfOz7qAfcwDLcfZyGJwm1SRZIMOeB5FODVhnM93mFSPsHB9b/PmxNNbSnd0RQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.15.tgz", - "integrity": "sha512-MLTgiXWEMAMr8nmS9Gigx43zPRmEfeBfGCwxFQEMgJ5MC53QKajaclW6XDPjwJvhbebv+RzK05TQjvH3/aM4Xw==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.15.tgz", - "integrity": "sha512-T0MVnYw9KT6b83/SqyznTs/3Jg2ODWrZfNccg11XjDehIved2oQfrX/wVuev9N936BpMRaTR9I1J0tdGgUgpJA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.15.tgz", - "integrity": "sha512-wp02sHs015T23zsQtU4Cj57WiteiuASHlD7rXjKUyAGYzlOKDAjqK6bk5dMi2QEl/KVOcsjwL36kD+WW7vJt8Q==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.15.tgz", - "integrity": "sha512-k7FsUJjGGSxwnBmMh8d7IbObWu+sF/qbwc+xKZkBe/lTAF16RqxRCnNHA7QTd3oS2AfGBAnHlXL67shV5bBThQ==", - "cpu": [ - "loong64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.15.tgz", - "integrity": "sha512-ZLWk6czDdog+Q9kE/Jfbilu24vEe/iW/Sj2d8EVsmiixQ1rM2RKH2n36qfxK4e8tVcaXkvuV3mU5zTZviE+NVQ==", - "cpu": [ - "mips64el" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.15.tgz", - "integrity": "sha512-mY6dPkIRAiFHRsGfOYZC8Q9rmr8vOBZBme0/j15zFUKM99d4ILY4WpOC7i/LqoY+RE7KaMaSfvY8CqjJtuO4xg==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.15.tgz", - "integrity": "sha512-EcyUtxffdDtWjjwIH8sKzpDRLcVtqANooMNASO59y+xmqqRYBBM7xVLQhqF7nksIbm2yHABptoioS9RAbVMWVA==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.15.tgz", - "integrity": "sha512-BuS6Jx/ezxFuHxgsfvz7T4g4YlVrmCmg7UAwboeyNNg0OzNzKsIZXpr3Sb/ZREDXWgt48RO4UQRDBxJN3B9Rbg==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.15.tgz", - "integrity": "sha512-JsdS0EgEViwuKsw5tiJQo9UdQdUJYuB+Mf6HxtJSPN35vez1hlrNb1KajvKWF5Sa35j17+rW1ECEO9iNrIXbNg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.15.tgz", - "integrity": "sha512-R6fKjtUysYGym6uXf6qyNephVUQAGtf3n2RCsOST/neIwPqRWcnc3ogcielOd6pT+J0RDR1RGcy0ZY7d3uHVLA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.15.tgz", - "integrity": "sha512-mVD4PGc26b8PI60QaPUltYKeSX0wxuy0AltC+WCTFwvKCq2+OgLP4+fFd+hZXzO2xW1HPKcytZBdjqL6FQFa7w==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.15.tgz", - "integrity": "sha512-U6tYPovOkw3459t2CBwGcFYfFRjivcJJc1WC8Q3funIwX8x4fP+R6xL/QuTPNGOblbq/EUDxj9GU+dWKX0oWlQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.15.tgz", - "integrity": "sha512-W+Z5F++wgKAleDABemiyXVnzXgvRFs+GVKThSI+mGgleLWluv0D7Diz4oQpgdpNzh4i2nNDzQtWbjJiqutRp6Q==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.15.tgz", - "integrity": "sha512-Muz/+uGgheShKGqSVS1KsHtCyEzcdOn/W/Xbh6H91Etm+wiIfwZaBn1W58MeGtfI8WA961YMHFYTthBdQs4t+w==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@esbuild/win32-x64": { "version": "0.17.15", "cpu": [ @@ -2747,8 +2436,7 @@ }, "node_modules/@headlessui/react": { "version": "1.7.13", - "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.13.tgz", - "integrity": "sha512-9n+EQKRtD9266xIHXdY5MfiXPDfYwl7zBM7KOx2Ae3Gdgxy8QML1FkCMjq6AsOf0l6N9uvI4HcFtuFlenaldKg==", + "license": "MIT", "dependencies": { "client-only": "^0.0.1" }, @@ -2997,8 +2685,7 @@ }, "node_modules/@radix-ui/number": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.0.tgz", - "integrity": "sha512-Ofwh/1HX69ZfJRiRBMTy7rgjAzHmwe4kW9C9Y99HTRUcYLUuVT0KESFj15rPjRgKJs20GPq8Bm5aEDJ8DuA3vA==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.13.10" } @@ -3041,8 +2728,7 @@ }, "node_modules/@radix-ui/react-checkbox": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.0.3.tgz", - "integrity": "sha512-55B8/vKzTuzxllH5sGJO4zaBf9gYpJuJRRzaOKm+0oAefRnMvbf+Kgww7IOANVN0w3z7agFJgtnXaZl8Uj95AA==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.0.0", @@ -3189,8 +2875,7 @@ }, "node_modules/@radix-ui/react-hover-card": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.0.5.tgz", - "integrity": "sha512-jXRuZEkxSWdHZbVyL0J46cm7pQjmOMpwJEFKY+VqAJnV+FxS+zIZExI1OCeIiDwCBzUy6If1FfouOsfqBxr86g==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.0.0", @@ -3340,8 +3025,7 @@ }, "node_modules/@radix-ui/react-slider": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.1.1.tgz", - "integrity": "sha512-0aswLpUKZIraPEOcXfwW25N1KPfLA6Mvm1TxogUChGsbLbys2ihd7uk9XAKsol9ZQPucxh2/mybwdRtAKrs/MQ==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.13.10", "@radix-ui/number": "1.0.0", @@ -3435,8 +3119,7 @@ }, "node_modules/@radix-ui/react-use-previous": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.0.0.tgz", - "integrity": "sha512-RG2K8z/K7InnOKpq6YLDmT49HGjNmrK+fr82UCVKT2sW0GYfVnYp4wZWBooT/EYfQ5faA9uIjvsuMMhH61rheg==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.13.10" }, @@ -3475,8 +3158,7 @@ }, "node_modules/@rc-component/mini-decimal": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rc-component/mini-decimal/-/mini-decimal-1.0.1.tgz", - "integrity": "sha512-9N8nRk0oKj1qJzANKl+n9eNSMUGsZtjwNuDCiZ/KA+dt1fE3zq5x2XxclRcAbOIXnZcJ53ozP2Pa60gyELXagA==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.0" }, @@ -3640,8 +3322,9 @@ }, "node_modules/@types/json5": { "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true, - "license": "MIT", "peer": true }, "node_modules/@types/katex": { @@ -4140,8 +3823,7 @@ }, "node_modules/@zattoo/use-double-click": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@zattoo/use-double-click/-/use-double-click-1.2.0.tgz", - "integrity": "sha512-ArRw8SDCgYFvxc4Vpm2JIk1TuWBSUm0cYFqUfgRokz9lgW9m39NZAoeKMu3n3Mp3eKaBMXBrZhTWHUt+vYD87w==", + "license": "MIT", "dependencies": { "react": ">=16.8.0" } @@ -4357,8 +4039,9 @@ }, "node_modules/array.prototype.flat": { "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "call-bind": "^1.0.2", @@ -4676,6 +4359,14 @@ "version": "1.0.2", "license": "MIT" }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/batch": { "version": "0.6.1", "dev": true, @@ -5044,8 +4735,7 @@ }, "node_modules/classnames": { "version": "2.3.2", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", - "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + "license": "MIT" }, "node_modules/clean-css": { "version": "5.3.2", @@ -5060,8 +4750,7 @@ }, "node_modules/client-only": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + "license": "MIT" }, "node_modules/clone-deep": { "version": "4.0.1", @@ -5236,8 +4925,7 @@ }, "node_modules/copy-to-clipboard": { "version": "3.3.3", - "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", - "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", + "license": "MIT", "dependencies": { "toggle-selection": "^1.0.6" } @@ -5388,6 +5076,14 @@ "postcss": "^8.4" } }, + "node_modules/css-line-break": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/css-loader": { "version": "6.7.3", "dev": true, @@ -5777,6 +5473,11 @@ "node": ">=12" } }, + "node_modules/downloadjs": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/downloadjs/-/downloadjs-1.4.7.tgz", + "integrity": "sha512-LN1gO7+u9xjU5oEScGFKvXhYf7Y/empUIIEAGBs1LzUq/rg5duiDrkuH5A2lQGd5jfMOb9X9usDa2oVXwJ0U/Q==" + }, "node_modules/ee-first": { "version": "1.1.1", "dev": true, @@ -5964,9 +5665,8 @@ }, "node_modules/esbuild": { "version": "0.17.15", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.15.tgz", - "integrity": "sha512-LBUV2VsUIc/iD9ME75qhT4aJj0r75abCVS0jakhFzOtR7TQsqQA5w0tZ+KTKnwl3kXE0MhskNdHDh/I5aCR1Zw==", "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -6105,8 +5805,9 @@ }, "node_modules/eslint-import-resolver-node": { "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "debug": "^3.2.7", @@ -6116,8 +5817,9 @@ }, "node_modules/eslint-import-resolver-node/node_modules/debug": { "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "ms": "^2.1.1" @@ -6125,8 +5827,9 @@ }, "node_modules/eslint-module-utils": { "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "debug": "^3.2.7" @@ -6142,8 +5845,9 @@ }, "node_modules/eslint-module-utils/node_modules/debug": { "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "ms": "^2.1.1" @@ -6151,8 +5855,9 @@ }, "node_modules/eslint-plugin-import": { "version": "2.27.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", + "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "array-includes": "^3.1.6", @@ -6180,8 +5885,9 @@ }, "node_modules/eslint-plugin-import/node_modules/debug": { "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "ms": "^2.1.1" @@ -6189,8 +5895,9 @@ }, "node_modules/eslint-plugin-import/node_modules/doctrine": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, - "license": "Apache-2.0", "peer": true, "dependencies": { "esutils": "^2.0.2" @@ -6576,8 +6283,7 @@ }, "node_modules/export-from-json": { "version": "1.7.2", - "resolved": "https://registry.npmjs.org/export-from-json/-/export-from-json-1.7.2.tgz", - "integrity": "sha512-AvjenglU3qqiXWnNz69KvTbZ6m1XhBiauSvyR+0KayPHCiWWhR0dQmaHJCHLWcFHPXeZ3/2PlgPKtGLLMApYmg==" + "license": "MIT" }, "node_modules/express": { "version": "4.18.2", @@ -6746,6 +6452,33 @@ "node": ">=10" } }, + "node_modules/filename-reserved-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-3.0.0.tgz", + "integrity": "sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/filenamify": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-5.1.1.tgz", + "integrity": "sha512-M45CbrJLGACfrPOkrTp3j2EcO9OBkKUYME0eiqOCa7i2poaklU0jhlIaMlr8ijLorT0uLAzrn3qXOp5684CkfA==", + "dependencies": { + "filename-reserved-regex": "^3.0.0", + "strip-outer": "^2.0.0", + "trim-repeated": "^2.0.0" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/fill-range": { "version": "7.0.1", "license": "MIT", @@ -7451,6 +7184,18 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "dependencies": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/http-deceiver": { "version": "1.2.7", "dev": true, @@ -9604,8 +9349,9 @@ }, "node_modules/minimist": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, - "license": "MIT", "peer": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -11244,8 +10990,7 @@ }, "node_modules/rc-input-number": { "version": "7.4.2", - "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-7.4.2.tgz", - "integrity": "sha512-yGturTw7WGP+M1GbJ+UTAO7L4buxeW6oilhL9Sq3DezsRS8/9qec4UiXUbeoiX9bzvRXH11JvgskBtxSp4YSNg==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.10.1", "@rc-component/mini-decimal": "^1.0.1", @@ -11259,8 +11004,7 @@ }, "node_modules/rc-util": { "version": "5.29.3", - "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.29.3.tgz", - "integrity": "sha512-wX6ZwQTzY2v7phJBquN4mSEIFR0E0qumlENx0zjENtDvoVSq2s7cR95UidKRO1hOHfDsecsfM9D1gO4Kebs7fA==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", "react-is": "^16.12.0" @@ -11272,8 +11016,7 @@ }, "node_modules/rc-util/node_modules/react-is": { "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "license": "MIT" }, "node_modules/react": { "version": "18.2.0", @@ -12428,8 +12171,9 @@ }, "node_modules/strip-bom": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, - "license": "MIT", "peer": true, "engines": { "node": ">=4" @@ -12454,6 +12198,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strip-outer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-2.0.0.tgz", + "integrity": "sha512-A21Xsm1XzUkK0qK1ZrytDUvqsQWict2Cykhvi0fBQntGG5JSprESasEyV1EZ/4CiR5WB5KjzLTrP/bO37B0wPg==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/style-loader": { "version": "3.3.2", "dev": true, @@ -12699,6 +12454,14 @@ "dev": true, "license": "MIT" }, + "node_modules/text-segmentation": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/text-table": { "version": "0.2.0", "dev": true, @@ -12746,8 +12509,7 @@ }, "node_modules/toggle-selection": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", - "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" + "license": "MIT" }, "node_modules/toidentifier": { "version": "1.0.1", @@ -12765,6 +12527,28 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/trim-repeated": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-2.0.0.tgz", + "integrity": "sha512-QUHBFTJGdOwmp0tbOG505xAgOp/YliZP/6UgafFXYZ26WT1bvQmSMJUvkeVSASuJJHbqsFbynTvkd5W8RBTipg==", + "dependencies": { + "escape-string-regexp": "^5.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/trim-repeated/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/trough": { "version": "2.1.0", "license": "MIT", @@ -12891,8 +12675,9 @@ }, "node_modules/tsconfig-paths": { "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "@types/json5": "^0.0.29", @@ -12903,8 +12688,9 @@ }, "node_modules/tsconfig-paths/node_modules/json5": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, - "license": "MIT", "peer": true, "dependencies": { "minimist": "^1.2.0" @@ -13266,6 +13052,19 @@ } } }, + "node_modules/use-react-screenshot": { + "version": "3.0.0", + "resolved": "git+ssh://git@github.com/danny-avila/use-react-screenshot.git#59260177849fc8d635170835e2f89ae2a126b7b6", + "license": "MIT", + "engines": { + "node": ">=8", + "npm": ">=5" + }, + "peerDependencies": { + "html2canvas": "^1.4.1", + "react": "^18.2.0" + } + }, "node_modules/use-sidecar": { "version": "1.1.2", "license": "MIT", @@ -13318,6 +13117,14 @@ "node": ">= 0.4.0" } }, + "node_modules/utrie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "dependencies": { + "base64-arraybuffer": "^1.0.2" + } + }, "node_modules/uuid": { "version": "8.3.2", "license": "MIT", @@ -15087,132 +14894,6 @@ "version": "0.5.7", "dev": true }, - "@esbuild/android-arm": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.15.tgz", - "integrity": "sha512-sRSOVlLawAktpMvDyJIkdLI/c/kdRTOqo8t6ImVxg8yT7LQDUYV5Rp2FKeEosLr6ZCja9UjYAzyRSxGteSJPYg==", - "optional": true - }, - "@esbuild/android-arm64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.15.tgz", - "integrity": "sha512-0kOB6Y7Br3KDVgHeg8PRcvfLkq+AccreK///B4Z6fNZGr/tNHX0z2VywCc7PTeWp+bPvjA5WMvNXltHw5QjAIA==", - "optional": true - }, - "@esbuild/android-x64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.15.tgz", - "integrity": "sha512-MzDqnNajQZ63YkaUWVl9uuhcWyEyh69HGpMIrf+acR4otMkfLJ4sUCxqwbCyPGicE9dVlrysI3lMcDBjGiBBcQ==", - "optional": true - }, - "@esbuild/darwin-arm64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.15.tgz", - "integrity": "sha512-7siLjBc88Z4+6qkMDxPT2juf2e8SJxmsbNVKFY2ifWCDT72v5YJz9arlvBw5oB4W/e61H1+HDB/jnu8nNg0rLA==", - "optional": true - }, - "@esbuild/darwin-x64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.15.tgz", - "integrity": "sha512-NbImBas2rXwYI52BOKTW342Tm3LTeVlaOQ4QPZ7XuWNKiO226DisFk/RyPk3T0CKZkKMuU69yOvlapJEmax7cg==", - "optional": true - }, - "@esbuild/freebsd-arm64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.15.tgz", - "integrity": "sha512-Xk9xMDjBVG6CfgoqlVczHAdJnCs0/oeFOspFap5NkYAmRCT2qTn1vJWA2f419iMtsHSLm+O8B6SLV/HlY5cYKg==", - "optional": true - }, - "@esbuild/freebsd-x64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.15.tgz", - "integrity": "sha512-3TWAnnEOdclvb2pnfsTWtdwthPfOz7qAfcwDLcfZyGJwm1SRZIMOeB5FODVhnM93mFSPsHB9b/PmxNNbSnd0RQ==", - "optional": true - }, - "@esbuild/linux-arm": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.15.tgz", - "integrity": "sha512-MLTgiXWEMAMr8nmS9Gigx43zPRmEfeBfGCwxFQEMgJ5MC53QKajaclW6XDPjwJvhbebv+RzK05TQjvH3/aM4Xw==", - "optional": true - }, - "@esbuild/linux-arm64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.15.tgz", - "integrity": "sha512-T0MVnYw9KT6b83/SqyznTs/3Jg2ODWrZfNccg11XjDehIved2oQfrX/wVuev9N936BpMRaTR9I1J0tdGgUgpJA==", - "optional": true - }, - "@esbuild/linux-ia32": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.15.tgz", - "integrity": "sha512-wp02sHs015T23zsQtU4Cj57WiteiuASHlD7rXjKUyAGYzlOKDAjqK6bk5dMi2QEl/KVOcsjwL36kD+WW7vJt8Q==", - "optional": true - }, - "@esbuild/linux-loong64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.15.tgz", - "integrity": "sha512-k7FsUJjGGSxwnBmMh8d7IbObWu+sF/qbwc+xKZkBe/lTAF16RqxRCnNHA7QTd3oS2AfGBAnHlXL67shV5bBThQ==", - "optional": true - }, - "@esbuild/linux-mips64el": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.15.tgz", - "integrity": "sha512-ZLWk6czDdog+Q9kE/Jfbilu24vEe/iW/Sj2d8EVsmiixQ1rM2RKH2n36qfxK4e8tVcaXkvuV3mU5zTZviE+NVQ==", - "optional": true - }, - "@esbuild/linux-ppc64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.15.tgz", - "integrity": "sha512-mY6dPkIRAiFHRsGfOYZC8Q9rmr8vOBZBme0/j15zFUKM99d4ILY4WpOC7i/LqoY+RE7KaMaSfvY8CqjJtuO4xg==", - "optional": true - }, - "@esbuild/linux-riscv64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.15.tgz", - "integrity": "sha512-EcyUtxffdDtWjjwIH8sKzpDRLcVtqANooMNASO59y+xmqqRYBBM7xVLQhqF7nksIbm2yHABptoioS9RAbVMWVA==", - "optional": true - }, - "@esbuild/linux-s390x": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.15.tgz", - "integrity": "sha512-BuS6Jx/ezxFuHxgsfvz7T4g4YlVrmCmg7UAwboeyNNg0OzNzKsIZXpr3Sb/ZREDXWgt48RO4UQRDBxJN3B9Rbg==", - "optional": true - }, - "@esbuild/linux-x64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.15.tgz", - "integrity": "sha512-JsdS0EgEViwuKsw5tiJQo9UdQdUJYuB+Mf6HxtJSPN35vez1hlrNb1KajvKWF5Sa35j17+rW1ECEO9iNrIXbNg==", - "optional": true - }, - "@esbuild/netbsd-x64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.15.tgz", - "integrity": "sha512-R6fKjtUysYGym6uXf6qyNephVUQAGtf3n2RCsOST/neIwPqRWcnc3ogcielOd6pT+J0RDR1RGcy0ZY7d3uHVLA==", - "optional": true - }, - "@esbuild/openbsd-x64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.15.tgz", - "integrity": "sha512-mVD4PGc26b8PI60QaPUltYKeSX0wxuy0AltC+WCTFwvKCq2+OgLP4+fFd+hZXzO2xW1HPKcytZBdjqL6FQFa7w==", - "optional": true - }, - "@esbuild/sunos-x64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.15.tgz", - "integrity": "sha512-U6tYPovOkw3459t2CBwGcFYfFRjivcJJc1WC8Q3funIwX8x4fP+R6xL/QuTPNGOblbq/EUDxj9GU+dWKX0oWlQ==", - "optional": true - }, - "@esbuild/win32-arm64": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.15.tgz", - "integrity": "sha512-W+Z5F++wgKAleDABemiyXVnzXgvRFs+GVKThSI+mGgleLWluv0D7Diz4oQpgdpNzh4i2nNDzQtWbjJiqutRp6Q==", - "optional": true - }, - "@esbuild/win32-ia32": { - "version": "0.17.15", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.15.tgz", - "integrity": "sha512-Muz/+uGgheShKGqSVS1KsHtCyEzcdOn/W/Xbh6H91Etm+wiIfwZaBn1W58MeGtfI8WA961YMHFYTthBdQs4t+w==", - "optional": true - }, "@esbuild/win32-x64": { "version": "0.17.15", "optional": true @@ -15280,8 +14961,6 @@ }, "@headlessui/react": { "version": "1.7.13", - "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.13.tgz", - "integrity": "sha512-9n+EQKRtD9266xIHXdY5MfiXPDfYwl7zBM7KOx2Ae3Gdgxy8QML1FkCMjq6AsOf0l6N9uvI4HcFtuFlenaldKg==", "requires": { "client-only": "^0.0.1" } @@ -15441,8 +15120,6 @@ }, "@radix-ui/number": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.0.tgz", - "integrity": "sha512-Ofwh/1HX69ZfJRiRBMTy7rgjAzHmwe4kW9C9Y99HTRUcYLUuVT0KESFj15rPjRgKJs20GPq8Bm5aEDJ8DuA3vA==", "requires": { "@babel/runtime": "^7.13.10" } @@ -15474,8 +15151,6 @@ }, "@radix-ui/react-checkbox": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.0.3.tgz", - "integrity": "sha512-55B8/vKzTuzxllH5sGJO4zaBf9gYpJuJRRzaOKm+0oAefRnMvbf+Kgww7IOANVN0w3z7agFJgtnXaZl8Uj95AA==", "requires": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.0.0", @@ -15577,8 +15252,6 @@ }, "@radix-ui/react-hover-card": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.0.5.tgz", - "integrity": "sha512-jXRuZEkxSWdHZbVyL0J46cm7pQjmOMpwJEFKY+VqAJnV+FxS+zIZExI1OCeIiDwCBzUy6If1FfouOsfqBxr86g==", "requires": { "@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.0.0", @@ -15685,8 +15358,6 @@ }, "@radix-ui/react-slider": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.1.1.tgz", - "integrity": "sha512-0aswLpUKZIraPEOcXfwW25N1KPfLA6Mvm1TxogUChGsbLbys2ihd7uk9XAKsol9ZQPucxh2/mybwdRtAKrs/MQ==", "requires": { "@babel/runtime": "^7.13.10", "@radix-ui/number": "1.0.0", @@ -15751,8 +15422,6 @@ }, "@radix-ui/react-use-previous": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.0.0.tgz", - "integrity": "sha512-RG2K8z/K7InnOKpq6YLDmT49HGjNmrK+fr82UCVKT2sW0GYfVnYp4wZWBooT/EYfQ5faA9uIjvsuMMhH61rheg==", "requires": { "@babel/runtime": "^7.13.10" } @@ -15779,8 +15448,6 @@ }, "@rc-component/mini-decimal": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rc-component/mini-decimal/-/mini-decimal-1.0.1.tgz", - "integrity": "sha512-9N8nRk0oKj1qJzANKl+n9eNSMUGsZtjwNuDCiZ/KA+dt1fE3zq5x2XxclRcAbOIXnZcJ53ozP2Pa60gyELXagA==", "requires": { "@babel/runtime": "^7.18.0" } @@ -15915,6 +15582,8 @@ }, "@types/json5": { "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true, "peer": true }, @@ -16268,8 +15937,6 @@ }, "@zattoo/use-double-click": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@zattoo/use-double-click/-/use-double-click-1.2.0.tgz", - "integrity": "sha512-ArRw8SDCgYFvxc4Vpm2JIk1TuWBSUm0cYFqUfgRokz9lgW9m39NZAoeKMu3n3Mp3eKaBMXBrZhTWHUt+vYD87w==", "requires": { "react": ">=16.8.0" } @@ -16404,6 +16071,8 @@ }, "array.prototype.flat": { "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", "dev": true, "peer": true, "requires": { @@ -16636,6 +16305,11 @@ "balanced-match": { "version": "1.0.2" }, + "base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==" + }, "batch": { "version": "0.6.1", "dev": true @@ -16865,9 +16539,7 @@ "requires": {} }, "classnames": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", - "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + "version": "2.3.2" }, "clean-css": { "version": "5.3.2", @@ -16877,9 +16549,7 @@ } }, "client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + "version": "0.0.1" }, "clone-deep": { "version": "4.0.1", @@ -16999,8 +16669,6 @@ }, "copy-to-clipboard": { "version": "3.3.3", - "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", - "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", "requires": { "toggle-selection": "^1.0.6" } @@ -17104,6 +16772,14 @@ "postcss-value-parser": "^4.2.0" } }, + "css-line-break": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "requires": { + "utrie": "^1.0.2" + } + }, "css-loader": { "version": "6.7.3", "dev": true, @@ -17333,6 +17009,11 @@ "version": "8.0.3", "dev": true }, + "downloadjs": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/downloadjs/-/downloadjs-1.4.7.tgz", + "integrity": "sha512-LN1gO7+u9xjU5oEScGFKvXhYf7Y/empUIIEAGBs1LzUq/rg5duiDrkuH5A2lQGd5jfMOb9X9usDa2oVXwJ0U/Q==" + }, "ee-first": { "version": "1.1.1", "dev": true @@ -17467,8 +17148,6 @@ }, "esbuild": { "version": "0.17.15", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.15.tgz", - "integrity": "sha512-LBUV2VsUIc/iD9ME75qhT4aJj0r75abCVS0jakhFzOtR7TQsqQA5w0tZ+KTKnwl3kXE0MhskNdHDh/I5aCR1Zw==", "requires": { "@esbuild/android-arm": "0.17.15", "@esbuild/android-arm64": "0.17.15", @@ -17637,6 +17316,8 @@ }, "eslint-import-resolver-node": { "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", "dev": true, "peer": true, "requires": { @@ -17647,6 +17328,8 @@ "dependencies": { "debug": { "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "peer": true, "requires": { @@ -17657,6 +17340,8 @@ }, "eslint-module-utils": { "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", "dev": true, "peer": true, "requires": { @@ -17665,6 +17350,8 @@ "dependencies": { "debug": { "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "peer": true, "requires": { @@ -17675,6 +17362,8 @@ }, "eslint-plugin-import": { "version": "2.27.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", + "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", "dev": true, "peer": true, "requires": { @@ -17697,6 +17386,8 @@ "dependencies": { "debug": { "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "peer": true, "requires": { @@ -17705,6 +17396,8 @@ }, "doctrine": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "peer": true, "requires": { @@ -17868,9 +17561,7 @@ } }, "export-from-json": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/export-from-json/-/export-from-json-1.7.2.tgz", - "integrity": "sha512-AvjenglU3qqiXWnNz69KvTbZ6m1XhBiauSvyR+0KayPHCiWWhR0dQmaHJCHLWcFHPXeZ3/2PlgPKtGLLMApYmg==" + "version": "1.7.2" }, "express": { "version": "4.18.2", @@ -18004,6 +17695,21 @@ } } }, + "filename-reserved-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-3.0.0.tgz", + "integrity": "sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==" + }, + "filenamify": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-5.1.1.tgz", + "integrity": "sha512-M45CbrJLGACfrPOkrTp3j2EcO9OBkKUYME0eiqOCa7i2poaklU0jhlIaMlr8ijLorT0uLAzrn3qXOp5684CkfA==", + "requires": { + "filename-reserved-regex": "^3.0.0", + "strip-outer": "^2.0.0", + "trim-repeated": "^2.0.0" + } + }, "fill-range": { "version": "7.0.1", "requires": { @@ -18445,6 +18151,15 @@ "html-void-elements": { "version": "2.0.1" }, + "html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "requires": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + } + }, "http-deceiver": { "version": "1.2.7", "dev": true @@ -19658,6 +19373,8 @@ }, "minimist": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, "peer": true }, @@ -20519,8 +20236,6 @@ }, "rc-input-number": { "version": "7.4.2", - "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-7.4.2.tgz", - "integrity": "sha512-yGturTw7WGP+M1GbJ+UTAO7L4buxeW6oilhL9Sq3DezsRS8/9qec4UiXUbeoiX9bzvRXH11JvgskBtxSp4YSNg==", "requires": { "@babel/runtime": "^7.10.1", "@rc-component/mini-decimal": "^1.0.1", @@ -20530,17 +20245,13 @@ }, "rc-util": { "version": "5.29.3", - "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.29.3.tgz", - "integrity": "sha512-wX6ZwQTzY2v7phJBquN4mSEIFR0E0qumlENx0zjENtDvoVSq2s7cR95UidKRO1hOHfDsecsfM9D1gO4Kebs7fA==", "requires": { "@babel/runtime": "^7.18.3", "react-is": "^16.12.0" }, "dependencies": { "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "version": "16.13.1" } } }, @@ -21267,6 +20978,8 @@ }, "strip-bom": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, "peer": true }, @@ -21278,6 +20991,11 @@ "version": "3.1.1", "dev": true }, + "strip-outer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-2.0.0.tgz", + "integrity": "sha512-A21Xsm1XzUkK0qK1ZrytDUvqsQWict2Cykhvi0fBQntGG5JSprESasEyV1EZ/4CiR5WB5KjzLTrP/bO37B0wPg==" + }, "style-loader": { "version": "3.3.2", "dev": true, @@ -21420,6 +21138,14 @@ } } }, + "text-segmentation": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "requires": { + "utrie": "^1.0.2" + } + }, "text-table": { "version": "0.2.0", "dev": true @@ -21451,9 +21177,7 @@ } }, "toggle-selection": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", - "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" + "version": "1.0.6" }, "toidentifier": { "version": "1.0.1", @@ -21462,6 +21186,21 @@ "trim-lines": { "version": "3.0.1" }, + "trim-repeated": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-2.0.0.tgz", + "integrity": "sha512-QUHBFTJGdOwmp0tbOG505xAgOp/YliZP/6UgafFXYZ26WT1bvQmSMJUvkeVSASuJJHbqsFbynTvkd5W8RBTipg==", + "requires": { + "escape-string-regexp": "^5.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==" + } + } + }, "trough": { "version": "2.1.0" }, @@ -21537,6 +21276,8 @@ }, "tsconfig-paths": { "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", "dev": true, "peer": true, "requires": { @@ -21548,6 +21289,8 @@ "dependencies": { "json5": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "peer": true, "requires": { @@ -21751,6 +21494,11 @@ "use-isomorphic-layout-effect": "^1.1.1" } }, + "use-react-screenshot": { + "version": "git+ssh://git@github.com/danny-avila/use-react-screenshot.git#59260177849fc8d635170835e2f89ae2a126b7b6", + "from": "use-react-screenshot@github:danny-avila/use-react-screenshot#master", + "requires": {} + }, "use-sidecar": { "version": "1.1.2", "requires": { @@ -21782,6 +21530,14 @@ "version": "1.0.1", "dev": true }, + "utrie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "requires": { + "base64-arraybuffer": "^1.0.2" + } + }, "uuid": { "version": "8.3.2" }, diff --git a/client/package.json b/client/package.json index f0f477baca..75d8361f1a 100644 --- a/client/package.json +++ b/client/package.json @@ -40,8 +40,11 @@ "clsx": "^1.2.1", "copy-to-clipboard": "^3.3.3", "crypto-browserify": "^3.12.0", + "downloadjs": "^1.4.7", "esbuild": "0.17.15", "export-from-json": "^1.7.2", + "filenamify": "^5.1.1", + "html2canvas": "^1.4.1", "lodash": "^4.17.21", "lucide-react": "^0.113.0", "rc-input-number": "^7.4.2", @@ -65,6 +68,7 @@ "tailwindcss-animate": "^1.0.5", "tailwindcss-radix": "^2.8.0", "url": "^0.11.0", + "use-react-screenshot": "github:danny-avila/use-react-screenshot#master", "uuidv4": "^6.2.13" }, "devDependencies": { diff --git a/client/src/App.jsx b/client/src/App.jsx index b63e474677..cca1de99a8 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -7,6 +7,8 @@ import store from './store'; import userAuth from './utils/userAuth'; import { useRecoilState, useSetRecoilState } from 'recoil'; +import { ScreenshotProvider } from './utils/screenshotContext.jsx'; + import axios from 'axios'; const router = createBrowserRouter([ @@ -97,4 +99,8 @@ const App = () => { else return
; }; -export default App; +export default () => ( + + + +); diff --git a/client/src/components/Conversations/Conversation.jsx b/client/src/components/Conversations/Conversation.jsx index 3fc07dea3e..c95c9d1f4b 100644 --- a/client/src/components/Conversations/Conversation.jsx +++ b/client/src/components/Conversations/Conversation.jsx @@ -32,6 +32,9 @@ export default function Conversation({ conversation, retainView }) { // stop existing submission setSubmission(null); + // set document title + document.title = title; + // set conversation to the new conversation switchToConversation(conversation); }; diff --git a/client/src/components/Endpoints/EditPresetDialog.jsx b/client/src/components/Endpoints/EditPresetDialog.jsx index 8457f27f57..e264920772 100644 --- a/client/src/components/Endpoints/EditPresetDialog.jsx +++ b/client/src/components/Endpoints/EditPresetDialog.jsx @@ -1,5 +1,6 @@ import React, { useEffect, useState } from 'react'; import { useSetRecoilState, useRecoilValue } from 'recoil'; +import filenamify from 'filenamify'; import axios from 'axios'; import exportFromJSON from 'export-from-json'; import DialogTemplate from '../ui/DialogTemplate'; @@ -51,9 +52,10 @@ const EditPresetDialog = ({ open, onOpenChange, preset: _preset, title }) => { }; const exportPreset = () => { + const fileName = filenamify(preset?.title || 'preset'); exportFromJSON({ data: cleanupPreset({ preset, endpointsFilter }), - fileName: `${preset?.title}.json`, + fileName, exportType: exportFromJSON.types.json }); }; diff --git a/client/src/components/Input/Endpoints/NewConversationMenu.jsx b/client/src/components/Input/Endpoints/NewConversationMenu.jsx index f91baab86d..2d5f35c85a 100644 --- a/client/src/components/Input/Endpoints/NewConversationMenu.jsx +++ b/client/src/components/Input/Endpoints/NewConversationMenu.jsx @@ -49,7 +49,8 @@ export default function NewConversationMenu() { // update the default model when availableModels changes // typically, availableModels changes => modelsFilter or customGPTModels changes useEffect(() => { - if (conversationId == 'new') { + const isInvalidConversation = !availableEndpoints.find(e => e === endpoint); + if (conversationId == 'new' && isInvalidConversation) { newConversation(); } }, [availableEndpoints]); diff --git a/client/src/components/Input/Endpoints/PresetItem.jsx b/client/src/components/Input/Endpoints/PresetItem.jsx index 6bb7d70af3..fe8503d2cc 100644 --- a/client/src/components/Input/Endpoints/PresetItem.jsx +++ b/client/src/components/Input/Endpoints/PresetItem.jsx @@ -56,16 +56,7 @@ export default function PresetItem({ preset = {}, value, onSelect, onChangePrese /> */}
- + ); } diff --git a/client/src/components/Input/index.jsx b/client/src/components/Input/index.jsx index 208695b570..460466a4f7 100644 --- a/client/src/components/Input/index.jsx +++ b/client/src/components/Input/index.jsx @@ -5,7 +5,7 @@ import OpenAIOptions from './OpenAIOptions'; import ChatGPTOptions from './ChatGPTOptions'; import BingAIOptions from './BingAIOptions'; // import BingStyles from './BingStyles'; -import EndpointMenu from './Endpoints/NewConversationMenu'; +import NewConversationMenu from './Endpoints/NewConversationMenu'; import Footer from './Footer'; import TextareaAutosize from 'react-textarea-autosize'; import { useMessageHandler } from '../../utils/handleSubmit'; @@ -145,7 +145,7 @@ export default function TextChat({ isSearchView = false }) { disabled ? 'dark:bg-gray-900' : 'dark:bg-gray-700' } dark:text-white dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] md:py-3 md:pl-4`} > - +
{ setSiblingIdx(messagesTree?.length - value - 1); diff --git a/client/src/components/Messages/index.jsx b/client/src/components/Messages/index.jsx index a458bf56e3..27a06be190 100644 --- a/client/src/components/Messages/index.jsx +++ b/client/src/components/Messages/index.jsx @@ -6,6 +6,7 @@ import { CSSTransition } from 'react-transition-group'; import ScrollToBottom from './ScrollToBottom'; import MultiMessage from './MultiMessage'; import MessageHeader from './MessageHeader'; +import { useScreenshot } from '~/utils/screenshotContext.jsx'; import store from '~/store'; @@ -23,6 +24,8 @@ export default function Messages({ isSearchView = false }) { const conversation = useRecoilValue(store.conversation) || {}; const { conversationId } = conversation; + const { screenshotTargetRef } = useScreenshot(); + // const models = useRecoilValue(store.models) || []; // const modelName = models.find(element => element.model == model)?.name; @@ -84,8 +87,11 @@ export default function Messages({ isSearchView = false }) { ref={scrollableRef} onScroll={debouncedHandleScroll} > -
-
+
+
{_messagesTree === null ? ( @@ -97,6 +103,7 @@ export default function Messages({ isSearchView = false }) { <> )}
diff --git a/client/src/components/Nav/ExportConversation/ExportModel.jsx b/client/src/components/Nav/ExportConversation/ExportModel.jsx new file mode 100644 index 0000000000..7a02dc96db --- /dev/null +++ b/client/src/components/Nav/ExportConversation/ExportModel.jsx @@ -0,0 +1,415 @@ +import React, { useEffect, useState } from 'react'; +import { useRecoilValue, useRecoilCallback } from 'recoil'; +import filenamify from 'filenamify'; +import exportFromJSON from 'export-from-json'; +import download from 'downloadjs'; +import DialogTemplate from '~/components/ui/DialogTemplate.jsx'; +import { Dialog, DialogClose, DialogButton } from '~/components/ui/Dialog.tsx'; +import { Input } from '~/components/ui/Input.tsx'; +import { Label } from '~/components/ui/Label.tsx'; +import { Checkbox } from '~/components/ui/Checkbox.tsx'; +import Dropdown from '~/components/ui/Dropdown'; +import { cn } from '~/utils/'; +import { useScreenshot } from '~/utils/screenshotContext'; + +import store from '~/store'; +import cleanupPreset from '~/utils/cleanupPreset.js'; + +export default function ExportModel({ open, onOpenChange }) { + const { captureScreenshot } = useScreenshot(); + + const [filename, setFileName] = useState(''); + const [type, setType] = useState(''); + + const [includeOptions, setIncludeOptions] = useState(true); + const [exportBranches, setExportBranches] = useState(false); + const [exportBranchesSupport, setExportBranchesSupport] = useState(false); + const [recursive, setRecursive] = useState(true); + + const conversation = useRecoilValue(store.conversation) || {}; + const messagesTree = useRecoilValue(store.messagesTree) || []; + const endpointsFilter = useRecoilValue(store.endpointsFilter); + + const getSiblingIdx = useRecoilCallback( + ({ snapshot }) => + async messageId => + await snapshot.getPromise(store.messagesSiblingIdxFamily(messageId)), + [] + ); + + const typeOptions = ['text', 'markdown', 'csv', 'json', 'screenshot']; //,, 'webpage']; + + useEffect(() => { + setFileName( + filenamify(String(conversation?.title || 'file')) + ); + setType('text'); + setIncludeOptions(true); + setExportBranches(false); + setExportBranchesSupport(false); + setRecursive(true); + }, [open]); + + const _setType = newType => { + if (newType === 'json' || newType === 'csv' || newType === 'webpage') { + setExportBranches(true); + setExportBranchesSupport(true); + } else { + setExportBranches(false); + setExportBranchesSupport(false); + } + setType(newType); + }; + + // return an object or an array based on branches and recursive option + // messageId is used to get siblindIdx from recoil snapshot + const buildMessageTree = async ({ messageId, message, messages, branches = false, recursive = false }) => { + let children = []; + if (messages?.length) + if (branches) + for (const message of messages) + children.push( + await buildMessageTree({ + messageId: message?.messageId, + message: message, + messages: message?.children, + branches, + recursive + }) + ); + else { + let message = messages[0]; + if (messages?.length > 1) { + const siblingIdx = await getSiblingIdx(messageId); + message = messages[messages.length - siblingIdx - 1]; + } + + children = [ + await buildMessageTree({ + messageId: message?.messageId, + message: message, + messages: message?.children, + branches, + recursive + }) + ]; + } + + if (recursive) return { ...message, children: children }; + else { + let ret = []; + if (message) { + let _message = { ...message }; + delete _message.children; + ret = [_message]; + } + for (const child of children) ret = ret.concat(child); + return ret; + } + }; + + const exportScreenshot = async () => { + const data = await captureScreenshot(); + download(data, `${filename}.png`, 'image/png'); + }; + + const exportCSV = async () => { + let data = []; + + const messages = await buildMessageTree({ + messageId: conversation?.conversationId, + message: null, + messages: messagesTree, + branches: exportBranches, + recursive: false + }); + + for (const message of messages) { + data.push(message); + } + + exportFromJSON({ + data: data, + fileName: filename, + extension: 'csv', + exportType: exportFromJSON.types.csv, + beforeTableEncode: entries => [ + { fieldName: 'sender', fieldValues: entries.find(e => e.fieldName == 'sender').fieldValues }, + { fieldName: 'text', fieldValues: entries.find(e => e.fieldName == 'text').fieldValues }, + { + fieldName: 'isCreatedByUser', + fieldValues: entries.find(e => e.fieldName == 'isCreatedByUser').fieldValues + }, + { fieldName: 'error', fieldValues: entries.find(e => e.fieldName == 'error').fieldValues }, + { fieldName: 'messageId', fieldValues: entries.find(e => e.fieldName == 'messageId').fieldValues }, + { + fieldName: 'parentMessageId', + fieldValues: entries.find(e => e.fieldName == 'parentMessageId').fieldValues + }, + { fieldName: 'createdAt', fieldValues: entries.find(e => e.fieldName == 'createdAt').fieldValues } + ] + }); + }; + + const exportMarkdown = async () => { + let data = + `# Conversation\n` + + `- conversationId: ${conversation?.conversationId}\n` + + `- endpoint: ${conversation?.endpoint}\n` + + `- title: ${conversation?.title}\n` + + `- exportAt: ${new Date().toTimeString()}\n`; + + if (includeOptions) { + data += `\n## Options\n`; + const options = cleanupPreset({ preset: conversation, endpointsFilter }); + + for (const key of Object.keys(options)) { + data += `- ${key}: ${options[key]}\n`; + } + } + + const messages = await buildMessageTree({ + messageId: conversation?.conversationId, + message: null, + messages: messagesTree, + branches: false, + recursive: false + }); + + data += `\n## History\n`; + for (const message of messages) { + data += `**${message?.sender}:**\n${message?.text}\n\n`; + } + + exportFromJSON({ + data: data, + fileName: filename, + extension: 'md', + exportType: exportFromJSON.types.text + }); + }; + + const exportText = async () => { + let data = + `Conversation\n` + + `########################\n` + + `conversationId: ${conversation?.conversationId}\n` + + `endpoint: ${conversation?.endpoint}\n` + + `title: ${conversation?.title}\n` + + `exportAt: ${new Date().toTimeString()}\n`; + + if (includeOptions) { + data += `\nOptions\n########################\n`; + const options = cleanupPreset({ preset: conversation, endpointsFilter }); + + for (const key of Object.keys(options)) { + data += `${key}: ${options[key]}\n`; + } + } + + const messages = await buildMessageTree({ + messageId: conversation?.conversationId, + message: null, + messages: messagesTree, + branches: false, + recursive: false + }); + + data += `\nHistory\n########################\n`; + for (const message of messages) { + data += `${message?.sender}:\n${message?.text}\n\n`; + } + + exportFromJSON({ + data: data, + fileName: filename, + extension: 'txt', + exportType: exportFromJSON.types.text + }); + }; + + const exportJSON = async () => { + let data = { + conversationId: conversation?.conversationId, + endpoint: conversation?.endpoint, + title: conversation?.title, + exportAt: new Date().toTimeString(), + branches: exportBranches, + recursive: recursive + }; + + if (includeOptions) data.options = cleanupPreset({ preset: conversation, endpointsFilter }); + + const messages = await buildMessageTree({ + messageId: conversation?.conversationId, + message: null, + messages: messagesTree, + branches: exportBranches, + recursive: recursive + }); + + if (recursive) data.messagesTree = messages.children; + else data.messages = messages; + + exportFromJSON({ + data: data, + fileName: filename, + extension: 'json', + exportType: exportFromJSON.types.json + }); + }; + + const exportConversation = () => { + if (type === 'json') exportJSON(); + else if (type == 'text') exportText(); + else if (type == 'markdown') exportMarkdown(); + else if (type == 'csv') exportCSV(); + else if (type == 'screenshot') exportScreenshot(); + }; + + const defaultTextProps = + 'rounded-md border border-gray-200 focus:border-slate-400 focus:bg-gray-50 bg-transparent text-sm shadow-[0_0_10px_rgba(0,0,0,0.05)] outline-none placeholder:text-gray-400 focus:outline-none focus:ring-gray-400 focus:ring-opacity-20 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-500 dark:bg-gray-700 focus:dark:bg-gray-600 dark:text-gray-50 dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] dark:focus:border-gray-400 dark:focus:outline-none dark:focus:ring-0 dark:focus:ring-gray-400 dark:focus:ring-offset-0'; + + return ( + + +
+
+ + setFileName(filenamify(e.target.value || ''))} + placeholder="Set the filename" + className={cn( + defaultTextProps, + 'flex h-10 max-h-10 w-full resize-none px-3 py-2 focus:outline-none focus:ring-0 focus:ring-opacity-0 focus:ring-offset-0' + )} + /> +
+
+ + +
+
+
+ {type !== 'csv' && type !== 'screenshot' ? ( +
+
+ +
+ + +
+
+
+ ) : null} + {type !== 'screenshot' ? ( +
+ +
+ + +
+
+ ) : null} + {type === 'json' ? ( +
+ +
+ + +
+
+ ) : null} +
+
+ } + buttons={ + <> + + Export + + + } + selection={null} + /> + + ); +} diff --git a/client/src/components/Nav/ExportConversation/index.jsx b/client/src/components/Nav/ExportConversation/index.jsx new file mode 100644 index 0000000000..7548c48374 --- /dev/null +++ b/client/src/components/Nav/ExportConversation/index.jsx @@ -0,0 +1,43 @@ +import React, { useState } from 'react'; +import { useRecoilValue } from 'recoil'; +import { Download } from 'lucide-react'; +import { cn } from '~/utils/'; + +import ExportModel from './ExportModel'; + +import store from '~/store'; + +export default function ExportConversation() { + const [open, setOpen] = useState(false); + + const conversation = useRecoilValue(store.conversation) || {}; + + const exportable = + conversation?.conversationId && + conversation?.conversationId !== 'new' && + conversation?.conversationId !== 'search'; + + const clickHandler = () => { + if (exportable) setOpen(true); + }; + + return ( + <> + + + Export conversation + + + + + ); +} diff --git a/client/src/components/Nav/NavLinks.jsx b/client/src/components/Nav/NavLinks.jsx index 9626845d46..33f0e453c7 100644 --- a/client/src/components/Nav/NavLinks.jsx +++ b/client/src/components/Nav/NavLinks.jsx @@ -3,6 +3,7 @@ import SearchBar from './SearchBar'; import ClearConvos from './ClearConvos'; import DarkMode from './DarkMode'; import Logout from './Logout'; +import ExportConversation from './ExportConversation'; export default function NavLinks({ fetch, onSearchSuccess, clearSearch, isSearchEnabled }) { return ( @@ -14,6 +15,7 @@ export default function NavLinks({ fetch, onSearchSuccess, clearSearch, isSearch clearSearch={clearSearch} /> )} + diff --git a/client/src/store/conversation.js b/client/src/store/conversation.js index 06520b2751..c13cbc48ec 100644 --- a/client/src/store/conversation.js +++ b/client/src/store/conversation.js @@ -1,7 +1,15 @@ import endpoints from './endpoints'; -import { atom, selector, useSetRecoilState, useResetRecoilState, useRecoilCallback } from 'recoil'; +import { + atom, + selector, + atomFamily, + useSetRecoilState, + useResetRecoilState, + useRecoilCallback +} from 'recoil'; import buildTree from '~/utils/buildTree'; import getDefaultConversation from '~/utils/getDefaultConversation'; +import submission from './submission.js'; // current conversation, can be null (need to be fetched from server) // sample structure @@ -56,9 +64,15 @@ const latestMessage = atom({ default: null }); +const messagesSiblingIdxFamily = atomFamily({ + key: 'messagesSiblingIdx', + default: 0 +}); + const useConversation = () => { const setConversation = useSetRecoilState(conversation); const setMessages = useSetRecoilState(messages); + const setSubmission = useSetRecoilState(submission.submission); const resetLatestMessage = useResetRecoilState(latestMessage); const switchToConversation = useRecoilCallback( @@ -93,6 +107,7 @@ const useConversation = () => { setConversation(conversation); setMessages(messages); + setSubmission({}); resetLatestMessage(); }; @@ -126,5 +141,6 @@ export default { messages, messagesTree, latestMessage, + messagesSiblingIdxFamily, useConversation }; diff --git a/client/src/utils/screenshotContext.jsx b/client/src/utils/screenshotContext.jsx new file mode 100644 index 0000000000..cc0ecfc640 --- /dev/null +++ b/client/src/utils/screenshotContext.jsx @@ -0,0 +1,21 @@ +import React, { createContext, useRef, useContext, useCallback } from 'react'; +import { useScreenshot as useScreenshot_ } from 'use-react-screenshot'; + +const ScreenshotContext = createContext({}); + +export const useScreenshot = () => { + const { ref } = useContext(ScreenshotContext); + const [image, takeScreenshot] = useScreenshot_(); + + const captureScreenshot = () => { + return takeScreenshot(ref.current); + }; + + return { screenshotTargetRef: ref, captureScreenshot }; +}; + +export const ScreenshotProvider = ({ children }) => { + const ref = useRef(null); + + return {children}; +}; diff --git a/docker-compose.yml b/docker-compose.yml index 6f7980de42..c6c5372678 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,6 +29,7 @@ services: - HOST=0.0.0.0 - NODE_ENV=production - MONGO_URI=mongodb://mongodb:27017/chatgpt-clone + # - CHATGPT_REVERSE_PROXY=http://host.docker.internal:8080/api/conversation # if you are hosting your own chatgpt reverse proxy - MEILI_HOST=http://meilisearch:7700 - MEILI_HTTP_ADDR=meilisearch:7700 volumes: