Add branches
This commit is contained in:
@@ -21,12 +21,20 @@
|
||||
import ModuleChatMenu from "../Setting/Pages/Module/ModuleChatMenu.svelte";
|
||||
import { ColorSchemeTypeStore } from "src/ts/gui/colorscheme";
|
||||
import Help from "./Help.svelte";
|
||||
import { getChatBranches } from "src/ts/gui/branches";
|
||||
import { getCurrentCharacter } from "src/ts/storage/database.svelte";
|
||||
import { message } from "@tauri-apps/plugin-dialog";
|
||||
let btn
|
||||
let input = $state('')
|
||||
let cardExportType = $state('realm')
|
||||
let cardExportType2 = $state('')
|
||||
let cardLicense = $state('')
|
||||
let generationInfoMenuIndex = $state(0)
|
||||
let branchHover:null|{
|
||||
x:number,
|
||||
y:number,
|
||||
content:string,
|
||||
} = $state(null)
|
||||
$effect.pre(() => {
|
||||
if(btn){
|
||||
btn.focus()
|
||||
@@ -34,6 +42,9 @@
|
||||
if($alertStore.type !== 'input'){
|
||||
input = ''
|
||||
}
|
||||
if($alertStore.type !== 'branches'){
|
||||
branchHover = null
|
||||
}
|
||||
if($alertStore.type !== 'cardexport'){
|
||||
cardExportType = 'realm'
|
||||
cardExportType2 = ''
|
||||
@@ -69,7 +80,7 @@
|
||||
}
|
||||
}}></svelte:window>
|
||||
|
||||
{#if $alertStore.type !== 'none' && $alertStore.type !== 'toast' && $alertStore.type !== 'cardexport' && $alertStore.type !== 'selectModule' && $alertStore.type !== 'pukmakkurit'}
|
||||
{#if $alertStore.type !== 'none' && $alertStore.type !== 'toast' && $alertStore.type !== 'cardexport' && $alertStore.type !== 'branches' && $alertStore.type !== 'selectModule' && $alertStore.type !== 'pukmakkurit'}
|
||||
<div class="absolute w-full h-full z-50 bg-black bg-opacity-50 flex justify-center items-center" class:vis={ $alertStore.type === 'wait2'}>
|
||||
<div class="bg-darkbg p-4 break-any rounded-md flex flex-col max-w-3xl max-h-full overflow-y-auto">
|
||||
{#if $alertStore.type === 'error'}
|
||||
@@ -551,7 +562,78 @@
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{:else if $alertStore.type === 'branches'}
|
||||
<div class="absolute w-full h-full z-50 bg-black bg-opacity-80 flex justify-center items-center overflow-x-auto overflow-y-auto">
|
||||
{#if branchHover !== null}
|
||||
<div class="z-30 whitespace-pre-wrap p-4 text-textcolor bg-darkbg border-darkborderc border rounded-md absolute text-white" style="top: {branchHover.y * 80 + 24}px; left: {(branchHover.x + 1) * 80 + 24}px">
|
||||
{branchHover.content}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="x-50 right-2 top-2 absolute">
|
||||
<button class="bg-darkbg border-darkborderc border p-2 rounded-md" onclick={() => {
|
||||
alertStore.set({
|
||||
type: 'none',
|
||||
msg: ''
|
||||
})
|
||||
}}>
|
||||
<XIcon />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{#each getChatBranches() as obj}
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
||||
<div
|
||||
role="table"
|
||||
class="peer w-12 h-12 z-20 bg-bgcolor border border-darkborderc rounded-full flex justify-center items-center overflow-y-auto absolute"
|
||||
style="top: {obj.y * 80 + 24}px; left: {obj.x * 80 + 24}px"
|
||||
onmouseenter={() => {
|
||||
if(branchHover === null){
|
||||
const char = getCurrentCharacter()
|
||||
branchHover = {
|
||||
x: obj.x,
|
||||
y: obj.y,
|
||||
content: char.chats[obj.chatId].message[obj.y - 1].data
|
||||
}
|
||||
}
|
||||
}}
|
||||
onclick={() => {
|
||||
if(branchHover === null){
|
||||
const char = getCurrentCharacter()
|
||||
branchHover = {
|
||||
x: obj.x,
|
||||
y: obj.y,
|
||||
content: char.chats[obj.chatId].message[obj.y - 1].data
|
||||
}
|
||||
}
|
||||
}}
|
||||
onmouseleave={() => {
|
||||
branchHover = null
|
||||
}}
|
||||
>
|
||||
|
||||
</div>
|
||||
{#if obj.connectX === obj.x}
|
||||
{#if obj.multiChild}
|
||||
<div class="w-0 h-20 border-x border-x-red-500 absolute" style="top: {(obj.y-1) * 80 + 24}px; left: {obj.x * 80 + 45}px">
|
||||
|
||||
</div>
|
||||
{:else}
|
||||
<div class="w-0 h-20 border-x border-x-blue-500 absolute" style="top: {(obj.y-1) * 80 + 24}px; left: {obj.x * 80 + 45}px">
|
||||
|
||||
</div>
|
||||
{/if}
|
||||
{:else if obj.connectX !== -1}
|
||||
<div class="w-0 h-10 border-x border-x-red-500 absolute" style="top: {(obj.y) * 80}px; left: {obj.x * 80 + 45}px">
|
||||
|
||||
</div>
|
||||
<div class="h-0 border-y border-y-red-500 absolute" style="top: {(obj.y) * 80}px; left: {obj.connectX * 80 + 46}px" style:width={Math.abs((obj.x - obj.connectX) * 80) + 'px'}>
|
||||
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
import { DBState } from 'src/ts/stores.svelte';
|
||||
import TextInput from "../UI/GUI/TextInput.svelte";
|
||||
import { DownloadIcon, PencilIcon, FolderUpIcon, MenuIcon, TrashIcon } from "lucide-svelte";
|
||||
import { DownloadIcon, PencilIcon, FolderUpIcon, MenuIcon, TrashIcon, GitBranchIcon, SplitIcon } from "lucide-svelte";
|
||||
import { exportChat, importChat } from "src/ts/characters";
|
||||
import { alertChatOptions, alertConfirm, alertError, alertNormal, alertSelect } from "src/ts/alert";
|
||||
import { alertChatOptions, alertConfirm, alertError, alertNormal, alertSelect, alertStore } from "src/ts/alert";
|
||||
import { language } from "src/lang";
|
||||
import Button from "../UI/GUI/Button.svelte";
|
||||
import { findCharacterbyId, parseKeyValue, sleep, sortableOptions } from "src/ts/util";
|
||||
@@ -15,6 +15,7 @@
|
||||
import Sortable from 'sortablejs/modular/sortable.core.esm.js';
|
||||
import { onDestroy, onMount } from "svelte";
|
||||
import { v4 } from "uuid";
|
||||
import { getChatBranches } from "src/ts/gui/branches";
|
||||
|
||||
interface Props {
|
||||
chara: character|groupChat;
|
||||
@@ -202,11 +203,19 @@
|
||||
}}>
|
||||
<FolderUpIcon size={18}/>
|
||||
</button>
|
||||
<button class="text-textcolor2 hover:text-green-500 cursor-pointer" onclick={() => {
|
||||
<button class="text-textcolor2 hover:text-green-500 mr-2 cursor-pointer" onclick={() => {
|
||||
editMode = !editMode
|
||||
}}>
|
||||
<PencilIcon size={18}/>
|
||||
</button>
|
||||
<button class="text-textcolor2 hover:text-green-500 cursor-pointer" onclick={() => {
|
||||
alertStore.set({
|
||||
type: "branches",
|
||||
msg: ""
|
||||
})
|
||||
}}>
|
||||
<SplitIcon size={18}/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{#if DBState.db.characters[$selectedCharID]?.chaId !== '§playground'}
|
||||
|
||||
@@ -10,7 +10,7 @@ export interface alertData{
|
||||
type: 'error'|'normal'|'none'|'ask'|'wait'|'selectChar'
|
||||
|'input'|'toast'|'wait2'|'markdown'|'select'|'login'
|
||||
|'tos'|'cardexport'|'requestdata'|'addchar'|'hypaV2'|'selectModule'
|
||||
|'chatOptions'|'pukmakkurit',
|
||||
|'chatOptions'|'pukmakkurit'|'branches',
|
||||
msg: string,
|
||||
submsg?: string
|
||||
}
|
||||
|
||||
104
src/ts/gui/branches.ts
Normal file
104
src/ts/gui/branches.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import { getCurrentCharacter } from "../storage/database.svelte";
|
||||
|
||||
type ChatBranch = {
|
||||
children: Map<string, ChatBranch>,
|
||||
maxChildren: number,
|
||||
chatId: number,
|
||||
}
|
||||
|
||||
function search(left: string[], branch: ChatBranch, chatId:number){
|
||||
if(left.length === 0){
|
||||
return
|
||||
}
|
||||
|
||||
const current = left[0]
|
||||
if(!branch.children.has(current)){
|
||||
branch.children.set(current, {
|
||||
children: new Map(),
|
||||
maxChildren: 0,
|
||||
chatId: chatId,
|
||||
})
|
||||
}
|
||||
|
||||
search(left.slice(1), branch.children.get(current)!, chatId)
|
||||
}
|
||||
|
||||
function getMaxChildren(branch: ChatBranch){
|
||||
let max = 0
|
||||
if(branch.children.size === 0){
|
||||
return 1
|
||||
}
|
||||
|
||||
for(const child of branch.children.values()){
|
||||
max += (getMaxChildren(child))
|
||||
}
|
||||
branch.maxChildren = max
|
||||
return max
|
||||
}
|
||||
|
||||
type RenderedBranch = {
|
||||
x: number,
|
||||
y: number,
|
||||
connectX:number,
|
||||
connectY:number,
|
||||
content: string,
|
||||
multiChild: boolean,
|
||||
chatId: number,
|
||||
}
|
||||
|
||||
function renderBranch(branch: ChatBranch, x: number, y: number, connectX = -1, connectY = -1): RenderedBranch[]{
|
||||
const rendered: RenderedBranch[] = []
|
||||
for(const [key, child] of branch.children){
|
||||
rendered.push({
|
||||
x,
|
||||
y,
|
||||
content: key,
|
||||
connectX,
|
||||
connectY,
|
||||
multiChild: branch.children.size > 1,
|
||||
chatId: child.chatId,
|
||||
})
|
||||
const childRendered = renderBranch(child, x, y + 1, x, y)
|
||||
rendered.push(...childRendered)
|
||||
x += child.maxChildren
|
||||
}
|
||||
return rendered
|
||||
|
||||
}
|
||||
|
||||
export function getChatBranches(){
|
||||
const character = getCurrentCharacter()
|
||||
|
||||
const mainBranch: ChatBranch = {
|
||||
children: new Map(),
|
||||
maxChildren: 0,
|
||||
chatId: -1,
|
||||
}
|
||||
|
||||
let i = 0;
|
||||
for(const chat of character.chats){
|
||||
const fm = chat.fmIndex === -1 ? character.firstMessage : character.alternateGreetings?.[chat.fmIndex ?? 0]
|
||||
// const chatList = [fm].concat(chat.message.map((v) => v.data))
|
||||
const chatList:string[] = [simpleHasher(fm)]
|
||||
for(const message of chat.message){
|
||||
chatList.push(simpleHasher(message.data))
|
||||
}
|
||||
|
||||
search(chatList, mainBranch, i++)
|
||||
}
|
||||
|
||||
getMaxChildren(mainBranch)
|
||||
|
||||
return renderBranch(mainBranch, 0, 0)
|
||||
}
|
||||
|
||||
function simpleHasher(str: string){
|
||||
let hash = 0;
|
||||
if (str.length == 0) return '';
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const char = str.charCodeAt(i);
|
||||
hash = ((hash<<5)-hash)+char;
|
||||
hash = hash & hash; // Convert to 32bit integer
|
||||
}
|
||||
return hash.toString(36);
|
||||
}
|
||||
@@ -346,6 +346,7 @@ export async function hypaMemoryV2(
|
||||
memory?: SerializableHypaV2Data;
|
||||
}> {
|
||||
const db = getDatabase();
|
||||
currentTokens -= db.maxResponse
|
||||
let data: HypaV2Data = {
|
||||
lastMainChunkID: 0,
|
||||
chunks: [],
|
||||
|
||||
Reference in New Issue
Block a user