Merge branch 'main' of https://github.com/kwaroran/RisuAI
This commit is contained in:
@@ -304,6 +304,8 @@ export const languageChinese = {
|
|||||||
tags: "标签",
|
tags: "标签",
|
||||||
copied: "已复制",
|
copied: "已复制",
|
||||||
useChatCopy: "使用聊天复制",
|
useChatCopy: "使用聊天复制",
|
||||||
|
useChatSticker: "使用聊天贴纸",
|
||||||
|
useAdditionalAssetsPreview: "使用附加资源预览",
|
||||||
autoTranslateInput: "使用自动翻译输入",
|
autoTranslateInput: "使用自动翻译输入",
|
||||||
enterMessageForTranslateToEnglish: "输入要翻译为英语的消息",
|
enterMessageForTranslateToEnglish: "输入要翻译为英语的消息",
|
||||||
recent: '最新',
|
recent: '最新',
|
||||||
|
|||||||
@@ -308,6 +308,8 @@ export const languageEnglish = {
|
|||||||
backgroundHTML: "Background Embedding",
|
backgroundHTML: "Background Embedding",
|
||||||
copied: "Copied",
|
copied: "Copied",
|
||||||
useChatCopy: "Use Chat Message Copy",
|
useChatCopy: "Use Chat Message Copy",
|
||||||
|
useChatSticker: "Use Chat Sticker",
|
||||||
|
useAdditionalAssetsPreview: "Use Additional Assets Preview",
|
||||||
autoTranslateInput: "Auto Translate Input",
|
autoTranslateInput: "Auto Translate Input",
|
||||||
enterMessageForTranslateToEnglish: "Enter Message for Translate to English",
|
enterMessageForTranslateToEnglish: "Enter Message for Translate to English",
|
||||||
recent: 'Recent',
|
recent: 'Recent',
|
||||||
|
|||||||
@@ -280,6 +280,8 @@ export const languageKorean = {
|
|||||||
backgroundHTML: "백그라운드 임베딩",
|
backgroundHTML: "백그라운드 임베딩",
|
||||||
copied: "복사됨",
|
copied: "복사됨",
|
||||||
useChatCopy: "채팅 메시지 복사 사용",
|
useChatCopy: "채팅 메시지 복사 사용",
|
||||||
|
useChatSticker: "채팅 스티커 사용",
|
||||||
|
useAdditionalAssetsPreview: "추가 에셋 미리보기 사용",
|
||||||
autoTranslateInput: "입력 자동 번역",
|
autoTranslateInput: "입력 자동 번역",
|
||||||
enterMessageForTranslateToEnglish: "영어로 번역할 메시지를 입력해주세요",
|
enterMessageForTranslateToEnglish: "영어로 번역할 메시지를 입력해주세요",
|
||||||
imageCompression: "이미지 압축",
|
imageCompression: "이미지 압축",
|
||||||
|
|||||||
75
src/lib/ChatScreens/AssetInput.svelte
Normal file
75
src/lib/ChatScreens/AssetInput.svelte
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { get } from 'svelte/store';
|
||||||
|
import { FileAudioIcon, PlusIcon } from "lucide-svelte";
|
||||||
|
import { DataBase, setDatabase, type character, type groupChat } from "src/ts/storage/database";
|
||||||
|
import { getFileSrc, saveAsset } from "src/ts/storage/globalApi";
|
||||||
|
import { selectMultipleFile } from "src/ts/util";
|
||||||
|
export let currentCharacter:character|groupChat;
|
||||||
|
export let onSelect:(additionalAsset:[string,string,string])=>void;
|
||||||
|
let assetFileExtensions:string[] = []
|
||||||
|
let assetFilePath:string[] = []
|
||||||
|
|
||||||
|
$:{
|
||||||
|
if(currentCharacter.type ==='character'){
|
||||||
|
if(currentCharacter.additionalAssets){
|
||||||
|
for(let i = 0; i < currentCharacter.additionalAssets.length; i++){
|
||||||
|
// console.log('check content type ...', currentCharacter.additionalAssets[i][0], currentCharacter.additionalAssets[i][1]);
|
||||||
|
if(currentCharacter.additionalAssets[i].length > 2 && currentCharacter.additionalAssets[i][2]) {
|
||||||
|
assetFileExtensions[i] = currentCharacter.additionalAssets[i][2]
|
||||||
|
} else {
|
||||||
|
assetFileExtensions[i] = currentCharacter.additionalAssets[i][1].split('.').pop()
|
||||||
|
}
|
||||||
|
getFileSrc(currentCharacter.additionalAssets[i][1]).then((filePath) => {
|
||||||
|
assetFilePath[i] = filePath
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{#if currentCharacter.type ==='character'}
|
||||||
|
<button class="hover:text-green-500 bg-gray-500 flex justify-center items-center w-16 h-16 m-1 rounded-md" on:click={async () => {
|
||||||
|
if(currentCharacter.type === 'character'){
|
||||||
|
const da = await selectMultipleFile(['png', 'webp', 'mp4', 'mp3', 'gif'])
|
||||||
|
currentCharacter.additionalAssets = currentCharacter.additionalAssets ?? []
|
||||||
|
if(!da){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for(const f of da){
|
||||||
|
console.log(f)
|
||||||
|
const img = f.data
|
||||||
|
const name = f.name
|
||||||
|
const extension = name.split('.').pop().toLowerCase()
|
||||||
|
const imgp = await saveAsset(img,'',extension)
|
||||||
|
currentCharacter.additionalAssets.push([name, imgp, extension])
|
||||||
|
currentCharacter = currentCharacter
|
||||||
|
}
|
||||||
|
const db = get(DataBase);
|
||||||
|
setDatabase(db)
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
<PlusIcon />
|
||||||
|
</button>
|
||||||
|
{#if currentCharacter.additionalAssets}
|
||||||
|
{#each currentCharacter.additionalAssets as additionalAsset, i}
|
||||||
|
<button on:click={()=>{
|
||||||
|
onSelect(additionalAsset)
|
||||||
|
}}>
|
||||||
|
{#if assetFilePath[i]}
|
||||||
|
{#if assetFileExtensions[i] === 'mp4'}
|
||||||
|
<!-- svelte-ignore a11y-media-has-caption -->
|
||||||
|
<video class="w-16 h-16 m-1 rounded-md"><source src={assetFilePath[i]} type="video/mp4"></video>
|
||||||
|
{:else if assetFileExtensions[i] === 'mp3'}
|
||||||
|
<div class='w-16 h-16 m-1 rounded-md bg-slate-500 flex flex-col justify-center items-center'>
|
||||||
|
<FileAudioIcon/>
|
||||||
|
<div class='w-16 px-1 text-ellipsis whitespace-nowrap overflow-hidden'>{additionalAsset[0]}</div>
|
||||||
|
</div>
|
||||||
|
<!-- <audio controls class="w-16 h-16 m-1 rounded-md"><source src={assetPath} type="audio/mpeg"></audio> -->
|
||||||
|
{:else}
|
||||||
|
<img src={assetFilePath[i]} class="w-16 h-16 m-1 rounded-md" alt={additionalAsset[0]}/>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
import { selectedCharID } from "../../ts/stores";
|
import { selectedCharID } from "../../ts/stores";
|
||||||
import { translate } from "../../ts/translator/translator";
|
import { translate } from "../../ts/translator/translator";
|
||||||
import { replacePlaceholders } from "../../ts/util";
|
import { replacePlaceholders } from "../../ts/util";
|
||||||
|
|
||||||
export let message = ''
|
export let message = ''
|
||||||
export let name = ''
|
export let name = ''
|
||||||
export let isLastMemory:boolean
|
export let isLastMemory:boolean
|
||||||
@@ -17,6 +18,7 @@
|
|||||||
export let onReroll = () => {}
|
export let onReroll = () => {}
|
||||||
export let unReroll = () => {}
|
export let unReroll = () => {}
|
||||||
export let character:character|groupChat|null = null
|
export let character:character|groupChat|null = null
|
||||||
|
let md:string
|
||||||
let translating = false
|
let translating = false
|
||||||
let editMode = false
|
let editMode = false
|
||||||
let statusMessage:string = ''
|
let statusMessage:string = ''
|
||||||
@@ -24,7 +26,8 @@
|
|||||||
|
|
||||||
let msgDisplay = ''
|
let msgDisplay = ''
|
||||||
let msgTranslated = ''
|
let msgTranslated = ''
|
||||||
let translated = false;
|
let translated = false
|
||||||
|
|
||||||
async function rm(){
|
async function rm(){
|
||||||
const rm = $DataBase.askRemoval ? await alertConfirm(language.removeChat) : true
|
const rm = $DataBase.askRemoval ? await alertConfirm(language.removeChat) : true
|
||||||
if(rm){
|
if(rm){
|
||||||
@@ -53,7 +56,7 @@
|
|||||||
$DataBase.characters[$selectedCharID].chats[$DataBase.characters[$selectedCharID].chatPage].message = msg
|
$DataBase.characters[$selectedCharID].chats[$DataBase.characters[$selectedCharID].chatPage].message = msg
|
||||||
}
|
}
|
||||||
|
|
||||||
async function displaya(message:string){
|
async function displaya(message:string, isStreaming:boolean = false){
|
||||||
if($DataBase.autoTranslate && $DataBase.translator !== ''){
|
if($DataBase.autoTranslate && $DataBase.translator !== ''){
|
||||||
if(msgTranslated==='')
|
if(msgTranslated==='')
|
||||||
msgDisplay = replacePlaceholders(message, name)
|
msgDisplay = replacePlaceholders(message, name)
|
||||||
@@ -64,6 +67,12 @@
|
|||||||
else{
|
else{
|
||||||
msgDisplay = replacePlaceholders(message, name)
|
msgDisplay = replacePlaceholders(message, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!md || !isStreaming || isStreaming && idx === $DataBase.characters[$selectedCharID].chats[$DataBase.characters[$selectedCharID].chatPage].message.length - 1) {
|
||||||
|
ParseMarkdown(msgDisplay, character, 'normal').then(mdNew=>{
|
||||||
|
md = mdNew
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const setStatusMessage = (message:string, timeout:number = 0)=>{
|
const setStatusMessage = (message:string, timeout:number = 0)=>{
|
||||||
@@ -74,7 +83,7 @@
|
|||||||
}, timeout)
|
}, timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
$: displaya(message)
|
$: displaya(message, $DataBase.characters[$selectedCharID].chats[$DataBase.characters[$selectedCharID].chatPage].isStreaming)
|
||||||
</script>
|
</script>
|
||||||
<div class="flex max-w-full justify-center" class:bgc={isLastMemory}>
|
<div class="flex max-w-full justify-center" class:bgc={isLastMemory}>
|
||||||
<div class="text-neutral-200 mt-1 ml-4 mr-4 mb-1 p-2 bg-transparent flex-grow border-t-gray-900 border-opacity-30 border-transparent flexium items-start max-w-full" >
|
<div class="text-neutral-200 mt-1 ml-4 mr-4 mb-1 p-2 bg-transparent flex-grow border-t-gray-900 border-opacity-30 border-transparent flexium items-start max-w-full" >
|
||||||
@@ -161,19 +170,17 @@
|
|||||||
</div>
|
</div>
|
||||||
{#if editMode}
|
{#if editMode}
|
||||||
<AutoresizeArea bind:value={message} />
|
<AutoresizeArea bind:value={message} />
|
||||||
{:else}
|
{:else if md}
|
||||||
{#await ParseMarkdown(msgDisplay, character) then md}
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
<span class="text chat chattext prose prose-invert minw-0" on:click={() => {
|
||||||
<span class="text chat chattext prose prose-invert minw-0" on:click={() => {
|
if($DataBase.clickToEdit && idx > -1){
|
||||||
if($DataBase.clickToEdit && idx > -1){
|
editMode = true
|
||||||
editMode = true
|
msgTranslated = ""
|
||||||
msgTranslated = ""
|
}
|
||||||
}
|
}}
|
||||||
}}
|
style:font-size="{0.875 * ($DataBase.zoomsize / 100)}rem"
|
||||||
style:font-size="{0.875 * ($DataBase.zoomsize / 100)}rem"
|
style:line-height="{1.25 * ($DataBase.zoomsize / 100)}rem"
|
||||||
style:line-height="{1.25 * ($DataBase.zoomsize / 100)}rem"
|
>{@html md}</span>
|
||||||
>{@html md}</span>
|
|
||||||
{/await}
|
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Suggestion from './Suggestion.svelte';
|
import Suggestion from './Suggestion.svelte';
|
||||||
import { DatabaseIcon, DicesIcon, LanguagesIcon, MenuIcon, MicOffIcon, PowerIcon, RefreshCcwIcon, ReplyIcon, Send } from "lucide-svelte";
|
import { DatabaseIcon, DicesIcon, LanguagesIcon, Laugh, MenuIcon, MicOffIcon, RefreshCcwIcon, ReplyIcon, 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, type Message } from "../../ts/storage/database";
|
import { DataBase, type Message, type character, type groupChat } from "../../ts/storage/database";
|
||||||
import { getCharImage } from "../../ts/characters";
|
import { getCharImage } from "../../ts/characters";
|
||||||
import { doingChat, sendChat } from "../../ts/process/index";
|
import { doingChat, sendChat } from "../../ts/process/index";
|
||||||
import { findCharacterbyId, messageForm, sleep } from "../../ts/util";
|
import { findCharacterbyId, messageForm, sleep } from "../../ts/util";
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
import { stopTTS } from "src/ts/process/tts";
|
import { stopTTS } from "src/ts/process/tts";
|
||||||
import MainMenu from '../UI/MainMenu.svelte';
|
import MainMenu from '../UI/MainMenu.svelte';
|
||||||
import Help from '../Others/Help.svelte';
|
import Help from '../Others/Help.svelte';
|
||||||
|
import AssetInput from './AssetInput.svelte';
|
||||||
|
|
||||||
let messageInput:string = ''
|
let messageInput:string = ''
|
||||||
let messageInputTranslate:string = ''
|
let messageInputTranslate:string = ''
|
||||||
@@ -28,6 +29,8 @@
|
|||||||
let rerollid = -1
|
let rerollid = -1
|
||||||
let lastCharId = -1
|
let lastCharId = -1
|
||||||
let doingChatInputTranslate = false
|
let doingChatInputTranslate = false
|
||||||
|
let currentCharacter:character|groupChat = $DataBase.characters[$selectedCharID]
|
||||||
|
let toggleStickers:boolean = false
|
||||||
|
|
||||||
async function send() {
|
async function send() {
|
||||||
let selectedChar = $selectedCharID
|
let selectedChar = $selectedCharID
|
||||||
@@ -218,6 +221,10 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: {
|
||||||
|
currentCharacter = $DataBase.characters[$selectedCharID]
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<div class="w-full h-full" style={customStyle} on:click={() => {
|
<div class="w-full h-full" style={customStyle} on:click={() => {
|
||||||
@@ -234,6 +241,12 @@
|
|||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
<div class="flex items-end mt-2 mb-2 w-full">
|
<div class="flex items-end mt-2 mb-2 w-full">
|
||||||
|
{#if $DataBase.useChatSticker && currentCharacter.type !== 'group'}
|
||||||
|
<div on:click={()=>{toggleStickers = !toggleStickers}}
|
||||||
|
class={"ml-4 bg-gray-500 flex justify-center items-center w-12 h-12 rounded-md hover:bg-green-500 transition-colors "+(toggleStickers ? 'text-green-500':'text-white')}>
|
||||||
|
<Laugh/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
<textarea class="text-neutral-200 p-2 min-w-0 bg-transparent input-text text-xl flex-grow ml-4 mr-2 border-gray-700 resize-none focus:bg-selected overflow-y-hidden overflow-x-hidden max-w-full"
|
<textarea class="text-neutral-200 p-2 min-w-0 bg-transparent input-text text-xl flex-grow ml-4 mr-2 border-gray-700 resize-none focus:bg-selected overflow-y-hidden overflow-x-hidden max-w-full"
|
||||||
bind:value={messageInput}
|
bind:value={messageInput}
|
||||||
bind:this={inputEle}
|
bind:this={inputEle}
|
||||||
@@ -299,9 +312,27 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
{#if toggleStickers}
|
||||||
|
<div class="ml-4 flex flex-wrap">
|
||||||
|
<AssetInput bind:currentCharacter={currentCharacter} onSelect={(additionalAsset)=>{
|
||||||
|
let fileType = 'img'
|
||||||
|
if(additionalAsset.length > 2 && additionalAsset[2]) {
|
||||||
|
const fileExtension = additionalAsset[2]
|
||||||
|
if(fileExtension === 'mp4' || fileExtension === 'webm')
|
||||||
|
fileType = 'video'
|
||||||
|
else if(fileExtension === 'mp3' || fileExtension === 'wav')
|
||||||
|
fileType = 'audio'
|
||||||
|
}
|
||||||
|
messageInput += `<span class='notranslate' translate='no'>{{${fileType}::${additionalAsset[0]}}}</span> *${additionalAsset[0]} added*`
|
||||||
|
updateInputSizeAll()
|
||||||
|
}}/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if $DataBase.useAutoSuggestions}
|
{#if $DataBase.useAutoSuggestions}
|
||||||
<Suggestion messageInput={(msg)=>messageInput=msg} {send}/>
|
<Suggestion messageInput={(msg)=>messageInput=msg} {send}/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#each messageForm($DataBase.characters[$selectedCharID].chats[$DataBase.characters[$selectedCharID].chatPage].message, loadPages) as chat, i}
|
{#each messageForm($DataBase.characters[$selectedCharID].chats[$DataBase.characters[$selectedCharID].chatPage].message, loadPages) as chat, i}
|
||||||
{#if chat.role === 'char'}
|
{#if chat.role === 'char'}
|
||||||
{#if $DataBase.characters[$selectedCharID].type !== 'group'}
|
{#if $DataBase.characters[$selectedCharID].type !== 'group'}
|
||||||
|
|||||||
@@ -141,4 +141,15 @@
|
|||||||
|
|
||||||
<div class="flex items-center mt-2">
|
<div class="flex items-center mt-2">
|
||||||
<Check bind:check={$DataBase.useChatCopy} name={language.useChatCopy}/>
|
<Check bind:check={$DataBase.useChatCopy} name={language.useChatCopy}/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center mt-2">
|
||||||
|
<Check bind:check={$DataBase.useAdditionalAssetsPreview} name={language.useAdditionalAssetsPreview}/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if $DataBase.useExperimental}
|
||||||
|
<div class="flex items-center mt-2">
|
||||||
|
<Check bind:check={$DataBase.useChatSticker} name={language.useChatSticker}/>
|
||||||
|
<Help key="experimental" name={language.useChatSticker}/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
import RegexData from "./RegexData.svelte";
|
import RegexData from "./RegexData.svelte";
|
||||||
import { exportChar, shareRisuHub } from "src/ts/characterCards";
|
import { exportChar, shareRisuHub } from "src/ts/characterCards";
|
||||||
import { getElevenTTSVoices, getWebSpeechTTSVoices, getVOICEVOXVoices } from "src/ts/process/tts";
|
import { getElevenTTSVoices, getWebSpeechTTSVoices, getVOICEVOXVoices } from "src/ts/process/tts";
|
||||||
import { checkCharOrder } from "src/ts/storage/globalApi";
|
import { checkCharOrder, getFileSrc } from "src/ts/storage/globalApi";
|
||||||
import { addGroupChar, rmCharFromGroup } from "src/ts/process/group";
|
import { addGroupChar, rmCharFromGroup } from "src/ts/process/group";
|
||||||
import HubUpload from "../UI/HubUpload.svelte";
|
import HubUpload from "../UI/HubUpload.svelte";
|
||||||
|
|
||||||
@@ -95,7 +95,9 @@
|
|||||||
currentChar = currentChar
|
currentChar = currentChar
|
||||||
})
|
})
|
||||||
|
|
||||||
|
let assetFileExtensions:string[] = []
|
||||||
|
let assetFilePath:string[] = []
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if(database.characters[$selectedCharID].chaId === currentChar.data.chaId){
|
if(database.characters[$selectedCharID].chaId === currentChar.data.chaId){
|
||||||
database.characters[$selectedCharID] = currentChar.data
|
database.characters[$selectedCharID] = currentChar.data
|
||||||
@@ -106,6 +108,20 @@
|
|||||||
emos = currentChar.data.emotionImages
|
emos = currentChar.data.emotionImages
|
||||||
DataBase.set(database)
|
DataBase.set(database)
|
||||||
loadTokenize(currentChar.data)
|
loadTokenize(currentChar.data)
|
||||||
|
|
||||||
|
if(currentChar.type ==='character' && database.useAdditionalAssetsPreview){
|
||||||
|
if(currentChar.data.additionalAssets){
|
||||||
|
for(let i = 0; i < currentChar.data.additionalAssets.length; i++){
|
||||||
|
if(currentChar.data.additionalAssets[i].length > 2 && currentChar.data.additionalAssets[i][2]) {
|
||||||
|
assetFileExtensions[i] = currentChar.data.additionalAssets[i][2]
|
||||||
|
} else
|
||||||
|
assetFileExtensions[i] = currentChar.data.additionalAssets[i][1].split('.').pop()
|
||||||
|
getFileSrc(currentChar.data.additionalAssets[i][1]).then((filePath) => {
|
||||||
|
assetFilePath[i] = filePath
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onDestroy(unsub);
|
onDestroy(unsub);
|
||||||
@@ -615,9 +631,10 @@
|
|||||||
for(const f of da){
|
for(const f of da){
|
||||||
console.log(f)
|
console.log(f)
|
||||||
const img = f.data
|
const img = f.data
|
||||||
const imgp = await saveAsset(img)
|
|
||||||
const name = f.name
|
const name = f.name
|
||||||
currentChar.data.additionalAssets.push([name, imgp])
|
const extension = name.split('.').pop().toLowerCase()
|
||||||
|
const imgp = await saveAsset(img,'', extension)
|
||||||
|
currentChar.data.additionalAssets.push([name, imgp, extension])
|
||||||
currentChar.data.additionalAssets = currentChar.data.additionalAssets
|
currentChar.data.additionalAssets = currentChar.data.additionalAssets
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -634,8 +651,19 @@
|
|||||||
{#each currentChar.data.additionalAssets as assets, i}
|
{#each currentChar.data.additionalAssets as assets, i}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="font-medium truncate">
|
<td class="font-medium truncate">
|
||||||
|
{#if assetFilePath[i] && database.useAdditionalAssetsPreview}
|
||||||
|
{#if assetFileExtensions[i] === 'mp4'}
|
||||||
|
<!-- svelte-ignore a11y-media-has-caption -->
|
||||||
|
<video controls class="mt-2 px-2 w-full m-1 rounded-md"><source src={assetFilePath[i]} type="video/mp4"></video>
|
||||||
|
{:else if assetFileExtensions[i] === 'mp3'}
|
||||||
|
<audio controls class="mt-2 px-2 w-full h-16 m-1 rounded-md" loop><source src={assetFilePath[i]} type="audio/mpeg"></audio>
|
||||||
|
{:else}
|
||||||
|
<img src={assetFilePath[i]} class="w-16 h-16 m-1 rounded-md" alt={assets[0]}/>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
<input class="text-neutral-200 mt-2 mb-4 p-2 bg-transparent input-text focus:bg-selected w-full resize-none" bind:value={currentChar.data.additionalAssets[i][0]} placeholder="..." />
|
<input class="text-neutral-200 mt-2 mb-4 p-2 bg-transparent input-text focus:bg-selected w-full resize-none" bind:value={currentChar.data.additionalAssets[i][0]} placeholder="..." />
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<th class="font-medium cursor-pointer w-10">
|
<th class="font-medium cursor-pointer w-10">
|
||||||
<button class="hover:text-green-500" on:click={() => {
|
<button class="hover:text-green-500" on:click={() => {
|
||||||
if(currentChar.type === 'character'){
|
if(currentChar.type === 'character'){
|
||||||
|
|||||||
@@ -329,7 +329,7 @@ async function importSpecv2(card:CharacterCardV2, img?:Uint8Array, mode?:'hub'|'
|
|||||||
let customScripts:customscript[] = []
|
let customScripts:customscript[] = []
|
||||||
let utilityBot = false
|
let utilityBot = false
|
||||||
let sdData = defaultSdDataFunc()
|
let sdData = defaultSdDataFunc()
|
||||||
let extAssets:[string,string][] = []
|
let extAssets:[string,string,string][] = []
|
||||||
|
|
||||||
if(risuext){
|
if(risuext){
|
||||||
if(risuext.emotions){
|
if(risuext.emotions){
|
||||||
@@ -350,8 +350,11 @@ async function importSpecv2(card:CharacterCardV2, img?:Uint8Array, mode?:'hub'|'
|
|||||||
msg: `Loading... (Getting Assets ${i} / ${risuext.additionalAssets.length})`
|
msg: `Loading... (Getting Assets ${i} / ${risuext.additionalAssets.length})`
|
||||||
})
|
})
|
||||||
await sleep(10)
|
await sleep(10)
|
||||||
const imgp = await saveAsset(mode === 'hub' ? (await getHubResources(risuext.additionalAssets[i][1])) :Buffer.from(risuext.additionalAssets[i][1], 'base64'))
|
let fileName = ''
|
||||||
extAssets.push([risuext.additionalAssets[i][0],imgp])
|
if(risuext.additionalAssets[i].length >= 3)
|
||||||
|
fileName = risuext.additionalAssets[i][2]
|
||||||
|
const imgp = await saveAsset(mode === 'hub' ? (await getHubResources(risuext.additionalAssets[i][1])) :Buffer.from(risuext.additionalAssets[i][1], 'base64'), '', fileName)
|
||||||
|
extAssets.push([risuext.additionalAssets[i][0],imgp,fileName])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bias = risuext.bias ?? bias
|
bias = risuext.bias ?? bias
|
||||||
@@ -756,7 +759,7 @@ type CharacterCardV2 = {
|
|||||||
customScripts?:customscript[]
|
customScripts?:customscript[]
|
||||||
utilityBot?: boolean,
|
utilityBot?: boolean,
|
||||||
sdData?:[string,string][],
|
sdData?:[string,string][],
|
||||||
additionalAssets?:[string,string][],
|
additionalAssets?:[string,string,string][],
|
||||||
backgroundHTML?:string
|
backgroundHTML?:string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,9 +63,9 @@ async function parseAdditionalAssets(data:string, char:character, mode:'normal'|
|
|||||||
for(const asset of char.additionalAssets){
|
for(const asset of char.additionalAssets){
|
||||||
const assetPath = await getFileSrc(asset[1])
|
const assetPath = await getFileSrc(asset[1])
|
||||||
data = data.replaceAll(`{{raw::${asset[0]}}}`, assetPath).
|
data = data.replaceAll(`{{raw::${asset[0]}}}`, assetPath).
|
||||||
replaceAll(`{{img::${asset[0]}}}`,`<img src="${assetPath}" />`)
|
replaceAll(`{{img::${asset[0]}}}`,`<img src="${assetPath}" alt="${asset[0]}"/>`)
|
||||||
.replaceAll(`{{video::${asset[0]}}}`,`<video autoplay loop><source src="${assetPath}" type="video/mp4"></video>`)
|
.replaceAll(`{{video::${asset[0]}}}`,`<video controls autoplay loop><source src="${assetPath}" type="video/mp4"></video>`)
|
||||||
.replaceAll(`{{audio::${asset[0]}}}`,`<audio autoplay loop><source src="${assetPath}" type="audio/mpeg"></audio>`)
|
.replaceAll(`{{audio::${asset[0]}}}`,`<audio controls autoplay loop><source src="${assetPath}" type="audio/mpeg"></audio>`)
|
||||||
if(mode === 'back'){
|
if(mode === 'back'){
|
||||||
data = data.replaceAll(`{{bg::${asset[0]}}}`, `<div style="width:100%;height:100%;background: linear-gradient(rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0.8)),url(${assetPath}); background-size: cover;"></div>`)
|
data = data.replaceAll(`{{bg::${asset[0]}}}`, `<div style="width:100%;height:100%;background: linear-gradient(rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0.8)),url(${assetPath}); background-size: cover;"></div>`)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -409,6 +409,7 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n
|
|||||||
else if(req.type === 'streaming'){
|
else if(req.type === 'streaming'){
|
||||||
const reader = req.result.getReader()
|
const reader = req.result.getReader()
|
||||||
const msgIndex = db.characters[selectedChar].chats[selectedChat].message.length
|
const msgIndex = db.characters[selectedChar].chats[selectedChat].message.length
|
||||||
|
db.characters[selectedChar].chats[selectedChat].isStreaming = true
|
||||||
db.characters[selectedChar].chats[selectedChat].message.push({
|
db.characters[selectedChar].chats[selectedChat].message.push({
|
||||||
role: 'char',
|
role: 'char',
|
||||||
data: "",
|
data: "",
|
||||||
@@ -424,6 +425,8 @@ export async function sendChat(chatProcessIndex = -1,arg:{chatAdditonalTokens?:n
|
|||||||
setDatabase(db)
|
setDatabase(db)
|
||||||
}
|
}
|
||||||
if(readed.done){
|
if(readed.done){
|
||||||
|
db.characters[selectedChar].chats[selectedChat].isStreaming = false
|
||||||
|
setDatabase(db)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -342,7 +342,7 @@ export interface character{
|
|||||||
VOLUME_SCALE?: number
|
VOLUME_SCALE?: number
|
||||||
}
|
}
|
||||||
supaMemory?:boolean
|
supaMemory?:boolean
|
||||||
additionalAssets?:[string, string][]
|
additionalAssets?:[string, string, string][]
|
||||||
ttsReadOnlyQuoted?:boolean
|
ttsReadOnlyQuoted?:boolean
|
||||||
replaceGlobalNote:string
|
replaceGlobalNote:string
|
||||||
backgroundHTML?:string
|
backgroundHTML?:string
|
||||||
@@ -525,7 +525,9 @@ export interface Database{
|
|||||||
expires_in?: number
|
expires_in?: number
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
classicMaxWidth: boolean
|
classicMaxWidth: boolean,
|
||||||
|
useChatSticker:boolean,
|
||||||
|
useAdditionalAssetsPreview:boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
interface hordeConfig{
|
interface hordeConfig{
|
||||||
@@ -564,6 +566,7 @@ export interface Chat{
|
|||||||
supaMemoryData?:string
|
supaMemoryData?:string
|
||||||
lastMemory?:string
|
lastMemory?:string
|
||||||
suggestMessages?:string[]
|
suggestMessages?:string[]
|
||||||
|
isStreaming?:boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Message{
|
export interface Message{
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ export async function readImage(data:string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function saveAsset(data:Uint8Array, customId:string = ''){
|
export async function saveAsset(data:Uint8Array, customId:string = '', fileName:string = ''){
|
||||||
let id = ''
|
let id = ''
|
||||||
if(customId !== ''){
|
if(customId !== ''){
|
||||||
id = customId
|
id = customId
|
||||||
@@ -182,13 +182,17 @@ export async function saveAsset(data:Uint8Array, customId:string = ''){
|
|||||||
id = uuidv4()
|
id = uuidv4()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let fileExtension:string = 'png'
|
||||||
|
if(fileName && fileName.split('.').length > 0){
|
||||||
|
fileExtension = fileName.split('.').pop()
|
||||||
|
}
|
||||||
if(isTauri){
|
if(isTauri){
|
||||||
await writeBinaryFile(`assets/${id}.png`, data ,{dir: BaseDirectory.AppData})
|
await writeBinaryFile(`assets/${id}.${fileExtension}`, data ,{dir: BaseDirectory.AppData})
|
||||||
return `assets/${id}.png`
|
return `assets/${id}.${fileExtension}`
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
await forageStorage.setItem(`assets/${id}.png`, data)
|
await forageStorage.setItem(`assets/${id}.${fileExtension}`, data)
|
||||||
return `assets/${id}.png`
|
return `assets/${id}.${fileExtension}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user