Merge branch 'gradio-dash-fe' of https://github.com/gradio-app/gradio into gradio-dash-fe

This commit is contained in:
Ömer Faruk Özdemir 2022-03-17 10:47:47 +03:00
commit 26cdff3d84
28 changed files with 126 additions and 190 deletions

View File

@ -7,94 +7,6 @@
import { tick } from "svelte";
setupi18n();
// const json = {
// mode: "blocks",
// components: [
// {
// id: 1,
// type: "markdown",
// props: {
// label:
// "\n\t# Detect Disease From Scan\n\tWith this model you can lorem ipsum\n\t- ipsum 1\n\t- ipsum 2\n\t"
// }
// },
// {
// id: 2,
// type: "checkboxgroup",
// props: {
// choices: ["Covid", "Malaria", "Lung Cancer"],
// default: [],
// label: "Disease to Scan For"
// }
// },
// { id: 3, type: "tabs" },
// { id: 4, type: "tabitem", props: { label: "X-ray" } },
// { id: 5, type: "row" },
// {
// id: 6,
// type: "image",
// props: {
// image_mode: "RGB",
// shape: null,
// source: "upload",
// tool: "editor",
// optional: false,
// label: null
// }
// },
// { id: 7, type: "json" },
// { id: 8, type: "button", props: { label: "Run" } },
// { id: 9, type: "tabitem", props: { label: "CT Scan" } },
// { id: 10, type: "row" },
// {
// id: 11,
// type: "image",
// props: {
// image_mode: "RGB",
// shape: null,
// source: "upload",
// tool: "editor",
// optional: false,
// label: null
// }
// },
// { id: 12, type: "json", props: { label: null } },
// { id: 13, type: "button", props: { label: "Run" } },
// { id: 14, type: "textbox", props: { label: null } }
// ],
// theme: "default",
// layout: {
// children: [
// { id: 1 },
// { id: 2 },
// {
// id: 3,
// children: [
// {
// id: 4,
// children: [{ id: 5, children: [{ id: 6 }, { id: 7 }] }, { id: 8 }]
// },
// {
// id: 9,
// children: [
// { id: 10, children: [{ id: 11 }, { id: 12 }] },
// { id: 13 }
// ]
// }
// ]
// },
// { id: 14 }
// ],
// type: "root"
// },
// dependencies: [
// { targets: [8], trigger: "click", inputs: [2, 6], outputs: [7] },
// { targets: [13], trigger: "click", inputs: [2, 11], outputs: [12] }
// ]
// };
interface Component {
id: string;
type: string;
@ -122,7 +34,6 @@
export let layout: Layout;
export let dependencies: Array<Dependency>;
export let theme: string;
export let static_src: string;
const dynamic_ids = dependencies.reduce((acc, next) => {
next.inputs.forEach((i) => acc.add(i));
@ -148,7 +59,7 @@
function load_component<T extends keyof typeof component_map>(
name: T
): Promise<{ name: T; component: SvelteComponentDev }> {
): Promise<{ name: T; component: SvelteComponentTyped }> {
return new Promise(async (res, rej) => {
try {
const c = await component_map[name]();
@ -190,53 +101,14 @@
let tree;
Promise.all(Array.from(component_set)).then((v) => {
Promise.all(layout.children.map((c) => walk_layout(c))).then((v) => {
// console.log(v);
console.log(v);
tree = v;
});
});
// let values: Record<string, unknown> = {};
// let component_id_map: Record<string, Component> = {};
// let event_listener_map: Record<string, Array<number>> = {};
// for (let component of components) {
// component_id_map[component.id] = component;
// if (component.props && "default" in component.props) {
// values[component.id] = component.props.default;
// } else {
// values[component.id] = null;
// }
// event_listener_map[component.id] = [];
// }
// dependencies.forEach((dependency, i) => {
// if (dependency.trigger === "click") {
// for (let target of dependency.targets) {
// event_listener_map[target].push(i);
// }
// }
// });
// const setValues = (i: string, value: unknown) => {
// values[i] = value;
// };
// const triggerTarget = (i: string) => {
// event_listener_map[i].forEach((fn_index: number) => {
// let dependency = dependencies[fn_index];
// fn("predict", {
// fn_index: fn_index,
// data: dependency.inputs.map((i) => values[i])
// }).then((output) => {
// output["data"].forEach((value, i) => {
// values[dependency.outputs[i]] = value;
// });
// });
// });
// };
let handled_dependencies: Array<number[]> = [];
async function handle_mount({ detail }) {
console.log("mount", detail);
// console.log("boo");
await tick();
dependencies.forEach(({ targets, trigger, inputs, outputs }, i) => {
const target_instances: [number, Instance][] = targets.map((t) => [
@ -254,7 +126,6 @@
fn_index: i,
data: inputs.map((id) => instance_map[id].value)
}).then((output) => {
console.log(output);
output.data.forEach((value, i) => {
instance_map[outputs[i]].value = value;
});
@ -268,14 +139,6 @@
}
function handle_destroy(id: number) {
console.log("destroy", id);
// console.log(
// id,
// handled_dependencies,
// handled_dependencies.map((dep) => {
// return dep.filter((_id) => _id !== id);
// })
// );
handled_dependencies = handled_dependencies.map((dep) => {
return dep.filter((_id) => _id !== id);
});
@ -295,7 +158,7 @@
{props}
{children}
{instance_map}
theme={theme}
{theme}
on:mount={handle_mount}
on:destroy={({ detail }) => handle_destroy(detail)}
/>

View File

@ -7,15 +7,21 @@
export let theme: string;
export let name: string;
export let source: "microphone" | "upload";
export let type: "normal" | "numpy" = "normal";
</script>
{#if mode === "static"}
{#if mode === "dynamic"}
<Audio
{value}
{theme}
{name}
{source}
{type}
on:change={({ detail }) => (value = detail)}
on:edit
on:play
on:pause
on:ended
/>
{:else if value}
<audio {theme} controls>

View File

@ -4,6 +4,6 @@
export let theme: string;
</script>
<Carousel {theme}>
<Carousel {theme} on:change>
<slot />
</Carousel>

View File

@ -3,4 +3,4 @@
export let value: Array<[string, string]>;
</script>
<ChatBot {value} />
<ChatBot {value} on:change />

View File

@ -7,8 +7,8 @@
export let mode: "static" | "dynamic";
</script>
{#if mode === "static"}
<FileUpload bind:value {theme} on:change />
{#if mode === "dynamic"}
<FileUpload bind:value {theme} on:change on:clear />
{:else if value}
<File {value} {theme} />
{/if}

View File

@ -1,7 +1,12 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
import { HTML } from "@gradio/html";
export let label: string;
export let theme: string;
const dispatch = createEventDispatcher<{ change: undefined }>();
$: label, dispatch("change");
</script>
<HTML value={label} {theme} />
<HTML value={label} {theme} on:change />

View File

@ -1,10 +1,15 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
import { HighlightedText } from "@gradio/highlighted-text";
export let value: Array<[string, string | number]>;
export let theme: string;
export let show_legend: boolean;
export let color_map: Record<string, string> = {};
const dispatch = createEventDispatcher<{ change: undefined }>();
$: value, dispatch("change");
</script>
<HighlightedText {value} {theme} {show_legend} {color_map} />

View File

@ -1,4 +1,5 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
import { Image } from "@gradio/image";
export let value: null | string = null;
@ -7,6 +8,10 @@
export let tool: "editor" | "select" = "editor";
export let mode: "static" | "dynamic";
const dispatch = createEventDispatcher<{ change: undefined }>();
$: value, dispatch("change");
</script>
{#if mode === "static"}
@ -18,5 +23,5 @@
<img class="w-full h-full object-contain" src={value} />
</div>
{:else}
<Image bind:value {theme} {source} {tool} on:change />
<Image bind:value {theme} {source} {tool} on:edit on:clear on:change />
{/if}

View File

@ -1,8 +1,13 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
import { JSON } from "@gradio/json";
export let value: any;
export let theme: string;
const dispatch = createEventDispatcher<{ change: undefined }>();
$: value, dispatch("change");
</script>
<JSON {theme} {value} />

View File

@ -1,4 +1,5 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
import { Label } from "@gradio/label";
export let value: {
@ -6,6 +7,10 @@
confidences?: Array<{ label: string; confidence: number }>;
};
export let theme: string;
const dispatch = createEventDispatcher<{ change: undefined }>();
$: value, dispatch("change");
</script>
<Label {theme} {value} />

View File

@ -5,4 +5,4 @@
export let mode: "static" | "dynamic";
</script>
<Number bind:value {theme} on:change disabled={mode === "static"} />
<Number bind:value {theme} disabled={mode === "static"} on:change on:submit />

View File

@ -17,7 +17,7 @@
{value}
</div>
{:else}
<TextBox bind:value {theme} {lines} {placeholder} on:change />
<TextBox bind:value {theme} {lines} {placeholder} on:change on:submit />
{/if}
<style lang="postcss" global>

View File

@ -1,4 +1,5 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
import { Upload } from "@gradio/upload";
import type { FileData } from "@gradio/upload";
import { Chart } from "@gradio/chart";
@ -10,6 +11,8 @@
);
}
const dispatch = createEventDispatcher<{ change: undefined }>();
interface StaticData {
data: Array<Array<number>>;
headers: Array<string>;
@ -94,6 +97,8 @@
$: _value = value == null ? null : _value;
$: static_data = is_static && format_value(value as StaticData);
$: value, dispatch("change");
</script>
{#if is_static && static_data}

View File

@ -44,5 +44,8 @@
or_text={$_("interface.or")}
upload_text={$_("interface.click_to_upload")}
on:change
on:clear
on:play
on:pause
/>
{/if}

View File

@ -1,9 +0,0 @@
import Component from "./Textbox.svelte";
import ExampleComponent from "./Example.svelte";
import Interpretation from "./Interpretation.svelte";
export default {
component: Component,
example: ExampleComponent,
interpretation: Interpretation
};

View File

@ -1,7 +0,0 @@
<script lang="ts">
export let label: string;
</script>
<button class="px-4 py-2 rounded bg-gray-100 hover:bg-gray-200 transition">
{label}
</button>

View File

@ -1,5 +0,0 @@
import Component from "./Button.svelte";
export default {
component: Component
};

View File

@ -1,5 +0,0 @@
<script lang="ts">
export let label: string;
</script>
<div>{@html label}</div>

View File

@ -1,5 +0,0 @@
import Component from "./Markdown.svelte";
export default {
component: Component
};

View File

@ -20,6 +20,9 @@
export let or_text: string = "or";
export let upload_text: string = "click to upload";
// TODO: make use of this
export let type: "normal" | "numpy" = "normal";
let recording = false;
let recorder: MediaRecorder;
let mode = "";
@ -31,6 +34,10 @@
const dispatch = createEventDispatcher<{
change: AudioData;
edit: AudioData;
play: undefined;
pause: undefined;
ended: undefined;
}>();
function blob_to_data_url(blob: Blob): Promise<string> {
@ -123,6 +130,8 @@
crop_min: values[0],
crop_max: values[1]
});
dispatch("edit");
}
function handle_load({
@ -176,6 +185,9 @@
bind:this={player}
preload="metadata"
src={value.data}
on:play
on:pause
on:ended
/>
{#if mode === "edit" && player?.duration}

View File

@ -3,11 +3,14 @@
</script>
<script lang="ts">
import { setContext } from "svelte";
import { setContext, createEventDispatcher } from "svelte";
import { writable } from "svelte/store";
export let theme: string = "default";
const dispatch = createEventDispatcher<{
change: undefined;
}>();
const items = writable<Array<number>>([]);
const current = writable<number>();
@ -33,10 +36,12 @@
const next = () => {
carousel_index = (carousel_index + 1) % $items.length;
dispatch("change");
};
const prev = () => {
carousel_index = (carousel_index - 1 + $items.length) % $items.length;
dispatch("change");
};
</script>

View File

@ -1,9 +1,11 @@
<script lang="ts">
import { beforeUpdate, afterUpdate } from "svelte";
import { beforeUpdate, afterUpdate, createEventDispatcher } from "svelte";
export let value: Array<[string, string]>;
let div: HTMLDivElement;
let autoscroll: Boolean;
const dispatch = createEventDispatcher<{ change: undefined }>();
beforeUpdate(() => {
autoscroll =
div && div.offsetHeight + div.scrollTop > div.scrollHeight - 20;
@ -12,6 +14,8 @@
afterUpdate(() => {
if (autoscroll) div.scrollTo(0, div.scrollHeight);
});
$: value && dispatch("change");
</script>
<div

View File

@ -10,6 +10,7 @@
export let drop_text: string = "Drop an audio file";
export let or_text: string = "or";
export let upload_text: string = "click to upload";
let file_count: string;
function handle_upload({ detail }: CustomEvent<FileData>) {
value = detail;
@ -17,9 +18,11 @@
function handle_clear({ detail }: CustomEvent<null>) {
value = null;
dispatch("clear");
}
const dispatch = createEventDispatcher<{ change: FileData | null }>();
const dispatch =
createEventDispatcher<{ change: FileData | null; clear: undefined }>();
$: dispatch("change", value);
</script>
@ -55,7 +58,7 @@
<div class="file-size text-2xl p-2">
{prettyBytes(value.size || 0)}
</div>
{#if file_count === "single" && "size" in value}
{#if file_count === "single" && value.size}
<div class="file-size text-2xl p-2">
{prettyBytes(value.size)}
</div>

View File

@ -6,13 +6,22 @@
export let theme: string = "default";
export let disabled: boolean = false;
const dispatch = createEventDispatcher<{ change: number }>();
const dispatch =
createEventDispatcher<{ change: number; submit: undefined }>();
function handle_change(n: number) {
dispatch("change", n);
}
function handle_keypress(e: KeyboardEvent) {
if (e.key === "Enter") {
e.preventDefault();
dispatch("submit");
}
}
const debounced_handle_change = debounce(handle_change, 500);
const debounced_handle_keypress = debounce(handle_keypress, 500);
$: debounced_handle_change(value);
</script>
@ -22,6 +31,7 @@
class="input-number w-full rounded box-border p-2 focus:outline-none appearance-none"
bind:value
{theme}
on:keypress={debounced_handle_keypress}
/>
<style lang="postcss" global>

View File

@ -7,7 +7,8 @@
export let lines: number = 1;
export let placeholder: string = "";
const dispatch = createEventDispatcher<{ change: string }>();
const dispatch =
createEventDispatcher<{ change: string; submit: undefined }>();
type CustomInputEvent =
| (Event & {
@ -21,7 +22,15 @@
dispatch("change", event?.target?.value);
}
function handle_keypress(e: KeyboardEvent) {
if (e.key === "Enter" && lines === 1) {
e.preventDefault();
dispatch("submit");
}
}
const debounced_handle_change = debounce(handle_change, 500);
const debounced_handle_keypress = debounce(handle_keypress, 500);
</script>
{#if lines > 1}
@ -40,6 +49,7 @@
{placeholder}
on:input={debounced_handle_change}
{theme}
on:keypress={debounced_handle_keypress}
/>
{/if}

View File

@ -1,6 +1,12 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
export let value: string;
export let theme: string = "default";
const dispatch = createEventDispatcher<{ change: undefined }>();
$: value, dispatch("change");
</script>
<div class="output-html" {theme}>

View File

@ -27,14 +27,20 @@
function handle_clear({ detail }: CustomEvent<null>) {
value = null;
dispatch("clear");
}
function handle_save({ detail }: { detail: string }) {
value = detail;
mode = "view";
dispatch("edit");
}
const dispatch = createEventDispatcher<{ change: string | null }>();
const dispatch = createEventDispatcher<{
change: string | null;
edit: undefined;
clear: undefined;
}>();
$: dispatch("change", value);
</script>

View File

@ -12,7 +12,13 @@
export let or_text: string = "or";
export let upload_text: string = "click to upload";
const dispatch = createEventDispatcher<{ change: FileData | null }>();
const dispatch = createEventDispatcher<{
change: FileData | null;
clear: undefined;
play: undefined;
pause: undefined;
ended: undefined;
}>();
function handle_load({ detail }: CustomEvent<FileData | null>) {
dispatch("change", detail);
@ -20,7 +26,7 @@
}
function handle_clear({ detail }: CustomEvent<FileData | null>) {
dispatch("change", null);
dispatch("clear");
value = null;
}
</script>
@ -51,8 +57,11 @@
playsInline
preload="auto"
src={value.data}
on:play
on:pause
on:ended
/>
{:else}
{:else if value.size}
<div class="file-name text-4xl p-6 break-all">{value.name}</div>
<div class="file-size text-2xl p-2">
{prettyBytes(value.size)}