From bdd027db2618ce8abb61a5cd95ed27f70f5e56cb Mon Sep 17 00:00:00 2001 From: kwaroran Date: Mon, 22 Jan 2024 01:49:32 +0900 Subject: [PATCH 1/5] Update version to 1.76.2 --- src-tauri/tauri.conf.json | 2 +- src/ts/storage/database.ts | 2 +- version.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 2a7b7c60..acef15db 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -8,7 +8,7 @@ }, "package": { "productName": "RisuAI", - "version": "1.76.1" + "version": "1.76.2" }, "tauri": { "allowlist": { diff --git a/src/ts/storage/database.ts b/src/ts/storage/database.ts index 360f5111..923a2acb 100644 --- a/src/ts/storage/database.ts +++ b/src/ts/storage/database.ts @@ -15,7 +15,7 @@ import type { OobaChatCompletionRequestParams } from '../model/ooba'; export const DataBase = writable({} as any as Database) export const loadedStore = writable(false) -export let appVer = "1.76.1" +export let appVer = "1.76.2" export let webAppSubVer = '' export function setDatabase(data:Database){ diff --git a/version.json b/version.json index b7967aba..bac3ac29 100644 --- a/version.json +++ b/version.json @@ -1 +1 @@ -{"version":"1.76.1"} \ No newline at end of file +{"version":"1.76.2"} \ No newline at end of file From afea17dfb3ca22debbd46ccc2dfe5a9c1aa05fdd Mon Sep 17 00:00:00 2001 From: kwaroran Date: Fri, 26 Jan 2024 04:24:02 +0900 Subject: [PATCH 2/5] Update model options in ModelList.svelte and request.ts --- src/lib/UI/ModelList.svelte | 3 ++- src/ts/process/request.ts | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib/UI/ModelList.svelte b/src/lib/UI/ModelList.svelte index 72c29bb8..38a214db 100644 --- a/src/lib/UI/ModelList.svelte +++ b/src/lib/UI/ModelList.svelte @@ -122,13 +122,14 @@ - + {#if showUnrec} + diff --git a/src/ts/process/request.ts b/src/ts/process/request.ts index c72727e5..3927836e 100644 --- a/src/ts/process/request.ts +++ b/src/ts/process/request.ts @@ -151,6 +151,7 @@ export async function requestChatDataMain(arg:requestDataArgument, model:'model' case 'gpt4_0613': case 'gpt4_32k_0613': case 'gpt4_1106': + case 'gpt4_0125': case 'gpt35_1106': case 'gpt35_0301': case 'gpt4_0301': @@ -402,6 +403,7 @@ export async function requestChatDataMain(arg:requestDataArgument, model:'model' : requestModel === "gpt4_0613" ? 'gpt-4-0613' : requestModel === "gpt4_32k_0613" ? 'gpt-4-32k-0613' : requestModel === "gpt4_1106" ? 'gpt-4-1106-preview' + : requestModel === 'gpt4_0125' ? 'gpt-4-0125-preview' : requestModel === "gptvi4_1106" ? 'gpt-4-vision-preview' : requestModel === "gpt35_1106" ? 'gpt-3.5-turbo-1106' : requestModel === 'gpt35_0301' ? 'gpt-3.5-turbo-0301' From 1123f79947b474b94fd36b817e7757fc294d0014 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Fri, 26 Jan 2024 04:24:22 +0900 Subject: [PATCH 3/5] Update version to 1.76.3 --- src-tauri/tauri.conf.json | 2 +- src/ts/storage/database.ts | 2 +- version.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index acef15db..bd481787 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -8,7 +8,7 @@ }, "package": { "productName": "RisuAI", - "version": "1.76.2" + "version": "1.76.3" }, "tauri": { "allowlist": { diff --git a/src/ts/storage/database.ts b/src/ts/storage/database.ts index 923a2acb..e813d5e1 100644 --- a/src/ts/storage/database.ts +++ b/src/ts/storage/database.ts @@ -15,7 +15,7 @@ import type { OobaChatCompletionRequestParams } from '../model/ooba'; export const DataBase = writable({} as any as Database) export const loadedStore = writable(false) -export let appVer = "1.76.2" +export let appVer = "1.76.3" export let webAppSubVer = '' export function setDatabase(data:Database){ diff --git a/version.json b/version.json index bac3ac29..9c6b468f 100644 --- a/version.json +++ b/version.json @@ -1 +1 @@ -{"version":"1.76.2"} \ No newline at end of file +{"version":"1.76.3"} \ No newline at end of file From f3cb493451acaff95f5fb796149d4396be304bc6 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Thu, 1 Feb 2024 00:36:08 +0900 Subject: [PATCH 4/5] Update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d2cae9ae..f1efa890 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ text -RisuAI, or Risu for short, is an AI chat software / web application with powerful features such as multiple API support, assets in the chat, regex functions and much more. +RisuAI, or Risu for short, is an AI chatting software / web application with powerful features such as multiple API support, assets in the chat, regex functions and much more. # Screenshots |![Screenshot_6](https://github.com/kwaroran/RisuAI/assets/116663078/cccb9b33-5dbd-47d7-9c85-61464790aafe) | ![image](https://github.com/kwaroran/RisuAI/assets/116663078/30d29f85-1380-4c73-9b82-1a40f2c5d2ea) | From bfb6633f890e7c85cdc3a9dec45368e7902592b0 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Fri, 2 Feb 2024 18:07:03 +0900 Subject: [PATCH 5/5] Add risu rcc for export --- src/lang/en.ts | 8 +++ src/lib/Others/AlertComp.svelte | 74 ++++++++++++++++++++-- src/ts/alert.ts | 24 +++++++- src/ts/characterCards.ts | 105 +++++++++++++++++++++++++++++--- 4 files changed, 196 insertions(+), 15 deletions(-) diff --git a/src/lang/en.ts b/src/lang/en.ts index bf005d77..afe1b768 100644 --- a/src/lang/en.ts +++ b/src/lang/en.ts @@ -23,6 +23,7 @@ export const languageEnglish = { alreadyCharInGroup: "There is already a character with the same name in the group.", noUserIcon: "You must set your icon first.", emptyText: "Text is empty.", + wrongPassword: "Wrong Password", }, showHelp: "Show Help", help:{ @@ -506,4 +507,11 @@ export const languageEnglish = { openrouterMiddleOut: "Openrouter Middle Out", geminiApiKey: "Gemini API Key", removePunctuationHypa: "Memory Punctuation Removal", + inputCardPassword: "Input Card Password", + ccv2Desc: 'Character Card V2 is is a format widely used in chatbot programs.', + rccDesc: 'Risu Refined Character Card is a format with additional features like password, integrity check and etc.', + password: "Password", + license: "License", + licenseDesc: "You can choose license for the downloaders to limit the usages of your card's prompt.", + passwordDesc: "You can set a password to protect your card from unauthorized access.", } \ No newline at end of file diff --git a/src/lib/Others/AlertComp.svelte b/src/lib/Others/AlertComp.svelte index 863a8099..09fb3eff 100644 --- a/src/lib/Others/AlertComp.svelte +++ b/src/lib/Others/AlertComp.svelte @@ -7,12 +7,19 @@ import BarIcon from '../SideBars/BarIcon.svelte'; import { User } from 'lucide-svelte'; import { hubURL } from 'src/ts/characterCards'; - import TextInput from '../UI/GUI/TextInput.svelte'; - import { openURL } from 'src/ts/storage/globalApi'; - import Button from '../UI/GUI/Button.svelte'; + import TextInput from '../UI/GUI/TextInput.svelte'; + import { openURL } from 'src/ts/storage/globalApi'; + import Button from '../UI/GUI/Button.svelte'; + import { XIcon } from "lucide-svelte"; + import SelectInput from "../UI/GUI/SelectInput.svelte"; + import { CCLicenseData } from "src/ts/creation/license"; + import OptionInput from "../UI/GUI/OptionInput.svelte"; + import { language } from 'src/lang'; let btn let input = '' - + let cardExportType = '' + let cardExportPassword = '' + let cardLicense = '' $: (() => { if(btn){ btn.focus() @@ -40,7 +47,7 @@ } }}> -{#if $alertStore.type !== 'none' && $alertStore.type !== 'toast'} +{#if $alertStore.type !== 'none' && $alertStore.type !== 'toast' && $alertStore.type !== 'cardexport'}
{#if $alertStore.type === 'error'} @@ -160,6 +167,63 @@ {/if}
+ +{:else if $alertStore.type === 'cardexport'} +
+
+

+ + Export Character + + +

+ Type + {#if cardExportType === ''} + {language.ccv2Desc} + {:else} + {language.rccDesc} + {/if} +
+ + +
+ {#if cardExportType === 'rcc'} + {language.password} + {language.passwordDesc} + + {language.license} + {language.licenseDesc} + + None + {#each Object.keys(CCLicenseData) as ccl} + {CCLicenseData[ccl][2]} ({CCLicenseData[ccl][1]}) + {/each} + + {/if} + +
+
+ {:else if $alertStore.type === 'toast'}
{ diff --git a/src/ts/alert.ts b/src/ts/alert.ts index 2d88a090..061348cd 100644 --- a/src/ts/alert.ts +++ b/src/ts/alert.ts @@ -3,7 +3,7 @@ import { sleep } from "./util" import { language } from "../lang" interface alertData{ - type: 'error'| 'normal'|'none'|'ask'|'wait'|'selectChar'|'input'|'toast'|'wait2'|'markdown'|'select'|'login'|'tos' + type: 'error'| 'normal'|'none'|'ask'|'wait'|'selectChar'|'input'|'toast'|'wait2'|'markdown'|'select'|'login'|'tos'|'cardexport' msg: string } @@ -100,6 +100,7 @@ export function alertWait(msg:string){ } + export function alertClear(){ alertStore.set({ 'type': 'none', @@ -140,6 +141,27 @@ export async function alertConfirm(msg:string){ return get(alertStore).msg === 'yes' } +export async function alertCardExport(){ + + alertStore.set({ + 'type': 'cardexport', + 'msg': '' + }) + + while(true){ + if (get(alertStore).type === 'none'){ + break + } + await sleep(10) + } + + return JSON.parse(get(alertStore).msg) as { + type: string, + password: string, + license: string + } +} + export async function alertTOS(){ // if(localStorage.getItem('tos') === 'true'){ diff --git a/src/ts/characterCards.ts b/src/ts/characterCards.ts index c7d450f4..f2443a9a 100644 --- a/src/ts/characterCards.ts +++ b/src/ts/characterCards.ts @@ -1,14 +1,14 @@ import { get, writable, type Writable } from "svelte/store" -import { alertConfirm, alertError, alertMd, alertNormal, alertSelect, alertStore, alertTOS, alertWait } from "./alert" +import { alertCardExport, alertConfirm, alertError, alertInput, alertMd, alertNormal, alertSelect, alertStore, alertTOS, alertWait } from "./alert" import { DataBase, defaultSdDataFunc, type character, setDatabase, type customscript, type loreSettings, type loreBook, type triggerscript } from "./storage/database" -import { checkNullish, selectMultipleFile, sleep } from "./util" +import { checkNullish, decryptBuffer, encryptBuffer, selectMultipleFile, sleep } from "./util" import { language } from "src/lang" import { v4 as uuidv4 } from 'uuid'; import { characterFormatUpdate } from "./characters" import { checkCharOrder, downloadFile, loadAsset, LocalWriter, readImage, saveAsset } from "./storage/globalApi" import { cloneDeep } from "lodash" import { selectedCharID } from "./stores" -import { convertImage } from "./parser" +import { convertImage, hasher } from "./parser" import { reencodeImage } from "./image" import { PngChunk } from "./pngChunk" @@ -71,7 +71,10 @@ async function importCharacterProcess(f:{ break } if(chunk.key === 'chara'){ - readedChara = chunk.value + //For memory reason, limit to 2MB + if(readedChara.length < 2 * 1024 * 1024){ + readedChara = chunk.value.replaceAll('\0', '') + } break } if(chunk.key.startsWith('chara-ext-asset_')){ @@ -86,7 +89,63 @@ async function importCharacterProcess(f:{ alertError(language.errors.noData) return } - { + + if(readedChara.startsWith('rcc||')){ + const parts = readedChara.split('||') + const type = parts[1] + if(type === 'rccv1'){ + if(parts.length !== 5){ + alertError(language.errors.noData) + return + } + const encrypted = Buffer.from(parts[2], 'base64') + const hashed = await hasher(encrypted) + if(hashed !== parts[3]){ + alertError(language.errors.noData) + return + } + console.log(parts[4]) + const metaData:RccCardMetaData = JSON.parse(Buffer.from(parts[4], 'base64').toString('utf-8')) + console.log(metaData) + if(metaData.usePassword){ + const password = await alertInput(language.inputCardPassword) + if(!password){ + return + } + else{ + try { + const decrypted = await decryptBuffer(encrypted, password) + const charaData:CharacterCardV2 = JSON.parse(Buffer.from(decrypted).toString('utf-8')) + if(await importSpecv2(charaData, img, "normal", assets)){ + let db = get(DataBase) + return db.characters.length - 1 + } + else{ + throw new Error('Error while importing') + } + } catch (error) { + alertError(language.errors.wrongPassword) + return + } + } + } + else{ + const decrypted = await decryptBuffer(encrypted, 'RISU_NONE') + try { + const charaData:CharacterCardV2 = JSON.parse(Buffer.from(decrypted).toString('utf-8')) + if(await importSpecv2(charaData, img, "normal", assets)){ + let db = get(DataBase) + return db.characters.length - 1 + } + } catch (error) { + alertError(language.errors.noData) + return + } + } + + } + } + else { const charaData:CharacterCardV2 = JSON.parse(Buffer.from(readedChara, 'base64').toString('utf-8')) if(await importSpecv2(charaData, img, "normal", assets)){ let db = get(DataBase) @@ -217,8 +276,17 @@ export async function exportChar(charaID:number) { return } - const sel = await alertSelect(['Export as PNG', 'Export as JSON']) - exportSpecV2(char, sel === '1' ? 'json' : 'png') + const option = await alertCardExport() + if(option.type === 'cancel'){ + return + } + else if(option.type === 'rcc'){ + char.license = option.license + exportSpecV2(char, 'rcc', {password:option.password}) + } + else{ + exportSpecV2(char,'png') + } return } @@ -535,7 +603,7 @@ async function createBaseV2(char:character) { } -export async function exportSpecV2(char:character, type:'png'|'json' = 'png') { +export async function exportSpecV2(char:character, type:'png'|'json'|'rcc' = 'png', rcc:{password?:string} = {}) { let img = await readImage(char.image) try{ @@ -605,7 +673,22 @@ export async function exportSpecV2(char:character, type:'png'|'json' = 'png') { type: 'wait', msg: 'Loading... (Writing)' }) - await writer.write("chara", Buffer.from(JSON.stringify(card)).toString('base64')) + + if(type === 'rcc'){ + const password = rcc.password || 'RISU_NONE' + const json = JSON.stringify(card) + const encrypted = Buffer.from(await encryptBuffer(Buffer.from(json, 'utf-8'), password)) + const hashed = await hasher(encrypted) + const metaData:RccCardMetaData = {} + if(password !== 'RISU_NONE'){ + metaData.usePassword = true + } + const rccString = 'rcc||rccv1||' + encrypted.toString('base64') + '||' + hashed + '||' + Buffer.from(JSON.stringify(metaData)).toString('base64') + await writer.write("chara", rccString) + } + else{ + await writer.write("chara", Buffer.from(JSON.stringify(card)).toString('base64')) + } await writer.end() @@ -879,4 +962,8 @@ interface charBookEntry{ constant?: boolean // if true, always inserted in the prompt (within budget limit) position?: 'before_char' | 'after_char' // whether the entry is placed before or after the character defs case_sensitive?:boolean +} + +interface RccCardMetaData{ + usePassword?: boolean } \ No newline at end of file