File size: 4,526 Bytes
39eb06d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<script lang="ts">
	import { HfInference } from '@huggingface/inference';

	import PlaygroundMessage from '$lib/components/Playground/PlaygroundMessage.svelte';
	import PlaygroundOptions from '$lib/components/Playground/PlaygroundOptions.svelte';

	type Message = {
		role: 'user' | 'assistant' | 'system';
		content: string;
	};

	const startMessages: Message[] = [{ role: 'user', content: '' }];
	const compatibleModels: string[] = [
		'meta-llama/Meta-Llama-3-8B-Instruct',
		'mistralai/Mistral-7B-Instruct-v0.3'
	];

	let hfToken: string | null;

	let currentModel = compatibleModels[0];
	let systemMessage: Message = { role: 'system', content: '' };
	let messages: Message[] = startMessages;

	function addMessage() {
		messages = [
			...messages,
			{ role: messages.at(-1)?.role === 'user' ? 'assistant' : 'user', content: '' }
		];
	}

	function deleteMessage(i: number) {
		messages = messages.filter((_, j) => j !== i);
	}

	function reset() {
		messages = startMessages;
	}

	function onKeydown(event: KeyboardEvent) {
		// check if the user is pressing the enter key + ctrl key or command key
		if ((event.ctrlKey || event.metaKey) && event.key === 'Enter') {
			submit();
		}
	}

	async function submit() {
		if (!hfToken) {
			const token = prompt(
				'Please enter your Hugging Face API token (with `inference` permission):'
			);
			if (!token) return;
			hfToken = token;
		}
		(document.activeElement as HTMLElement).blur();
		const hf = new HfInference(hfToken);

		const out = await hf.chatCompletion({
			model: currentModel,
			messages: systemMessage.content ? [systemMessage, ...messages] : messages,
			max_tokens: 500,
			temperature: 0.1,
			seed: 0
		});

		messages = [...messages, ...out.choices.map((o) => o.message)];
	}

	$: console.log(messages);
</script>

<svelte:window on:keydown={onKeydown} />

<div
	class="grid h-dvh divide-gray-200 overflow-hidden max-md:grid-cols-1 max-md:divide-y md:grid-cols-[260px,1fr,260px] md:divide-x"
>
	<div class="relative flex flex-col overflow-y-auto p-5 pb-24">
		<div class="pb-2 text-sm font-semibold">SYSTEM</div>
		<textarea
			name=""
			id=""
			placeholder="Enter a custom prompt"
			bind:value={systemMessage.content}
			class="absolute inset-x-0 bottom-0 h-full resize-none bg-transparent p-2 pl-5 pr-3 pt-12 outline-none"
		></textarea>
	</div>
	<div class="relative divide-y divide-gray-200">
		{#each messages as message, i}
			<PlaygroundMessage {message} on:delete={() => deleteMessage(i)} />
		{/each}

		<button
			class="grid w-full grid-cols-[130px,1fr] items-center py-6 hover:bg-gray-50"
			on:click={addMessage}
		>
			<div class="button !p-0 text-sm font-semibold">Add message</div>
		</button>
		<div class="absolute inset-x-0 bottom-0 flex h-20 items-center gap-2 whitespace-nowrap px-5">
			<button
				type="button"
				class="rounded-lg border border-gray-200 bg-white px-5 py-2.5 text-sm font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:outline-none focus:ring-4 focus:ring-gray-100 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700"
				>Share</button
			>

			<button
				type="button"
				on:click={reset}
				class="rounded-lg border border-gray-200 bg-white px-5 py-2.5 text-sm font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:outline-none focus:ring-4 focus:ring-gray-100 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700"
				>Reset</button
			>
			<div class="flex-1 items-center justify-center text-center text-sm text-gray-500">
				23 tokens · Latency 750ms
			</div>
			<button
				type="button"
				class="rounded-lg border border-gray-200 bg-white px-5 py-2.5 text-sm font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:outline-none focus:ring-4 focus:ring-gray-100 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700"
				>View Code</button
			>
			<button
				on:click={submit}
				type="button"
				class="rounded-lg bg-black px-5 py-2.5 text-sm font-medium text-white hover:bg-gray-900 focus:outline-none focus:ring-4 focus:ring-gray-300 dark:border-gray-700 dark:bg-gray-800 dark:hover:bg-gray-700 dark:focus:ring-gray-700"
				>Submit</button
			>
		</div>
	</div>
	<div class="flex flex-col gap-6 p-5">
		<PlaygroundOptions {compatibleModels} bind:currentModel />
	</div>
</div>