Merge branch 'main' of https://github.com/kwaroran/RisuAI
This commit is contained in:
60
pnpm-lock.yaml
generated
60
pnpm-lock.yaml
generated
@@ -71,6 +71,9 @@ dependencies:
|
|||||||
isomorphic-dompurify:
|
isomorphic-dompurify:
|
||||||
specifier: ^1.8.0
|
specifier: ^1.8.0
|
||||||
version: 1.8.0
|
version: 1.8.0
|
||||||
|
jszip:
|
||||||
|
specifier: ^3.10.1
|
||||||
|
version: 3.10.1
|
||||||
libsodium-wrappers-sumo:
|
libsodium-wrappers-sumo:
|
||||||
specifier: ^0.7.11
|
specifier: ^0.7.11
|
||||||
version: 0.7.11
|
version: 0.7.11
|
||||||
@@ -1537,6 +1540,10 @@ packages:
|
|||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/core-util-is@1.0.3:
|
||||||
|
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/cors@2.8.5:
|
/cors@2.8.5:
|
||||||
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
|
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
|
||||||
engines: {node: '>= 0.10'}
|
engines: {node: '>= 0.10'}
|
||||||
@@ -2238,6 +2245,10 @@ packages:
|
|||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/isarray@1.0.0:
|
||||||
|
resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/isexe@2.0.0:
|
/isexe@2.0.0:
|
||||||
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
||||||
dev: true
|
dev: true
|
||||||
@@ -2298,6 +2309,15 @@ packages:
|
|||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/jszip@3.10.1:
|
||||||
|
resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==}
|
||||||
|
dependencies:
|
||||||
|
lie: 3.3.0
|
||||||
|
pako: 1.0.11
|
||||||
|
readable-stream: 2.3.8
|
||||||
|
setimmediate: 1.0.5
|
||||||
|
dev: false
|
||||||
|
|
||||||
/kleur@4.1.5:
|
/kleur@4.1.5:
|
||||||
resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
|
resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -2319,6 +2339,12 @@ packages:
|
|||||||
immediate: 3.0.6
|
immediate: 3.0.6
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/lie@3.3.0:
|
||||||
|
resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==}
|
||||||
|
dependencies:
|
||||||
|
immediate: 3.0.6
|
||||||
|
dev: false
|
||||||
|
|
||||||
/lil-gui@0.17.0:
|
/lil-gui@0.17.0:
|
||||||
resolution: {integrity: sha512-MVBHmgY+uEbmJNApAaPbtvNh1RCAeMnKym82SBjtp5rODTYKWtM+MXHCifLe2H2Ti1HuBGBtK/5SyG4ShQ3pUQ==}
|
resolution: {integrity: sha512-MVBHmgY+uEbmJNApAaPbtvNh1RCAeMnKym82SBjtp5rODTYKWtM+MXHCifLe2H2Ti1HuBGBtK/5SyG4ShQ3pUQ==}
|
||||||
dev: true
|
dev: true
|
||||||
@@ -2730,6 +2756,10 @@ packages:
|
|||||||
p-finally: 1.0.0
|
p-finally: 1.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/pako@1.0.11:
|
||||||
|
resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/parent-module@1.0.1:
|
/parent-module@1.0.1:
|
||||||
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
|
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -2931,6 +2961,10 @@ packages:
|
|||||||
tunnel-agent: 0.6.0
|
tunnel-agent: 0.6.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/process-nextick-args@2.0.1:
|
||||||
|
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/protobufjs@6.11.3:
|
/protobufjs@6.11.3:
|
||||||
resolution: {integrity: sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==}
|
resolution: {integrity: sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -3035,6 +3069,18 @@ packages:
|
|||||||
pify: 2.3.0
|
pify: 2.3.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/readable-stream@2.3.8:
|
||||||
|
resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
|
||||||
|
dependencies:
|
||||||
|
core-util-is: 1.0.3
|
||||||
|
inherits: 2.0.4
|
||||||
|
isarray: 1.0.0
|
||||||
|
process-nextick-args: 2.0.1
|
||||||
|
safe-buffer: 5.1.2
|
||||||
|
string_decoder: 1.1.1
|
||||||
|
util-deprecate: 1.0.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/readable-stream@3.6.2:
|
/readable-stream@3.6.2:
|
||||||
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
|
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
@@ -3105,6 +3151,10 @@ packages:
|
|||||||
mri: 1.2.0
|
mri: 1.2.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/safe-buffer@5.1.2:
|
||||||
|
resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/safe-buffer@5.2.1:
|
/safe-buffer@5.2.1:
|
||||||
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||||
dev: false
|
dev: false
|
||||||
@@ -3174,6 +3224,10 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/setimmediate@1.0.5:
|
||||||
|
resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/setprototypeof@1.2.0:
|
/setprototypeof@1.2.0:
|
||||||
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
||||||
dev: false
|
dev: false
|
||||||
@@ -3276,6 +3330,12 @@ packages:
|
|||||||
queue-tick: 1.0.1
|
queue-tick: 1.0.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/string_decoder@1.1.1:
|
||||||
|
resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
|
||||||
|
dependencies:
|
||||||
|
safe-buffer: 5.1.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/string_decoder@1.3.0:
|
/string_decoder@1.3.0:
|
||||||
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
|
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
},
|
},
|
||||||
"package": {
|
"package": {
|
||||||
"productName": "RisuAI",
|
"productName": "RisuAI",
|
||||||
"version": "1.59.9"
|
"version": "1.60.1"
|
||||||
},
|
},
|
||||||
"tauri": {
|
"tauri": {
|
||||||
"allowlist": {
|
"allowlist": {
|
||||||
|
|||||||
@@ -453,4 +453,8 @@ export const languageEnglish = {
|
|||||||
joinMultiUserRoom: "Join MultiUser Room",
|
joinMultiUserRoom: "Join MultiUser Room",
|
||||||
exactTokens: "Exact Tokens",
|
exactTokens: "Exact Tokens",
|
||||||
fixedTokens: "Approximate Tokens",
|
fixedTokens: "Approximate Tokens",
|
||||||
|
inlayViewScreen: "Inlay Screen",
|
||||||
|
imgGenPrompt: "Image Generation Prompt",
|
||||||
|
imgGenNegatives: "Image Generation Negative Prompt",
|
||||||
|
imgGenInstructions: "Image Generation Instructions",
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ArrowLeft, ArrowRight, EditIcon, LanguagesIcon, RefreshCcwIcon, TrashIcon, CopyIcon } from "lucide-svelte";
|
import { ArrowLeft, ArrowRight, PencilIcon, LanguagesIcon, RefreshCcwIcon, TrashIcon, CopyIcon } from "lucide-svelte";
|
||||||
import { ParseMarkdown, type simpleCharacterArgument } from "../../ts/parser";
|
import { ParseMarkdown, type simpleCharacterArgument } from "../../ts/parser";
|
||||||
import AutoresizeArea from "../UI/GUI/TextAreaResizable.svelte";
|
import AutoresizeArea from "../UI/GUI/TextAreaResizable.svelte";
|
||||||
import { alertConfirm, alertError } from "../../ts/alert";
|
import { alertConfirm, alertError } from "../../ts/alert";
|
||||||
@@ -154,7 +154,7 @@
|
|||||||
edit()
|
edit()
|
||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
<EditIcon size={20}/>
|
<PencilIcon size={20}/>
|
||||||
</button>
|
</button>
|
||||||
<button class="ml-2 hover:text-green-500 transition-colors" on:click={rm}>
|
<button class="ml-2 hover:text-green-500 transition-colors" on:click={rm}>
|
||||||
<TrashIcon size={20}/>
|
<TrashIcon size={20}/>
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
<BackgroundDom />
|
<BackgroundDom />
|
||||||
<div style={bgImg} class="h-full w-full" class:max-w-6xl={$DataBase.classicMaxWidth}>
|
<div style={bgImg} class="h-full w-full" class:max-w-6xl={$DataBase.classicMaxWidth}>
|
||||||
{#if $selectedCharID >= 0}
|
{#if $selectedCharID >= 0}
|
||||||
{#if $CurrentCharacter.viewScreen !== 'none'}
|
{#if $CurrentCharacter.viewScreen !== 'none' && ($CurrentCharacter.type === 'group' || (!$CurrentCharacter.inlayViewScreen))}
|
||||||
<ResizeBox />
|
<ResizeBox />
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -4,31 +4,32 @@
|
|||||||
import Help from "src/lib/Others/Help.svelte";
|
import Help from "src/lib/Others/Help.svelte";
|
||||||
import { selectSingleFile } from "src/ts/util";
|
import { selectSingleFile } from "src/ts/util";
|
||||||
import { DataBase } from "src/ts/storage/database";
|
import { DataBase } from "src/ts/storage/database";
|
||||||
import { isTauri } from "src/ts/storage/globalApi";
|
import { isTauri, saveAsset } from "src/ts/storage/globalApi";
|
||||||
import NumberInput from "src/lib/UI/GUI/NumberInput.svelte";
|
import NumberInput from "src/lib/UI/GUI/NumberInput.svelte";
|
||||||
import TextInput from "src/lib/UI/GUI/TextInput.svelte";
|
import TextInput from "src/lib/UI/GUI/TextInput.svelte";
|
||||||
import SelectInput from "src/lib/UI/GUI/SelectInput.svelte";
|
import SelectInput from "src/lib/UI/GUI/SelectInput.svelte";
|
||||||
import OptionInput from "src/lib/UI/GUI/OptionInput.svelte";
|
import OptionInput from "src/lib/UI/GUI/OptionInput.svelte";
|
||||||
import SliderInput from "src/lib/UI/GUI/SliderInput.svelte";
|
import SliderInput from "src/lib/UI/GUI/SliderInput.svelte";
|
||||||
import Button from "src/lib/UI/GUI/Button.svelte";
|
import Button from "src/lib/UI/GUI/Button.svelte";
|
||||||
import { convertToBase64 } from "src/ts/process/uinttobase64";
|
import { getCharImage } from "src/ts/characters";
|
||||||
|
import Arcodion from "src/lib/UI/Arcodion.svelte";
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<h2 class="mb-2 text-2xl font-bold mt-2">{language.otherBots}</h2>
|
<h2 class="mb-2 text-2xl font-bold mt-2">{language.otherBots}</h2>
|
||||||
|
|
||||||
<span class="text-textcolor mt-4 text-lg font-bold">{language.imageGeneration}</span>
|
|
||||||
|
|
||||||
<span class="text-textcolor mt-2">{language.imageGeneration} {language.provider} <Help key="sdProvider"/></span>
|
<Arcodion name={language.imageGeneration} styled>
|
||||||
<SelectInput className="mt-2 mb-4" bind:value={$DataBase.sdProvider}>
|
<span class="text-textcolor mt-2">{language.imageGeneration} {language.provider} <Help key="sdProvider"/></span>
|
||||||
|
<SelectInput className="mt-2 mb-4" bind:value={$DataBase.sdProvider}>
|
||||||
<OptionInput value="" >None</OptionInput>
|
<OptionInput value="" >None</OptionInput>
|
||||||
<OptionInput value="webui" >Stable Diffusion WebUI</OptionInput>
|
<OptionInput value="webui" >Stable Diffusion WebUI</OptionInput>
|
||||||
<OptionInput value="novelai" >Novel AI</OptionInput>
|
<OptionInput value="novelai" >Novel AI</OptionInput>
|
||||||
<!-- TODO -->
|
<!-- TODO -->
|
||||||
<!-- <OptionInput value="runpod" >Runpod Serverless</OptionInput> -->
|
<!-- <OptionInput value="runpod" >Runpod Serverless</OptionInput> -->
|
||||||
</SelectInput>
|
</SelectInput>
|
||||||
|
|
||||||
{#if $DataBase.sdProvider === 'webui'}
|
{#if $DataBase.sdProvider === 'webui'}
|
||||||
<span class="text-draculared text-xs mb-2">You must use WebUI with --api flag</span>
|
<span class="text-draculared text-xs mb-2">You must use WebUI with --api flag</span>
|
||||||
<span class="text-draculared text-xs mb-2">You must use WebUI without agpl license or use unmodified version with agpl license to observe the contents of the agpl license.</span>
|
<span class="text-draculared text-xs mb-2">You must use WebUI without agpl license or use unmodified version with agpl license to observe the contents of the agpl license.</span>
|
||||||
{#if !isTauri}
|
{#if !isTauri}
|
||||||
<span class="text-draculared text-xs mb-2">You are using web version. you must use ngrok or other tunnels to use your local webui.</span>
|
<span class="text-draculared text-xs mb-2">You are using web version. you must use ngrok or other tunnels to use your local webui.</span>
|
||||||
@@ -59,9 +60,9 @@
|
|||||||
<span class="text-textcolor">Upscaler</span>
|
<span class="text-textcolor">Upscaler</span>
|
||||||
<TextInput size="sm" marginBottom bind:value={$DataBase.sdConfig.hr_upscaler}/>
|
<TextInput size="sm" marginBottom bind:value={$DataBase.sdConfig.hr_upscaler}/>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if $DataBase.sdProvider === 'novelai'}
|
{#if $DataBase.sdProvider === 'novelai'}
|
||||||
<span class="text-textcolor mt-2">Novel AI {language.providerURL}</span>
|
<span class="text-textcolor mt-2">Novel AI {language.providerURL}</span>
|
||||||
<TextInput size="sm" marginBottom placeholder="https://api.novelai.net" bind:value={$DataBase.NAIImgUrl}/>
|
<TextInput size="sm" marginBottom placeholder="https://api.novelai.net" bind:value={$DataBase.NAIImgUrl}/>
|
||||||
<span class="text-textcolor">API Key</span>
|
<span class="text-textcolor">API Key</span>
|
||||||
@@ -70,38 +71,6 @@
|
|||||||
<span class="text-textcolor">Model</span>
|
<span class="text-textcolor">Model</span>
|
||||||
<TextInput size="sm" marginBottom placeholder="nai-diffusion-3" bind:value={$DataBase.NAIImgModel}/>
|
<TextInput size="sm" marginBottom placeholder="nai-diffusion-3" bind:value={$DataBase.NAIImgModel}/>
|
||||||
|
|
||||||
<span class="text-textcolor">Enable I2I</span>
|
|
||||||
<Check bind:check={$DataBase.NAII2I}/>
|
|
||||||
|
|
||||||
|
|
||||||
{#if $DataBase.NAII2I}
|
|
||||||
|
|
||||||
<span class="text-textcolor">strength</span>
|
|
||||||
<SliderInput min={0} max={0.99} step={0.01} bind:value={$DataBase.NAIImgConfig.strength}/>
|
|
||||||
<span class="text-textcolor2 mb-6 text-sm">{$DataBase.NAIImgConfig.strength}</span>
|
|
||||||
<span class="text-textcolor">noise</span>
|
|
||||||
<SliderInput min={0} max={0.99} step={0.01} bind:value={$DataBase.NAIImgConfig.noise}/>
|
|
||||||
<span class="text-textcolor2 mb-6 text-sm">{$DataBase.NAIImgConfig.noise}</span>
|
|
||||||
|
|
||||||
<span class="text-textcolor">base image</span>
|
|
||||||
<TextInput size="sm" marginBottom placeholder="If empty, a profile picture is sent." bind:value={$DataBase.NAIImgConfig.image}/>
|
|
||||||
<span class="text-textcolor">If empty, a profile picture is sent.</span>
|
|
||||||
|
|
||||||
<Button on:click={async () => {
|
|
||||||
const img = await selectSingleFile([
|
|
||||||
'jpg',
|
|
||||||
'jpeg',
|
|
||||||
'png',
|
|
||||||
'webp'
|
|
||||||
])
|
|
||||||
if(!img){
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
const base64 = await convertToBase64(img.data)
|
|
||||||
$DataBase.NAIImgConfig.image = base64
|
|
||||||
}}>Select Image</Button>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<span class="text-textcolor">Width</span>
|
<span class="text-textcolor">Width</span>
|
||||||
<NumberInput size="sm" marginBottom min={0} max={2048} bind:value={$DataBase.NAIImgConfig.width}/>
|
<NumberInput size="sm" marginBottom min={0} max={2048} bind:value={$DataBase.NAIImgConfig.width}/>
|
||||||
<span class="text-textcolor">Height</span>
|
<span class="text-textcolor">Height</span>
|
||||||
@@ -114,58 +83,99 @@
|
|||||||
<NumberInput size="sm" marginBottom min={0} max={2048} bind:value={$DataBase.NAIImgConfig.scale}/>
|
<NumberInput size="sm" marginBottom min={0} max={2048} bind:value={$DataBase.NAIImgConfig.scale}/>
|
||||||
|
|
||||||
{#if !$DataBase.NAII2I}
|
{#if !$DataBase.NAII2I}
|
||||||
<span class="text-textcolor">Use SMEA</span>
|
<Check bind:check={$DataBase.NAIImgConfig.sm} name="Use SMEA"/>
|
||||||
<Check bind:check={$DataBase.NAIImgConfig.sm}/>
|
<Check bind:check={$DataBase.NAIImgConfig.sm_dyn} name='Use DYN'/>
|
||||||
<span class="text-textcolor">Use DYN</span>
|
|
||||||
<Check bind:check={$DataBase.NAIImgConfig.sm_dyn}/>
|
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
<Check bind:check={$DataBase.NAII2I} name="Enable I2I"/>
|
||||||
|
|
||||||
<span class="text-textcolor mt-4 text-lg font-bold">TTS</span>
|
{#if $DataBase.NAII2I}
|
||||||
<span class="text-textcolor mt-2">ElevenLabs API key</span>
|
|
||||||
<TextInput size="sm" marginBottom bind:value={$DataBase.elevenLabKey}/>
|
|
||||||
|
|
||||||
<span class="text-textcolor mt-2">VOICEVOX URL</span>
|
<span class="text-textcolor mt-4">strength</span>
|
||||||
<TextInput size="sm" marginBottom bind:value={$DataBase.voicevoxUrl}/>
|
<SliderInput min={0} max={0.99} step={0.01} bind:value={$DataBase.NAIImgConfig.strength}/>
|
||||||
|
<span class="text-textcolor2 mb-6 text-sm">{$DataBase.NAIImgConfig.strength}</span>
|
||||||
|
<span class="text-textcolor">noise</span>
|
||||||
|
<SliderInput min={0} max={0.99} step={0.01} bind:value={$DataBase.NAIImgConfig.noise}/>
|
||||||
|
<span class="text-textcolor2 mb-6 text-sm">{$DataBase.NAIImgConfig.noise}</span>
|
||||||
|
|
||||||
<span class="text-textcolor mt-2">NovelAI API key</span>
|
<span class="text-textcolor">Base image</span>
|
||||||
<TextInput size="sm" marginBottom placeholder="pst-..." bind:value={$DataBase.NAIApiKey}/>
|
<button on:click={async () => {
|
||||||
|
const img = await selectSingleFile([
|
||||||
|
'jpg',
|
||||||
|
'jpeg',
|
||||||
|
'png',
|
||||||
|
'webp'
|
||||||
|
])
|
||||||
|
if(!img){
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const saveId = await saveAsset(img.data)
|
||||||
|
$DataBase.NAIImgConfig.image = saveId
|
||||||
|
}}>
|
||||||
|
{#if $DataBase.NAIImgConfig.image === ''}
|
||||||
|
<div class="rounded-md h-20 w-20 shadow-lg bg-textcolor2 cursor-pointer hover:text-green-500"/>
|
||||||
|
{:else}
|
||||||
|
{#await getCharImage($DataBase.NAIImgConfig.image, 'css')}
|
||||||
|
<div class="rounded-md h-20 w-20 shadow-lg bg-textcolor2 cursor-pointer hover:text-green-500"/>
|
||||||
|
{:then im}
|
||||||
|
<div class="rounded-md h-20 w-20 shadow-lg bg-textcolor2 cursor-pointer hover:text-green-500" style={im} />
|
||||||
|
{/await}
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
|
||||||
<span class="text-textcolor mt-4 text-lg font-bold">{language.emotionImage}</span>
|
{/if}
|
||||||
|
{/if}
|
||||||
|
</Arcodion>
|
||||||
|
|
||||||
<span class="text-textcolor mt-2">{language.emotionMethod}</span>
|
<Arcodion name="TTS" styled>
|
||||||
<SelectInput className="mt-2 mb-4" bind:value={$DataBase.emotionProcesser}>
|
<span class="text-textcolor mt-2">ElevenLabs API key</span>
|
||||||
|
<TextInput size="sm" marginBottom bind:value={$DataBase.elevenLabKey}/>
|
||||||
|
|
||||||
|
<span class="text-textcolor mt-2">VOICEVOX URL</span>
|
||||||
|
<TextInput size="sm" marginBottom bind:value={$DataBase.voicevoxUrl}/>
|
||||||
|
|
||||||
|
<span class="text-textcolor mt-2">NovelAI API key</span>
|
||||||
|
<TextInput size="sm" marginBottom placeholder="pst-..." bind:value={$DataBase.NAIApiKey}/>
|
||||||
|
|
||||||
|
|
||||||
|
</Arcodion>
|
||||||
|
|
||||||
|
<Arcodion name={language.emotionImage} styled>
|
||||||
|
<span class="text-textcolor mt-2">{language.emotionMethod}</span>
|
||||||
|
|
||||||
|
<SelectInput className="mt-2 mb-4" bind:value={$DataBase.emotionProcesser}>
|
||||||
<OptionInput value="submodel" >Ax. Model</OptionInput>
|
<OptionInput value="submodel" >Ax. Model</OptionInput>
|
||||||
<OptionInput value="embedding" >MiniLM-L6-v2</OptionInput>
|
<OptionInput value="embedding" >MiniLM-L6-v2</OptionInput>
|
||||||
</SelectInput>
|
</SelectInput>
|
||||||
|
</Arcodion>
|
||||||
|
|
||||||
<span class="text-textcolor mt-4 text-lg font-bold">{language.SuperMemory} <Help key="superMemory" /></span>
|
<Arcodion name="superMemory" styled>
|
||||||
<span class="text-textcolor mt-4">{language.SuperMemory} {language.model}</span>
|
<span class="text-textcolor mt-4">{language.SuperMemory} {language.model}</span>
|
||||||
<SelectInput className="mt-2 mb-2" bind:value={$DataBase.supaMemoryType}>
|
<SelectInput className="mt-2 mb-2" bind:value={$DataBase.supaMemoryType}>
|
||||||
<OptionInput value="none" >None</OptionInput>
|
<OptionInput value="none" >None</OptionInput>
|
||||||
<OptionInput value="distilbart" >distilbart-cnn-6-6 (Free/Local)</OptionInput>
|
<OptionInput value="distilbart" >distilbart-cnn-6-6 (Free/Local)</OptionInput>
|
||||||
<OptionInput value="instruct35" >OpenAI 3.5 Turbo Instruct</OptionInput>
|
<OptionInput value="instruct35" >OpenAI 3.5 Turbo Instruct</OptionInput>
|
||||||
<OptionInput value="davinci" >OpenAI Davinci</OptionInput>
|
<OptionInput value="davinci" >OpenAI Davinci</OptionInput>
|
||||||
<OptionInput value="curie" >OpenAI Curie</OptionInput>
|
<OptionInput value="curie" >OpenAI Curie</OptionInput>
|
||||||
<OptionInput value="subModel" >{language.submodel} ({language.unrecommended})</OptionInput>
|
<OptionInput value="subModel" >{language.submodel} ({language.unrecommended})</OptionInput>
|
||||||
</SelectInput>
|
</SelectInput>
|
||||||
{#if $DataBase.supaMemoryType === 'davinci' || $DataBase.supaMemoryType === 'curie' || $DataBase.supaMemoryType === 'instruct35'}
|
{#if $DataBase.supaMemoryType === 'davinci' || $DataBase.supaMemoryType === 'curie' || $DataBase.supaMemoryType === 'instruct35'}
|
||||||
<span class="text-textcolor">{language.SuperMemory} OpenAI Key</span>
|
<span class="text-textcolor">{language.SuperMemory} OpenAI Key</span>
|
||||||
<TextInput size="sm" marginBottom bind:value={$DataBase.supaMemoryKey}/>
|
<TextInput size="sm" marginBottom bind:value={$DataBase.supaMemoryKey}/>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $DataBase.supaMemoryType !== 'none'}
|
{#if $DataBase.supaMemoryType !== 'none'}
|
||||||
<span class="text-textcolor">{language.SuperMemory} Prompt</span>
|
<span class="text-textcolor">{language.SuperMemory} Prompt</span>
|
||||||
<TextInput size="sm" marginBottom bind:value={$DataBase.supaMemoryPrompt} placeholder="recommended to leave it blank to use default"/>
|
<TextInput size="sm" marginBottom bind:value={$DataBase.supaMemoryPrompt} placeholder="recommended to leave it blank to use default"/>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $DataBase.hypaMemory}
|
{#if $DataBase.hypaMemory}
|
||||||
<span class="text-textcolor">{language.HypaMemory} Model</span>
|
<span class="text-textcolor">{language.HypaMemory} Model</span>
|
||||||
<SelectInput className="mt-2 mb-2" bind:value={$DataBase.hypaModel}>
|
<SelectInput className="mt-2 mb-2" bind:value={$DataBase.hypaModel}>
|
||||||
<OptionInput value="MiniLM" >MiniLM-L6-v2 (Free / Local)</OptionInput>
|
<OptionInput value="MiniLM" >MiniLM-L6-v2 (Free / Local)</OptionInput>
|
||||||
<OptionInput value="ada" >OpenAI Ada (Davinci / Curie Only)</OptionInput>
|
<OptionInput value="ada" >OpenAI Ada (Davinci / Curie Only)</OptionInput>
|
||||||
</SelectInput>
|
</SelectInput>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $DataBase.useExperimental}
|
{#if $DataBase.useExperimental}
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<Check bind:check={$DataBase.hypaMemory} name={language.able + ' ' + language.HypaMemory}/> <Help key="experimental" />
|
<Check bind:check={$DataBase.hypaMemory} name={language.able + ' ' + language.HypaMemory}/> <Help key="experimental" />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
</Arcodion>
|
||||||
@@ -27,6 +27,8 @@
|
|||||||
import OptionInput from "../UI/GUI/OptionInput.svelte";
|
import OptionInput from "../UI/GUI/OptionInput.svelte";
|
||||||
import RegexList from "./Scripts/RegexList.svelte";
|
import RegexList from "./Scripts/RegexList.svelte";
|
||||||
import TriggerList from "./Scripts/TriggerList.svelte";
|
import TriggerList from "./Scripts/TriggerList.svelte";
|
||||||
|
import CheckInput from "../UI/GUI/CheckInput.svelte";
|
||||||
|
import { updateInlayScreen } from "src/ts/process/inlayScreen";
|
||||||
|
|
||||||
|
|
||||||
let subMenu = 0
|
let subMenu = 0
|
||||||
@@ -319,7 +321,11 @@
|
|||||||
<!-- svelte-ignore empty-block -->
|
<!-- svelte-ignore empty-block -->
|
||||||
|
|
||||||
{#if currentChar.type !== 'group'}
|
{#if currentChar.type !== 'group'}
|
||||||
<SelectInput className="mb-2" bind:value={currentChar.data.viewScreen}>
|
<SelectInput className="mb-2" bind:value={currentChar.data.viewScreen} on:change={() => {
|
||||||
|
if(currentChar.type === 'character'){
|
||||||
|
currentChar.data = updateInlayScreen(currentChar.data)
|
||||||
|
}
|
||||||
|
}}>
|
||||||
<OptionInput value="none">{language.none}</OptionInput>
|
<OptionInput value="none">{language.none}</OptionInput>
|
||||||
<OptionInput value="emotion">{language.emotionImage}</OptionInput>
|
<OptionInput value="emotion">{language.emotionImage}</OptionInput>
|
||||||
<OptionInput value="imggen">{language.imageGeneration}</OptionInput>
|
<OptionInput value="imggen">{language.imageGeneration}</OptionInput>
|
||||||
@@ -383,73 +389,34 @@
|
|||||||
<span>Loading...</span>
|
<span>Loading...</span>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{#if currentChar.data.inlayViewScreen}
|
||||||
|
<span class="text-textcolor mt-2">{language.imgGenInstructions}</span>
|
||||||
|
<TextAreaInput bind:value={currentChar.data.newGenData.emotionInstructions} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<CheckInput bind:check={currentChar.data.inlayViewScreen} name={language.inlayViewScreen} onChange={() => {
|
||||||
|
if(currentChar.type === 'character'){
|
||||||
|
currentChar.data = updateInlayScreen(currentChar.data)
|
||||||
|
}
|
||||||
|
}}/>
|
||||||
{/if}
|
{/if}
|
||||||
{#if currentChar.data.viewScreen === 'imggen'}
|
{#if currentChar.data.viewScreen === 'imggen'}
|
||||||
<span class="text-textcolor mt-6">{language.imageGeneration} <Help key="imggen"/></span>
|
<span class="text-textcolor mt-6">{language.imageGeneration} <Help key="imggen"/></span>
|
||||||
<span class="text-textcolor2 text-xs">{language.emotionWarn}</span>
|
<span class="text-textcolor2 text-xs">{language.emotionWarn}</span>
|
||||||
|
|
||||||
<div class="w-full max-w-full border border-selected rounded-md p-2">
|
<span class="text-textcolor mt-2">{language.imgGenPrompt}</span>
|
||||||
<table class="w-full max-w-full tabler">
|
<TextAreaInput bind:value={currentChar.data.newGenData.prompt} />
|
||||||
<tr>
|
<span class="text-textcolor mt-2">{language.imgGenNegatives}</span>
|
||||||
<th class="font-medium w-1/3">{language.key}</th>
|
<TextAreaInput bind:value={currentChar.data.newGenData.negative} />
|
||||||
<th class="font-medium w-1/2">{language.value}</th>
|
<span class="text-textcolor mt-2">{language.imgGenInstructions}</span>
|
||||||
<th class="font-medium"></th>
|
<TextAreaInput bind:value={currentChar.data.newGenData.instructions} />
|
||||||
</tr>
|
|
||||||
{#if currentChar.data.sdData.length === 0}
|
<CheckInput bind:check={currentChar.data.inlayViewScreen} name={language.inlayViewScreen} onChange={() => {
|
||||||
<tr>
|
if(currentChar.type === 'character'){
|
||||||
<div class="text-textcolor2">{language.noData}</div>
|
currentChar.data = updateInlayScreen(currentChar.data)
|
||||||
</tr>
|
|
||||||
{/if}
|
|
||||||
{#each currentChar.data.sdData as emo, i}
|
|
||||||
<tr>
|
|
||||||
<td class="font-medium truncate w-1/3">
|
|
||||||
<TextInput size="sm" marginBottom bind:value={currentChar.data.sdData[i][0]} />
|
|
||||||
</td>
|
|
||||||
<td class="font-medium truncate w-1/2">
|
|
||||||
<TextInput size="sm" marginBottom bind:value={currentChar.data.sdData[i][1]} />
|
|
||||||
</td>
|
|
||||||
{#if (!['always','negative'].includes(currentChar.data.sdData[i][0]))}
|
|
||||||
<button class="font-medium flex justify-center items-center h-full cursor-pointer hover:text-green-500" on:click={() => {
|
|
||||||
let db = ($DataBase)
|
|
||||||
let charId = $selectedCharID
|
|
||||||
let dbChar = db.characters[charId]
|
|
||||||
if(dbChar.type !== 'group'){
|
|
||||||
dbChar.sdData.splice(i, 1)
|
|
||||||
db.characters[charId] = dbChar
|
|
||||||
}
|
}
|
||||||
$DataBase = (db)
|
}}/>
|
||||||
}}><TrashIcon /></button>
|
|
||||||
{:else}
|
|
||||||
<td></td>
|
|
||||||
{/if}
|
|
||||||
</tr>
|
|
||||||
{/each}
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="text-textcolor2 hover:text-textcolor mt-2 flex">
|
|
||||||
{#if !$addingEmotion}
|
|
||||||
<button class="cursor-pointer hover:text-green-500" on:click={() => {
|
|
||||||
let db = ($DataBase)
|
|
||||||
let charId = $selectedCharID
|
|
||||||
let dbChar = db.characters[charId]
|
|
||||||
if(dbChar.type !== 'group'){
|
|
||||||
dbChar.sdData.push(['', ''])
|
|
||||||
db.characters[charId] = dbChar
|
|
||||||
}
|
|
||||||
$DataBase = (db)
|
|
||||||
}}>
|
|
||||||
<PlusIcon />
|
|
||||||
</button>
|
|
||||||
{:else}
|
|
||||||
<span>Loading...</span>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
<span class="text-textcolor mt-6">{language.currentImageGeneration}</span>
|
|
||||||
{#if currentChar.data.chats[currentChar.data.chatPage].sdData}
|
|
||||||
<TextAreaInput margin="both" autocomplete="off" bind:value={currentChar.data.chats[currentChar.data.chatPage].sdData}></TextAreaInput>
|
|
||||||
{:else}
|
|
||||||
<span><div class="text-textcolor2">{language.noData}</div></span>
|
|
||||||
{/if}
|
|
||||||
{/if}
|
{/if}
|
||||||
{:else if subMenu === 3}
|
{:else if subMenu === 3}
|
||||||
<h2 class="mb-2 text-2xl font-bold mt-2">{language.loreBook} <Help key="lorebook"/></h2>
|
<h2 class="mb-2 text-2xl font-bold mt-2">{language.loreBook} <Help key="lorebook"/></h2>
|
||||||
|
|||||||
@@ -1,9 +1,26 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export let name = ""
|
export let name = ""
|
||||||
let open = false
|
let open = false
|
||||||
|
export let styled = false
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex flex-col">
|
{#if styled}
|
||||||
|
<div class="flex flex-col mt-2">
|
||||||
|
<button class="hover:bg-selected px-6 py-2 text-lg rounded-t-md border-selected border"
|
||||||
|
class:bg-selected={open}
|
||||||
|
class:rounded-b-md={!open}
|
||||||
|
on:click={() => {
|
||||||
|
open = !open
|
||||||
|
}}
|
||||||
|
>{name}</button>
|
||||||
|
{#if open}
|
||||||
|
<div class="flex flex-col border border-selected p-2 rounded-b-md">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<div class="flex flex-col">
|
||||||
<button class="hover:bg-selected px-6 py-2 text-lg" class:bg-selected={open} on:click={() => {
|
<button class="hover:bg-selected px-6 py-2 text-lg" class:bg-selected={open} on:click={() => {
|
||||||
open = !open
|
open = !open
|
||||||
}}>{name}</button>
|
}}>{name}</button>
|
||||||
@@ -12,4 +29,5 @@
|
|||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
@@ -1,10 +1,50 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { getFileSrc } from "src/ts/storage/globalApi";
|
||||||
import { CurrentCharacter } from "src/ts/stores";
|
import { CurrentCharacter } from "src/ts/stores";
|
||||||
|
import { sleep } from "src/ts/util";
|
||||||
|
import { onDestroy, onMount } from "svelte";
|
||||||
|
|
||||||
|
const style:number = 1
|
||||||
|
export let text:string = "Hello World, this is a test, so I can see if this works. I hope it does, because I don't want to have to rewrite this. I hope this is long enough to test the text wrapping. Lonnnnnng String "
|
||||||
|
let renderedText = ''
|
||||||
|
let alive = true
|
||||||
|
|
||||||
|
export const forceRender = () => {
|
||||||
|
renderedText = text
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
while(alive){
|
||||||
|
if(renderedText.length >= text.length){
|
||||||
|
if(renderedText !== text){
|
||||||
|
renderedText = ''
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
renderedText = text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(renderedText.length < text.length){
|
||||||
|
renderedText += text[renderedText.length]
|
||||||
|
}
|
||||||
|
await sleep(10)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
renderedText = ''
|
||||||
|
alive = false
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="w-full flex justify-center absolute bottom-5">
|
{#if $CurrentCharacter.type === 'character' && $CurrentCharacter.emotionImages[0]}
|
||||||
|
{#await getFileSrc($CurrentCharacter.emotionImages[0][1]) then imglink}
|
||||||
|
<div class="w-full absolute top-0 h-full bottom-0 justify-center flex">
|
||||||
|
<img src={imglink} alt="character">
|
||||||
|
</div>
|
||||||
|
{/await}
|
||||||
|
{/if}
|
||||||
|
{#if style === 0}
|
||||||
|
<div class="w-full flex justify-center absolute bottom-5">
|
||||||
<div class="w-3xl max-w-full flex flex-col">
|
<div class="w-3xl max-w-full flex flex-col">
|
||||||
|
|
||||||
<div class="bg-slate-700 h-12 rounded-lg border-slate-500 border-1 w-40 mb-2 bg-opacity-90 text-center flex items-center justify-center">
|
<div class="bg-slate-700 h-12 rounded-lg border-slate-500 border-1 w-40 mb-2 bg-opacity-90 text-center flex items-center justify-center">
|
||||||
@@ -14,4 +54,25 @@
|
|||||||
Test
|
Test
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{:else}
|
||||||
|
<div class="w-full flex justify-center absolute bottom-5">
|
||||||
|
<div class="w-3xl max-w-full flex flex-col text-black">
|
||||||
|
|
||||||
|
<div class="bg-neutral-200 h-12 rounded-lg border-pink-900 border-1 w-48 mb-2 text-center relative top-6 left-4 text-lg">
|
||||||
|
<div class="border-pink-300 border-4 h-full rounded-lg">
|
||||||
|
<div class="border-pink-900 border-1 text-justify h-full rounded-lg flex items-center justify-center">
|
||||||
|
<span class="font-bold p-2">{$CurrentCharacter.name}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-neutral-200 h-40 rounded-lg border-pink-900 border-1 w-full">
|
||||||
|
<div class="border-pink-300 border-4 h-full rounded-lg">
|
||||||
|
<div class="border-pink-900 border-1 px-4 pt-6 pb-4 h-full rounded-lg tracking-normal text-clip">
|
||||||
|
{renderedText}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
@@ -3,11 +3,11 @@
|
|||||||
import { DataBase } from "../../ts/storage/database";
|
import { DataBase } from "../../ts/storage/database";
|
||||||
import BackgroundDom from "../ChatScreens/BackgroundDom.svelte";
|
import BackgroundDom from "../ChatScreens/BackgroundDom.svelte";
|
||||||
import SideBarArrow from "../UI/GUI/SideBarArrow.svelte";
|
import SideBarArrow from "../UI/GUI/SideBarArrow.svelte";
|
||||||
import defaultWallpaper from '../../etc/bg.jpg'
|
import defaultWallpaper from './test.png'
|
||||||
import VisualNovelChat from "./VisualNovelChat.svelte";
|
import VisualNovelChat from "./VisualNovelChat.svelte";
|
||||||
|
|
||||||
const wallPaper = `background: url(${defaultWallpaper})`
|
const wallPaper = `background-image: url(${defaultWallpaper})`
|
||||||
|
let forceRender:() => void
|
||||||
let bgImg= ''
|
let bgImg= ''
|
||||||
let lastBg = ''
|
let lastBg = ''
|
||||||
$: (async () =>{
|
$: (async () =>{
|
||||||
@@ -20,7 +20,9 @@
|
|||||||
<div class="flex-grow h-full min-w-0 relative justify-center flex">
|
<div class="flex-grow h-full min-w-0 relative justify-center flex">
|
||||||
<SideBarArrow />
|
<SideBarArrow />
|
||||||
<BackgroundDom />
|
<BackgroundDom />
|
||||||
<div style={wallPaper} class="h-full w-full">
|
<div style={wallPaper} class="h-full w-full bg-cover" on:click={() => {
|
||||||
<VisualNovelChat />
|
forceRender()
|
||||||
|
}}>
|
||||||
|
<VisualNovelChat bind:forceRender />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
BIN
src/lib/VisualNovel/test.png
Normal file
BIN
src/lib/VisualNovel/test.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 366 KiB |
@@ -71,6 +71,11 @@ html, body{
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.strokeme {
|
||||||
|
color: #000;
|
||||||
|
text-shadow: -1px -1px 0 white, 1px -1px 0 white, -1px 1px 0 white, 1px 1px 0 white;
|
||||||
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 5px;
|
width: 5px;
|
||||||
height: 5px;
|
height: 5px;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { selectedCharID } from "./stores";
|
|||||||
import { checkCharOrder, downloadFile, getFileSrc, readImage } from "./storage/globalApi";
|
import { checkCharOrder, downloadFile, getFileSrc, readImage } from "./storage/globalApi";
|
||||||
import * as yuso from 'yuso'
|
import * as yuso from 'yuso'
|
||||||
import { reencodeImage } from "./image";
|
import { reencodeImage } from "./image";
|
||||||
|
import { updateInlayScreen } from "./process/inlayScreen";
|
||||||
|
|
||||||
export function createNewCharacter() {
|
export function createNewCharacter() {
|
||||||
let db = get(DataBase)
|
let db = get(DataBase)
|
||||||
@@ -300,6 +301,9 @@ export function characterFormatUpdate(index:number|character){
|
|||||||
depth: 0,
|
depth: 0,
|
||||||
prompt: ''
|
prompt: ''
|
||||||
}
|
}
|
||||||
|
if(!cha.newGenData){
|
||||||
|
cha = updateInlayScreen(cha)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if((!cha.characterTalks) || cha.characterTalks.length !== cha.characters.length){
|
if((!cha.characterTalks) || cha.characterTalks.length !== cha.characters.length){
|
||||||
|
|||||||
@@ -24,12 +24,21 @@ export async function postInlayImage(){
|
|||||||
|
|
||||||
const extention = img.name.split('.').at(-1)
|
const extention = img.name.split('.').at(-1)
|
||||||
|
|
||||||
//darw in canvas to convert to png
|
const imgObj = new Image()
|
||||||
|
imgObj.src = URL.createObjectURL(new Blob([img.data], {type: `image/${extention}`}))
|
||||||
|
|
||||||
|
return await writeInlayImage(imgObj, {
|
||||||
|
name: img.name,
|
||||||
|
ext: extention
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function writeInlayImage(imgObj:HTMLImageElement, arg:{name?:string, ext?:string} = {}) {
|
||||||
|
|
||||||
|
let drawHeight = 0
|
||||||
|
let drawWidth = 0
|
||||||
const canvas = document.createElement('canvas')
|
const canvas = document.createElement('canvas')
|
||||||
const ctx = canvas.getContext('2d')
|
const ctx = canvas.getContext('2d')
|
||||||
const imgObj = new Image()
|
|
||||||
let drawHeight, drawWidth = 0
|
|
||||||
imgObj.src = URL.createObjectURL(new Blob([img.data], {type: `image/${extention}`}))
|
|
||||||
await new Promise((resolve) => {
|
await new Promise((resolve) => {
|
||||||
imgObj.onload = () => {
|
imgObj.onload = () => {
|
||||||
drawHeight = imgObj.height
|
drawHeight = imgObj.height
|
||||||
@@ -59,9 +68,9 @@ export async function postInlayImage(){
|
|||||||
const imgid = v4()
|
const imgid = v4()
|
||||||
|
|
||||||
await inlayStorage.setItem(imgid, {
|
await inlayStorage.setItem(imgid, {
|
||||||
name: img.name,
|
name: arg.name ?? imgid,
|
||||||
data: dataURI,
|
data: dataURI,
|
||||||
ext: extention,
|
ext: arg.ext ?? 'png',
|
||||||
height: drawHeight,
|
height: drawHeight,
|
||||||
width: drawWidth
|
width: drawWidth
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ DOMPurify.addHook("uponSanitizeAttribute", (node, data) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const assetRegex = /{{(raw|img|video|audio|bg)::(.+?)}}/g
|
const assetRegex = /{{(raw|img|video|audio|bg|emotion)::(.+?)}}/g
|
||||||
|
|
||||||
async function parseAdditionalAssets(data:string, char:simpleCharacterArgument|character, mode:'normal'|'back', mode2:'unset'|'pre'|'post' = 'unset'){
|
async function parseAdditionalAssets(data:string, char:simpleCharacterArgument|character, mode:'normal'|'back', mode2:'unset'|'pre'|'post' = 'unset'){
|
||||||
const db = get(DataBase)
|
const db = get(DataBase)
|
||||||
@@ -74,13 +74,28 @@ async function parseAdditionalAssets(data:string, char:simpleCharacterArgument|c
|
|||||||
if(char.additionalAssets){
|
if(char.additionalAssets){
|
||||||
|
|
||||||
let assetPaths:{[key:string]:string} = {}
|
let assetPaths:{[key:string]:string} = {}
|
||||||
|
let emoPaths:{[key:string]:string} = {}
|
||||||
|
|
||||||
for(const asset of char.additionalAssets){
|
for(const asset of char.additionalAssets){
|
||||||
const assetPath = await getFileSrc(asset[1])
|
const assetPath = await getFileSrc(asset[1])
|
||||||
assetPaths[asset[0].toLocaleLowerCase()] = assetPath
|
assetPaths[asset[0].toLocaleLowerCase()] = assetPath
|
||||||
}
|
}
|
||||||
|
if(char.emotionImages){
|
||||||
|
for(const emo of char.emotionImages){
|
||||||
|
const emoPath = await getFileSrc(emo[1])
|
||||||
|
emoPaths[emo[0].toLocaleLowerCase()] = emoPath
|
||||||
|
}
|
||||||
|
}
|
||||||
data = data.replaceAll(assetRegex, (full:string, type:string, name:string) => {
|
data = data.replaceAll(assetRegex, (full:string, type:string, name:string) => {
|
||||||
name = name.toLocaleLowerCase()
|
name = name.toLocaleLowerCase()
|
||||||
|
if(type === 'emotion'){
|
||||||
|
console.log(emoPaths, name)
|
||||||
|
const path = emoPaths[name]
|
||||||
|
if(!path){
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
return `<img src="${path}" alt="${path}" style="${assetWidthString} "/>`
|
||||||
|
}
|
||||||
const path = assetPaths[name]
|
const path = assetPaths[name]
|
||||||
if(!path){
|
if(!path){
|
||||||
return ''
|
return ''
|
||||||
@@ -129,6 +144,7 @@ export interface simpleCharacterArgument{
|
|||||||
customscript: customscript[]
|
customscript: customscript[]
|
||||||
chaId: string,
|
chaId: string,
|
||||||
virtualscript?: string
|
virtualscript?: string
|
||||||
|
emotionImages?: [string, string][]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
export function generateRandomSeed(length) {
|
|
||||||
let result = '';
|
|
||||||
const characters = '0123456789';
|
|
||||||
const charactersLength = characters.length;
|
|
||||||
for (let i = 0; i < length; i++) {
|
|
||||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -22,6 +22,7 @@ import { cipherChat, decipherChat } from "./cipherChat";
|
|||||||
import { getInlayImage, supportsInlayImage } from "../image";
|
import { getInlayImage, supportsInlayImage } from "../image";
|
||||||
import { getGenerationModelString } from "./models/modelString";
|
import { getGenerationModelString } from "./models/modelString";
|
||||||
import { sendPeerChar } from "../sync/multiuser";
|
import { sendPeerChar } from "../sync/multiuser";
|
||||||
|
import { runInlayScreen } from "./inlayScreen";
|
||||||
|
|
||||||
export interface OpenAIChat{
|
export interface OpenAIChat{
|
||||||
role: 'system'|'user'|'assistant'|'function'
|
role: 'system'|'user'|'assistant'|'function'
|
||||||
@@ -300,6 +301,21 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(currentChar.inlayViewScreen){
|
||||||
|
if(currentChar.viewScreen === 'emotion'){
|
||||||
|
unformated.postEverything.push({
|
||||||
|
role: 'system',
|
||||||
|
content: currentChar.newGenData.emotionInstructions.replaceAll('{{slot}}', currentChar.emotionImages.map((v) => v[0]).join(', '))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if(currentChar.viewScreen === 'imggen'){
|
||||||
|
unformated.postEverything.push({
|
||||||
|
role: 'system',
|
||||||
|
content: currentChar.newGenData.instructions
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(lorepmt.special_act){
|
if(lorepmt.special_act){
|
||||||
unformated.postEverything.push({
|
unformated.postEverything.push({
|
||||||
role: 'system',
|
role: 'system',
|
||||||
@@ -498,6 +514,10 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n
|
|||||||
}
|
}
|
||||||
let inlays:string[] = []
|
let inlays:string[] = []
|
||||||
if(db.inlayImage){
|
if(db.inlayImage){
|
||||||
|
if(msg.role === 'char'){
|
||||||
|
formedChat = formedChat.replace(/{{inlay::(.+?)}}/g, '')
|
||||||
|
}
|
||||||
|
else{
|
||||||
const inlayMatch = formedChat.match(/{{inlay::(.+?)}}/g)
|
const inlayMatch = formedChat.match(/{{inlay::(.+?)}}/g)
|
||||||
if(inlayMatch){
|
if(inlayMatch){
|
||||||
for(const inlay of inlayMatch){
|
for(const inlay of inlayMatch){
|
||||||
@@ -505,6 +525,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(inlays.length > 0){
|
if(inlays.length > 0){
|
||||||
for(const inlay of inlays){
|
for(const inlay of inlays){
|
||||||
@@ -653,7 +674,6 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function pushPrompts(cha:OpenAIChat[]){
|
function pushPrompts(cha:OpenAIChat[]){
|
||||||
for(const chat of cha){
|
for(const chat of cha){
|
||||||
if(!chat.content){
|
if(!chat.content){
|
||||||
@@ -913,9 +933,17 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n
|
|||||||
|
|
||||||
currentChat = db.characters[selectedChar].chats[selectedChat]
|
currentChat = db.characters[selectedChar].chats[selectedChat]
|
||||||
const triggerResult = await runTrigger(currentChar, 'output', {chat:currentChat})
|
const triggerResult = await runTrigger(currentChar, 'output', {chat:currentChat})
|
||||||
console.log(triggerResult)
|
|
||||||
if(triggerResult && triggerResult.chat){
|
if(triggerResult && triggerResult.chat){
|
||||||
db.characters[selectedChar].chats[selectedChat] = triggerResult.chat
|
currentChat = triggerResult.chat
|
||||||
|
}
|
||||||
|
const inlayr = runInlayScreen(currentChar, currentChat.message[msgIndex].data)
|
||||||
|
currentChat.message[msgIndex].data = inlayr.text
|
||||||
|
db.characters[selectedChar].chats[selectedChat] = currentChat
|
||||||
|
setDatabase(db)
|
||||||
|
if(inlayr.promise){
|
||||||
|
const t = await inlayr.promise
|
||||||
|
currentChat.message[msgIndex].data = t
|
||||||
|
db.characters[selectedChar].chats[selectedChat] = currentChat
|
||||||
setDatabase(db)
|
setDatabase(db)
|
||||||
}
|
}
|
||||||
await sayTTS(currentChar, result)
|
await sayTTS(currentChar, result)
|
||||||
@@ -938,6 +966,8 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n
|
|||||||
result2 = await processScriptFull(nowChatroom, reformatContent(beforeChat.data + mess), 'editoutput', msgIndex)
|
result2 = await processScriptFull(nowChatroom, reformatContent(beforeChat.data + mess), 'editoutput', msgIndex)
|
||||||
}
|
}
|
||||||
result = result2.data
|
result = result2.data
|
||||||
|
const inlayResult = runInlayScreen(currentChar, result)
|
||||||
|
result = inlayResult.text
|
||||||
emoChanged = result2.emoChanged
|
emoChanged = result2.emoChanged
|
||||||
if(i === 0 && arg.continue){
|
if(i === 0 && arg.continue){
|
||||||
db.characters[selectedChar].chats[selectedChat].message[msgIndex] = {
|
db.characters[selectedChar].chats[selectedChat].message[msgIndex] = {
|
||||||
@@ -950,6 +980,10 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n
|
|||||||
generationId: generationId,
|
generationId: generationId,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(inlayResult.promise){
|
||||||
|
const p = await inlayResult.promise
|
||||||
|
db.characters[selectedChar].chats[selectedChat].message[msgIndex].data = p
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
db.characters[selectedChar].chats[selectedChat].message.push({
|
db.characters[selectedChar].chats[selectedChat].message.push({
|
||||||
@@ -962,6 +996,11 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n
|
|||||||
generationId: generationId,
|
generationId: generationId,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
const ind = db.characters[selectedChar].chats[selectedChat].message.length - 1
|
||||||
|
if(inlayResult.promise){
|
||||||
|
const p = await inlayResult.promise
|
||||||
|
db.characters[selectedChar].chats[selectedChat].message[ind].data = p
|
||||||
|
}
|
||||||
}
|
}
|
||||||
db.characters[selectedChar].reloadKeys += 1
|
db.characters[selectedChar].reloadKeys += 1
|
||||||
await sayTTS(currentChar, result)
|
await sayTTS(currentChar, result)
|
||||||
@@ -1005,6 +1044,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!currentChar.inlayViewScreen){
|
||||||
if(currentChar.viewScreen === 'emotion' && (!emoChanged) && (abortSignal.aborted === false)){
|
if(currentChar.viewScreen === 'emotion' && (!emoChanged) && (abortSignal.aborted === false)){
|
||||||
|
|
||||||
let currentEmotion = currentChar.emotionImages
|
let currentEmotion = currentChar.emotionImages
|
||||||
@@ -1198,10 +1238,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const ch = await stableDiff(currentChar, msgStr)
|
await stableDiff(currentChar, msgStr)
|
||||||
if(ch){
|
|
||||||
db.characters[selectedChar].chats[selectedChat].sdData = ch
|
|
||||||
setDatabase(db)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
97
src/ts/process/inlayScreen.ts
Normal file
97
src/ts/process/inlayScreen.ts
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
import { writeInlayImage } from "../image";
|
||||||
|
import type { character } from "../storage/database";
|
||||||
|
import { generateAIImage } from "./stableDiff";
|
||||||
|
|
||||||
|
const imggenRegex = [/<ImgGen="(.+?)">/gi, /{{ImgGen="(.+?)"}}/gi] as const
|
||||||
|
|
||||||
|
export function runInlayScreen(char:character, data:string):{text:string, promise?:Promise<string>} {
|
||||||
|
if(char.inlayViewScreen){
|
||||||
|
if(char.viewScreen === 'emotion'){
|
||||||
|
return {text: data.replace(/<Emotion="(.+?)">/gi, '{{emotion::$1}}')}
|
||||||
|
}
|
||||||
|
if(char.viewScreen === 'imggen'){
|
||||||
|
return {
|
||||||
|
text: data.replace(imggenRegex[0],'[Generating...]').replace(imggenRegex[1],'[Generating...]'),
|
||||||
|
promise : (async () => {
|
||||||
|
for(const regex of imggenRegex){
|
||||||
|
const promises:Promise<string|false>[] = [];
|
||||||
|
const neg = char.newGenData.negative
|
||||||
|
data.replace(regex, (match, p1) => {
|
||||||
|
const prompt = char.newGenData.prompt.replaceAll('{{slot}}', p1)
|
||||||
|
promises.push((async () => {
|
||||||
|
const v = await generateAIImage(prompt, char, neg, 'inlay')
|
||||||
|
if(!v){
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
const imgHTML = new Image()
|
||||||
|
imgHTML.src = v
|
||||||
|
const inlay = await writeInlayImage(imgHTML)
|
||||||
|
return inlay
|
||||||
|
})())
|
||||||
|
return match
|
||||||
|
})
|
||||||
|
const d = await Promise.all(promises)
|
||||||
|
data = data.replace(regex, () => {
|
||||||
|
const result = d.shift()
|
||||||
|
if(result === false){
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return {text: data}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateInlayScreen(char:character):character {
|
||||||
|
switch(char.viewScreen){
|
||||||
|
case 'emotion':
|
||||||
|
if(char.inlayViewScreen){
|
||||||
|
char.newGenData = {
|
||||||
|
prompt: '',
|
||||||
|
negative: '',
|
||||||
|
instructions: '',
|
||||||
|
emotionInstructions: `You must always output the character's emotional image as a command at the end of a conversation. The command must be selected from a given list, and it's better to have variety than to repeat images used in previous chats. Use one image, depending on the character's emotion. See the list below. Form: <Emotion="<image command>"> Example: <Emotion="Agree"> List of commands: {{slot}}`,
|
||||||
|
}
|
||||||
|
return char
|
||||||
|
}
|
||||||
|
char.newGenData = {
|
||||||
|
prompt: '',
|
||||||
|
negative: '',
|
||||||
|
instructions: '',
|
||||||
|
emotionInstructions: `You must always output the character's emotional image as a command. The command must be selected from a given list, only output the command, depending on the character's emotion. List of commands: {{slot}}`
|
||||||
|
}
|
||||||
|
return char
|
||||||
|
case 'imggen':
|
||||||
|
if(char.inlayViewScreen){
|
||||||
|
char.newGenData = {
|
||||||
|
prompt: 'best quality, {{slot}}',
|
||||||
|
negative: 'worse quality',
|
||||||
|
instructions: 'You must always output the character\'s image as a keyword-formatted prompts that can be used in stable diffusion at the end of a conversation. Use one image, depending on character, place, situation, etc. keyword should be long enough. Form: <ImgGen="<keyword-formatted prompt>">',
|
||||||
|
emotionInstructions: ''
|
||||||
|
}
|
||||||
|
return char
|
||||||
|
}
|
||||||
|
char.newGenData = {
|
||||||
|
prompt: 'best quality, {{slot}}',
|
||||||
|
negative: 'worse quality',
|
||||||
|
instructions: 'You must always output the character\'s image as a keyword-formatted prompts that can be used in stable diffusion. only output the that prompt, depending on character, place, situation, etc. keyword should be long enough.',
|
||||||
|
emotionInstructions: ''
|
||||||
|
}
|
||||||
|
return char
|
||||||
|
default:
|
||||||
|
char.newGenData = {
|
||||||
|
prompt: '',
|
||||||
|
negative: '',
|
||||||
|
instructions: '',
|
||||||
|
emotionInstructions: ''
|
||||||
|
}
|
||||||
|
return char
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import JSZip from "jszip";
|
|
||||||
|
|
||||||
export async function processZip(dataArray: Uint8Array): Promise<string> {
|
export async function processZip(dataArray: Uint8Array): Promise<string> {
|
||||||
|
const jszip = await import("jszip");
|
||||||
const blob = new Blob([dataArray], { type: "application/zip" });
|
const blob = new Blob([dataArray], { type: "application/zip" });
|
||||||
const zip = new JSZip();
|
const zip = new jszip.default();
|
||||||
const zipData = await zip.loadAsync(blob);
|
const zipData = await zip.loadAsync(blob);
|
||||||
|
|
||||||
const imageFile = Object.keys(zipData.files).find(fileName => /\.(jpg|jpeg|png)$/.test(fileName));
|
const imageFile = Object.keys(zipData.files).find(fileName => /\.(jpg|jpeg|png)$/.test(fileName));
|
||||||
|
|||||||
@@ -6,11 +6,7 @@ import { globalFetch, readImage } from "../storage/globalApi"
|
|||||||
import { CharEmotion } from "../stores"
|
import { CharEmotion } from "../stores"
|
||||||
import type { OpenAIChat } from "."
|
import type { OpenAIChat } from "."
|
||||||
import { processZip } from "./processzip"
|
import { processZip } from "./processzip"
|
||||||
import { convertToBase64 } from "./uinttobase64"
|
|
||||||
import type { List } from "lodash"
|
|
||||||
import { generateRandomSeed } from "./generateSeed"
|
|
||||||
export async function stableDiff(currentChar:character,prompt:string){
|
export async function stableDiff(currentChar:character,prompt:string){
|
||||||
const mainPrompt = "assistant is a chat analyzer.\nuser will input a data of situation with key and values before chat, and a chat of a user and character.\nView the status of the chat and change the data.\nif data's key starts with $, it must change it every time.\nif data value is none, it must change it."
|
|
||||||
let db = get(DataBase)
|
let db = get(DataBase)
|
||||||
|
|
||||||
if(db.sdProvider === ''){
|
if(db.sdProvider === ''){
|
||||||
@@ -18,53 +14,14 @@ export async function stableDiff(currentChar:character,prompt:string){
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
let proompt = 'Data:'
|
|
||||||
|
|
||||||
let currentSd:[string,string][] = []
|
const proompt = `Chat:\n${prompt}`
|
||||||
|
|
||||||
const sdData = currentChar.chats[currentChar.chatPage].sdData
|
|
||||||
if(sdData){
|
|
||||||
const das = sdData.split('\n')
|
|
||||||
for(const data of das){
|
|
||||||
const splited = data.split(':::')
|
|
||||||
currentSd.push([splited[0].trim(), splited[1].trim()])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
currentSd = JSON.parse(JSON.stringify(currentChar.sdData))
|
|
||||||
}
|
|
||||||
|
|
||||||
for(const d of currentSd){
|
|
||||||
let val = d[1].trim()
|
|
||||||
if(val === ''){
|
|
||||||
val = 'none'
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!d[0].startsWith('|') || d[0] === 'negative' || d[0] === 'always'){
|
|
||||||
proompt += `\n${d[0].trim()}: ${val}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
proompt += `\n\nChat:\n${prompt}`
|
|
||||||
|
|
||||||
const promptbody:OpenAIChat[] = [
|
const promptbody:OpenAIChat[] = [
|
||||||
{
|
{
|
||||||
|
|
||||||
role:'system',
|
role:'system',
|
||||||
content: mainPrompt
|
content: currentChar.newGenData.instructions
|
||||||
},
|
|
||||||
{
|
|
||||||
role: 'user',
|
|
||||||
content: `Data:\ncharacter's appearance: red hair, cute, black eyes\ncurrent situation: none\n$character's pose: none\n$character's emotion: none\n\nChat:\nuser: *eats breakfeast* \n I'm ready.\ncharacter: Lemon waits patiently outside your room while you get ready. Once you are dressed and have finished your breakfast, she escorts you to the door.\n"Have a good day at school, Master. Don't forget to study hard and make the most of your time there," Lemon reminds you with a smile as she sees you off.`
|
|
||||||
},
|
|
||||||
{
|
|
||||||
role: 'assistant',
|
|
||||||
content: "character's appearance: red hair, cute, black eyes\ncurrent situation: waking up in the morning\n$character's pose: standing\n$character's emotion: apologetic"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
|
|
||||||
role:'system',
|
|
||||||
content: mainPrompt
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
role: 'user',
|
role: 'user',
|
||||||
@@ -72,7 +29,6 @@ export async function stableDiff(currentChar:character,prompt:string){
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
console.log(proompt)
|
|
||||||
const rq = await requestChatData({
|
const rq = await requestChatData({
|
||||||
formated: promptbody,
|
formated: promptbody,
|
||||||
currentChar: currentChar,
|
currentChar: currentChar,
|
||||||
@@ -86,38 +42,20 @@ export async function stableDiff(currentChar:character,prompt:string){
|
|||||||
alertError(`${rq.result}`)
|
alertError(`${rq.result}`)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
else{
|
|
||||||
const res = rq.result
|
|
||||||
const das = res.split('\n')
|
|
||||||
for(const data of das){
|
|
||||||
const splited = data.split(':')
|
|
||||||
if(splited.length === 2){
|
|
||||||
for(let i=0;i<currentSd.length;i++){
|
|
||||||
if(currentSd[i][0].trim() === splited[0]){
|
|
||||||
currentSd[i][1] = splited[1].trim()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let returnSdData = currentSd.map((val) => {
|
const r = rq.result
|
||||||
return val.join(':::')
|
|
||||||
}).join('\n')
|
|
||||||
|
|
||||||
|
|
||||||
|
const genPrompt = currentChar.newGenData.prompt.replaceAll('{{slot}}', r)
|
||||||
|
const neg = currentChar.newGenData.negative
|
||||||
|
|
||||||
|
return await generateAIImage(genPrompt, currentChar, neg, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generateAIImage(genPrompt:string, currentChar:character, neg:string, returnSdData:string){
|
||||||
|
const db = get(DataBase)
|
||||||
if(db.sdProvider === 'webui'){
|
if(db.sdProvider === 'webui'){
|
||||||
|
|
||||||
let prompts:string[] = []
|
|
||||||
let neg = ''
|
|
||||||
for(let i=0;i<currentSd.length;i++){
|
|
||||||
if(currentSd[i][0] !== 'negative'){
|
|
||||||
prompts.push(currentSd[i][1])
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
neg = currentSd[i][1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const uri = new URL(db.webUiUrl)
|
const uri = new URL(db.webUiUrl)
|
||||||
uri.pathname = '/sdapi/v1/txt2img'
|
uri.pathname = '/sdapi/v1/txt2img'
|
||||||
@@ -129,7 +67,7 @@ export async function stableDiff(currentChar:character,prompt:string){
|
|||||||
"seed": -1,
|
"seed": -1,
|
||||||
"steps": db.sdSteps,
|
"steps": db.sdSteps,
|
||||||
"cfg_scale": db.sdCFG,
|
"cfg_scale": db.sdCFG,
|
||||||
"prompt": prompts.join(','),
|
"prompt": genPrompt,
|
||||||
"negative_prompt": neg,
|
"negative_prompt": neg,
|
||||||
"sampler_name": db.sdConfig.sampler_name,
|
"sampler_name": db.sdConfig.sampler_name,
|
||||||
"enable_hr": db.sdConfig.enable_hr,
|
"enable_hr": db.sdConfig.enable_hr,
|
||||||
@@ -142,6 +80,16 @@ export async function stableDiff(currentChar:character,prompt:string){
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if(returnSdData === 'inlay'){
|
||||||
|
if(da.ok){
|
||||||
|
return `data:image/png;base64,${da.data.images[0]}`
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
alertError(JSON.stringify(da.data))
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(da.ok){
|
if(da.ok){
|
||||||
let charemotions = get(CharEmotion)
|
let charemotions = get(CharEmotion)
|
||||||
const img = `data:image/png;base64,${da.data.images[0]}`
|
const img = `data:image/png;base64,${da.data.images[0]}`
|
||||||
@@ -165,39 +113,32 @@ export async function stableDiff(currentChar:character,prompt:string){
|
|||||||
}
|
}
|
||||||
if(db.sdProvider === 'novelai'){
|
if(db.sdProvider === 'novelai'){
|
||||||
|
|
||||||
let prompts:string[] = []
|
|
||||||
let neg = ''
|
|
||||||
for(let i=0;i<currentSd.length;i++){
|
|
||||||
if(currentSd[i][0] !== 'negative'){
|
|
||||||
prompts.push(currentSd[i][1])
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
neg = currentSd[i][1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let reqlist= {}
|
let reqlist= {}
|
||||||
|
|
||||||
if(db.NAII2I){
|
if(db.NAII2I){
|
||||||
|
genPrompt = genPrompt
|
||||||
|
.replaceAll('\\(', "♧")
|
||||||
|
.replaceAll('\\)', "♤")
|
||||||
|
.replaceAll('(','{')
|
||||||
|
.replaceAll(')','}')
|
||||||
|
.replaceAll('♧','(')
|
||||||
|
.replaceAll('♤',')')
|
||||||
|
|
||||||
let base64img = ''
|
let base64img = ''
|
||||||
if(db.NAIImgConfig.image === ''){
|
if(db.NAIImgConfig.image === ''){
|
||||||
const charimg = currentChar.image;
|
const charimg = currentChar.image;
|
||||||
|
|
||||||
const img = await readImage(charimg)
|
const img = await readImage(charimg)
|
||||||
const base64 = await convertToBase64(img);
|
base64img = Buffer.from(img).toString('base64');
|
||||||
base64img = base64.split('base64,')[1];
|
} else{
|
||||||
}else{
|
base64img = Buffer.from(await readImage(db.NAIImgConfig.image)).toString('base64');
|
||||||
base64img = db.NAIImgConfig.image.split('base64,')[1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let randomseed = generateRandomSeed(10);
|
let seed = Math.floor(Math.random() * 100000000000)
|
||||||
let seed = parseInt(randomseed, 10);
|
|
||||||
reqlist = {
|
reqlist = {
|
||||||
body: {
|
body: {
|
||||||
"action": "img2img",
|
"action": "img2img",
|
||||||
"input": prompts.join(','),
|
"input": genPrompt,
|
||||||
"model": db.NAIImgModel,
|
"model": db.NAIImgModel,
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"seed": seed,
|
"seed": seed,
|
||||||
@@ -225,12 +166,13 @@ export async function stableDiff(currentChar:character,prompt:string){
|
|||||||
},
|
},
|
||||||
headers:{
|
headers:{
|
||||||
"Authorization": "Bearer " + db.NAIApiKey
|
"Authorization": "Bearer " + db.NAIApiKey
|
||||||
}
|
},
|
||||||
|
rawResponse: true
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
reqlist = {
|
reqlist = {
|
||||||
body: {
|
body: {
|
||||||
"input": prompts.join(','),
|
"input": genPrompt,
|
||||||
"model": db.NAIImgModel,
|
"model": db.NAIImgModel,
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"width": db.NAIImgConfig.width,
|
"width": db.NAIImgConfig.width,
|
||||||
@@ -245,13 +187,26 @@ export async function stableDiff(currentChar:character,prompt:string){
|
|||||||
},
|
},
|
||||||
headers:{
|
headers:{
|
||||||
"Authorization": "Bearer " + db.NAIApiKey
|
"Authorization": "Bearer " + db.NAIApiKey
|
||||||
}
|
},
|
||||||
|
rawResponse: true
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const da = await globalFetch(db.NAIImgUrl, reqlist)
|
const da = await globalFetch(db.NAIImgUrl, reqlist)
|
||||||
|
|
||||||
if(da){
|
if(returnSdData === 'inlay'){
|
||||||
|
if(da.ok){
|
||||||
|
const img = await processZip(da.data);
|
||||||
|
return img
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
alertError(Buffer.from(da.data).toString())
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(da.ok){
|
||||||
let charemotions = get(CharEmotion)
|
let charemotions = get(CharEmotion)
|
||||||
const img = await processZip(da.data);
|
const img = await processZip(da.data);
|
||||||
const emos:[string, string,number][] = [[img, img, Date.now()]]
|
const emos:[string, string,number][] = [[img, img, Date.now()]]
|
||||||
@@ -259,7 +214,7 @@ export async function stableDiff(currentChar:character,prompt:string){
|
|||||||
CharEmotion.set(charemotions)
|
CharEmotion.set(charemotions)
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
alertError(JSON.stringify(da.data))
|
alertError(Buffer.from(da.data).toString())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
export async function convertToBase64(data: Uint8Array): Promise<string> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const blob = new Blob([data]);
|
|
||||||
const reader = new FileReader();
|
|
||||||
|
|
||||||
reader.onloadend = function() {
|
|
||||||
const base64String = reader.result as string;
|
|
||||||
resolve(base64String);
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.onerror = function(error) {
|
|
||||||
reject(error);
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.readAsDataURL(blob);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -15,7 +15,7 @@ import type { OobaChatCompletionRequestParams } from '../model/ooba';
|
|||||||
|
|
||||||
export const DataBase = writable({} as any as Database)
|
export const DataBase = writable({} as any as Database)
|
||||||
export const loadedStore = writable(false)
|
export const loadedStore = writable(false)
|
||||||
export let appVer = "1.59.9"
|
export let appVer = "1.60.1"
|
||||||
export let webAppSubVer = ''
|
export let webAppSubVer = ''
|
||||||
|
|
||||||
export function setDatabase(data:Database){
|
export function setDatabase(data:Database){
|
||||||
@@ -588,6 +588,12 @@ export interface character{
|
|||||||
globalLore: loreBook[]
|
globalLore: loreBook[]
|
||||||
chaId: string
|
chaId: string
|
||||||
sdData: [string, string][]
|
sdData: [string, string][]
|
||||||
|
newGenData?: {
|
||||||
|
prompt: string,
|
||||||
|
negative: string,
|
||||||
|
instructions: string,
|
||||||
|
emotionInstructions: string,
|
||||||
|
}
|
||||||
customscript: customscript[]
|
customscript: customscript[]
|
||||||
triggerscript: triggerscript[]
|
triggerscript: triggerscript[]
|
||||||
utilityBot: boolean
|
utilityBot: boolean
|
||||||
@@ -641,6 +647,7 @@ export interface character{
|
|||||||
extentions?:{[key:string]:any}
|
extentions?:{[key:string]:any}
|
||||||
largePortrait?:boolean
|
largePortrait?:boolean
|
||||||
lorePlus?:boolean
|
lorePlus?:boolean
|
||||||
|
inlayViewScreen?:boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -685,16 +685,6 @@ export async function globalFetch(url:string, arg:{
|
|||||||
headers: headers,
|
headers: headers,
|
||||||
method: method
|
method: method
|
||||||
})
|
})
|
||||||
if(da.headers.get('content-type')?.includes('application/x-zip-compressed')){
|
|
||||||
const daText = await da.blob()
|
|
||||||
|
|
||||||
addFetchLog(daText, da.ok && da.status >= 200 && da.status < 300)
|
|
||||||
return {
|
|
||||||
ok: da.ok && da.status >= 200 && da.status < 300,
|
|
||||||
data: daText,
|
|
||||||
headers: Object.fromEntries(da.headers)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const daText = await da.text()
|
const daText = await da.text()
|
||||||
try {
|
try {
|
||||||
const dat = JSON.parse(daText)
|
const dat = JSON.parse(daText)
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ function createSimpleCharacter(char:character|groupChat){
|
|||||||
chaId: char.chaId,
|
chaId: char.chaId,
|
||||||
additionalAssets: char.additionalAssets,
|
additionalAssets: char.additionalAssets,
|
||||||
virtualscript: char.virtualscript,
|
virtualscript: char.virtualscript,
|
||||||
|
emotionImages: char.emotionImages,
|
||||||
}
|
}
|
||||||
|
|
||||||
return simpleChar
|
return simpleChar
|
||||||
@@ -71,7 +72,9 @@ function updateCurrentCharacter(){
|
|||||||
if(isEqual(gotCharacter, currentChar)){
|
if(isEqual(gotCharacter, currentChar)){
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if((currentChar?.viewScreen === 'vn') !== get(ShowVN)){
|
||||||
ShowVN.set(currentChar?.viewScreen === 'vn')
|
ShowVN.set(currentChar?.viewScreen === 'vn')
|
||||||
|
}
|
||||||
|
|
||||||
console.log("Character updated")
|
console.log("Character updated")
|
||||||
CurrentCharacter.set(cloneDeep(currentChar))
|
CurrentCharacter.set(cloneDeep(currentChar))
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"version":"1.59.9"}
|
{"version":"1.60.1"}
|
||||||
Reference in New Issue
Block a user