Spaces:
Sleeping
Sleeping
Add "disable streaming tokens" settings & remove media query (#1299)
Browse files- src/lib/components/chat/ChatMessage.svelte +5 -10
- src/lib/stores/settings.ts +1 -0
- src/lib/types/Settings.ts +4 -1
- src/lib/utils/isReduceMotion.ts +0 -5
- src/routes/+layout.server.ts +1 -0
- src/routes/conversation/[id]/+page.svelte +1 -4
- src/routes/settings/(nav)/+page.svelte +8 -0
- src/routes/settings/(nav)/+server.ts +3 -2
src/lib/components/chat/ChatMessage.svelte
CHANGED
|
@@ -2,7 +2,7 @@
|
|
| 2 |
import { marked, type MarkedOptions } from "marked";
|
| 3 |
import markedKatex from "marked-katex-extension";
|
| 4 |
import type { Message, MessageFile } from "$lib/types/Message";
|
| 5 |
-
import { afterUpdate, createEventDispatcher,
|
| 6 |
import { deepestChild } from "$lib/utils/deepestChild";
|
| 7 |
import { page } from "$app/stores";
|
| 8 |
|
|
@@ -30,9 +30,9 @@
|
|
| 30 |
} from "$lib/types/MessageUpdate";
|
| 31 |
import { base } from "$app/paths";
|
| 32 |
import { useConvTreeStore } from "$lib/stores/convTree";
|
| 33 |
-
import { isReducedMotion } from "$lib/utils/isReduceMotion";
|
| 34 |
import Modal from "../Modal.svelte";
|
| 35 |
import ToolUpdate from "./ToolUpdate.svelte";
|
|
|
|
| 36 |
|
| 37 |
function sanitizeMd(md: string) {
|
| 38 |
let ret = md
|
|
@@ -80,9 +80,6 @@
|
|
| 80 |
let isCopied = false;
|
| 81 |
|
| 82 |
let initialized = false;
|
| 83 |
-
|
| 84 |
-
let reducedMotionMode = false;
|
| 85 |
-
|
| 86 |
const renderer = new marked.Renderer();
|
| 87 |
// For code blocks with simple backticks
|
| 88 |
renderer.codespan = (code) => {
|
|
@@ -118,12 +115,10 @@
|
|
| 118 |
$: emptyLoad =
|
| 119 |
!message.content && (webSearchIsDone || (searchUpdates && searchUpdates.length === 0));
|
| 120 |
|
| 121 |
-
|
| 122 |
-
reducedMotionMode = isReducedMotion(window);
|
| 123 |
-
});
|
| 124 |
|
| 125 |
afterUpdate(() => {
|
| 126 |
-
if (
|
| 127 |
return;
|
| 128 |
}
|
| 129 |
|
|
@@ -301,7 +296,7 @@
|
|
| 301 |
class="prose max-w-none max-sm:prose-sm dark:prose-invert prose-headings:font-semibold prose-h1:text-lg prose-h2:text-base prose-h3:text-base prose-pre:bg-gray-800 dark:prose-pre:bg-gray-900"
|
| 302 |
bind:this={contentEl}
|
| 303 |
>
|
| 304 |
-
{#if isLast && loading &&
|
| 305 |
<IconLoading classNames="loading inline ml-2 first:ml-0" />
|
| 306 |
{/if}
|
| 307 |
{#each tokens as token}
|
|
|
|
| 2 |
import { marked, type MarkedOptions } from "marked";
|
| 3 |
import markedKatex from "marked-katex-extension";
|
| 4 |
import type { Message, MessageFile } from "$lib/types/Message";
|
| 5 |
+
import { afterUpdate, createEventDispatcher, tick } from "svelte";
|
| 6 |
import { deepestChild } from "$lib/utils/deepestChild";
|
| 7 |
import { page } from "$app/stores";
|
| 8 |
|
|
|
|
| 30 |
} from "$lib/types/MessageUpdate";
|
| 31 |
import { base } from "$app/paths";
|
| 32 |
import { useConvTreeStore } from "$lib/stores/convTree";
|
|
|
|
| 33 |
import Modal from "../Modal.svelte";
|
| 34 |
import ToolUpdate from "./ToolUpdate.svelte";
|
| 35 |
+
import { useSettingsStore } from "$lib/stores/settings";
|
| 36 |
|
| 37 |
function sanitizeMd(md: string) {
|
| 38 |
let ret = md
|
|
|
|
| 80 |
let isCopied = false;
|
| 81 |
|
| 82 |
let initialized = false;
|
|
|
|
|
|
|
|
|
|
| 83 |
const renderer = new marked.Renderer();
|
| 84 |
// For code blocks with simple backticks
|
| 85 |
renderer.codespan = (code) => {
|
|
|
|
| 115 |
$: emptyLoad =
|
| 116 |
!message.content && (webSearchIsDone || (searchUpdates && searchUpdates.length === 0));
|
| 117 |
|
| 118 |
+
const settings = useSettingsStore();
|
|
|
|
|
|
|
| 119 |
|
| 120 |
afterUpdate(() => {
|
| 121 |
+
if ($settings.disableStream) {
|
| 122 |
return;
|
| 123 |
}
|
| 124 |
|
|
|
|
| 296 |
class="prose max-w-none max-sm:prose-sm dark:prose-invert prose-headings:font-semibold prose-h1:text-lg prose-h2:text-base prose-h3:text-base prose-pre:bg-gray-800 dark:prose-pre:bg-gray-900"
|
| 297 |
bind:this={contentEl}
|
| 298 |
>
|
| 299 |
+
{#if isLast && loading && $settings.disableStream}
|
| 300 |
<IconLoading classNames="loading inline ml-2 first:ml-0" />
|
| 301 |
{/if}
|
| 302 |
{#each tokens as token}
|
src/lib/stores/settings.ts
CHANGED
|
@@ -16,6 +16,7 @@ type SettingsStore = {
|
|
| 16 |
recentlySaved: boolean;
|
| 17 |
assistants: Array<ObjectId | string>;
|
| 18 |
tools?: Record<string, boolean>;
|
|
|
|
| 19 |
};
|
| 20 |
|
| 21 |
type SettingsStoreWritable = Writable<SettingsStore> & {
|
|
|
|
| 16 |
recentlySaved: boolean;
|
| 17 |
assistants: Array<ObjectId | string>;
|
| 18 |
tools?: Record<string, boolean>;
|
| 19 |
+
disableStream: boolean;
|
| 20 |
};
|
| 21 |
|
| 22 |
type SettingsStoreWritable = Writable<SettingsStore> & {
|
src/lib/types/Settings.ts
CHANGED
|
@@ -22,8 +22,10 @@ export interface Settings extends Timestamps {
|
|
| 22 |
|
| 23 |
assistants?: Assistant["_id"][];
|
| 24 |
tools?: Record<string, boolean>;
|
|
|
|
| 25 |
}
|
| 26 |
|
|
|
|
| 27 |
// TODO: move this to a constant file along with other constants
|
| 28 |
export const DEFAULT_SETTINGS = {
|
| 29 |
shareConversationsWithModelAuthors: true,
|
|
@@ -32,4 +34,5 @@ export const DEFAULT_SETTINGS = {
|
|
| 32 |
customPrompts: {},
|
| 33 |
assistants: [],
|
| 34 |
tools: {},
|
| 35 |
-
|
|
|
|
|
|
| 22 |
|
| 23 |
assistants?: Assistant["_id"][];
|
| 24 |
tools?: Record<string, boolean>;
|
| 25 |
+
disableStream: boolean;
|
| 26 |
}
|
| 27 |
|
| 28 |
+
export type SettingsEditable = Omit<Settings, "ethicsModalAcceptedAt" | "createdAt" | "updatedAt">;
|
| 29 |
// TODO: move this to a constant file along with other constants
|
| 30 |
export const DEFAULT_SETTINGS = {
|
| 31 |
shareConversationsWithModelAuthors: true,
|
|
|
|
| 34 |
customPrompts: {},
|
| 35 |
assistants: [],
|
| 36 |
tools: {},
|
| 37 |
+
disableStream: false,
|
| 38 |
+
} satisfies SettingsEditable;
|
src/lib/utils/isReduceMotion.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
| 1 |
-
export function isReducedMotion(window: Window) {
|
| 2 |
-
const { matchMedia } = window;
|
| 3 |
-
|
| 4 |
-
return matchMedia("(prefers-reduced-motion: reduce)").matches;
|
| 5 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/routes/+layout.server.ts
CHANGED
|
@@ -147,6 +147,7 @@ export const load: LayoutServerLoad = async ({ locals, depends }) => {
|
|
| 147 |
customPrompts: settings?.customPrompts ?? {},
|
| 148 |
assistants: userAssistants,
|
| 149 |
tools: settings?.tools ?? {},
|
|
|
|
| 150 |
},
|
| 151 |
models: models.map((model) => ({
|
| 152 |
id: model.id,
|
|
|
|
| 147 |
customPrompts: settings?.customPrompts ?? {},
|
| 148 |
assistants: userAssistants,
|
| 149 |
tools: settings?.tools ?? {},
|
| 150 |
+
disableStream: settings?.disableStream ?? DEFAULT_SETTINGS.disableStream,
|
| 151 |
},
|
| 152 |
models: models.map((model) => ({
|
| 153 |
id: model.id,
|
src/routes/conversation/[id]/+page.svelte
CHANGED
|
@@ -23,7 +23,6 @@
|
|
| 23 |
import { fetchMessageUpdates } from "$lib/utils/messageUpdates";
|
| 24 |
import { createConvTreeStore } from "$lib/stores/convTree";
|
| 25 |
import type { v4 } from "uuid";
|
| 26 |
-
import { isReducedMotion } from "$lib/utils/isReduceMotion.js";
|
| 27 |
import { useSettingsStore } from "$lib/stores/settings.js";
|
| 28 |
|
| 29 |
export let data;
|
|
@@ -80,8 +79,6 @@
|
|
| 80 |
$isAborted = false;
|
| 81 |
loading = true;
|
| 82 |
pending = true;
|
| 83 |
-
const reducedMotionMode = isReducedMotion(window);
|
| 84 |
-
|
| 85 |
const base64Files = await Promise.all(
|
| 86 |
(files ?? []).map((file) =>
|
| 87 |
file2base64(file).then((value) => ({
|
|
@@ -237,7 +234,7 @@
|
|
| 237 |
|
| 238 |
messageUpdates.push(update);
|
| 239 |
|
| 240 |
-
if (update.type === MessageUpdateType.Stream &&
|
| 241 |
messageToWriteTo.content += update.token;
|
| 242 |
pending = false;
|
| 243 |
messages = [...messages];
|
|
|
|
| 23 |
import { fetchMessageUpdates } from "$lib/utils/messageUpdates";
|
| 24 |
import { createConvTreeStore } from "$lib/stores/convTree";
|
| 25 |
import type { v4 } from "uuid";
|
|
|
|
| 26 |
import { useSettingsStore } from "$lib/stores/settings.js";
|
| 27 |
|
| 28 |
export let data;
|
|
|
|
| 79 |
$isAborted = false;
|
| 80 |
loading = true;
|
| 81 |
pending = true;
|
|
|
|
|
|
|
| 82 |
const base64Files = await Promise.all(
|
| 83 |
(files ?? []).map((file) =>
|
| 84 |
file2base64(file).then((value) => ({
|
|
|
|
| 234 |
|
| 235 |
messageUpdates.push(update);
|
| 236 |
|
| 237 |
+
if (update.type === MessageUpdateType.Stream && !$settings.disableStream) {
|
| 238 |
messageToWriteTo.content += update.token;
|
| 239 |
pending = false;
|
| 240 |
messages = [...messages];
|
src/routes/settings/(nav)/+page.svelte
CHANGED
|
@@ -46,6 +46,14 @@
|
|
| 46 |
</div>
|
| 47 |
</label>
|
| 48 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
<div class="mt-12 flex flex-col gap-3">
|
| 50 |
<a
|
| 51 |
href="https://huggingface.co/spaces/huggingchat/chat-ui/discussions"
|
|
|
|
| 46 |
</div>
|
| 47 |
</label>
|
| 48 |
|
| 49 |
+
<!-- svelte-ignore a11y-label-has-associated-control -->
|
| 50 |
+
<label class="mt-6 flex items-center">
|
| 51 |
+
<Switch name="disableStream" bind:checked={$settings.disableStream} />
|
| 52 |
+
<div class="inline cursor-pointer select-none items-center gap-2 pl-2">
|
| 53 |
+
Disable streaming tokens
|
| 54 |
+
</div>
|
| 55 |
+
</label>
|
| 56 |
+
|
| 57 |
<div class="mt-12 flex flex-col gap-3">
|
| 58 |
<a
|
| 59 |
href="https://huggingface.co/spaces/huggingchat/chat-ui/discussions"
|
src/routes/settings/(nav)/+server.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
import { collections } from "$lib/server/database";
|
| 2 |
import { z } from "zod";
|
| 3 |
import { authCondition } from "$lib/server/auth";
|
| 4 |
-
import { DEFAULT_SETTINGS } from "$lib/types/Settings";
|
| 5 |
|
| 6 |
export async function POST({ request, locals }) {
|
| 7 |
const body = await request.json();
|
|
@@ -16,8 +16,9 @@ export async function POST({ request, locals }) {
|
|
| 16 |
activeModel: z.string().default(DEFAULT_SETTINGS.activeModel),
|
| 17 |
customPrompts: z.record(z.string()).default({}),
|
| 18 |
tools: z.record(z.boolean()).optional(),
|
|
|
|
| 19 |
})
|
| 20 |
-
.parse(body);
|
| 21 |
|
| 22 |
await collections.settings.updateOne(
|
| 23 |
authCondition(locals),
|
|
|
|
| 1 |
import { collections } from "$lib/server/database";
|
| 2 |
import { z } from "zod";
|
| 3 |
import { authCondition } from "$lib/server/auth";
|
| 4 |
+
import { DEFAULT_SETTINGS, type SettingsEditable } from "$lib/types/Settings";
|
| 5 |
|
| 6 |
export async function POST({ request, locals }) {
|
| 7 |
const body = await request.json();
|
|
|
|
| 16 |
activeModel: z.string().default(DEFAULT_SETTINGS.activeModel),
|
| 17 |
customPrompts: z.record(z.string()).default({}),
|
| 18 |
tools: z.record(z.boolean()).optional(),
|
| 19 |
+
disableStream: z.boolean().default(false),
|
| 20 |
})
|
| 21 |
+
.parse(body) satisfies SettingsEditable;
|
| 22 |
|
| 23 |
await collections.settings.updateOne(
|
| 24 |
authCondition(locals),
|