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

Count system prompt tokens #850

Merged
merged 13 commits into from Mar 22, 2024
6 changes: 5 additions & 1 deletion .env.template
Expand Up @@ -7,6 +7,7 @@ MODELS=`[
"logoUrl": "https://huggingface.co/datasets/huggingchat/models-logo/resolve/main/mistral-logo.png",
"websiteUrl" : "https://mistral.ai/news/mixtral-of-experts/",
"modelUrl": "https://huggingface.co/mistralai/Mixtral-8x7B-Instruct-v0.1",
"tokenizer": "mistralai/Mixtral-8x7B-Instruct-v0.1",
"preprompt" : "",
"chatPromptTemplate": "<s> {{#each messages}}{{#ifUser}}[INST]{{#if @first}}{{#if @root.preprompt}}{{@root.preprompt}}\n{{/if}}{{/if}} {{content}} [/INST]{{/ifUser}}{{#ifAssistant}} {{content}}</s> {{/ifAssistant}}{{/each}}",
"parameters" : {
Expand Down Expand Up @@ -63,7 +64,6 @@ MODELS=`[
"description": "The latest and biggest model from Meta, fine-tuned for chat.",
"logoUrl": "https://huggingface.co/datasets/huggingchat/models-logo/resolve/main/meta-logo.png",
"websiteUrl": "https://ai.meta.com/llama/",
"modelUrl": "https://huggingface.co/meta-llama/Llama-2-70b-chat-hf",
"preprompt": " ",
"chatPromptTemplate" : "<s>[INST] <<SYS>>\n{{preprompt}}\n<</SYS>>\n\n{{#each messages}}{{#ifUser}}{{content}} [/INST] {{/ifUser}}{{#ifAssistant}}{{content}} </s><s>[INST] {{/ifAssistant}}{{/each}}",
"promptExamples": [
Expand Down Expand Up @@ -94,6 +94,7 @@ MODELS=`[
"logoUrl": "https://huggingface.co/datasets/huggingchat/models-logo/resolve/main/nous-logo.png",
"websiteUrl" : "https://nousresearch.com/",
"modelUrl": "https://huggingface.co/NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO",
"tokenizer": "NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO",
"chatPromptTemplate" : "{{#if @root.preprompt}}<|im_start|>system\n{{@root.preprompt}}<|im_end|>\n{{/if}}{{#each messages}}{{#ifUser}}<|im_start|>user\n{{content}}<|im_end|>\n<|im_start|>assistant\n{{/ifUser}}{{#ifAssistant}}{{content}}<|im_end|>\n{{/ifAssistant}}{{/each}}",
"promptExamples": [
{
Expand Down Expand Up @@ -155,6 +156,7 @@ MODELS=`[
"logoUrl": "https://huggingface.co/datasets/huggingchat/models-logo/resolve/main/mistral-logo.png",
"websiteUrl": "https://mistral.ai/news/announcing-mistral-7b/",
"modelUrl": "https://huggingface.co/mistralai/Mistral-7B-Instruct-v0.1",
"tokenizer": "mistralai/Mistral-7B-Instruct-v0.1",
"preprompt": "",
"chatPromptTemplate" : "<s>{{#each messages}}{{#ifUser}}[INST] {{#if @first}}{{#if @root.preprompt}}{{@root.preprompt}}\n{{/if}}{{/if}}{{content}} [/INST]{{/ifUser}}{{#ifAssistant}}{{content}}</s>{{/ifAssistant}}{{/each}}",
"parameters": {
Expand Down Expand Up @@ -187,6 +189,7 @@ MODELS=`[
"logoUrl": "https://huggingface.co/datasets/huggingchat/models-logo/resolve/main/mistral-logo.png",
"websiteUrl": "https://mistral.ai/news/announcing-mistral-7b/",
"modelUrl": "https://huggingface.co/mistralai/Mistral-7B-Instruct-v0.2",
"tokenizer": "mistralai/Mistral-7B-Instruct-v0.2",
"preprompt": "",
"chatPromptTemplate" : "<s>{{#each messages}}{{#ifUser}}[INST] {{#if @first}}{{#if @root.preprompt}}{{@root.preprompt}}\n{{/if}}{{/if}}{{content}} [/INST]{{/ifUser}}{{#ifAssistant}}{{content}}</s>{{/ifAssistant}}{{/each}}",
"parameters": {
Expand Down Expand Up @@ -218,6 +221,7 @@ MODELS=`[
"logoUrl": "https://huggingface.co/datasets/huggingchat/models-logo/resolve/main/openchat-logo.png",
"websiteUrl": "https://huggingface.co/openchat/openchat-3.5-0106",
"modelUrl": "https://huggingface.co/openchat/openchat-3.5-0106",
"tokenizer": "openchat/openchat-3.5-0106",
"preprompt": "",
"chatPromptTemplate" : "<s>{{#each messages}}{{#ifUser}}GPT4 Correct User: {{#if @first}}{{#if @root.preprompt}}{{@root.preprompt}}\n{{/if}}{{/if}}{{content}}<|end_of_turn|>GPT4 Correct Assistant:{{/ifUser}}{{#ifAssistant}}{{content}}<|end_of_turn|>{{/ifAssistant}}{{/each}}",
"parameters": {
Expand Down
36 changes: 28 additions & 8 deletions src/lib/components/AssistantSettings.svelte
Expand Up @@ -12,6 +12,7 @@

import { useSettingsStore } from "$lib/stores/settings";
import { isHuggingChat } from "$lib/utils/isHuggingChat";
import TokensCounter from "./TokensCounter.svelte";

type ActionData = {
error: boolean;
Expand All @@ -28,8 +29,10 @@
export let models: Model[] = [];

let files: FileList | null = null;

const settings = useSettingsStore();
let modelId =
assistant?.modelId ?? models.find((_model) => _model.id === $settings.activeModel)?.name;
let systemPrompt = assistant?.preprompt ?? "";

let compress: typeof readAndCompressImage | null = null;

Expand Down Expand Up @@ -238,7 +241,11 @@

<label>
<div class="mb-1 font-semibold">Model</div>
<select name="modelId" class="w-full rounded-lg border-2 border-gray-200 bg-gray-100 p-2">
<select
name="modelId"
class="w-full rounded-lg border-2 border-gray-200 bg-gray-100 p-2"
bind:value={modelId}
>
{#each models.filter((model) => !model.unlisted) as model}
<option
value={model.id}
Expand Down Expand Up @@ -390,12 +397,25 @@

<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-100 p-2 text-sm"
placeholder="You'll act as..."
value={assistant?.preprompt ?? ""}
/>
<div class="relative mb-20 flex min-h-[8lh] flex-1 grow flex-col">
<textarea
name="preprompt"
class="flex-1 rounded-lg border-2 border-gray-200 bg-gray-100 p-2 text-sm"
placeholder="You'll act as..."
bind:value={systemPrompt}
/>
{#if modelId}
{@const model = models.find((_model) => _model.id === modelId)}
{#if model?.tokenizer && systemPrompt}
<TokensCounter
classNames="absolute bottom-2 right-2"
prompt={systemPrompt}
modelTokenizer={model.tokenizer}
max_new_tokens={model?.parameters?.max_new_tokens}
Copy link
Collaborator

Choose a reason for hiding this comment

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

use truncate value instead?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

handled in f47c6bb

/>
{/if}
{/if}
</div>
<p class="text-xs text-red-500">{getError("preprompt", form)}</p>
</div>
</div>
Expand Down
48 changes: 48 additions & 0 deletions src/lib/components/TokensCounter.svelte
Copy link
Collaborator

Choose a reason for hiding this comment

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

This won't work on local models with chat-ui. I would probably set an explicit key in the config for models that are compatible.

@@ -0,0 +1,48 @@
<script lang="ts">
import type { Model } from "$lib/types/Model";
import { AutoTokenizer, PreTrainedTokenizer } from "@xenova/transformers";

export let classNames = "";
export let prompt = "";
export let modelTokenizer: Exclude<Model["tokenizer"], undefined>;
export let max_new_tokens: number | undefined = undefined;

let tokenizer: PreTrainedTokenizer | undefined = undefined;

async function getTokenizer(_modelTokenizer: Exclude<Model["tokenizer"], undefined>) {
if (typeof _modelTokenizer === "string") {
// return auto tokenizer
return await AutoTokenizer.from_pretrained(_modelTokenizer);
}
{
// construct & return pretrained tokenizer
const { tokenizerUrl, tokenizerConfigUrl } = _modelTokenizer satisfies {
tokenizerUrl: string;
tokenizerConfigUrl: string;
};
const tokenizerJSON = await (await fetch(tokenizerUrl)).json();
const tokenizerConfig = await (await fetch(tokenizerConfigUrl)).json();
return new PreTrainedTokenizer(tokenizerJSON, tokenizerConfig);
}
}

async function tokenizeText(_prompt: string) {
if (!tokenizer) {
return;
}
const { input_ids } = await tokenizer(_prompt);
return input_ids.size;
}

$: (async () => {
tokenizer = await getTokenizer(modelTokenizer);
})();
</script>

{#if tokenizer}
{#await tokenizeText(prompt) then nTokens}
<p class="text-sm opacity-60 hover:opacity-80 {classNames}">
{nTokens}{max_new_tokens ? `/${max_new_tokens}` : ""}
</p>
{/await}
{/if}
9 changes: 9 additions & 0 deletions src/lib/server/models.ts
Expand Up @@ -28,6 +28,15 @@ const modelConfig = z.object({
logoUrl: z.string().url().optional(),
websiteUrl: z.string().url().optional(),
modelUrl: z.string().url().optional(),
tokenizer: z
.union([
z.string(),
z.object({
tokenizerUrl: z.string().url(),
tokenizerConfigUrl: z.string().url(),
}),
])
.optional(),
datasetName: z.string().min(1).optional(),
datasetUrl: z.string().url().optional(),
userMessageToken: z.string().default(""),
Expand Down
1 change: 1 addition & 0 deletions src/lib/types/Model.ts
Expand Up @@ -12,6 +12,7 @@ export type Model = Pick<
| "description"
| "logoUrl"
| "modelUrl"
| "tokenizer"
| "datasetUrl"
| "preprompt"
| "multimodal"
Expand Down
1 change: 1 addition & 0 deletions src/routes/+layout.server.ts
Expand Up @@ -158,6 +158,7 @@ export const load: LayoutServerLoad = async ({ locals, depends }) => {
name: model.name,
websiteUrl: model.websiteUrl,
modelUrl: model.modelUrl,
tokenizer: model.tokenizer,
datasetName: model.datasetName,
datasetUrl: model.datasetUrl,
displayName: model.displayName,
Expand Down
1 change: 1 addition & 0 deletions src/routes/api/models/+server.ts
Expand Up @@ -6,6 +6,7 @@ export async function GET() {
name: model.name,
websiteUrl: model.websiteUrl,
modelUrl: model.modelUrl,
tokenizer: model.tokenizer,
datasetName: model.datasetName,
datasetUrl: model.datasetUrl,
displayName: model.displayName,
Expand Down
11 changes: 10 additions & 1 deletion src/routes/settings/(nav)/[...model]/+page.svelte
Expand Up @@ -5,6 +5,7 @@
import type { BackendModel } from "$lib/server/models";
import { useSettingsStore } from "$lib/stores/settings";
import CopyToClipBoardBtn from "$lib/components/CopyToClipBoardBtn.svelte";
import TokensCounter from "$lib/components/TokensCounter.svelte";
import CarbonArrowUpRight from "~icons/carbon/arrow-up-right";
import CarbonLink from "~icons/carbon/link";

Expand Down Expand Up @@ -99,7 +100,7 @@
{isActive ? "Active model" : "Activate"}
</button>

<div class="flex w-full flex-col gap-2">
<div class="relative flex w-full flex-col gap-2">
<div class="flex w-full flex-row content-between">
<h3 class="mb-1.5 text-lg font-semibold text-gray-800">System Prompt</h3>
{#if hasCustomPreprompt}
Expand All @@ -117,5 +118,13 @@
class="w-full resize-none rounded-md border-2 bg-gray-100 p-2"
bind:value={$settings.customPrompts[$page.params.model]}
/>
{#if model.tokenizer && $settings.customPrompts[$page.params.model]}
<TokensCounter
classNames="absolute bottom-2 right-2"
prompt={$settings.customPrompts[$page.params.model]}
modelTokenizer={model.tokenizer}
max_new_tokens={model?.parameters?.max_new_tokens}
/>
{/if}
</div>
</div>