Risuai 0.6.3 first commit

This commit is contained in:
kwaroran
2023-05-07 12:41:45 +09:00
parent 50e5e1d917
commit 2c5c7d2694
98 changed files with 15070 additions and 0 deletions

View File

@@ -0,0 +1,148 @@
<script>
import { onMount } from 'svelte';
import { alertStore } from "../../ts/alert";
import { DataBase } from '../../ts/database';
import { getCharImage } from '../../ts/characters';
import { ParseMarkdown } from '../../ts/parser';
import BarIcon from '../SideBars/BarIcon.svelte';
import { User } from 'lucide-svelte';
let btn
let input = ''
$: (() => {
if(btn){
btn.focus()
}
if($alertStore.type !== 'input'){
input = ''
}
})()
</script>
{#if $alertStore.type !== 'none' && $alertStore.type !== 'toast'}
<div class="absolute w-full h-full z-50 bg-black bg-opacity-50 flex justify-center items-center" class:vis={ $alertStore.type === 'wait2'}>
<div class="bg-darkbg p-4 break-any rounded-md flex flex-col max-w-3xl max-h-11/12 overflow-y-auto">
{#if $alertStore.type === 'error'}
<h2 class="text-red-700 mt-0 mb-2 w-40 max-w-full">Error</h2>
{:else if $alertStore.type === 'ask'}
<h2 class="text-green-700 mt-0 mb-2 w-40 max-w-full">Confirm</h2>
{:else if $alertStore.type === 'selectChar'}
<h2 class="text-green-700 mt-0 mb-2 w-40 max-w-full">Select</h2>
{:else if $alertStore.type === 'input'}
<h2 class="text-green-700 mt-0 mb-2 w-40 max-w-full">Input</h2>
{/if}
{#if $alertStore.type === 'markdown'}
<span class="text-gray-300 chattext prose prose-invert chattext2">{@html ParseMarkdown($alertStore.msg)}</span>
{:else if $alertStore.type !== 'select'}
<span class="text-gray-300">{$alertStore.msg}</span>
{/if}
{#if $alertStore.type === 'ask'}
<div class="flex gap-2 w-full">
<button bind:this={btn} class="mt-4 border-borderc bg-transparent outline-none border-solid border-1 p-2 text-lg text-neutral-200 hover:bg-green-500 transition-colors flex-1 focus:border-3" on:click={() => {
alertStore.set({
type: 'none',
msg: 'yes'
})
}}>YES</button>
<button class="mt-4 border-borderc bg-transparent outline-none border-solid border-1 p-2 text-lg text-neutral-200 hover:bg-red-500 transition-colors focus:border-3 flex-1" on:click={() => {
alertStore.set({
type: 'none',
msg: 'no'
})
}}>NO</button>
</div>
{:else if $alertStore.type === 'select'}
{#each $alertStore.msg.split('||') as n, i}
<button bind:this={btn} class="mt-4 border-borderc bg-transparent outline-none border-solid border-1 p-2 text-lg text-neutral-200 hover:bg-green-500 transition-colors focus:border-3" on:click={() => {
alertStore.set({
type: 'none',
msg: i.toString()
})
}}>{n}</button>
{/each}
{:else if $alertStore.type === 'error' || $alertStore.type === 'normal' || $alertStore.type === 'markdown'}
<button bind:this={btn} class="mt-4 border-borderc bg-transparent outline-none border-solid border-1 p-2 text-lg text-neutral-200 hover:bg-green-500 transition-colors focus:border-3" on:click={() => {
alertStore.set({
type: 'none',
msg: ''
})
}}>OK</button>
{:else if $alertStore.type === 'input'}
<input class="text-neutral-200 mt-2 p-2 bg-transparent input-text focus:bg-selected" bind:value={input}>
<button bind:this={btn} class="mt-4 border-borderc bg-transparent outline-none border-solid border-1 p-2 text-lg text-neutral-200 hover:bg-green-500 transition-colors focus:border-3" on:click={() => {
alertStore.set({
type: 'none',
msg: input
})
}}>OK</button>
{:else if $alertStore.type === 'selectChar'}
<div class="flex w-full items-start flex-wrap gap-2 justify-start">
{#each $DataBase.characters as char, i}
{#if char.type !== 'group'}
{#if char.image}
{#await getCharImage($DataBase.characters[i].image, 'css')}
<BarIcon onClick={() => {
//@ts-ignore
alertStore.set({type: 'none',msg: char.chaId})
}}>
<User/>
</BarIcon>
{:then im}
<BarIcon onClick={() => {
//@ts-ignore
alertStore.set({type: 'none',msg: char.chaId})
}} additionalStyle={im} />
{/await}
{:else}
<BarIcon onClick={() => {
//@ts-ignore
alertStore.set({type: 'none',msg: char.chaId})
}}>
<User/>
</BarIcon>
{/if}
{/if}
{/each}
</div>
{/if}
</div>
</div>
{:else if $alertStore.type === 'toast'}
<div class="toast-anime absolute right-0 bottom-0 bg-darkbg p-4 break-any rounded-md flex flex-col max-w-3xl max-h-11/12 overflow-y-auto z-50 text-neutral-200"
on:animationend={() => {
alertStore.set({
type: 'none',
msg: ''
})
}}
>{$alertStore.msg}</div>
{/if}
<style>
.break-any{
word-break: normal;
overflow-wrap: anywhere;
}
@keyframes toastAnime {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.toast-anime {
animation: toastAnime 1s ease-out;
}
.vis{
opacity: 1 !important;
--tw-bg-opacity: 1 !important;
}
</style>

View File

@@ -0,0 +1,104 @@
<script>
import { alertConfirm, alertError } from "../../ts/alert";
import { language } from "../../lang";
import { DataBase } from "../../ts/database";
import { selectedCharID } from "../../ts/stores";
import { DownloadIcon, EditIcon, FolderUpIcon, PlusIcon, TrashIcon, XIcon } from "lucide-svelte";
import { exportChat, importChat } from "../../ts/characters";
import { findCharacterbyId } from "../../ts/util";
let editMode = false
export let close = () => {}
</script>
<div class="absolute w-full h-full z-40 bg-black bg-opacity-50 flex justify-center items-center">
<div class="bg-darkbg p-4 break-any rounded-md flex flex-col max-w-3xl w-72">
<div class="flex items-center text-neutral-200 mb-4">
<h2 class="mt-0 mb-0">{language.chatList}</h2>
<div class="flex-grow flex justify-end">
<button class="text-gray-500 hover:text-green-500 mr-2 cursor-pointer items-center" on:click={close}>
<XIcon size={24}/>
</button>
</div>
</div>
{#each $DataBase.characters[$selectedCharID].chats as chat, i}
<button on:click={() => {
if(!editMode){
$DataBase.characters[$selectedCharID].chatPage = i
close()
}
}} class="flex items-center text-neutral-200 border-t-1 border-solid border-0 border-gray-600 p-2 cursor-pointer" class:bg-selected={i === $DataBase.characters[$selectedCharID].chatPage}>
{#if editMode}
<input class="text-neutral-200 p-2 bg-transparent input-text focus:bg-selected" bind:value={$DataBase.characters[$selectedCharID].chats[i].name} placeholder="string">
{:else}
<span>{chat.name}</span>
{/if}
<div class="flex-grow flex justify-end">
<button class="text-gray-500 hover:text-green-500 mr-2 cursor-pointer" on:click={async (e) => {
e.stopPropagation()
exportChat(i)
}}>
<DownloadIcon size={18}/>
</button>
<button class="text-gray-500 hover:text-green-500 cursor-pointer" on:click={async (e) => {
e.stopPropagation()
if($DataBase.characters[$selectedCharID].chats.length === 1){
alertError(language.errors.onlyOneChat)
return
}
const d = await alertConfirm(`${language.removeConfirm}${chat.name}`)
if(d){
$DataBase.characters[$selectedCharID].chatPage = 0
let chats = $DataBase.characters[$selectedCharID].chats
chats.splice(i, 1)
$DataBase.characters[$selectedCharID].chats = chats
}
}}>
<TrashIcon size={18}/>
</button>
</div>
</button>
{/each}
<div class="flex mt-2 items-center">
<button class="text-gray-500 hover:text-green-500 cursor-pointer mr-1" on:click={() => {
const cha = $DataBase.characters[$selectedCharID]
const len = $DataBase.characters[$selectedCharID].chats.length
let chats = $DataBase.characters[$selectedCharID].chats
chats.push({
message:[], note:'', name:`New Chat ${len + 1}`, localLore:[]
})
if(cha.type === 'group'){
cha.characters.map((c) => {
chats[len].message.push({
saying: c,
role: 'char',
data: findCharacterbyId(c).firstMessage
})
})
}
$DataBase.characters[$selectedCharID].chats = chats
$DataBase.characters[$selectedCharID].chatPage = len
close()
}}>
<PlusIcon/>
</button>
<button class="text-gray-500 hover:text-green-500 mr-2 cursor-pointer" on:click={() => {
importChat()
}}>
<FolderUpIcon size={18}/>
</button>
<button class="text-gray-500 hover:text-green-500 cursor-pointer" on:click={() => {
editMode = !editMode
}}>
<EditIcon size={18}/>
</button>
</div>
</div>
</div>
<style>
.break-any{
word-break: normal;
overflow-wrap: anywhere;
}
</style>

View File

@@ -0,0 +1,19 @@
<script lang="ts">
import { CheckIcon } from "lucide-svelte";
export let check = false
export let onChange = (check) => {}
</script>
<label class="mr-2">
<input type="checkbox" class="hidden" bind:checked={check} on:change={() => {
onChange(check)
}}>
{#if check}
<div class="w-6 h-6 bg-green-500 flex justify-center items-center text-sm">
<CheckIcon />
</div>
{:else}
<div class="w-6 h-6 bg-selected"></div>
{/if}
</label>

View File

@@ -0,0 +1,52 @@
<script lang="ts">
import { characterFormatUpdate, getCharImage } from "../../ts/characters";
import { DataBase } from "../../ts/database";
import BarIcon from "../SideBars/BarIcon.svelte";
import { User, Users } from "lucide-svelte";
import { selectedCharID } from "../../ts/stores";
export let endGrid = () => {}
let search = ''
function changeChar(index = -1){
characterFormatUpdate(index)
selectedCharID.set(index)
endGrid()
}
</script>
<div class="h-full w-full flex justify-center">
<div class="h-full p-2 bg-darkbg max-w-full w-2xl flex items-center flex-col ">
<h1 class="text-neutral-200 text-2xl font-bold mt-2">Catalog</h1>
<input class="text-neutral-200 mt-2 mb-4 p-2 bg-transparent input-text focus:bg-selected w-4/5 text-xl" placeholder="Search" bind:value={search}>
<div class="w-full flex justify-center">
<div class="flex flex-wrap gap-2 mx-auto container">
{#each $DataBase.characters.filter((c) => {
return c.name.toLocaleLowerCase().includes(search.toLocaleLowerCase())
}) as char, i}
<div class="flex items-center text-neutral-200">
{#if char.image}
<BarIcon onClick={() => {changeChar(i)}} additionalStyle={getCharImage($DataBase.characters[i].image, 'css')}></BarIcon>
{:else}
<BarIcon onClick={() => {changeChar(i)}} additionalStyle={i === $selectedCharID ? 'background:#44475a' : ''}>
{#if char.type === 'group'}
<Users />
{:else}
<User/>
{/if}
</BarIcon>
{/if}
</div>
{/each}
</div>
</div>
</div>
</div>
<style>
@media (max-width: 640px) {
.container {
justify-content: center;
width: fit-content;
}
}
</style>

View File

@@ -0,0 +1,19 @@
<button class="relative help inline-block cursor-default hover:text-green-500" on:click={() => {
alertMd(language.help[key])
}}>
{#if key === "experimental"}
<FlaskConicalIcon size={14} />
{:else}
<HelpCircleIcon size={14} />
{/if}
</button>
<script lang="ts">
import { FlaskConicalIcon, HelpCircleIcon } from "lucide-svelte";
import { language } from "src/lang";
import { alertMd } from "src/ts/alert";
export let key: (keyof (typeof language.help))
</script>

View File

@@ -0,0 +1,191 @@
<script>
import { ArrowBigLeftIcon } from "lucide-svelte";
import { changeLanguage, language } from "src/lang";
import { addDefaultCharacters } from "src/ts/characters";
import { DataBase } from "src/ts/database";
let step = 0
let provider = 0
</script>
<div class="w-full h-full bg-bgcolor flex justify-center">
<article class="max-w-screen-md w-full prose prose-invert bg-darkbg p-5 overflow-y-auto overflow-x-hidden">
<div class="w-full justify-center flex">
<img src="/logo.png" alt="logo">
</div>
<div class="w-full justify-center flex">
<h1>Welcome to RisuAI!</h1>
</div>
{#if step === 0}
<h2>Choose the language</h2>
<div class="flex flex-col items-start ml-2">
<button class="hover:text-green-500 transition-colors" on:click={() => {
changeLanguage('en')
step = 1
}}> English</button>
<button class="hover:text-green-500 transition-colors" on:click={() => {
changeLanguage('ko')
step = 1
}}> 한국어</button>
</div>
{:else if step === 1}
<h2>{language.setup.chooseProvider}</h2>
<div class="flex flex-col items-start ml-2">
<button class="hover:text-green-500 transition-colors" on:click={() => {
provider = 1
step += 1
}}> {language.setup.openaikey}</button>
<button class="hover:text-green-500 transition-colors"on:click={() => {
provider = 2
step += 1
}}> {language.setup.openaiProxy}</button>
<button class="hover:text-green-500 transition-colors" on:click={() => {
provider = 3
step += 1
}}> {language.setup.setupmodelself}</button>
</div>
{:else if step === 2}
{#if provider === 1}
<h2>{language.setup.openaikey}</h2>
<div class="w-full ml-2">
<span>API key</span>
<input class="text-neutral-200 mt-2 p-2 bg-transparent input-text focus:bg-selected m-0" bind:value={$DataBase.openAIKey}>
</div>
<span class="text-gray-400">{language.setup.apiKeyhelp} <a href="https://platform.openai.com/account/api-keys" target="_blank">https://platform.openai.com/account/api-keys</a></span>
<div class="flex flex-col items-start ml-2 mt-6">
<button class="hover:text-green-500 transition-colors" on:click={() => {
provider = 1
step += 1
}}> {language.confirm}</button>
</div>
{:else if provider === 2}
<h2>{language.setup.openaiProxy}</h2>
<div class="w-full ml-2">
<span>OpenAI Reverse Proxy URL</span>
<input class="text-neutral-200 mt-2 p-2 bg-transparent input-text focus:bg-selected m-0" bind:value={$DataBase.forceReplaceUrl} placeholder="https://...">
</div>
<div class="w-full ml-2 mt-4">
<span>API key (Used for passwords)</span>
<input class="text-neutral-200 mt-2 p-2 bg-transparent input-text focus:bg-selected m-0" bind:value={$DataBase.openAIKey} placeholder="Optional">
</div>
<div class="flex flex-col items-start ml-2 mt-6">
<button class="hover:text-green-500 transition-colors" on:click={() => {
provider = 1
step += 1
}}> {language.confirm}</button>
</div>
{:else}
<h2>{language.setup.setupmodelself}</h2>
<div class="w-full ml-2">
<span>{language.setup.setupSelfHelp}</span>
</div>
<div class="flex flex-col items-start ml-2 mt-6">
<button class="hover:text-green-500 transition-colors" on:click={() => {
provider = 1
step += 1
}}> {language.confirm}</button>
</div>
{/if}
{:else if step === 3}
<h2>{language.setup.theme}</h2>
<div class="flex flex-col items-start ml-2">
<button class="hover:text-green-500 transition-colors flex flex-col items-start" on:click={() => {
$DataBase.theme = ''
step += 1
}}><span>• Standard Risu</span>
<img class="w-3/4 mt-2" src="/ss2.webp" alt="example"></button>
<button class="hover:text-green-500 transition-colors flex flex-col items-start" on:click={() => {
$DataBase.theme = 'waifu'
step += 1
}}><span>• Waifulike (Not suitable for mobile)</span>
<img class="w-3/4 mt-2" src="/ss3.webp" alt="example"></button>
</div>
{:else if step === 4}
<h2>{language.setup.theme}</h2>
<div class="flex flex-col items-start ml-2">
<button class="hover:text-green-500 transition-colors flex flex-col items-start" on:click={() => {
$DataBase.theme = ''
step += 1
}}><span>• Standard Risu</span>
<img class="w-3/4 mt-2" src="/ss2.webp" alt="example"></button>
<button class="hover:text-green-500 transition-colors flex flex-col items-start" on:click={() => {
$DataBase.theme = 'waifu'
step += 1
}}><span>• Waifulike</span>
<img class="w-3/4 mt-2" src="/ss3.webp" alt="example"></button>
</div>
{:else if step === 4}
<h2>{language.setup.theme}</h2>
<div class="flex flex-col items-start ml-2">
<button class="hover:text-green-500 transition-colors flex flex-col items-start" on:click={() => {
$DataBase.theme = ''
step += 1
}}><span>• Standard Risu</span>
<img class="w-3/4 mt-2" src="/ss2.webp" alt="example"></button>
<button class="hover:text-green-500 transition-colors flex flex-col items-start" on:click={() => {
$DataBase.theme = 'waifu'
step += 1
}}><span>• Waifulike</span>
<img class="w-3/4 mt-2" src="/ss3.webp" alt="example"></button>
</div>
{:else if step === 5}
<h2>{language.setup.texttheme}</h2>
<div class="flex flex-col items-start ml-2">
<button class="hover:text-green-500 transition-colors flex flex-col items-start" on:click={() => {
$DataBase.theme = ''
step += 1
}}><span>{language.classicRisu}</span>
<div class="border-borderc py-2 px-8 not-prose">
<p class="mt-2 mb-0 classic p-0"> Normal Text</p>
<p class="mt-2 mb-0 classic-italic italic p-0">Italic Text</p>
<p class="mt-2 mb-0 classic font-bold p-0">Bold Text</p>
</div>
</button>
</div>
<div class="flex flex-col items-start ml-2 mt-2 mb-2">
<button class="hover:text-green-500 transition-colors flex flex-col items-start" on:click={() => {
$DataBase.theme = ''
step += 1
}}><span>{language.highcontrast}</span>
<div class="border-borderc p-2 py-2 px-8 not-prose">
<p class="mt-2 mb-0 classic p-0" style="color:#f8f8f2"> Normal Text</p>
<p class="mt-2 mb-0 classic-italic italic p-0" style="color:#F1FA8C">Italic Text</p>
<p class="mt-2 mb-0 classic font-bold p-0" style="color:#FFB86C">Bold Text</p>
</div>
</button>
</div>
{:else if step === 6}
<h2>{language.setup.inputName}</h2>
<div class="w-full ml-2">
<input class="text-neutral-200 mt-2 p-2 bg-transparent input-text focus:bg-selected m-0" bind:value={$DataBase.username}>
</div>
<div class="flex flex-col items-start ml-2 mt-6">
<button class="hover:text-green-500 transition-colors" on:click={async () => {
$DataBase.forceReplaceUrl2 = $DataBase.forceReplaceUrl
await addDefaultCharacters()
$DataBase.didFirstSetup = true
}}> {language.confirm}</button>
</div>
{/if}
{#if step > 0}
<button class="hover:text-green-500 transition-colors ml-2" on:click={() => {
step = step - 1
}}> Go Back</button>
{/if}
</article>
</div>
<style>
.classic{
color: #fafafa;
}
.classic-italic{
color: #8C8D93;
}
</style>

View File

@@ -0,0 +1,83 @@
<script>
import { alertConfirm, alertError } from "../../ts/alert";
import { language } from "../../lang";
import { DataBase, changeToPreset, presetTemplate } from "../../ts/database";
import { EditIcon, PlusIcon, TrashIcon, XIcon } from "lucide-svelte";
let editMode = false
export let close = () => {}
</script>
<div class="absolute w-full h-full z-40 bg-black bg-opacity-50 flex justify-center items-center">
<div class="bg-darkbg p-4 break-any rounded-md flex flex-col max-w-3xl w-96">
<div class="flex items-center text-neutral-200 mb-4">
<h2 class="mt-0 mb-0">{language.presets}</h2>
<div class="flex-grow flex justify-end">
<button class="text-gray-500 hover:text-green-500 mr-2 cursor-pointer items-center" on:click={close}>
<XIcon size={24}/>
</button>
</div>
</div>
{#each $DataBase.botPresets as presets, i}
<button on:click={() => {
if(!editMode){
changeToPreset(i)
close()
}
}} class="flex items-center text-neutral-200 border-t-1 border-solid border-0 border-gray-600 p-2 cursor-pointer" class:bg-selected={i === $DataBase.botPresetsId}>
{#if editMode}
<input class="text-neutral-200 p-2 bg-transparent input-text focus:bg-selected" bind:value={$DataBase.botPresets[i].name} placeholder="string">
{:else}
{#if i < 9}
<span class="w-2 text-center mr-2 text-gray-400">{i + 1}</span>
{/if}
<span>{presets.name}</span>
{/if}
<div class="flex-grow flex justify-end">
<button class="text-gray-500 hover:text-green-500 cursor-pointer" on:click={async (e) => {
e.stopPropagation()
if($DataBase.botPresets.length === 1){
alertError(language.errors.onlyOneChat)
return
}
const d = await alertConfirm(`${language.removeConfirm}${presets.name}`)
if(d){
changeToPreset(0)
let botPresets = $DataBase.botPresets
botPresets.splice(i, 1)
$DataBase.botPresets = botPresets
}
}}>
<TrashIcon size={18}/>
</button>
</div>
</button>
{/each}
<div class="flex mt-2 items-center">
<button class="text-gray-500 hover:text-green-500 cursor-pointer mr-1" on:click={() => {
let botPresets = $DataBase.botPresets
let newPreset = JSON.parse(JSON.stringify(presetTemplate))
newPreset.name = `New Preset`
botPresets.push(newPreset)
$DataBase.botPresets = botPresets
}}>
<PlusIcon/>
</button>
<button class="text-gray-500 hover:text-green-500 cursor-pointer" on:click={() => {
editMode = !editMode
}}>
<EditIcon size={18}/>
</button>
</div>
<span class="text-gray-400 text-sm">{language.quickPreset}</span>
</div>
</div>
<style>
.break-any{
word-break: normal;
overflow-wrap: anywhere;
}
</style>