SvelteKit-based WebUI (#14839)
This commit is contained in:
parent
8f8f2274ee
commit
a7a98e0fff
288 changed files with 25749 additions and 11502 deletions
|
|
@ -0,0 +1,72 @@
|
|||
<script lang="ts">
|
||||
import * as AlertDialog from '$lib/components/ui/alert-dialog';
|
||||
import type { Component } from 'svelte';
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
title: string;
|
||||
description: string;
|
||||
confirmText?: string;
|
||||
cancelText?: string;
|
||||
variant?: 'default' | 'destructive';
|
||||
icon?: Component;
|
||||
onConfirm: () => void;
|
||||
onCancel: () => void;
|
||||
onKeydown?: (event: KeyboardEvent) => void;
|
||||
}
|
||||
|
||||
let {
|
||||
open = $bindable(),
|
||||
title,
|
||||
description,
|
||||
confirmText = 'Confirm',
|
||||
cancelText = 'Cancel',
|
||||
variant = 'default',
|
||||
icon,
|
||||
onConfirm,
|
||||
onCancel,
|
||||
onKeydown
|
||||
}: Props = $props();
|
||||
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
onConfirm();
|
||||
}
|
||||
onKeydown?.(event);
|
||||
}
|
||||
|
||||
function handleOpenChange(newOpen: boolean) {
|
||||
if (!newOpen) {
|
||||
onCancel();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<AlertDialog.Root {open} onOpenChange={handleOpenChange}>
|
||||
<AlertDialog.Content onkeydown={handleKeydown}>
|
||||
<AlertDialog.Header>
|
||||
<AlertDialog.Title class="flex items-center gap-2">
|
||||
{#if icon}
|
||||
{@const IconComponent = icon}
|
||||
<IconComponent class="h-5 w-5 {variant === 'destructive' ? 'text-destructive' : ''}" />
|
||||
{/if}
|
||||
{title}
|
||||
</AlertDialog.Title>
|
||||
|
||||
<AlertDialog.Description>
|
||||
{description}
|
||||
</AlertDialog.Description>
|
||||
</AlertDialog.Header>
|
||||
|
||||
<AlertDialog.Footer>
|
||||
<AlertDialog.Cancel onclick={onCancel}>{cancelText}</AlertDialog.Cancel>
|
||||
<AlertDialog.Action
|
||||
onclick={onConfirm}
|
||||
class={variant === 'destructive' ? 'bg-destructive text-white hover:bg-destructive/80' : ''}
|
||||
>
|
||||
{confirmText}
|
||||
</AlertDialog.Action>
|
||||
</AlertDialog.Footer>
|
||||
</AlertDialog.Content>
|
||||
</AlertDialog.Root>
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<script lang="ts">
|
||||
import * as AlertDialog from '$lib/components/ui/alert-dialog';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
currentTitle: string;
|
||||
newTitle: string;
|
||||
onConfirm: () => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
let { open = $bindable(), currentTitle, newTitle, onConfirm, onCancel }: Props = $props();
|
||||
</script>
|
||||
|
||||
<AlertDialog.Root bind:open>
|
||||
<AlertDialog.Content>
|
||||
<AlertDialog.Header>
|
||||
<AlertDialog.Title>Update Conversation Title?</AlertDialog.Title>
|
||||
|
||||
<AlertDialog.Description>
|
||||
Do you want to update the conversation title to match the first message content?
|
||||
</AlertDialog.Description>
|
||||
</AlertDialog.Header>
|
||||
|
||||
<div class="space-y-4 pt-2 pb-6">
|
||||
<div class="space-y-2">
|
||||
<p class="text-sm font-medium text-muted-foreground">Current title:</p>
|
||||
|
||||
<p class="rounded-md bg-muted/50 p-3 text-sm font-medium">{currentTitle}</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<p class="text-sm font-medium text-muted-foreground">New title would be:</p>
|
||||
|
||||
<p class="rounded-md bg-muted/50 p-3 text-sm font-medium">{newTitle}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<AlertDialog.Footer>
|
||||
<Button variant="outline" onclick={onCancel}>Keep Current Title</Button>
|
||||
|
||||
<Button onclick={onConfirm}>Update Title</Button>
|
||||
</AlertDialog.Footer>
|
||||
</AlertDialog.Content>
|
||||
</AlertDialog.Root>
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
<script lang="ts">
|
||||
import * as AlertDialog from '$lib/components/ui/alert-dialog';
|
||||
import { FileX } from '@lucide/svelte';
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
emptyFiles: string[];
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
}
|
||||
|
||||
let { open = $bindable(), emptyFiles, onOpenChange }: Props = $props();
|
||||
|
||||
function handleOpenChange(newOpen: boolean) {
|
||||
open = newOpen;
|
||||
onOpenChange?.(newOpen);
|
||||
}
|
||||
</script>
|
||||
|
||||
<AlertDialog.Root {open} onOpenChange={handleOpenChange}>
|
||||
<AlertDialog.Content>
|
||||
<AlertDialog.Header>
|
||||
<AlertDialog.Title class="flex items-center gap-2">
|
||||
<FileX class="h-5 w-5 text-destructive" />
|
||||
|
||||
Empty Files Detected
|
||||
</AlertDialog.Title>
|
||||
|
||||
<AlertDialog.Description>
|
||||
The following files are empty and have been removed from your attachments:
|
||||
</AlertDialog.Description>
|
||||
</AlertDialog.Header>
|
||||
|
||||
<div class="space-y-3 text-sm">
|
||||
<div class="rounded-lg bg-muted p-3">
|
||||
<div class="mb-2 font-medium">Empty Files:</div>
|
||||
|
||||
<ul class="list-inside list-disc space-y-1 text-muted-foreground">
|
||||
{#each emptyFiles as fileName (fileName)}
|
||||
<li class="font-mono text-sm">{fileName}</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="mb-2 font-medium">What happened:</div>
|
||||
|
||||
<ul class="list-inside list-disc space-y-1 text-muted-foreground">
|
||||
<li>Empty files cannot be processed or sent to the AI model</li>
|
||||
|
||||
<li>These files have been automatically removed from your attachments</li>
|
||||
|
||||
<li>You can try uploading files with content instead</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<AlertDialog.Footer>
|
||||
<AlertDialog.Action onclick={() => handleOpenChange(false)}>Got it</AlertDialog.Action>
|
||||
</AlertDialog.Footer>
|
||||
</AlertDialog.Content>
|
||||
</AlertDialog.Root>
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
<script lang="ts">
|
||||
import { AlertTriangle } from '@lucide/svelte';
|
||||
import * as AlertDialog from '$lib/components/ui/alert-dialog';
|
||||
import { maxContextError, clearMaxContextError } from '$lib/stores/chat.svelte';
|
||||
</script>
|
||||
|
||||
<AlertDialog.Root
|
||||
open={maxContextError() !== null}
|
||||
onOpenChange={(open) => !open && clearMaxContextError()}
|
||||
>
|
||||
<AlertDialog.Content>
|
||||
<AlertDialog.Header>
|
||||
<AlertDialog.Title class="flex items-center gap-2">
|
||||
<AlertTriangle class="h-5 w-5 text-destructive" />
|
||||
|
||||
Message Too Long
|
||||
</AlertDialog.Title>
|
||||
|
||||
<AlertDialog.Description>
|
||||
Your message exceeds the model's context window and cannot be processed.
|
||||
</AlertDialog.Description>
|
||||
</AlertDialog.Header>
|
||||
|
||||
{#if maxContextError()}
|
||||
<div class="space-y-3 text-sm">
|
||||
<div class="rounded-lg bg-muted p-3">
|
||||
<div class="mb-2 font-medium">Token Usage:</div>
|
||||
|
||||
<div class="space-y-1 text-muted-foreground">
|
||||
<div>
|
||||
Estimated tokens:
|
||||
|
||||
<span class="font-mono">
|
||||
{maxContextError()?.estimatedTokens.toLocaleString()}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
Context window:
|
||||
|
||||
<span class="font-mono">
|
||||
{maxContextError()?.maxContext.toLocaleString()}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="mb-2 font-medium">Suggestions:</div>
|
||||
|
||||
<ul class="list-inside list-disc space-y-1 text-muted-foreground">
|
||||
<li>Shorten your message</li>
|
||||
|
||||
<li>Remove some file attachments</li>
|
||||
|
||||
<li>Start a new conversation</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<AlertDialog.Footer>
|
||||
<AlertDialog.Action onclick={() => clearMaxContextError()}>Got it</AlertDialog.Action>
|
||||
</AlertDialog.Footer>
|
||||
</AlertDialog.Content>
|
||||
</AlertDialog.Root>
|
||||
Loading…
Add table
Add a link
Reference in a new issue