Update to 1.14.0 (#78)
This commit is contained in:
@@ -8,7 +8,7 @@
|
|||||||
},
|
},
|
||||||
"package": {
|
"package": {
|
||||||
"productName": "RisuAI",
|
"productName": "RisuAI",
|
||||||
"version": "1.13.2"
|
"version": "1.14.0"
|
||||||
},
|
},
|
||||||
"tauri": {
|
"tauri": {
|
||||||
"allowlist": {
|
"allowlist": {
|
||||||
|
|||||||
@@ -259,5 +259,11 @@ export const languageEnglish = {
|
|||||||
user:"User",
|
user:"User",
|
||||||
additionalAssets:"Additional Assets",
|
additionalAssets:"Additional Assets",
|
||||||
editDisplay: "Modify Display",
|
editDisplay: "Modify Display",
|
||||||
community: "Community"
|
community: "Community",
|
||||||
|
textBackgrounds: "Custom Text Screen Color",
|
||||||
|
textBorder: "Text Outlines",
|
||||||
|
textScreenRound: "Round Text Screen",
|
||||||
|
textScreenBorder: "Text Screen Borders",
|
||||||
|
ttsReadOnlyQuoted: "Read Only Quoted",
|
||||||
|
ttsStop: "Stop TTS"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,11 @@
|
|||||||
let openChatList = false
|
let openChatList = false
|
||||||
|
|
||||||
const wallPaper = `background: url(${defaultWallpaper})`
|
const wallPaper = `background: url(${defaultWallpaper})`
|
||||||
|
const externalStyles =
|
||||||
|
("background: " + ($DataBase.textScreenColor ? ($DataBase.textScreenColor + '80') : "rgba(0,0,0,0.8)") + ';\n')
|
||||||
|
+ ($DataBase.textBorder ? "text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;" : '')
|
||||||
|
+ ($DataBase.textScreenRounded ? "border-radius: 2rem; padding: 1rem;" : '')
|
||||||
|
+ ($DataBase.textScreenBorder ? `border: 0.3rem solid ${$DataBase.textScreenBorder};` : '')
|
||||||
let bgImg= ''
|
let bgImg= ''
|
||||||
let lastBg = ''
|
let lastBg = ''
|
||||||
|
|
||||||
@@ -27,7 +32,7 @@
|
|||||||
<ResizeBox />
|
<ResizeBox />
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
<DefaultChatScreen customStyle={bgImg.length > 2 ? 'background: rgba(0,0,0,0.8)': ''} bind:openChatList/>
|
<DefaultChatScreen customStyle={bgImg.length > 2 ? `${externalStyles}`: ''} bind:openChatList/>
|
||||||
</div>
|
</div>
|
||||||
{:else if $DataBase.theme === 'waifu'}
|
{:else if $DataBase.theme === 'waifu'}
|
||||||
<div class="flex-grow h-full flex justify-center" style="max-width:calc({$sideBarStore ? $SizeStore.w - 400 : $SizeStore.w}px);{bgImg.length < 4 ? wallPaper : bgImg}">
|
<div class="flex-grow h-full flex justify-center" style="max-width:calc({$sideBarStore ? $SizeStore.w - 400 : $SizeStore.w}px);{bgImg.length < 4 ? wallPaper : bgImg}">
|
||||||
@@ -39,13 +44,13 @@
|
|||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
<div class="h-full w-2xl" style:width="{42 * ($DataBase.waifuWidth / 100)}rem" class:halfwp={$selectedCharID >= 0 && $DataBase.characters[$selectedCharID].viewScreen !== 'none'}>
|
<div class="h-full w-2xl" style:width="{42 * ($DataBase.waifuWidth / 100)}rem" class:halfwp={$selectedCharID >= 0 && $DataBase.characters[$selectedCharID].viewScreen !== 'none'}>
|
||||||
<DefaultChatScreen customStyle={'background: rgba(0,0,0,0.8);backdrop-filter: blur(4px);'} bind:openChatList/>
|
<DefaultChatScreen customStyle={`${externalStyles}backdrop-filter: blur(4px);`} bind:openChatList/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else if $DataBase.theme === 'waifuMobile'}
|
{:else if $DataBase.theme === 'waifuMobile'}
|
||||||
<div class="flex-grow h-full relative" style={bgImg.length < 4 ? wallPaper : bgImg}>
|
<div class="flex-grow h-full relative" style={bgImg.length < 4 ? wallPaper : bgImg}>
|
||||||
<div class="w-full h-1/3 absolute z-10 bottom-0 left-0">
|
<div class="w-full h-1/3 absolute z-10 bottom-0 left-0">
|
||||||
<DefaultChatScreen customStyle={'background: rgba(0,0,0,0.8);backdrop-filter: blur(4px);'} bind:openChatList/>
|
<DefaultChatScreen customStyle={`${externalStyles}backdrop-filter: blur(4px);`} bind:openChatList/>
|
||||||
</div>
|
</div>
|
||||||
{#if $selectedCharID >= 0}
|
{#if $selectedCharID >= 0}
|
||||||
{#if $DataBase.characters[$selectedCharID].viewScreen !== 'none'}
|
{#if $DataBase.characters[$selectedCharID].viewScreen !== 'none'}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { DatabaseIcon, DicesIcon, LanguagesIcon, MenuIcon, RefreshCcwIcon, Send } from "lucide-svelte";
|
import { DatabaseIcon, DicesIcon, LanguagesIcon, MenuIcon, MicOffIcon, RefreshCcwIcon, Send } from "lucide-svelte";
|
||||||
import { selectedCharID } from "../../ts/stores";
|
import { selectedCharID } from "../../ts/stores";
|
||||||
import Chat from "./Chat.svelte";
|
import Chat from "./Chat.svelte";
|
||||||
import { DataBase, appVer, type Message } from "../../ts/database";
|
import { DataBase, appVer, type Message } from "../../ts/database";
|
||||||
@@ -11,9 +11,10 @@
|
|||||||
import { alertError } from "../../ts/alert";
|
import { alertError } from "../../ts/alert";
|
||||||
import sendSound from '../../etc/send.mp3'
|
import sendSound from '../../etc/send.mp3'
|
||||||
import {cloneDeep} from 'lodash'
|
import {cloneDeep} from 'lodash'
|
||||||
import { processScript } from "src/ts/process/scripts";
|
import { processScript } from "src/ts/process/scripts";
|
||||||
import GithubStars from "../Others/GithubStars.svelte";
|
import GithubStars from "../Others/GithubStars.svelte";
|
||||||
import CreatorQuote from "./CreatorQuote.svelte";
|
import CreatorQuote from "./CreatorQuote.svelte";
|
||||||
|
import { stopTTS } from "src/ts/process/tts";
|
||||||
|
|
||||||
let messageInput = ''
|
let messageInput = ''
|
||||||
let openMenu = false
|
let openMenu = false
|
||||||
@@ -333,6 +334,17 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
||||||
|
<!-- svelte-ignore empty-block -->
|
||||||
|
{#if $DataBase.characters[$selectedCharID].ttsMode === 'webspeech' || $DataBase.characters[$selectedCharID].ttsMode === 'elevenlab'}
|
||||||
|
<div class="flex items-center cursor-pointer hover:text-green-500 transition-colors" on:click={() => {
|
||||||
|
stopTTS()
|
||||||
|
}}>
|
||||||
|
<MicOffIcon />
|
||||||
|
<span class="ml-2">{language.ttsStop}</span>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div class="flex items-center cursor-pointer hover:text-green-500 transition-colors" on:click={() => {
|
<div class="flex items-center cursor-pointer hover:text-green-500 transition-colors" on:click={() => {
|
||||||
openChatList = true
|
openChatList = true
|
||||||
openMenu = false
|
openMenu = false
|
||||||
|
|||||||
@@ -128,3 +128,52 @@
|
|||||||
<Check bind:check={$DataBase.instantRemove}/>
|
<Check bind:check={$DataBase.instantRemove}/>
|
||||||
<span>{language.instantRemove}</span>
|
<span>{language.instantRemove}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{#if $DataBase.textScreenColor}
|
||||||
|
<div class="flex items-center mt-2">
|
||||||
|
<Check check={true} onChange={() => {
|
||||||
|
$DataBase.textScreenColor = null
|
||||||
|
}}/>
|
||||||
|
<input type="color" class="style2 text-sm mr-2" bind:value={$DataBase.textScreenColor} >
|
||||||
|
<span>{language.textBackgrounds}</span>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<div class="flex items-center mt-2">
|
||||||
|
<Check check={false} onChange={() => {
|
||||||
|
$DataBase.textScreenColor = "#121212"
|
||||||
|
}}/>
|
||||||
|
<span>{language.textBackgrounds}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div class="flex items-center mt-2">
|
||||||
|
<Check bind:check={$DataBase.textBorder}/>
|
||||||
|
<span>{language.textBorder}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="flex items-center mt-2">
|
||||||
|
<Check bind:check={$DataBase.textScreenRounded}/>
|
||||||
|
<span>{language.textScreenRound}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if $DataBase.textScreenBorder}
|
||||||
|
<div class="flex items-center mt-2">
|
||||||
|
<Check check={true} onChange={() => {
|
||||||
|
$DataBase.textScreenBorder = null
|
||||||
|
}}/>
|
||||||
|
<input type="color" class="style2 text-sm mr-2" bind:value={$DataBase.textScreenBorder} >
|
||||||
|
<span>{language.textScreenBorder}</span>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<div class="flex items-center mt-2">
|
||||||
|
<Check check={false} onChange={() => {
|
||||||
|
$DataBase.textScreenBorder = "#121212"
|
||||||
|
}}/>
|
||||||
|
<span>{language.textScreenBorder}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/if}
|
||||||
@@ -498,6 +498,12 @@
|
|||||||
</select>
|
</select>
|
||||||
{/await}
|
{/await}
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if currentChar.data.ttsMode === 'webspeech' || currentChar.data.ttsMode === 'elevenlab'}
|
||||||
|
<div class="flex items-center mt-2">
|
||||||
|
<Check bind:check={currentChar.data.ttsReadOnlyQuoted}/>
|
||||||
|
<span>{language.ttsReadOnlyQuoted}</span>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
{:else if subMenu === 2}
|
{:else if subMenu === 2}
|
||||||
<h2 class="mb-2 text-2xl font-bold mt-2">{language.advancedSettings}</h2>
|
<h2 class="mb-2 text-2xl font-bold mt-2">{language.advancedSettings}</h2>
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
}
|
}
|
||||||
async function createImport() {
|
async function createImport() {
|
||||||
reseter();
|
reseter();
|
||||||
const cid = await importCharacter();
|
await importCharacter();
|
||||||
selectedCharID.set(-1);
|
selectedCharID.set(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
import { alertConfirm, alertError, alertNormal, alertSelect, alertStore } from "./alert"
|
import { alertConfirm, alertError, alertNormal, alertSelect, alertStore } from "./alert"
|
||||||
import { DataBase, defaultSdDataFunc, type character, setDatabase, type customscript, type loreSettings, type loreBook } from "./database"
|
import { DataBase, defaultSdDataFunc, type character, setDatabase, type customscript, type loreSettings, type loreBook } from "./database"
|
||||||
import { checkNullish, selectSingleFile, sleep } from "./util"
|
import { checkNullish, selectMultipleFile, selectSingleFile, sleep } from "./util"
|
||||||
import { language } from "src/lang"
|
import { language } from "src/lang"
|
||||||
import { encode as encodeMsgpack, decode as decodeMsgpack } from "@msgpack/msgpack";
|
import { encode as encodeMsgpack, decode as decodeMsgpack } from "@msgpack/msgpack";
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
@@ -14,96 +14,13 @@ import { cloneDeep } from "lodash"
|
|||||||
|
|
||||||
export async function importCharacter() {
|
export async function importCharacter() {
|
||||||
try {
|
try {
|
||||||
const f = await selectSingleFile(['png', 'json'])
|
const files = await selectMultipleFile(['png', 'json'])
|
||||||
if(!f){
|
if(!files){
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if(f.name.endsWith('json')){
|
|
||||||
const da = JSON.parse(Buffer.from(f.data).toString('utf-8'))
|
|
||||||
if(await importSpecv2(da)){
|
|
||||||
let db = get(DataBase)
|
|
||||||
return db.characters.length - 1
|
|
||||||
}
|
|
||||||
if((da.char_name || da.name) && (da.char_persona || da.description) && (da.char_greeting || da.first_mes)){
|
|
||||||
let db = get(DataBase)
|
|
||||||
db.characters.push(convertOldTavernAndJSON(da))
|
|
||||||
DataBase.set(db)
|
|
||||||
alertNormal(language.importedCharacter)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
alertError(language.errors.noData)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
alertStore.set({
|
|
||||||
type: 'wait',
|
|
||||||
msg: 'Loading... (Reading)'
|
|
||||||
})
|
|
||||||
await sleep(10)
|
|
||||||
const img = f.data
|
|
||||||
const readed = (await exifr.parse(img, true))
|
|
||||||
if(readed.chara){
|
|
||||||
// standard spec v2 imports
|
|
||||||
const charaData:CharacterCardV2 = JSON.parse(Buffer.from(readed.chara, 'base64').toString('utf-8'))
|
|
||||||
if(await importSpecv2(charaData, img)){
|
|
||||||
let db = get(DataBase)
|
|
||||||
return db.characters.length - 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(readed.risuai){
|
|
||||||
// old risu imports
|
|
||||||
await sleep(10)
|
|
||||||
const va = decodeMsgpack(Buffer.from(readed.risuai, 'base64')) as any
|
|
||||||
if(va.type !== 101){
|
|
||||||
alertError(language.errors.noData)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let char:character = va.data
|
for(const f of files){
|
||||||
let db = get(DataBase)
|
await importCharacterProcess(f)
|
||||||
if(char.emotionImages && char.emotionImages.length > 0){
|
|
||||||
for(let i=0;i<char.emotionImages.length;i++){
|
|
||||||
alertStore.set({
|
|
||||||
type: 'wait',
|
|
||||||
msg: `Loading... (Getting Emotions ${i} / ${char.emotionImages.length})`
|
|
||||||
})
|
|
||||||
await sleep(10)
|
|
||||||
const imgp = await saveAsset(char.emotionImages[i][1] as any)
|
|
||||||
char.emotionImages[i][1] = imgp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
char.chats = [{
|
|
||||||
message: [],
|
|
||||||
note: '',
|
|
||||||
name: 'Chat 1',
|
|
||||||
localLore: []
|
|
||||||
}]
|
|
||||||
|
|
||||||
if(checkNullish(char.sdData)){
|
|
||||||
char.sdData = defaultSdDataFunc()
|
|
||||||
}
|
|
||||||
|
|
||||||
char.chatPage = 0
|
|
||||||
char.image = await saveAsset(PngMetadata.filter(img))
|
|
||||||
db.characters.push(characterFormatUpdate(char))
|
|
||||||
char.chaId = uuidv4()
|
|
||||||
setDatabase(db)
|
|
||||||
alertNormal(language.importedCharacter)
|
|
||||||
return db.characters.length - 1
|
|
||||||
}
|
|
||||||
else if(readed.chara){
|
|
||||||
const charaData:OldTavernChar = JSON.parse(Buffer.from(readed.chara, 'base64').toString('utf-8'))
|
|
||||||
const imgp = await saveAsset(PngMetadata.filter(img))
|
|
||||||
let db = get(DataBase)
|
|
||||||
db.characters.push(convertOldTavernAndJSON(charaData, imgp))
|
|
||||||
DataBase.set(db)
|
|
||||||
alertNormal(language.importedCharacter)
|
|
||||||
return db.characters.length - 1
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
alertError(language.errors.noData)
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
alertError(`${error}`)
|
alertError(`${error}`)
|
||||||
@@ -111,6 +28,99 @@ export async function importCharacter() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function importCharacterProcess(f:{
|
||||||
|
name: string;
|
||||||
|
data: Uint8Array;
|
||||||
|
}) {
|
||||||
|
if(f.name.endsWith('json')){
|
||||||
|
const da = JSON.parse(Buffer.from(f.data).toString('utf-8'))
|
||||||
|
if(await importSpecv2(da)){
|
||||||
|
let db = get(DataBase)
|
||||||
|
return db.characters.length - 1
|
||||||
|
}
|
||||||
|
if((da.char_name || da.name) && (da.char_persona || da.description) && (da.char_greeting || da.first_mes)){
|
||||||
|
let db = get(DataBase)
|
||||||
|
db.characters.push(convertOldTavernAndJSON(da))
|
||||||
|
DataBase.set(db)
|
||||||
|
alertNormal(language.importedCharacter)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
alertError(language.errors.noData)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
alertStore.set({
|
||||||
|
type: 'wait',
|
||||||
|
msg: 'Loading... (Reading)'
|
||||||
|
})
|
||||||
|
await sleep(10)
|
||||||
|
const img = f.data
|
||||||
|
const readed = (await exifr.parse(img, true))
|
||||||
|
if(readed.chara){
|
||||||
|
// standard spec v2 imports
|
||||||
|
const charaData:CharacterCardV2 = JSON.parse(Buffer.from(readed.chara, 'base64').toString('utf-8'))
|
||||||
|
if(await importSpecv2(charaData, img)){
|
||||||
|
let db = get(DataBase)
|
||||||
|
return db.characters.length - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(readed.risuai){
|
||||||
|
// old risu imports
|
||||||
|
await sleep(10)
|
||||||
|
const va = decodeMsgpack(Buffer.from(readed.risuai, 'base64')) as any
|
||||||
|
if(va.type !== 101){
|
||||||
|
alertError(language.errors.noData)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let char:character = va.data
|
||||||
|
let db = get(DataBase)
|
||||||
|
if(char.emotionImages && char.emotionImages.length > 0){
|
||||||
|
for(let i=0;i<char.emotionImages.length;i++){
|
||||||
|
alertStore.set({
|
||||||
|
type: 'wait',
|
||||||
|
msg: `Loading... (Getting Emotions ${i} / ${char.emotionImages.length})`
|
||||||
|
})
|
||||||
|
await sleep(10)
|
||||||
|
const imgp = await saveAsset(char.emotionImages[i][1] as any)
|
||||||
|
char.emotionImages[i][1] = imgp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char.chats = [{
|
||||||
|
message: [],
|
||||||
|
note: '',
|
||||||
|
name: 'Chat 1',
|
||||||
|
localLore: []
|
||||||
|
}]
|
||||||
|
|
||||||
|
if(checkNullish(char.sdData)){
|
||||||
|
char.sdData = defaultSdDataFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
char.chatPage = 0
|
||||||
|
char.image = await saveAsset(PngMetadata.filter(img))
|
||||||
|
db.characters.push(characterFormatUpdate(char))
|
||||||
|
char.chaId = uuidv4()
|
||||||
|
setDatabase(db)
|
||||||
|
alertNormal(language.importedCharacter)
|
||||||
|
return db.characters.length - 1
|
||||||
|
}
|
||||||
|
else if(readed.chara){
|
||||||
|
const charaData:OldTavernChar = JSON.parse(Buffer.from(readed.chara, 'base64').toString('utf-8'))
|
||||||
|
const imgp = await saveAsset(PngMetadata.filter(img))
|
||||||
|
let db = get(DataBase)
|
||||||
|
db.characters.push(convertOldTavernAndJSON(charaData, imgp))
|
||||||
|
DataBase.set(db)
|
||||||
|
alertNormal(language.importedCharacter)
|
||||||
|
return db.characters.length - 1
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
alertError(language.errors.noData)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function characterHubImport() {
|
export async function characterHubImport() {
|
||||||
const charPath = (new URLSearchParams(location.search)).get('charahub')
|
const charPath = (new URLSearchParams(location.search)).get('charahub')
|
||||||
try {
|
try {
|
||||||
@@ -262,10 +272,10 @@ export async function exportChar(charaID:number) {
|
|||||||
create_date: `${Date.now()}`,
|
create_date: `${Date.now()}`,
|
||||||
description: char.desc,
|
description: char.desc,
|
||||||
first_mes: char.firstMessage,
|
first_mes: char.firstMessage,
|
||||||
mes_example: "<START>",
|
mes_example: char.exampleMessage ?? "<START>",
|
||||||
name: char.name,
|
name: char.name,
|
||||||
personality: "",
|
personality: char.personality ?? "",
|
||||||
scenario: "",
|
scenario: char.scenario ?? "",
|
||||||
talkativeness: "0.5"
|
talkativeness: "0.5"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -580,8 +590,8 @@ interface OldTavernChar{
|
|||||||
first_mes: string
|
first_mes: string
|
||||||
mes_example: string
|
mes_example: string
|
||||||
name: string
|
name: string
|
||||||
personality: ""
|
personality: string
|
||||||
scenario: ""
|
scenario: string
|
||||||
talkativeness: "0.5"
|
talkativeness: "0.5"
|
||||||
}
|
}
|
||||||
type CharacterBook = {
|
type CharacterBook = {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { cloneDeep } from 'lodash';
|
|||||||
|
|
||||||
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.13.2'
|
export let appVer = '1.14.0'
|
||||||
|
|
||||||
|
|
||||||
export function setDatabase(data:Database){
|
export function setDatabase(data:Database){
|
||||||
@@ -284,6 +284,7 @@ export interface character{
|
|||||||
ttsSpeech?:string
|
ttsSpeech?:string
|
||||||
supaMemory?:boolean
|
supaMemory?:boolean
|
||||||
additionalAssets?:[string, string][]
|
additionalAssets?:[string, string][]
|
||||||
|
ttsReadOnlyQuoted?:boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -315,6 +316,7 @@ export interface groupChat{
|
|||||||
firstMsgIndex?:number,
|
firstMsgIndex?:number,
|
||||||
loreSettings?:loreSettings
|
loreSettings?:loreSettings
|
||||||
supaMemory?:boolean
|
supaMemory?:boolean
|
||||||
|
ttsMode?:string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface botPreset{
|
export interface botPreset{
|
||||||
@@ -418,6 +420,10 @@ export interface Database{
|
|||||||
palmAPI:string,
|
palmAPI:string,
|
||||||
supaMemoryKey:string
|
supaMemoryKey:string
|
||||||
supaMemoryType:string
|
supaMemoryType:string
|
||||||
|
textScreenColor?:string
|
||||||
|
textBorder?:boolean
|
||||||
|
textScreenRounded?:boolean
|
||||||
|
textScreenBorder?:string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -350,13 +350,15 @@ export async function sendChat(chatProcessIndex = -1):Promise<boolean> {
|
|||||||
while(true){
|
while(true){
|
||||||
const readed = (await reader.read())
|
const readed = (await reader.read())
|
||||||
if(readed.value){
|
if(readed.value){
|
||||||
db.characters[selectedChar].chats[selectedChat].message[msgIndex].data =readed.value
|
result = readed.value
|
||||||
|
db.characters[selectedChar].chats[selectedChat].message[msgIndex].data = result
|
||||||
setDatabase(db)
|
setDatabase(db)
|
||||||
}
|
}
|
||||||
if(readed.done){
|
if(readed.done){
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
await sayTTS(currentChar, result)
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
const result2 = processScriptFull(currentChar, reformatContent(req.result), 'editoutput')
|
const result2 = processScriptFull(currentChar, reformatContent(req.result), 'editoutput')
|
||||||
|
|||||||
@@ -2,11 +2,23 @@ import { get } from "svelte/store";
|
|||||||
import { alertError } from "../alert";
|
import { alertError } from "../alert";
|
||||||
import { DataBase, type character } from "../database";
|
import { DataBase, type character } from "../database";
|
||||||
|
|
||||||
|
let sourceNode:AudioBufferSourceNode = null
|
||||||
|
|
||||||
export async function sayTTS(character:character,text:string) {
|
export async function sayTTS(character:character,text:string) {
|
||||||
|
|
||||||
let db = get(DataBase)
|
let db = get(DataBase)
|
||||||
text = text.replace(/\*/g,'')
|
text = text.replace(/\*/g,'')
|
||||||
|
|
||||||
|
if(character.ttsReadOnlyQuoted){
|
||||||
|
const matches = text.match(/"(.*?)"/g)
|
||||||
|
if(matches.length > 0){
|
||||||
|
text = matches.map(match => match.slice(1, -1)).join("");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
text = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch(character.ttsMode){
|
switch(character.ttsMode){
|
||||||
case "webspeech":{
|
case "webspeech":{
|
||||||
if(speechSynthesis && SpeechSynthesisUtterance){
|
if(speechSynthesis && SpeechSynthesisUtterance){
|
||||||
@@ -19,7 +31,7 @@ export async function sayTTS(character:character,text:string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
utterThis.voice = voices[voiceIndex]
|
utterThis.voice = voices[voiceIndex]
|
||||||
speechSynthesis.speak(utterThis)
|
const speak = speechSynthesis.speak(utterThis)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -37,7 +49,7 @@ export async function sayTTS(character:character,text:string) {
|
|||||||
})
|
})
|
||||||
if(da.status >= 200 && da.status < 300){
|
if(da.status >= 200 && da.status < 300){
|
||||||
const audioBuffer = await audioContext.decodeAudioData(await da.arrayBuffer())
|
const audioBuffer = await audioContext.decodeAudioData(await da.arrayBuffer())
|
||||||
const sourceNode = audioContext.createBufferSource();
|
sourceNode = audioContext.createBufferSource();
|
||||||
sourceNode.buffer = audioBuffer;
|
sourceNode.buffer = audioBuffer;
|
||||||
sourceNode.connect(audioContext.destination);
|
sourceNode.connect(audioContext.destination);
|
||||||
sourceNode.start();
|
sourceNode.start();
|
||||||
@@ -50,6 +62,15 @@ export async function sayTTS(character:character,text:string) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function stopTTS(){
|
||||||
|
if(sourceNode){
|
||||||
|
sourceNode.stop()
|
||||||
|
}
|
||||||
|
if(speechSynthesis && SpeechSynthesisUtterance){
|
||||||
|
speechSynthesis.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export function getWebSpeechTTSVoices() {
|
export function getWebSpeechTTSVoices() {
|
||||||
return speechSynthesis.getVoices().map(v => {
|
return speechSynthesis.getVoices().map(v => {
|
||||||
|
|||||||
3
todo.txt
3
todo.txt
@@ -11,3 +11,6 @@
|
|||||||
플러그인:
|
플러그인:
|
||||||
일단 되게 만들기
|
일단 되게 만들기
|
||||||
|
|
||||||
|
TTS 개선:
|
||||||
|
나레이션 분리하기
|
||||||
|
나레이션 중지 만들기
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":"1.13.2"}
|
{"version":"1.14.0"}
|
||||||
@@ -53,6 +53,7 @@ export default defineConfig(async () => {
|
|||||||
minify: process.env.TAURI_DEBUG ? false : 'esbuild',
|
minify: process.env.TAURI_DEBUG ? false : 'esbuild',
|
||||||
// produce sourcemaps for debug builds
|
// produce sourcemaps for debug builds
|
||||||
sourcemap: !!process.env.TAURI_DEBUG,
|
sourcemap: !!process.env.TAURI_DEBUG,
|
||||||
|
chunkSizeWarningLimit: 2000
|
||||||
},
|
},
|
||||||
|
|
||||||
resolve:{
|
resolve:{
|
||||||
|
|||||||
Reference in New Issue
Block a user