unbrandedhuman commited on
Commit
8f3d5b1
·
1 Parent(s): df29fd0

Delete src

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. src/app.d.ts +0 -20
  2. src/app.html +0 -73
  3. src/hooks.server.ts +0 -95
  4. src/lib/actions/snapScrollToBottom.ts +0 -54
  5. src/lib/buildPrompt.ts +0 -36
  6. src/lib/components/AnnouncementBanner.svelte +0 -15
  7. src/lib/components/CodeBlock.svelte +0 -28
  8. src/lib/components/CopyToClipBoardBtn.svelte +0 -50
  9. src/lib/components/EthicsModal.svelte +0 -47
  10. src/lib/components/MobileNav.svelte +0 -62
  11. src/lib/components/Modal.svelte +0 -59
  12. src/lib/components/ModelCardMetadata.svelte +0 -48
  13. src/lib/components/ModelsModal.svelte +0 -80
  14. src/lib/components/NavMenu.svelte +0 -109
  15. src/lib/components/Portal.svelte +0 -19
  16. src/lib/components/ScrollToBottomBtn.svelte +0 -46
  17. src/lib/components/SettingsModal.svelte +0 -65
  18. src/lib/components/StopGeneratingBtn.svelte +0 -17
  19. src/lib/components/Switch.svelte +0 -11
  20. src/lib/components/Toast.svelte +0 -19
  21. src/lib/components/Tooltip.svelte +0 -22
  22. src/lib/components/chat/ChatInput.svelte +0 -64
  23. src/lib/components/chat/ChatIntroduction.svelte +0 -77
  24. src/lib/components/chat/ChatMessage.svelte +0 -148
  25. src/lib/components/chat/ChatMessages.svelte +0 -65
  26. src/lib/components/chat/ChatWindow.svelte +0 -105
  27. src/lib/components/icons/IconChevron.svelte +0 -20
  28. src/lib/components/icons/IconCopy.svelte +0 -26
  29. src/lib/components/icons/IconDazzled.svelte +0 -36
  30. src/lib/components/icons/IconLoading.svelte +0 -31
  31. src/lib/components/icons/Logo.svelte +0 -25
  32. src/lib/constants/publicSepToken.ts +0 -1
  33. src/lib/server/abortedGenerations.ts +0 -29
  34. src/lib/server/auth.ts +0 -9
  35. src/lib/server/database.ts +0 -52
  36. src/lib/server/modelEndpoint.ts +0 -32
  37. src/lib/server/models.ts +0 -80
  38. src/lib/shareConversation.ts +0 -27
  39. src/lib/stores/errors.ts +0 -7
  40. src/lib/stores/pendingMessage.ts +0 -3
  41. src/lib/stores/pendingMessageIdToRetry.ts +0 -4
  42. src/lib/switchTheme.ts +0 -10
  43. src/lib/types/AbortedGeneration.ts +0 -8
  44. src/lib/types/Conversation.ts +0 -20
  45. src/lib/types/Message.ts +0 -5
  46. src/lib/types/Model.ts +0 -13
  47. src/lib/types/Settings.ts +0 -16
  48. src/lib/types/SharedConversation.ts +0 -12
  49. src/lib/types/Timestamps.ts +0 -4
  50. src/lib/types/UrlDependency.ts +0 -4
src/app.d.ts DELETED
@@ -1,20 +0,0 @@
1
- /// <reference types="@sveltejs/kit" />
2
- /// <reference types="unplugin-icons/types/svelte" />
3
-
4
- import type { ObjectId } from "mongodb";
5
-
6
- // See https://kit.svelte.dev/docs/types#app
7
- // for information about these interfaces
8
- declare global {
9
- namespace App {
10
- // interface Error {}
11
- interface Locals {
12
- sessionId: string;
13
- userId?: ObjectId;
14
- }
15
- // interface PageData {}
16
- // interface Platform {}
17
- }
18
- }
19
-
20
- export {};
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/app.html DELETED
@@ -1,73 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en" class="h-full">
3
- <head>
4
- <meta charset="utf-8" />
5
- <link rel="icon" href="%sveltekit.assets%/favicon.png" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
7
- <title>Macie</title>
8
- <script>
9
- if (
10
- localStorage.theme === "dark" ||
11
- (!("theme" in localStorage) && window.matchMedia("(prefers-color-scheme: dark)").matches)
12
- ) {
13
- document.documentElement.classList.add("dark");
14
- }
15
-
16
- // For some reason, Sveltekit doesn't let us load env variables from .env here, so we load it from hooks.server.ts
17
- window.gaId = "%gaId%";
18
- window.gaIdDeprecated = "%gaIdDeprecated%";
19
- </script>
20
- %sveltekit.head%
21
- </head>
22
- <body data-sveltekit-preload-data="hover" class="h-full dark:bg-gray-900">
23
- <div id="app" class="contents h-full">%sveltekit.body%</div>
24
-
25
- <!-- Google Tag Manager -->
26
- <script>
27
- if (window.gaId) {
28
- const script = document.createElement("script");
29
- script.src = "https://www.googletagmanager.com/gtag/js?id=" + window.gaId;
30
- script.async = true;
31
- document.head.appendChild(script);
32
-
33
- window.dataLayer = window.dataLayer || [];
34
- function gtag() {
35
- dataLayer.push(arguments);
36
- }
37
- gtag("js", new Date());
38
- /// ^ See https://developers.google.com/tag-platform/gtagjs/install
39
- gtag("config", window.gaId);
40
- gtag("consent", "default", { ad_storage: "denied", analytics_storage: "denied" });
41
- /// ^ See https://developers.google.com/tag-platform/gtagjs/reference#consent
42
- /// TODO: ask the user for their consent and update this with gtag('consent', 'update')
43
- }
44
- </script>
45
-
46
- <!-- Google Analytics v3 (deprecated on 1 July 2023) -->
47
- <script>
48
- if (window.gaIdDeprecated) {
49
- (function (i, s, o, g, r, a, m) {
50
- i["GoogleAnalyticsObject"] = r;
51
- (i[r] =
52
- i[r] ||
53
- function () {
54
- (i[r].q = i[r].q || []).push(arguments);
55
- }),
56
- (i[r].l = 1 * new Date());
57
- (a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]);
58
- a.async = 1;
59
- a.src = g;
60
- m.parentNode.insertBefore(a, m);
61
- })(
62
- window,
63
- document,
64
- "script",
65
- "https://www.google-analytics.com/analytics.js",
66
- "ganalytics"
67
- );
68
- ganalytics("create", window.gaIdDeprecated, "auto");
69
- ganalytics("send", "pageview");
70
- }
71
- </script>
72
- </body>
73
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/hooks.server.ts DELETED
@@ -1,95 +0,0 @@
1
- import { dev } from "$app/environment";
2
- import { COOKIE_NAME } from "$env/static/private";
3
- import type { Handle } from "@sveltejs/kit";
4
- import {
5
- PUBLIC_GOOGLE_ANALYTICS_ID,
6
- PUBLIC_DEPRECATED_GOOGLE_ANALYTICS_ID,
7
- } from "$env/static/public";
8
- import { addYears } from "date-fns";
9
- import { collections } from "$lib/server/database";
10
- import { base } from "$app/paths";
11
- import { requiresUser } from "$lib/server/auth";
12
-
13
- export const handle: Handle = async ({ event, resolve }) => {
14
- const token = event.cookies.get(COOKIE_NAME);
15
-
16
- event.locals.sessionId = token || crypto.randomUUID();
17
-
18
- const user = await collections.users.findOne({ sessionId: event.locals.sessionId });
19
-
20
- if (user) {
21
- event.locals.userId = user._id;
22
- }
23
-
24
- if (
25
- !event.url.pathname.startsWith(`${base}/admin`) &&
26
- !["GET", "OPTIONS", "HEAD"].includes(event.request.method)
27
- ) {
28
- const sendJson =
29
- event.request.headers.get("accept")?.includes("application/json") ||
30
- event.request.headers.get("content-type")?.includes("application/json");
31
-
32
- if (!user && requiresUser) {
33
- return new Response(
34
- sendJson
35
- ? JSON.stringify({ error: "You need to be logged in first" })
36
- : "You need to be logged in first",
37
- {
38
- status: 401,
39
- headers: {
40
- "content-type": sendJson ? "application/json" : "text/plain",
41
- },
42
- }
43
- );
44
- }
45
-
46
- if (!event.url.pathname.startsWith(`${base}/settings`)) {
47
- const hasAcceptedEthicsModal = await collections.settings.countDocuments({
48
- sessionId: event.locals.sessionId,
49
- ethicsModalAcceptedAt: { $exists: true },
50
- });
51
-
52
- if (!hasAcceptedEthicsModal) {
53
- return new Response(
54
- sendJson
55
- ? JSON.stringify({ error: "You need to accept the welcome modal first" })
56
- : "You need to accept the welcome modal first",
57
- {
58
- status: 405,
59
- headers: {
60
- "content-type": sendJson ? "application/json" : "text/plain",
61
- },
62
- }
63
- );
64
- }
65
- }
66
- }
67
-
68
- // Refresh cookie expiration date
69
- event.cookies.set(COOKIE_NAME, event.locals.sessionId, {
70
- path: "/",
71
- // So that it works inside the space's iframe
72
- sameSite: dev ? "lax" : "none",
73
- secure: !dev,
74
- httpOnly: true,
75
- expires: addYears(new Date(), 1),
76
- });
77
-
78
- let replaced = false;
79
-
80
- const response = await resolve(event, {
81
- transformPageChunk: (chunk) => {
82
- // For some reason, Sveltekit doesn't let us load env variables from .env in the app.html template
83
- if (replaced || !chunk.html.includes("%gaId%") || !chunk.html.includes("%gaIdDeprecated%")) {
84
- return chunk.html;
85
- }
86
- replaced = true;
87
-
88
- return chunk.html
89
- .replace("%gaId%", PUBLIC_GOOGLE_ANALYTICS_ID)
90
- .replace("%gaIdDeprecated%", PUBLIC_DEPRECATED_GOOGLE_ANALYTICS_ID);
91
- },
92
- });
93
-
94
- return response;
95
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/actions/snapScrollToBottom.ts DELETED
@@ -1,54 +0,0 @@
1
- import { navigating } from "$app/stores";
2
- import { tick } from "svelte";
3
- import { get } from "svelte/store";
4
-
5
- const detachedOffset = 10;
6
-
7
- /**
8
- * @param node element to snap scroll to bottom
9
- * @param dependency pass in a dependency to update scroll on changes.
10
- */
11
- export const snapScrollToBottom = (node: HTMLElement, dependency: unknown) => {
12
- let prevScrollValue = node.scrollTop;
13
- let isDetached = false;
14
-
15
- const handleScroll = () => {
16
- // if user scrolled up, we detach
17
- if (node.scrollTop < prevScrollValue) {
18
- isDetached = true;
19
- }
20
-
21
- // if user scrolled back to within 10px of bottom, we reattach
22
- if (node.scrollTop - (node.scrollHeight - node.clientHeight) >= -detachedOffset) {
23
- isDetached = false;
24
- }
25
-
26
- prevScrollValue = node.scrollTop;
27
- };
28
-
29
- const updateScroll = async (_options: { force?: boolean } = {}) => {
30
- const defaultOptions = { force: false };
31
- const options = { ...defaultOptions, ..._options };
32
- const { force } = options;
33
-
34
- if (!force && isDetached && !get(navigating)) return;
35
-
36
- // wait for next tick to ensure that the DOM is updated
37
- await tick();
38
-
39
- node.scrollTo({ top: node.scrollHeight });
40
- };
41
-
42
- node.addEventListener("scroll", handleScroll);
43
-
44
- if (dependency) {
45
- updateScroll({ force: true });
46
- }
47
-
48
- return {
49
- update: updateScroll,
50
- destroy: () => {
51
- node.removeEventListener("scroll", handleScroll);
52
- },
53
- };
54
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/buildPrompt.ts DELETED
@@ -1,36 +0,0 @@
1
- import type { BackendModel } from "./server/models";
2
- import type { Message } from "./types/Message";
3
-
4
- /**
5
- * Convert [{user: "assistant", content: "hi"}, {user: "user", content: "hello"}] to:
6
- *
7
- * <|assistant|>hi<|endoftext|><|prompter|>hello<|endoftext|><|assistant|>
8
- */
9
- export function buildPrompt(
10
- messages: Pick<Message, "from" | "content">[],
11
- model: BackendModel
12
- ): string {
13
- const prompt =
14
- messages
15
- .map(
16
- (m) =>
17
- (m.from === "user"
18
- ? model.userMessageToken + m.content
19
- : model.assistantMessageToken + m.content) +
20
- (model.messageEndToken
21
- ? m.content.endsWith(model.messageEndToken)
22
- ? ""
23
- : model.messageEndToken
24
- : "")
25
- )
26
- .join("") + model.assistantMessageToken;
27
-
28
- // Not super precise, but it's truncated in the model's backend anyway
29
- return (
30
- model.preprompt +
31
- prompt
32
- .split(" ")
33
- .slice(-(model.parameters?.truncate ?? 0))
34
- .join(" ")
35
- );
36
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/AnnouncementBanner.svelte DELETED
@@ -1,15 +0,0 @@
1
- <script lang="ts">
2
- export let title = "";
3
- export let classNames = "";
4
- </script>
5
-
6
- <div class="flex items-center rounded-xl bg-gray-100 p-1 text-sm dark:bg-gray-800 {classNames}">
7
- <span
8
- class="mr-2 inline-flex items-center rounded-lg bg-gradient-to-br from-yellow-300 px-2 py-1 text-xxs font-medium uppercase leading-3 text-yellow-700 dark:from-[#373010] dark:text-yellow-400"
9
- >New</span
10
- >
11
- {title}
12
- <div class="ml-auto shrink-0">
13
- <slot />
14
- </div>
15
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/CodeBlock.svelte DELETED
@@ -1,28 +0,0 @@
1
- <script lang="ts">
2
- import { afterUpdate } from "svelte";
3
- import CopyToClipBoardBtn from "./CopyToClipBoardBtn.svelte";
4
-
5
- export let code = "";
6
- export let lang = "";
7
-
8
- $: highlightedCode = "";
9
-
10
- afterUpdate(async () => {
11
- const { default: hljs } = await import("highlight.js");
12
- const language = hljs.getLanguage(lang);
13
-
14
- highlightedCode = hljs.highlightAuto(code, language?.aliases).value;
15
- });
16
- </script>
17
-
18
- <div class="group relative my-4 rounded-lg">
19
- <!-- eslint-disable svelte/no-at-html-tags -->
20
- <pre
21
- class="scrollbar-custom overflow-auto px-5 scrollbar-thumb-gray-500 hover:scrollbar-thumb-gray-400 dark:scrollbar-thumb-white/10 dark:hover:scrollbar-thumb-white/20"><code
22
- class="language-{lang}">{@html highlightedCode || code.replaceAll("<", "&lt;")}</code
23
- ></pre>
24
- <CopyToClipBoardBtn
25
- classNames="absolute top-2 right-2 invisible opacity-0 group-hover:visible group-hover:opacity-100"
26
- value={code}
27
- />
28
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/CopyToClipBoardBtn.svelte DELETED
@@ -1,50 +0,0 @@
1
- <script lang="ts">
2
- import { onDestroy } from "svelte";
3
-
4
- import IconCopy from "./icons/IconCopy.svelte";
5
- import Tooltip from "./Tooltip.svelte";
6
-
7
- export let classNames = "";
8
- export let value: string;
9
-
10
- let isSuccess = false;
11
- let timeout: ReturnType<typeof setTimeout>;
12
-
13
- const handleClick = async () => {
14
- // writeText() can be unavailable or fail in some cases (iframe, etc) so we try/catch
15
- try {
16
- await navigator.clipboard.writeText(value);
17
-
18
- isSuccess = true;
19
- if (timeout) {
20
- clearTimeout(timeout);
21
- }
22
- timeout = setTimeout(() => {
23
- isSuccess = false;
24
- }, 1000);
25
- } catch (err) {
26
- console.error(err);
27
- }
28
- };
29
-
30
- onDestroy(() => {
31
- if (timeout) {
32
- clearTimeout(timeout);
33
- }
34
- });
35
- </script>
36
-
37
- <button
38
- class="btn rounded-lg border border-gray-200 px-2 py-2 text-sm shadow-sm transition-all hover:border-gray-300 active:shadow-inner dark:border-gray-600 dark:hover:border-gray-400 {classNames}
39
- {!isSuccess && 'text-gray-200 dark:text-gray-200'}
40
- {isSuccess && 'text-green-500'}
41
- "
42
- title={"Copy to clipboard"}
43
- type="button"
44
- on:click={handleClick}
45
- >
46
- <span class="relative">
47
- <IconCopy />
48
- <Tooltip classNames={isSuccess ? "opacity-100" : "opacity-0"} />
49
- </span>
50
- </button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/EthicsModal.svelte DELETED
@@ -1,47 +0,0 @@
1
- <script lang="ts">
2
- import { enhance } from "$app/forms";
3
- import { base } from "$app/paths";
4
- import { PUBLIC_VERSION } from "$env/static/public";
5
- import Logo from "$lib/components/icons/Logo.svelte";
6
- import Modal from "$lib/components/Modal.svelte";
7
- import type { LayoutData } from "../../routes/$types";
8
-
9
- export let settings: LayoutData["settings"];
10
- </script>
11
-
12
- <Modal>
13
- <div
14
- class="flex w-full flex-col items-center gap-6 bg-gradient-to-t from-yellow-500/40 via-yellow-500/10 to-yellow-500/0 px-4 pb-10 pt-9 text-center"
15
- >
16
- <h2 class="flex items-center text-2xl font-semibold text-gray-800">
17
- <Logo classNames="text-3xl mr-1.5" />HuggingChat
18
- <div
19
- class="ml-3 flex h-6 items-center rounded-lg border border-gray-100 bg-gray-50 px-2 text-base text-gray-400"
20
- >
21
- v{PUBLIC_VERSION}
22
- </div>
23
- </h2>
24
- <p class="px-4 text-lg font-semibold leading-snug text-gray-800 sm:px-12">
25
- This application is for demonstration purposes only.
26
- </p>
27
- <p class="text-gray-800">
28
- AI is an area of active research with known problems such as biased generation and
29
- misinformation. Do not use this application for high-stakes decisions or advice.
30
- </p>
31
- <p class="px-2 text-sm text-gray-500">
32
- Your conversations will be shared with model authors unless you disable it from your settings.
33
- </p>
34
- <form action="{base}/settings" use:enhance method="POST">
35
- <input type="hidden" name="ethicsModalAccepted" value={true} />
36
- {#each Object.entries(settings) as [key, val]}
37
- <input type="hidden" name={key} value={val} />
38
- {/each}
39
- <button
40
- type="submit"
41
- class="mt-2 rounded-full bg-black px-5 py-2 text-lg font-semibold text-gray-100 transition-colors hover:bg-yellow-500"
42
- >
43
- Start chatting
44
- </button>
45
- </form>
46
- </div>
47
- </Modal>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/MobileNav.svelte DELETED
@@ -1,62 +0,0 @@
1
- <script lang="ts">
2
- import { navigating } from "$app/stores";
3
- import { createEventDispatcher } from "svelte";
4
- import { browser } from "$app/environment";
5
- import { base } from "$app/paths";
6
-
7
- import CarbonClose from "~icons/carbon/close";
8
- import CarbonAdd from "~icons/carbon/add";
9
- import CarbonTextAlignJustify from "~icons/carbon/text-align-justify";
10
-
11
- export let isOpen = false;
12
- export let title: string | undefined;
13
-
14
- $: title = title || "New Chat";
15
-
16
- let closeEl: HTMLButtonElement;
17
- let openEl: HTMLButtonElement;
18
-
19
- const dispatch = createEventDispatcher();
20
-
21
- $: if ($navigating) {
22
- dispatch("toggle", false);
23
- }
24
-
25
- $: if (isOpen && closeEl) {
26
- closeEl.focus();
27
- } else if (!isOpen && browser && document.activeElement === closeEl) {
28
- openEl.focus();
29
- }
30
- </script>
31
-
32
- <nav
33
- class="flex h-12 items-center justify-between border-b bg-gray-50 px-4 dark:border-gray-800 dark:bg-gray-800/70 md:hidden"
34
- >
35
- <button
36
- type="button"
37
- class="-ml-3 flex h-9 w-9 shrink-0 items-center justify-center"
38
- on:click={() => dispatch("toggle", true)}
39
- aria-label="Open menu"
40
- bind:this={openEl}><CarbonTextAlignJustify /></button
41
- >
42
- <span class="truncate px-4">{title}</span>
43
- <a href={base || "/"} class="-mr-3 flex h-9 w-9 shrink-0 items-center justify-center"
44
- ><CarbonAdd /></a
45
- >
46
- </nav>
47
- <nav
48
- class="fixed inset-0 z-30 grid max-h-screen grid-cols-1 grid-rows-[auto,auto,1fr,auto] bg-white bg-gradient-to-l from-gray-50 dark:bg-gray-900 dark:from-gray-800/30 {isOpen
49
- ? 'block'
50
- : 'hidden'}"
51
- >
52
- <div class="flex h-12 items-center px-4">
53
- <button
54
- type="button"
55
- class="-mr-3 ml-auto flex h-9 w-9 items-center justify-center"
56
- on:click={() => dispatch("toggle", false)}
57
- aria-label="Close menu"
58
- bind:this={closeEl}><CarbonClose /></button
59
- >
60
- </div>
61
- <slot />
62
- </nav>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/Modal.svelte DELETED
@@ -1,59 +0,0 @@
1
- <script lang="ts">
2
- import { createEventDispatcher, onDestroy, onMount } from "svelte";
3
- import { cubicOut } from "svelte/easing";
4
- import { fade } from "svelte/transition";
5
- import Portal from "./Portal.svelte";
6
- import { browser } from "$app/environment";
7
-
8
- export let width = "max-w-sm";
9
-
10
- let backdropEl: HTMLDivElement;
11
- let modalEl: HTMLDivElement;
12
-
13
- const dispatch = createEventDispatcher<{ close: void }>();
14
-
15
- function handleKeydown(event: KeyboardEvent) {
16
- // close on ESC
17
- if (event.key === "Escape") {
18
- event.preventDefault();
19
- dispatch("close");
20
- }
21
- }
22
-
23
- function handleBackdropClick(event: MouseEvent) {
24
- if (event.target === backdropEl) {
25
- dispatch("close");
26
- }
27
- }
28
-
29
- onMount(() => {
30
- document.getElementById("app")?.setAttribute("inert", "true");
31
- modalEl.focus();
32
- });
33
-
34
- onDestroy(() => {
35
- if (!browser) return;
36
- document.getElementById("app")?.removeAttribute("inert");
37
- });
38
- </script>
39
-
40
- <Portal>
41
- <div
42
- role="presentation"
43
- tabindex="-1"
44
- bind:this={backdropEl}
45
- on:click={handleBackdropClick}
46
- transition:fade={{ easing: cubicOut, duration: 300 }}
47
- class="fixed inset-0 z-40 flex items-center justify-center bg-black/80 p-8 backdrop-blur-sm dark:bg-black/50"
48
- >
49
- <div
50
- role="dialog"
51
- tabindex="-1"
52
- bind:this={modalEl}
53
- on:keydown={handleKeydown}
54
- class="-mt-10 overflow-hidden rounded-2xl bg-white shadow-2xl outline-none md:-mt-20 {width}"
55
- >
56
- <slot />
57
- </div>
58
- </div>
59
- </Portal>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/ModelCardMetadata.svelte DELETED
@@ -1,48 +0,0 @@
1
- <script lang="ts">
2
- import CarbonEarth from "~icons/carbon/earth";
3
- import CarbonArrowUpRight from "~icons/carbon/arrow-up-right";
4
- import type { Model } from "$lib/types/Model";
5
-
6
- export let model: Pick<Model, "name" | "datasetName" | "websiteUrl">;
7
-
8
- export let variant: "light" | "dark" = "light";
9
- </script>
10
-
11
- <div
12
- class="flex items-center gap-5 rounded-xl bg-gray-100 px-3 py-2 text-sm
13
- {variant === 'dark'
14
- ? 'text-gray-600 dark:bg-gray-800 dark:text-gray-300'
15
- : 'text-gray-800 dark:bg-gray-100 dark:text-gray-600'}"
16
- >
17
- <a
18
- href="https://huggingface.co/{model.name}"
19
- target="_blank"
20
- rel="noreferrer"
21
- class="flex items-center hover:underline"
22
- ><CarbonArrowUpRight class="mr-1.5 shrink-0 text-xs text-gray-400" />
23
- Model
24
- <div class="max-sm:hidden">&nbsp;page</div></a
25
- >
26
- {#if model.datasetName}
27
- <a
28
- href="https://huggingface.co/datasets/{model.datasetName}"
29
- target="_blank"
30
- rel="noreferrer"
31
- class="flex items-center hover:underline"
32
- ><CarbonArrowUpRight class="mr-1.5 shrink-0 text-xs text-gray-400" />
33
- Dataset
34
- <div class="max-sm:hidden">&nbsp;page</div></a
35
- >
36
- {/if}
37
- {#if model.websiteUrl}
38
- <a
39
- href={model.websiteUrl}
40
- target="_blank"
41
- class="ml-auto flex items-center hover:underline"
42
- rel="noreferrer"
43
- >
44
- <CarbonEarth class="mr-1.5 shrink-0 text-xs text-gray-400" />
45
- Website
46
- </a>
47
- {/if}
48
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/ModelsModal.svelte DELETED
@@ -1,80 +0,0 @@
1
- <script lang="ts">
2
- import { createEventDispatcher } from "svelte";
3
-
4
- import Modal from "$lib/components/Modal.svelte";
5
- import CarbonClose from "~icons/carbon/close";
6
- import CarbonCheckmark from "~icons/carbon/checkmark-filled";
7
- import ModelCardMetadata from "./ModelCardMetadata.svelte";
8
- import type { Model } from "$lib/types/Model";
9
- import type { LayoutData } from "../../routes/$types";
10
- import { enhance } from "$app/forms";
11
- import { base } from "$app/paths";
12
-
13
- export let settings: LayoutData["settings"];
14
- export let models: Array<Model>;
15
-
16
- let selectedModelId = settings.activeModel;
17
-
18
- const dispatch = createEventDispatcher<{ close: void }>();
19
- </script>
20
-
21
- <Modal width="max-w-lg" on:close>
22
- <form
23
- action="{base}/settings"
24
- method="post"
25
- use:enhance={() => {
26
- dispatch("close");
27
- }}
28
- class="flex w-full flex-col gap-5 p-6"
29
- >
30
- {#each Object.entries(settings).filter(([k]) => k !== "activeModel") as [key, val]}
31
- <input type="hidden" name={key} value={val} />
32
- {/each}
33
- <div class="flex items-start justify-between text-xl font-semibold text-gray-800">
34
- <h2>Models</h2>
35
- <button type="button" class="group" on:click={() => dispatch("close")}>
36
- <CarbonClose class="text-gray-900 group-hover:text-gray-500" />
37
- </button>
38
- </div>
39
-
40
- <div class="space-y-4">
41
- {#each models as model}
42
- <div
43
- class="rounded-xl border border-gray-100 {model.id === selectedModelId
44
- ? 'bg-gradient-to-r from-yellow-200/40 via-yellow-500/10'
45
- : ''}"
46
- >
47
- <label class="group flex cursor-pointer p-3" on:change aria-label={model.displayName}>
48
- <input
49
- type="radio"
50
- class="sr-only"
51
- name="activeModel"
52
- value={model.id}
53
- bind:group={selectedModelId}
54
- />
55
- <span>
56
- <span class="text-md block font-semibold leading-tight text-gray-800"
57
- >{model.displayName}</span
58
- >
59
- {#if model.description}
60
- <span class="text-xs text-[#9FA8B5]">{model.description}</span>
61
- {/if}
62
- </span>
63
- <CarbonCheckmark
64
- class="-mr-1 -mt-1 ml-auto shrink-0 text-xl {model.id === selectedModelId
65
- ? 'text-yellow-400'
66
- : 'text-transparent group-hover:text-gray-200'}"
67
- />
68
- </label>
69
- <ModelCardMetadata {model} />
70
- </div>
71
- {/each}
72
- </div>
73
- <button
74
- type="submit"
75
- class="mt-2 rounded-full bg-black px-5 py-2 text-lg font-semibold text-gray-100 ring-gray-400 ring-offset-1 transition-colors hover:ring"
76
- >
77
- Apply
78
- </button>
79
- </form>
80
- </Modal>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/NavMenu.svelte DELETED
@@ -1,109 +0,0 @@
1
- <script lang="ts">
2
- import { base } from "$app/paths";
3
- import { page } from "$app/stores";
4
- import { createEventDispatcher } from "svelte";
5
-
6
- import Logo from "$lib/components/icons/Logo.svelte";
7
- import CarbonTrashCan from "~icons/carbon/trash-can";
8
- import CarbonEdit from "~icons/carbon/edit";
9
-
10
- import { switchTheme } from "$lib/switchTheme";
11
- import { PUBLIC_ORIGIN } from "$env/static/public";
12
-
13
- const dispatch = createEventDispatcher<{
14
- shareConversation: { id: string; title: string };
15
- deleteConversation: string;
16
- clickSettings: void;
17
- editConversationTitle: { id: string; title: string };
18
- }>();
19
-
20
- export let conversations: Array<{
21
- id: string;
22
- title: string;
23
- }> = [];
24
- </script>
25
-
26
- <div class="sticky top-0 flex flex-none items-center justify-between px-3 py-3.5 max-sm:pt-0">
27
- <a class="flex items-center rounded-xl text-lg font-semibold" href="{PUBLIC_ORIGIN}{base}/">
28
- <Logo classNames="mr-1 text-3xl" />
29
- HuggingChat
30
- </a>
31
- <a
32
- href={base || "/"}
33
- class="flex rounded-lg border bg-white px-2 py-0.5 text-center shadow-sm hover:shadow-none dark:border-gray-600 dark:bg-gray-700"
34
- >
35
- New Chat
36
- </a>
37
- </div>
38
- <div
39
- class="scrollbar-custom flex flex-col gap-1 overflow-y-auto rounded-r-xl bg-gradient-to-l from-gray-50 px-3 pb-3 pt-2 dark:from-gray-800/30"
40
- >
41
- {#each conversations as conv (conv.id)}
42
- <a
43
- data-sveltekit-noscroll
44
- href="{base}/conversation/{conv.id}"
45
- class="group flex h-11 flex-none items-center gap-1.5 rounded-lg pl-3 pr-2 text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700 {conv.id ===
46
- $page.params.id
47
- ? 'bg-gray-100 dark:bg-gray-700'
48
- : ''}"
49
- >
50
- <div class="flex-1 truncate">{conv.title}</div>
51
-
52
- <button
53
- type="button"
54
- class="flex h-5 w-5 items-center justify-center rounded md:hidden md:group-hover:flex"
55
- title="Edit conversation title"
56
- on:click|preventDefault={() => {
57
- const newTitle = prompt("Edit this conversation title:", conv.title);
58
- if (!newTitle) return;
59
- dispatch("editConversationTitle", { id: conv.id, title: newTitle });
60
- }}
61
- >
62
- <CarbonEdit class="text-xs text-gray-400 hover:text-gray-500 dark:hover:text-gray-300" />
63
- </button>
64
-
65
- <button
66
- type="button"
67
- class="flex h-5 w-5 items-center justify-center rounded md:hidden md:group-hover:flex"
68
- title="Delete conversation"
69
- on:click|preventDefault={() => dispatch("deleteConversation", conv.id)}
70
- >
71
- <CarbonTrashCan
72
- class="text-xs text-gray-400 hover:text-gray-500 dark:hover:text-gray-300"
73
- />
74
- </button>
75
- </a>
76
- {/each}
77
- </div>
78
- <div
79
- class="mt-0.5 flex flex-col gap-1 rounded-r-xl bg-gradient-to-l from-gray-50 p-3 text-sm dark:from-gray-800/30"
80
- >
81
- <button
82
- on:click={switchTheme}
83
- type="button"
84
- class="group flex h-9 flex-none items-center gap-1.5 rounded-lg pl-3 pr-2 text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700"
85
- >
86
- Theme
87
- </button>
88
- <button
89
- on:click={() => dispatch("clickSettings")}
90
- type="button"
91
- class="group flex h-9 flex-none items-center gap-1.5 rounded-lg pl-3 pr-2 text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700"
92
- >
93
- Settings
94
- </button>
95
- <a
96
- href="https://huggingface.co/spaces/huggingchat/chat-ui/discussions"
97
- target="_blank"
98
- rel="noreferrer"
99
- class="group flex h-9 flex-none items-center gap-1.5 rounded-lg pl-3 pr-2 text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700"
100
- >
101
- Feedback
102
- </a>
103
- <a
104
- href="{base}/privacy"
105
- class="group flex h-9 flex-none items-center gap-1.5 rounded-lg pl-3 pr-2 text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700"
106
- >
107
- About & Privacy
108
- </a>
109
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/Portal.svelte DELETED
@@ -1,19 +0,0 @@
1
- <script lang="ts">
2
- import { onMount, onDestroy } from "svelte";
3
-
4
- let el: HTMLElement;
5
-
6
- onMount(() => {
7
- el.ownerDocument.body.appendChild(el);
8
- });
9
-
10
- onDestroy(() => {
11
- if (el?.parentNode) {
12
- el.parentNode.removeChild(el);
13
- }
14
- });
15
- </script>
16
-
17
- <div bind:this={el} class="contents" hidden>
18
- <slot />
19
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/ScrollToBottomBtn.svelte DELETED
@@ -1,46 +0,0 @@
1
- <script lang="ts">
2
- import { fade } from "svelte/transition";
3
- import { onDestroy } from "svelte";
4
- import IconChevron from "./icons/IconChevron.svelte";
5
-
6
- export let scrollNode: HTMLElement;
7
- export { className as class };
8
-
9
- let visible = false;
10
- let className = "";
11
- let observer: ResizeObserver | null = null;
12
-
13
- $: if (scrollNode) {
14
- destroy();
15
-
16
- if (window.ResizeObserver) {
17
- observer = new ResizeObserver(() => {
18
- updateVisibility();
19
- });
20
- observer.observe(scrollNode);
21
- }
22
- scrollNode.addEventListener("scroll", updateVisibility);
23
- }
24
-
25
- function updateVisibility() {
26
- if (!scrollNode) return;
27
- visible =
28
- Math.ceil(scrollNode.scrollTop) + 200 < scrollNode.scrollHeight - scrollNode.clientHeight;
29
- }
30
-
31
- function destroy() {
32
- observer?.disconnect();
33
- scrollNode?.removeEventListener("scroll", updateVisibility);
34
- }
35
-
36
- onDestroy(destroy);
37
- </script>
38
-
39
- {#if visible}
40
- <button
41
- transition:fade|local={{ duration: 150 }}
42
- on:click={() => scrollNode.scrollTo({ top: scrollNode.scrollHeight, behavior: "smooth" })}
43
- class="btn absolute flex h-[41px] w-[41px] rounded-full border bg-white shadow-md transition-all hover:bg-gray-100 dark:border-gray-600 dark:bg-gray-700 dark:shadow-gray-950 dark:hover:bg-gray-600 {className}"
44
- ><IconChevron classNames="mt-[2px]" /></button
45
- >
46
- {/if}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/SettingsModal.svelte DELETED
@@ -1,65 +0,0 @@
1
- <script lang="ts">
2
- import { createEventDispatcher } from "svelte";
3
-
4
- import Modal from "$lib/components/Modal.svelte";
5
- import CarbonClose from "~icons/carbon/close";
6
- import Switch from "$lib/components/Switch.svelte";
7
- import type { Settings } from "$lib/types/Settings";
8
- import { enhance } from "$app/forms";
9
- import { base } from "$app/paths";
10
-
11
- export let settings: Pick<Settings, "shareConversationsWithModelAuthors">;
12
-
13
- const dispatch = createEventDispatcher<{ close: void }>();
14
- </script>
15
-
16
- <Modal on:close>
17
- <form
18
- class="flex w-full flex-col gap-5 p-6"
19
- use:enhance={() => {
20
- dispatch("close");
21
- }}
22
- method="post"
23
- action="{base}/settings"
24
- >
25
- <div class="flex items-start justify-between text-xl font-semibold text-gray-800">
26
- <h2>Settings</h2>
27
- <button type="button" class="group" on:click={() => dispatch("close")}>
28
- <CarbonClose class="text-gray-900 group-hover:text-gray-500" />
29
- </button>
30
- </div>
31
-
32
- <label class="flex cursor-pointer select-none items-center gap-2 text-gray-500">
33
- {#each Object.entries(settings).filter(([k]) => k !== "shareConversationsWithModelAuthors") as [key, val]}
34
- <input type="hidden" name={key} value={val} />
35
- {/each}
36
- <Switch
37
- name="shareConversationsWithModelAuthors"
38
- bind:checked={settings.shareConversationsWithModelAuthors}
39
- />
40
- Share conversations with model authors
41
- </label>
42
-
43
- <p class="text-gray-800">
44
- Sharing your data will help improve the training data and make open models better over time.
45
- </p>
46
- <p class="text-gray-800">
47
- You can change this setting at any time, it applies to all your conversations.
48
- </p>
49
- <p class="text-gray-800">
50
- Read more about this model's authors,
51
- <a
52
- href="https://open-assistant.io/"
53
- target="_blank"
54
- rel="noreferrer"
55
- class="underline decoration-gray-300 hover:decoration-gray-700">Open Assistant</a
56
- >.
57
- </p>
58
- <button
59
- type="submit"
60
- class="mt-2 rounded-full bg-black px-5 py-2 text-lg font-semibold text-gray-100 ring-gray-400 ring-offset-1 transition-colors hover:ring"
61
- >
62
- Apply
63
- </button>
64
- </form>
65
- </Modal>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/StopGeneratingBtn.svelte DELETED
@@ -1,17 +0,0 @@
1
- <script lang="ts">
2
- import CarbonPause from "~icons/carbon/pause-filled";
3
-
4
- export let visible = false;
5
- export let className = "";
6
- </script>
7
-
8
- <button
9
- type="button"
10
- on:click
11
- class="btn absolute flex rounded-lg border bg-white px-3 py-1 shadow-sm transition-all hover:bg-gray-100 dark:border-gray-600 dark:bg-gray-700 dark:hover:bg-gray-600
12
- {className}
13
- {visible ? 'visible opacity-100' : 'invisible opacity-0'}
14
- "
15
- >
16
- <CarbonPause class="-ml-1 mr-1 h-[1.25rem] w-[1.1875rem] text-gray-400" /> Stop generating
17
- </button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/Switch.svelte DELETED
@@ -1,11 +0,0 @@
1
- <script lang="ts">
2
- export let checked: boolean;
3
- export let name: string;
4
- </script>
5
-
6
- <input bind:checked type="checkbox" {name} class="peer pointer-events-none absolute opacity-0" />
7
- <div
8
- class="relative inline-flex h-5 w-9 items-center rounded-full bg-gray-300 p-1 shadow-inner transition-all peer-checked:bg-black hover:bg-gray-400 peer-checked:[&>div]:translate-x-3.5"
9
- >
10
- <div class="h-3.5 w-3.5 rounded-full bg-white shadow-sm transition-all" />
11
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/Toast.svelte DELETED
@@ -1,19 +0,0 @@
1
- <script lang="ts">
2
- import { fade } from "svelte/transition";
3
-
4
- import IconDazzled from "$lib/components/icons/IconDazzled.svelte";
5
-
6
- export let message = "";
7
- </script>
8
-
9
- <div
10
- transition:fade={{ duration: 300 }}
11
- class="pointer-events-none fixed right-0 top-12 z-20 bg-gradient-to-bl from-red-500/20 via-red-500/0 to-red-500/0 pb-36 pl-36 pr-2 pt-2 md:top-0 md:pr-8 md:pt-5"
12
- >
13
- <div
14
- class="pointer-events-auto flex items-center rounded-full bg-white/90 px-3 py-1 shadow-sm dark:bg-gray-900/80"
15
- >
16
- <IconDazzled classNames="text-2xl mr-2" />
17
- <h2 class="font-semibold">{message}</h2>
18
- </div>
19
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/Tooltip.svelte DELETED
@@ -1,22 +0,0 @@
1
- <script lang="ts">
2
- export let classNames = "";
3
- export let label = "Copied";
4
- export let position = "left-1/2 top-full transform -translate-x-1/2 translate-y-2";
5
- </script>
6
-
7
- <div
8
- class="
9
- pointer-events-none absolute rounded bg-black px-2 py-1 font-normal leading-tight text-white shadow transition-opacity
10
- {position}
11
- {classNames}
12
- "
13
- >
14
- <div
15
- class="absolute bottom-full left-1/2 h-0 w-0 -translate-x-1/2 transform border-4 border-t-0 border-black"
16
- style="
17
- border-left-color: transparent;
18
- border-right-color: transparent;
19
- "
20
- />
21
- {label}
22
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/chat/ChatInput.svelte DELETED
@@ -1,64 +0,0 @@
1
- <script lang="ts">
2
- import { createEventDispatcher, onMount } from "svelte";
3
-
4
- export let value = "";
5
- export let minRows = 1;
6
- export let maxRows: null | number = null;
7
- export let placeholder = "";
8
- export let disabled = false;
9
-
10
- // Approximate width from which we disable autofocus
11
- const TABLET_VIEWPORT_WIDTH = 768;
12
-
13
- let innerWidth = 0;
14
- let textareaElement: HTMLTextAreaElement;
15
-
16
- const dispatch = createEventDispatcher<{ submit: void }>();
17
-
18
- $: minHeight = `${1 + minRows * 1.5}em`;
19
- $: maxHeight = maxRows ? `${1 + maxRows * 1.5}em` : `auto`;
20
-
21
- function handleKeydown(event: KeyboardEvent) {
22
- // submit on enter
23
- if (event.key === "Enter" && !event.shiftKey) {
24
- event.preventDefault();
25
- dispatch("submit"); // use a custom event instead of `event.target.form.requestSubmit()` as it does not work on Safari 14
26
- }
27
- }
28
-
29
- onMount(() => {
30
- if (innerWidth > TABLET_VIEWPORT_WIDTH) {
31
- textareaElement.focus();
32
- }
33
- });
34
- </script>
35
-
36
- <svelte:window bind:innerWidth />
37
-
38
- <div class="relative min-w-0 flex-1">
39
- <pre
40
- class="invisible whitespace-pre-wrap p-3"
41
- aria-hidden="true"
42
- style="min-height: {minHeight}; max-height: {maxHeight}">{(value || " ") + "\n"}</pre>
43
-
44
- <textarea
45
- enterkeyhint="send"
46
- tabindex="0"
47
- rows="1"
48
- class="scrollbar-custom absolute top-0 m-0 h-full w-full resize-none scroll-p-3 overflow-x-hidden overflow-y-scroll border-0 bg-transparent p-3 outline-none focus:ring-0 focus-visible:ring-0"
49
- bind:value
50
- bind:this={textareaElement}
51
- {disabled}
52
- on:keydown={handleKeydown}
53
- {placeholder}
54
- />
55
- </div>
56
-
57
- <style>
58
- pre,
59
- textarea {
60
- font-family: inherit;
61
- box-sizing: border-box;
62
- line-height: 1.5;
63
- }
64
- </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/chat/ChatIntroduction.svelte DELETED
@@ -1,77 +0,0 @@
1
- <script lang="ts">
2
- import { PUBLIC_VERSION } from "$env/static/public";
3
- import Logo from "$lib/components/icons/Logo.svelte";
4
- import { createEventDispatcher } from "svelte";
5
- import IconChevron from "$lib/components/icons/IconChevron.svelte";
6
- import ModelsModal from "../ModelsModal.svelte";
7
- import type { Model } from "$lib/types/Model";
8
- import ModelCardMetadata from "../ModelCardMetadata.svelte";
9
- import type { LayoutData } from "../../../routes/$types";
10
- import { findCurrentModel } from "$lib/utils/models";
11
-
12
- export let currentModel: Model;
13
- export let settings: LayoutData["settings"];
14
- export let models: Model[];
15
-
16
- let isModelsModalOpen = false;
17
-
18
- $: currentModelMetadata = findCurrentModel(models, settings.activeModel);
19
-
20
- const dispatch = createEventDispatcher<{ message: string }>();
21
- </script>
22
-
23
- <div class="my-auto grid gap-8 lg:grid-cols-3">
24
- <div class="lg:col-span-1">
25
- <div>
26
- <div class="mb-3 flex items-center text-2xl font-semibold">
27
- <Logo classNames="mr-1 text-yellow-400 text-4xl" />
28
- HuggingChat
29
- <div
30
- class="ml-3 flex h-6 items-center rounded-lg border border-gray-100 bg-gray-50 px-2 text-base text-gray-400 dark:border-gray-700/60 dark:bg-gray-800"
31
- >
32
- v{PUBLIC_VERSION}
33
- </div>
34
- </div>
35
- <p class="text-base text-gray-600 dark:text-gray-400">
36
- Making the community's best AI chat models available to everyone.
37
- </p>
38
- </div>
39
- </div>
40
- <div class="lg:col-span-2 lg:pl-24">
41
- {#if isModelsModalOpen}
42
- <ModelsModal {settings} {models} on:close={() => (isModelsModalOpen = false)} />
43
- {/if}
44
- <div class="overflow-hidden rounded-xl border dark:border-gray-800">
45
- <div class="flex p-3">
46
- <div>
47
- <div class="text-sm text-gray-600 dark:text-gray-400">Current Model</div>
48
- <div class="font-semibold">{currentModel.displayName}</div>
49
- </div>
50
- {#if models.length > 1}
51
- <button
52
- type="button"
53
- on:click={() => (isModelsModalOpen = true)}
54
- class="btn ml-auto flex h-7 w-7 self-start rounded-full bg-gray-100 p-1 text-xs hover:bg-gray-100 dark:border-gray-600 dark:bg-gray-800 dark:hover:bg-gray-600"
55
- ><IconChevron /></button
56
- >
57
- {/if}
58
- </div>
59
- <ModelCardMetadata variant="dark" model={currentModel} />
60
- </div>
61
- </div>
62
- {#if currentModelMetadata.promptExamples}
63
- <div class="lg:col-span-3 lg:mt-12">
64
- <p class="mb-3 text-gray-600 dark:text-gray-300">Examples</p>
65
- <div class="grid gap-3 lg:grid-cols-3 lg:gap-5">
66
- {#each currentModelMetadata.promptExamples as example}
67
- <button
68
- type="button"
69
- class="rounded-xl border bg-gray-50 p-2.5 text-gray-600 hover:bg-gray-100 dark:border-gray-800 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700 sm:p-4"
70
- on:click={() => dispatch("message", example.prompt)}
71
- >
72
- {example.title}
73
- </button>
74
- {/each}
75
- </div>
76
- </div>{/if}
77
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/chat/ChatMessage.svelte DELETED
@@ -1,148 +0,0 @@
1
- <script lang="ts">
2
- import { marked } from "marked";
3
- import type { Message } from "$lib/types/Message";
4
- import { afterUpdate, createEventDispatcher } from "svelte";
5
- import { deepestChild } from "$lib/utils/deepestChild";
6
- import { page } from "$app/stores";
7
-
8
- import CodeBlock from "../CodeBlock.svelte";
9
- import IconLoading from "../icons/IconLoading.svelte";
10
- import CarbonRotate360 from "~icons/carbon/rotate-360";
11
- import CarbonDownload from "~icons/carbon/download";
12
- import { PUBLIC_SEP_TOKEN } from "$lib/constants/publicSepToken";
13
- import type { Model } from "$lib/types/Model";
14
-
15
- function sanitizeMd(md: string) {
16
- let ret = md
17
- .replace(/<\|[a-z]*$/, "")
18
- .replace(/<\|[a-z]+\|$/, "")
19
- .replace(/<$/, "")
20
- .replaceAll(PUBLIC_SEP_TOKEN, " ")
21
- .replaceAll(/<\|[a-z]+\|>/g, " ")
22
- .replaceAll(/<br\s?\/?>/gi, "\n")
23
- .replaceAll("<", "&lt;")
24
- .trim();
25
-
26
- for (const stop of [...(model.parameters?.stop ?? []), "<|endoftext|>"]) {
27
- if (ret.endsWith(stop)) {
28
- ret = ret.slice(0, -stop.length).trim();
29
- }
30
- }
31
-
32
- return ret;
33
- }
34
- function unsanitizeMd(md: string) {
35
- return md.replaceAll("&lt;", "<");
36
- }
37
-
38
- export let model: Model;
39
- export let message: Message;
40
- export let loading = false;
41
- export let readOnly = false;
42
-
43
- const dispatch = createEventDispatcher<{ retry: void }>();
44
-
45
- let contentEl: HTMLElement;
46
- let loadingEl: IconLoading;
47
- let pendingTimeout: ReturnType<typeof setTimeout>;
48
-
49
- const renderer = new marked.Renderer();
50
-
51
- // For code blocks with simple backticks
52
- renderer.codespan = (code) => {
53
- // Unsanitize double-sanitized code
54
- return `<code>${code.replaceAll("&amp;", "&")}</code>`;
55
- };
56
-
57
- const options: marked.MarkedOptions = {
58
- ...marked.getDefaults(),
59
- gfm: true,
60
- breaks: true,
61
- renderer,
62
- };
63
-
64
- $: tokens = marked.lexer(sanitizeMd(message.content));
65
-
66
- afterUpdate(() => {
67
- loadingEl?.$destroy();
68
- clearTimeout(pendingTimeout);
69
-
70
- // Add loading animation to the last message if update takes more than 600ms
71
- if (loading) {
72
- pendingTimeout = setTimeout(() => {
73
- if (contentEl) {
74
- loadingEl = new IconLoading({
75
- target: deepestChild(contentEl),
76
- props: { classNames: "loading inline ml-2" },
77
- });
78
- }
79
- }, 600);
80
- }
81
- });
82
-
83
- $: downloadLink =
84
- message.from === "user" ? `${$page.url.pathname}/message/${message.id}/prompt` : undefined;
85
- </script>
86
-
87
- {#if message.from === "assistant"}
88
- <div class="flex items-start justify-start gap-4 leading-relaxed">
89
- <img
90
- alt=""
91
- src="https://huggingface.co/avatars/2edb18bd0206c16b433841a47f53fa8e.svg"
92
- class="mt-5 h-3 w-3 flex-none select-none rounded-full shadow-lg"
93
- />
94
- <div
95
- class="relative min-h-[calc(2rem+theme(spacing[3.5])*2)] min-w-[100px] rounded-2xl border border-gray-100 bg-gradient-to-br from-gray-50 px-5 py-3.5 text-gray-600 prose-pre:my-2 dark:border-gray-800 dark:from-gray-800/40 dark:text-gray-300"
96
- >
97
- {#if !message.content}
98
- <IconLoading classNames="absolute inset-0 m-auto" />
99
- {/if}
100
- <div
101
- class="prose max-w-none dark:prose-invert max-sm:prose-sm 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"
102
- bind:this={contentEl}
103
- >
104
- {#each tokens as token}
105
- {#if token.type === "code"}
106
- <CodeBlock lang={token.lang} code={unsanitizeMd(token.text)} />
107
- {:else}
108
- <!-- eslint-disable-next-line svelte/no-at-html-tags -->
109
- {@html marked(token.raw, options)}
110
- {/if}
111
- {/each}
112
- </div>
113
- </div>
114
- </div>
115
- {/if}
116
- {#if message.from === "user"}
117
- <div class="group relative flex items-start justify-start gap-4 max-sm:text-sm">
118
- <div class="mt-5 h-3 w-3 flex-none rounded-full" />
119
- <div class="whitespace-break-spaces rounded-2xl px-5 py-3.5 text-gray-500 dark:text-gray-400">
120
- {message.content.trim()}
121
- </div>
122
- {#if !loading}
123
- <div class="absolute right-0 top-3.5 flex gap-2 lg:-right-2">
124
- {#if downloadLink}
125
- <a
126
- class="rounded-lg border border-gray-100 p-1 text-xs text-gray-400 group-hover:block hover:text-gray-500 dark:border-gray-800 dark:text-gray-400 dark:hover:text-gray-300 md:hidden"
127
- title="Download prompt and parameters"
128
- type="button"
129
- target="_blank"
130
- href={downloadLink}
131
- >
132
- <CarbonDownload />
133
- </a>
134
- {/if}
135
- {#if !readOnly}
136
- <button
137
- class="cursor-pointer rounded-lg border border-gray-100 p-1 text-xs text-gray-400 group-hover:block hover:text-gray-500 dark:border-gray-800 dark:text-gray-400 dark:hover:text-gray-300 md:hidden lg:-right-2"
138
- title="Retry"
139
- type="button"
140
- on:click={() => dispatch("retry")}
141
- >
142
- <CarbonRotate360 />
143
- </button>
144
- {/if}
145
- </div>
146
- {/if}
147
- </div>
148
- {/if}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/chat/ChatMessages.svelte DELETED
@@ -1,65 +0,0 @@
1
- <script lang="ts">
2
- import type { Message } from "$lib/types/Message";
3
- import { snapScrollToBottom } from "$lib/actions/snapScrollToBottom";
4
- import ScrollToBottomBtn from "$lib/components/ScrollToBottomBtn.svelte";
5
- import { createEventDispatcher, tick } from "svelte";
6
-
7
- import ChatIntroduction from "./ChatIntroduction.svelte";
8
- import ChatMessage from "./ChatMessage.svelte";
9
- import { randomUUID } from "$lib/utils/randomUuid";
10
- import type { Model } from "$lib/types/Model";
11
- import type { LayoutData } from "../../../routes/$types";
12
-
13
- const dispatch = createEventDispatcher<{ retry: { id: Message["id"]; content: string } }>();
14
-
15
- export let messages: Message[];
16
- export let loading: boolean;
17
- export let pending: boolean;
18
- export let currentModel: Model;
19
- export let settings: LayoutData["settings"];
20
- export let models: Model[];
21
- export let readOnly: boolean;
22
-
23
- let chatContainer: HTMLElement;
24
-
25
- async function scrollToBottom() {
26
- await tick();
27
- chatContainer.scrollTop = chatContainer.scrollHeight;
28
- }
29
-
30
- // If last message is from user, scroll to bottom
31
- $: if (messages[messages.length - 1]?.from === "user") {
32
- scrollToBottom();
33
- }
34
- </script>
35
-
36
- <div
37
- class="scrollbar-custom mr-1 h-full overflow-y-auto"
38
- use:snapScrollToBottom={messages.length ? messages : false}
39
- bind:this={chatContainer}
40
- >
41
- <div class="mx-auto flex h-full max-w-3xl flex-col gap-5 px-5 pt-6 sm:gap-8 xl:max-w-4xl">
42
- {#each messages as message, i}
43
- <ChatMessage
44
- loading={loading && i === messages.length - 1}
45
- {message}
46
- model={currentModel}
47
- {readOnly}
48
- on:retry={() => dispatch("retry", { id: message.id, content: message.content })}
49
- />
50
- {:else}
51
- <ChatIntroduction {settings} {models} {currentModel} on:message />
52
- {/each}
53
- {#if pending}
54
- <ChatMessage
55
- message={{ from: "assistant", content: "", id: randomUUID() }}
56
- model={currentModel}
57
- />
58
- {/if}
59
- <div class="h-32 flex-none" />
60
- </div>
61
- <ScrollToBottomBtn
62
- class="bottom-36 right-4 max-md:hidden lg:right-10"
63
- scrollNode={chatContainer}
64
- />
65
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/chat/ChatWindow.svelte DELETED
@@ -1,105 +0,0 @@
1
- <script lang="ts">
2
- import type { Message } from "$lib/types/Message";
3
- import { createEventDispatcher } from "svelte";
4
-
5
- import CarbonSendAltFilled from "~icons/carbon/send-alt-filled";
6
- import CarbonExport from "~icons/carbon/export";
7
-
8
- import ChatMessages from "./ChatMessages.svelte";
9
- import ChatInput from "./ChatInput.svelte";
10
- import StopGeneratingBtn from "../StopGeneratingBtn.svelte";
11
- import type { Model } from "$lib/types/Model";
12
- import type { LayoutData } from "../../../routes/$types";
13
-
14
- export let messages: Message[] = [];
15
- export let loading = false;
16
- export let pending = false;
17
- export let currentModel: Model;
18
- export let models: Model[];
19
- export let settings: LayoutData["settings"];
20
-
21
- $: isReadOnly = !models.some((model) => model.id === currentModel.id);
22
-
23
- let message: string;
24
-
25
- const dispatch = createEventDispatcher<{
26
- message: string;
27
- share: void;
28
- stop: void;
29
- retry: { id: Message["id"]; content: string };
30
- }>();
31
-
32
- const handleSubmit = () => {
33
- if (loading) return;
34
- dispatch("message", message);
35
- message = "";
36
- };
37
- </script>
38
-
39
- <div class="relative min-h-0 min-w-0">
40
- <ChatMessages
41
- {loading}
42
- {pending}
43
- {settings}
44
- {currentModel}
45
- {models}
46
- {messages}
47
- readOnly={isReadOnly}
48
- on:message
49
- on:retry={(ev) => {
50
- if (!loading) dispatch("retry", ev.detail);
51
- }}
52
- />
53
- <div
54
- class="dark:via-gray-80 pointer-events-none absolute inset-x-0 bottom-0 z-0 mx-auto flex w-full max-w-3xl flex-col items-center justify-center bg-gradient-to-t from-white via-white/80 to-white/0 px-3.5 py-4 dark:border-gray-800 dark:from-gray-900 dark:to-gray-900/0 max-md:border-t max-md:bg-white max-md:dark:bg-gray-900 sm:px-5 md:py-8 xl:max-w-4xl [&>*]:pointer-events-auto"
55
- >
56
- <StopGeneratingBtn
57
- visible={loading}
58
- className="right-5 mr-[1px] md:mr-0 md:right-7 top-6 md:top-10 z-10"
59
- on:click={() => dispatch("stop")}
60
- />
61
- <form
62
- on:submit|preventDefault={handleSubmit}
63
- class="relative flex w-full max-w-4xl flex-1 items-center rounded-xl border bg-gray-100 focus-within:border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:focus-within:border-gray-500
64
- {isReadOnly ? 'opacity-30' : ''}"
65
- >
66
- <div class="flex w-full flex-1 border-none bg-transparent">
67
- <ChatInput
68
- placeholder="Ask anything"
69
- bind:value={message}
70
- on:submit={handleSubmit}
71
- maxRows={4}
72
- disabled={isReadOnly}
73
- />
74
- <button
75
- class="btn mx-1 my-1 h-[2.4rem] self-end rounded-lg bg-transparent p-1 px-[0.7rem] text-gray-400 disabled:opacity-60 enabled:hover:text-gray-700 dark:disabled:opacity-40 enabled:dark:hover:text-gray-100"
76
- disabled={!message || loading || isReadOnly}
77
- type="submit"
78
- >
79
- <CarbonSendAltFilled />
80
- </button>
81
- </div>
82
- </form>
83
- <div class="mt-2 flex justify-between self-stretch px-1 text-xs text-gray-400/90 max-sm:gap-2">
84
- <p>
85
- Model: <a
86
- href="https://huggingface.co/{currentModel.name}"
87
- target="_blank"
88
- rel="noreferrer"
89
- class="hover:underline">{currentModel.displayName}</a
90
- > <span class="max-sm:hidden">·</span><br class="sm:hidden" /> Generated content may be inaccurate
91
- or false.
92
- </p>
93
- {#if messages.length}
94
- <button
95
- class="flex flex-none items-center hover:text-gray-400 hover:underline max-sm:rounded-lg max-sm:bg-gray-50 max-sm:px-2.5 dark:max-sm:bg-gray-800"
96
- type="button"
97
- on:click={() => dispatch("share")}
98
- >
99
- <CarbonExport class="text-[.6rem] sm:mr-1.5 sm:text-yellow-500" />
100
- <div class="max-sm:hidden">Share this conversation</div>
101
- </button>
102
- {/if}
103
- </div>
104
- </div>
105
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/icons/IconChevron.svelte DELETED
@@ -1,20 +0,0 @@
1
- <script lang="ts">
2
- export let classNames = "";
3
- </script>
4
-
5
- <svg
6
- width="1em"
7
- height="1em"
8
- viewBox="0 0 15 6"
9
- class={classNames}
10
- fill="none"
11
- xmlns="http://www.w3.org/2000/svg"
12
- >
13
- <path
14
- d="M1.67236 1L7.67236 7L13.6724 1"
15
- stroke="currentColor"
16
- stroke-width="2"
17
- stroke-linecap="round"
18
- stroke-linejoin="round"
19
- />
20
- </svg>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/icons/IconCopy.svelte DELETED
@@ -1,26 +0,0 @@
1
- <script lang="ts">
2
- export let classNames = "";
3
- </script>
4
-
5
- <svg
6
- class={classNames}
7
- xmlns="http://www.w3.org/2000/svg"
8
- aria-hidden="true"
9
- fill="currentColor"
10
- focusable="false"
11
- role="img"
12
- width="1em"
13
- height="1em"
14
- preserveAspectRatio="xMidYMid meet"
15
- viewBox="0 0 32 32"
16
- >
17
- <path
18
- d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z"
19
- transform="translate(0)"
20
- />
21
- <path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)" /><rect
22
- fill="none"
23
- width="32"
24
- height="32"
25
- />
26
- </svg>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/icons/IconDazzled.svelte DELETED
@@ -1,36 +0,0 @@
1
- <script lang="ts">
2
- export let classNames = "";
3
- </script>
4
-
5
- <svg
6
- xmlns="http://www.w3.org/2000/svg"
7
- width="1em"
8
- height="1em"
9
- class={classNames}
10
- fill="none"
11
- viewBox="0 0 26 23"
12
- >
13
- <path
14
- fill="url(#a)"
15
- d="M.93 10.65A10.17 10.17 0 0 1 11.11.48h4.67a9.45 9.45 0 0 1 0 18.89H4.53L1.62 22.2a.38.38 0 0 1-.69-.28V10.65Z"
16
- />
17
- <path
18
- fill="#000"
19
- fill-rule="evenodd"
20
- d="M11.52 7.4a1.86 1.86 0 1 1-3.72 0 1.86 1.86 0 0 1 3.72 0Zm7.57 0a1.86 1.86 0 1 1-3.73 0 1.86 1.86 0 0 1 3.73 0ZM8.9 12.9a.55.55 0 0 0-.11.35.76.76 0 0 1-1.51 0c0-.95.67-1.94 1.76-1.94 1.09 0 1.76 1 1.76 1.94H9.3a.55.55 0 0 0-.12-.35c-.06-.07-.1-.08-.13-.08s-.08 0-.14.08Zm4.04 0a.55.55 0 0 0-.12.35h-1.51c0-.95.68-1.94 1.76-1.94 1.1 0 1.77 1 1.77 1.94h-1.51a.55.55 0 0 0-.12-.35c-.06-.07-.11-.08-.14-.08-.02 0-.07 0-.13.08Zm-1.89.79c-.02 0-.07-.01-.13-.08a.55.55 0 0 1-.12-.36h-1.5c0 .95.67 1.95 1.75 1.95 1.1 0 1.77-1 1.77-1.95h-1.51c0 .16-.06.28-.12.36-.06.07-.11.08-.14.08Zm4.04 0c-.03 0-.08-.01-.14-.08a.55.55 0 0 1-.12-.36h-1.5c0 .95.67 1.95 1.76 1.95 1.08 0 1.76-1 1.76-1.95h-1.51c0 .16-.06.28-.12.36-.06.07-.11.08-.13.08Zm1.76-.44c0-.16.05-.28.12-.35.06-.07.1-.08.13-.08s.08 0 .14.08c.06.07.11.2.11.35a.76.76 0 0 0 1.51 0c0-.95-.67-1.94-1.76-1.94-1.09 0-1.76 1-1.76 1.94h1.5Z"
21
- clip-rule="evenodd"
22
- />
23
- <defs>
24
- <radialGradient
25
- id="a"
26
- cx="0"
27
- cy="0"
28
- r="1"
29
- gradientTransform="matrix(0 31.37 -34.85 0 13.08 -9.02)"
30
- gradientUnits="userSpaceOnUse"
31
- >
32
- <stop stop-color="#FFD21E" />
33
- <stop offset="1" stop-color="red" />
34
- </radialGradient>
35
- </defs>
36
- </svg>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/icons/IconLoading.svelte DELETED
@@ -1,31 +0,0 @@
1
- <script lang="ts">
2
- export let classNames = "";
3
- </script>
4
-
5
- <svg
6
- xmlns="http://www.w3.org/2000/svg"
7
- width="40px"
8
- height="25px"
9
- viewBox="0 0 60 40"
10
- preserveAspectRatio="xMidYMid"
11
- class={classNames}
12
- >
13
- {#each Array(3) as _, index}
14
- <g transform={`translate(${20 * index + 10} 20)`}>
15
- {index}
16
- <circle cx="0" cy="0" r="6" fill="currentColor">
17
- <animateTransform
18
- attributeName="transform"
19
- type="scale"
20
- begin={`${-0.375 + 0.15 * index}s`}
21
- calcMode="spline"
22
- keySplines="0.3 0 0.7 1;0.3 0 0.7 1"
23
- values="0.5;1;0.5"
24
- keyTimes="0;0.5;1"
25
- dur="1s"
26
- repeatCount="indefinite"
27
- />
28
- </circle>
29
- </g>
30
- {/each}
31
- </svg>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/components/icons/Logo.svelte DELETED
@@ -1,25 +0,0 @@
1
- <script lang="ts">
2
- export let classNames = "";
3
- </script>
4
-
5
- <svg
6
- width="1em"
7
- height="1em"
8
- class={classNames}
9
- viewBox="0 0 13 12"
10
- fill="none"
11
- xmlns="http://www.w3.org/2000/svg"
12
- >
13
- <path
14
- fill="#FFD21E"
15
- d="M1.76 5.63a3.7 3.7 0 0 1 3.7-3.7h1.7a3.43 3.43 0 0 1 0 6.87H3.07L2.01 9.83a.14.14 0 0 1-.25-.1v-4.1Z"
16
- />
17
- <path
18
- fill="#32343D"
19
- d="M7.37 4.8c.13.05.19.33.33.25a.54.54 0 0 0 .22-.73.54.54 0 0 0-.73-.22.54.54 0 0 0-.22.73c.06.13.27-.08.4-.03ZM4.83 4.8c-.14.05-.2.33-.33.25a.54.54 0 0 1-.23-.73A.54.54 0 0 1 5 4.1c.26.14.36.47.22.73-.06.13-.27-.08-.4-.03ZM6.12 7.4c1.06 0 1.4-.96 1.4-1.44 0-.49-.62.26-1.4.26-.77 0-1.4-.75-1.4-.26 0 .48.34 1.43 1.4 1.43Z"
20
- />
21
- <path
22
- fill="#FF323D"
23
- d="M6.97 7.12c-.2.16-.49.27-.85.27-.34 0-.6-.1-.81-.24a.94.94 0 0 1 .57-.49c.04-.01.09.06.13.14.05.07.1.15.14.15.05 0 .1-.08.14-.15.05-.08.1-.15.14-.13a.93.93 0 0 1 .54.45Z"
24
- />
25
- </svg>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/constants/publicSepToken.ts DELETED
@@ -1 +0,0 @@
1
- export const PUBLIC_SEP_TOKEN = "</s>";
 
 
src/lib/server/abortedGenerations.ts DELETED
@@ -1,29 +0,0 @@
1
- // Shouldn't be needed if we dove into sveltekit internals, see https://github.com/huggingface/chat-ui/pull/88#issuecomment-1523173850
2
-
3
- import { setTimeout } from "node:timers/promises";
4
- import { collections } from "./database";
5
-
6
- let closed = false;
7
- process.on("SIGINT", () => {
8
- closed = true;
9
- });
10
-
11
- export let abortedGenerations: Map<string, Date> = new Map();
12
-
13
- async function maintainAbortedGenerations() {
14
- while (!closed) {
15
- await setTimeout(1000);
16
-
17
- try {
18
- const aborts = await collections.abortedGenerations.find({}).sort({ createdAt: 1 }).toArray();
19
-
20
- abortedGenerations = new Map(
21
- aborts.map(({ conversationId, createdAt }) => [conversationId.toString(), createdAt])
22
- );
23
- } catch (err) {
24
- console.error(err);
25
- }
26
- }
27
- }
28
-
29
- maintainAbortedGenerations();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/server/auth.ts DELETED
@@ -1,9 +0,0 @@
1
- import { HF_CLIENT_ID, HF_CLIENT_SECRET } from "$env/static/private";
2
-
3
- export const requiresUser = !!HF_CLIENT_ID && !!HF_CLIENT_SECRET;
4
-
5
- export const authCondition = (locals: App.Locals) => {
6
- return locals.userId
7
- ? { userId: locals.userId }
8
- : { sessionId: locals.sessionId, userId: { $exists: false } };
9
- };
 
 
 
 
 
 
 
 
 
 
src/lib/server/database.ts DELETED
@@ -1,52 +0,0 @@
1
- import { MONGODB_URL, MONGODB_DB_NAME } from "$env/static/private";
2
- import { MongoClient } from "mongodb";
3
- import type { Conversation } from "$lib/types/Conversation";
4
- import type { SharedConversation } from "$lib/types/SharedConversation";
5
- import type { AbortedGeneration } from "$lib/types/AbortedGeneration";
6
- import type { Settings } from "$lib/types/Settings";
7
- import type { User } from "$lib/types/User";
8
-
9
- const client = new MongoClient(MONGODB_URL, {
10
- // directConnection: true
11
- });
12
-
13
- export const connectPromise = client.connect().catch(console.error);
14
-
15
- const db = client.db(MONGODB_DB_NAME);
16
-
17
- const conversations = db.collection<Conversation>("conversations");
18
- const sharedConversations = db.collection<SharedConversation>("sharedConversations");
19
- const abortedGenerations = db.collection<AbortedGeneration>("abortedGenerations");
20
- const settings = db.collection<Settings>("settings");
21
- const users = db.collection<User>("users");
22
-
23
- export { client, db };
24
- export const collections = {
25
- conversations,
26
- sharedConversations,
27
- abortedGenerations,
28
- settings,
29
- users,
30
- };
31
-
32
- client.on("open", () => {
33
- conversations
34
- .createIndex(
35
- { sessionId: 1, updatedAt: -1 },
36
- { partialFilterExpression: { sessionId: { $exists: true } } }
37
- )
38
- .catch(console.error);
39
- conversations
40
- .createIndex(
41
- { userId: 1, updatedAt: -1 },
42
- { partialFilterExpression: { userId: { $exists: true } } }
43
- )
44
- .catch(console.error);
45
- abortedGenerations.createIndex({ updatedAt: 1 }, { expireAfterSeconds: 30 }).catch(console.error);
46
- abortedGenerations.createIndex({ conversationId: 1 }, { unique: true }).catch(console.error);
47
- sharedConversations.createIndex({ hash: 1 }, { unique: true }).catch(console.error);
48
- settings.createIndex({ sessionId: 1 }, { unique: true, sparse: true }).catch(console.error);
49
- settings.createIndex({ userId: 1 }, { unique: true, sparse: true }).catch(console.error);
50
- users.createIndex({ hfUserId: 1 }, { unique: true }).catch(console.error);
51
- users.createIndex({ sessionId: 1 }, { unique: true, sparse: true }).catch(console.error);
52
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/server/modelEndpoint.ts DELETED
@@ -1,32 +0,0 @@
1
- import { HF_ACCESS_TOKEN } from "$env/static/private";
2
- import { sum } from "$lib/utils/sum";
3
- import type { BackendModel } from "./models";
4
-
5
- /**
6
- * Find a random load-balanced endpoint
7
- */
8
- export function modelEndpoint(model: BackendModel): {
9
- url: string;
10
- authorization: string;
11
- weight: number;
12
- } {
13
- if (!model.endpoints) {
14
- return {
15
- url: `https://api-inference.huggingface.co/models/${model.name}`,
16
- authorization: `Bearer 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`,
17
- weight: 1,
18
- };
19
- }
20
- const endpoints = model.endpoints;
21
- const totalWeight = sum(endpoints.map((e) => e.weight));
22
-
23
- let random = Math.random() * totalWeight;
24
- for (const endpoint of endpoints) {
25
- if (random < endpoint.weight) {
26
- return endpoint;
27
- }
28
- random -= endpoint.weight;
29
- }
30
-
31
- throw new Error("Invalid config, no endpoint found");
32
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/server/models.ts DELETED
@@ -1,80 +0,0 @@
1
- import { HF_ACCESS_TOKEN, MODELS, OLD_MODELS } from "$env/static/private";
2
- import { z } from "zod";
3
-
4
- const modelsRaw = z
5
- .array(
6
- z.object({
7
- /** Used as an identifier in DB */
8
- id: z.string().optional(),
9
- /** Used to link to the model page, and for inference */
10
- name: z.string().min(1),
11
- displayName: z.string().min(1).optional(),
12
- description: z.string().min(1).optional(),
13
- websiteUrl: z.string().url().optional(),
14
- datasetName: z.string().min(1).optional(),
15
- userMessageToken: z.string().min(1),
16
- assistantMessageToken: z.string().min(1),
17
- messageEndToken: z.string().min(1).optional(),
18
- preprompt: z.string().default(""),
19
- prepromptUrl: z.string().url().optional(),
20
- promptExamples: z
21
- .array(
22
- z.object({
23
- title: z.string().min(1),
24
- prompt: z.string().min(1),
25
- })
26
- )
27
- .optional(),
28
- endpoints: z
29
- .array(
30
- z.object({
31
- url: z.string().url(),
32
- authorization: z.string().min(1).default(`Bearer ${HF_ACCESS_TOKEN}`),
33
- weight: z.number().int().positive().default(1),
34
- })
35
- )
36
- .optional(),
37
- parameters: z
38
- .object({
39
- temperature: z.number().min(0).max(1),
40
- truncate: z.number().int().positive(),
41
- max_new_tokens: z.number().int().positive(),
42
- stop: z.array(z.string()).optional(),
43
- })
44
- .passthrough()
45
- .optional(),
46
- })
47
- )
48
- .parse(JSON.parse(MODELS));
49
-
50
- export const models = await Promise.all(
51
- modelsRaw.map(async (m) => ({
52
- ...m,
53
- id: m.id || m.name,
54
- displayName: m.displayName || m.name,
55
- preprompt: m.prepromptUrl ? await fetch(m.prepromptUrl).then((r) => r.text()) : m.preprompt,
56
- }))
57
- );
58
-
59
- // Models that have been deprecated
60
- export const oldModels = OLD_MODELS
61
- ? z
62
- .array(
63
- z.object({
64
- id: z.string().optional(),
65
- name: z.string().min(1),
66
- displayName: z.string().min(1).optional(),
67
- })
68
- )
69
- .parse(JSON.parse(OLD_MODELS))
70
- .map((m) => ({ ...m, id: m.id || m.name, displayName: m.displayName || m.name }))
71
- : [];
72
-
73
- export type BackendModel = (typeof models)[0];
74
-
75
- export const defaultModel = models[0];
76
-
77
- export const validateModel = (_models: BackendModel[]) => {
78
- // Zod enum function requires 2 parameters
79
- return z.enum([_models[0].id, ..._models.slice(1).map((m) => m.id)]);
80
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/shareConversation.ts DELETED
@@ -1,27 +0,0 @@
1
- import { base } from "$app/paths";
2
- import { ERROR_MESSAGES, error } from "$lib/stores/errors";
3
- import { share } from "./utils/share";
4
-
5
- export async function shareConversation(id: string, title: string) {
6
- try {
7
- const res = await fetch(`${base}/conversation/${id}/share`, {
8
- method: "POST",
9
- headers: {
10
- "Content-Type": "application/json",
11
- },
12
- });
13
-
14
- if (!res.ok) {
15
- error.set("Error while sharing conversation, try again.");
16
- console.error("Error while sharing conversation: " + (await res.text()));
17
- return;
18
- }
19
-
20
- const { url } = await res.json();
21
-
22
- share(url, title);
23
- } catch (err) {
24
- error.set(ERROR_MESSAGES.default);
25
- console.error(err);
26
- }
27
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/stores/errors.ts DELETED
@@ -1,7 +0,0 @@
1
- import { writable } from "svelte/store";
2
-
3
- export const ERROR_MESSAGES = {
4
- default: "Oops, something went wrong.",
5
- };
6
-
7
- export const error = writable<string | null>(null);
 
 
 
 
 
 
 
 
src/lib/stores/pendingMessage.ts DELETED
@@ -1,3 +0,0 @@
1
- import { writable } from "svelte/store";
2
-
3
- export const pendingMessage = writable<string>("");
 
 
 
 
src/lib/stores/pendingMessageIdToRetry.ts DELETED
@@ -1,4 +0,0 @@
1
- import type { Message } from "$lib/types/Message";
2
- import { writable } from "svelte/store";
3
-
4
- export const pendingMessageIdToRetry = writable<Message["id"] | null>(null);
 
 
 
 
 
src/lib/switchTheme.ts DELETED
@@ -1,10 +0,0 @@
1
- export function switchTheme() {
2
- const { classList } = document.querySelector("html") as HTMLElement;
3
- if (classList.contains("dark")) {
4
- classList.remove("dark");
5
- localStorage.theme = "light";
6
- } else {
7
- classList.add("dark");
8
- localStorage.theme = "dark";
9
- }
10
- }
 
 
 
 
 
 
 
 
 
 
 
src/lib/types/AbortedGeneration.ts DELETED
@@ -1,8 +0,0 @@
1
- // Ideally shouldn't be needed, see https://github.com/huggingface/chat-ui/pull/88#issuecomment-1523173850
2
-
3
- import type { Conversation } from "./Conversation";
4
- import type { Timestamps } from "./Timestamps";
5
-
6
- export interface AbortedGeneration extends Timestamps {
7
- conversationId: Conversation["_id"];
8
- }
 
 
 
 
 
 
 
 
 
src/lib/types/Conversation.ts DELETED
@@ -1,20 +0,0 @@
1
- import type { ObjectId } from "mongodb";
2
- import type { Message } from "./Message";
3
- import type { Timestamps } from "./Timestamps";
4
- import type { User } from "./User";
5
-
6
- export interface Conversation extends Timestamps {
7
- _id: ObjectId;
8
-
9
- sessionId?: string;
10
- userId?: User["_id"];
11
-
12
- model: string;
13
-
14
- title: string;
15
- messages: Message[];
16
-
17
- meta?: {
18
- fromShareId?: string;
19
- };
20
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/types/Message.ts DELETED
@@ -1,5 +0,0 @@
1
- export interface Message {
2
- from: "user" | "assistant";
3
- id: ReturnType<typeof crypto.randomUUID>;
4
- content: string;
5
- }
 
 
 
 
 
 
src/lib/types/Model.ts DELETED
@@ -1,13 +0,0 @@
1
- import type { BackendModel } from "$lib/server/models";
2
-
3
- export type Model = Pick<
4
- BackendModel,
5
- | "id"
6
- | "name"
7
- | "displayName"
8
- | "websiteUrl"
9
- | "datasetName"
10
- | "promptExamples"
11
- | "parameters"
12
- | "description"
13
- >;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/types/Settings.ts DELETED
@@ -1,16 +0,0 @@
1
- import type { Timestamps } from "./Timestamps";
2
- import type { User } from "./User";
3
-
4
- export interface Settings extends Timestamps {
5
- userId?: User["_id"];
6
- sessionId?: string;
7
-
8
- /**
9
- * Note: Only conversations with this settings explictly set to true should be shared.
10
- *
11
- * This setting is explicitly set to true when users accept the ethics modal.
12
- * */
13
- shareConversationsWithModelAuthors: boolean;
14
- ethicsModalAcceptedAt: Date | null;
15
- activeModel: string;
16
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/types/SharedConversation.ts DELETED
@@ -1,12 +0,0 @@
1
- import type { Message } from "./Message";
2
- import type { Timestamps } from "./Timestamps";
3
-
4
- export interface SharedConversation extends Timestamps {
5
- _id: string;
6
-
7
- hash: string;
8
-
9
- model: string;
10
- title: string;
11
- messages: Message[];
12
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/types/Timestamps.ts DELETED
@@ -1,4 +0,0 @@
1
- export interface Timestamps {
2
- createdAt: Date;
3
- updatedAt: Date;
4
- }
 
 
 
 
 
src/lib/types/UrlDependency.ts DELETED
@@ -1,4 +0,0 @@
1
- /* eslint-disable no-shadow */
2
- export enum UrlDependency {
3
- ConversationList = "conversation:list",
4
- }