feat: chat overview
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
<script>
|
||||
import { getContext, createEventDispatcher } from 'svelte';
|
||||
import { useSvelteFlow, useNodesInitialized, useStore } from '@xyflow/svelte';
|
||||
import { SvelteFlow, Controls, Background, BackgroundVariant } from '@xyflow/svelte';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const i18n = getContext('i18n');
|
||||
|
||||
import { onMount, tick } from 'svelte';
|
||||
|
||||
import { writable } from 'svelte/store';
|
||||
import { models, showOverview, theme, user } from '$lib/stores';
|
||||
|
||||
import '@xyflow/svelte/dist/style.css';
|
||||
|
||||
import CustomNode from './Overview/Node.svelte';
|
||||
import Flow from './Overview/Flow.svelte';
|
||||
import XMark from '../icons/XMark.svelte';
|
||||
|
||||
const { width, height } = useStore();
|
||||
|
||||
const { fitView, getViewport } = useSvelteFlow();
|
||||
const nodesInitialized = useNodesInitialized();
|
||||
|
||||
export let history;
|
||||
|
||||
const nodes = writable([]);
|
||||
const edges = writable([]);
|
||||
|
||||
const nodeTypes = {
|
||||
custom: CustomNode
|
||||
};
|
||||
|
||||
$: if (history) {
|
||||
drawFlow();
|
||||
}
|
||||
|
||||
const drawFlow = async () => {
|
||||
const nodeList = [];
|
||||
const edgeList = [];
|
||||
const levelOffset = 150; // Vertical spacing between layers
|
||||
const siblingOffset = 250; // Horizontal spacing between nodes at the same layer
|
||||
|
||||
// Map to keep track of node positions at each level
|
||||
let positionMap = new Map();
|
||||
|
||||
// Helper function to truncate labels
|
||||
function createLabel(content) {
|
||||
const maxLength = 100;
|
||||
return content.length > maxLength ? content.substr(0, maxLength) + '...' : content;
|
||||
}
|
||||
|
||||
// Create nodes and map children to ensure alignment in width
|
||||
let layerWidths = {}; // Track widths of each layer
|
||||
|
||||
Object.keys(history.messages).forEach((id) => {
|
||||
const message = history.messages[id];
|
||||
const level = message.parentId ? positionMap.get(message.parentId).level + 1 : 0;
|
||||
if (!layerWidths[level]) layerWidths[level] = 0;
|
||||
|
||||
positionMap.set(id, {
|
||||
id: message.id,
|
||||
level,
|
||||
position: layerWidths[level]++
|
||||
});
|
||||
});
|
||||
|
||||
// Adjust positions based on siblings count to centralize vertical spacing
|
||||
Object.keys(history.messages).forEach((id) => {
|
||||
const pos = positionMap.get(id);
|
||||
const xOffset = pos.position * siblingOffset;
|
||||
const y = pos.level * levelOffset;
|
||||
const x = xOffset;
|
||||
|
||||
nodeList.push({
|
||||
id: pos.id,
|
||||
type: 'custom',
|
||||
data: {
|
||||
user: $user,
|
||||
message: history.messages[id],
|
||||
model: $models.find((model) => model.id === history.messages[id].model),
|
||||
label: createLabel(history.messages[id].content)
|
||||
},
|
||||
position: { x, y }
|
||||
});
|
||||
|
||||
// Create edges
|
||||
const parentId = history.messages[id].parentId;
|
||||
if (parentId) {
|
||||
edgeList.push({
|
||||
id: parentId + '-' + pos.id,
|
||||
source: parentId,
|
||||
target: pos.id,
|
||||
type: 'smoothstep',
|
||||
animated: true
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
await edges.set([...edgeList]);
|
||||
await nodes.set([...nodeList]);
|
||||
};
|
||||
|
||||
onMount(() => {
|
||||
nodesInitialized.subscribe(async (initialized) => {
|
||||
if (initialized) {
|
||||
await tick();
|
||||
const res = await fitView();
|
||||
}
|
||||
});
|
||||
|
||||
width.subscribe((value) => {
|
||||
if (value) {
|
||||
fitView();
|
||||
}
|
||||
});
|
||||
|
||||
height.subscribe((value) => {
|
||||
if (value) {
|
||||
fitView();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="w-full h-full relative">
|
||||
<div class=" absolute z-50 w-full flex justify-between dark:text-gray-100 px-5 py-4">
|
||||
<div class=" text-lg font-medium self-center font-primary">{$i18n.t('Chat Overview')}</div>
|
||||
<button
|
||||
class="self-center"
|
||||
on:click={() => {
|
||||
dispatch('close');
|
||||
showOverview.set(false);
|
||||
}}
|
||||
>
|
||||
<XMark className="size-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{#if $nodes.length > 0}
|
||||
<Flow {nodes} {nodeTypes} {edges} />
|
||||
{/if}
|
||||
</div>
|
||||
Reference in New Issue
Block a user