@gradio/core 0.21.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/dist/src/Blocks.svelte +71 -17
- package/dist/src/api_docs/ApiDocs.svelte +98 -65
- package/dist/src/api_docs/CodeSnippet.svelte +8 -10
- package/dist/src/api_docs/CodeSnippet.svelte.d.ts +1 -2
- package/dist/src/api_docs/EndpointDetail.svelte +12 -13
- package/dist/src/api_docs/EndpointDetail.svelte.d.ts +1 -2
- package/dist/src/init.js +6 -2
- package/package.json +47 -47
- package/src/Blocks.svelte +81 -19
- package/src/api_docs/ApiDocs.svelte +106 -65
- package/src/api_docs/CodeSnippet.svelte +8 -10
- package/src/api_docs/EndpointDetail.svelte +12 -13
- package/src/init.ts +8 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# @gradio/core
|
|
2
2
|
|
|
3
|
+
## 0.23.0
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- [#11578](https://github.com/gradio-app/gradio/pull/11578) [`872798a`](https://github.com/gradio-app/gradio/commit/872798a780dd81c834a44b05277f6c9ebe09de8b) - Add an `api_description` parameter for API and MCP server. Thanks @abidlabs!
|
|
8
|
+
- [#11543](https://github.com/gradio-app/gradio/pull/11543) [`ac95ac0`](https://github.com/gradio-app/gradio/commit/ac95ac0d8c2e65d1632376e632fb7d16131334b6) - Connection handling messaging. Thanks @aliabid94!
|
|
9
|
+
- [#11508](https://github.com/gradio-app/gradio/pull/11508) [`f5a6fa8`](https://github.com/gradio-app/gradio/commit/f5a6fa8c52bcb8f508e10ea54a3427f3dab8e3f8) - Handle uploading files in mcp server automatically. Thanks @freddyaboulton!
|
|
10
|
+
- [#11515](https://github.com/gradio-app/gradio/pull/11515) [`2c24ca7`](https://github.com/gradio-app/gradio/commit/2c24ca709396291a344d981c19ed1655028b5d64) - Making it easier for MCP developers call APIs with user credentials. Thanks @freddyaboulton!
|
|
11
|
+
- [#11584](https://github.com/gradio-app/gradio/pull/11584) [`78428cb`](https://github.com/gradio-app/gradio/commit/78428cb29bf6dc66d583b7cf93dd404aef737e75) - Fix reload mode. Thanks @aliabid94!
|
|
12
|
+
|
|
13
|
+
### Fixes
|
|
14
|
+
|
|
15
|
+
- [#11590](https://github.com/gradio-app/gradio/pull/11590) [`33b6057`](https://github.com/gradio-app/gradio/commit/33b6057dc5cbdfdab15b1ee000b0f0b3d9f3fff6) - Add Gradio File Input keyword to gradio file inputs. Thanks @freddyaboulton!
|
|
16
|
+
|
|
17
|
+
### Dependency updates
|
|
18
|
+
|
|
19
|
+
- @gradio/video@0.14.21
|
|
20
|
+
- @gradio/client@1.15.6
|
|
21
|
+
- @gradio/statustracker@0.10.15
|
|
22
|
+
- @gradio/button@0.5.7
|
|
23
|
+
- @gradio/upload@0.16.11
|
|
24
|
+
- @gradio/checkbox@0.4.26
|
|
25
|
+
- @gradio/image@0.22.13
|
|
26
|
+
- @gradio/gallery@0.15.27
|
|
27
|
+
- @gradio/plot@0.9.20
|
|
28
|
+
- @gradio/textbox@0.10.17
|
|
29
|
+
- @gradio/file@0.12.24
|
|
30
|
+
- @gradio/code@0.14.11
|
|
31
|
+
- @gradio/paramviewer@0.7.13
|
|
32
|
+
- @gradio/column@0.2.1
|
|
33
|
+
|
|
34
|
+
## 0.22.0
|
|
35
|
+
|
|
36
|
+
### Features
|
|
37
|
+
|
|
38
|
+
- [#11572](https://github.com/gradio-app/gradio/pull/11572) [`552a5eb`](https://github.com/gradio-app/gradio/commit/552a5ebf9beb5d543f82a24a546daaf9ad3d88b1) - handle i18n error when browsers aren't set to en. Thanks @hannahblair!
|
|
39
|
+
|
|
3
40
|
## 0.21.0
|
|
4
41
|
|
|
5
42
|
### Features
|
package/dist/src/Blocks.svelte
CHANGED
|
@@ -35,6 +35,7 @@ export let api_prefix = "";
|
|
|
35
35
|
export let max_file_size = void 0;
|
|
36
36
|
export let initial_layout = void 0;
|
|
37
37
|
export let css = null;
|
|
38
|
+
let broken_connection = false;
|
|
38
39
|
let {
|
|
39
40
|
layout: _layout,
|
|
40
41
|
targets,
|
|
@@ -60,6 +61,7 @@ $:
|
|
|
60
61
|
old_dependencies = dependencies;
|
|
61
62
|
}
|
|
62
63
|
async function run() {
|
|
64
|
+
await setupi18n(app.config?.i18n_translations || void 0);
|
|
63
65
|
layout_creating = true;
|
|
64
66
|
await create_layout({
|
|
65
67
|
components,
|
|
@@ -202,11 +204,13 @@ export function add_new_message(title2, message, type) {
|
|
|
202
204
|
messages = [new_message(title2, message, -1, type), ...messages];
|
|
203
205
|
}
|
|
204
206
|
let _error_id = -1;
|
|
205
|
-
let user_left_page = false;
|
|
206
207
|
const MESSAGE_QUOTE_RE = /^'([^]+)'$/;
|
|
207
208
|
const DUPLICATE_MESSAGE = $_("blocks.long_requests_queue");
|
|
208
209
|
const MOBILE_QUEUE_WARNING = $_("blocks.connection_can_break");
|
|
209
|
-
const
|
|
210
|
+
const LOST_CONNECTION_MESSAGE = "Connection to the server was lost. Attempting reconnection...";
|
|
211
|
+
const CHANGED_CONNECTION_MESSAGE = "Reconnected to server, but the server has changed. You may need to <a href=''>refresh the page</a>.";
|
|
212
|
+
const RECONNECTION_MESSAGE = "Connection re-established.";
|
|
213
|
+
const SESSION_NOT_FOUND_MESSAGE = "Session not found - this is likely because the machine you were connected to has changed. <a href=''>Refresh the page</a> to continue.";
|
|
210
214
|
const WAITING_FOR_INPUTS_MESSAGE = $_("blocks.waiting_for_inputs");
|
|
211
215
|
const SHOW_DUPLICATE_MESSAGE_ON_ETA = 15;
|
|
212
216
|
const SHOW_MOBILE_QUEUE_WARNING_ON_ETA = 10;
|
|
@@ -321,6 +325,42 @@ async function trigger_api_call(dep_index, trigger_id = null, event_data = null)
|
|
|
321
325
|
}
|
|
322
326
|
}
|
|
323
327
|
}
|
|
328
|
+
async function reconnect() {
|
|
329
|
+
const connection_status = await app.reconnect();
|
|
330
|
+
if (connection_status === "broken") {
|
|
331
|
+
setTimeout(reconnect, 1e3);
|
|
332
|
+
} else if (connection_status === "changed") {
|
|
333
|
+
broken_connection = false;
|
|
334
|
+
messages = [
|
|
335
|
+
new_message(
|
|
336
|
+
"Changed Connection",
|
|
337
|
+
CHANGED_CONNECTION_MESSAGE,
|
|
338
|
+
-1,
|
|
339
|
+
"info",
|
|
340
|
+
3,
|
|
341
|
+
true
|
|
342
|
+
),
|
|
343
|
+
...messages.map(
|
|
344
|
+
(m) => m.message === LOST_CONNECTION_MESSAGE ? { ...m, visible: false } : m
|
|
345
|
+
)
|
|
346
|
+
];
|
|
347
|
+
} else if (connection_status === "connected") {
|
|
348
|
+
broken_connection = false;
|
|
349
|
+
messages = [
|
|
350
|
+
new_message(
|
|
351
|
+
"Reconnected",
|
|
352
|
+
RECONNECTION_MESSAGE,
|
|
353
|
+
-1,
|
|
354
|
+
"success",
|
|
355
|
+
null,
|
|
356
|
+
true
|
|
357
|
+
),
|
|
358
|
+
...messages.map(
|
|
359
|
+
(m) => m.message === LOST_CONNECTION_MESSAGE ? { ...m, visible: false } : m
|
|
360
|
+
)
|
|
361
|
+
];
|
|
362
|
+
}
|
|
363
|
+
}
|
|
324
364
|
async function make_prediction(payload2, streaming = false) {
|
|
325
365
|
if (allow_video_trim) {
|
|
326
366
|
screen_recorder.markRemoveSegmentStart();
|
|
@@ -438,6 +478,34 @@ async function trigger_api_call(dep_index, trigger_id = null, event_data = null)
|
|
|
438
478
|
}
|
|
439
479
|
}
|
|
440
480
|
function handle_status_update(message) {
|
|
481
|
+
if (message.broken && !broken_connection) {
|
|
482
|
+
messages = [
|
|
483
|
+
new_message(
|
|
484
|
+
"Broken Connection",
|
|
485
|
+
LOST_CONNECTION_MESSAGE,
|
|
486
|
+
-1,
|
|
487
|
+
"error",
|
|
488
|
+
null,
|
|
489
|
+
true
|
|
490
|
+
),
|
|
491
|
+
...messages
|
|
492
|
+
];
|
|
493
|
+
broken_connection = true;
|
|
494
|
+
setTimeout(reconnect, 1e3);
|
|
495
|
+
}
|
|
496
|
+
if (message.session_not_found) {
|
|
497
|
+
messages = [
|
|
498
|
+
new_message(
|
|
499
|
+
"Session Not Found",
|
|
500
|
+
SESSION_NOT_FOUND_MESSAGE,
|
|
501
|
+
-1,
|
|
502
|
+
"error",
|
|
503
|
+
null,
|
|
504
|
+
true
|
|
505
|
+
),
|
|
506
|
+
...messages
|
|
507
|
+
];
|
|
508
|
+
}
|
|
441
509
|
const { fn_index, ...status } = message;
|
|
442
510
|
if (status.stage === "streaming" && status.time_limit) {
|
|
443
511
|
dep.inputs.forEach((id) => {
|
|
@@ -491,16 +559,7 @@ async function trigger_api_call(dep_index, trigger_id = null, event_data = null)
|
|
|
491
559
|
});
|
|
492
560
|
submit_map.delete(dep_index);
|
|
493
561
|
}
|
|
494
|
-
if (status.
|
|
495
|
-
window.setTimeout(() => {
|
|
496
|
-
messages = [
|
|
497
|
-
new_message("Error", MOBILE_RECONNECT_MESSAGE, fn_index, "error"),
|
|
498
|
-
...messages
|
|
499
|
-
];
|
|
500
|
-
}, 0);
|
|
501
|
-
wait_then_trigger_api_call(dep.id, payload2.trigger_id, event_data);
|
|
502
|
-
user_left_page = false;
|
|
503
|
-
} else if (status.stage === "error") {
|
|
562
|
+
if (status.stage === "error" && !broken_connection && !message.session_not_found) {
|
|
504
563
|
if (status.message) {
|
|
505
564
|
const _message = status.message.replace(
|
|
506
565
|
MESSAGE_QUOTE_RE,
|
|
@@ -671,11 +730,6 @@ function isCustomEvent(event) {
|
|
|
671
730
|
}
|
|
672
731
|
let is_screen_recording = writable(false);
|
|
673
732
|
onMount(() => {
|
|
674
|
-
document.addEventListener("visibilitychange", function() {
|
|
675
|
-
if (document.visibilityState === "hidden") {
|
|
676
|
-
user_left_page = true;
|
|
677
|
-
}
|
|
678
|
-
});
|
|
679
733
|
is_mobile_device = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
|
680
734
|
navigator.userAgent
|
|
681
735
|
);
|
|
@@ -65,16 +65,83 @@ get_js_info().then((js_api_info) => {
|
|
|
65
65
|
const dispatch = createEventDispatcher();
|
|
66
66
|
const mcp_server_url = `${root}gradio_api/mcp/sse`;
|
|
67
67
|
let tools = [];
|
|
68
|
+
let headers = [];
|
|
69
|
+
let mcp_json_sse;
|
|
70
|
+
let mcp_json_stdio;
|
|
71
|
+
let file_data_present = false;
|
|
72
|
+
const upload_file_mcp_server = {
|
|
73
|
+
command: "uvx",
|
|
74
|
+
args: [
|
|
75
|
+
"--from",
|
|
76
|
+
"gradio[mcp]",
|
|
77
|
+
"gradio",
|
|
78
|
+
"upload-mcp",
|
|
79
|
+
root,
|
|
80
|
+
"<UPLOAD_DIRECTORY>"
|
|
81
|
+
]
|
|
82
|
+
};
|
|
68
83
|
async function fetchMcpTools() {
|
|
69
84
|
try {
|
|
70
85
|
const response = await fetch(`${root}gradio_api/mcp/schema`);
|
|
71
86
|
const schema = await response.json();
|
|
87
|
+
file_data_present = schema.map((tool) => tool.meta?.file_data_present).some((present) => present);
|
|
72
88
|
tools = schema.map((tool) => ({
|
|
73
89
|
name: tool.name,
|
|
74
90
|
description: tool.description || "",
|
|
75
91
|
parameters: tool.inputSchema?.properties || {},
|
|
76
92
|
expanded: false
|
|
77
93
|
}));
|
|
94
|
+
headers = schema.map((tool) => tool.meta?.headers || []).flat();
|
|
95
|
+
if (headers.length > 0) {
|
|
96
|
+
mcp_json_sse = {
|
|
97
|
+
mcpServers: {
|
|
98
|
+
gradio: {
|
|
99
|
+
url: mcp_server_url,
|
|
100
|
+
headers: headers.reduce((accumulator, current_key) => {
|
|
101
|
+
accumulator[current_key] = "<YOUR_HEADER_VALUE>";
|
|
102
|
+
return accumulator;
|
|
103
|
+
}, {})
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
mcp_json_stdio = {
|
|
108
|
+
mcpServers: {
|
|
109
|
+
gradio: {
|
|
110
|
+
command: "npx",
|
|
111
|
+
args: [
|
|
112
|
+
"mcp-remote",
|
|
113
|
+
mcp_server_url,
|
|
114
|
+
"--transport",
|
|
115
|
+
"sse-only",
|
|
116
|
+
...headers.map((header) => [
|
|
117
|
+
"--header",
|
|
118
|
+
`${header}: <YOUR_HEADER_VALUE>`
|
|
119
|
+
]).flat()
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
} else {
|
|
125
|
+
mcp_json_sse = {
|
|
126
|
+
mcpServers: {
|
|
127
|
+
gradio: {
|
|
128
|
+
url: mcp_server_url
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
mcp_json_stdio = {
|
|
133
|
+
mcpServers: {
|
|
134
|
+
gradio: {
|
|
135
|
+
command: "npx",
|
|
136
|
+
args: ["mcp-remote", mcp_server_url, "--transport", "sse-only"]
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
if (file_data_present) {
|
|
141
|
+
mcp_json_sse.mcpServers.upload_files_to_gradio = upload_file_mcp_server;
|
|
142
|
+
mcp_json_stdio.mcpServers.upload_files_to_gradio = upload_file_mcp_server;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
78
145
|
} catch (error) {
|
|
79
146
|
console.error("Failed to fetch MCP tools:", error);
|
|
80
147
|
tools = [];
|
|
@@ -180,7 +247,7 @@ onMount(() => {
|
|
|
180
247
|
<div class="mcp-url">
|
|
181
248
|
<label
|
|
182
249
|
><span class="status-indicator active">●</span>MCP Server
|
|
183
|
-
URL</label
|
|
250
|
+
URL (SSE)</label
|
|
184
251
|
>
|
|
185
252
|
<div class="textbox">
|
|
186
253
|
<input type="text" readonly value={mcp_server_url} />
|
|
@@ -239,45 +306,42 @@ onMount(() => {
|
|
|
239
306
|
</div>
|
|
240
307
|
<p> </p>
|
|
241
308
|
|
|
242
|
-
<strong>
|
|
309
|
+
<strong>SSE Transport</strong>: To add this MCP to clients that
|
|
243
310
|
support SSE (e.g. Cursor, Windsurf, Cline), simply add the
|
|
244
|
-
following configuration to your MCP config
|
|
311
|
+
following configuration to your MCP config.
|
|
245
312
|
<p> </p>
|
|
246
313
|
<Block>
|
|
247
314
|
<code>
|
|
248
315
|
<div class="copy">
|
|
249
316
|
<CopyButton
|
|
250
|
-
code={JSON.stringify(
|
|
251
|
-
{
|
|
252
|
-
mcpServers: {
|
|
253
|
-
gradio: {
|
|
254
|
-
url: mcp_server_url
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
},
|
|
258
|
-
null,
|
|
259
|
-
2
|
|
260
|
-
)}
|
|
317
|
+
code={JSON.stringify(mcp_json_sse, null, 2)}
|
|
261
318
|
/>
|
|
262
319
|
</div>
|
|
263
320
|
<div>
|
|
264
|
-
<pre>{JSON.stringify(
|
|
265
|
-
{
|
|
266
|
-
mcpServers: {
|
|
267
|
-
gradio: {
|
|
268
|
-
url: mcp_server_url
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
},
|
|
272
|
-
null,
|
|
273
|
-
2
|
|
274
|
-
)}</pre>
|
|
321
|
+
<pre>{JSON.stringify(mcp_json_sse, null, 2)}</pre>
|
|
275
322
|
</div>
|
|
276
323
|
</code>
|
|
277
324
|
</Block>
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
325
|
+
{#if file_data_present}
|
|
326
|
+
<p> </p>
|
|
327
|
+
<em>Note about files</em>: Gradio MCP servers that have files
|
|
328
|
+
as inputs need the files as URLs, so the
|
|
329
|
+
<code>upload_files_to_gradio</code>
|
|
330
|
+
tool is included for your convenience. This tool can upload files
|
|
331
|
+
located in the specified <code>UPLOAD_DIRECTORY</code>
|
|
332
|
+
argument (an absolute path in your local machine) or any of its
|
|
333
|
+
subdirectories to the Gradio app. You can omit this tool if you
|
|
334
|
+
are fine manually uploading files yourself and providing the URLs.
|
|
335
|
+
Before using this tool, you must have
|
|
336
|
+
<a
|
|
337
|
+
href="https://docs.astral.sh/uv/getting-started/installation/"
|
|
338
|
+
target="_blank">uv installed</a
|
|
339
|
+
>.
|
|
340
|
+
<p> </p>
|
|
341
|
+
{/if}
|
|
342
|
+
|
|
343
|
+
<strong>STDIO Transport</strong>: For clients that only support
|
|
344
|
+
stdio (e.g. Claude Desktop), first
|
|
281
345
|
<a href="https://nodejs.org/en/download/" target="_blank"
|
|
282
346
|
>install Node.js</a
|
|
283
347
|
>. Then, you can use the following command:
|
|
@@ -286,43 +350,11 @@ onMount(() => {
|
|
|
286
350
|
<code>
|
|
287
351
|
<div class="copy">
|
|
288
352
|
<CopyButton
|
|
289
|
-
code={JSON.stringify(
|
|
290
|
-
{
|
|
291
|
-
mcpServers: {
|
|
292
|
-
gradio: {
|
|
293
|
-
command: "npx",
|
|
294
|
-
args: [
|
|
295
|
-
"mcp-remote",
|
|
296
|
-
mcp_server_url,
|
|
297
|
-
"--transport",
|
|
298
|
-
"sse-only"
|
|
299
|
-
]
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
},
|
|
303
|
-
null,
|
|
304
|
-
2
|
|
305
|
-
)}
|
|
353
|
+
code={JSON.stringify(mcp_json_stdio, null, 2)}
|
|
306
354
|
/>
|
|
307
355
|
</div>
|
|
308
356
|
<div>
|
|
309
|
-
<pre>{JSON.stringify(
|
|
310
|
-
{
|
|
311
|
-
mcpServers: {
|
|
312
|
-
gradio: {
|
|
313
|
-
command: "npx",
|
|
314
|
-
args: [
|
|
315
|
-
"mcp-remote",
|
|
316
|
-
mcp_server_url,
|
|
317
|
-
"--transport",
|
|
318
|
-
"sse-only"
|
|
319
|
-
]
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
},
|
|
323
|
-
null,
|
|
324
|
-
2
|
|
325
|
-
)}</pre>
|
|
357
|
+
<pre>{JSON.stringify(mcp_json_stdio, null, 2)}</pre>
|
|
326
358
|
</div>
|
|
327
359
|
</code>
|
|
328
360
|
</Block>
|
|
@@ -398,21 +430,22 @@ onMount(() => {
|
|
|
398
430
|
{/if}
|
|
399
431
|
|
|
400
432
|
{#if current_language !== "mcp"}
|
|
401
|
-
{#each dependencies as dependency
|
|
433
|
+
{#each dependencies as dependency}
|
|
402
434
|
{#if dependency.show_api && info.named_endpoints["/" + dependency.api_name]}
|
|
403
435
|
<div class="endpoint-container">
|
|
404
436
|
<CodeSnippet
|
|
405
|
-
named={true}
|
|
406
437
|
endpoint_parameters={info.named_endpoints[
|
|
407
438
|
"/" + dependency.api_name
|
|
408
439
|
].parameters}
|
|
409
440
|
{dependency}
|
|
410
|
-
{dependency_index}
|
|
411
441
|
{current_language}
|
|
412
442
|
{root}
|
|
413
443
|
{space_id}
|
|
414
444
|
{username}
|
|
415
445
|
api_prefix={app.api_prefix}
|
|
446
|
+
api_description={info.named_endpoints[
|
|
447
|
+
"/" + dependency.api_name
|
|
448
|
+
].description}
|
|
416
449
|
/>
|
|
417
450
|
|
|
418
451
|
<ParametersSnippet
|
|
@@ -3,14 +3,13 @@ import { represent_value, is_potentially_nested_file_data } from "./utils";
|
|
|
3
3
|
import { Block } from "@gradio/atoms";
|
|
4
4
|
import EndpointDetail from "./EndpointDetail.svelte";
|
|
5
5
|
export let dependency;
|
|
6
|
-
export let dependency_index;
|
|
7
6
|
export let root;
|
|
8
7
|
export let api_prefix;
|
|
9
8
|
export let space_id;
|
|
10
9
|
export let endpoint_parameters;
|
|
11
|
-
export let named;
|
|
12
10
|
export let username;
|
|
13
11
|
export let current_language;
|
|
12
|
+
export let api_description = null;
|
|
14
13
|
let python_code;
|
|
15
14
|
let js_code;
|
|
16
15
|
let bash_post_code;
|
|
@@ -29,11 +28,10 @@ $:
|
|
|
29
28
|
</script>
|
|
30
29
|
|
|
31
30
|
<div class="container">
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
{/if}
|
|
31
|
+
<EndpointDetail
|
|
32
|
+
api_name={dependency.api_name}
|
|
33
|
+
description={api_description}
|
|
34
|
+
/>
|
|
37
35
|
{#if current_language === "python"}
|
|
38
36
|
<Block>
|
|
39
37
|
<code>
|
|
@@ -86,9 +84,9 @@ const example{component} = await response_{i}.blob();
|
|
|
86
84
|
const client = await Client.connect(<span class="token string"
|
|
87
85
|
>"{space_id || root}"</span
|
|
88
86
|
>{#if username !== null}, {auth: ["{username}", **password**]}{/if});
|
|
89
|
-
const result = await client.predict(
|
|
90
|
-
|
|
91
|
-
|
|
87
|
+
const result = await client.predict(<span class="api-name"
|
|
88
|
+
>"/{dependency.api_name}"</span
|
|
89
|
+
>, { <!--
|
|
92
90
|
-->{#each endpoint_parameters as { label, parameter_name, type, python_type, component, example_input, serializer }, i}<!--
|
|
93
91
|
-->{#if blob_components.includes(component)}<!--
|
|
94
92
|
-->
|
|
@@ -3,14 +3,13 @@ import type { Dependency } from "../types";
|
|
|
3
3
|
declare const __propDef: {
|
|
4
4
|
props: {
|
|
5
5
|
dependency: Dependency;
|
|
6
|
-
dependency_index: number;
|
|
7
6
|
root: string;
|
|
8
7
|
api_prefix: string;
|
|
9
8
|
space_id: string | null;
|
|
10
9
|
endpoint_parameters: any;
|
|
11
|
-
named: boolean;
|
|
12
10
|
username: string | null;
|
|
13
11
|
current_language: "python" | "javascript" | "bash";
|
|
12
|
+
api_description?: (string | null) | undefined;
|
|
14
13
|
};
|
|
15
14
|
events: {
|
|
16
15
|
[evt: string]: CustomEvent<any>;
|
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
<script>export let api_name = null;
|
|
2
|
-
export let
|
|
3
|
-
export let named;
|
|
2
|
+
export let description = null;
|
|
4
3
|
</script>
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
{:else}
|
|
12
|
-
<h3>
|
|
13
|
-
fn_index:
|
|
14
|
-
<span class="post">{fn_index}</span>
|
|
15
|
-
</h3>
|
|
16
|
-
{/if}
|
|
5
|
+
<h3>
|
|
6
|
+
API name:
|
|
7
|
+
<span class="post">{"/" + api_name}</span>
|
|
8
|
+
<span class="desc">{description}</span>
|
|
9
|
+
</h3>
|
|
17
10
|
|
|
18
11
|
<style>
|
|
19
12
|
h3 {
|
|
@@ -33,4 +26,10 @@ export let named;
|
|
|
33
26
|
color: var(--color-accent);
|
|
34
27
|
font-weight: var(--weight-semibold);
|
|
35
28
|
}
|
|
29
|
+
|
|
30
|
+
.desc {
|
|
31
|
+
color: var(--body-text-color-subdued);
|
|
32
|
+
font-size: var(--text-lg);
|
|
33
|
+
margin-top: var(--size-1);
|
|
34
|
+
}
|
|
36
35
|
</style>
|
|
@@ -2,8 +2,7 @@ import { SvelteComponent } from "svelte";
|
|
|
2
2
|
declare const __propDef: {
|
|
3
3
|
props: {
|
|
4
4
|
api_name?: (string | null) | undefined;
|
|
5
|
-
|
|
6
|
-
named: boolean;
|
|
5
|
+
description?: (string | null) | undefined;
|
|
7
6
|
};
|
|
8
7
|
events: {
|
|
9
8
|
[evt: string]: CustomEvent<any>;
|
package/dist/src/init.js
CHANGED
|
@@ -48,8 +48,12 @@ export function create_components(initial_layout) {
|
|
|
48
48
|
if (instance_map) {
|
|
49
49
|
// re-render in reload mode
|
|
50
50
|
components.forEach((c) => {
|
|
51
|
-
if (c.props.value == null && c.
|
|
52
|
-
|
|
51
|
+
if (c.props.value == null && c.key) {
|
|
52
|
+
// If the component has a key, we preserve its value by finding a matching instance with the same key
|
|
53
|
+
const matching_instance = Object.values(instance_map).find((instance) => instance.key === c.key);
|
|
54
|
+
if (matching_instance) {
|
|
55
|
+
c.props.value = matching_instance.props.value;
|
|
56
|
+
}
|
|
53
57
|
}
|
|
54
58
|
});
|
|
55
59
|
}
|
package/package.json
CHANGED
|
@@ -1,67 +1,67 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gradio/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"devDependencies": {
|
|
6
|
-
"@gradio/accordion": "^0.5.19",
|
|
7
6
|
"@gradio/atoms": "^0.16.3",
|
|
8
|
-
"@gradio/audio": "^0.17.
|
|
7
|
+
"@gradio/audio": "^0.17.21",
|
|
8
|
+
"@gradio/accordion": "^0.5.20",
|
|
9
|
+
"@gradio/annotatedimage": "^0.9.25",
|
|
9
10
|
"@gradio/box": "^0.2.21",
|
|
10
|
-
"@gradio/
|
|
11
|
-
"@gradio/
|
|
12
|
-
"@gradio/
|
|
13
|
-
"@gradio/
|
|
14
|
-
"@gradio/
|
|
15
|
-
"@gradio/
|
|
16
|
-
"@gradio/colorpicker": "^0.4.
|
|
17
|
-
"@gradio/
|
|
11
|
+
"@gradio/button": "^0.5.7",
|
|
12
|
+
"@gradio/chatbot": "^0.26.18",
|
|
13
|
+
"@gradio/checkbox": "^0.4.26",
|
|
14
|
+
"@gradio/checkboxgroup": "^0.6.25",
|
|
15
|
+
"@gradio/client": "^1.15.6",
|
|
16
|
+
"@gradio/code": "^0.14.11",
|
|
17
|
+
"@gradio/colorpicker": "^0.4.25",
|
|
18
|
+
"@gradio/dataset": "^0.4.27",
|
|
19
|
+
"@gradio/datetime": "^0.3.18",
|
|
18
20
|
"@gradio/column": "^0.2.1",
|
|
19
|
-
"@gradio/dataframe": "^0.18.
|
|
20
|
-
"@gradio/
|
|
21
|
-
"@gradio/
|
|
22
|
-
"@gradio/
|
|
23
|
-
"@gradio/
|
|
24
|
-
"@gradio/
|
|
25
|
-
"@gradio/file": "^0.12.23",
|
|
26
|
-
"@gradio/fileexplorer": "^0.5.34",
|
|
27
|
-
"@gradio/gallery": "^0.15.26",
|
|
21
|
+
"@gradio/dataframe": "^0.18.3",
|
|
22
|
+
"@gradio/downloadbutton": "^0.4.7",
|
|
23
|
+
"@gradio/dropdown": "^0.9.25",
|
|
24
|
+
"@gradio/fallback": "^0.4.25",
|
|
25
|
+
"@gradio/file": "^0.12.24",
|
|
26
|
+
"@gradio/fileexplorer": "^0.5.35",
|
|
28
27
|
"@gradio/form": "^0.2.21",
|
|
29
28
|
"@gradio/group": "^0.2.0",
|
|
29
|
+
"@gradio/gallery": "^0.15.27",
|
|
30
|
+
"@gradio/highlightedtext": "^0.9.8",
|
|
31
|
+
"@gradio/html": "^0.6.17",
|
|
30
32
|
"@gradio/icons": "^0.12.0",
|
|
31
|
-
"@gradio/
|
|
32
|
-
"@gradio/
|
|
33
|
-
"@gradio/
|
|
34
|
-
"@gradio/
|
|
35
|
-
"@gradio/imageslider": "^0.2.8",
|
|
36
|
-
"@gradio/label": "^0.5.16",
|
|
37
|
-
"@gradio/json": "^0.5.26",
|
|
38
|
-
"@gradio/markdown": "^0.13.17",
|
|
39
|
-
"@gradio/model3d": "^0.14.19",
|
|
33
|
+
"@gradio/image": "^0.22.13",
|
|
34
|
+
"@gradio/imageeditor": "^0.16.1",
|
|
35
|
+
"@gradio/imageslider": "^0.2.9",
|
|
36
|
+
"@gradio/json": "^0.5.27",
|
|
40
37
|
"@gradio/browserstate": "^0.3.2",
|
|
41
|
-
"@gradio/
|
|
42
|
-
"@gradio/
|
|
43
|
-
"@gradio/
|
|
44
|
-
"@gradio/
|
|
45
|
-
"@gradio/
|
|
38
|
+
"@gradio/model3d": "^0.14.20",
|
|
39
|
+
"@gradio/markdown": "^0.13.18",
|
|
40
|
+
"@gradio/label": "^0.5.17",
|
|
41
|
+
"@gradio/nativeplot": "^0.7.2",
|
|
42
|
+
"@gradio/number": "^0.6.2",
|
|
43
|
+
"@gradio/paramviewer": "^0.7.13",
|
|
44
|
+
"@gradio/multimodaltextbox": "^0.10.13",
|
|
45
|
+
"@gradio/plot": "^0.9.20",
|
|
46
|
+
"@gradio/radio": "^0.7.8",
|
|
46
47
|
"@gradio/row": "^0.2.1",
|
|
47
|
-
"@gradio/
|
|
48
|
-
"@gradio/
|
|
49
|
-
"@gradio/simpleimage": "^0.8.
|
|
50
|
-
"@gradio/
|
|
51
|
-
"@gradio/
|
|
52
|
-
"@gradio/
|
|
53
|
-
"@gradio/slider": "^0.6.13",
|
|
54
|
-
"@gradio/tabitem": "^0.5.0",
|
|
48
|
+
"@gradio/sidebar": "^0.1.18",
|
|
49
|
+
"@gradio/simpletextbox": "^0.3.26",
|
|
50
|
+
"@gradio/simpleimage": "^0.8.35",
|
|
51
|
+
"@gradio/sketchbox": "^0.6.13",
|
|
52
|
+
"@gradio/slider": "^0.6.14",
|
|
53
|
+
"@gradio/simpledropdown": "^0.3.25",
|
|
55
54
|
"@gradio/state": "^0.1.2",
|
|
56
|
-
"@gradio/
|
|
55
|
+
"@gradio/statustracker": "^0.10.15",
|
|
57
56
|
"@gradio/tabs": "^0.4.5",
|
|
57
|
+
"@gradio/textbox": "^0.10.17",
|
|
58
|
+
"@gradio/tabitem": "^0.5.0",
|
|
58
59
|
"@gradio/theme": "^0.4.0",
|
|
59
60
|
"@gradio/timer": "^0.4.5",
|
|
60
|
-
"@gradio/upload": "^0.16.
|
|
61
|
-
"@gradio/uploadbutton": "^0.9.
|
|
62
|
-
"@gradio/statustracker": "^0.10.14",
|
|
61
|
+
"@gradio/upload": "^0.16.11",
|
|
62
|
+
"@gradio/uploadbutton": "^0.9.7",
|
|
63
63
|
"@gradio/utils": "^0.10.2",
|
|
64
|
-
"@gradio/video": "^0.14.
|
|
64
|
+
"@gradio/video": "^0.14.21",
|
|
65
65
|
"@gradio/wasm": "^0.18.1"
|
|
66
66
|
},
|
|
67
67
|
"msw": {
|
package/src/Blocks.svelte
CHANGED
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
export let max_file_size: number | undefined = undefined;
|
|
57
57
|
export let initial_layout: ComponentMeta | undefined = undefined;
|
|
58
58
|
export let css: string | null | undefined = null;
|
|
59
|
+
let broken_connection = false;
|
|
59
60
|
|
|
60
61
|
let {
|
|
61
62
|
layout: _layout,
|
|
@@ -89,6 +90,8 @@
|
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
async function run(): Promise<void> {
|
|
93
|
+
await setupi18n(app.config?.i18n_translations || undefined);
|
|
94
|
+
|
|
92
95
|
layout_creating = true;
|
|
93
96
|
await create_layout({
|
|
94
97
|
components,
|
|
@@ -273,13 +276,17 @@
|
|
|
273
276
|
|
|
274
277
|
let _error_id = -1;
|
|
275
278
|
|
|
276
|
-
let user_left_page = false;
|
|
277
|
-
|
|
278
279
|
const MESSAGE_QUOTE_RE = /^'([^]+)'$/;
|
|
279
280
|
|
|
280
281
|
const DUPLICATE_MESSAGE = $_("blocks.long_requests_queue");
|
|
281
282
|
const MOBILE_QUEUE_WARNING = $_("blocks.connection_can_break");
|
|
282
|
-
const
|
|
283
|
+
const LOST_CONNECTION_MESSAGE =
|
|
284
|
+
"Connection to the server was lost. Attempting reconnection...";
|
|
285
|
+
const CHANGED_CONNECTION_MESSAGE =
|
|
286
|
+
"Reconnected to server, but the server has changed. You may need to <a href=''>refresh the page</a>.";
|
|
287
|
+
const RECONNECTION_MESSAGE = "Connection re-established.";
|
|
288
|
+
const SESSION_NOT_FOUND_MESSAGE =
|
|
289
|
+
"Session not found - this is likely because the machine you were connected to has changed. <a href=''>Refresh the page</a> to continue.";
|
|
283
290
|
const WAITING_FOR_INPUTS_MESSAGE = $_("blocks.waiting_for_inputs");
|
|
284
291
|
const SHOW_DUPLICATE_MESSAGE_ON_ETA = 15;
|
|
285
292
|
const SHOW_MOBILE_QUEUE_WARNING_ON_ETA = 10;
|
|
@@ -422,6 +429,43 @@
|
|
|
422
429
|
}
|
|
423
430
|
}
|
|
424
431
|
|
|
432
|
+
async function reconnect(): Promise<void> {
|
|
433
|
+
const connection_status = await app.reconnect();
|
|
434
|
+
if (connection_status === "broken") {
|
|
435
|
+
setTimeout(reconnect, 1000);
|
|
436
|
+
} else if (connection_status === "changed") {
|
|
437
|
+
broken_connection = false;
|
|
438
|
+
messages = [
|
|
439
|
+
new_message(
|
|
440
|
+
"Changed Connection",
|
|
441
|
+
CHANGED_CONNECTION_MESSAGE,
|
|
442
|
+
-1,
|
|
443
|
+
"info",
|
|
444
|
+
3,
|
|
445
|
+
true
|
|
446
|
+
),
|
|
447
|
+
...messages.map((m) =>
|
|
448
|
+
m.message === LOST_CONNECTION_MESSAGE ? { ...m, visible: false } : m
|
|
449
|
+
)
|
|
450
|
+
];
|
|
451
|
+
} else if (connection_status === "connected") {
|
|
452
|
+
broken_connection = false;
|
|
453
|
+
messages = [
|
|
454
|
+
new_message(
|
|
455
|
+
"Reconnected",
|
|
456
|
+
RECONNECTION_MESSAGE,
|
|
457
|
+
-1,
|
|
458
|
+
"success",
|
|
459
|
+
null,
|
|
460
|
+
true
|
|
461
|
+
),
|
|
462
|
+
...messages.map((m) =>
|
|
463
|
+
m.message === LOST_CONNECTION_MESSAGE ? { ...m, visible: false } : m
|
|
464
|
+
)
|
|
465
|
+
];
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
425
469
|
async function make_prediction(
|
|
426
470
|
payload: Payload,
|
|
427
471
|
streaming = false
|
|
@@ -565,6 +609,35 @@
|
|
|
565
609
|
|
|
566
610
|
/* eslint-disable complexity */
|
|
567
611
|
function handle_status_update(message: StatusMessage): void {
|
|
612
|
+
if (message.broken && !broken_connection) {
|
|
613
|
+
messages = [
|
|
614
|
+
new_message(
|
|
615
|
+
"Broken Connection",
|
|
616
|
+
LOST_CONNECTION_MESSAGE,
|
|
617
|
+
-1,
|
|
618
|
+
"error",
|
|
619
|
+
null,
|
|
620
|
+
true
|
|
621
|
+
),
|
|
622
|
+
...messages
|
|
623
|
+
];
|
|
624
|
+
|
|
625
|
+
broken_connection = true;
|
|
626
|
+
setTimeout(reconnect, 1000);
|
|
627
|
+
}
|
|
628
|
+
if (message.session_not_found) {
|
|
629
|
+
messages = [
|
|
630
|
+
new_message(
|
|
631
|
+
"Session Not Found",
|
|
632
|
+
SESSION_NOT_FOUND_MESSAGE,
|
|
633
|
+
-1,
|
|
634
|
+
"error",
|
|
635
|
+
null,
|
|
636
|
+
true
|
|
637
|
+
),
|
|
638
|
+
...messages
|
|
639
|
+
];
|
|
640
|
+
}
|
|
568
641
|
const { fn_index, ...status } = message;
|
|
569
642
|
if (status.stage === "streaming" && status.time_limit) {
|
|
570
643
|
dep.inputs.forEach((id) => {
|
|
@@ -634,16 +707,11 @@
|
|
|
634
707
|
});
|
|
635
708
|
submit_map.delete(dep_index);
|
|
636
709
|
}
|
|
637
|
-
if (
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
];
|
|
643
|
-
}, 0);
|
|
644
|
-
wait_then_trigger_api_call(dep.id, payload.trigger_id, event_data);
|
|
645
|
-
user_left_page = false;
|
|
646
|
-
} else if (status.stage === "error") {
|
|
710
|
+
if (
|
|
711
|
+
status.stage === "error" &&
|
|
712
|
+
!broken_connection &&
|
|
713
|
+
!message.session_not_found
|
|
714
|
+
) {
|
|
647
715
|
if (status.message) {
|
|
648
716
|
const _message = status.message.replace(
|
|
649
717
|
MESSAGE_QUOTE_RE,
|
|
@@ -849,12 +917,6 @@
|
|
|
849
917
|
let is_screen_recording = writable(false);
|
|
850
918
|
|
|
851
919
|
onMount(() => {
|
|
852
|
-
document.addEventListener("visibilitychange", function () {
|
|
853
|
-
if (document.visibilityState === "hidden") {
|
|
854
|
-
user_left_page = true;
|
|
855
|
-
}
|
|
856
|
-
});
|
|
857
|
-
|
|
858
920
|
is_mobile_device =
|
|
859
921
|
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
|
860
922
|
navigator.userAgent
|
|
@@ -112,11 +112,30 @@
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
let tools: Tool[] = [];
|
|
115
|
+
let headers: string[] = [];
|
|
116
|
+
let mcp_json_sse: any;
|
|
117
|
+
let mcp_json_stdio: any;
|
|
118
|
+
let file_data_present = false;
|
|
119
|
+
|
|
120
|
+
const upload_file_mcp_server = {
|
|
121
|
+
command: "uvx",
|
|
122
|
+
args: [
|
|
123
|
+
"--from",
|
|
124
|
+
"gradio[mcp]",
|
|
125
|
+
"gradio",
|
|
126
|
+
"upload-mcp",
|
|
127
|
+
root,
|
|
128
|
+
"<UPLOAD_DIRECTORY>"
|
|
129
|
+
]
|
|
130
|
+
};
|
|
115
131
|
|
|
116
132
|
async function fetchMcpTools() {
|
|
117
133
|
try {
|
|
118
134
|
const response = await fetch(`${root}gradio_api/mcp/schema`);
|
|
119
135
|
const schema = await response.json();
|
|
136
|
+
file_data_present = schema
|
|
137
|
+
.map((tool: any) => tool.meta?.file_data_present)
|
|
138
|
+
.some((present: boolean) => present);
|
|
120
139
|
|
|
121
140
|
tools = schema.map((tool: any) => ({
|
|
122
141
|
name: tool.name,
|
|
@@ -124,6 +143,62 @@
|
|
|
124
143
|
parameters: tool.inputSchema?.properties || {},
|
|
125
144
|
expanded: false
|
|
126
145
|
}));
|
|
146
|
+
headers = schema.map((tool: any) => tool.meta?.headers || []).flat();
|
|
147
|
+
if (headers.length > 0) {
|
|
148
|
+
mcp_json_sse = {
|
|
149
|
+
mcpServers: {
|
|
150
|
+
gradio: {
|
|
151
|
+
url: mcp_server_url,
|
|
152
|
+
headers: headers.reduce((accumulator, current_key) => {
|
|
153
|
+
// @ts-ignore
|
|
154
|
+
accumulator[current_key] = "<YOUR_HEADER_VALUE>";
|
|
155
|
+
return accumulator;
|
|
156
|
+
}, {})
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
mcp_json_stdio = {
|
|
161
|
+
mcpServers: {
|
|
162
|
+
gradio: {
|
|
163
|
+
command: "npx",
|
|
164
|
+
args: [
|
|
165
|
+
"mcp-remote",
|
|
166
|
+
mcp_server_url,
|
|
167
|
+
"--transport",
|
|
168
|
+
"sse-only",
|
|
169
|
+
...headers
|
|
170
|
+
.map((header) => [
|
|
171
|
+
"--header",
|
|
172
|
+
`${header}: <YOUR_HEADER_VALUE>`
|
|
173
|
+
])
|
|
174
|
+
.flat()
|
|
175
|
+
]
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
} else {
|
|
180
|
+
mcp_json_sse = {
|
|
181
|
+
mcpServers: {
|
|
182
|
+
gradio: {
|
|
183
|
+
url: mcp_server_url
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
mcp_json_stdio = {
|
|
188
|
+
mcpServers: {
|
|
189
|
+
gradio: {
|
|
190
|
+
command: "npx",
|
|
191
|
+
args: ["mcp-remote", mcp_server_url, "--transport", "sse-only"]
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
if (file_data_present) {
|
|
196
|
+
mcp_json_sse.mcpServers.upload_files_to_gradio =
|
|
197
|
+
upload_file_mcp_server;
|
|
198
|
+
mcp_json_stdio.mcpServers.upload_files_to_gradio =
|
|
199
|
+
upload_file_mcp_server;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
127
202
|
} catch (error) {
|
|
128
203
|
console.error("Failed to fetch MCP tools:", error);
|
|
129
204
|
tools = [];
|
|
@@ -235,7 +310,7 @@
|
|
|
235
310
|
<div class="mcp-url">
|
|
236
311
|
<label
|
|
237
312
|
><span class="status-indicator active">●</span>MCP Server
|
|
238
|
-
URL</label
|
|
313
|
+
URL (SSE)</label
|
|
239
314
|
>
|
|
240
315
|
<div class="textbox">
|
|
241
316
|
<input type="text" readonly value={mcp_server_url} />
|
|
@@ -294,45 +369,42 @@
|
|
|
294
369
|
</div>
|
|
295
370
|
<p> </p>
|
|
296
371
|
|
|
297
|
-
<strong>
|
|
372
|
+
<strong>SSE Transport</strong>: To add this MCP to clients that
|
|
298
373
|
support SSE (e.g. Cursor, Windsurf, Cline), simply add the
|
|
299
|
-
following configuration to your MCP config
|
|
374
|
+
following configuration to your MCP config.
|
|
300
375
|
<p> </p>
|
|
301
376
|
<Block>
|
|
302
377
|
<code>
|
|
303
378
|
<div class="copy">
|
|
304
379
|
<CopyButton
|
|
305
|
-
code={JSON.stringify(
|
|
306
|
-
{
|
|
307
|
-
mcpServers: {
|
|
308
|
-
gradio: {
|
|
309
|
-
url: mcp_server_url
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
},
|
|
313
|
-
null,
|
|
314
|
-
2
|
|
315
|
-
)}
|
|
380
|
+
code={JSON.stringify(mcp_json_sse, null, 2)}
|
|
316
381
|
/>
|
|
317
382
|
</div>
|
|
318
383
|
<div>
|
|
319
|
-
<pre>{JSON.stringify(
|
|
320
|
-
{
|
|
321
|
-
mcpServers: {
|
|
322
|
-
gradio: {
|
|
323
|
-
url: mcp_server_url
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
},
|
|
327
|
-
null,
|
|
328
|
-
2
|
|
329
|
-
)}</pre>
|
|
384
|
+
<pre>{JSON.stringify(mcp_json_sse, null, 2)}</pre>
|
|
330
385
|
</div>
|
|
331
386
|
</code>
|
|
332
387
|
</Block>
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
388
|
+
{#if file_data_present}
|
|
389
|
+
<p> </p>
|
|
390
|
+
<em>Note about files</em>: Gradio MCP servers that have files
|
|
391
|
+
as inputs need the files as URLs, so the
|
|
392
|
+
<code>upload_files_to_gradio</code>
|
|
393
|
+
tool is included for your convenience. This tool can upload files
|
|
394
|
+
located in the specified <code>UPLOAD_DIRECTORY</code>
|
|
395
|
+
argument (an absolute path in your local machine) or any of its
|
|
396
|
+
subdirectories to the Gradio app. You can omit this tool if you
|
|
397
|
+
are fine manually uploading files yourself and providing the URLs.
|
|
398
|
+
Before using this tool, you must have
|
|
399
|
+
<a
|
|
400
|
+
href="https://docs.astral.sh/uv/getting-started/installation/"
|
|
401
|
+
target="_blank">uv installed</a
|
|
402
|
+
>.
|
|
403
|
+
<p> </p>
|
|
404
|
+
{/if}
|
|
405
|
+
|
|
406
|
+
<strong>STDIO Transport</strong>: For clients that only support
|
|
407
|
+
stdio (e.g. Claude Desktop), first
|
|
336
408
|
<a href="https://nodejs.org/en/download/" target="_blank"
|
|
337
409
|
>install Node.js</a
|
|
338
410
|
>. Then, you can use the following command:
|
|
@@ -341,43 +413,11 @@
|
|
|
341
413
|
<code>
|
|
342
414
|
<div class="copy">
|
|
343
415
|
<CopyButton
|
|
344
|
-
code={JSON.stringify(
|
|
345
|
-
{
|
|
346
|
-
mcpServers: {
|
|
347
|
-
gradio: {
|
|
348
|
-
command: "npx",
|
|
349
|
-
args: [
|
|
350
|
-
"mcp-remote",
|
|
351
|
-
mcp_server_url,
|
|
352
|
-
"--transport",
|
|
353
|
-
"sse-only"
|
|
354
|
-
]
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
},
|
|
358
|
-
null,
|
|
359
|
-
2
|
|
360
|
-
)}
|
|
416
|
+
code={JSON.stringify(mcp_json_stdio, null, 2)}
|
|
361
417
|
/>
|
|
362
418
|
</div>
|
|
363
419
|
<div>
|
|
364
|
-
<pre>{JSON.stringify(
|
|
365
|
-
{
|
|
366
|
-
mcpServers: {
|
|
367
|
-
gradio: {
|
|
368
|
-
command: "npx",
|
|
369
|
-
args: [
|
|
370
|
-
"mcp-remote",
|
|
371
|
-
mcp_server_url,
|
|
372
|
-
"--transport",
|
|
373
|
-
"sse-only"
|
|
374
|
-
]
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
},
|
|
378
|
-
null,
|
|
379
|
-
2
|
|
380
|
-
)}</pre>
|
|
420
|
+
<pre>{JSON.stringify(mcp_json_stdio, null, 2)}</pre>
|
|
381
421
|
</div>
|
|
382
422
|
</code>
|
|
383
423
|
</Block>
|
|
@@ -453,21 +493,22 @@
|
|
|
453
493
|
{/if}
|
|
454
494
|
|
|
455
495
|
{#if current_language !== "mcp"}
|
|
456
|
-
{#each dependencies as dependency
|
|
496
|
+
{#each dependencies as dependency}
|
|
457
497
|
{#if dependency.show_api && info.named_endpoints["/" + dependency.api_name]}
|
|
458
498
|
<div class="endpoint-container">
|
|
459
499
|
<CodeSnippet
|
|
460
|
-
named={true}
|
|
461
500
|
endpoint_parameters={info.named_endpoints[
|
|
462
501
|
"/" + dependency.api_name
|
|
463
502
|
].parameters}
|
|
464
503
|
{dependency}
|
|
465
|
-
{dependency_index}
|
|
466
504
|
{current_language}
|
|
467
505
|
{root}
|
|
468
506
|
{space_id}
|
|
469
507
|
{username}
|
|
470
508
|
api_prefix={app.api_prefix}
|
|
509
|
+
api_description={info.named_endpoints[
|
|
510
|
+
"/" + dependency.api_name
|
|
511
|
+
].description}
|
|
471
512
|
/>
|
|
472
513
|
|
|
473
514
|
<ParametersSnippet
|
|
@@ -15,14 +15,13 @@
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export let dependency: Dependency;
|
|
18
|
-
export let dependency_index: number;
|
|
19
18
|
export let root: string;
|
|
20
19
|
export let api_prefix: string;
|
|
21
20
|
export let space_id: string | null;
|
|
22
21
|
export let endpoint_parameters: any;
|
|
23
|
-
export let named: boolean;
|
|
24
22
|
export let username: string | null;
|
|
25
23
|
export let current_language: "python" | "javascript" | "bash";
|
|
24
|
+
export let api_description: string | null = null;
|
|
26
25
|
|
|
27
26
|
let python_code: HTMLElement;
|
|
28
27
|
let js_code: HTMLElement;
|
|
@@ -42,11 +41,10 @@
|
|
|
42
41
|
</script>
|
|
43
42
|
|
|
44
43
|
<div class="container">
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
{/if}
|
|
44
|
+
<EndpointDetail
|
|
45
|
+
api_name={dependency.api_name}
|
|
46
|
+
description={api_description}
|
|
47
|
+
/>
|
|
50
48
|
{#if current_language === "python"}
|
|
51
49
|
<Block>
|
|
52
50
|
<code>
|
|
@@ -99,9 +97,9 @@ const example{component} = await response_{i}.blob();
|
|
|
99
97
|
const client = await Client.connect(<span class="token string"
|
|
100
98
|
>"{space_id || root}"</span
|
|
101
99
|
>{#if username !== null}, {auth: ["{username}", **password**]}{/if});
|
|
102
|
-
const result = await client.predict(
|
|
103
|
-
|
|
104
|
-
|
|
100
|
+
const result = await client.predict(<span class="api-name"
|
|
101
|
+
>"/{dependency.api_name}"</span
|
|
102
|
+
>, { <!--
|
|
105
103
|
-->{#each endpoint_parameters as { label, parameter_name, type, python_type, component, example_input, serializer }, i}<!--
|
|
106
104
|
-->{#if blob_components.includes(component)}<!--
|
|
107
105
|
-->
|
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
export let api_name: string | null = null;
|
|
3
|
-
export let
|
|
4
|
-
export let named: boolean;
|
|
3
|
+
export let description: string | null = null;
|
|
5
4
|
</script>
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
{:else}
|
|
13
|
-
<h3>
|
|
14
|
-
fn_index:
|
|
15
|
-
<span class="post">{fn_index}</span>
|
|
16
|
-
</h3>
|
|
17
|
-
{/if}
|
|
6
|
+
<h3>
|
|
7
|
+
API name:
|
|
8
|
+
<span class="post">{"/" + api_name}</span>
|
|
9
|
+
<span class="desc">{description}</span>
|
|
10
|
+
</h3>
|
|
18
11
|
|
|
19
12
|
<style>
|
|
20
13
|
h3 {
|
|
@@ -34,4 +27,10 @@
|
|
|
34
27
|
color: var(--color-accent);
|
|
35
28
|
font-weight: var(--weight-semibold);
|
|
36
29
|
}
|
|
30
|
+
|
|
31
|
+
.desc {
|
|
32
|
+
color: var(--body-text-color-subdued);
|
|
33
|
+
font-size: var(--text-lg);
|
|
34
|
+
margin-top: var(--size-1);
|
|
35
|
+
}
|
|
37
36
|
</style>
|
package/src/init.ts
CHANGED
|
@@ -114,8 +114,14 @@ export function create_components(initial_layout: ComponentMeta | undefined): {
|
|
|
114
114
|
if (instance_map) {
|
|
115
115
|
// re-render in reload mode
|
|
116
116
|
components.forEach((c) => {
|
|
117
|
-
if (c.props.value == null && c.
|
|
118
|
-
|
|
117
|
+
if (c.props.value == null && c.key) {
|
|
118
|
+
// If the component has a key, we preserve its value by finding a matching instance with the same key
|
|
119
|
+
const matching_instance = Object.values(instance_map).find(
|
|
120
|
+
(instance) => instance.key === c.key
|
|
121
|
+
);
|
|
122
|
+
if (matching_instance) {
|
|
123
|
+
c.props.value = matching_instance.props.value;
|
|
124
|
+
}
|
|
119
125
|
}
|
|
120
126
|
});
|
|
121
127
|
}
|