From 02878958b68cd1922c0ec0c05973c542ce71f2d0 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Sat, 3 Jun 2023 06:10:26 +0900 Subject: [PATCH] [feat] basic risuhub --- src/lang/en.ts | 2 +- src/lib/ChatScreens/DefaultChatScreen.svelte | 12 +- src/lib/Others/Help.svelte | 4 +- src/lib/SideBars/CharConfig.svelte | 12 +- src/lib/SideBars/Sidebar.svelte | 19 +- src/lib/UI/Hub.svelte | 60 +++++ src/lib/UI/MainMenu.svelte | 14 + src/ts/characterCards.ts | 261 ++++++++++++++----- src/ts/storage/database.ts | 4 +- tailwind.config.js | 2 + 10 files changed, 301 insertions(+), 89 deletions(-) create mode 100644 src/lib/UI/Hub.svelte create mode 100644 src/lib/UI/MainMenu.svelte diff --git a/src/lang/en.ts b/src/lang/en.ts index f3e9ace4..b4a9f023 100644 --- a/src/lang/en.ts +++ b/src/lang/en.ts @@ -65,7 +65,7 @@ export const languageEnglish = { + "\n\n- $(name)\n\n - inserts the named group" + "\n\nIf OUT starts with **@@**, it doesn't replaces the string, but instead does a special effect if matching string founds." + "\n\n- @@emo (emotion name)\n\n - if character is Emotion Images mode, sets (emotion name) as emotion and prevents default.", - experimental: "This is a experimental setting. it might be unstable.", + experimental: "This is a experimental feature. it might be unstable.", oogaboogaURL: "If your WebUI supports older version of api, your url should look *like https:.../run/textgen*\n\n" + "If your WebUI supports newVersion of api, your url should look like *https://.../api/v1/generate* and use the api server as host, and add --api to arguments.", exampleMessage: "Example conversations that effects output of the character. it dosen't uses tokens permanently." diff --git a/src/lib/ChatScreens/DefaultChatScreen.svelte b/src/lib/ChatScreens/DefaultChatScreen.svelte index 551df72f..8b3da038 100644 --- a/src/lib/ChatScreens/DefaultChatScreen.svelte +++ b/src/lib/ChatScreens/DefaultChatScreen.svelte @@ -3,9 +3,9 @@ import { DatabaseIcon, DicesIcon, LanguagesIcon, MenuIcon, MicOffIcon, PowerIcon, RefreshCcwIcon, ReplyIcon, Send } from "lucide-svelte"; import { selectedCharID } from "../../ts/stores"; import Chat from "./Chat.svelte"; - import { DataBase, appVer, type Message, type character } from "../../ts/storage/database"; + import { DataBase, type Message } from "../../ts/storage/database"; import { getCharImage } from "../../ts/characters"; - import { doingChat, sendChat, type OpenAIChat } from "../../ts/process/index"; + import { doingChat, sendChat } from "../../ts/process/index"; import { findCharacterbyId, messageForm, sleep } from "../../ts/util"; import { language } from "../../lang"; import { translate } from "../../ts/translator/translator"; @@ -13,9 +13,9 @@ import sendSound from '../../etc/send.mp3' import {cloneDeep} from 'lodash' import { processScript } from "src/ts/process/scripts"; - import GithubStars from "../Others/GithubStars.svelte"; import CreatorQuote from "./CreatorQuote.svelte"; import { stopTTS } from "src/ts/process/tts"; + import MainMenu from '../UI/MainMenu.svelte'; let messageInput = '' let openMenu = false @@ -186,11 +186,7 @@ openMenu = false }}> {#if $selectedCharID < 0} -
-

RisuAI

-

Version {appVer}

- -
+ {:else}
{ //@ts-ignore diff --git a/src/lib/Others/Help.svelte b/src/lib/Others/Help.svelte index 3c2c11d7..763b2e7e 100644 --- a/src/lib/Others/Help.svelte +++ b/src/lib/Others/Help.svelte @@ -4,7 +4,9 @@ alertMd(language.help[key]) }}> {#if key === "experimental"} - +
+ +
{:else if unrecommended}
diff --git a/src/lib/SideBars/CharConfig.svelte b/src/lib/SideBars/CharConfig.svelte index ee3f5c19..334e7daf 100644 --- a/src/lib/SideBars/CharConfig.svelte +++ b/src/lib/SideBars/CharConfig.svelte @@ -14,7 +14,7 @@ import {isEqual, cloneDeep} from 'lodash' import Help from "../Others/Help.svelte"; import RegexData from "./RegexData.svelte"; - import { exportChar } from "src/ts/characterCards"; + import { exportChar, shareRisuHub } from "src/ts/characterCards"; import { getElevenTTSVoices, getWebSpeechTTSVoices, getVOICEVOXVoices } from "src/ts/process/tts"; import { checkCharOrder } from "src/ts/storage/globalApi"; import { addGroupChar, rmCharFromGroup } from "src/ts/process/group"; @@ -663,7 +663,15 @@ - + + {#if $DataBase.useExperimental} + + {/if} {:else} {#if currentChar.data.chats[currentChar.data.chatPage].supaMemoryData && currentChar.data.chats[currentChar.data.chatPage].supaMemoryData.length > 4} {language.SuperMemory} diff --git a/src/lib/SideBars/Sidebar.svelte b/src/lib/SideBars/Sidebar.svelte index 4bc405c2..4f90fdae 100644 --- a/src/lib/SideBars/Sidebar.svelte +++ b/src/lib/SideBars/Sidebar.svelte @@ -51,18 +51,27 @@ function createScratch() { reseter(); - const cid = createNewCharacter(); - selectedCharID.set(-1); + createNewCharacter(); + let db = get(DataBase) + if(db.characters[db.characters.length-1]){ + changeChar(db.characters.length-1) + } } function createGroup() { reseter(); - const cid = createNewGroup(); - selectedCharID.set(-1); + createNewGroup(); + let db = get(DataBase) + if(db.characters[db.characters.length-1]){ + changeChar(db.characters.length-1) + } } async function createImport() { reseter(); await importCharacter(); - selectedCharID.set(-1); + let db = get(DataBase) + if(db.characters[db.characters.length-1]){ + changeChar(db.characters.length-1) + } } function changeChar(index: number) { diff --git a/src/lib/UI/Hub.svelte b/src/lib/UI/Hub.svelte new file mode 100644 index 00000000..54f48f8a --- /dev/null +++ b/src/lib/UI/Hub.svelte @@ -0,0 +1,60 @@ + +

Shared Characters

+
+ {#await getRisuHub() then charas} + {#each charas as chara} + + {/each} + {/await} +
+ + +{#if openedData} + +
{ + openedData = null + }}> +
+
+
+ {openedData.name} +

{openedData.name}

+
+ {openedData.desc} +
+
+ + +
+
+
+ +{/if} \ No newline at end of file diff --git a/src/lib/UI/MainMenu.svelte b/src/lib/UI/MainMenu.svelte new file mode 100644 index 00000000..083aadff --- /dev/null +++ b/src/lib/UI/MainMenu.svelte @@ -0,0 +1,14 @@ + +
+

RisuAI

+

Version {appVer}

+ +
+ +
+
\ No newline at end of file diff --git a/src/ts/characterCards.ts b/src/ts/characterCards.ts index 6053ade8..0fc7fce0 100644 --- a/src/ts/characterCards.ts +++ b/src/ts/characterCards.ts @@ -10,7 +10,9 @@ import { PngMetadata } from "./exif" import { characterFormatUpdate } from "./characters" import { checkCharOrder, downloadFile, readImage, saveAsset } from "./storage/globalApi" import { cloneDeep } from "lodash" +import { selectedCharID } from "./stores" +export const hubURL = import.meta.env.DEV ? "http://127.0.0.1:8787" : "https://sv.risuai.xyz" export async function importCharacter() { try { @@ -200,7 +202,7 @@ function convertOldTavernAndJSON(charaData:OldTavernChar, imgp:string|undefined alternateGreetings:[], tags:[], creator:"", - characterVersion: 0, + characterVersion: '', personality: charaData.personality ?? '', scenario:charaData.scenario ?? '', firstMsgIndex: -1, @@ -307,10 +309,13 @@ export async function exportChar(charaID:number) { } -async function importSpecv2(card:CharacterCardV2, img?:Uint8Array):Promise{ +async function importSpecv2(card:CharacterCardV2, img?:Uint8Array, mode?:'hub'|'normal'):Promise{ if(!card ||card.spec !== 'chara_card_v2'){ return false } + if(!mode){ + mode = 'normal' + } const data = card.data const im = img ? await saveAsset(PngMetadata.filter(img)) : undefined @@ -333,7 +338,7 @@ async function importSpecv2(card:CharacterCardV2, img?:Uint8Array):Promise r.trim()), + secondary_keys: lore.selective ? lore.secondkey.split(',').map(r => r.trim()) : undefined, + content: lore.content, + extensions: ext, + enabled: true, + insertion_order: lore.insertorder, + constant: lore.alwaysActive, + selective:lore.selective, + name: lore.comment, + comment: lore.comment, + case_sensitive: caseSensitive, + }) + } + + const card:CharacterCardV2 = { + spec: "chara_card_v2", + spec_version: "2.0", + data: { + name: char.name, + description: char.desc, + personality: char.personality, + scenario: char.scenario, + first_mes: char.firstMessage, + mes_example: char.exampleMessage, + creator_notes: char.creatorNotes, + system_prompt: char.systemPrompt, + post_history_instructions: char.replaceGlobalNote, + alternate_greetings: char.alternateGreetings, + character_book: { + scan_depth: char.loreSettings?.scanDepth, + token_budget: char.loreSettings?.tokenBudget, + recursive_scanning: char.loreSettings?.recursiveScanning, + extensions: char.loreExt ?? {}, + entries: charBook + }, + tags: char.additionalData?.tag ?? [], + creator: char.additionalData?.creator ?? '', + character_version: `${char.additionalData?.character_version}` ?? '', + extensions: { + risuai: { + emotions: char.emotionImages, + bias: char.bias, + viewScreen: char.viewScreen, + customScripts: char.customscript, + utilityBot: char.utilityBot, + sdData: char.sdData, + additionalAssets: char.additionalAssets + } + } + } + } + console.log(card) + return card +} + + export async function exportSpecV2(char:character) { let img = await readImage(char.image) try{ - - let charBook:charBookEntry[] = [] - for(const lore of char.globalLore){ - let ext:{ - risu_case_sensitive?: boolean; - risu_activationPercent?: number - } = cloneDeep(lore.extentions ?? {}) - - let caseSensitive = ext.risu_case_sensitive ?? false - ext.risu_activationPercent = lore.activationPercent - - charBook.push({ - keys: lore.key.split(',').map(r => r.trim()), - secondary_keys: lore.selective ? lore.secondkey.split(',').map(r => r.trim()) : undefined, - content: lore.content, - extensions: ext, - enabled: true, - insertion_order: lore.insertorder, - constant: lore.alwaysActive, - selective:lore.selective, - name: lore.comment, - comment: lore.comment, - case_sensitive: caseSensitive, - }) - } - - const card:CharacterCardV2 = { - spec: "chara_card_v2", - spec_version: "2.0", - data: { - name: char.name, - description: char.desc, - personality: char.personality, - scenario: char.scenario, - first_mes: char.firstMessage, - mes_example: char.exampleMessage, - creator_notes: char.creatorNotes, - system_prompt: char.systemPrompt, - post_history_instructions: char.replaceGlobalNote, - alternate_greetings: char.alternateGreetings, - character_book: { - scan_depth: char.loreSettings?.scanDepth, - token_budget: char.loreSettings?.tokenBudget, - recursive_scanning: char.loreSettings?.recursiveScanning, - extensions: char.loreExt ?? {}, - entries: charBook - }, - tags: char.additionalData?.tag ?? [], - creator: char.additionalData?.creator ?? '', - character_version: char.additionalData?.character_version ?? 0, - extensions: { - risuai: { - emotions: char.emotionImages, - bias: char.bias, - viewScreen: char.viewScreen, - customScripts: char.customscript, - utilityBot: char.utilityBot, - sdData: char.sdData, - additionalAssets: char.additionalAssets - } - } - } - } - + const card = await createBaseV2(char) if(card.data.extensions.risuai.emotions && card.data.extensions.risuai.emotions.length > 0){ for(let i=0;i 0){ + for(let i=0;i 0){ + for(let i=0;i { + const da = await fetch(hubURL + '/hub/list', { + method: "POST", + body: JSON.stringify({ + + }) + }) + if(da.status !== 200){ + return [] + } + return da.json() +} + +export async function downloadRisuHub(id:string, img:string) { + alertStore.set({ + type: "wait", + msg: "Downloading..." + }) + const res = await fetch(hubURL + '/hub/get', { + method: "POST", + body: JSON.stringify({ + id: id + }) + }) + if(res.status !== 200){ + alertError(await res.text()) + } + + const data:CharacterCardV2 = await res.json() + + await importSpecv2(data, await getHubResources(img), 'hub') + checkCharOrder() + let db = get(DataBase) + if(db.characters[db.characters.length-1]){ + const index = db.characters.length-1 + characterFormatUpdate(index); + selectedCharID.set(index); + } + +} + +export async function getHubResources(id:string) { + const res = await fetch(`${hubURL}/resource/${id}`) + if(res.status !== 200){ + throw (await res.text()) + } + return Buffer.from(await (res).arrayBuffer()) +} + + type CharacterCardV2 = { spec: 'chara_card_v2' @@ -581,7 +702,7 @@ type CharacterCardV2 = { character_book?: CharacterBook tags: string[] creator: string - character_version: number + character_version: string extensions: { risuai?:{ emotions?:[string, string][] diff --git a/src/ts/storage/database.ts b/src/ts/storage/database.ts index a42d2a72..47980977 100644 --- a/src/ts/storage/database.ts +++ b/src/ts/storage/database.ts @@ -311,7 +311,7 @@ export interface character{ alternateGreetings:string[] tags:string[] creator:string - characterVersion: number + characterVersion: string personality:string scenario:string firstMsgIndex:number @@ -320,7 +320,7 @@ export interface character{ additionalData?: { tag?:string[] creator?:string - character_version?:number + character_version?:string } ttsMode?:string ttsSpeech?:string diff --git a/tailwind.config.js b/tailwind.config.js index ec5f8e37..992bf6c6 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -23,6 +23,8 @@ export default { '80p': '80%', '80vw': '80vw', '14': '3.5rem', + '24': '6rem', + '36': '9rem', '100vw': '100vw' }, borderWidth: {