Lite: Chatbot (#6897)

* Make Chatbot Wasm-compatible

* Make UploadButton Wasm-compatible

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
Co-authored-by: Ali Abdalla <ali.si3luwa@gmail.com>
This commit is contained in:
Yuichiro Tachibana (Tsuchiya) 2024-01-02 16:41:10 +09:00 committed by GitHub
parent 649cd4d680
commit fb9c6cacd7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 98 additions and 14 deletions

View File

@ -0,0 +1,10 @@
---
"@gradio/audio": minor
"@gradio/chatbot": minor
"@gradio/image": minor
"@gradio/uploadbutton": minor
"@gradio/video": minor
"gradio": minor
---
feat:Lite: Chatbot

View File

@ -27,6 +27,7 @@
"exports": {
".": "./index.ts",
"./example": "./Example.svelte",
"./shared": "./shared/index.ts",
"./package.json": "./package.json"
}
}

View File

@ -0,0 +1,45 @@
<script lang="ts">
import type { HTMLAudioAttributes } from "svelte/elements";
import { createEventDispatcher } from "svelte";
interface Props extends HTMLAudioAttributes {
"data-testid"?: string;
}
type $$Props = Props;
import { resolve_wasm_src } from "@gradio/wasm/svelte";
export let src: HTMLAudioAttributes["src"] = undefined;
let resolved_src: typeof src;
// The `src` prop can be updated before the Promise from `resolve_wasm_src` is resolved.
// In such a case, the resolved value for the old `src` has to be discarded,
// This variable `latest_src` is used to pick up only the value resolved for the latest `src` prop.
let latest_src: typeof src;
$: {
// In normal (non-Wasm) Gradio, the `<audio>` element should be rendered with the passed `src` props immediately
// without waiting for `resolve_wasm_src()` to resolve.
// If it waits, a black image is displayed until the async task finishes
// and it leads to undesirable flickering.
// So set `src` to `resolved_src` here.
resolved_src = src;
latest_src = src;
const resolving_src = src;
resolve_wasm_src(resolving_src).then((s) => {
if (latest_src === resolving_src) {
resolved_src = s;
}
});
}
const dispatch = createEventDispatcher();
</script>
<audio
src={resolved_src}
{...$$restProps}
on:play={dispatch.bind(null, "play")}
on:pause={dispatch.bind(null, "pause")}
on:ended={dispatch.bind(null, "ended")}
/>

1
js/audio/shared/index.ts Normal file
View File

@ -0,0 +1 @@
export { default as Audio } from "./Audio.svelte";

View File

@ -8,13 +8,16 @@
"private": false,
"dependencies": {
"@gradio/atoms": "workspace:^",
"@gradio/audio": "workspace:^",
"@gradio/client": "workspace:^",
"@gradio/icons": "workspace:^",
"@gradio/image": "workspace:^",
"@gradio/markdown": "workspace:^",
"@gradio/statustracker": "workspace:^",
"@gradio/theme": "workspace:^",
"@gradio/upload": "workspace:^",
"@gradio/utils": "workspace:^",
"@gradio/video": "workspace:^",
"@types/dompurify": "^3.0.2",
"@types/katex": "^0.16.0",
"@types/prismjs": "1.26.3",

View File

@ -5,6 +5,9 @@
import { dequal } from "dequal/lite";
import { beforeUpdate, afterUpdate, createEventDispatcher } from "svelte";
import { ShareButton } from "@gradio/atoms";
import { Audio } from "@gradio/audio/shared";
import { Image } from "@gradio/image/shared";
import { Video } from "@gradio/video/shared";
import type { SelectData, LikeData } from "@gradio/utils";
import { MarkdownCode as Markdown } from "@gradio/markdown";
import { get_fetchable_url_or_file, type FileData } from "@gradio/client";
@ -135,7 +138,7 @@
<div class="message-row {layout} {j == 0 ? 'user-row' : 'bot-row'}">
{#if avatar_images[j] !== null}
<div class="avatar-container">
<img
<Image
class="avatar-image"
src={get_fetchable_url_or_file(
avatar_images[j],
@ -183,7 +186,7 @@
on:load={scroll}
/>
{:else if message !== null && message.file?.mime_type?.includes("audio")}
<audio
<Audio
data-testid="chatbot-audio"
controls
preload="metadata"
@ -194,7 +197,7 @@
on:ended
/>
{:else if message !== null && message.file?.mime_type?.includes("video")}
<video
<Video
data-testid="chatbot-video"
controls
src={message.file?.url}
@ -205,9 +208,9 @@
on:ended
>
<track kind="captions" />
</video>
</Video>
{:else if message !== null && message.file?.mime_type?.includes("image")}
<img
<Image
data-testid="chatbot-image"
src={message.file?.url}
alt={message.alt_text}
@ -407,7 +410,8 @@
margin-left: 25px;
align-self: center;
}
img.avatar-image {
.avatar-container :global(img) {
width: 100%;
height: 100%;
object-fit: cover;

View File

@ -23,6 +23,7 @@
"exports": {
".": "./Index.svelte",
"./example": "./Example.svelte",
"./shared": "./shared/index.ts",
"./package.json": "./package.json"
}
}

View File

@ -1,6 +1,9 @@
<script lang="ts">
import type { HTMLImgAttributes } from "svelte/elements";
type $$Props = HTMLImgAttributes;
interface Props extends HTMLImgAttributes {
"data-testid"?: string;
}
type $$Props = Props;
import { resolve_wasm_src } from "@gradio/wasm/svelte";

1
js/image/shared/index.ts Normal file
View File

@ -0,0 +1 @@
export { default as Image } from "./Image.svelte";

View File

@ -1,11 +1,12 @@
<script lang="ts">
import { tick, createEventDispatcher } from "svelte";
import { tick, createEventDispatcher, getContext } from "svelte";
import { BaseButton } from "@gradio/button";
import {
upload,
prepare_files,
type FileData,
get_fetchable_url_or_file
get_fetchable_url_or_file,
type upload_files
} from "@gradio/client";
export let elem_id = "";
@ -27,6 +28,9 @@
const dispatch = createEventDispatcher();
// Needed for wasm support
const upload_fn = getContext<typeof upload_files>("upload_files");
let hidden_upload: HTMLInputElement;
let accept_file_types: string | null;
@ -58,9 +62,9 @@
let all_file_data = await prepare_files(_files);
await tick();
all_file_data = (await upload(all_file_data, root))?.filter(
(x) => x !== null
) as FileData[];
all_file_data = (
await upload(all_file_data, root, undefined, upload_fn)
)?.filter((x) => x !== null) as FileData[];
value = file_count === "single" ? all_file_data?.[0] : all_file_data;
dispatch("change", value);
dispatch("upload", value);

View File

@ -24,6 +24,7 @@
"exports": {
".": "./index.ts",
"./example": "./Example.svelte",
"./shared": "./shared/index.ts",
"./package.json": "./package.json"
},
"main": "index.ts",

View File

@ -21,8 +21,6 @@
export let processingVideo = false;
const dispatch = createEventDispatcher();
let resolved_src: typeof src;
// The `src` prop can be updated before the Promise from `resolve_wasm_src` is resolved.
@ -45,6 +43,8 @@
}
});
}
const dispatch = createEventDispatcher();
</script>
<!--

1
js/video/shared/index.ts Normal file
View File

@ -0,0 +1 @@
export { default as Video } from "./Video.svelte";

View File

@ -600,12 +600,18 @@ importers:
'@gradio/atoms':
specifier: workspace:^
version: link:../atoms
'@gradio/audio':
specifier: workspace:^
version: link:../audio
'@gradio/client':
specifier: workspace:^
version: link:../../client/js
'@gradio/icons':
specifier: workspace:^
version: link:../icons
'@gradio/image':
specifier: workspace:^
version: link:../image
'@gradio/markdown':
specifier: workspace:^
version: link:../markdown
@ -621,6 +627,9 @@ importers:
'@gradio/utils':
specifier: workspace:^
version: link:../utils
'@gradio/video':
specifier: workspace:^
version: link:../video
'@types/dompurify':
specifier: ^3.0.2
version: 3.0.2