victor HF Staff commited on
Commit
4228faa
·
unverified ·
1 Parent(s): a32010b

Some UI tweaks (#93)

Browse files

* **Styling:**
* The bottom action bar in
[`src/lib/components/inference-playground/playground.svelte`](src/lib/components/inference-playground/playground.svelte:122)
and its buttons were made more compact.

* **User Experience:**
* A welcome message is now displayed for new conversations in
[`src/lib/components/inference-playground/conversation.svelte`](src/lib/components/inference-playground/conversation.svelte:59).
* The validation preventing consecutive user messages was removed in
[`src/lib/components/inference-playground/message-textarea.svelte`](src/lib/components/inference-playground/message-textarea.svelte:24),
allowing for a more natural conversation flow.

* **State Management:**
* In
[`src/lib/state/conversations.svelte.ts`](src/lib/state/conversations.svelte.ts:81),
new conversations are now initialized with an empty message list, and so
when you send the first message it's not spawning a 2nd user message.

src/app.css CHANGED
@@ -64,19 +64,19 @@
64
  }
65
 
66
  @utility btn {
67
- @apply flex h-[39px] items-center justify-center gap-2 rounded-lg border border-gray-200 bg-white px-3 py-2.5 text-sm font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:ring-4 focus:ring-gray-100 focus:outline-hidden 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;
68
  }
69
 
70
  @utility btn-sm {
71
- @apply flex h-[32px] items-center justify-center gap-1.5 rounded-md border border-gray-200 bg-white px-2.5 py-2 text-xs font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:ring-4 focus:ring-gray-100 focus:outline-hidden 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;
72
  }
73
 
74
  @utility btn-xs {
75
- @apply flex h-[28px] items-center justify-center gap-1 rounded border border-gray-200 bg-white px-2 py-1.5 text-xs font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:ring-4 focus:ring-gray-100 focus:outline-hidden 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;
76
  }
77
 
78
  @utility btn-mini {
79
- @apply flex h-[24px] items-center justify-center gap-0.5 rounded-sm border border-gray-200 bg-white px-1.5 py-1 text-[10px] font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:ring-2 focus:ring-gray-100 focus:outline-hidden 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;
80
  }
81
 
82
  @utility custom-outline {
 
64
  }
65
 
66
  @utility btn {
67
+ @apply flex h-[39px] items-center justify-center gap-2 rounded-lg border border-gray-200 bg-white px-3 py-2.5 text-sm font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:ring-4 focus:ring-gray-100 focus:outline-hidden dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-white dark:focus:ring-gray-700;
68
  }
69
 
70
  @utility btn-sm {
71
+ @apply flex h-[32px] items-center justify-center gap-1.5 rounded-md border border-gray-200 bg-white px-2.5 py-2 text-xs font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:ring-4 focus:ring-gray-100 focus:outline-hidden dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-white dark:focus:ring-gray-700;
72
  }
73
 
74
  @utility btn-xs {
75
+ @apply flex h-[28px] items-center justify-center gap-1 rounded border border-gray-200 bg-white px-2 py-1.5 text-xs font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:ring-4 focus:ring-gray-100 focus:outline-hidden dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-white dark:focus:ring-gray-700;
76
  }
77
 
78
  @utility btn-mini {
79
+ @apply flex h-[24px] items-center justify-center gap-0.5 rounded-sm border border-gray-200 bg-white px-1.5 py-1 text-[10px] font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:ring-2 focus:ring-gray-100 focus:outline-hidden dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-white dark:focus:ring-gray-700;
80
  }
81
 
82
  @utility custom-outline {
src/lib/components/inference-playground/conversation.svelte CHANGED
@@ -57,15 +57,22 @@
57
  bind:this={messageContainer}
58
  >
59
  {#if !viewCode}
60
- {#each conversation.data.messages || [] as message, index}
61
- <Message
62
- {message}
63
- {index}
64
- {conversation}
65
- onDelete={() => conversation.deleteMessage(index)}
66
- onRegen={() => regenMessage(index)}
67
- />
68
- {/each}
 
 
 
 
 
 
 
69
  {:else}
70
  <CodeSnippets {conversation} {onCloseCode} />
71
  {/if}
 
57
  bind:this={messageContainer}
58
  >
59
  {#if !viewCode}
60
+ {#if conversation.data.messages?.length}
61
+ {#each conversation.data.messages as message, index}
62
+ <Message
63
+ {message}
64
+ {index}
65
+ {conversation}
66
+ onDelete={() => conversation.deleteMessage(index)}
67
+ onRegen={() => regenMessage(index)}
68
+ />
69
+ {:else}
70
+ <div class="m-auto flex flex-col items-center gap-2 text-center px-4 text-balance">
71
+ <h1 class="text-2xl font-semibold">Welcome to Hugging Face Inference Playground</h1>
72
+ <p class="text-lg text-gray-500">Try hundreds of models on different providers</p>
73
+ </div>
74
+ {/each}
75
+ {/if}
76
  {:else}
77
  <CodeSnippets {conversation} {onCloseCode} />
78
  {/if}
src/lib/components/inference-playground/message-textarea.svelte CHANGED
@@ -21,20 +21,9 @@
21
 
22
  async function sendMessage() {
23
  const c = conversations.active;
24
- const isValid = c.every(c => c.data.messages?.at(-1)?.role !== "user");
25
-
26
- if (!isValid) {
27
- addToast({
28
- title: "Cannot add message",
29
- description: "Cannot have multiple user messages in a row",
30
-
31
- variant: "error",
32
- });
33
- } else {
34
- await Promise.all(c.map(c => c.addMessage({ role: "user", content: input })));
35
- c.forEach(c => c.genNextMessage());
36
- input = "";
37
- }
38
  }
39
 
40
  const autosized = new TextareaAutosize();
@@ -42,9 +31,9 @@
42
 
43
  <svelte:window onkeydown={onKeydown} />
44
 
45
- <div class="mt-auto p-2">
46
  <label
47
- class="flex w-full items-end rounded-[32px] bg-gray-200 p-2 pl-8 outline-offset-2 outline-blue-500 focus-within:outline-2 dark:bg-gray-800"
48
  >
49
  <textarea
50
  placeholder="Enter your message"
 
21
 
22
  async function sendMessage() {
23
  const c = conversations.active;
24
+ await Promise.all(c.map(c => c.addMessage({ role: "user", content: input })));
25
+ c.forEach(c => c.genNextMessage());
26
+ input = "";
 
 
 
 
 
 
 
 
 
 
 
27
  }
28
 
29
  const autosized = new TextareaAutosize();
 
31
 
32
  <svelte:window onkeydown={onKeydown} />
33
 
34
+ <div class="mt-auto px-2">
35
  <label
36
+ class="flex w-full items-end rounded-[32px] bg-gray-200 p-2 pl-6 outline-gray-500 focus-within:outline-2 dark:bg-gray-800"
37
  >
38
  <textarea
39
  placeholder="Enter your message"
src/lib/components/inference-playground/playground.svelte CHANGED
@@ -119,18 +119,16 @@
119
 
120
  <!-- Bottom bar -->
121
  <div
122
- class="relative mt-auto flex h-20 shrink-0 items-center justify-center gap-2 overflow-hidden border-t border-gray-200 px-3 whitespace-nowrap dark:border-gray-800"
123
  >
124
  <div class="flex flex-1 justify-start gap-x-2">
125
  {#if !compareActive}
126
  <button
127
  type="button"
128
  onclick={() => (viewSettings = !viewSettings)}
129
- class="flex h-[39px] items-center gap-1 rounded-lg border border-gray-200 bg-white px-3 py-2.5 text-sm font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 focus:outline-hidden md:hidden 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"
130
  >
131
- <div class="text-black dark:text-white">
132
- <IconSettings />
133
- </div>
134
  {!viewSettings ? "Settings" : "Hide"}
135
  </button>
136
  {/if}
@@ -139,7 +137,7 @@
139
  <button
140
  type="button"
141
  onclick={conversations.reset}
142
- class="btn size-[39px]"
143
  {...tooltip.trigger}
144
  data-test-id={TEST_IDS.reset}
145
  >
@@ -170,7 +168,7 @@
170
  <button
171
  type="button"
172
  onclick={() => (viewCode = !viewCode)}
173
- class="btn"
174
  {@attach observe({ name: ObservedElements.BottomActions, useRaf: true })}
175
  >
176
  <IconCode />
 
119
 
120
  <!-- Bottom bar -->
121
  <div
122
+ class="relative mt-auto flex h-14 shrink-0 items-center justify-center gap-2 overflow-hidden px-3 whitespace-nowrap"
123
  >
124
  <div class="flex flex-1 justify-start gap-x-2">
125
  {#if !compareActive}
126
  <button
127
  type="button"
128
  onclick={() => (viewSettings = !viewSettings)}
129
+ class="flex h-[28px]! px-2 items-center gap-1 rounded-lg border border-gray-200 bg-white py-2.5 text-sm font-medium text-gray-900 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 focus:outline-hidden md:hidden dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700"
130
  >
131
+ <IconSettings />
 
 
132
  {!viewSettings ? "Settings" : "Hide"}
133
  </button>
134
  {/if}
 
137
  <button
138
  type="button"
139
  onclick={conversations.reset}
140
+ class="btn size-[28px]! p-0!"
141
  {...tooltip.trigger}
142
  data-test-id={TEST_IDS.reset}
143
  >
 
168
  <button
169
  type="button"
170
  onclick={() => (viewCode = !viewCode)}
171
+ class="btn h-[28px]! px-2!"
172
  {@attach observe({ name: ObservedElements.BottomActions, useRaf: true })}
173
  >
174
  <IconCode />
src/lib/state/conversations.svelte.ts CHANGED
@@ -57,8 +57,6 @@ export type ConversationEntityMembers = MembersOnly<ConversationEntity>;
57
 
58
  const conversationsRepo = repo(ConversationEntity, idb);
59
 
60
- const startMessageUser: ConversationMessage = { role: "user", content: "" };
61
-
62
  export const emptyModel: Model = {
63
  _id: "",
64
  inferenceProviderMapping: [],
@@ -78,7 +76,7 @@ function getDefaultConversation(projectId: string) {
78
  projectId,
79
  modelId: models.trending[0]?.id ?? models.remote[0]?.id ?? emptyModel.id,
80
  config: { ...defaultGenerationConfig },
81
- messages: [{ ...startMessageUser }],
82
  streaming: true,
83
  createdAt: new Date(),
84
  } satisfies Partial<ConversationEntityMembers>;
 
57
 
58
  const conversationsRepo = repo(ConversationEntity, idb);
59
 
 
 
60
  export const emptyModel: Model = {
61
  _id: "",
62
  inferenceProviderMapping: [],
 
76
  projectId,
77
  modelId: models.trending[0]?.id ?? models.remote[0]?.id ?? emptyModel.id,
78
  config: { ...defaultGenerationConfig },
79
+ messages: [],
80
  streaming: true,
81
  createdAt: new Date(),
82
  } satisfies Partial<ConversationEntityMembers>;