Bring back disclaimer modal & updates to guest mode (#526)
Browse files* Changes to modal on login:
- Ethics modal on page load
- Login modal pop up for guest mode later
- Change message limit to be 5 messages across all conversations
* fix login button width
* tweak modals
* Update src/routes/+layout.server.ts
Co-authored-by: Mishig <[email protected]>
* Fix linting
---------
Co-authored-by: Victor Mustar <[email protected]>
Co-authored-by: Mishig <[email protected]>
- .env.template +1 -1
- src/lib/components/DisclaimerModal.svelte +72 -0
- src/lib/components/LoginModal.svelte +14 -29
- src/lib/components/NavMenu.svelte +1 -1
- src/lib/components/chat/ChatWindow.svelte +23 -6
- src/routes/+layout.server.ts +23 -2
- src/routes/+layout.svelte +3 -14
- src/routes/conversation/[id]/+page.svelte +0 -9
- src/routes/conversation/[id]/+server.ts +18 -3
.env.template
CHANGED
|
@@ -142,7 +142,7 @@ PUBLIC_APP_DATA_SHARING=1
|
|
| 142 |
PUBLIC_APP_DISCLAIMER=1
|
| 143 |
|
| 144 |
RATE_LIMIT=16
|
| 145 |
-
MESSAGES_BEFORE_LOGIN=
|
| 146 |
|
| 147 |
PUBLIC_GOOGLE_ANALYTICS_ID=G-8Q63TH4CSL
|
| 148 |
|
|
|
|
| 142 |
PUBLIC_APP_DISCLAIMER=1
|
| 143 |
|
| 144 |
RATE_LIMIT=16
|
| 145 |
+
MESSAGES_BEFORE_LOGIN=5# how many messages a user can send in a conversation before having to login. set to 0 to force login right away
|
| 146 |
|
| 147 |
PUBLIC_GOOGLE_ANALYTICS_ID=G-8Q63TH4CSL
|
| 148 |
|
src/lib/components/DisclaimerModal.svelte
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script lang="ts">
|
| 2 |
+
import { base } from "$app/paths";
|
| 3 |
+
import { page } from "$app/stores";
|
| 4 |
+
import { PUBLIC_APP_DESCRIPTION, PUBLIC_APP_NAME } from "$env/static/public";
|
| 5 |
+
import LogoHuggingFaceBorderless from "$lib/components/icons/LogoHuggingFaceBorderless.svelte";
|
| 6 |
+
import Modal from "$lib/components/Modal.svelte";
|
| 7 |
+
import type { LayoutData } from "../../routes/$types";
|
| 8 |
+
import Logo from "./icons/Logo.svelte";
|
| 9 |
+
|
| 10 |
+
export let settings: LayoutData["settings"];
|
| 11 |
+
</script>
|
| 12 |
+
|
| 13 |
+
<Modal>
|
| 14 |
+
<div
|
| 15 |
+
class="flex w-full flex-col items-center gap-6 bg-gradient-to-b from-primary-500/40 via-primary-500/10 to-primary-500/0 px-5 pb-8 pt-9 text-center sm:px-6"
|
| 16 |
+
>
|
| 17 |
+
<h2 class="flex items-center text-2xl font-semibold text-gray-800">
|
| 18 |
+
<Logo classNames="mr-1" />
|
| 19 |
+
{PUBLIC_APP_NAME}
|
| 20 |
+
</h2>
|
| 21 |
+
|
| 22 |
+
<p class="text-lg font-semibold leading-snug text-gray-800" style="text-wrap: balance;">
|
| 23 |
+
{PUBLIC_APP_DESCRIPTION}
|
| 24 |
+
</p>
|
| 25 |
+
|
| 26 |
+
<p class="text-sm text-gray-500">
|
| 27 |
+
Disclaimer: AI is an area of active research with known problems such as biased generation and
|
| 28 |
+
misinformation. Do not use this application for high-stakes decisions or advice.
|
| 29 |
+
</p>
|
| 30 |
+
|
| 31 |
+
<div class="flex w-full flex-col items-center gap-2">
|
| 32 |
+
{#if $page.data.guestMode || !$page.data.loginEnabled}
|
| 33 |
+
<form action="{base}/settings" target="_parent" method="POST" class="w-full">
|
| 34 |
+
<input type="hidden" name="ethicsModalAccepted" value={true} />
|
| 35 |
+
{#each Object.entries(settings).filter(([k]) => !(k === "customPrompts")) as [key, val]}
|
| 36 |
+
<input type="hidden" name={key} value={val} />
|
| 37 |
+
{/each}
|
| 38 |
+
<input
|
| 39 |
+
type="hidden"
|
| 40 |
+
name="customPrompts"
|
| 41 |
+
value={JSON.stringify(settings.customPrompts)}
|
| 42 |
+
/>
|
| 43 |
+
<button
|
| 44 |
+
type="submit"
|
| 45 |
+
class="w-full justify-center rounded-full border-2 border-gray-300 bg-black px-5 py-2 text-lg font-semibold text-gray-100 transition-colors hover:bg-gray-100"
|
| 46 |
+
class:bg-white={$page.data.loginEnabled}
|
| 47 |
+
class:text-gray-800={$page.data.loginEnabled}
|
| 48 |
+
>
|
| 49 |
+
{#if $page.data.loginEnabled}
|
| 50 |
+
Try as guest
|
| 51 |
+
{:else}
|
| 52 |
+
Start chatting
|
| 53 |
+
{/if}
|
| 54 |
+
</button>
|
| 55 |
+
</form>
|
| 56 |
+
{/if}
|
| 57 |
+
{#if $page.data.loginEnabled}
|
| 58 |
+
<form action="{base}/login" target="_parent" method="POST" class="w-full">
|
| 59 |
+
<button
|
| 60 |
+
type="submit"
|
| 61 |
+
class="flex w-full items-center justify-center whitespace-nowrap rounded-full border-2 border-black bg-black px-5 py-2 text-lg font-semibold text-gray-100 transition-colors hover:bg-gray-900"
|
| 62 |
+
>
|
| 63 |
+
Sign in
|
| 64 |
+
{#if PUBLIC_APP_NAME === "HuggingChat"}
|
| 65 |
+
with <LogoHuggingFaceBorderless classNames="text-xl mr-1 ml-1.5 flex-none" /> Hugging Face
|
| 66 |
+
{/if}
|
| 67 |
+
</button>
|
| 68 |
+
</form>
|
| 69 |
+
{/if}
|
| 70 |
+
</div>
|
| 71 |
+
</div>
|
| 72 |
+
</Modal>
|
src/lib/components/LoginModal.svelte
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
<script lang="ts">
|
| 2 |
import { base } from "$app/paths";
|
| 3 |
import { page } from "$app/stores";
|
| 4 |
-
import {
|
| 5 |
import LogoHuggingFaceBorderless from "$lib/components/icons/LogoHuggingFaceBorderless.svelte";
|
| 6 |
import Modal from "$lib/components/Modal.svelte";
|
| 7 |
import type { LayoutData } from "../../routes/$types";
|
|
@@ -9,47 +9,32 @@
|
|
| 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-
|
| 15 |
>
|
| 16 |
<h2 class="flex items-center text-2xl font-semibold text-gray-800">
|
| 17 |
<Logo classNames="mr-1" />
|
| 18 |
{PUBLIC_APP_NAME}
|
| 19 |
-
<div
|
| 20 |
-
class="ml-3 flex h-6 items-center rounded-lg border border-gray-100 bg-gray-50 px-2 text-base text-gray-400"
|
| 21 |
-
>
|
| 22 |
-
v{PUBLIC_VERSION}
|
| 23 |
-
</div>
|
| 24 |
</h2>
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
class="px-4 text-lg font-semibold leading-snug text-gray-800 sm:px-12"
|
| 28 |
-
style="text-wrap: balance;"
|
| 29 |
-
>
|
| 30 |
-
Please Sign in with Hugging Face to continue
|
| 31 |
-
</p>
|
| 32 |
-
{/if}
|
| 33 |
-
<p class="text-base text-gray-800">
|
| 34 |
-
Disclaimer: AI is an area of active research with known problems such as biased generation and
|
| 35 |
-
misinformation. Do not use this application for high-stakes decisions or advice.
|
| 36 |
</p>
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
{/if}
|
| 43 |
<form
|
| 44 |
-
action="{base}/{$page.data.
|
| 45 |
target="_parent"
|
| 46 |
method="POST"
|
| 47 |
class="flex w-full flex-col items-center gap-2"
|
| 48 |
>
|
| 49 |
-
{#if $page.data.
|
| 50 |
<button
|
| 51 |
type="submit"
|
| 52 |
-
class="
|
| 53 |
>
|
| 54 |
Sign in
|
| 55 |
{#if PUBLIC_APP_NAME === "HuggingChat"}
|
|
@@ -63,7 +48,7 @@
|
|
| 63 |
{/each}
|
| 64 |
<button
|
| 65 |
type="submit"
|
| 66 |
-
class="
|
| 67 |
>
|
| 68 |
Start chatting
|
| 69 |
</button>
|
|
|
|
| 1 |
<script lang="ts">
|
| 2 |
import { base } from "$app/paths";
|
| 3 |
import { page } from "$app/stores";
|
| 4 |
+
import { PUBLIC_APP_DESCRIPTION, PUBLIC_APP_NAME } from "$env/static/public";
|
| 5 |
import LogoHuggingFaceBorderless from "$lib/components/icons/LogoHuggingFaceBorderless.svelte";
|
| 6 |
import Modal from "$lib/components/Modal.svelte";
|
| 7 |
import type { LayoutData } from "../../routes/$types";
|
|
|
|
| 9 |
export let settings: LayoutData["settings"];
|
| 10 |
</script>
|
| 11 |
|
| 12 |
+
<Modal on:close>
|
| 13 |
<div
|
| 14 |
+
class="flex w-full flex-col items-center gap-6 bg-gradient-to-b from-primary-500/40 via-primary-500/10 to-primary-500/0 px-5 pb-8 pt-9 text-center"
|
| 15 |
>
|
| 16 |
<h2 class="flex items-center text-2xl font-semibold text-gray-800">
|
| 17 |
<Logo classNames="mr-1" />
|
| 18 |
{PUBLIC_APP_NAME}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
</h2>
|
| 20 |
+
<p class="text-lg font-semibold leading-snug text-gray-800" style="text-wrap: balance;">
|
| 21 |
+
{PUBLIC_APP_DESCRIPTION}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
</p>
|
| 23 |
+
<p class="rounded-xl border bg-white/80 p-2 text-base text-gray-800">
|
| 24 |
+
You have reached the guest message limit, please Sign In with your Hugging Face account to
|
| 25 |
+
continue.
|
| 26 |
+
</p>
|
| 27 |
+
|
|
|
|
| 28 |
<form
|
| 29 |
+
action="{base}/{$page.data.loginRequired ? 'login' : 'settings'}"
|
| 30 |
target="_parent"
|
| 31 |
method="POST"
|
| 32 |
class="flex w-full flex-col items-center gap-2"
|
| 33 |
>
|
| 34 |
+
{#if $page.data.loginRequired}
|
| 35 |
<button
|
| 36 |
type="submit"
|
| 37 |
+
class="flex w-full items-center justify-center whitespace-nowrap rounded-full bg-black px-5 py-2 text-center text-lg font-semibold text-gray-100 transition-colors hover:bg-gray-900"
|
| 38 |
>
|
| 39 |
Sign in
|
| 40 |
{#if PUBLIC_APP_NAME === "HuggingChat"}
|
|
|
|
| 48 |
{/each}
|
| 49 |
<button
|
| 50 |
type="submit"
|
| 51 |
+
class="flex w-full items-center justify-center whitespace-nowrap rounded-full border-2 border-black bg-black px-5 py-2 text-lg font-semibold text-gray-100 transition-colors hover:bg-gray-900"
|
| 52 |
>
|
| 53 |
Start chatting
|
| 54 |
</button>
|
src/lib/components/NavMenu.svelte
CHANGED
|
@@ -67,7 +67,7 @@
|
|
| 67 |
<form action="{base}/login" method="POST" target="_parent">
|
| 68 |
<button
|
| 69 |
type="submit"
|
| 70 |
-
class="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"
|
| 71 |
>
|
| 72 |
Login
|
| 73 |
</button>
|
|
|
|
| 67 |
<form action="{base}/login" method="POST" target="_parent">
|
| 68 |
<button
|
| 69 |
type="submit"
|
| 70 |
+
class="flex h-9 w-full 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"
|
| 71 |
>
|
| 72 |
Login
|
| 73 |
</button>
|
src/lib/components/chat/ChatWindow.svelte
CHANGED
|
@@ -15,6 +15,8 @@
|
|
| 15 |
import WebSearchToggle from "../WebSearchToggle.svelte";
|
| 16 |
import LoginModal from "../LoginModal.svelte";
|
| 17 |
import type { WebSearchUpdate } from "$lib/types/MessageUpdate";
|
|
|
|
|
|
|
| 18 |
|
| 19 |
export let messages: Message[] = [];
|
| 20 |
export let loading = false;
|
|
@@ -26,7 +28,6 @@
|
|
| 26 |
export let webSearchMessages: WebSearchUpdate[] = [];
|
| 27 |
export let preprompt: string | undefined = undefined;
|
| 28 |
|
| 29 |
-
export let loginRequired = false;
|
| 30 |
$: isReadOnly = !models.some((model) => model.id === currentModel.id);
|
| 31 |
|
| 32 |
let loginModalOpen = false;
|
|
@@ -47,8 +48,15 @@
|
|
| 47 |
</script>
|
| 48 |
|
| 49 |
<div class="relative min-h-0 min-w-0">
|
| 50 |
-
{#if
|
| 51 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
{/if}
|
| 53 |
<ChatMessages
|
| 54 |
{loading}
|
|
@@ -61,7 +69,13 @@
|
|
| 61 |
isAuthor={!shared}
|
| 62 |
{webSearchMessages}
|
| 63 |
{preprompt}
|
| 64 |
-
on:message
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
on:vote
|
| 66 |
on:retry={(ev) => {
|
| 67 |
if (!loading) dispatch("retry", ev.detail);
|
|
@@ -91,8 +105,11 @@
|
|
| 91 |
placeholder="Ask anything"
|
| 92 |
bind:value={message}
|
| 93 |
on:submit={handleSubmit}
|
| 94 |
-
on:keypress={() => {
|
| 95 |
-
if (loginRequired)
|
|
|
|
|
|
|
|
|
|
| 96 |
}}
|
| 97 |
maxRows={4}
|
| 98 |
disabled={isReadOnly}
|
|
|
|
| 15 |
import WebSearchToggle from "../WebSearchToggle.svelte";
|
| 16 |
import LoginModal from "../LoginModal.svelte";
|
| 17 |
import type { WebSearchUpdate } from "$lib/types/MessageUpdate";
|
| 18 |
+
import { page } from "$app/stores";
|
| 19 |
+
import DisclaimerModal from "../DisclaimerModal.svelte";
|
| 20 |
|
| 21 |
export let messages: Message[] = [];
|
| 22 |
export let loading = false;
|
|
|
|
| 28 |
export let webSearchMessages: WebSearchUpdate[] = [];
|
| 29 |
export let preprompt: string | undefined = undefined;
|
| 30 |
|
|
|
|
| 31 |
$: isReadOnly = !models.some((model) => model.id === currentModel.id);
|
| 32 |
|
| 33 |
let loginModalOpen = false;
|
|
|
|
| 48 |
</script>
|
| 49 |
|
| 50 |
<div class="relative min-h-0 min-w-0">
|
| 51 |
+
{#if !settings.ethicsModalAcceptedAt}
|
| 52 |
+
<DisclaimerModal {settings} />
|
| 53 |
+
{:else if loginModalOpen}
|
| 54 |
+
<LoginModal
|
| 55 |
+
{settings}
|
| 56 |
+
on:close={() => {
|
| 57 |
+
loginModalOpen = false;
|
| 58 |
+
}}
|
| 59 |
+
/>
|
| 60 |
{/if}
|
| 61 |
<ChatMessages
|
| 62 |
{loading}
|
|
|
|
| 69 |
isAuthor={!shared}
|
| 70 |
{webSearchMessages}
|
| 71 |
{preprompt}
|
| 72 |
+
on:message={(ev) => {
|
| 73 |
+
if ($page.data.loginRequired) {
|
| 74 |
+
loginModalOpen = true;
|
| 75 |
+
} else {
|
| 76 |
+
dispatch("message", ev.detail);
|
| 77 |
+
}
|
| 78 |
+
}}
|
| 79 |
on:vote
|
| 80 |
on:retry={(ev) => {
|
| 81 |
if (!loading) dispatch("retry", ev.detail);
|
|
|
|
| 105 |
placeholder="Ask anything"
|
| 106 |
bind:value={message}
|
| 107 |
on:submit={handleSubmit}
|
| 108 |
+
on:keypress={(ev) => {
|
| 109 |
+
if ($page.data.loginRequired) {
|
| 110 |
+
ev.preventDefault();
|
| 111 |
+
loginModalOpen = true;
|
| 112 |
+
}
|
| 113 |
}}
|
| 114 |
maxRows={4}
|
| 115 |
disabled={isReadOnly}
|
src/routes/+layout.server.ts
CHANGED
|
@@ -38,6 +38,26 @@ export const load: LayoutServerLoad = async ({ locals, depends, url }) => {
|
|
| 38 |
});
|
| 39 |
}
|
| 40 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
return {
|
| 42 |
conversations: await conversations
|
| 43 |
.find(authCondition(locals))
|
|
@@ -83,7 +103,8 @@ export const load: LayoutServerLoad = async ({ locals, depends, url }) => {
|
|
| 83 |
avatarUrl: locals.user.avatarUrl,
|
| 84 |
email: locals.user.email,
|
| 85 |
},
|
| 86 |
-
|
| 87 |
-
|
|
|
|
| 88 |
};
|
| 89 |
};
|
|
|
|
| 38 |
});
|
| 39 |
}
|
| 40 |
|
| 41 |
+
// get the number of messages where `from === "assistant"` across all conversations.
|
| 42 |
+
const totalMessages =
|
| 43 |
+
(
|
| 44 |
+
await conversations
|
| 45 |
+
.aggregate([
|
| 46 |
+
{ $match: authCondition(locals) },
|
| 47 |
+
{ $project: { messages: 1 } },
|
| 48 |
+
{ $unwind: "$messages" },
|
| 49 |
+
{ $match: { "messages.from": "assistant" } },
|
| 50 |
+
{ $count: "messages" },
|
| 51 |
+
])
|
| 52 |
+
.toArray()
|
| 53 |
+
)[0]?.messages ?? 0;
|
| 54 |
+
|
| 55 |
+
const messagesBeforeLogin = MESSAGES_BEFORE_LOGIN ? parseInt(MESSAGES_BEFORE_LOGIN) : 0;
|
| 56 |
+
|
| 57 |
+
const userHasExceededMessages = messagesBeforeLogin > 0 && totalMessages > messagesBeforeLogin;
|
| 58 |
+
|
| 59 |
+
const loginRequired = requiresUser && !locals.user && userHasExceededMessages;
|
| 60 |
+
|
| 61 |
return {
|
| 62 |
conversations: await conversations
|
| 63 |
.find(authCondition(locals))
|
|
|
|
| 103 |
avatarUrl: locals.user.avatarUrl,
|
| 104 |
email: locals.user.email,
|
| 105 |
},
|
| 106 |
+
loginRequired,
|
| 107 |
+
loginEnabled: requiresUser,
|
| 108 |
+
guestMode: requiresUser && messagesBeforeLogin > 0,
|
| 109 |
};
|
| 110 |
};
|
src/routes/+layout.svelte
CHANGED
|
@@ -4,7 +4,7 @@
|
|
| 4 |
import { page } from "$app/stores";
|
| 5 |
import "../styles/main.css";
|
| 6 |
import { base } from "$app/paths";
|
| 7 |
-
import { PUBLIC_ORIGIN
|
| 8 |
|
| 9 |
import { shareConversation } from "$lib/shareConversation";
|
| 10 |
import { UrlDependency } from "$lib/types/UrlDependency";
|
|
@@ -14,7 +14,6 @@
|
|
| 14 |
import NavMenu from "$lib/components/NavMenu.svelte";
|
| 15 |
import Toast from "$lib/components/Toast.svelte";
|
| 16 |
import SettingsModal from "$lib/components/SettingsModal.svelte";
|
| 17 |
-
import LoginModal from "$lib/components/LoginModal.svelte";
|
| 18 |
import { PUBLIC_APP_ASSETS, PUBLIC_APP_NAME } from "$env/static/public";
|
| 19 |
import titleUpdate from "$lib/stores/titleUpdate";
|
| 20 |
|
|
@@ -94,13 +93,6 @@
|
|
| 94 |
|
| 95 |
$: if ($error) onError();
|
| 96 |
|
| 97 |
-
const requiresLogin =
|
| 98 |
-
!$page.error &&
|
| 99 |
-
!$page.route.id?.startsWith("/r/") &&
|
| 100 |
-
(data.requiresLogin
|
| 101 |
-
? !data.user
|
| 102 |
-
: !data.settings.ethicsModalAcceptedAt && !!PUBLIC_APP_DISCLAIMER);
|
| 103 |
-
|
| 104 |
$: if ($titleUpdate) {
|
| 105 |
const convIdx = data.conversations.findIndex(({ id }) => id === $titleUpdate?.convId);
|
| 106 |
|
|
@@ -157,7 +149,7 @@
|
|
| 157 |
<NavMenu
|
| 158 |
conversations={data.conversations}
|
| 159 |
user={data.user}
|
| 160 |
-
canLogin={data.user === undefined && data.
|
| 161 |
on:shareConversation={(ev) => shareConversation(ev.detail.id, ev.detail.title)}
|
| 162 |
on:deleteConversation={(ev) => deleteConversation(ev.detail)}
|
| 163 |
on:clickSettings={() => (isSettingsOpen = true)}
|
|
@@ -168,7 +160,7 @@
|
|
| 168 |
<NavMenu
|
| 169 |
conversations={data.conversations}
|
| 170 |
user={data.user}
|
| 171 |
-
canLogin={data.user === undefined && data.
|
| 172 |
on:shareConversation={(ev) => shareConversation(ev.detail.id, ev.detail.title)}
|
| 173 |
on:deleteConversation={(ev) => deleteConversation(ev.detail)}
|
| 174 |
on:clickSettings={() => (isSettingsOpen = true)}
|
|
@@ -185,8 +177,5 @@
|
|
| 185 |
models={data.models}
|
| 186 |
/>
|
| 187 |
{/if}
|
| 188 |
-
{#if requiresLogin && data.messagesBeforeLogin === 0}
|
| 189 |
-
<LoginModal settings={data.settings} />
|
| 190 |
-
{/if}
|
| 191 |
<slot />
|
| 192 |
</div>
|
|
|
|
| 4 |
import { page } from "$app/stores";
|
| 5 |
import "../styles/main.css";
|
| 6 |
import { base } from "$app/paths";
|
| 7 |
+
import { PUBLIC_ORIGIN } from "$env/static/public";
|
| 8 |
|
| 9 |
import { shareConversation } from "$lib/shareConversation";
|
| 10 |
import { UrlDependency } from "$lib/types/UrlDependency";
|
|
|
|
| 14 |
import NavMenu from "$lib/components/NavMenu.svelte";
|
| 15 |
import Toast from "$lib/components/Toast.svelte";
|
| 16 |
import SettingsModal from "$lib/components/SettingsModal.svelte";
|
|
|
|
| 17 |
import { PUBLIC_APP_ASSETS, PUBLIC_APP_NAME } from "$env/static/public";
|
| 18 |
import titleUpdate from "$lib/stores/titleUpdate";
|
| 19 |
|
|
|
|
| 93 |
|
| 94 |
$: if ($error) onError();
|
| 95 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
$: if ($titleUpdate) {
|
| 97 |
const convIdx = data.conversations.findIndex(({ id }) => id === $titleUpdate?.convId);
|
| 98 |
|
|
|
|
| 149 |
<NavMenu
|
| 150 |
conversations={data.conversations}
|
| 151 |
user={data.user}
|
| 152 |
+
canLogin={data.user === undefined && data.loginEnabled}
|
| 153 |
on:shareConversation={(ev) => shareConversation(ev.detail.id, ev.detail.title)}
|
| 154 |
on:deleteConversation={(ev) => deleteConversation(ev.detail)}
|
| 155 |
on:clickSettings={() => (isSettingsOpen = true)}
|
|
|
|
| 160 |
<NavMenu
|
| 161 |
conversations={data.conversations}
|
| 162 |
user={data.user}
|
| 163 |
+
canLogin={data.user === undefined && data.loginEnabled}
|
| 164 |
on:shareConversation={(ev) => shareConversation(ev.detail.id, ev.detail.title)}
|
| 165 |
on:deleteConversation={(ev) => deleteConversation(ev.detail)}
|
| 166 |
on:clickSettings={() => (isSettingsOpen = true)}
|
|
|
|
| 177 |
models={data.models}
|
| 178 |
/>
|
| 179 |
{/if}
|
|
|
|
|
|
|
|
|
|
| 180 |
<slot />
|
| 181 |
</div>
|
src/routes/conversation/[id]/+page.svelte
CHANGED
|
@@ -12,7 +12,6 @@
|
|
| 12 |
import { findCurrentModel } from "$lib/utils/models";
|
| 13 |
import { webSearchParameters } from "$lib/stores/webSearchParameters";
|
| 14 |
import type { Message } from "$lib/types/Message";
|
| 15 |
-
import { PUBLIC_APP_DISCLAIMER } from "$env/static/public";
|
| 16 |
import type { MessageUpdate, WebSearchUpdate } from "$lib/types/MessageUpdate";
|
| 17 |
import titleUpdate from "$lib/stores/titleUpdate";
|
| 18 |
|
|
@@ -32,7 +31,6 @@
|
|
| 32 |
|
| 33 |
let loading = false;
|
| 34 |
let pending = false;
|
| 35 |
-
let loginRequired = false;
|
| 36 |
|
| 37 |
async function convFromShared() {
|
| 38 |
try {
|
|
@@ -266,12 +264,6 @@
|
|
| 266 |
|
| 267 |
$: $page.params.id, (isAborted = true);
|
| 268 |
$: title = data.conversations.find((conv) => conv.id === $page.params.id)?.title ?? data.title;
|
| 269 |
-
|
| 270 |
-
$: loginRequired =
|
| 271 |
-
(data.requiresLogin
|
| 272 |
-
? !data.user
|
| 273 |
-
: !data.settings.ethicsModalAcceptedAt && !!PUBLIC_APP_DISCLAIMER) &&
|
| 274 |
-
messages.length >= data.messagesBeforeLogin;
|
| 275 |
</script>
|
| 276 |
|
| 277 |
<svelte:head>
|
|
@@ -299,5 +291,4 @@
|
|
| 299 |
models={data.models}
|
| 300 |
currentModel={findCurrentModel([...data.models, ...data.oldModels], data.model)}
|
| 301 |
settings={data.settings}
|
| 302 |
-
{loginRequired}
|
| 303 |
/>
|
|
|
|
| 12 |
import { findCurrentModel } from "$lib/utils/models";
|
| 13 |
import { webSearchParameters } from "$lib/stores/webSearchParameters";
|
| 14 |
import type { Message } from "$lib/types/Message";
|
|
|
|
| 15 |
import type { MessageUpdate, WebSearchUpdate } from "$lib/types/MessageUpdate";
|
| 16 |
import titleUpdate from "$lib/stores/titleUpdate";
|
| 17 |
|
|
|
|
| 31 |
|
| 32 |
let loading = false;
|
| 33 |
let pending = false;
|
|
|
|
| 34 |
|
| 35 |
async function convFromShared() {
|
| 36 |
try {
|
|
|
|
| 264 |
|
| 265 |
$: $page.params.id, (isAborted = true);
|
| 266 |
$: title = data.conversations.find((conv) => conv.id === $page.params.id)?.title ?? data.title;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 267 |
</script>
|
| 268 |
|
| 269 |
<svelte:head>
|
|
|
|
| 291 |
models={data.models}
|
| 292 |
currentModel={findCurrentModel([...data.models, ...data.oldModels], data.model)}
|
| 293 |
settings={data.settings}
|
|
|
|
| 294 |
/>
|
src/routes/conversation/[id]/+server.ts
CHANGED
|
@@ -49,13 +49,28 @@ export async function POST({ request, fetch, locals, params, getClientAddress })
|
|
| 49 |
ip: getClientAddress(),
|
| 50 |
});
|
| 51 |
|
| 52 |
-
//
|
| 53 |
if (
|
| 54 |
!locals.user?._id &&
|
| 55 |
requiresUser &&
|
| 56 |
-
|
| 57 |
) {
|
| 58 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
}
|
| 60 |
|
| 61 |
// check if the user is rate limited
|
|
|
|
| 49 |
ip: getClientAddress(),
|
| 50 |
});
|
| 51 |
|
| 52 |
+
// guest mode check
|
| 53 |
if (
|
| 54 |
!locals.user?._id &&
|
| 55 |
requiresUser &&
|
| 56 |
+
(MESSAGES_BEFORE_LOGIN ? parseInt(MESSAGES_BEFORE_LOGIN) : 0) > 0
|
| 57 |
) {
|
| 58 |
+
const totalMessages =
|
| 59 |
+
(
|
| 60 |
+
await collections.conversations
|
| 61 |
+
.aggregate([
|
| 62 |
+
{ $match: authCondition(locals) },
|
| 63 |
+
{ $project: { messages: 1 } },
|
| 64 |
+
{ $unwind: "$messages" },
|
| 65 |
+
{ $match: { "messages.from": "assistant" } },
|
| 66 |
+
{ $count: "messages" },
|
| 67 |
+
])
|
| 68 |
+
.toArray()
|
| 69 |
+
)[0]?.messages ?? 0;
|
| 70 |
+
|
| 71 |
+
if (totalMessages > parseInt(MESSAGES_BEFORE_LOGIN)) {
|
| 72 |
+
throw error(429, "Exceeded number of messages before login");
|
| 73 |
+
}
|
| 74 |
}
|
| 75 |
|
| 76 |
// check if the user is rate limited
|