Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set assistant prompt from URL #942

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
50 changes: 48 additions & 2 deletions src/lib/components/AssistantSettings.svelte
Expand Up @@ -74,12 +74,14 @@

let loading = false;

let ragMode: false | "links" | "domains" | "all" = assistant?.rag?.allowAllDomains
let ragMode: false | "links" | "domains" | "all" | "preprompt" = assistant?.rag?.allowAllDomains
? "all"
: assistant?.rag?.allowedLinks?.length ?? 0 > 0
? "links"
: (assistant?.rag?.allowedDomains?.length ?? 0) > 0
? "domains"
: (assistant?.rag?.prepromptUrl ?? "").length > 0
? "preprompt"
: false;
</script>

Expand Down Expand Up @@ -119,18 +121,29 @@
formData.set("ragAllowAll", "false");
formData.set("ragLinkList", "");
formData.set("ragDomainList", "");
formData.set("ragPrepromptUrl", "");
} else if (ragMode === "all") {
formData.set("ragAllowAll", "true");
formData.set("ragLinkList", "");
formData.set("ragDomainList", "");
formData.set("ragPrepromptUrl", "");
} else if (ragMode === "links") {
formData.set("ragAllowAll", "false");
formData.set("ragDomainList", "");
formData.set("ragPrepromptUrl", "");
} else if (ragMode === "domains") {
formData.set("ragAllowAll", "false");
formData.set("ragLinkList", "");
formData.set("ragPrepromptUrl", "");
} else if (ragMode === "preprompt") {
formData.set("ragAllowAll", "false");
formData.set("ragLinkList", "");
formData.set("ragDomainList", "");
formData.set(
"preprompt",
"The system prompt input is disabled when using a system prompt URL."
Comment on lines +124 to +144
Copy link
Collaborator

@gary149 gary149 Mar 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could just refactor later no? I don't get why we need this list this should be handled natively by the <form>.

);
}

return async ({ result }) => {
loading = false;
await applyAction(result);
Expand Down Expand Up @@ -384,17 +397,50 @@
/>
<p class="text-xs text-red-500">{getError("ragLinkList", form)}</p>
{/if}
<label class="mt-1">
<input
checked={ragMode === "preprompt"}
on:change={() => (ragMode = "preprompt")}
type="radio"
name="ragMode"
value={false}
/>
<span class="my-2 text-sm" class:font-semibold={ragMode === "links"}>
System Prompt URL
</span>
</label>
{#if ragMode === "preprompt"}
<span class="mb-2 text-xs text-gray-500">
Specify a single URL which returns a plain-text response that will be passed directly
as the system prompt.
</span>
<input
name="ragPrepromptUrl"
class="w-full rounded-lg border-2 border-gray-200 bg-gray-100 p-2"
placeholder="https://raw.githubusercontent.com/huggingface/chat-ui/main/README.md"
value={assistant?.rag?.prepromptUrl ?? ""}
/>
<p class="text-xs text-red-500">{getError("ragPrepromptUrl", form)}</p>
{/if}
</div>
{/if}
</div>

<div class="col-span-1 flex h-full flex-col">
<span class="mb-1 text-sm font-semibold"> Instructions (system prompt) </span>
<textarea
name="preprompt"
class="mb-20 min-h-[8lh] flex-1 rounded-lg border-2 border-gray-200 bg-gray-200 p-2 text-sm text-gray-600"
value="The system prompt input is disabled when using a system prompt URL."
disabled
class:hidden={ragMode !== "preprompt"}
/>
<textarea
name="preprompt"
class="mb-20 min-h-[8lh] flex-1 rounded-lg border-2 border-gray-200 bg-gray-100 p-2 text-sm"
placeholder="You'll act as..."
value={assistant?.preprompt ?? ""}
class:hidden={ragMode === "preprompt"}
/>
<p class="text-xs text-red-500">{getError("preprompt", form)}</p>
</div>
Expand Down
7 changes: 3 additions & 4 deletions src/lib/components/chat/AssistantIntroduction.svelte
Expand Up @@ -19,10 +19,9 @@

const dispatch = createEventDispatcher<{ message: string }>();

$: hasRag =
assistant?.rag?.allowAllDomains ||
(assistant?.rag?.allowedDomains?.length ?? 0) > 0 ||
(assistant?.rag?.allowedLinks?.length ?? 0) > 0;
$: hasRag = Object.values(assistant?.rag ?? {}).some((value) =>
Array.isArray(value) ? value.length > 0 : !!value
);
</script>

<div class="flex h-full w-full flex-col content-center items-center justify-center pb-52">
Expand Down
1 change: 1 addition & 0 deletions src/lib/types/Assistant.ts
Expand Up @@ -18,6 +18,7 @@ export interface Assistant extends Timestamps {
allowAllDomains: boolean;
allowedDomains: string[];
allowedLinks: string[];
prepromptUrl?: string;
};
searchTokens: string[];
}
7 changes: 3 additions & 4 deletions src/routes/assistants/+page.svelte
Expand Up @@ -202,10 +202,9 @@

<div class="mt-8 grid grid-cols-2 gap-3 sm:gap-5 md:grid-cols-3 lg:grid-cols-4">
{#each data.assistants as assistant (assistant._id)}
{@const hasRag =
assistant?.rag?.allowAllDomains ||
!!assistant?.rag?.allowedDomains?.length ||
!!assistant?.rag?.allowedLinks?.length}
{@const hasRag = Object.values(assistant?.rag ?? {}).some((value) =>
Array.isArray(value) ? value.length > 0 : !!value
)}

<button
class="relative flex flex-col items-center justify-center overflow-hidden text-balance rounded-xl border bg-gray-50/50 px-4 py-6 text-center shadow hover:bg-gray-50 hover:shadow-inner max-sm:px-4 sm:h-64 sm:pb-4 xl:pt-8 dark:border-gray-800/70 dark:bg-gray-950/20 dark:hover:bg-gray-950/40"
Expand Down
19 changes: 16 additions & 3 deletions src/routes/conversation/+server.ts
Expand Up @@ -10,6 +10,8 @@ import { defaultEmbeddingModel } from "$lib/server/embeddingModels";
import { v4 } from "uuid";
import { authCondition } from "$lib/server/auth";
import { usageLimits } from "$lib/server/usageLimits";
import { isURLLocal } from "$lib/server/isURLLocal";
import { parseWeb } from "$lib/server/websearch/parseWeb";

export const POST: RequestHandler = async ({ locals, request }) => {
const body = await request.text();
Expand Down Expand Up @@ -51,11 +53,22 @@ export const POST: RequestHandler = async ({ locals, request }) => {
});

if (assistant) {
values.preprompt = assistant.preprompt;
} else {
values.preprompt ??= model?.preprompt ?? "";
// if the assistant has a preprompt Url and it's not local, try to fetch it
if (assistant.rag?.prepromptUrl && !(await isURLLocal(new URL(assistant.rag.prepromptUrl)))) {
try {
const content = await parseWeb(assistant.rag.prepromptUrl);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not parse like for web content.

values.preprompt = content;
} catch (e) {
values.preprompt = assistant.preprompt;
}
} else {
values.preprompt = assistant.preprompt;
}
}

// if no prompt was set try the model preprompt
values.preprompt ??= model?.preprompt ?? "";

let messages: Message[] = [
{
id: v4(),
Expand Down
7 changes: 5 additions & 2 deletions src/routes/conversation/[id]/+server.ts
Expand Up @@ -346,10 +346,13 @@ export async function POST({ request, locals, params, getClientAddress }) {
const assistantHasRAG =
ENABLE_ASSISTANTS_RAG === "true" &&
rag &&
(rag.allowedLinks.length > 0 || rag.allowedDomains.length > 0 || rag.allowAllDomains);
Object.values(rag).some((value) => (Array.isArray(value) ? value.length > 0 : !!value));

// perform websearch if needed
if (!isContinue && ((webSearch && !conv.assistantId) || assistantHasRAG)) {
if (
!isContinue &&
((webSearch && !conv.assistantId) || (assistantHasRAG && !rag.prepromptUrl))
) {
messageToWriteTo.webSearch = await runWebSearch(conv, messagesForPrompt, update, rag);
}

Expand Down
42 changes: 31 additions & 11 deletions src/routes/settings/(nav)/assistants/[assistantId]/+page.svelte
Expand Up @@ -29,10 +29,9 @@

let displayReportModal = false;

$: hasRag =
assistant?.rag?.allowAllDomains ||
!!assistant?.rag?.allowedDomains?.length ||
!!assistant?.rag?.allowedLinks?.length;
$: hasRag = Object.values(assistant?.rag ?? {}).some((value) =>
Array.isArray(value) ? value.length > 0 : !!value
);
</script>

{#if displayReportModal}
Expand Down Expand Up @@ -164,14 +163,35 @@

<!-- two columns for big screen, single column for small screen -->
<div class="mb-12 mt-3">
<h2 class="mb-2 font-semibold">System Instructions</h2>
<textarea
disabled
class="box-border h-full min-h-[8lh] w-full rounded-lg border-2 border-gray-200 bg-gray-100 p-2 disabled:cursor-not-allowed"
>{assistant?.preprompt}</textarea
>
<h2 class="mb-2 font-semibold">
System Instructions
{#if assistant?.rag?.prepromptUrl}
<span
class="inline-grid size-5 place-items-center rounded-full bg-blue-500/10"
title="This assistant gets its instructions from the internet.."
>
<IconInternet classNames="text-sm text-blue-600" />
</span>
{/if}
</h2>
{#if assistant?.rag?.prepromptUrl}
<p class="pb-3 text-sm text-gray-500">
This assistant loads system instructions from the following URL:
</p>
<a
target="_blank"
class="break-all rounded-lg border border-gray-200 bg-gray-100 px-2 py-1.5 leading-tight underline decoration-gray-400"
href={assistant?.rag?.prepromptUrl}>{assistant?.rag?.prepromptUrl}</a
>
{:else}
<textarea
disabled
class="box-border h-full min-h-[8lh] w-full rounded-lg border-2 border-gray-200 bg-gray-100 p-2 disabled:cursor-not-allowed"
>{assistant?.preprompt}</textarea
>
{/if}

{#if hasRag}
{#if hasRag && !assistant?.rag?.prepromptUrl}
<div class="mt-4">
<h2 class=" font-semibold">Internet Access</h2>
{#if assistant?.rag?.allowAllDomains}
Expand Down
Expand Up @@ -24,6 +24,7 @@ const newAsssistantSchema = z.object({
ragLinkList: z.preprocess(parseStringToList, z.string().url().array().max(10)),
ragDomainList: z.preprocess(parseStringToList, z.string().array()),
ragAllowAll: z.preprocess((v) => v === "true", z.boolean()),
ragPrepromptUrl: z.union([z.literal(""), z.string().trim().url()]),
});

const uploadAvatar = async (avatar: File, assistantId: ObjectId): Promise<string> => {
Expand Down Expand Up @@ -139,6 +140,7 @@ export const actions: Actions = {
allowedLinks: parse.data.ragLinkList,
allowedDomains: parse.data.ragDomainList,
allowAllDomains: parse.data.ragAllowAll,
prepromptUrl: parse.data.ragPrepromptUrl,
},
searchTokens: generateSearchTokens(parse.data.name),
},
Expand Down
2 changes: 2 additions & 0 deletions src/routes/settings/(nav)/assistants/new/+page.server.ts
Expand Up @@ -24,6 +24,7 @@ const newAsssistantSchema = z.object({
ragLinkList: z.preprocess(parseStringToList, z.string().url().array().max(10)),
ragDomainList: z.preprocess(parseStringToList, z.string().array()),
ragAllowAll: z.preprocess((v) => v === "true", z.boolean()),
ragPrepromptUrl: z.union([z.literal(""), z.string().trim().url()]),
});

const uploadAvatar = async (avatar: File, assistantId: ObjectId): Promise<string> => {
Expand Down Expand Up @@ -121,6 +122,7 @@ export const actions: Actions = {
allowedLinks: parse.data.ragLinkList,
allowedDomains: parse.data.ragDomainList,
allowAllDomains: parse.data.ragAllowAll,
prepromptUrl: parse.data.ragPrepromptUrl,
},
searchTokens: generateSearchTokens(parse.data.name),
});
Expand Down