|
<script lang="ts"> |
|
|
|
import { onMount, createEventDispatcher } from "svelte"; |
|
import type { ComponentMeta, Dependency } from "../types"; |
|
import { post_data } from "@gradio/client"; |
|
import NoApi from "./NoApi.svelte"; |
|
import type { client } from "@gradio/client"; |
|
|
|
import { represent_value } from "./utils"; |
|
|
|
import ApiBanner from "./ApiBanner.svelte"; |
|
import ResponseObject from "./ResponseObject.svelte"; |
|
import InstallSnippet from "./InstallSnippet.svelte"; |
|
import CodeSnippets from "./CodeSnippets.svelte"; |
|
|
|
import python from "./img/python.svg"; |
|
import javascript from "./img/javascript.svg"; |
|
|
|
export let instance_map: { |
|
[id: number]: ComponentMeta; |
|
}; |
|
export let dependencies: Dependency[]; |
|
export let root: string; |
|
export let app: Awaited<ReturnType<typeof client>>; |
|
|
|
if (root === "") { |
|
root = location.protocol + "//" + location.host + location.pathname; |
|
} |
|
if (!root.endsWith("/")) { |
|
root += "/"; |
|
} |
|
|
|
let current_language: "python" | "javascript" = "python"; |
|
|
|
const langs = [ |
|
["python", python], |
|
["javascript", javascript] |
|
] as const; |
|
|
|
let is_running = false; |
|
|
|
let dependency_inputs = dependencies.map((dependency) => |
|
dependency.inputs.map((_id) => { |
|
let default_data = instance_map[_id].documentation?.example_data; |
|
if (default_data === undefined) { |
|
default_data = ""; |
|
} else if (typeof default_data === "object") { |
|
default_data = JSON.stringify(default_data); |
|
} |
|
return default_data; |
|
}) |
|
); |
|
|
|
let dependency_outputs: any[][] = dependencies.map( |
|
(dependency) => new Array(dependency.outputs.length) |
|
); |
|
|
|
let dependency_failures: boolean[][] = dependencies.map((dependency) => |
|
new Array(dependency.inputs.length).fill(false) |
|
); |
|
|
|
async function get_info(): Promise<{ |
|
named_endpoints: any; |
|
unnamed_endpoints: any; |
|
}> { |
|
let response = await fetch(root + "info"); |
|
let data = await response.json(); |
|
return data; |
|
} |
|
async function get_js_info(): Promise<Record<string, any>> { |
|
let js_api_info = await app.view_api(); |
|
return js_api_info; |
|
} |
|
|
|
let info: { |
|
named_endpoints: any; |
|
unnamed_endpoints: any; |
|
}; |
|
|
|
let js_info: Record<string, any>; |
|
|
|
get_info().then((data) => { |
|
info = data; |
|
}); |
|
|
|
get_js_info().then((js_api_info) => { |
|
js_info = js_api_info; |
|
}); |
|
|
|
async function run(index: number): Promise<void> { |
|
is_running = true; |
|
let dependency = dependencies[index]; |
|
let attempted_component_index = 0; |
|
try { |
|
var inputs = dependency_inputs[index].map((input_val, i) => { |
|
attempted_component_index = i; |
|
let component = instance_map[dependency.inputs[i]]; |
|
// @ts-ignore |
|
input_val = represent_value( |
|
input_val, |
|
component.documentation?.type?.input_payload || |
|
component.documentation?.type?.payload |
|
); |
|
dependency_failures[index][attempted_component_index] = false; |
|
return input_val; |
|
}); |
|
} catch (err) { |
|
dependency_failures[index][attempted_component_index] = true; |
|
is_running = false; |
|
return; |
|
} |
|
let [response, status_code] = await post_data( |
|
`${root}run/${dependency.api_name}`, |
|
{ |
|
data: inputs |
|
} |
|
); |
|
is_running = false; |
|
if (status_code == 200) { |
|
dependency_outputs[index] = response.data.map( |
|
(output_val: any, i: number) => { |
|
let component = instance_map[dependency.outputs[i]]; |
|
|
|
return represent_value( |
|
output_val, |
|
component.documentation?.type?.response_object || |
|
component.documentation?.type?.payload, |
|
"js" |
|
); |
|
} |
|
); |
|
} else { |
|
dependency_failures[index] = new Array( |
|
dependency_failures[index].length |
|
).fill(true); |
|
} |
|
} |
|
|
|
onMount(() => { |
|
document.body.style.overflow = "hidden"; |
|
if ("parentIFrame" in window) { |
|
window.parentIFrame?.scrollTo(0, 0); |
|
} |
|
return () => { |
|
document.body.style.overflow = "auto"; |
|
}; |
|
}); |
|
</script> |
|
|
|
{#if info} |
|
{#if dependencies.filter((dependency) => dependency.show_api).length} |
|
<div class="banner-wrap"> |
|
<ApiBanner |
|
on:close |
|
{root} |
|
api_count={dependencies.filter((dependency) => dependency.show_api) |
|
.length} |
|
/> |
|
</div> |
|
<div class="docs-wrap"> |
|
<div class="client-doc"> |
|
<p> |
|
Use the <a |
|
href="https://gradio.app/docs/#python-client" |
|
target="_blank"><code class="library">gradio_client</code></a |
|
> |
|
Python library or the |
|
<a href="https://gradio.app/docs/#javascript-client" target="_blank" |
|
><code class="library">@gradio/client</code></a |
|
> Javascript package to query the demo via API. |
|
</p> |
|
</div> |
|
<div class="endpoint"> |
|
<div class="snippets"> |
|
{#each langs as [language, img]} |
|
<li |
|
class="snippet |
|
{current_language === language ? 'current-lang' : 'inactive-lang'}" |
|
on:click={() => (current_language = language)} |
|
> |
|
<img src={img} alt="" /> |
|
{language} |
|
</li> |
|
{/each} |
|
</div> |
|
<InstallSnippet {current_language} /> |
|
|
|
{#if Object.keys(info.named_endpoints).length} |
|
<h2 class="header">Endpoints</h2> |
|
{/if} |
|
|
|
{#each dependencies as dependency, dependency_index} |
|
{#if dependency.show_api} |
|
<div class="endpoint-container"> |
|
<CodeSnippets |
|
named={true} |
|
endpoint_parameters={info.named_endpoints[ |
|
"/" + dependency.api_name |
|
].parameters} |
|
js_parameters={js_info.named_endpoints[ |
|
"/" + dependency.api_name |
|
].parameters} |
|
{dependency} |
|
{dependency_index} |
|
{current_language} |
|
{root} |
|
{dependency_failures} |
|
/> |
|
|
|
|
|
{true} |
|
{dependency_index} |
|
{run} |
|
|
|
|
|
<ResponseObject |
|
endpoint_returns={info.named_endpoints[ |
|
"/" + dependency.api_name |
|
].returns} |
|
js_returns={js_info.named_endpoints["/" + dependency.api_name] |
|
.returns} |
|
{is_running} |
|
{current_language} |
|
/> |
|
</div> |
|
{/if} |
|
{/each} |
|
</div> |
|
</div> |
|
{:else} |
|
<NoApi {root} on:close /> |
|
{/if} |
|
{/if} |
|
|
|
<style> |
|
.banner-wrap { |
|
position: relative; |
|
border-bottom: 1px solid var(--border-color-primary); |
|
padding: var(--size-4) var(--size-6); |
|
font-size: var(--text-md); |
|
} |
|
|
|
@media (--screen-md) { |
|
.banner-wrap { |
|
font-size: var(--text-xl); |
|
} |
|
} |
|
|
|
.docs-wrap { |
|
display: flex; |
|
flex-direction: column; |
|
gap: var(--spacing-xxl); |
|
} |
|
|
|
.endpoint { |
|
border-radius: var(--radius-md); |
|
background: var(--background-fill-primary); |
|
padding: var(--size-6); |
|
padding-top: var(--size-1); |
|
font-size: var(--text-md); |
|
} |
|
|
|
.client-doc { |
|
padding-top: var(--size-6); |
|
padding-right: var(--size-6); |
|
padding-left: var(--size-6); |
|
font-size: var(--text-md); |
|
} |
|
|
|
.library { |
|
border: 1px solid var(--border-color-accent); |
|
border-radius: var(--radius-sm); |
|
background: var(--color-accent-soft); |
|
padding-right: var(--size-1); |
|
padding-bottom: var(--size-1); |
|
padding-left: var(--size-1); |
|
color: var(--color-accent); |
|
} |
|
|
|
.snippets { |
|
display: flex; |
|
align-items: center; |
|
margin-bottom: var(--size-4); |
|
} |
|
|
|
.snippets > * + * { |
|
margin-left: var(--size-2); |
|
} |
|
|
|
.snippet { |
|
display: flex; |
|
align-items: center; |
|
border: 1px solid var(--border-color-primary); |
|
|
|
border-radius: var(--radius-md); |
|
padding: var(--size-1) var(--size-1-5); |
|
color: var(--body-text-color-subdued); |
|
color: var(--body-text-color); |
|
line-height: 1; |
|
user-select: none; |
|
text-transform: capitalize; |
|
} |
|
|
|
.current-lang { |
|
border: 1px solid var(--body-text-color-subdued); |
|
color: var(--body-text-color); |
|
} |
|
|
|
.inactive-lang { |
|
cursor: pointer; |
|
color: var(--body-text-color-subdued); |
|
} |
|
|
|
.inactive-lang:hover, |
|
.inactive-lang:focus { |
|
box-shadow: var(--shadow-drop); |
|
color: var(--body-text-color); |
|
} |
|
|
|
.snippet img { |
|
margin-right: var(--size-1-5); |
|
width: var(--size-3); |
|
} |
|
|
|
.header { |
|
margin-top: var(--size-6); |
|
font-size: var(--text-xl); |
|
} |
|
|
|
.endpoint-container { |
|
margin-top: var(--size-3); |
|
margin-bottom: var(--size-3); |
|
border: 1px solid var(--border-color-primary); |
|
border-radius: var(--radius-xl); |
|
padding: var(--size-3); |
|
padding-top: 0; |
|
} |
|
</style> |
|
|