File size: 4,583 Bytes
ef5513c
 
 
669277f
ef5513c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
669277f
0f32539
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1a39133
7e19a85
8b86866
ef5513c
 
 
 
 
1a39133
ef5513c
 
 
 
 
 
b4899ca
ef5513c
 
 
1a39133
ef5513c
 
 
b4899ca
ef5513c
7e19a85
 
b4899ca
7e19a85
 
669277f
7e19a85
ef5513c
 
1a39133
7e19a85
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b4899ca
7e19a85
8b86866
ef5513c
 
 
 
7e19a85
ef5513c
7e19a85
 
 
 
 
b4899ca
 
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
<script lang="ts">
	import { fetchEventSource } from '@microsoft/fetch-event-source';
	const ENDPOINT = 'https://joi-20b.ngrok.io/generate_stream';

	type Message =
		| {
				from: 'user';
				content: string;
		  }
		| {
				from: 'bot';
				content: string;
		  };

	let messages: Message[] = [];
	let message = '';

	function onWrite() {
		messages = [...messages, { from: 'user', content: message }];
		message = '';
		let incoming = '';
		const inputs =
			messages
				.map((m) => (m.from === 'user' ? `User: ${m.content}\n` : `Joi:${m.content}\n`))
				.join('\n') + '\nJoi:';

		fetchEventSource(ENDPOINT, {
			method: 'POST',
			headers: {
				Accept: 'text/event-stream',
				'Content-Type': 'application/json'
			},
			body: JSON.stringify({
				inputs: inputs,
				parameters: {
					temperature: 0.5,
					top_p: 0.95,
					do_sample: true,
					max_new_tokens: 512,
					top_k: 4,
					repetition_penalty: 1.03,
					stop: ['User:']
				}
			}),
			async onopen(response) {
				if (response.ok && response.headers.get('content-type') === 'text/event-stream') {
					messages = [...messages, { from: 'bot', content: incoming }];
				} else {
					console.error('error opening the SSE endpoint');
				}
			},
			onmessage(msg) {
				const data = JSON.parse(msg.data);
				// console.log(data);
				messages.at(-1)!.content += data.token.text;
				messages = messages;
			}
		});
	}
</script>

<div class="grid h-screen w-screen md:grid-cols-[280px,1fr] overflow-hidden text-smd">
	<nav
		class="max-md:hidden bg-gradient-to-l from-gray-800/10 grid grid-rows-[auto,1fr,auto] grid-cols-1 max-h-screen"
	>
		<div class="flex-none sticky top-0 relative p-3 flex flex-col bg-black">
			<button class="border px-12 py-2.5 rounded-lg bg-gray-800/20 border border-gray-800/50 shadow"
				>New Chat</button
			>
		</div>
		<div class="flex flex-col overflow-y-auto p-3 -mt-3 gap-2">
			{#each Array(4) as _}
				<a
					href=""
					class="truncate text-gray-400 hover:bg-gray-800/50 py-3 px-3 rounded-lg flex-none"
				>
					sit amet consectetur adipisicing elit. Eos dolorum nihil alias.
				</a>
			{/each}
		</div>
		<div class="flex flex-col p-3 gap-2">
			<a href="" class="truncate text-gray-400 hover:bg-gray-800/50 py-3 px-3 rounded-lg mt-auto">
				Appearance
			</a>
			<a href="" class="truncate text-gray-400 hover:bg-gray-800/50 py-3 px-3 rounded-lg">
				Settings
			</a>
		</div>
	</nav>
	<div class="overflow-y-auto">
		<div class="max-w-4xl mx-auto px-5 pt-6 flex flex-col gap-8">
			{#each messages as { from, content }}
				{#if from === 'bot'}
					<div class="flex items-start justify-start gap-4 leading-relaxed">
						<img
							src="https://huggingface.co/avatars/2edb18bd0206c16b433841a47f53fa8e.svg"
							class="mt-5 w-3 h-3 flex-none rounded-full shadow-lg shadow-white/40"
						/>
						<div
							class="group relative rounded-2xl bg-gradient-to-br from-gray-800/50 to-gray-800/20 px-5 py-3.5"
						>
							{content}
						</div>
					</div>
				{/if}
				{#if from === 'user'}
					<div class="flex items-start justify-start gap-4 text-gray-300/80">
						<div class="mt-5 w-3 h-3 flex-none rounded-full" />
						<div class="rounded-2xl px-5 py-3.5">
							{content}
						</div>
					</div>
				{/if}
			{/each}
			<div class="h-32" />
		</div>
	</div>
	<div
		class="flex items-center justify-center absolute left-0 md:left-[280px] right-0 px-8 md:px-24 bottom-0 h-32 bg-gradient-to-t from-gray-900/50 to-black/0"
	>
		<form
			on:submit={onWrite}
			class="shadow-alternate relative flex items-center rounded-xl border border-gray-900 bg-black shadow-xl flex-1 max-w-4xl mx-4"
		>
			<svg
				class="absolute left-3 text-gray-300 top-1/2 transform -translate-y-1/2 pointer-events-none"
				xmlns="http://www.w3.org/2000/svg"
				xmlns:xlink="http://www.w3.org/1999/xlink"
				aria-hidden="true"
				focusable="false"
				role="img"
				width="1em"
				height="1em"
				preserveAspectRatio="xMidYMid meet"
				viewBox="0 0 32 32"
				><path
					d="M30 28.59L22.45 21A11 11 0 1 0 21 22.45L28.59 30zM5 14a9 9 0 1 1 9 9a9 9 0 0 1-9-9z"
					fill="currentColor"
				/></svg
			>
			<input
				class="flex-1 border-none bg-transparent px-1 py-3 pr-3 pl-10 outline-none placeholder:text-gray-400"
				bind:value={message}
				on:submit={onWrite}
				placeholder="Ask anything"
				autofocus
			/>
		</form>
		<!-- <input
			type="text"
			placeholder="Type anything..."
			class="w-full rounded-2xl border border-black bg-black px-4 py-3.5 shadow-2xl shadow-white/5 outline-none ring-gray-700 focus:ring-1 max-w-4xl"
		/> -->
	</div>
</div>