feat: add preset sharing
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
<script lang="ts">
|
||||
import Sidebar from './lib/SideBars/Sidebar.svelte';
|
||||
import {ArrowRight} from 'lucide-svelte'
|
||||
import { DynamicGUI, settingsOpen, sideBarStore } from './ts/stores';
|
||||
import { DynamicGUI, settingsOpen, sideBarStore, ShowRealmFrameStore } from './ts/stores';
|
||||
import { DataBase, loadedStore } from './ts/storage/database';
|
||||
import ChatScreen from './lib/ChatScreens/ChatScreen.svelte';
|
||||
import AlertComp from './lib/Others/AlertComp.svelte';
|
||||
@@ -11,6 +10,7 @@
|
||||
import WelcomeRisu from './lib/Others/WelcomeRisu.svelte';
|
||||
import Settings from './lib/Setting/Settings.svelte';
|
||||
import { showRealmInfoStore } from './ts/characterCards';
|
||||
import RealmFrame from './lib/UI/Realm/RealmFrame.svelte';
|
||||
|
||||
let didFirstSetup: boolean = false
|
||||
let gridOpen = false
|
||||
@@ -60,4 +60,7 @@
|
||||
{#if $showRealmInfoStore}
|
||||
<RealmPopUp bind:openedData={$showRealmInfoStore} />
|
||||
{/if}
|
||||
{#if $ShowRealmFrameStore}
|
||||
<RealmFrame />
|
||||
{/if}
|
||||
</main>
|
||||
@@ -529,6 +529,7 @@ export const languageEnglish = {
|
||||
memoryLimitThickness: "Memory Limit Thickness",
|
||||
inputCardPassword: "Input Card Password",
|
||||
ccv2Desc: 'Character Card V2 is is a format widely used in chatbot programs.',
|
||||
realmDesc: 'RisuRealm is a content sharing platform for RisuAI. you can share your character to other users.',
|
||||
rccDesc: 'Risu Refined Character Card is a format with additional features like password, integrity check and etc.',
|
||||
password: "Password",
|
||||
license: "License",
|
||||
@@ -599,4 +600,7 @@ export const languageEnglish = {
|
||||
list: "List",
|
||||
trash: "Trash",
|
||||
trashDesc: "Deleted characters are moved to trash. you can restore or delete them permanently. deleted characters are automatically purged after 3 days.",
|
||||
shareExport: "Share/Export",
|
||||
risupresetDesc: "Risupreset format is a format specifically designed for RisuAI presets.",
|
||||
jsonDesc: "JSON format is a format that is easy to read and write for both humans and machines.",
|
||||
}
|
||||
@@ -24,15 +24,19 @@
|
||||
let cardExportPassword = ''
|
||||
let cardLicense = ''
|
||||
let generationInfoMenuIndex = 0
|
||||
$: (() => {
|
||||
$: {
|
||||
if(btn){
|
||||
btn.focus()
|
||||
}
|
||||
if($alertStore.type !== 'input'){
|
||||
input = ''
|
||||
}
|
||||
|
||||
})()
|
||||
if($alertStore.type !== 'cardexport'){
|
||||
cardExportType = ''
|
||||
cardExportPassword = ''
|
||||
cardLicense = ''
|
||||
}
|
||||
}
|
||||
|
||||
const beautifyJSON = (data:string) =>{
|
||||
try {
|
||||
@@ -372,7 +376,7 @@
|
||||
<div class="bg-darkbg rounded-md p-4 max-w-full flex flex-col w-2xl" on:click|stopPropagation>
|
||||
<h1 class="font-bold text-2xl w-full">
|
||||
<span>
|
||||
Export Character
|
||||
{language.shareExport}
|
||||
</span>
|
||||
<button class="float-right text-textcolor2 hover:text-green-500" on:click={() => {
|
||||
alertStore.set({
|
||||
@@ -387,29 +391,27 @@
|
||||
<XIcon />
|
||||
</button>
|
||||
</h1>
|
||||
<span class="text-textcolor mt-4">Type</span>
|
||||
<span class="text-textcolor mt-4">{language.type}</span>
|
||||
{#if cardExportType === ''}
|
||||
<span class="text-textcolor2 text-sm">{language.ccv2Desc}</span>
|
||||
{#if $alertStore.submsg !== 'preset'}
|
||||
<span class="text-textcolor2 text-sm">{language.risupresetDesc}</span>
|
||||
{:else}
|
||||
<span class="text-textcolor2 text-sm">{language.ccv2Desc}</span>
|
||||
{/if}
|
||||
{:else if cardExportType === 'json'}
|
||||
<span class="text-textcolor2 text-sm">{language.jsonDesc}</span>
|
||||
{:else}
|
||||
<span class="text-textcolor2 text-sm">{language.rccDesc}</span>
|
||||
<span class="text-textcolor2 text-sm">{language.realmDesc}</span>
|
||||
{/if}
|
||||
<div class="flex items-center flex-wrap mt-2">
|
||||
<button class="bg-bgcolor px-2 py-4 rounded-lg flex-1" class:ring-1={cardExportType === ''} on:click={() => {cardExportType = ''}}>Character Card V2</button>
|
||||
<button class="bg-bgcolor px-2 py-4 rounded-lg ml-2 flex-1" class:ring-1={cardExportType === 'rcc'} on:click={() => {cardExportType = 'rcc'}}>Risu RCC</button>
|
||||
{#if $alertStore.submsg === 'preset'}
|
||||
<button class="bg-bgcolor px-2 py-4 rounded-lg flex-1" class:ring-1={cardExportType === ''} on:click={() => {cardExportType = ''}}>Risupreset</button>
|
||||
<button class="bg-bgcolor px-2 py-4 rounded-lg ml-2 flex-1" class:ring-1={cardExportType === 'json'} on:click={() => {cardExportType = 'json'}}>JSON</button>
|
||||
<button class="bg-bgcolor px-2 py-4 rounded-lg ml-2 flex-1" class:ring-1={cardExportType === 'realm'} on:click={() => {cardExportType = 'realm'}}>RisuRealm</button>
|
||||
{:else}
|
||||
<button class="bg-bgcolor px-2 py-4 rounded-lg flex-1" class:ring-1={cardExportType === ''} on:click={() => {cardExportType = ''}}>Character Card V2</button>
|
||||
{/if}
|
||||
</div>
|
||||
{#if cardExportType === 'rcc'}
|
||||
<span class="text-textcolor mt-4">{language.password}</span>
|
||||
<span class="text-textcolor2 text-sm">{language.passwordDesc}</span>
|
||||
<TextInput placeholder="" bind:value={cardExportPassword} />
|
||||
<span class="text-textcolor mt-4">{language.license}</span>
|
||||
<span class="text-textcolor2 text-sm">{language.licenseDesc}</span>
|
||||
<SelectInput bind:value={cardLicense}>
|
||||
<OptionInput value="">None</OptionInput>
|
||||
{#each Object.keys(CCLicenseData) as ccl}
|
||||
<OptionInput value={ccl}>{CCLicenseData[ccl][2]} ({CCLicenseData[ccl][1]})</OptionInput>
|
||||
{/each}
|
||||
</SelectInput>
|
||||
{/if}
|
||||
<Button className="mt-4" on:click={() => {
|
||||
alertStore.set({
|
||||
type: 'none',
|
||||
@@ -419,7 +421,7 @@
|
||||
license: cardLicense
|
||||
})
|
||||
})
|
||||
}}>{language.export}</Button>
|
||||
}}>{cardExportType === 'realm' ? language.shareCloud : language.export}</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<script>
|
||||
import { alertConfirm, alertError } from "../../ts/alert";
|
||||
<script lang="ts">
|
||||
import { alertCardExport, alertConfirm, alertError } from "../../ts/alert";
|
||||
import { language } from "../../lang";
|
||||
import { DataBase, changeToPreset, copyPreset, downloadPreset, importPreset, presetTemplate } from "../../ts/storage/database";
|
||||
import { CopyIcon, DownloadIcon, EditIcon, FolderUpIcon, PlusIcon, TrashIcon, XIcon } from "lucide-svelte";
|
||||
import { DataBase, changeToPreset, copyPreset, downloadPreset, importPreset } from "../../ts/storage/database";
|
||||
import { CopyIcon, Share2Icon, PencilIcon, FolderUpIcon, PlusIcon, TrashIcon, XIcon } from "lucide-svelte";
|
||||
import TextInput from "../UI/GUI/TextInput.svelte";
|
||||
import { prebuiltPresets } from "src/ts/process/templates/templates";
|
||||
import { ShowRealmFrameStore } from "src/ts/stores";
|
||||
|
||||
let editMode = false
|
||||
export let close = () => {}
|
||||
@@ -43,12 +44,26 @@
|
||||
}}>
|
||||
<CopyIcon size={18}/>
|
||||
</button>
|
||||
<button class="text-textcolor2 hover:text-green-500 cursor-pointer mr-2" on:click={(e) => {
|
||||
<button class="text-textcolor2 hover:text-green-500 cursor-pointer mr-2" on:click={async (e) => {
|
||||
e.stopPropagation()
|
||||
downloadPreset(i)
|
||||
const data = await alertCardExport('preset')
|
||||
console.log(data.type)
|
||||
if(data.type === ''){
|
||||
downloadPreset(i, 'risupreset')
|
||||
}
|
||||
if(data.type === 'json'){
|
||||
downloadPreset(i, 'json')
|
||||
}
|
||||
if(data.type === 'realm'){
|
||||
if(!$DataBase.account){
|
||||
alertError(language.notLoggedIn)
|
||||
return
|
||||
}
|
||||
$ShowRealmFrameStore = `preset:${i}`
|
||||
}
|
||||
}}>
|
||||
|
||||
<DownloadIcon size={18} />
|
||||
<Share2Icon size={18} />
|
||||
</button>
|
||||
<button class="text-textcolor2 hover:text-green-500 cursor-pointer" on:click={async (e) => {
|
||||
e.stopPropagation()
|
||||
@@ -89,7 +104,7 @@
|
||||
<button class="text-textcolor2 hover:text-green-500 cursor-pointer" on:click={() => {
|
||||
editMode = !editMode
|
||||
}}>
|
||||
<EditIcon size={18}/>
|
||||
<PencilIcon size={18}/>
|
||||
</button>
|
||||
</div>
|
||||
<span class="text-textcolor2 text-sm">{language.quickPreset}</span>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { language } from "../../lang";
|
||||
import { tokenizeAccurate } from "../../ts/tokenizer";
|
||||
import { DataBase, saveImage as saveAsset, type Database, type character, type groupChat } from "../../ts/storage/database";
|
||||
import { selectedCharID } from "../../ts/stores";
|
||||
import { ShowRealmFrameStore, selectedCharID } from "../../ts/stores";
|
||||
import { PlusIcon, SmileIcon, TrashIcon, UserIcon, ActivityIcon, BookIcon, User, CurlyBraces, Volume2Icon } from 'lucide-svelte'
|
||||
import Check from "../UI/GUI/CheckInput.svelte";
|
||||
import { addCharEmotion, addingEmotion, getCharImage, rmCharEmotion, selectCharImg, makeGroupImage, removeChar } from "../../ts/characters";
|
||||
@@ -17,7 +17,6 @@
|
||||
import { getElevenTTSVoices, getWebSpeechTTSVoices, getVOICEVOXVoices, oaiVoices, getNovelAIVoices, FixNAITTS } from "src/ts/process/tts";
|
||||
import { checkCharOrder, getFileSrc } from "src/ts/storage/globalApi";
|
||||
import { addGroupChar, rmCharFromGroup } from "src/ts/process/group";
|
||||
import RealmUpload from "../UI/Realm/RealmUpload.svelte";
|
||||
import TextInput from "../UI/GUI/TextInput.svelte";
|
||||
import NumberInput from "../UI/GUI/NumberInput.svelte";
|
||||
import TextAreaInput from "../UI/GUI/TextAreaInput.svelte";
|
||||
@@ -30,11 +29,9 @@
|
||||
import { updateInlayScreen } from "src/ts/process/inlayScreen";
|
||||
import { registerOnnxModel } from "src/ts/process/transformers";
|
||||
import MultiLangInput from "../UI/GUI/MultiLangInput.svelte";
|
||||
import RealmFrame from "../UI/Realm/RealmFrame.svelte";
|
||||
|
||||
|
||||
let subMenu = 0
|
||||
let openHubUpload = false
|
||||
let emos:[string, string][] = []
|
||||
let tokens = {
|
||||
desc: 0,
|
||||
@@ -833,7 +830,7 @@
|
||||
|| $DataBase.tpo
|
||||
}
|
||||
<Button size="lg" on:click={async () => {
|
||||
exportChar($selectedCharID)
|
||||
const res = await exportChar($selectedCharID)
|
||||
}} className="mt-2">{language.exportCharacter}</Button>
|
||||
{/if}
|
||||
|
||||
@@ -846,7 +843,7 @@
|
||||
return
|
||||
}
|
||||
if(await alertTOS()){
|
||||
openHubUpload = true
|
||||
$ShowRealmFrameStore = 'character'
|
||||
}
|
||||
}} className="mt-2">
|
||||
{#if currentChar.data.realmId}
|
||||
@@ -856,11 +853,6 @@
|
||||
{/if}
|
||||
</Button>
|
||||
{/if}
|
||||
|
||||
{#if openHubUpload}
|
||||
<!-- <RealmUpload bind:char={currentChar.data} close={() => {openHubUpload=false}}/> -->
|
||||
<RealmFrame close={() => {openHubUpload=false}}/>
|
||||
{/if}
|
||||
{:else}
|
||||
{#if currentChar.data.chats[currentChar.data.chatPage].supaMemoryData && currentChar.data.chats[currentChar.data.chatPage].supaMemoryData.length > 4 || currentChar.data.supaMemory}
|
||||
<span class="text-textcolor">{language.SuperMemory}</span>
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { alertMd } from "src/ts/alert";
|
||||
import { shareRealmCardData } from "src/ts/realm";
|
||||
import { DataBase } from "src/ts/storage/database";
|
||||
import { CurrentCharacter } from "src/ts/stores";
|
||||
import { DataBase, downloadPreset } from "src/ts/storage/database";
|
||||
import { CurrentCharacter, ShowRealmFrameStore } from "src/ts/stores";
|
||||
import { sleep } from "src/ts/util";
|
||||
import { onDestroy, onMount } from "svelte";
|
||||
|
||||
export let close: () => void
|
||||
const close = () => {
|
||||
$ShowRealmFrameStore = ''
|
||||
}
|
||||
let iframe: HTMLIFrameElement = null
|
||||
const tk = $DataBase?.account?.token;
|
||||
const id = $DataBase?.account?.id
|
||||
@@ -25,7 +27,10 @@
|
||||
}
|
||||
if(e.data.type === 'success'){
|
||||
alertMd(`## Upload Success\n\nYour character has been uploaded to Realm successfully.\n\n${"```\nhttps://realm.risuai.net/character/" + e.data.id + "\n```"}`)
|
||||
if($CurrentCharacter.type === 'character'){
|
||||
if($ShowRealmFrameStore.startsWith('preset')){
|
||||
//TODO, add preset edit
|
||||
}
|
||||
else if($CurrentCharacter.type === 'character'){
|
||||
loadingStage = 0
|
||||
$CurrentCharacter.realmId = e.data.id
|
||||
}
|
||||
@@ -47,7 +52,23 @@
|
||||
onMount(async () => {
|
||||
window.addEventListener('message', pmfunc)
|
||||
|
||||
const data = await shareRealmCardData()
|
||||
let data:{
|
||||
data: ArrayBuffer,
|
||||
name: ArrayBuffer
|
||||
}
|
||||
|
||||
if($ShowRealmFrameStore.startsWith('preset')){
|
||||
const predata = await downloadPreset(Number($ShowRealmFrameStore.split(':')[1]), 'return')
|
||||
const encodedPredata = predata.buf
|
||||
const encodedPredataName = new TextEncoder().encode(predata.data.name + '.risupreset')
|
||||
data = {
|
||||
data: encodedPredata.buffer,
|
||||
name: encodedPredataName.buffer
|
||||
}
|
||||
}
|
||||
else{
|
||||
data = await shareRealmCardData()
|
||||
}
|
||||
|
||||
if(iframe){
|
||||
await waitPing()
|
||||
@@ -61,7 +82,10 @@
|
||||
|
||||
const getUrl = () => {
|
||||
let url = `https://realm.risuai.net/upload?token=${tk}&token_id=${id}`
|
||||
if($CurrentCharacter.type === 'character' && $CurrentCharacter.realmId){
|
||||
if($ShowRealmFrameStore.startsWith('preset')){
|
||||
//TODO, add preset edit
|
||||
}
|
||||
else if($CurrentCharacter.type === 'character' && $CurrentCharacter.realmId){
|
||||
url += `&edit=${$CurrentCharacter.realmId}&edit-type=normal`
|
||||
}
|
||||
url += '#noLayout'
|
||||
|
||||
@@ -205,11 +205,12 @@ export async function alertConfirm(msg:string){
|
||||
return get(alertStore).msg === 'yes'
|
||||
}
|
||||
|
||||
export async function alertCardExport(){
|
||||
export async function alertCardExport(type:string = ''){
|
||||
|
||||
alertStore.set({
|
||||
'type': 'cardexport',
|
||||
'msg': ''
|
||||
'msg': '',
|
||||
'submsg': type
|
||||
})
|
||||
|
||||
while(true){
|
||||
|
||||
@@ -293,35 +293,27 @@ function convertOldTavernAndJSON(charaData:OldTavernChar, imgp:string|undefined
|
||||
}
|
||||
}
|
||||
|
||||
export async function exportChar(charaID:number) {
|
||||
export async function exportChar(charaID:number):Promise<string> {
|
||||
const db = get(DataBase)
|
||||
let char = structuredClone(db.characters[charaID])
|
||||
|
||||
if(char.type === 'group'){
|
||||
return
|
||||
return ''
|
||||
}
|
||||
|
||||
if(!char.image){
|
||||
alertError('Image Required')
|
||||
return
|
||||
}
|
||||
const conf = await alertConfirm(language.exportConfirm)
|
||||
if(!conf){
|
||||
return
|
||||
return ''
|
||||
}
|
||||
|
||||
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{
|
||||
if(option.type === ''){
|
||||
exportSpecV2(char,'png')
|
||||
}
|
||||
return
|
||||
else{
|
||||
return option.type
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1222,7 +1222,7 @@ import type { OnnxModelFiles } from '../process/transformers';
|
||||
import type { RisuModule } from '../process/modules';
|
||||
import type { HypaV2Data } from '../process/memory/hypav2';
|
||||
|
||||
export async function downloadPreset(id:number){
|
||||
export async function downloadPreset(id:number, type:'json'|'risupreset'|'return' = 'json'){
|
||||
saveCurrentPreset()
|
||||
let db = get(DataBase)
|
||||
let pres = structuredClone(db.botPresets[id])
|
||||
@@ -1233,21 +1233,37 @@ export async function downloadPreset(id:number){
|
||||
pres.proxyKey = ''
|
||||
pres.textgenWebUIStreamURL= ''
|
||||
pres.textgenWebUIBlockingURL= ''
|
||||
const sel = parseInt(await alertSelect(['RISUPRESET (recommended)','JSON']))
|
||||
if(sel === 1){
|
||||
if(type === 'json'){
|
||||
downloadFile(pres.name + "_preset.json", Buffer.from(JSON.stringify(pres, null, 2)))
|
||||
}
|
||||
else{
|
||||
downloadFile(pres.name + "_preset.risupreset", fflate.compressSync(encodeMsgpack({
|
||||
else if(type === 'risupreset' || type === 'return'){
|
||||
const buf = fflate.compressSync(encodeMsgpack({
|
||||
presetVersion: 0,
|
||||
type: 'preset',
|
||||
pres: await encryptBuffer(
|
||||
encodeMsgpack(pres),
|
||||
'risupreset'
|
||||
)
|
||||
})))
|
||||
}))
|
||||
if(type === 'risupreset'){
|
||||
downloadFile(pres.name + "_preset.risupreset", buf)
|
||||
}
|
||||
else{
|
||||
return {
|
||||
data: pres,
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
alertNormal(language.successExport)
|
||||
|
||||
|
||||
return {
|
||||
data: pres,
|
||||
buf: null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ export const ShowVN = writable(false)
|
||||
export const SettingsMenuIndex = writable(-1)
|
||||
export const CurrentVariablePointer = writable({} as {[key:string]: string|number|boolean})
|
||||
export const OpenRealmStore = writable(false)
|
||||
export const ShowRealmFrameStore = writable('')
|
||||
export const PlaygroundStore = writable(0)
|
||||
|
||||
function createSimpleCharacter(char:character|groupChat){
|
||||
|
||||
Reference in New Issue
Block a user