|
150 | 150 | ![documentParserToolId, imageGenToolId, webSearchToolId, fetchUrlToolId].includes(t._id)
|
151 | 151 | ) satisfies ToolFront[]
|
152 | 152 | );
|
| 153 | +
|
| 154 | + let showWebSearch = $derived(!assistant); |
| 155 | + let showImageGen = $derived(modelHasTools && !assistant); |
| 156 | + let showFileUpload = $derived((modelIsMultimodal || modelHasTools) && mimeTypes.length > 0); |
| 157 | + let showExtraTools = $derived(modelHasTools && !assistant); |
| 158 | +
|
| 159 | + let showNoTools = $derived(!showWebSearch && !showImageGen && !showFileUpload && !showExtraTools); |
| 160 | + |
153 | 161 | </script>
|
154 | 162 |
|
155 | 163 | <div class="flex min-h-full flex-1 flex-col" onpaste={onPaste}>
|
|
175 | 183 | {disabled}
|
176 | 184 | ></textarea>
|
177 | 185 |
|
178 |
| - {#if !assistant} |
179 |
| - <div |
180 |
| - class="scrollbar-custom -ml-0.5 flex max-w-[calc(100%-40px)] flex-wrap items-center justify-start gap-2.5 px-3 pb-2.5 pt-1.5 text-gray-500 dark:text-gray-400 max-md:flex-nowrap max-md:overflow-x-auto sm:gap-2" |
181 |
| - > |
| 186 | + {#if !showNoTools} |
| 187 | + <div |
| 188 | + class={[ |
| 189 | + "scrollbar-custom -ml-0.5 flex max-w-[calc(100%-40px)] flex-wrap items-center justify-start gap-2.5 px-3 pb-2.5 pt-1.5 text-gray-500 dark:text-gray-400 max-md:flex-nowrap max-md:overflow-x-auto sm:gap-2", |
| 190 | + ]} |
| 191 | + > |
| 192 | + {#if showWebSearch} |
182 | 193 | <HoverTooltip
|
183 | 194 | label="Search the web"
|
184 | 195 | position="top"
|
|
215 | 226 | {/if}
|
216 | 227 | </button>
|
217 | 228 | </HoverTooltip>
|
218 |
| - {#if modelHasTools} |
| 229 | + {/if} |
| 230 | + {#if showImageGen} |
| 231 | + <HoverTooltip |
| 232 | + label="Generate images" |
| 233 | + position="top" |
| 234 | + TooltipClassNames="text-xs !text-left !w-auto whitespace-nowrap !py-1 !mb-0 max-sm:hidden {imageGenIsOn |
| 235 | + ? 'hidden' |
| 236 | + : ''}" |
| 237 | + > |
| 238 | + <button |
| 239 | + class="base-tool" |
| 240 | + class:active-tool={imageGenIsOn} |
| 241 | + disabled={loading} |
| 242 | + onclick={async (e) => { |
| 243 | + e.preventDefault(); |
| 244 | + if (modelHasTools) { |
| 245 | + if (imageGenIsOn) { |
| 246 | + await settings.instantSet({ |
| 247 | + tools: ($settings.tools ?? []).filter((t) => t !== imageGenToolId), |
| 248 | + }); |
| 249 | + } else { |
| 250 | + await settings.instantSet({ |
| 251 | + tools: [...($settings.tools ?? []), imageGenToolId], |
| 252 | + }); |
| 253 | + } |
| 254 | + } |
| 255 | + }} |
| 256 | + > |
| 257 | + <IconImageGen classNames="text-xl" /> |
| 258 | + {#if imageGenIsOn} |
| 259 | + Image Gen |
| 260 | + {/if} |
| 261 | + </button> |
| 262 | + </HoverTooltip> |
| 263 | + {/if} |
| 264 | + {#if showFileUpload} |
| 265 | + {@const mimeTypesString = mimeTypes |
| 266 | + .map((m) => { |
| 267 | + // if the mime type ends in *, grab the first part so image/* becomes image |
| 268 | + if (m.endsWith("*")) { |
| 269 | + return m.split("/")[0]; |
| 270 | + } |
| 271 | + // otherwise, return the second part for example application/pdf becomes pdf |
| 272 | + return m.split("/")[1]; |
| 273 | + }) |
| 274 | + .join(", ")} |
| 275 | + <div class="flex items-center"> |
| 276 | + <HoverTooltip |
| 277 | + label={mimeTypesString.includes("*") |
| 278 | + ? "Upload any file" |
| 279 | + : `Upload ${mimeTypesString} files`} |
| 280 | + position="top" |
| 281 | + TooltipClassNames="text-xs !text-left !w-auto whitespace-nowrap !py-1 !mb-0 max-sm:hidden" |
| 282 | + > |
| 283 | + <label class="base-tool relative" class:active-tool={documentParserIsOn}> |
| 284 | + <input |
| 285 | + disabled={loading} |
| 286 | + class="absolute hidden size-0" |
| 287 | + aria-label="Upload file" |
| 288 | + type="file" |
| 289 | + onchange={onFileChange} |
| 290 | + accept={mimeTypes.join(",")} |
| 291 | + /> |
| 292 | + <IconPaperclip classNames="text-xl" /> |
| 293 | + {#if documentParserIsOn} |
| 294 | + Document Parser |
| 295 | + {/if} |
| 296 | + </label> |
| 297 | + </HoverTooltip> |
| 298 | + </div> |
| 299 | + {#if mimeTypes.includes("image/*")} |
219 | 300 | <HoverTooltip
|
220 |
| - label="Generate images" |
| 301 | + label="Capture screenshot" |
221 | 302 | position="top"
|
222 |
| - TooltipClassNames="text-xs !text-left !w-auto whitespace-nowrap !py-1 !mb-0 max-sm:hidden {imageGenIsOn |
223 |
| - ? 'hidden' |
224 |
| - : ''}" |
| 303 | + TooltipClassNames="text-xs !text-left !w-auto whitespace-nowrap !py-1 !mb-0 max-sm:hidden" |
225 | 304 | >
|
226 | 305 | <button
|
227 | 306 | class="base-tool"
|
228 |
| - class:active-tool={imageGenIsOn} |
229 |
| - disabled={loading} |
230 | 307 | onclick={async (e) => {
|
231 | 308 | e.preventDefault();
|
232 |
| - if (modelHasTools) { |
233 |
| - if (imageGenIsOn) { |
234 |
| - await settings.instantSet({ |
235 |
| - tools: ($settings.tools ?? []).filter((t) => t !== imageGenToolId), |
236 |
| - }); |
237 |
| - } else { |
238 |
| - await settings.instantSet({ |
239 |
| - tools: [...($settings.tools ?? []), imageGenToolId], |
240 |
| - }); |
241 |
| - } |
242 |
| - } |
243 |
| - }} |
244 |
| - > |
245 |
| - <IconImageGen classNames="text-xl" /> |
246 |
| - {#if imageGenIsOn} |
247 |
| - Image Gen |
248 |
| - {/if} |
249 |
| - </button> |
250 |
| - </HoverTooltip> |
251 |
| - {/if} |
252 |
| - {#if modelIsMultimodal || modelHasTools} |
253 |
| - {@const mimeTypesString = mimeTypes |
254 |
| - .map((m) => { |
255 |
| - // if the mime type ends in *, grab the first part so image/* becomes image |
256 |
| - if (m.endsWith("*")) { |
257 |
| - return m.split("/")[0]; |
258 |
| - } |
259 |
| - // otherwise, return the second part for example application/pdf becomes pdf |
260 |
| - return m.split("/")[1]; |
261 |
| - }) |
262 |
| - .join(", ")} |
263 |
| - <div class="flex items-center"> |
264 |
| - <HoverTooltip |
265 |
| - label={mimeTypesString.includes("*") |
266 |
| - ? "Upload any file" |
267 |
| - : `Upload ${mimeTypesString} files`} |
268 |
| - position="top" |
269 |
| - TooltipClassNames="text-xs !text-left !w-auto whitespace-nowrap !py-1 !mb-0 max-sm:hidden" |
270 |
| - > |
271 |
| - <label class="base-tool relative" class:active-tool={documentParserIsOn}> |
272 |
| - <input |
273 |
| - disabled={loading} |
274 |
| - class="absolute hidden size-0" |
275 |
| - aria-label="Upload file" |
276 |
| - type="file" |
277 |
| - onchange={onFileChange} |
278 |
| - accept={mimeTypes.join(",")} |
279 |
| - /> |
280 |
| - <IconPaperclip classNames="text-xl" /> |
281 |
| - {#if documentParserIsOn} |
282 |
| - Document Parser |
283 |
| - {/if} |
284 |
| - </label> |
285 |
| - </HoverTooltip> |
286 |
| - </div> |
287 |
| - {#if mimeTypes.includes("image/*")} |
288 |
| - <HoverTooltip |
289 |
| - label="Capture screenshot" |
290 |
| - position="top" |
291 |
| - TooltipClassNames="text-xs !text-left !w-auto whitespace-nowrap !py-1 !mb-0 max-sm:hidden" |
292 |
| - > |
293 |
| - <button |
294 |
| - class="base-tool" |
295 |
| - onclick={async (e) => { |
296 |
| - e.preventDefault(); |
297 |
| - const screenshot = await captureScreen(); |
| 309 | + const screenshot = await captureScreen(); |
298 | 310 |
|
299 |
| - // Convert base64 to blob |
300 |
| - const base64Response = await fetch(screenshot); |
301 |
| - const blob = await base64Response.blob(); |
| 311 | + // Convert base64 to blob |
| 312 | + const base64Response = await fetch(screenshot); |
| 313 | + const blob = await base64Response.blob(); |
302 | 314 |
|
303 |
| - // Create a File object from the blob |
304 |
| - const file = new File([blob], "screenshot.png", { type: "image/png" }); |
| 315 | + // Create a File object from the blob |
| 316 | + const file = new File([blob], "screenshot.png", { type: "image/png" }); |
305 | 317 |
|
306 |
| - files = [...files, file]; |
307 |
| - }} |
308 |
| - > |
309 |
| - <IconScreenshot classNames="text-xl" /> |
310 |
| - </button> |
311 |
| - </HoverTooltip> |
312 |
| - {/if} |
313 |
| - {/if} |
314 |
| - {#if modelHasTools} |
315 |
| - {#each extraTools as tool} |
316 |
| - <button |
317 |
| - class="active-tool base-tool" |
318 |
| - disabled={loading} |
319 |
| - onclick={async (e) => { |
320 |
| - e.preventDefault(); |
321 |
| - goto(`${base}/tools/${tool._id}`); |
| 318 | + files = [...files, file]; |
322 | 319 | }}
|
323 | 320 | >
|
324 |
| - {#key tool.icon + tool.color} |
325 |
| - <ToolLogo icon={tool.icon} color={tool.color} size="xs" /> |
326 |
| - {/key} |
327 |
| - {tool.displayName} |
| 321 | + <IconScreenshot classNames="text-xl" /> |
328 | 322 | </button>
|
329 |
| - {/each} |
330 |
| - {/if} |
331 |
| - {#if modelHasTools} |
332 |
| - <HoverTooltip |
333 |
| - label="Browse more tools" |
334 |
| - position="right" |
335 |
| - TooltipClassNames="text-xs !text-left !w-auto whitespace-nowrap !py-1 max-sm:hidden" |
336 |
| - > |
337 |
| - <a |
338 |
| - class="base-tool flex !size-[20px] items-center justify-center rounded-full border !border-gray-200 !bg-white !transition-none dark:!border-gray-500 dark:!bg-transparent" |
339 |
| - href={`${base}/tools`} |
340 |
| - title="Browse more tools" |
341 |
| - > |
342 |
| - <IconAdd class="text-sm" /> |
343 |
| - </a> |
344 | 323 | </HoverTooltip>
|
345 | 324 | {/if}
|
346 |
| - </div> |
| 325 | + {/if} |
| 326 | + {#if showExtraTools} |
| 327 | + {#each extraTools as tool} |
| 328 | + <button |
| 329 | + class="active-tool base-tool" |
| 330 | + disabled={loading} |
| 331 | + onclick={async (e) => { |
| 332 | + e.preventDefault(); |
| 333 | + goto(`${base}/tools/${tool._id}`); |
| 334 | + }} |
| 335 | + > |
| 336 | + {#key tool.icon + tool.color} |
| 337 | + <ToolLogo icon={tool.icon} color={tool.color} size="xs" /> |
| 338 | + {/key} |
| 339 | + {tool.displayName} |
| 340 | + </button> |
| 341 | + {/each} |
| 342 | + <HoverTooltip |
| 343 | + label="Browse more tools" |
| 344 | + position="right" |
| 345 | + TooltipClassNames="text-xs !text-left !w-auto whitespace-nowrap !py-1 max-sm:hidden" |
| 346 | + > |
| 347 | + <a |
| 348 | + class="base-tool flex !size-[20px] items-center justify-center rounded-full border !border-gray-200 !bg-white !transition-none dark:!border-gray-500 dark:!bg-transparent" |
| 349 | + href={`${base}/tools`} |
| 350 | + title="Browse more tools" |
| 351 | + > |
| 352 | + <IconAdd class="text-sm" /> |
| 353 | + </a> |
| 354 | + </HoverTooltip> |
| 355 | + {/if} |
| 356 | + </div> |
347 | 357 | {/if}
|
348 | 358 | {@render children?.()}
|
349 | 359 | </div>
|
|
0 commit comments