feat: persona binding
This commit is contained in:
@@ -670,4 +670,11 @@ export const languageEnglish = {
|
||||
helpBlock: "Help",
|
||||
hideChatIcon: "Hide Icon UI",
|
||||
loadInternalBackup: "Load Internal Backup",
|
||||
createCopy: "Create a Copy",
|
||||
bindPersona: "Bind Persona",
|
||||
chatOptions: "Chat Options",
|
||||
doYouWantToBindCurrentPersona: "Do you want to bind the current persona to this chat?",
|
||||
doYouWantToUnbindCurrentPersona: "Do you want to unbind the persona from this chat?",
|
||||
personaBindedSuccess: "Persona is successfully binded",
|
||||
personaUnbindedSuccess: "Persona is successfully unbinded",
|
||||
}
|
||||
@@ -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 } from "lucide-svelte";
|
||||
import { CurrentCharacter, CurrentChat, CurrentUsername, selectedCharID, CurrentUserIcon, CurrentShowMemoryLimit,CurrentSimpleCharacter, PlaygroundStore } from "../../ts/stores";
|
||||
import { CurrentCharacter, CurrentChat, CurrentUsername, selectedCharID, CurrentUserIcon, CurrentShowMemoryLimit,CurrentSimpleCharacter, PlaygroundStore, UserIconProtrait } from "../../ts/stores";
|
||||
import Chat from "./Chat.svelte";
|
||||
import { DataBase, type Message, type character, type groupChat } from "../../ts/storage/database";
|
||||
import { getCharImage } from "../../ts/characters";
|
||||
@@ -587,7 +587,7 @@
|
||||
message={chat.data}
|
||||
img={getCharImage($CurrentUserIcon, 'css')}
|
||||
isLastMemory={$CurrentChat.lastMemory === (chat.chatId ?? 'none') && $CurrentShowMemoryLimit}
|
||||
largePortrait={$DataBase.personas[$DataBase.selectedPersona].largePortrait}
|
||||
largePortrait={$UserIconProtrait}
|
||||
MessageGenerationInfo={chat.generationInfo}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
<div class="text-textcolor">You should accept RisuRealm's <a class="text-green-600 hover:text-green-500 transition-colors duration-200 cursor-pointer" on:click={() => {
|
||||
openURL('https://sv.risuai.xyz/hub/tos')
|
||||
}}>Terms of Service</a> to continue</div>
|
||||
{:else if $alertStore.type !== 'select' && $alertStore.type !== 'requestdata' && $alertStore.type !== 'addchar' && $alertStore.type !== 'hypaV2'}
|
||||
{:else if $alertStore.type !== 'select' && $alertStore.type !== 'requestdata' && $alertStore.type !== 'addchar' && $alertStore.type !== 'hypaV2' && $alertStore.type !== 'chatOptions'}
|
||||
<span class="text-gray-300">{$alertStore.msg}</span>
|
||||
{#if $alertStore.submsg}
|
||||
<span class="text-gray-500 text-sm">{$alertStore.submsg}</span>
|
||||
@@ -368,6 +368,48 @@
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
{:else if $alertStore.type === 'chatOptions'}
|
||||
<div class="w-2xl flex flex-col max-w-full">
|
||||
<h1 class="text-xl mb-4 font-bold">
|
||||
{language.chatOptions}
|
||||
</h1>
|
||||
<button class="border-darkborderc border py-2 px-8 flex rounded-md hover:ring-2 items-center mt-2" on:click={() => {
|
||||
alertStore.set({
|
||||
type: 'none',
|
||||
msg: '0'
|
||||
})
|
||||
}}>
|
||||
<div class="flex flex-col justify-start items-start">
|
||||
<span>{language.createCopy}</span>
|
||||
</div>
|
||||
<div class="ml-9 float-right flex-1 flex justify-end">
|
||||
<ChevronRightIcon />
|
||||
</div>
|
||||
</button>
|
||||
<button class="border-darkborderc border py-2 px-8 flex rounded-md hover:ring-2 items-center mt-2" on:click={() => {
|
||||
alertStore.set({
|
||||
type: 'none',
|
||||
msg: '1'
|
||||
})
|
||||
}}>
|
||||
<div class="flex flex-col justify-start items-start">
|
||||
<span>{language.bindPersona}</span>
|
||||
</div>
|
||||
<div class="ml-9 float-right flex-1 flex justify-end">
|
||||
<ChevronRightIcon />
|
||||
</div>
|
||||
</button>
|
||||
<button class="border-darkborderc border py-2 px-8 flex rounded-md hover:ring-2 items-center mt-2" on:click={() => {
|
||||
alertStore.set({
|
||||
type: 'none',
|
||||
msg: 'cancel'
|
||||
})
|
||||
}}>
|
||||
<div class="flex flex-col justify-start items-start">
|
||||
<span>{language.cancel}</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
import { getCharImage } from "src/ts/characters";
|
||||
import { changeUserPersona, exportUserPersona, importUserPersona, saveUserPersona, selectUserImg } from "src/ts/persona";
|
||||
import { DataBase, setDatabase } from "src/ts/storage/database";
|
||||
import { CurrentUserIcon } from "src/ts/stores";
|
||||
import { get } from "svelte/store";
|
||||
|
||||
</script>
|
||||
@@ -68,10 +67,10 @@
|
||||
<div class="flex w-full items-starts rounded-md bg-darkbg p-4 max-w-full flex-wrap">
|
||||
<div class="flex flex-col mt-4 mr-4">
|
||||
<button on:click={() => {selectUserImg()}}>
|
||||
{#if $CurrentUserIcon === ''}
|
||||
{#if $DataBase.userIcon === ''}
|
||||
<div class="rounded-md h-28 w-28 shadow-lg bg-textcolor2 cursor-pointer hover:text-green-500" />
|
||||
{:else}
|
||||
{#await getCharImage($CurrentUserIcon, $DataBase.personas[$DataBase.selectedPersona].largePortrait ? 'lgcss' : 'css')}
|
||||
{#await getCharImage($DataBase.userIcon, $DataBase.personas[$DataBase.selectedPersona].largePortrait ? 'lgcss' : 'css')}
|
||||
<div class="rounded-md h-28 w-28 shadow-lg bg-textcolor2 cursor-pointer hover:text-green-500" />
|
||||
{:then im}
|
||||
<div class="rounded-md h-28 w-28 shadow-lg bg-textcolor2 cursor-pointer hover:text-green-500" style={im} />
|
||||
@@ -81,7 +80,7 @@
|
||||
</div>
|
||||
<div class="flex flex-grow flex-col p-2 max-w-full">
|
||||
<span class="text-sm text-textcolor2">{language.name}</span>
|
||||
<TextInput marginBottom size="lg" placeholder="User" bind:value={$DataBase.username} />
|
||||
<TextInput marginBottom size="lg" placeholder="User" bind:value={$DataBase.username}/>
|
||||
<span class="text-sm text-textcolor2">{language.description}</span>
|
||||
<TextAreaInput autocomplete="off" bind:value={$DataBase.personaPrompt} placeholder={`Put the description of this persona here.\nExample: [<user> is a 20 year old girl.]`} />
|
||||
<div class="flex gap-2 mt-4 max-w-full flex-wrap">
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<script lang="ts">
|
||||
import type { Chat, character, groupChat } from "src/ts/storage/database";
|
||||
import { DataBase } from "src/ts/storage/database";
|
||||
import { DataBase, setDatabase } from "src/ts/storage/database";
|
||||
import TextInput from "../UI/GUI/TextInput.svelte";
|
||||
import { DownloadIcon, PencilIcon, FolderUpIcon, MenuIcon, TrashIcon } from "lucide-svelte";
|
||||
import { exportChat, importChat } from "src/ts/characters";
|
||||
import { alertConfirm, alertError, alertSelect } from "src/ts/alert";
|
||||
import { alertChatOptions, alertConfirm, alertError, alertNormal, alertSelect } from "src/ts/alert";
|
||||
import { language } from "src/lang";
|
||||
import Button from "../UI/GUI/Button.svelte";
|
||||
import { findCharacterbyId, parseKeyValue, sleep, sortableOptions } from "src/ts/util";
|
||||
@@ -13,6 +13,7 @@
|
||||
import { CurrentCharacter } from "src/ts/stores";
|
||||
import Sortable from 'sortablejs/modular/sortable.core.esm.js';
|
||||
import { onDestroy, onMount } from "svelte";
|
||||
import { v4 } from "uuid";
|
||||
|
||||
export let chara:character|groupChat
|
||||
let editMode = false
|
||||
@@ -95,16 +96,41 @@
|
||||
<span>{chat.name}</span>
|
||||
{/if}
|
||||
<div class="flex-grow flex justify-end">
|
||||
{#if $DataBase.tpo}
|
||||
<button class="text-textcolor2 hover:text-green-500 mr-1 cursor-pointer" on:click={async () => {
|
||||
const multiuser = parseInt(await alertSelect(["Open Multiuser Room"]))
|
||||
if(multiuser === 0){
|
||||
createMultiuserRoom()
|
||||
<button class="text-textcolor2 hover:text-green-500 mr-1 cursor-pointer" on:click={async () => {
|
||||
const option = await alertChatOptions()
|
||||
switch(option){
|
||||
case 0:{
|
||||
const newChat = structuredClone(chara.chats[i])
|
||||
newChat.name = `Copy of ${newChat.name}`
|
||||
chara.chats.unshift(newChat)
|
||||
chara.chatPage = 0
|
||||
chara.chats = chara.chats
|
||||
}
|
||||
}}>
|
||||
<MenuIcon size={18}/>
|
||||
</button>
|
||||
{/if}
|
||||
case 1:{
|
||||
const chat = chara.chats[i]
|
||||
if(chat.bindedPersona){
|
||||
const confirm = await alertConfirm(language.doYouWantToUnbindCurrentPersona)
|
||||
if(confirm){
|
||||
chat.bindedPersona = ''
|
||||
alertNormal(language.personaUnbindedSuccess)
|
||||
}
|
||||
}
|
||||
else{
|
||||
const confirm = await alertConfirm(language.doYouWantToBindCurrentPersona)
|
||||
if(confirm){
|
||||
if(!$DataBase.personas[$DataBase.selectedPersona].id){
|
||||
$DataBase.personas[$DataBase.selectedPersona].id = v4()
|
||||
}
|
||||
chat.bindedPersona = $DataBase.personas[$DataBase.selectedPersona].id
|
||||
console.log($DataBase.personas[$DataBase.selectedPersona])
|
||||
alertNormal(language.personaBindedSuccess)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}}>
|
||||
<MenuIcon size={18}/>
|
||||
</button>
|
||||
<button class="text-textcolor2 hover:text-green-500 mr-1 cursor-pointer" on:click={() => {
|
||||
editMode = !editMode
|
||||
}}>
|
||||
|
||||
@@ -6,7 +6,10 @@ import { Capacitor } from "@capacitor/core"
|
||||
import { DataBase, type MessageGenerationInfo } from "./storage/database"
|
||||
|
||||
interface alertData{
|
||||
type: 'error'| 'normal'|'none'|'ask'|'wait'|'selectChar'|'input'|'toast'|'wait2'|'markdown'|'select'|'login'|'tos'|'cardexport'|'requestdata'|'addchar'|'hypaV2'|'selectModule',
|
||||
type: 'error'|'normal'|'none'|'ask'|'wait'|'selectChar'
|
||||
|'input'|'toast'|'wait2'|'markdown'|'select'|'login'
|
||||
|'tos'|'cardexport'|'requestdata'|'addchar'|'hypaV2'|'selectModule'
|
||||
|'chatOptions',
|
||||
msg: string,
|
||||
submsg?: string
|
||||
}
|
||||
@@ -94,6 +97,21 @@ export async function alertAddCharacter() {
|
||||
return get(alertStore).msg
|
||||
}
|
||||
|
||||
export async function alertChatOptions() {
|
||||
alertStore.set({
|
||||
'type': 'chatOptions',
|
||||
'msg': language.chatOptions
|
||||
})
|
||||
while(true){
|
||||
if (get(alertStore).type === 'none'){
|
||||
break
|
||||
}
|
||||
await sleep(10)
|
||||
}
|
||||
|
||||
return parseInt(get(alertStore).msg)
|
||||
}
|
||||
|
||||
export async function alertLogin(){
|
||||
alertStore.set({
|
||||
'type': 'login',
|
||||
|
||||
@@ -6,6 +6,7 @@ import { downloadFile, readImage } from "./storage/globalApi"
|
||||
import { language } from "src/lang"
|
||||
import { reencodeImage } from "./process/files/image"
|
||||
import { PngChunk } from "./pngChunk"
|
||||
import { v4 } from "uuid"
|
||||
|
||||
export async function selectUserImg() {
|
||||
const selected = await selectSingleFile(['png'])
|
||||
@@ -17,21 +18,20 @@ export async function selectUserImg() {
|
||||
const imgp = await saveImage(img)
|
||||
db.userIcon = imgp
|
||||
db.personas[db.selectedPersona] = {
|
||||
name: getUserName(),
|
||||
name: db.username,
|
||||
icon: db.userIcon,
|
||||
personaPrompt: db.personaPrompt
|
||||
personaPrompt: db.personaPrompt,
|
||||
id: v4()
|
||||
}
|
||||
setDatabase(db)
|
||||
}
|
||||
|
||||
export function saveUserPersona() {
|
||||
let db = get(DataBase)
|
||||
db.personas[db.selectedPersona] = {
|
||||
name: getUserName(),
|
||||
icon: db.userIcon,
|
||||
personaPrompt: db.personaPrompt,
|
||||
largePortrait: db.personas[db.selectedPersona]?.largePortrait,
|
||||
}
|
||||
db.personas[db.selectedPersona].name=db.username
|
||||
db.personas[db.selectedPersona].icon=db.userIcon,
|
||||
db.personas[db.selectedPersona].personaPrompt=db.personaPrompt,
|
||||
db.personas[db.selectedPersona].largePortrait=db.personas[db.selectedPersona]?.largePortrait,
|
||||
setDatabase(db)
|
||||
}
|
||||
|
||||
@@ -111,7 +111,8 @@ export async function importUserPersona(){
|
||||
db.personas.push({
|
||||
name: data.name,
|
||||
icon: await saveImage(await reencodeImage(v.data)),
|
||||
personaPrompt: data.personaPrompt
|
||||
personaPrompt: data.personaPrompt,
|
||||
id: v4()
|
||||
})
|
||||
setDatabase(db)
|
||||
alertNormal(language.successImport)
|
||||
|
||||
@@ -595,6 +595,7 @@ export interface Database{
|
||||
name:string
|
||||
icon:string
|
||||
largePortrait?:boolean
|
||||
id?:string
|
||||
}[]
|
||||
assetWidth:number
|
||||
animationSpeed:number
|
||||
@@ -1005,6 +1006,7 @@ export interface Chat{
|
||||
scriptstate?:{[key:string]:string|number|boolean}
|
||||
modules?:string[]
|
||||
id?:string
|
||||
bindedPersona?:string
|
||||
}
|
||||
|
||||
export interface Message{
|
||||
|
||||
@@ -923,6 +923,11 @@ async function checkNewFormat() {
|
||||
return v
|
||||
})
|
||||
|
||||
db.personas = (db.personas ?? []).map((v) => {
|
||||
v.id ??= uuidv4()
|
||||
return v
|
||||
})
|
||||
|
||||
if(!db.formatversion){
|
||||
function checkParge(data:string){
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { get, writable, type Writable } from "svelte/store";
|
||||
import { DataBase, type Chat, type character, type groupChat } from "./storage/database";
|
||||
import { isEqual } from "lodash";
|
||||
import type { simpleCharacterArgument } from "./parser";
|
||||
import { getUserIcon, getUserName, sleep } from "./util";
|
||||
import { getUserIcon, getUserIconProtrait, getUserName, sleep } from "./util";
|
||||
import { getModules } from "./process/modules";
|
||||
|
||||
function updateSize(){
|
||||
@@ -43,6 +43,7 @@ export const OpenRealmStore = writable(false)
|
||||
export const ShowRealmFrameStore = writable('')
|
||||
export const PlaygroundStore = writable(0)
|
||||
export const HideIconStore = writable(false)
|
||||
export const UserIconProtrait = writable(false)
|
||||
let lastGlobalEnabledModules: string[] = []
|
||||
let lastChatEnabledModules: string[] = []
|
||||
let moduleHideIcon = false
|
||||
@@ -136,7 +137,10 @@ async function preInit(){
|
||||
CurrentUsername.set(getUserName())
|
||||
}
|
||||
if(getUserIcon() !== get(CurrentUserIcon)){
|
||||
CurrentUserIcon.set(data.userIcon)
|
||||
CurrentUserIcon.set(getUserIcon())
|
||||
}
|
||||
if(getUserIconProtrait() !== get(UserIconProtrait)){
|
||||
UserIconProtrait.set(getUserIconProtrait())
|
||||
}
|
||||
if(data.showMemoryLimit !== get(CurrentShowMemoryLimit)){
|
||||
CurrentShowMemoryLimit.set(data.showMemoryLimit)
|
||||
@@ -161,7 +165,15 @@ async function preInit(){
|
||||
characterHideIcon = char?.hideChatIcon
|
||||
HideIconStore.set(characterHideIcon || moduleHideIcon)
|
||||
}
|
||||
|
||||
if(getUserName() !== get(CurrentUsername)){
|
||||
CurrentUsername.set(getUserName())
|
||||
}
|
||||
if(getUserIcon() !== get(CurrentUserIcon)){
|
||||
CurrentUserIcon.set(getUserIcon())
|
||||
}
|
||||
if(getUserIconProtrait() !== get(UserIconProtrait)){
|
||||
UserIconProtrait.set(getUserIconProtrait())
|
||||
}
|
||||
if(charId === -1 || charId > db.characters.length){
|
||||
return
|
||||
}
|
||||
|
||||
@@ -107,21 +107,65 @@ export const replacePlaceholders = (msg:string, name:string) => {
|
||||
.replace(/(\{\{((set)|(get))var::.+?\}\})/gu,'')
|
||||
}
|
||||
|
||||
function checkPersonaBinded(){
|
||||
try {
|
||||
let db = get(DataBase)
|
||||
const selectedChar = get(selectedCharID)
|
||||
const character = db.characters[selectedChar]
|
||||
const chat = character.chats[character.chatPage]
|
||||
console.log(chat.bindedPersona)
|
||||
if(!chat.bindedPersona){
|
||||
return null
|
||||
}
|
||||
const persona = db.personas.find(v => v.id === chat.bindedPersona)
|
||||
console.log(db.personas, persona)
|
||||
return persona
|
||||
} catch (error) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export function getUserName(){
|
||||
const bindedPersona = checkPersonaBinded()
|
||||
if(bindedPersona){
|
||||
return bindedPersona.name
|
||||
}
|
||||
const db = get(DataBase)
|
||||
return db.username ?? 'User'
|
||||
}
|
||||
|
||||
export function getUserIcon(){
|
||||
const bindedPersona = checkPersonaBinded()
|
||||
console.log(`Icon: ${bindedPersona?.icon}`)
|
||||
if(bindedPersona){
|
||||
return bindedPersona.icon
|
||||
}
|
||||
const db = get(DataBase)
|
||||
return db.userIcon ?? ''
|
||||
}
|
||||
|
||||
export function getPersonaPrompt(){
|
||||
const bindedPersona = checkPersonaBinded()
|
||||
if(bindedPersona){
|
||||
return bindedPersona.personaPrompt
|
||||
}
|
||||
const db = get(DataBase)
|
||||
return db.personaPrompt ?? ''
|
||||
}
|
||||
|
||||
export function getUserIconProtrait(){
|
||||
try {
|
||||
const bindedPersona = checkPersonaBinded()
|
||||
if(bindedPersona){
|
||||
return bindedPersona.largePortrait
|
||||
}
|
||||
const db = get(DataBase)
|
||||
return db.personas[db.selectedPersona].largePortrait
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export function checkIsIos(){
|
||||
return /(iPad|iPhone|iPod)/g.test(navigator.userAgent)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user