From 150e97351bcd00bf384ff32891812772c9f32e45 Mon Sep 17 00:00:00 2001 From: Nathan Sarrazin Date: Wed, 16 Oct 2024 09:56:58 +0000 Subject: [PATCH] feat: better prompt examples --- .env | 4 +- chart/env/prod.yaml | 121 +++++------------- .../components/chat/ChatIntroduction.svelte | 57 +++++++-- src/lib/components/chat/ChatWindow.svelte | 4 +- src/lib/server/promptExamples.ts | 55 ++++++++ src/lib/server/tools/index.ts | 3 + src/routes/+layout.server.ts | 3 +- src/routes/+page.svelte | 1 + src/routes/conversation/[id]/+page.svelte | 1 + src/routes/models/[...model]/+page.svelte | 1 + 10 files changed, 150 insertions(+), 100 deletions(-) create mode 100644 src/lib/server/promptExamples.ts diff --git a/.env b/.env index db44ca3217e..a30848385a1 100644 --- a/.env +++ b/.env @@ -182,4 +182,6 @@ HF_ORG_EARLY_ACCESS= PUBLIC_SMOOTH_UPDATES=false COMMUNITY_TOOLS=false -PUBLIC_COMMIT_SHA= \ No newline at end of file +PUBLIC_COMMIT_SHA= + +PROMPT_EXAMPLES=`[]` \ No newline at end of file diff --git a/chart/env/prod.yaml b/chart/env/prod.yaml index 994f58c6bd9..c6b37b93633 100644 --- a/chart/env/prod.yaml +++ b/chart/env/prod.yaml @@ -60,21 +60,7 @@ envVars: "temperature": 0.6, "max_new_tokens": 1024, "truncate": 7167 - }, - "promptExamples": [ - { - "title": "Write an email from bullet list", - "prompt": "As a restaurant owner, write a professional email to the supplier to get these products every week: \n\n- Wine (x10)\n- Eggs (x24)\n- Bread (x12)" - }, - { - "title": "Code a snake game", - "prompt": "Code a basic snake game in python, give explanations for each step." - }, - { - "title": "Assist in a task", - "prompt": "How do I make a delicious lemon cheesecake?" - } - ] + } }, { "name": "CohereForAI/c4ai-command-r-plus-08-2024", @@ -92,21 +78,7 @@ envVars: "truncate": 28672, "max_new_tokens": 2048, "temperature": 0.3 - }, - "promptExamples": [ - { - "title": "Generate a mouse portrait", - "prompt": "Generate the portrait of a scientific mouse in its laboratory." - }, - { - "title": "Review a pull request", - "prompt": "Review this pull request: https://github.com/huggingface/chat-ui/pull/1131/files" - }, - { - "title": "Code a snake game", - "prompt": "Code a basic snake game in python, give explanations for each step." - } - ] + } }, { "name": "Qwen/Qwen2.5-72B-Instruct", @@ -121,21 +93,7 @@ envVars: "temperature": 0.6, "truncate": 28672, "max_new_tokens": 3072 - }, - "promptExamples": [ - { - "title": "Write an email from bullet list", - "prompt": "As a restaurant owner, write a professional email to the supplier to get these products every week: \n\n- Wine (x10)\n- Eggs (x24)\n- Bread (x12)" - }, - { - "title": "Code a snake game", - "prompt": "Code a basic snake game in python, give explanations for each step." - }, - { - "title": "Assist in a task", - "prompt": "How do I make a delicious lemon cheesecake?" - } - ] + } }, { "name": "meta-llama/Llama-3.2-11B-Vision-Instruct", @@ -170,20 +128,6 @@ envVars: "websiteUrl": "https://nousresearch.com/", "modelUrl": "https://huggingface.co/NousResearch/Hermes-3-Llama-3.1-8B", "tokenizer": "NousResearch/Hermes-3-Llama-3.1-8B", - "promptExamples": [ - { - "title": "Write an email from bullet list", - "prompt": "As a restaurant owner, write a professional email to the supplier to get these products every week: \n\n- Wine (x10)\n- Eggs (x24)\n- Bread (x12)" - }, - { - "title": "Code a snake game", - "prompt": "Code a basic snake game in python, give explanations for each step." - }, - { - "title": "Assist in a task", - "prompt": "How do I make a delicious lemon cheesecake?" - } - ], "parameters": { "stop": ["<|im_end|>"], "temperature": 0.6, @@ -205,21 +149,7 @@ envVars: "temperature": 0.6, "truncate": 14336, "max_new_tokens": 1536 - }, - "promptExamples": [ - { - "title": "Write an email from bullet list", - "prompt": "As a restaurant owner, write a professional email to the supplier to get these products every week: \n\n- Wine (x10)\n- Eggs (x24)\n- Bread (x12)" - }, - { - "title": "Code a snake game", - "prompt": "Code a basic snake game in python, give explanations for each step." - }, - { - "title": "Assist in a task", - "prompt": "How do I make a delicious lemon cheesecake?" - } - ] + } }, { "name": "microsoft/Phi-3.5-mini-instruct", @@ -234,21 +164,7 @@ envVars: "temperature": 0.6, "truncate": 28672, "max_new_tokens": 3072 - }, - "promptExamples": [ - { - "title": "Write an email from bullet list", - "prompt": "As a restaurant owner, write a professional email to the supplier to get these products every week: \n\n- Wine (x10)\n- Eggs (x24)\n- Bread (x12)" - }, - { - "title": "Code a snake game", - "prompt": "Code a basic snake game in python, give explanations for each step." - }, - { - "title": "Assist in a task", - "prompt": "How do I make a delicious lemon cheesecake?" - } - ] + } }, { "name": "llhf/Meta-Llama-3.1-8B-Instruct", @@ -306,6 +222,33 @@ envVars: "transferTo": "microsoft/Phi-3.5-mini-instruct" } ] + PROMPT_EXAMPLES: > + [ + { + "title": "Write an email from bullet list", + "prompt": "As a restaurant owner, write a professional email to the supplier to get these products every week: \n\n- Wine (x10)\n- Eggs (x24)\n- Bread (x12)" + }, + { + "title": "Code a snake game", + "prompt": "Code a basic snake game in python, give explanations for each step." + }, + { + "title": "Assist in a task", + "prompt": "How do I make a delicious lemon cheesecake?" + }, + { + "type": "multimodal", + "title": "Identify a flower", + "prompt": "What kind of flower is this?", + "fileUrl": "https://huggingface.co/datasets/huggingchat/prompt-examples/resolve/main/flower.jpg" + }, + { + "type": "tool", + "title": "Generate a painting", + "prompt": "Generate a painting of a forest, oil painting style.", + "toolId": "000000000000000000000001" + } + ] PUBLIC_ORIGIN: "https://huggingface.co" PUBLIC_SHARE_PREFIX: "https://hf.co/chat" PUBLIC_ANNOUNCEMENT_BANNERS: "[]" diff --git a/src/lib/components/chat/ChatIntroduction.svelte b/src/lib/components/chat/ChatIntroduction.svelte index 729a21ad3e3..6b5599c05af 100644 --- a/src/lib/components/chat/ChatIntroduction.svelte +++ b/src/lib/components/chat/ChatIntroduction.svelte @@ -8,14 +8,31 @@ import ModelCardMetadata from "../ModelCardMetadata.svelte"; import { base } from "$app/paths"; import JSON5 from "json5"; + import type { PromptExample } from "$lib/server/promptExamples"; + + import CarbonImage from "~icons/carbon/image"; + import CarbonTools from "~icons/carbon/tools"; export let currentModel: Model; + export let promptExamples: PromptExample[]; const announcementBanners = envPublic.PUBLIC_ANNOUNCEMENT_BANNERS ? JSON5.parse(envPublic.PUBLIC_ANNOUNCEMENT_BANNERS) : []; - const dispatch = createEventDispatcher<{ message: string }>(); + const dispatch = createEventDispatcher<{ + message: { + prompt: string; + file?: File | string; + tool?: string; + }; + }>(); + + const prompts = promptExamples + .filter((prompt: PromptExample) => prompt?.models?.includes(currentModel.id) ?? true) + .filter(Boolean) + .sort(() => Math.random() - 0.5) + .slice(0, 3) as PromptExample[];
@@ -72,20 +89,44 @@
- {#if currentModel.promptExamples} + {#if prompts && prompts.length > 0}
-

Examples

+

Examples

- {#each currentModel.promptExamples as example} + {#each prompts as example} {/each}
-
{/if} + + {/if}
+ + diff --git a/src/lib/components/chat/ChatWindow.svelte b/src/lib/components/chat/ChatWindow.svelte index 65f3cbf20f2..44035e53b13 100644 --- a/src/lib/components/chat/ChatWindow.svelte +++ b/src/lib/components/chat/ChatWindow.svelte @@ -48,6 +48,7 @@ export let assistant: Assistant | undefined = undefined; export let preprompt: string | undefined = undefined; export let files: File[] = []; + export let promptExamples: PromptExample[] = []; $: isReadOnly = !models.some((model) => model.id === currentModel.id); @@ -304,6 +305,7 @@ {:else if !assistant} { if ($page.data.loginRequired) { ev.preventDefault(); @@ -498,7 +500,7 @@
Link copied to clipboard
{:else} - +
Share this conversation
{/if} diff --git a/src/lib/server/promptExamples.ts b/src/lib/server/promptExamples.ts new file mode 100644 index 00000000000..13750b7be09 --- /dev/null +++ b/src/lib/server/promptExamples.ts @@ -0,0 +1,55 @@ +import { z } from "zod"; +import { validModelIdSchema, models } from "./models"; +import { validToolIdSchema } from "./tools"; +import JSON5 from "json5"; +import { env } from "$env/dynamic/private"; + +const basePromptSchema = z.object({ + title: z.string(), + prompt: z.string(), + models: z.array(validModelIdSchema).optional(), +}); + +const multimodalPromptSchema = basePromptSchema.extend({ + type: z.literal("multimodal"), + fileUrl: z.string().url(), +}); + +const toolPromptSchema = basePromptSchema.extend({ + type: z.literal("tool"), + toolId: validToolIdSchema, + fileUrl: z.string().url().optional(), +}); + +const simplePromptSchema = basePromptSchema + .extend({ + type: z.literal("simple").optional(), + }) + .transform((data) => ({ + ...data, + type: data, + })); + +const promptExamplesSchema = z.array( + z.union([multimodalPromptSchema, toolPromptSchema, simplePromptSchema]) +); + +export type PromptExample = z.infer[number]; + +// parse the prompt examples from the environment variable +const promptExamples = promptExamplesSchema.parse(JSON5.parse(env.PROMPT_EXAMPLES)); + +// add model specific prompt examples for legacy configs +const modelSpecificPromptExamples = models + .filter((model) => !!model.promptExamples) + .map((model) => + model.promptExamples?.map((example) => ({ + ...example, + models: [model.id], + })) + ) + .flat(); + +const combinedPromptExamples = [...promptExamples, ...modelSpecificPromptExamples]; + +export { combinedPromptExamples as promptExamples }; diff --git a/src/lib/server/tools/index.ts b/src/lib/server/tools/index.ts index 2cb06903586..e61016bf7b3 100644 --- a/src/lib/server/tools/index.ts +++ b/src/lib/server/tools/index.ts @@ -308,3 +308,6 @@ export function getCallMethod(tool: Omit): BackendCall { } export const toolFromConfigs = configTools.parse(JSON5.parse(env.TOOLS)) satisfies ConfigTool[]; +export const validToolIdSchema = z.enum( + toolFromConfigs.map((t) => t._id.toString()) as [string, ...string[]] +); diff --git a/src/routes/+layout.server.ts b/src/routes/+layout.server.ts index 913dc9dc37b..9cb82f32db9 100644 --- a/src/routes/+layout.server.ts +++ b/src/routes/+layout.server.ts @@ -12,6 +12,7 @@ import { toolFromConfigs } from "$lib/server/tools"; import { MetricsServer } from "$lib/server/metrics"; import type { ToolFront, ToolInputFile } from "$lib/types/Tool"; import { ReviewStatus } from "$lib/types/Review"; +import { promptExamples } from "$lib/server/promptExamples"; export const load: LayoutServerLoad = async ({ locals, depends }) => { depends(UrlDependency.ConversationList); @@ -186,7 +187,6 @@ export const load: LayoutServerLoad = async ({ locals, depends }) => { displayName: model.displayName, description: model.description, logoUrl: model.logoUrl, - promptExamples: model.promptExamples, parameters: model.parameters, preprompt: model.preprompt, multimodal: model.multimodal, @@ -240,6 +240,7 @@ export const load: LayoutServerLoad = async ({ locals, depends }) => { isAdmin: locals.user.isAdmin ?? false, isEarlyAccess: locals.user.isEarlyAccess ?? false, }, + promptExamples, assistant, enableAssistants, enableAssistantsRAG: env.ENABLE_ASSISTANTS_RAG === "true", diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 32f976d9962..13569b2f1dc 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -97,5 +97,6 @@ assistant={data.assistant} {currentModel} models={data.models} + promptExamples={data.promptExamples} bind:files /> diff --git a/src/routes/conversation/[id]/+page.svelte b/src/routes/conversation/[id]/+page.svelte index b5d7ad3f569..2e8529055e4 100644 --- a/src/routes/conversation/[id]/+page.svelte +++ b/src/routes/conversation/[id]/+page.svelte @@ -398,6 +398,7 @@ {messages} shared={data.shared} preprompt={data.preprompt} + promptExamples={data.promptExamples} bind:files on:message={onMessage} on:retry={onRetry} diff --git a/src/routes/models/[...model]/+page.svelte b/src/routes/models/[...model]/+page.svelte index c86b4089e05..89b0b3e749a 100644 --- a/src/routes/models/[...model]/+page.svelte +++ b/src/routes/models/[...model]/+page.svelte @@ -99,5 +99,6 @@ {loading} currentModel={findCurrentModel([...data.models, ...data.oldModels], modelId)} models={data.models} + promptExamples={data.promptExamples} bind:files />