From bccb4a78ecd42dcdac33b9f95d0dacdb8c1bd65a Mon Sep 17 00:00:00 2001 From: bangonicdd <157843588+bangonicdd2@users.noreply.github.com> Date: Thu, 17 Apr 2025 11:43:06 +0900 Subject: [PATCH 01/26] fix: lorebook matches excluding dummy prefix/suffix --- src/ts/process/lorebook.svelte.ts | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/ts/process/lorebook.svelte.ts b/src/ts/process/lorebook.svelte.ts index 5e578be7..973898fc 100644 --- a/src/ts/process/lorebook.svelte.ts +++ b/src/ts/process/lorebook.svelte.ts @@ -55,7 +55,8 @@ export async function loadLoreBookV3Prompt(){ const recursiveScanning = char.loreSettings?.recursiveScanning ?? true let recursivePrompt:{ prompt: string, - source: string + source: string, + data: string }[] = [] let matchLog:{ prompt: string, @@ -75,23 +76,27 @@ export async function loadLoreBookV3Prompt(){ let mList:{ source:string prompt:string + data:string }[] = sliced.map((msg, i) => { if(msg.role === 'user'){ return { source: `message ${i} by user`, - prompt: `\x01{{${DBState.db.username}}}:` + msg.data + '\x01' + prompt: `\x01{{${DBState.db.username}}}:` + msg.data + '\x01', + data: msg.data } } else{ return { source: `message ${i} by char`, - prompt: `\x01{{${msg.name ?? (msg.saying ? findCharacterbyId(msg.saying)?.name : null) ?? char.name}}}:` + msg.data + '\x01' + prompt: `\x01{{${msg.name ?? (msg.saying ? findCharacterbyId(msg.saying)?.name : null) ?? char.name}}}:` + msg.data + '\x01', + data: msg.data } } }).concat(recursivePrompt.map((msg) => { return { source: 'lorebook ' + msg.source, - prompt: msg.prompt + prompt: msg.prompt, + data: msg.data } })) @@ -106,7 +111,7 @@ export async function loadLoreBookV3Prompt(){ arg.keys[0] = regexString.replace('/'+regexFlag,'') try { const regex = new RegExp(arg.keys[0],regexFlag) - const d = regex.test(mText.prompt) + const d = regex.test(mText.data) if(d){ matchLog.push({ prompt: mText.prompt, @@ -127,7 +132,8 @@ export async function loadLoreBookV3Prompt(){ mList = mList.map((m) => { return { source: m.source, - prompt: m.prompt.toLocaleLowerCase().replace(/\{\{\/\/(.+?)\}\}/g,'').replace(/\{\{comment:(.+?)\}\}/g,'') + prompt: m.prompt.toLocaleLowerCase().replace(/\{\{\/\/(.+?)\}\}/g,'').replace(/\{\{comment:(.+?)\}\}/g,''), + data: m.data.toLocaleLowerCase().replace(/\{\{\/\/(.+?)\}\}/g,'').replace(/\{\{comment:(.+?)\}\}/g,'') } }) @@ -135,7 +141,7 @@ export async function loadLoreBookV3Prompt(){ let allModeMatched = true for(const m of mList){ - let mText = m.prompt + let mText = m.data if(arg.fullWordMatching){ const splited = mText.split(' ') for(const key of arg.keys){ From e0038749a411f00d6f1cd539ed40d5120e55e45f Mon Sep 17 00:00:00 2001 From: shirosaki-hana Date: Thu, 17 Apr 2025 13:14:12 +0900 Subject: [PATCH 02/26] Fix: Resolve account login issues in Node.js hosted version In a previous commit, a new proxy endpoint was added to the backend to resolve CORS errors that occurred when the frontend directly fetched data from Risu Realm. However, the proxy endpoint handler failed to properly process POST requests, causing account login failures. Additionally, the backend was inefficiently performing complex body processing. The updated code now directly pipes the original request, providing a more efficient and reliable solution. --- package.json | 1 - pnpm-lock.yaml | 18 +++++- server/node/server.cjs | 126 ++++++++++------------------------------- 3 files changed, 45 insertions(+), 100 deletions(-) diff --git a/package.json b/package.json index 32109138..99f759a0 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,6 @@ "mnemonist": "^0.40.3", "mobile-drag-drop": "3.0.0-rc.0", "msgpackr": "1.10.1", - "node-fetch": "2", "node-html-parser": "^6.1.12", "ollama": "^0.5.0", "pdfjs-dist": "^4.0.379", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c460c2c9..f247c718 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -158,15 +158,15 @@ importers: ml-distance: specifier: ^4.0.1 version: 4.0.1 + mnemonist: + specifier: ^0.40.3 + version: 0.40.3 mobile-drag-drop: specifier: 3.0.0-rc.0 version: 3.0.0-rc.0 msgpackr: specifier: 1.10.1 version: 1.10.1 - node-fetch: - specifier: '2' - version: 2.7.0 node-html-parser: specifier: ^6.1.12 version: 6.1.12 @@ -2756,6 +2756,9 @@ packages: ml-tree-similarity@1.0.0: resolution: {integrity: sha512-XJUyYqjSuUQkNQHMscr6tcjldsOoAekxADTplt40QKfwW6nd++1wHWV9AArl0Zvw/TIHgNaZZNvr8QGvE8wLRg==} + mnemonist@0.40.3: + resolution: {integrity: sha512-Vjyr90sJ23CKKH/qPAgUKicw/v6pRoamxIEDFOF8uSgFME7DqPRpHgRTejWVjkdGg5dXj0/NyxZHZ9bcjH+2uQ==} + mobile-drag-drop@3.0.0-rc.0: resolution: {integrity: sha512-f8wIDTbBYLBW/+5sei1cqUE+StyDpf/LP+FRZELlVX6tmOOmELk84r3wh1z3woxCB9G5octhF06K5COvFjGgqg==} @@ -2900,6 +2903,9 @@ packages: object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + obliterator@2.0.5: + resolution: {integrity: sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==} + ollama@0.5.0: resolution: {integrity: sha512-CRtRzsho210EGdK52GrUMohA2pU+7NbgEaBG3DcYeRmvQthDO7E2LHOkLlUUeaYUlNmEd8icbjC02ug9meSYnw==} @@ -6505,6 +6511,10 @@ snapshots: binary-search: 1.3.6 num-sort: 2.1.0 + mnemonist@0.40.3: + dependencies: + obliterator: 2.0.5 + mobile-drag-drop@3.0.0-rc.0: {} modify-values@1.0.1: {} @@ -6665,6 +6675,8 @@ snapshots: object-inspect@1.13.1: {} + obliterator@2.0.5: {} + ollama@0.5.0: dependencies: whatwg-fetch: 3.6.20 diff --git a/server/node/server.cjs b/server/node/server.cjs index b2871d9d..6e16bcce 100644 --- a/server/node/server.cjs +++ b/server/node/server.cjs @@ -11,8 +11,7 @@ app.use(express.raw({ type: 'application/octet-stream', limit: '50mb' })); const {pipeline} = require('stream/promises') const https = require('https'); const sslPath = path.join(process.cwd(), 'server/node/ssl/certificate'); -const EXTERNAL_HUB_URL = 'https://sv.risuai.xyz'; -const fetch = require('node-fetch'); +const hubURL = 'https://sv.risuai.xyz'; let password = '' @@ -31,12 +30,17 @@ function isHex(str) { } app.get('/', async (req, res, next) => { - console.log("[Server] Connected") + + const clientIP = req.headers['x-forwarded-for'] || req.ip || req.socket.remoteAddress || 'Unknown IP'; + const timestamp = new Date().toISOString(); + console.log(`[Server] ${timestamp} | Connection from: ${clientIP}`); + try { const mainIndex = await fs.readFile(path.join(process.cwd(), 'dist', 'index.html')) const root = htmlparser.parse(mainIndex) const head = root.querySelector('head') head.innerHTML = `` + head.innerHTML + res.send(root.toString()) } catch (error) { console.log(error) @@ -139,116 +143,49 @@ const reverseProxyFunc_get = async (req, res, next) => { } } -// Risu Realm Proxy -async function hubProxyHandler(req, res, next) { +async function hubProxyFunc(req, res) { + try { - // Extract request path and query parameters const pathAndQuery = req.originalUrl.replace(/^\/hub-proxy/, ''); - const externalURL = EXTERNAL_HUB_URL + pathAndQuery; - - console.log(`[Hub Proxy] Forwarding ${req.method} request to: ${externalURL}`); - - // Prepare headers to send to the realm server (including Accept-Encoding modification) + const externalURL = hubURL + pathAndQuery; + const headersToSend = { ...req.headers }; - delete headersToSend['host']; - delete headersToSend['connection']; - headersToSend['accept-encoding'] = 'gzip, deflate'; // Exclude zstd, etc. - if (!headersToSend['x-forwarded-for']) { - headersToSend['x-forwarded-for'] = req.ip; - } - - // Execute the fetch request to the realm server - const response = await fetch(externalURL, { + delete headersToSend.host; + delete headersToSend.connection; + + const proxyReq = new Request(externalURL, { method: req.method, headers: headersToSend, - body: (req.method !== 'GET' && req.method !== 'HEAD') ? req.body : undefined, + body: req.method !== 'GET' && req.method !== 'HEAD' ? req : undefined, + duplex: 'half' }); - - console.log(`[Hub Proxy] Received status ${response.status} from external server`); - - // Handle the realm server response - // Clean up response headers and extract Content-Type - const responseHeaders = {}; - // Check the Content-Type of the realm server response (use default if missing) - let contentType = response.headers.get('content-type') || 'application/octet-stream'; - - response.headers.forEach((value, key) => { - const lowerKey = key.toLowerCase(); - // List of headers not to be forwarded to the client - const excludedHeaders = [ - 'transfer-encoding', 'connection', 'content-encoding', - 'access-control-allow-origin', 'access-control-allow-methods', - 'access-control-allow-headers', 'content-security-policy', - 'content-security-policy-report-only', 'clear-site-data', - 'strict-transport-security', 'expect-ct', - 'cf-ray', 'cf-cache-status', 'report-to', 'nel', 'server', 'server-timing', 'alt-svc' - ]; - if (!excludedHeaders.includes(lowerKey)) { - responseHeaders[key] = value; - } - }); - - // Set the status code and cleaned headers for the client - res.status(response.status).set(responseHeaders); - - // Determine body processing method based on Content-Type - try { - if (contentType.startsWith('application/json')) { - // JSON response: read as text and send - const bodyText = await response.text(); - console.log(`[Hub Proxy] Processing JSON response (size: ${bodyText.length})`); - res.setHeader('Content-Type', contentType); // Set the final Content-Type - res.send(bodyText); - - } else if (contentType.startsWith('image/')) { - // Image response: read as buffer and send - const bodyBuffer = await response.buffer(); // Assuming 'fetch' response object has a .buffer() method or similar - console.log(`[Hub Proxy] Processing Image response (type: ${contentType}, size: ${bodyBuffer.length} bytes)`); - res.setHeader('Content-Type', contentType); // Set the final Content-Type - res.send(bodyBuffer); - - } else { - // Other responses (HTML, other text, unknown binary, etc.): read as buffer and send safely - const bodyBuffer = await response.buffer(); // Assuming 'fetch' response object has a .buffer() method or similar - console.log(`[Hub Proxy] Processing Other response as buffer (type: ${contentType}, size: ${bodyBuffer.length} bytes)`); - // Use original Content-Type if available, otherwise use octet-stream (already handled by default assignment) - res.setHeader('Content-Type', contentType); - res.send(bodyBuffer); - } - } catch (bodyError) { - // If an error occurs while reading/processing the response body - console.error("[Hub Proxy] Error reading/processing response body:", bodyError); - if (!res.headersSent) { - res.status(500).send({ error: 'Failed to process response body from hub server.' }); - } else { - console.error("[Hub Proxy] Headers already sent, cannot send body error to client."); - res.end(); - } - return; // End the handler + + const response = await fetch(proxyReq); + + for (const [key, value] of response.headers.entries()) { + res.setHeader(key, value); } - + res.status(response.status); + + await pipeline(response.body, res); + } catch (error) { - // Fetch request itself failed or other exceptions - console.error("[Hub Proxy] Request failed:", error); + console.error("[Hub Proxy] Error:", error); if (!res.headersSent) { - res.status(502).send({ error: 'Proxy failed to connect to or get response from the hub server.' }); + res.status(502).send({ error: 'Proxy request failed' }); } else { - console.error("[Hub Proxy] Headers already sent, cannot send connection error to client."); res.end(); } } } -app.get('/hub-proxy/*', hubProxyHandler); -app.post('/hub-proxy/*', hubProxyHandler); -app.put('/hub-proxy/*', hubProxyHandler); - app.get('/proxy', reverseProxyFunc_get); app.get('/proxy2', reverseProxyFunc_get); +app.get('/hub-proxy/*', hubProxyFunc); app.post('/proxy', reverseProxyFunc); app.post('/proxy2', reverseProxyFunc); - +app.post('/hub-proxy/*', hubProxyFunc); app.get('/api/password', async(req, res)=> { if(password === ''){ @@ -408,9 +345,6 @@ async function getHttpsOptions() { const keyPath = path.join(sslPath, 'server.key'); const certPath = path.join(sslPath, 'server.crt'); - console.log(keyPath) - console.log(certPath) - try { await fs.access(keyPath); From 5168565b4f7961e680751a31aceed90453811dc6 Mon Sep 17 00:00:00 2001 From: shirosaki-hana Date: Thu, 17 Apr 2025 17:31:46 +0900 Subject: [PATCH 03/26] Update : server.cjs --- server/node/server.cjs | 29 +++++++++++++++++++---- src/lib/Others/AlertComp.svelte | 2 +- src/lib/Setting/Pages/UserSettings.svelte | 2 +- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/server/node/server.cjs b/server/node/server.cjs index 6e16bcce..b8feb4fd 100644 --- a/server/node/server.cjs +++ b/server/node/server.cjs @@ -153,26 +153,45 @@ async function hubProxyFunc(req, res) { delete headersToSend.host; delete headersToSend.connection; - const proxyReq = new Request(externalURL, { + const response = await fetch(externalURL, { method: req.method, headers: headersToSend, body: req.method !== 'GET' && req.method !== 'HEAD' ? req : undefined, - duplex: 'half' + redirect: 'manual' }); - const response = await fetch(proxyReq); - for (const [key, value] of response.headers.entries()) { res.setHeader(key, value); } res.status(response.status); + if (response.status >= 300 && response.status < 400) { + // Redirect handling (due to ‘/redirect/docs/lua’) + const redirectUrl = response.headers.get('location'); + if (redirectUrl) { + + if (redirectUrl.startsWith('http')) { + + if (redirectUrl.startsWith(hubURL)) { + const newPath = redirectUrl.replace(hubURL, '/hub-proxy'); + res.setHeader('location', newPath); + } + + } else if (redirectUrl.startsWith('/')) { + + res.setHeader('location', `/hub-proxy${redirectUrl}`); + } + } + + return res.end(); + } + await pipeline(response.body, res); } catch (error) { console.error("[Hub Proxy] Error:", error); if (!res.headersSent) { - res.status(502).send({ error: 'Proxy request failed' }); + res.status(502).send({ error: 'Proxy request failed: ' + error.message }); } else { res.end(); } diff --git a/src/lib/Others/AlertComp.svelte b/src/lib/Others/AlertComp.svelte index 16273635..7801aee6 100644 --- a/src/lib/Others/AlertComp.svelte +++ b/src/lib/Others/AlertComp.svelte @@ -72,7 +72,7 @@ { - if(e.origin.startsWith("https://sv.risuai.xyz") || e.origin.startsWith("http://127.0.0.1")){ + if(e.origin.startsWith("https://sv.risuai.xyz") || e.origin.startsWith("http://127.0.0.1") || e.origin === window.location.origin){ if(e.data.msg.data.vaild && $alertStore.type === 'login'){ $alertStore = { type: 'none', diff --git a/src/lib/Setting/Pages/UserSettings.svelte b/src/lib/Setting/Pages/UserSettings.svelte index 95a4a6c5..2cdcb012 100644 --- a/src/lib/Setting/Pages/UserSettings.svelte +++ b/src/lib/Setting/Pages/UserSettings.svelte @@ -19,7 +19,7 @@ { - if(e.origin.startsWith("https://sv.risuai.xyz") || e.origin.startsWith("http://127.0.0.1")){ + if(e.origin.startsWith("https://sv.risuai.xyz") || e.origin.startsWith("http://127.0.0.1") || e.origin === window.location.origin){ if(e.data.msg.type === 'drive'){ await loadRisuAccountData() DBState.db.account.data.refresh_token = e.data.msg.data.refresh_token From 1b62dc95ed385b1291b813440cf73a33edb4cd34 Mon Sep 17 00:00:00 2001 From: shirosaki-hana Date: Fri, 18 Apr 2025 13:18:37 +0900 Subject: [PATCH 04/26] Add duplex --- server/node/server.cjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/node/server.cjs b/server/node/server.cjs index b8feb4fd..0828d9f7 100644 --- a/server/node/server.cjs +++ b/server/node/server.cjs @@ -157,7 +157,8 @@ async function hubProxyFunc(req, res) { method: req.method, headers: headersToSend, body: req.method !== 'GET' && req.method !== 'HEAD' ? req : undefined, - redirect: 'manual' + redirect: 'manual', + duplex: 'half' }); for (const [key, value] of response.headers.entries()) { From 9af38ced76cb1727119c038046f554b8b6494ba2 Mon Sep 17 00:00:00 2001 From: bangonicdd <157843588+bangonicdd2@users.noreply.github.com> Date: Sat, 19 Apr 2025 12:01:53 +0900 Subject: [PATCH 05/26] feat: add persona sort --- src/lib/Setting/Pages/PersonaSettings.svelte | 54 +++++++++++++++++++- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/src/lib/Setting/Pages/PersonaSettings.svelte b/src/lib/Setting/Pages/PersonaSettings.svelte index f6824319..f533ca2a 100644 --- a/src/lib/Setting/Pages/PersonaSettings.svelte +++ b/src/lib/Setting/Pages/PersonaSettings.svelte @@ -8,16 +8,65 @@ import { alertConfirm, alertSelect } from "src/ts/alert"; import { getCharImage } from "src/ts/characters"; import { changeUserPersona, exportUserPersona, importUserPersona, saveUserPersona, selectUserImg } from "src/ts/persona"; + import Sortable from 'sortablejs/modular/sortable.core.esm.js'; + import { onDestroy, onMount } from "svelte"; + import { sleep, sortableOptions } from "src/ts/util"; import { setDatabase } from "src/ts/storage/database.svelte"; import { DBState } from 'src/ts/stores.svelte'; import { get } from "svelte/store"; + let stb: Sortable = null + let ele: HTMLDivElement = $state() + let sorted = $state(0) + const createStb = () => { + stb = Sortable.create(ele, { + onStart: async () => { + saveUserPersona() + }, + onEnd: async () => { + let idx:number[] = [] + ele.querySelectorAll('[data-risu-idx]').forEach((e, i) => { + idx.push(parseInt(e.getAttribute('data-risu-idx'))) + }) + let newValue:{ + personaPrompt:string + name:string + icon:string + largePortrait?:boolean + id?:string + }[] = [] + idx.forEach((i) => { + newValue.push(DBState.db.personas[i]) + }) + DBState.db.personas = newValue + changeUserPersona(0, 'noSave') + try { + stb.destroy() + } catch (error) {} + sorted += 1 + await sleep(1) + createStb() + }, + ...sortableOptions + }) + } + + onMount(createStb) + + onDestroy(() => { + if(stb){ + try { + stb.destroy() + } catch (error) {} + } + })

{language.persona}

-
+{#key sorted} +
{#each DBState.db.personas as persona, i} -
+{/key}
From a7aebab65cdcc31560da4f1e17ff104bf879204c Mon Sep 17 00:00:00 2001 From: bangonicdd <157843588+bangonicdd2@users.noreply.github.com> Date: Sat, 19 Apr 2025 15:34:52 +0900 Subject: [PATCH 06/26] fix: preserve selected persona after sorting --- src/lib/Setting/Pages/PersonaSettings.svelte | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/lib/Setting/Pages/PersonaSettings.svelte b/src/lib/Setting/Pages/PersonaSettings.svelte index f533ca2a..6e2e70c6 100644 --- a/src/lib/Setting/Pages/PersonaSettings.svelte +++ b/src/lib/Setting/Pages/PersonaSettings.svelte @@ -14,13 +14,17 @@ import { setDatabase } from "src/ts/storage/database.svelte"; import { DBState } from 'src/ts/stores.svelte'; import { get } from "svelte/store"; + import { v4 } from "uuid" let stb: Sortable = null let ele: HTMLDivElement = $state() let sorted = $state(0) + let selectedId:string = null const createStb = () => { stb = Sortable.create(ele, { onStart: async () => { + DBState.db.personas[DBState.db.selectedPersona].id ??= v4() + selectedId = DBState.db.personas[DBState.db.selectedPersona].id saveUserPersona() }, onEnd: async () => { @@ -39,7 +43,8 @@ newValue.push(DBState.db.personas[i]) }) DBState.db.personas = newValue - changeUserPersona(0, 'noSave') + const selectedPersona = DBState.db.personas.findIndex((e) => e.id === selectedId) + changeUserPersona(selectedPersona !== -1 ? selectedPersona : 0, 'noSave') try { stb.destroy() } catch (error) {} From 5f1d63dcfb1141545ae0c2d16673ceb196b33dac Mon Sep 17 00:00:00 2001 From: bangonicdd <157843588+bangonicdd2@users.noreply.github.com> Date: Sat, 19 Apr 2025 17:00:18 +0900 Subject: [PATCH 07/26] feat: module lorebook sort, import, export --- .../Setting/Pages/Module/ModuleMenu.svelte | 69 ++++++++++++++++--- src/lib/SideBars/LoreBook/LoreBookList.svelte | 22 +++++- src/ts/process/lorebook.svelte.ts | 2 +- 3 files changed, 80 insertions(+), 13 deletions(-) diff --git a/src/lib/Setting/Pages/Module/ModuleMenu.svelte b/src/lib/Setting/Pages/Module/ModuleMenu.svelte index 82e51fce..d06d16ac 100644 --- a/src/lib/Setting/Pages/Module/ModuleMenu.svelte +++ b/src/lib/Setting/Pages/Module/ModuleMenu.svelte @@ -2,6 +2,9 @@ import { language } from "src/lang"; import TextInput from "src/lib/UI/GUI/TextInput.svelte"; import LoreBookData from "src/lib/SideBars/LoreBook/LoreBookData.svelte"; + import type { loreBook } from "src/ts/storage/database.svelte"; + import LoreBookList from "src/lib/SideBars/LoreBook/LoreBookList.svelte"; + import { type CCLorebook, convertExternalLorebook } from "src/ts/process/lorebook.svelte"; import type { RisuModule } from "src/ts/process/modules"; import { DownloadIcon, FolderUpIcon, PlusIcon, TrashIcon } from "lucide-svelte"; import RegexList from "src/lib/SideBars/Scripts/RegexList.svelte"; @@ -9,7 +12,8 @@ import Check from "src/lib/UI/GUI/CheckInput.svelte"; import Help from "src/lib/Others/Help.svelte"; import TextAreaInput from "src/lib/UI/GUI/TextAreaInput.svelte"; - import { getFileSrc, openURL, saveAsset } from "src/ts/globalApi.svelte"; + import { getFileSrc, openURL, saveAsset, downloadFile } from "src/ts/globalApi.svelte"; + import { alertNormal, alertError } from "src/ts/alert"; import { exportRegex, importRegex } from "src/ts/process/scripts"; import { selectMultipleFile } from "src/ts/util"; @@ -57,6 +61,48 @@ } } + async function exportLoreBook(){ + try { + const lore = currentModule.lorebook + const stringl = Buffer.from(JSON.stringify({ + type: 'risu', + ver: 1, + data: lore + }), 'utf-8') + + await downloadFile(`lorebook_export.json`, stringl) + + alertNormal(language.successExport) + } catch (error) { + alertError(`${error}`) + } + } + + async function importLoreBook(){ + let lore = currentModule.lorebook + const lorebook = (await selectMultipleFile(['json', 'lorebook'])) + if(!lorebook){ + return + } + try { + for(const f of lorebook){ + const importedlore = JSON.parse(Buffer.from(f.data).toString('utf-8')) + if(importedlore.type === 'risu' && importedlore.data){ + const datas:loreBook[] = importedlore.data + for(const data of datas){ + lore.push(data) + } + } + else if(importedlore.entries){ + const entries:{[key:string]:CCLorebook} = importedlore.entries + lore.push(...convertExternalLorebook(entries)) + } + } + } catch (error) { + alertError(`${error}`) + } + } + function addRegex(){ if(Array.isArray(currentModule.regex)){ currentModule.regex.push({ @@ -150,17 +196,18 @@ {/if} {#if submenu === 1 && (Array.isArray(currentModule.lorebook))} -
- {#each currentModule.lorebook as lore, i} - { - currentModule.lorebook.splice(i, 1) - currentModule.lorebook = currentModule.lorebook - }}/> - {/each} + +
+ + +
- {/if} {#if submenu === 2 && (Array.isArray(currentModule.regex))} diff --git a/src/lib/SideBars/LoreBook/LoreBookList.svelte b/src/lib/SideBars/LoreBook/LoreBookList.svelte index 89b1f455..213eec65 100644 --- a/src/lib/SideBars/LoreBook/LoreBookList.svelte +++ b/src/lib/SideBars/LoreBook/LoreBookList.svelte @@ -11,9 +11,10 @@ globalMode?: boolean; submenu?: number; lorePlus?: boolean; + externalLoreBooks?: loreBook[]; } - let { globalMode = false, submenu = 0, lorePlus = false }: Props = $props(); + let { globalMode = false, submenu = 0, lorePlus = false, externalLoreBooks = null }: Props = $props(); let stb: Sortable = null let ele: HTMLDivElement = $state() let sorted = $state(0) @@ -31,6 +32,13 @@ }) DBState.db.loreBook[DBState.db.loreBookPage].data = newLore } + else if(externalLoreBooks){ + let newLore:loreBook[] = [] + idx.forEach((i) => { + newLore.push(externalLoreBooks[i]) + }) + externalLoreBooks = newLore + } else if(submenu === 1){ let newLore:loreBook[] = [] idx.forEach((i) => { @@ -97,6 +105,18 @@ }} onOpen={onOpen} onClose={onClose}/> {/each} {/if} + {:else if externalLoreBooks} + {#if externalLoreBooks.length === 0} + No Lorebook + {:else} + {#each externalLoreBooks as book, i} + { + let lore = externalLoreBooks + lore.splice(i, 1) + externalLoreBooks = lore + }} onOpen={onOpen} onClose={onClose}/> + {/each} + {/if} {:else if submenu === 0} {#if DBState.db.characters[$selectedCharID].globalLore.length === 0} No Lorebook diff --git a/src/ts/process/lorebook.svelte.ts b/src/ts/process/lorebook.svelte.ts index 5e578be7..b81b503d 100644 --- a/src/ts/process/lorebook.svelte.ts +++ b/src/ts/process/lorebook.svelte.ts @@ -510,7 +510,7 @@ export async function importLoreBook(mode:'global'|'local'|'sglobal'){ } } -interface CCLorebook{ +export interface CCLorebook{ key:string[] comment:string content:string From 4703bd463b7fcb98b93f86de3ab0885aa24cd6a6 Mon Sep 17 00:00:00 2001 From: Bo26fhmC5M <88071760+Bo26fhmC5M@users.noreply.github.com> Date: Sun, 20 Apr 2025 14:57:45 +0900 Subject: [PATCH 08/26] feat: add option to show Hypa modal button in chat menu - feat: add accessibility setting to control visibility of Hypa V2/V3 modal button in chat menu - feat: add summarization condition tip to HypaV3 modal --- src/lang/cn.ts | 1 + src/lang/de.ts | 1 + src/lang/en.ts | 6 +++- src/lang/es.ts | 1 + src/lang/ko.ts | 6 +++- src/lang/vi.ts | 1 + src/lang/zh-Hant.ts | 1 + src/lib/ChatScreens/DefaultChatScreen.svelte | 28 +++++++++++++++++-- src/lib/Others/HypaV3Modal.svelte | 23 +++++++++++---- .../Pages/AccessibilitySettings.svelte | 4 +++ src/lib/SideBars/CharConfig.svelte | 8 ++---- src/ts/storage/database.svelte.ts | 1 + 12 files changed, 66 insertions(+), 15 deletions(-) diff --git a/src/lang/cn.ts b/src/lang/cn.ts index 4a4116be..efdf13de 100644 --- a/src/lang/cn.ts +++ b/src/lang/cn.ts @@ -816,6 +816,7 @@ export const languageChinese = { "nextSummarizationLabel": "HypaV3 将总结 [{0}]", "nextSummarizationNoMessagesFoundLabel": "警告:未找到消息", "nextSummarizationLoadingError": "加载下一个总结目标时出错:{0}", + "summarizationConditionLabel": "提示:当输入标记超过最大上下文大小时,HypaV3 将开始进行摘要处理。", "emptySelectedFirstMessageLabel": "警告:所选的第一条消息为空" }, } diff --git a/src/lang/de.ts b/src/lang/de.ts index c3ac6507..744b67a9 100644 --- a/src/lang/de.ts +++ b/src/lang/de.ts @@ -480,6 +480,7 @@ export const languageGerman = { "nextSummarizationLabel": "HypaV3 wird [{0}] zusammenfassen", "nextSummarizationNoMessagesFoundLabel": "WARNUNG: Keine Nachrichten gefunden", "nextSummarizationLoadingError": "Fehler beim Laden des nächsten Zusammenfassungsziels: {0}", + "summarizationConditionLabel": "Hinweis: HypaV3 beginnt mit der Zusammenfassung, wenn die Eingabe-Tokens die maximale Kontextgröße überschreiten.", "emptySelectedFirstMessageLabel": "WARNUNG: Ausgewählte erste Nachricht ist leer" }, } diff --git a/src/lang/en.ts b/src/lang/en.ts index c1cb81df..f410a812 100644 --- a/src/lang/en.ts +++ b/src/lang/en.ts @@ -1052,6 +1052,7 @@ export const languageEnglish = { nextSummarizationLabel: "HypaV3 will summarize [{0}]", nextSummarizationNoMessagesFoundLabel: "WARN: No messages found", nextSummarizationLoadingError: "Error loading next summarization target: {0}", + summarizationConditionLabel: "Tip: HypaV3 begins summarization when input tokens exceed the maximum context size.", emptySelectedFirstMessageLabel: "WARN: Selected first message is empty", }, bulkEnabling: "Lorebook Bulk Enabling", @@ -1115,5 +1116,8 @@ export const languageEnglish = { fallbackWhenBlankResponse: "Fallback When Blank Response", doNotChangeFallbackModels: "Do Not Change Fallback Models on Preset Change", customModels: "Custom Models", - igpPrompt: "IGP Prompt" + igpPrompt: "IGP Prompt", + hypaMemoryV2Modal: "Hypa V2 Modal", + hypaMemoryV3Modal: "Hypa V3 Modal", + showMenuHypaMemoryModal: "Show Menu Hypa Modal", } diff --git a/src/lang/es.ts b/src/lang/es.ts index af4168b1..369cb839 100644 --- a/src/lang/es.ts +++ b/src/lang/es.ts @@ -725,6 +725,7 @@ export const languageSpanish = { "nextSummarizationLabel": "HypaV3 resumirá [{0}]", "nextSummarizationNoMessagesFoundLabel": "ADVERTENCIA: No se encontraron mensajes", "nextSummarizationLoadingError": "Error al cargar el siguiente objetivo de resumen: {0}", + "summarizationConditionLabel": "Consejo: HypaV3 comienza a resumir cuando los tokens de entrada superan el tamaño máximo de contexto.", "emptySelectedFirstMessageLabel": "ADVERTENCIA: El primer mensaje seleccionado está vacío" }, } diff --git a/src/lang/ko.ts b/src/lang/ko.ts index 863ec86c..97c7fbf0 100644 --- a/src/lang/ko.ts +++ b/src/lang/ko.ts @@ -971,7 +971,8 @@ export const languageKorean = { "nextSummarizationLabel": "HypaV3가 [{0}]를 요약할 예정입니다", "nextSummarizationNoMessagesFoundLabel": "경고: 메시지를 찾을 수 없습니다", "nextSummarizationLoadingError": "다음 요약 대상을 불러오는 동안 오류 발생: {0}", - "emptySelectedFirstMessageLabel": "경고: 선택된 첫 메시지가 비어있습니다" + "summarizationConditionLabel": "팁: HypaV3는 입력 토큰이 최대 컨텍스트 크기를 넘으면 요약을 시작합니다.", + "emptySelectedFirstMessageLabel": "경고: 선택된 첫 메시지가 비어있습니다", }, "bulkEnabling": "한번에 로어북 활성화 버튼", "showTranslationLoading": "번역 로딩 보이기", @@ -984,4 +985,7 @@ export const languageKorean = { "childLoreDesc": "이것은 캐릭터 로어의 복사본이며, 삭제하거나 원본 로어에서 직접 비활성화하기 전에는 '언제나 활성화' 상태로 유지됩니다.", "cachePoint": "캐시 포인트", "all": "모두", + "hypaMemoryV2Modal": "하이파 V2 모달", + "hypaMemoryV3Modal": "하이파 V3 모달", + "showMenuHypaMemoryModal": "메뉴에서 하이파 모달 보이기", } diff --git a/src/lang/vi.ts b/src/lang/vi.ts index 4cbe52b2..da26f795 100644 --- a/src/lang/vi.ts +++ b/src/lang/vi.ts @@ -454,6 +454,7 @@ export const LanguageVietnamese = { "nextSummarizationLabel": "HypaV3 sẽ tóm tắt [{0}]", "nextSummarizationNoMessagesFoundLabel": "CẢNH BÁO: Không tìm thấy tin nhắn", "nextSummarizationLoadingError": "Lỗi khi tải mục tiêu tóm tắt tiếp theo: {0}", + "summarizationConditionLabel": "Mẹo: HypaV3 bắt đầu tóm tắt khi số lượng token đầu vào vượt quá kích thước ngữ cảnh tối đa.", "emptySelectedFirstMessageLabel": "CẢNH BÁO: Tin nhắn đầu tiên được chọn trống" }, } diff --git a/src/lang/zh-Hant.ts b/src/lang/zh-Hant.ts index 481587af..300ba5b9 100644 --- a/src/lang/zh-Hant.ts +++ b/src/lang/zh-Hant.ts @@ -849,6 +849,7 @@ export const languageChineseTraditional = { "nextSummarizationLabel": "HypaV3 將摘要 [{0}]", "nextSummarizationNoMessagesFoundLabel": "警告:找不到訊息", "nextSummarizationLoadingError": "載入下一個摘要目標時出錯:{0}", + "summarizationConditionLabel": "提示:當輸入標記超過最大上下文大小時,HypaV3 將開始進行摘要處理。", "emptySelectedFirstMessageLabel": "警告:選定的第一條訊息為空" }, } diff --git a/src/lib/ChatScreens/DefaultChatScreen.svelte b/src/lib/ChatScreens/DefaultChatScreen.svelte index 8449ee70..508c1cf8 100644 --- a/src/lib/ChatScreens/DefaultChatScreen.svelte +++ b/src/lib/ChatScreens/DefaultChatScreen.svelte @@ -2,7 +2,7 @@ import Suggestion from './Suggestion.svelte'; import AdvancedChatEditor from './AdvancedChatEditor.svelte'; - import { CameraIcon, DatabaseIcon, DicesIcon, GlobeIcon, ImagePlusIcon, LanguagesIcon, Laugh, MenuIcon, MicOffIcon, PackageIcon, Plus, RefreshCcwIcon, ReplyIcon, Send, StepForwardIcon, XIcon } from "lucide-svelte"; + import { CameraIcon, DatabaseIcon, DicesIcon, GlobeIcon, ImagePlusIcon, LanguagesIcon, Laugh, MenuIcon, MicOffIcon, PackageIcon, Plus, RefreshCcwIcon, ReplyIcon, Send, StepForwardIcon, XIcon, BrainIcon } from "lucide-svelte"; import { selectedCharID, PlaygroundStore, createSimpleCharacter } from "../../ts/stores.svelte"; import Chat from "./Chat.svelte"; import { type Message, type character, type groupChat } from "../../ts/storage/database.svelte"; @@ -12,7 +12,7 @@ import { findCharacterbyId, getUserIconProtrait, messageForm, sleep } from "../../ts/util"; import { language } from "../../lang"; import { isExpTranslator, translate } from "../../ts/translator/translator"; - import { alertError, alertNormal, alertWait } from "../../ts/alert"; + import { alertError, alertNormal, alertWait, showHypaV2Alert, showHypaV3Alert } from "../../ts/alert"; import sendSound from '../../etc/send.mp3' import { processScript } from "src/ts/process/scripts"; import CreatorQuote from "./CreatorQuote.svelte"; @@ -803,6 +803,30 @@ {language.chatList}
{/if} + + {#if DBState.db.showMenuHypaMemoryModal} + {#if DBState.db.supaModelType !== 'none' && (DBState.db.hypav2 || DBState.db.hypaV3)} +
{ + if (DBState.db.hypav2) { + DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].hypaV2Data ??= { + lastMainChunkID: 0, + mainChunks: [], + chunks: [], + } + showHypaV2Alert(); + } else if (DBState.db.hypaV3) { + showHypaV3Alert(); + } + + openMenu = false + }}> + + + {DBState.db.hypav2 ? language.hypaMemoryV2Modal : language.hypaMemoryV3Modal} + +
+ {/if} + {/if} {#if DBState.db.translator !== ''}
{ diff --git a/src/lib/Others/HypaV3Modal.svelte b/src/lib/Others/HypaV3Modal.svelte index 51451563..bd1bebb5 100644 --- a/src/lib/Others/HypaV3Modal.svelte +++ b/src/lib/Others/HypaV3Modal.svelte @@ -91,6 +91,15 @@ let showImportantOnly = $state(false); $effect.pre(() => { + untrack(() => { + DBState.db.characters[$selectedCharID].chats[ + DBState.db.characters[$selectedCharID].chatPage + ].hypaV3Data ??= { + summaries: [], + lastSelectedSummaries: [], + }; + }); + summaryUIStates = hypaV3DataState.summaries.map((summary) => ({ originalRef: null, isTranslating: false, @@ -1359,14 +1368,18 @@ {/await}
- - {#if !getFirstMessage()} -
+
+
+ {language.hypaV3Modal.summarizationConditionLabel} +
+ + + {#if !getFirstMessage()} {language.hypaV3Modal.emptySelectedFirstMessageLabel} -
- {/if} + {/if} +
diff --git a/src/lib/Setting/Pages/AccessibilitySettings.svelte b/src/lib/Setting/Pages/AccessibilitySettings.svelte index da9dc756..c5ba653a 100644 --- a/src/lib/Setting/Pages/AccessibilitySettings.svelte +++ b/src/lib/Setting/Pages/AccessibilitySettings.svelte @@ -43,6 +43,10 @@ +
+ +
+
diff --git a/src/lib/SideBars/CharConfig.svelte b/src/lib/SideBars/CharConfig.svelte index 7af6beca..c4c90a6e 100644 --- a/src/lib/SideBars/CharConfig.svelte +++ b/src/lib/SideBars/CharConfig.svelte @@ -1101,20 +1101,16 @@ }} className="mt-4" > - {language.HypaMemory} V2 Data + {language.hypaMemoryV2Modal} {:else if DBState.db.supaModelType !== 'none' && DBState.db.hypaV3} {:else if DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].supaMemoryData && DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].supaMemoryData.length > 4 || DBState.db.characters[$selectedCharID].supaMemory} {language.SuperMemory} diff --git a/src/ts/storage/database.svelte.ts b/src/ts/storage/database.svelte.ts index 12618efe..6c7cc284 100644 --- a/src/ts/storage/database.svelte.ts +++ b/src/ts/storage/database.svelte.ts @@ -1022,6 +1022,7 @@ export interface Database{ flags: LLMFlags[] }[] igpPrompt:string + showMenuHypaMemoryModal:boolean } interface SeparateParameters{ From 33d8ed45680f52dbd545cdd12076eaff576052d6 Mon Sep 17 00:00:00 2001 From: sub-hub <70351692+sub-hub@users.noreply.github.com> Date: Mon, 21 Apr 2025 13:27:43 +0900 Subject: [PATCH 09/26] restore tokenizer caching with old-bug version --- src/ts/tokenizer.ts | 162 ++++++++++++++++++++++++++------------------ 1 file changed, 97 insertions(+), 65 deletions(-) diff --git a/src/ts/tokenizer.ts b/src/ts/tokenizer.ts index e71528a4..b553ba27 100644 --- a/src/ts/tokenizer.ts +++ b/src/ts/tokenizer.ts @@ -6,9 +6,27 @@ import { supportsInlayImage } from "./process/files/inlays"; import { risuChatParser } from "./parser.svelte"; import { tokenizeGGUFModel } from "./process/models/local"; import { globalFetch } from "./globalApi.svelte"; -import { getModelInfo, LLMTokenizer } from "./model/modellist"; +import { getModelInfo, LLMTokenizer, type LLMModel } from "./model/modellist"; import { pluginV2 } from "./plugins/plugins"; import type { GemmaTokenizer } from "@huggingface/transformers"; +import { LRUMap } from 'mnemonist'; + +const MAX_CACHE_SIZE = 1500; + +const encodeCache = new LRUMap(MAX_CACHE_SIZE); + +function getHash( + data: string, + aiModel: string, + customTokenizer: string, + currentPluginProvider: string, + googleClaudeTokenizing: boolean, + modelInfo: LLMModel, + pluginTokenizer: string +): string { + const combined = `${data}::${aiModel}::${customTokenizer}::${currentPluginProvider}::${googleClaudeTokenizing ? '1' : '0'}::${modelInfo.tokenizer}::${pluginTokenizer}`; + return combined; +} export const tokenizerList = [ @@ -25,100 +43,114 @@ export const tokenizerList = [ ] as const export async function encode(data:string):Promise<(number[]|Uint32Array|Int32Array)>{ - let db = getDatabase() + const db = getDatabase(); + const modelInfo = getModelInfo(db.aiModel); + const pluginTokenizer = pluginV2.providerOptions.get(db.currentPluginProvider)?.tokenizer ?? "none"; + + let cacheKey = '' + if(db.useTokenizerCaching){ + cacheKey = getHash( + data, + db.aiModel, + db.customTokenizer, + db.currentPluginProvider, + db.googleClaudeTokenizing, + modelInfo, + pluginTokenizer + ); + const cachedResult = encodeCache.get(cacheKey); + if (cachedResult !== undefined) { + return cachedResult; + } + } + + let result: number[] | Uint32Array | Int32Array; + if(db.aiModel === 'openrouter' || db.aiModel === 'reverse_proxy'){ switch(db.customTokenizer){ case 'mistral': - return await tokenizeWebTokenizers(data, 'mistral') + result = await tokenizeWebTokenizers(data, 'mistral'); break; case 'llama': - return await tokenizeWebTokenizers(data, 'llama') + result = await tokenizeWebTokenizers(data, 'llama'); break; case 'novelai': - return await tokenizeWebTokenizers(data, 'novelai') + result = await tokenizeWebTokenizers(data, 'novelai'); break; case 'claude': - return await tokenizeWebTokenizers(data, 'claude') + result = await tokenizeWebTokenizers(data, 'claude'); break; case 'novellist': - return await tokenizeWebTokenizers(data, 'novellist') + result = await tokenizeWebTokenizers(data, 'novellist'); break; case 'llama3': - return await tokenizeWebTokenizers(data, 'llama') + result = await tokenizeWebTokenizers(data, 'llama'); break; case 'gemma': - return await gemmaTokenize(data) + result = await gemmaTokenize(data); break; case 'cohere': - return await tokenizeWebTokenizers(data, 'cohere') + result = await tokenizeWebTokenizers(data, 'cohere'); break; case 'deepseek': - return await tokenizeWebTokenizers(data, 'DeepSeek') + result = await tokenizeWebTokenizers(data, 'DeepSeek'); break; default: - return await tikJS(data, 'o200k_base') + result = await tikJS(data, 'o200k_base'); break; } } - - const modelInfo = getModelInfo(db.aiModel) - - if(db.aiModel === 'custom' && pluginV2.providerOptions.get(db.currentPluginProvider)?.tokenizer){ - const tokenizer = pluginV2.providerOptions.get(db.currentPluginProvider)?.tokenizer - switch(tokenizer){ + + if(db.aiModel === 'custom' && pluginTokenizer){ + switch(pluginTokenizer){ case 'mistral': - return await tokenizeWebTokenizers(data, 'mistral') + result = await tokenizeWebTokenizers(data, 'mistral'); break; case 'llama': - return await tokenizeWebTokenizers(data, 'llama') + result = await tokenizeWebTokenizers(data, 'llama'); break; case 'novelai': - return await tokenizeWebTokenizers(data, 'novelai') + result = await tokenizeWebTokenizers(data, 'novelai'); break; case 'claude': - return await tokenizeWebTokenizers(data, 'claude') + result = await tokenizeWebTokenizers(data, 'claude'); break; case 'novellist': - return await tokenizeWebTokenizers(data, 'novellist') + result = await tokenizeWebTokenizers(data, 'novellist'); break; case 'llama3': - return await tokenizeWebTokenizers(data, 'llama') + result = await tokenizeWebTokenizers(data, 'llama'); break; case 'gemma': - return await gemmaTokenize(data) + result = await gemmaTokenize(data); break; case 'cohere': - return await tokenizeWebTokenizers(data, 'cohere') + result = await tokenizeWebTokenizers(data, 'cohere'); break; case 'o200k_base': - return await tikJS(data, 'o200k_base') + result = await tikJS(data, 'o200k_base'); break; case 'cl100k_base': - return await tikJS(data, 'cl100k_base') + result = await tikJS(data, 'cl100k_base'); break; case 'custom': - return await pluginV2.providerOptions.get(db.currentPluginProvider)?.tokenizerFunc?.(data) ?? [0] + result = await pluginV2.providerOptions.get(db.currentPluginProvider)?.tokenizerFunc?.(data) ?? [0]; break; default: - return await tikJS(data, 'o200k_base') + result = await tikJS(data, 'o200k_base'); break; } - } - + } + if(modelInfo.tokenizer === LLMTokenizer.NovelList){ - const nv= await tokenizeWebTokenizers(data, 'novellist') - return nv - } - if(modelInfo.tokenizer === LLMTokenizer.Claude){ - return await tokenizeWebTokenizers(data, 'claude') - } - if(modelInfo.tokenizer === LLMTokenizer.NovelAI){ - return await tokenizeWebTokenizers(data, 'novelai') - } - if(modelInfo.tokenizer === LLMTokenizer.Mistral){ - return await tokenizeWebTokenizers(data, 'mistral') - } - if(modelInfo.tokenizer === LLMTokenizer.Llama){ - return await tokenizeWebTokenizers(data, 'llama') - } - if(modelInfo.tokenizer === LLMTokenizer.Local){ - return await tokenizeGGUFModel(data) - } - if(modelInfo.tokenizer === LLMTokenizer.tiktokenO200Base){ - return await tikJS(data, 'o200k_base') - } - if(modelInfo.tokenizer === LLMTokenizer.GoogleCloud && db.googleClaudeTokenizing){ - return await tokenizeGoogleCloud(data) - } - if(modelInfo.tokenizer === LLMTokenizer.Gemma || modelInfo.tokenizer === LLMTokenizer.GoogleCloud){ - return await gemmaTokenize(data) - } - if(modelInfo.tokenizer === LLMTokenizer.DeepSeek){ - return await tokenizeWebTokenizers(data, 'DeepSeek') - } - if(modelInfo.tokenizer === LLMTokenizer.Cohere){ - return await tokenizeWebTokenizers(data, 'cohere') + result = await tokenizeWebTokenizers(data, 'novellist'); + } else if(modelInfo.tokenizer === LLMTokenizer.Claude){ + result = await tokenizeWebTokenizers(data, 'claude'); + } else if(modelInfo.tokenizer === LLMTokenizer.NovelAI){ + result = await tokenizeWebTokenizers(data, 'novelai'); + } else if(modelInfo.tokenizer === LLMTokenizer.Mistral){ + result = await tokenizeWebTokenizers(data, 'mistral'); + } else if(modelInfo.tokenizer === LLMTokenizer.Llama){ + result = await tokenizeWebTokenizers(data, 'llama'); + } else if(modelInfo.tokenizer === LLMTokenizer.Local){ + result = await tokenizeGGUFModel(data); + } else if(modelInfo.tokenizer === LLMTokenizer.tiktokenO200Base){ + result = await tikJS(data, 'o200k_base'); + } else if(modelInfo.tokenizer === LLMTokenizer.GoogleCloud && db.googleClaudeTokenizing){ + result = await tokenizeGoogleCloud(data); + } else if(modelInfo.tokenizer === LLMTokenizer.Gemma || modelInfo.tokenizer === LLMTokenizer.GoogleCloud){ + result = await gemmaTokenize(data); + } else if(modelInfo.tokenizer === LLMTokenizer.DeepSeek){ + result = await tokenizeWebTokenizers(data, 'DeepSeek'); + } else if(modelInfo.tokenizer === LLMTokenizer.Cohere){ + result = await tokenizeWebTokenizers(data, 'cohere'); + } else { + result = await tikJS(data); } - return await tikJS(data) + if(db.useTokenizerCaching){ + encodeCache.set(cacheKey, result); + } + + return result; } type tokenizerType = 'novellist'|'claude'|'novelai'|'llama'|'mistral'|'llama3'|'gemma'|'cohere'|'googleCloud'|'DeepSeek' From 09228f3f867a2f05b24e5bf1163ab743e3913894 Mon Sep 17 00:00:00 2001 From: sub-hub <70351692+sub-hub@users.noreply.github.com> Date: Mon, 21 Apr 2025 13:34:01 +0900 Subject: [PATCH 10/26] Fix: Correct tokenize flow in tokenizer encode function --- src/ts/tokenizer.ts | 56 ++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/ts/tokenizer.ts b/src/ts/tokenizer.ts index b553ba27..1e433534 100644 --- a/src/ts/tokenizer.ts +++ b/src/ts/tokenizer.ts @@ -89,9 +89,7 @@ export async function encode(data:string):Promise<(number[]|Uint32Array|Int32Arr default: result = await tikJS(data, 'o200k_base'); break; } - } - - if(db.aiModel === 'custom' && pluginTokenizer){ + } else if (db.aiModel === 'custom' && pluginTokenizer) { switch(pluginTokenizer){ case 'mistral': result = await tokenizeWebTokenizers(data, 'mistral'); break; @@ -120,32 +118,34 @@ export async function encode(data:string):Promise<(number[]|Uint32Array|Int32Arr } } - if(modelInfo.tokenizer === LLMTokenizer.NovelList){ - result = await tokenizeWebTokenizers(data, 'novellist'); - } else if(modelInfo.tokenizer === LLMTokenizer.Claude){ - result = await tokenizeWebTokenizers(data, 'claude'); - } else if(modelInfo.tokenizer === LLMTokenizer.NovelAI){ - result = await tokenizeWebTokenizers(data, 'novelai'); - } else if(modelInfo.tokenizer === LLMTokenizer.Mistral){ - result = await tokenizeWebTokenizers(data, 'mistral'); - } else if(modelInfo.tokenizer === LLMTokenizer.Llama){ - result = await tokenizeWebTokenizers(data, 'llama'); - } else if(modelInfo.tokenizer === LLMTokenizer.Local){ - result = await tokenizeGGUFModel(data); - } else if(modelInfo.tokenizer === LLMTokenizer.tiktokenO200Base){ - result = await tikJS(data, 'o200k_base'); - } else if(modelInfo.tokenizer === LLMTokenizer.GoogleCloud && db.googleClaudeTokenizing){ - result = await tokenizeGoogleCloud(data); - } else if(modelInfo.tokenizer === LLMTokenizer.Gemma || modelInfo.tokenizer === LLMTokenizer.GoogleCloud){ - result = await gemmaTokenize(data); - } else if(modelInfo.tokenizer === LLMTokenizer.DeepSeek){ - result = await tokenizeWebTokenizers(data, 'DeepSeek'); - } else if(modelInfo.tokenizer === LLMTokenizer.Cohere){ - result = await tokenizeWebTokenizers(data, 'cohere'); - } else { - result = await tikJS(data); + // Fallback + if (result === undefined) { + if(modelInfo.tokenizer === LLMTokenizer.NovelList){ + result = await tokenizeWebTokenizers(data, 'novellist'); + } else if(modelInfo.tokenizer === LLMTokenizer.Claude){ + result = await tokenizeWebTokenizers(data, 'claude'); + } else if(modelInfo.tokenizer === LLMTokenizer.NovelAI){ + result = await tokenizeWebTokenizers(data, 'novelai'); + } else if(modelInfo.tokenizer === LLMTokenizer.Mistral){ + result = await tokenizeWebTokenizers(data, 'mistral'); + } else if(modelInfo.tokenizer === LLMTokenizer.Llama){ + result = await tokenizeWebTokenizers(data, 'llama'); + } else if(modelInfo.tokenizer === LLMTokenizer.Local){ + result = await tokenizeGGUFModel(data); + } else if(modelInfo.tokenizer === LLMTokenizer.tiktokenO200Base){ + result = await tikJS(data, 'o200k_base'); + } else if(modelInfo.tokenizer === LLMTokenizer.GoogleCloud && db.googleClaudeTokenizing){ + result = await tokenizeGoogleCloud(data); + } else if(modelInfo.tokenizer === LLMTokenizer.Gemma || modelInfo.tokenizer === LLMTokenizer.GoogleCloud){ + result = await gemmaTokenize(data); + } else if(modelInfo.tokenizer === LLMTokenizer.DeepSeek){ + result = await tokenizeWebTokenizers(data, 'DeepSeek'); + } else if(modelInfo.tokenizer === LLMTokenizer.Cohere){ + result = await tokenizeWebTokenizers(data, 'cohere'); + } else { + result = await tikJS(data); + } } - if(db.useTokenizerCaching){ encodeCache.set(cacheKey, result); } From 2a36743cb6966b3a193dbb692bde6acabf547c7f Mon Sep 17 00:00:00 2001 From: sub-hub <70351692+sub-hub@users.noreply.github.com> Date: Mon, 21 Apr 2025 14:57:19 +0900 Subject: [PATCH 11/26] Fix: Potential problem in tikJS function --- src/ts/tokenizer.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ts/tokenizer.ts b/src/ts/tokenizer.ts index 1e433534..25fb442d 100644 --- a/src/ts/tokenizer.ts +++ b/src/ts/tokenizer.ts @@ -209,6 +209,7 @@ async function gemmaTokenize(text:string) { async function tikJS(text:string, model='cl100k_base') { if(!tikParser || lastTikModel !== model){ + tikParser?.free() if(model === 'cl100k_base'){ const {Tiktoken} = await import('@dqbd/tiktoken') const cl100k_base = await import("@dqbd/tiktoken/encoders/cl100k_base.json"); From 0f70c5404abb1e817b6877ec433e903d109b6ab2 Mon Sep 17 00:00:00 2001 From: TiamaTiramisu Date: Mon, 21 Apr 2025 11:42:42 +0900 Subject: [PATCH 12/26] fix: avoid flatMap crash when output.images is undefined --- src/ts/process/stableDiff.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ts/process/stableDiff.ts b/src/ts/process/stableDiff.ts index fb24033a..b1c09b1e 100644 --- a/src/ts/process/stableDiff.ts +++ b/src/ts/process/stableDiff.ts @@ -435,7 +435,7 @@ export async function generateAIImage(genPrompt:string, currentChar:character, n } await new Promise(r => setTimeout(r, 1000)) } // Check history until the generation is complete. - const genImgInfo = Object.values(item.outputs).flatMap((output: any) => output.images)[0]; + const genImgInfo = Object.values(item.outputs).flatMap((output: any) => output.images || [])[0]; const imgResponse = await fetchNative(createUrl('/view', { filename: genImgInfo.filename, From 91e3a352a376084e45edc3e340ffbcbf51613de3 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Wed, 23 Apr 2025 12:26:27 +0900 Subject: [PATCH 13/26] Change download to blob --- src/ts/globalApi.svelte.ts | 11 ++++++++++- src/ts/process/scripts.ts | 4 +--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/ts/globalApi.svelte.ts b/src/ts/globalApi.svelte.ts index 72c2feee..ed4d607d 100644 --- a/src/ts/globalApi.svelte.ts +++ b/src/ts/globalApi.svelte.ts @@ -87,7 +87,16 @@ export async function downloadFile(name:string, dat:Uint8Array|ArrayBuffer|strin await writeFile(name, data, {baseDir: BaseDirectory.Download}) } else{ - downloadURL(`data:png/image;base64,${Buffer.from(data).toString('base64')}`, name) + const blob = new Blob([data], { type: 'application/octet-stream' }) + const url = URL.createObjectURL(blob) + + downloadURL(url, name) + + setTimeout(() => { + URL.revokeObjectURL(url) + }, 10000) + + } } diff --git a/src/ts/process/scripts.ts b/src/ts/process/scripts.ts index 3c95ab81..ed4c9ed7 100644 --- a/src/ts/process/scripts.ts +++ b/src/ts/process/scripts.ts @@ -74,9 +74,7 @@ function generateScriptCacheKey(scripts: customscript[], data: string, mode: Scr if(script.type !== mode){ continue } - hash += `${script.flag?.includes('') ? - risuChatParser(script.in, { chatID: chatID, cbsConditions }) : - script.in}|||${risuChatParser(script.out, { chatID: chatID, cbsConditions})}|||${script.flag ?? ''}|||${script.ableFlag ? 1 : 0}`; + hash += `${script.flag?.includes('') ? risuChatParser(script.in, { chatID: chatID, cbsConditions }) : script.in}|||${script.out}${chatID}|||${script.flag ?? ''}|||${script.ableFlag ? 1 : 0}`; } return hash; } From e029456f01a7a0a6a867306149512cdd239584c1 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Wed, 23 Apr 2025 12:29:45 +0900 Subject: [PATCH 14/26] Fix comment --- src/ts/parser.svelte.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ts/parser.svelte.ts b/src/ts/parser.svelte.ts index 54824838..1613470c 100644 --- a/src/ts/parser.svelte.ts +++ b/src/ts/parser.svelte.ts @@ -2124,7 +2124,7 @@ export function risuChatParser(da:string, arg:{ break } } - if(dat.startsWith('/')){ + if(dat.startsWith('/') && !dat.startsWith('//')){ if(stackType[nested.length] === 5){ const blockType = blockNestType.get(nested.length) if( blockType.type === 'ignore' || blockType.type === 'pure' || From e443eadb12ab76d9cb611aadacbc700e478d1b97 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Wed, 23 Apr 2025 12:36:34 +0900 Subject: [PATCH 15/26] Add code cbs --- src/ts/parser.svelte.ts | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/ts/parser.svelte.ts b/src/ts/parser.svelte.ts index 1613470c..3438294f 100644 --- a/src/ts/parser.svelte.ts +++ b/src/ts/parser.svelte.ts @@ -1877,7 +1877,7 @@ const legacyBlockMatcher = (p1:string,matcherArg:matcherArg) => { return null } -type blockMatch = 'ignore'|'parse'|'nothing'|'parse-pure'|'pure'|'each'|'function'|'pure-display' +type blockMatch = 'ignore'|'parse'|'nothing'|'parse-pure'|'pure'|'each'|'function'|'pure-display'|'normalize' function parseArray(p1:string):string[]{ try { @@ -1923,6 +1923,10 @@ function blockStartMatcher(p1:string,matcherArg:matcherArg):{type:blockMatch,typ if(p1 === '#pure_display' || p1 === '#puredisplay'){ return {type:'pure-display'} } + if(p1 === '#code'){ + return {type:'normalize'} + + } if(p1.startsWith('#each')){ let t2 = p1.substring(5).trim() if(t2.startsWith('as ')){ @@ -1963,6 +1967,31 @@ function blockEndMatcher(p1:string,type:{type:blockMatch,type2?:string},matcherA case 'parse-pure':{ return p1 } + case 'normalize':{ + return p1Trimed.trim().replaceAll('\n','').replaceAll('\t','') + .replaceAll(/\\(.)/g, (match, p1) => { + switch(p1){ + case 'n': + return '\n' + case 'r': + return '\r' + case 't': + return '\t' + case 'b': + return '\b' + case 'f': + return '\f' + case 'v': + return '\v' + case 'a': + return '\a' + case 'x': + return '\x00' + default: + return p1 + } + }) + } default:{ return '' } From 2ca28aff78b9027a9bcea02d722384dda64e7dd9 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Wed, 23 Apr 2025 12:37:40 +0900 Subject: [PATCH 16/26] Add u escape --- src/ts/parser.svelte.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ts/parser.svelte.ts b/src/ts/parser.svelte.ts index 3438294f..c562bcbd 100644 --- a/src/ts/parser.svelte.ts +++ b/src/ts/parser.svelte.ts @@ -1969,6 +1969,9 @@ function blockEndMatcher(p1:string,type:{type:blockMatch,type2?:string},matcherA } case 'normalize':{ return p1Trimed.trim().replaceAll('\n','').replaceAll('\t','') + .replaceAll(/\\u([0-9A-Fa-f]{4})/g, (match, p1) => { + return String.fromCharCode(parseInt(p1, 16)) + }) .replaceAll(/\\(.)/g, (match, p1) => { switch(p1){ case 'n': From 59fdcc20b3ee3f6e3b52653be8f4800b19dd53a4 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Wed, 23 Apr 2025 12:40:38 +0900 Subject: [PATCH 17/26] Add randint and cbr, cnl, cnewline --- src/ts/parser.svelte.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/ts/parser.svelte.ts b/src/ts/parser.svelte.ts index c562bcbd..7c234648 100644 --- a/src/ts/parser.svelte.ts +++ b/src/ts/parser.svelte.ts @@ -1677,6 +1677,19 @@ function basicMatcher (p1:string,matcherArg:matcherArg,vars:{[key:string]:string case 'hash':{ return ((pickHashRand(0, arra[1]) * 10000000) + 1).toFixed(0).padStart(7, '0') } + case 'randint':{ + const min = Number(arra[1]) + const max = Number(arra[2]) + if(isNaN(min) || isNaN(max)){ + return 'NaN' + } + return (Math.floor(Math.random() * (max - min + 1)) + min).toString() + } + case 'cbr': + case 'cnl': + case 'cnewline':{ + return '\\n' + } } } if(p1.startsWith('random')){ From 89257b2ed4ccaf9ce8a49a21ad924897cc5f59a3 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Wed, 23 Apr 2025 12:41:48 +0900 Subject: [PATCH 18/26] Accept cbr,cnl,cnewline without params --- src/ts/parser.svelte.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ts/parser.svelte.ts b/src/ts/parser.svelte.ts index 7c234648..3f4fe8d6 100644 --- a/src/ts/parser.svelte.ts +++ b/src/ts/parser.svelte.ts @@ -1239,6 +1239,11 @@ function basicMatcher (p1:string,matcherArg:matcherArg,vars:{[key:string]:string case 'screen_height':{ return get(SizeStore).h.toString() } + case 'cbr': + case 'cnl': + case 'cnewline':{ + return '\\n' + } } const arra = p1.split("::") if(arra.length > 1){ @@ -1688,7 +1693,7 @@ function basicMatcher (p1:string,matcherArg:matcherArg,vars:{[key:string]:string case 'cbr': case 'cnl': case 'cnewline':{ - return '\\n' + return '\\n'.repeat(Number(arra[1])) } } } From 39048dd142e1fcc5591ae203b739463442c4ef9a Mon Sep 17 00:00:00 2001 From: kwaroran Date: Wed, 23 Apr 2025 12:44:32 +0900 Subject: [PATCH 19/26] Add dice CBS --- src/ts/parser.svelte.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/ts/parser.svelte.ts b/src/ts/parser.svelte.ts index 3f4fe8d6..2aeca4a2 100644 --- a/src/ts/parser.svelte.ts +++ b/src/ts/parser.svelte.ts @@ -1695,6 +1695,19 @@ function basicMatcher (p1:string,matcherArg:matcherArg,vars:{[key:string]:string case 'cnewline':{ return '\\n'.repeat(Number(arra[1])) } + case 'dice':{ + const notation = arra[1].split('d') + const num = Number(notation[0]) + const sides = Number(notation[1]) + if(isNaN(num) || isNaN(sides)){ + return 'NaN' + } + let total = 0 + for(let i = 0; i < num; i++){ + total += Math.floor(Math.random() * sides) + 1 + } + return total.toString() + } } } if(p1.startsWith('random')){ From a899a02d301eb5296f37545c541a48e4f9a03c39 Mon Sep 17 00:00:00 2001 From: niceandneat Date: Mon, 28 Apr 2025 01:19:47 +0900 Subject: [PATCH 20/26] Add nai cfg_rescale, noise_schedule options settings --- src/lib/Setting/Pages/OtherBotSettings.svelte | 13 +++++++++++++ src/ts/process/stableDiff.ts | 4 ++-- src/ts/storage/database.svelte.ts | 4 ++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/lib/Setting/Pages/OtherBotSettings.svelte b/src/lib/Setting/Pages/OtherBotSettings.svelte index 13b8e9bd..474eb59b 100644 --- a/src/lib/Setting/Pages/OtherBotSettings.svelte +++ b/src/lib/Setting/Pages/OtherBotSettings.svelte @@ -26,8 +26,10 @@ width: 512, height: 512, sampler: 'k_euler', + noise_schedule: 'native', steps: 100, scale: 1, + cfg_rescale: 0, sm: false, sm_dyn: false, strength: 0.5, @@ -245,10 +247,21 @@ {/if} + Noise Schedule + + Choose... + native + karras + exponential + polyexponential + + steps CFG scale + CFG rescale + {#if !DBState.db.NAII2I || DBState.db.NAIImgConfig.sampler !== 'ddim_v3'} diff --git a/src/ts/process/stableDiff.ts b/src/ts/process/stableDiff.ts index fb24033a..34ed094e 100644 --- a/src/ts/process/stableDiff.ts +++ b/src/ts/process/stableDiff.ts @@ -132,7 +132,7 @@ export async function generateAIImage(genPrompt:string, currentChar:character, n "parameters": { "params_version": 3, "add_original_image": true, - "cfg_rescale": 0, + "cfg_rescale": db.NAIImgConfig.cfg_rescale, "controlnet_strength": 1, "dynamic_thresholding": false, "n_samples": 1, @@ -145,7 +145,7 @@ export async function generateAIImage(genPrompt:string, currentChar:character, n "sm": false, "sm_dyn": false, "noise": db.NAIImgConfig.noise, - "noise_schedule": "native", + "noise_schedule": db.NAIImgConfig.noise_schedule, "strength": db.NAIImgConfig.strength, "ucPreset": 3, "uncond_scale": 1, diff --git a/src/ts/storage/database.svelte.ts b/src/ts/storage/database.svelte.ts index 1c0f6aad..49d9a5a8 100644 --- a/src/ts/storage/database.svelte.ts +++ b/src/ts/storage/database.svelte.ts @@ -255,8 +255,10 @@ export function setDatabase(data:Database){ width:512, height:768, sampler:"k_dpmpp_sde", + noise_schedule:"native", steps:28, scale:5, + cfg_rescale: 0, sm:true, sm_dyn:false, noise:0.0, @@ -1408,8 +1410,10 @@ export interface NAIImgConfig{ width:number, height:number, sampler:string, + noise_schedule:string, steps:number, scale:number, + cfg_rescale:number, sm:boolean, sm_dyn:boolean, noise:number, From 05c51f333ff5809f60eec2114be247ae515ae8f4 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Mon, 28 Apr 2025 15:38:57 +0900 Subject: [PATCH 21/26] Implement lazy loading of chats via lazy portal --- src/lib/ChatScreens/DefaultChatScreen.svelte | 215 ++++++++++--------- src/lib/UI/GUI/LazyPortal.svelte | 65 ++++++ src/ts/parser.svelte.ts | 6 + 3 files changed, 190 insertions(+), 96 deletions(-) create mode 100644 src/lib/UI/GUI/LazyPortal.svelte diff --git a/src/lib/ChatScreens/DefaultChatScreen.svelte b/src/lib/ChatScreens/DefaultChatScreen.svelte index 8449ee70..9fe92edd 100644 --- a/src/lib/ChatScreens/DefaultChatScreen.svelte +++ b/src/lib/ChatScreens/DefaultChatScreen.svelte @@ -29,11 +29,11 @@ import PlaygroundMenu from '../Playground/PlaygroundMenu.svelte'; import { ConnectionOpenStore } from 'src/ts/sync/multiuser'; import { coldStorageHeader, preLoadChat } from 'src/ts/process/coldstorage.svelte'; + import LazyPortal from '../UI/GUI/LazyPortal.svelte'; let messageInput:string = $state('') let messageInputTranslate:string = $state('') let openMenu = $state(false) - let loadPages = $state(30) let autoMode = $state(false) let rerolls:Message[][] = [] let rerollid = -1 @@ -42,6 +42,23 @@ let currentCharacter:character|groupChat = $state(DBState.db.characters[$selectedCharID]) let toggleStickers:boolean = $state(false) let fileInput:string[] = $state([]) + let blocks = $state(new Uint8Array(500) )//hacky hacky + let blockEle:HTMLElement[] = [] + let root: HTMLElement = $state(null) + + for(let i=0;i<500;i++){ + blockEle.push(null) + } + + $effect(() => { + if(blocks.length-10 < DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message.length){ + blocks = new Uint8Array(blocks.length + 500) + for(let i=0;i<500;i++){ + blockEle.push(null) + } + } + + }) async function send(){ return sendMain(false) @@ -365,7 +382,6 @@ async function screenShot(){ try { - loadPages = Infinity const html2canvas = await import('html-to-image'); const chats = document.querySelectorAll('.default-chat-screen .risu-chat') alertWait("Taking screenShot...") @@ -412,7 +428,6 @@ mergedCanvas.remove(); } alertNormal(language.screenshotSaved) - loadPages = 10 } catch (error) { console.error(error) alertError("Error while taking screenshot") @@ -435,13 +450,7 @@ {/if} {:else} -
{ - //@ts-ignore - const scrolled = (e.target.scrollHeight - e.target.clientHeight + e.target.scrollTop) - if(scrolled < 100 && DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message.length > loadPages){ - loadPages += 15 - } - }}> +
{/if} + {#each blocks as block, i} +
+ +
+ {/each} + {#if DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message?.[0]?.data?.startsWith(coldStorageHeader) } {#await preLoadChat($selectedCharID, DBState.db.characters[$selectedCharID].chatPage)}
@@ -658,103 +676,108 @@
{/await} {:else} - {#each messageForm(DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message, loadPages) as chat, i} - {#if chat.role === 'char'} - {#if DBState.db.characters[$selectedCharID].type !== 'group'} - + + {#each DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message as chat, i} + + {#if chat.role === 'char'} + {#if DBState.db.characters[$selectedCharID].type !== 'group'} + + {:else} + + {/if} {:else} {/if} - {:else} - - {/if} + {/each} - {#if DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage].message.length <= loadPages} - {#if DBState.db.characters[$selectedCharID].type !== 'group' } - 0} - largePortrait={DBState.db.characters[$selectedCharID].largePortrait} - firstMessage={true} - onReroll={() => { - const cha = DBState.db.characters[$selectedCharID] - const chat = DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage] - if(cha.type !== 'group'){ - if (chat.fmIndex >= (cha.alternateGreetings.length - 1)){ - chat.fmIndex = -1 - } - else{ - chat.fmIndex += 1 - } - } - DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage] = chat - }} - unReroll={() => { - const cha = DBState.db.characters[$selectedCharID] - const chat = DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage] - if(cha.type !== 'group'){ - if (chat.fmIndex === -1){ - chat.fmIndex = (cha.alternateGreetings.length - 1) - } - else{ - chat.fmIndex -= 1 - } - } - DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage] = chat - }} - isLastMemory={false} + - /> - {#if !DBState.db.characters[$selectedCharID].removedQuotes && DBState.db.characters[$selectedCharID].creatorNotes.length >= 2} - { - const cha = DBState.db.characters[$selectedCharID] - if(cha.type !== 'group'){ - cha.removedQuotes = true - } - DBState.db.characters[$selectedCharID] = cha - }} /> + {#if DBState.db.characters[$selectedCharID].type !== 'group' } + 0} + largePortrait={DBState.db.characters[$selectedCharID].largePortrait} + firstMessage={true} + onReroll={() => { + const cha = DBState.db.characters[$selectedCharID] + const chat = DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage] + if(cha.type !== 'group'){ + if (chat.fmIndex >= (cha.alternateGreetings.length - 1)){ + chat.fmIndex = -1 + } + else{ + chat.fmIndex += 1 + } + } + DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage] = chat + }} + unReroll={() => { + const cha = DBState.db.characters[$selectedCharID] + const chat = DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage] + if(cha.type !== 'group'){ + if (chat.fmIndex === -1){ + chat.fmIndex = (cha.alternateGreetings.length - 1) + } + else{ + chat.fmIndex -= 1 + } + } + DBState.db.characters[$selectedCharID].chats[DBState.db.characters[$selectedCharID].chatPage] = chat + }} + isLastMemory={false} + + /> + {#if !DBState.db.characters[$selectedCharID].removedQuotes && DBState.db.characters[$selectedCharID].creatorNotes.length >= 2} + { + const cha = DBState.db.characters[$selectedCharID] + if(cha.type !== 'group'){ + cha.removedQuotes = true + } + DBState.db.characters[$selectedCharID] = cha + }} /> + {/if} {/if} - {/if} - {/if} + + {/if} diff --git a/src/lib/UI/GUI/LazyPortal.svelte b/src/lib/UI/GUI/LazyPortal.svelte new file mode 100644 index 00000000..b22152d5 --- /dev/null +++ b/src/lib/UI/GUI/LazyPortal.svelte @@ -0,0 +1,65 @@ + \ No newline at end of file diff --git a/src/ts/parser.svelte.ts b/src/ts/parser.svelte.ts index 2aeca4a2..20b20a58 100644 --- a/src/ts/parser.svelte.ts +++ b/src/ts/parser.svelte.ts @@ -1708,6 +1708,12 @@ function basicMatcher (p1:string,matcherArg:matcherArg,vars:{[key:string]:string } return total.toString() } + case 'fromhex':{ + return Number.parseInt(arra[1], 16).toString() + } + case 'tohex':{ + return Number.parseInt(arra[1]).toString(16) + } } } if(p1.startsWith('random')){ From 780cbce164c6f5974bfde64b402e4ed569a51c8b Mon Sep 17 00:00:00 2001 From: kwaroran Date: Mon, 28 Apr 2025 15:47:06 +0900 Subject: [PATCH 22/26] Remove sleep --- src/lib/UI/GUI/LazyPortal.svelte | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/lib/UI/GUI/LazyPortal.svelte b/src/lib/UI/GUI/LazyPortal.svelte index b22152d5..5d70245d 100644 --- a/src/lib/UI/GUI/LazyPortal.svelte +++ b/src/lib/UI/GUI/LazyPortal.svelte @@ -27,25 +27,23 @@ target.appendChild(paddingEle) - sleep(100).then(() => { - const observer = new IntersectionObserver((v) => { - if(v[0].intersectionRatio > 0.5){ - seen = true - target.removeChild(paddingEle) - observer.disconnect() - } - }, { - threshold: 0.5, - }) - - observer.observe(target) - - return () => { - if(!seen){ - observer.disconnect() - } + const observer = new IntersectionObserver((v) => { + if(v[0].intersectionRatio > 0.5){ + seen = true + target.removeChild(paddingEle) + observer.disconnect() } + }, { + threshold: 0.5, }) + + observer.observe(target) + + return () => { + if(!seen){ + observer.disconnect() + } + } }) $effect(() => { From bf55f77e0d14d2c7ddbf32b0fb3b9ed7d002f045 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Mon, 28 Apr 2025 16:09:29 +0900 Subject: [PATCH 23/26] Upgrade dep --- package.json | 8 +- pnpm-lock.yaml | 392 ++++------------------------------------ src-tauri/Cargo.toml | 2 +- src/ts/parser.svelte.ts | 2 +- 4 files changed, 39 insertions(+), 365 deletions(-) diff --git a/package.json b/package.json index 99f759a0..5e944acf 100644 --- a/package.json +++ b/package.json @@ -28,16 +28,18 @@ "@huggingface/transformers": "^3.1.1", "@mlc-ai/web-tokenizers": "^0.1.2", "@risuai/ccardlib": "^0.4.1", + "@rollup/rollup-win32-arm64-msvc": "^4.40.1", "@smithy/protocol-http": "^3.0.12", "@smithy/signature-v4": "^2.0.19", "@tauri-apps/api": "2.0.0", + "@tauri-apps/cli-win32-arm64-msvc": "^2.5.0", "@tauri-apps/plugin-deep-link": "~2", "@tauri-apps/plugin-dialog": "~2", "@tauri-apps/plugin-fs": "~2", "@tauri-apps/plugin-http": "~2", "@tauri-apps/plugin-os": "~2", "@tauri-apps/plugin-process": "~2", - "@tauri-apps/plugin-shell": "~2", + "@tauri-apps/plugin-shell": "2.2.1", "@tauri-apps/plugin-updater": "~2", "@types/markdown-it": "^14.1.1", "blueimp-md5": "^2.19.0", @@ -49,7 +51,7 @@ "cors": "^2.8.5", "crc": "^4.3.2", "diff": "^7.0.0", - "dompurify": "^3.0.8", + "dompurify": "^3.2.5", "eventsource-parser": "^1.1.2", "exifr": "^7.1.3", "express": "^4.18.2", @@ -58,7 +60,6 @@ "gpt3-tokenizer": "^1.1.5", "highlight.js": "^11.9.0", "html-to-image": "^1.11.11", - "isomorphic-dompurify": "^1.13.0", "jszip": "^3.10.1", "libsodium-wrappers-sumo": "^0.7.13", "localforage": "^1.10.0", @@ -102,7 +103,6 @@ "@types/blueimp-md5": "^2.18.2", "@types/codemirror": "^5.60.15", "@types/diff": "^6.0.0", - "@types/dompurify": "^3.0.5", "@types/libsodium-wrappers-sumo": "^0.7.8", "@types/lodash": "^4.14.202", "@types/lodash.isequal": "^4.5.8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f247c718..71ece55d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,6 +44,9 @@ importers: '@risuai/ccardlib': specifier: ^0.4.1 version: 0.4.1 + '@rollup/rollup-win32-arm64-msvc': + specifier: ^4.40.1 + version: 4.40.1 '@smithy/protocol-http': specifier: ^3.0.12 version: 3.0.12 @@ -53,6 +56,9 @@ importers: '@tauri-apps/api': specifier: 2.0.0 version: 2.0.0 + '@tauri-apps/cli-win32-arm64-msvc': + specifier: ^2.5.0 + version: 2.5.0 '@tauri-apps/plugin-deep-link': specifier: ~2 version: 2.0.0 @@ -72,8 +78,8 @@ importers: specifier: ~2 version: 2.0.0 '@tauri-apps/plugin-shell': - specifier: ~2 - version: 2.0.0 + specifier: 2.2.1 + version: 2.2.1 '@tauri-apps/plugin-updater': specifier: ~2 version: 2.0.0 @@ -108,8 +114,8 @@ importers: specifier: ^7.0.0 version: 7.0.0 dompurify: - specifier: ^3.0.8 - version: 3.0.8 + specifier: ^3.2.5 + version: 3.2.5 eventsource-parser: specifier: ^1.1.2 version: 1.1.2 @@ -134,9 +140,6 @@ importers: html-to-image: specifier: ^1.11.11 version: 1.11.11 - isomorphic-dompurify: - specifier: ^1.13.0 - version: 1.13.0(canvas@2.11.2) jszip: specifier: ^3.10.1 version: 3.10.1 @@ -261,9 +264,6 @@ importers: '@types/diff': specifier: ^6.0.0 version: 6.0.0 - '@types/dompurify': - specifier: ^3.0.5 - version: 3.0.5 '@types/libsodium-wrappers-sumo': specifier: ^0.7.8 version: 0.7.8 @@ -344,9 +344,6 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} - '@asamuzakjp/dom-selector@2.0.2': - resolution: {integrity: sha512-x1KXOatwofR6ZAYzXRBL5wrdV0vwNxlTCK9NCuLqAzQYARqGcvFwiJA6A1ERuh+dgeA4Dxm3JBYictIes+SqUQ==} - '@aws-crypto/crc32@3.0.0': resolution: {integrity: sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==} @@ -978,6 +975,10 @@ packages: cpu: [arm64] os: [win32] + '@rollup/rollup-win32-arm64-msvc@4.40.1': + resolution: {integrity: sha512-b2bcNm9Kbde03H+q+Jjw9tSfhYkzrDUf2d5MAd1bOJuVplXvFhWz7tRtWvD8/ORZi7qSCy0idW6tf2HgxSXQSg==} + os: [win32] + '@rollup/rollup-win32-ia32-msvc@4.24.0': resolution: {integrity: sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==} cpu: [ia32] @@ -1173,6 +1174,11 @@ packages: cpu: [arm64] os: [win32] + '@tauri-apps/cli-win32-arm64-msvc@2.5.0': + resolution: {integrity: sha512-pFSHFK6b+o9y4Un8w0gGLwVyFTZaC3P0kQ7umRt/BLDkzD5RnQ4vBM7CF8BCU5nkwmEBUCZd7Wt3TWZxe41o6Q==} + engines: {node: '>= 10'} + os: [win32] + '@tauri-apps/cli-win32-ia32-msvc@2.0.2': resolution: {integrity: sha512-axgICLunFi0To3EibdCBgbST5RocsSmtM4c04+CbcX8WQQosJ9ziWlCSrrOTRr+gJERAMSvEyVUS98f6bWMw9A==} engines: {node: '>= 10'} @@ -1208,8 +1214,8 @@ packages: '@tauri-apps/plugin-process@2.0.0': resolution: {integrity: sha512-OYzi0GnkrF4NAnsHZU7U3tjSoP0PbeAlO7T1Z+vJoBUH9sFQ1NSLqWYWQyf8hcb3gVWe7P1JggjiskO+LST1ug==} - '@tauri-apps/plugin-shell@2.0.0': - resolution: {integrity: sha512-OpW2+ycgJLrEoZityWeWYk+6ZWP9VyiAfbO+N/O8VfLkqyOym8kXh7odKDfINx9RAotkSGBtQM4abyKfJDkcUg==} + '@tauri-apps/plugin-shell@2.2.1': + resolution: {integrity: sha512-G1GFYyWe/KlCsymuLiNImUgC8zGY0tI0Y3p8JgBCWduR5IEXlIJS+JuG1qtveitwYXlfJrsExt3enhv5l2/yhA==} '@tauri-apps/plugin-updater@2.0.0': resolution: {integrity: sha512-N0cl71g7RPr7zK2Fe5aoIwzw14NcdLcz7XMGFWZVjprsqgDRWoxbnUkknyCQMZthjhGkppCd/wN2MIsUz+eAhQ==} @@ -1247,9 +1253,6 @@ packages: '@types/diff@6.0.0': resolution: {integrity: sha512-dhVCYGv3ZSbzmQaBSagrv1WJ6rXCdkyTcDyoNu1MD8JohI7pR7k8wdZEm+mvdxRKXyHVwckFzWU1vJc+Z29MlA==} - '@types/dompurify@3.0.5': - resolution: {integrity: sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==} - '@types/emscripten@1.39.10': resolution: {integrity: sha512-TB/6hBkYQJxsZHSqyeuO1Jt0AB/bW6G7rHt9g7lML7SOF6lbgcHvw/Lr+69iqN0qxgXLhWKScAon73JNnptuDw==} @@ -1368,10 +1371,6 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} - agent-base@7.1.0: - resolution: {integrity: sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==} - engines: {node: '>= 14'} - aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} @@ -1444,9 +1443,6 @@ packages: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - at-least-node@1.0.0: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} @@ -1471,9 +1467,6 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - bidi-js@1.0.3: - resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} - big-integer@1.6.52: resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} engines: {node: '>=0.6'} @@ -1640,10 +1633,6 @@ packages: colord@2.9.3: resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -1788,10 +1777,6 @@ packages: css-select@5.1.0: resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} - css-tree@2.3.1: - resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} - engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} - css-what@6.1.0: resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} engines: {node: '>= 6'} @@ -1801,18 +1786,10 @@ packages: engines: {node: '>=4'} hasBin: true - cssstyle@4.0.1: - resolution: {integrity: sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==} - engines: {node: '>=18'} - dargs@7.0.0: resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==} engines: {node: '>=8'} - data-urls@5.0.0: - resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} - engines: {node: '>=18'} - dateformat@3.0.3: resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==} @@ -1858,9 +1835,6 @@ packages: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} engines: {node: '>=0.10.0'} - decimal.js@10.4.3: - resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} - decompress-response@4.2.1: resolution: {integrity: sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==} engines: {node: '>=8'} @@ -1893,10 +1867,6 @@ packages: resolution: {integrity: sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==} engines: {node: '>=10'} - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - delegates@1.0.0: resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} @@ -1955,8 +1925,8 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} - dompurify@3.0.8: - resolution: {integrity: sha512-b7uwreMYL2eZhrSCRC4ahLTeZcPZxSmYfmcQGXGkXiZSNW1X85v+SDM5KsWcpivIiUBH47Ji7NtyUdpLeF5JZQ==} + dompurify@3.2.5: + resolution: {integrity: sha512-mLPd29uoRe9HpvwP2TxClGQBzGXeEC/we/q+bFlmPPmj2p2Ugl3r6ATu/UU1v77DXNcehiBg9zsr1dREyA/dJQ==} domutils@2.8.0: resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} @@ -2116,10 +2086,6 @@ packages: resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} engines: {node: '>=14'} - form-data@4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} - engines: {node: '>= 6'} - formidable@1.2.6: resolution: {integrity: sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==} deprecated: 'Please upgrade to latest, formidable@v2 or formidable@v3! Check these notes: https://bit.ly/2ZEqIau' @@ -2291,10 +2257,6 @@ packages: resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} engines: {node: '>=10'} - html-encoding-sniffer@4.0.0: - resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} - engines: {node: '>=18'} - html-to-image@1.11.11: resolution: {integrity: sha512-9gux8QhvjRO/erSnDPv28noDZcPZmYE7e1vFsBLKLlRlKDSqNJYebj6Qz1TGd5lsRV+X+xYyjCKjuZdABinWjA==} @@ -2302,18 +2264,10 @@ packages: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} - http-proxy-agent@7.0.0: - resolution: {integrity: sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==} - engines: {node: '>= 14'} - https-proxy-agent@5.0.1: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} - https-proxy-agent@7.0.2: - resolution: {integrity: sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==} - engines: {node: '>= 14'} - human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -2322,10 +2276,6 @@ packages: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -2433,9 +2383,6 @@ packages: resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} engines: {node: '>=0.10.0'} - is-potential-custom-element-name@1.0.1: - resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} - is-reference@3.0.2: resolution: {integrity: sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==} @@ -2457,10 +2404,6 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - isomorphic-dompurify@1.13.0: - resolution: {integrity: sha512-9qOYGngy9ZR9JB/iLmr7SViPSZ7uWGvepdnLaXYznbTxvJOCuONneKajJ54f+IRQpvL8608ylUy9EK1iPtL3Ag==} - engines: {node: '>=18'} - jackspeak@2.3.6: resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} engines: {node: '>=14'} @@ -2472,15 +2415,6 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - jsdom@23.2.0: - resolution: {integrity: sha512-L88oL7D/8ufIES+Zjz7v0aes+oBMh2Xnh3ygWvL0OaICOomKEPKuPnIfBJekiXr+BHbbMjrWn/xqrDQuxFTeyA==} - engines: {node: '>=18'} - peerDependencies: - canvas: ^2.11.2 - peerDependenciesMeta: - canvas: - optional: true - json-parse-better-errors@1.0.2: resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} @@ -2612,9 +2546,6 @@ packages: resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} hasBin: true - mdn-data@2.0.30: - resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} - mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} @@ -2985,9 +2916,6 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} - parse5@7.1.2: - resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} - parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -3164,9 +3092,6 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} - psl@1.9.0: - resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} - pstree.remy@1.1.8: resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} @@ -3177,10 +3102,6 @@ packages: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - q@1.5.1: resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} engines: {node: '>=0.6.0', teleport: '>=0.2.0'} @@ -3189,9 +3110,6 @@ packages: resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} engines: {node: '>=0.6'} - querystringify@2.2.0: - resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} - queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -3268,16 +3186,9 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - require-main-filename@2.0.0: resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} - requires-port@1.0.0: - resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} - resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -3312,9 +3223,6 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - rrweb-cssom@0.6.0: - resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==} - run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -3337,10 +3245,6 @@ packages: sax@1.3.0: resolution: {integrity: sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==} - saxes@6.0.0: - resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} - engines: {node: '>=v12.22.7'} - sdp@3.2.0: resolution: {integrity: sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw==} @@ -3615,9 +3519,6 @@ packages: resolution: {integrity: sha512-nzq+PPKGS2PoEWDjAcXSrKSbXmmmOAxd6dAz1IhRusUpVkFS6DMELWPyBPGwu6TpO/gsgtFXwX0M4+pAR5gzKw==} engines: {node: '>=18'} - symbol-tree@3.2.4: - resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - tailwindcss@3.4.1: resolution: {integrity: sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==} engines: {node: '>=14.0.0'} @@ -3694,17 +3595,9 @@ packages: resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==} hasBin: true - tough-cookie@4.1.3: - resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} - engines: {node: '>=6'} - tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - tr46@5.0.0: - resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==} - engines: {node: '>=18'} - tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -3782,10 +3675,6 @@ packages: resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} engines: {node: '>=8'} - universalify@0.2.0: - resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} - engines: {node: '>= 4.0.0'} - universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -3804,9 +3693,6 @@ packages: peerDependencies: browserslist: '>= 4.21.0' - url-parse@1.5.10: - resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -3881,10 +3767,6 @@ packages: vite: optional: true - w3c-xmlserializer@5.0.0: - resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} - engines: {node: '>=18'} - wasmoon@1.16.0: resolution: {integrity: sha512-FlRLb15WwAOz1A9OQDbf6oOKKSiefi5VK0ZRF2wgH9xk3o5SnU11tNPaOnQuAh1Ucr66cwwvVXaeVRaFdRBt5g==} hasBin: true @@ -3901,29 +3783,13 @@ packages: webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - webidl-conversions@7.0.0: - resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} - engines: {node: '>=12'} - webrtc-adapter@8.2.3: resolution: {integrity: sha512-gnmRz++suzmvxtp3ehQts6s2JtAGPuDPjA1F3a9ckNpG1kYdYuHWYpazoAnL9FS5/B21tKlhkorbdCXat0+4xQ==} engines: {node: '>=6.0.0', npm: '>=3.10.0'} - whatwg-encoding@3.1.1: - resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} - engines: {node: '>=18'} - whatwg-fetch@3.6.20: resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} - whatwg-mimetype@4.0.0: - resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} - engines: {node: '>=18'} - - whatwg-url@14.0.0: - resolution: {integrity: sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==} - engines: {node: '>=18'} - whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -3956,18 +3822,6 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.16.0: - resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - xcode@3.0.1: resolution: {integrity: sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==} engines: {node: '>=10.0.0'} @@ -3976,10 +3830,6 @@ packages: resolution: {integrity: sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==} hasBin: true - xml-name-validator@5.0.0: - resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} - engines: {node: '>=18'} - xml2js@0.5.0: resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} engines: {node: '>=4.0.0'} @@ -3992,9 +3842,6 @@ packages: resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} engines: {node: '>=8.0'} - xmlchars@2.2.0: - resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - xpath@0.0.27: resolution: {integrity: sha512-fg03WRxtkCV6ohClePNAECYsmpKKTv5L8y/X3Dn1hQrec3POx2jHZ/0P2qQ6HvsrU1BmeqXcof3NGGueG6LxwQ==} engines: {node: '>=0.6.0'} @@ -4071,12 +3918,6 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - '@asamuzakjp/dom-selector@2.0.2': - dependencies: - bidi-js: 1.0.3 - css-tree: 2.3.1 - is-potential-custom-element-name: 1.0.1 - '@aws-crypto/crc32@3.0.0': dependencies: '@aws-crypto/util': 3.0.0 @@ -4656,6 +4497,8 @@ snapshots: '@rollup/rollup-win32-arm64-msvc@4.24.0': optional: true + '@rollup/rollup-win32-arm64-msvc@4.40.1': {} + '@rollup/rollup-win32-ia32-msvc@4.24.0': optional: true @@ -4824,6 +4667,8 @@ snapshots: '@tauri-apps/cli-win32-arm64-msvc@2.0.2': optional: true + '@tauri-apps/cli-win32-arm64-msvc@2.5.0': {} + '@tauri-apps/cli-win32-ia32-msvc@2.0.2': optional: true @@ -4867,7 +4712,7 @@ snapshots: dependencies: '@tauri-apps/api': 2.0.0 - '@tauri-apps/plugin-shell@2.0.0': + '@tauri-apps/plugin-shell@2.2.1': dependencies: '@tauri-apps/api': 2.0.0 @@ -4934,10 +4779,6 @@ snapshots: '@types/diff@6.0.0': {} - '@types/dompurify@3.0.5': - dependencies: - '@types/trusted-types': 2.0.7 - '@types/emscripten@1.39.10': {} '@types/estree@1.0.5': {} @@ -5000,7 +4841,8 @@ snapshots: lil-gui: 0.17.0 meshoptimizer: 0.18.1 - '@types/trusted-types@2.0.7': {} + '@types/trusted-types@2.0.7': + optional: true '@types/uuid@9.0.7': {} @@ -5045,12 +4887,6 @@ snapshots: - supports-color optional: true - agent-base@7.1.0: - dependencies: - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - aggregate-error@3.1.0: dependencies: clean-stack: 2.2.0 @@ -5106,8 +4942,6 @@ snapshots: astral-regex@2.0.0: {} - asynckit@0.4.0: {} - at-least-node@1.0.0: {} autoprefixer@10.4.16(postcss@8.4.33): @@ -5128,10 +4962,6 @@ snapshots: base64-js@1.5.1: {} - bidi-js@1.0.3: - dependencies: - require-from-string: 2.0.2 - big-integer@1.6.52: {} binary-extensions@2.2.0: {} @@ -5353,10 +5183,6 @@ snapshots: colord@2.9.3: {} - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - commander@4.1.1: {} commander@8.3.0: {} @@ -5533,26 +5359,12 @@ snapshots: domutils: 3.1.0 nth-check: 2.1.1 - css-tree@2.3.1: - dependencies: - mdn-data: 2.0.30 - source-map-js: 1.0.2 - css-what@6.1.0: {} cssesc@3.0.0: {} - cssstyle@4.0.1: - dependencies: - rrweb-cssom: 0.6.0 - dargs@7.0.0: {} - data-urls@5.0.0: - dependencies: - whatwg-mimetype: 4.0.0 - whatwg-url: 14.0.0 - dateformat@3.0.3: {} debug@2.6.9: @@ -5580,8 +5392,6 @@ snapshots: decamelize@1.2.0: {} - decimal.js@10.4.3: {} - decompress-response@4.2.1: dependencies: mimic-response: 2.1.0 @@ -5618,8 +5428,6 @@ snapshots: rimraf: 3.0.2 slash: 3.0.0 - delayed-stream@1.0.0: {} - delegates@1.0.0: optional: true @@ -5667,7 +5475,9 @@ snapshots: dependencies: domelementtype: 2.3.0 - dompurify@3.0.8: {} + dompurify@3.2.5: + optionalDependencies: + '@types/trusted-types': 2.0.7 domutils@2.8.0: dependencies: @@ -5876,12 +5686,6 @@ snapshots: cross-spawn: 7.0.3 signal-exit: 4.1.0 - form-data@4.0.0: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - formidable@1.2.6: {} forwarded@0.2.0: {} @@ -6068,10 +5872,6 @@ snapshots: dependencies: lru-cache: 6.0.0 - html-encoding-sniffer@4.0.0: - dependencies: - whatwg-encoding: 3.1.1 - html-to-image@1.11.11: {} http-errors@2.0.0: @@ -6082,13 +5882,6 @@ snapshots: statuses: 2.0.1 toidentifier: 1.0.1 - http-proxy-agent@7.0.0: - dependencies: - agent-base: 7.1.0 - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 @@ -6097,23 +5890,12 @@ snapshots: - supports-color optional: true - https-proxy-agent@7.0.2: - dependencies: - agent-base: 7.1.0 - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - human-signals@2.1.0: {} iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - ieee754@1.2.1: {} ignore-by-default@1.0.1: {} @@ -6188,8 +5970,6 @@ snapshots: is-plain-obj@1.1.0: {} - is-potential-custom-element-name@1.0.1: {} - is-reference@3.0.2: dependencies: '@types/estree': 1.0.6 @@ -6208,17 +5988,6 @@ snapshots: isexe@2.0.0: {} - isomorphic-dompurify@1.13.0(canvas@2.11.2): - dependencies: - '@types/dompurify': 3.0.5 - dompurify: 3.0.8 - jsdom: 23.2.0(canvas@2.11.2) - transitivePeerDependencies: - - bufferutil - - canvas - - supports-color - - utf-8-validate - jackspeak@2.3.6: dependencies: '@isaacs/cliui': 8.0.2 @@ -6229,36 +5998,6 @@ snapshots: js-tokens@4.0.0: {} - jsdom@23.2.0(canvas@2.11.2): - dependencies: - '@asamuzakjp/dom-selector': 2.0.2 - cssstyle: 4.0.1 - data-urls: 5.0.0 - decimal.js: 10.4.3 - form-data: 4.0.0 - html-encoding-sniffer: 4.0.0 - http-proxy-agent: 7.0.0 - https-proxy-agent: 7.0.2 - is-potential-custom-element-name: 1.0.1 - parse5: 7.1.2 - rrweb-cssom: 0.6.0 - saxes: 6.0.0 - symbol-tree: 3.2.4 - tough-cookie: 4.1.3 - w3c-xmlserializer: 5.0.0 - webidl-conversions: 7.0.0 - whatwg-encoding: 3.1.1 - whatwg-mimetype: 4.0.0 - whatwg-url: 14.0.0 - ws: 8.16.0 - xml-name-validator: 5.0.0 - optionalDependencies: - canvas: 2.11.2 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - json-parse-better-errors@1.0.2: {} json-parse-even-better-errors@2.3.1: {} @@ -6380,8 +6119,6 @@ snapshots: punycode.js: 2.3.1 uc.micro: 2.1.0 - mdn-data@2.0.30: {} - mdurl@2.0.0: {} media-typer@0.3.0: {} @@ -6763,10 +6500,6 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - parse5@7.1.2: - dependencies: - entities: 4.5.0 - parseurl@1.3.3: {} path-exists@3.0.0: {} @@ -6943,8 +6676,6 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 - psl@1.9.0: {} - pstree.remy@1.1.8: {} pump@3.0.0: @@ -6954,16 +6685,12 @@ snapshots: punycode.js@2.3.1: {} - punycode@2.3.1: {} - q@1.5.1: {} qs@6.11.0: dependencies: side-channel: 1.0.4 - querystringify@2.2.0: {} - queue-microtask@1.2.3: {} queue-tick@1.0.1: {} @@ -7058,12 +6785,8 @@ snapshots: require-directory@2.1.1: {} - require-from-string@2.0.2: {} - require-main-filename@2.0.0: {} - requires-port@1.0.0: {} - resolve@1.22.8: dependencies: is-core-module: 2.13.1 @@ -7112,8 +6835,6 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.24.0 fsevents: 2.3.3 - rrweb-cssom@0.6.0: {} - run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -7132,10 +6853,6 @@ snapshots: sax@1.3.0: {} - saxes@6.0.0: - dependencies: - xmlchars: 2.2.0 - sdp@3.2.0: {} semver@5.7.2: {} @@ -7434,8 +7151,6 @@ snapshots: magic-string: 0.30.12 zimmerframe: 1.1.2 - symbol-tree@3.2.4: {} - tailwindcss@3.4.1(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.7)(typescript@5.6.3)): dependencies: '@alloc/quick-lru': 5.2.0 @@ -7559,19 +7274,8 @@ snapshots: dependencies: nopt: 1.0.10 - tough-cookie@4.1.3: - dependencies: - psl: 1.9.0 - punycode: 2.3.1 - universalify: 0.2.0 - url-parse: 1.5.10 - tr46@0.0.3: {} - tr46@5.0.0: - dependencies: - punycode: 2.3.1 - tree-kill@1.2.2: {} trim-newlines@3.0.1: {} @@ -7634,8 +7338,6 @@ snapshots: dependencies: crypto-random-string: 2.0.0 - universalify@0.2.0: {} - universalify@2.0.1: {} unpipe@1.0.0: {} @@ -7648,11 +7350,6 @@ snapshots: escalade: 3.1.1 picocolors: 1.0.0 - url-parse@1.5.10: - dependencies: - querystringify: 2.2.0 - requires-port: 1.0.0 - util-deprecate@1.0.2: {} utils-merge@1.0.1: {} @@ -7697,10 +7394,6 @@ snapshots: optionalDependencies: vite: 5.4.9(@types/node@18.19.7) - w3c-xmlserializer@5.0.0: - dependencies: - xml-name-validator: 5.0.0 - wasmoon@1.16.0: dependencies: '@types/emscripten': 1.39.10 @@ -7711,25 +7404,12 @@ snapshots: webidl-conversions@3.0.1: {} - webidl-conversions@7.0.0: {} - webrtc-adapter@8.2.3: dependencies: sdp: 3.2.0 - whatwg-encoding@3.1.1: - dependencies: - iconv-lite: 0.6.3 - whatwg-fetch@3.6.20: {} - whatwg-mimetype@4.0.0: {} - - whatwg-url@14.0.0: - dependencies: - tr46: 5.0.0 - webidl-conversions: 7.0.0 - whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -7768,8 +7448,6 @@ snapshots: wrappy@1.0.2: {} - ws@8.16.0: {} - xcode@3.0.1: dependencies: simple-plist: 1.3.1 @@ -7779,8 +7457,6 @@ snapshots: dependencies: sax: 1.3.0 - xml-name-validator@5.0.0: {} - xml2js@0.5.0: dependencies: sax: 1.3.0 @@ -7790,8 +7466,6 @@ snapshots: xmlbuilder@15.1.1: {} - xmlchars@2.2.0: {} - xpath@0.0.27: {} xpath@0.0.32: {} diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index ab68959d..b29c38fd 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -29,7 +29,7 @@ tauri-plugin-fs = "2" tauri-plugin-os = "2" tauri-plugin-dialog = "2" tauri-plugin-process = "2" -tauri-plugin-shell = "2" +tauri-plugin-shell = "2.2.1" tauri-plugin-http = "2" [target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\"))".dependencies] tauri-plugin-deep-link = "2" diff --git a/src/ts/parser.svelte.ts b/src/ts/parser.svelte.ts index 20b20a58..b9767916 100644 --- a/src/ts/parser.svelte.ts +++ b/src/ts/parser.svelte.ts @@ -1,4 +1,4 @@ -import DOMPurify from 'isomorphic-dompurify'; +import DOMPurify from 'dompurify'; import markdownit from 'markdown-it' import { getCurrentCharacter, type Database, type Message, type character, type customscript, type groupChat, type triggerscript } from './storage/database.svelte'; import { DBState } from './stores.svelte'; From 165e6741bdeef908592ffbd4636f4bacb82b1e79 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Mon, 28 Apr 2025 16:40:28 +0900 Subject: [PATCH 24/26] feat: add request api with rate limiting and URL validation in Lua engine --- src/ts/process/lua.ts | 46 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/ts/process/lua.ts b/src/ts/process/lua.ts index 727cfb59..64841e93 100644 --- a/src/ts/process/lua.ts +++ b/src/ts/process/lua.ts @@ -18,6 +18,8 @@ let luaFactory:LuaFactory let LuaSafeIds = new Set() let LuaEditDisplayIds = new Set() let LuaLowLevelIds = new Set() +let lastRequestResetTime = 0 +let lastRequestsCount = 0 interface LuaEngineState { code?: string; @@ -205,6 +207,50 @@ export async function runLua(code:string, arg:{ return await processer.similaritySearch(source) }) + luaEngine.global.set('request', async (id:string, url:string) => { + if(!LuaLowLevelIds.has(id)){ + return + } + + if(lastRequestResetTime + 60000 < Date.now()){ + lastRequestsCount = 0 + lastRequestResetTime = Date.now() + } + + if(lastRequestsCount > 8){ + return { + status: 429, + data: 'Too many requests. you can request 8 times per minute' + } + } + + lastRequestsCount++ + + try { + //for security and other reasons, only get request in 120 char is allowed + if(url.length > 120){ + return { + status: 413, + data: 'URL to large. max is 120 characters' + } + } + + //browser fetch + const d = await fetch(url) + const text = await d.text() + return { + status: d.status, + data: text + } + + } catch (error) { + return { + status: 400, + data: 'internal error' + } + } + }) + luaEngine.global.set('generateImage', async (id:string, value:string, negValue:string = '') => { if(!LuaLowLevelIds.has(id)){ return From f2839e66bbc10cef745f02532e9150952c4dde7f Mon Sep 17 00:00:00 2001 From: kwaroran Date: Mon, 28 Apr 2025 16:41:30 +0900 Subject: [PATCH 25/26] fix: update request limit to 5 and use fetchNative for API calls --- src/ts/process/lua.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ts/process/lua.ts b/src/ts/process/lua.ts index 64841e93..623df500 100644 --- a/src/ts/process/lua.ts +++ b/src/ts/process/lua.ts @@ -13,6 +13,7 @@ import { v4 } from "uuid"; import { getModuleTriggers } from "./modules"; import { Mutex } from "../mutex"; import { tokenize } from "../tokenizer"; +import { fetchNative } from "../globalApi.svelte"; let luaFactory:LuaFactory let LuaSafeIds = new Set() @@ -217,10 +218,10 @@ export async function runLua(code:string, arg:{ lastRequestResetTime = Date.now() } - if(lastRequestsCount > 8){ + if(lastRequestsCount > 5){ return { status: 429, - data: 'Too many requests. you can request 8 times per minute' + data: 'Too many requests. you can request 5 times per minute' } } @@ -236,7 +237,9 @@ export async function runLua(code:string, arg:{ } //browser fetch - const d = await fetch(url) + const d = await fetchNative(url, { + method: "GET" + }) const text = await d.text() return { status: d.status, From 6db9bd08f1a5ccb8c3705f155e2137c215790e88 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Mon, 28 Apr 2025 16:45:06 +0900 Subject: [PATCH 26/26] Add more restrictions --- src/ts/process/lua.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/ts/process/lua.ts b/src/ts/process/lua.ts index 623df500..bc737239 100644 --- a/src/ts/process/lua.ts +++ b/src/ts/process/lua.ts @@ -236,6 +236,29 @@ export async function runLua(code:string, arg:{ } } + if(!url.startsWith('https://')){ + return { + status: 400, + data: "Only https requests are allowed" + } + } + + const bannedURL = [ + "https://realm.risuai.net", + "https://risuai.net", + "https://risuai.xyz" + ] + + for(const burl of bannedURL){ + + if(url.startsWith(burl)){ + return { + status: 400, + data: "request to " + url + ' is not allowed' + } + } + } + //browser fetch const d = await fetchNative(url, { method: "GET"