diff --git a/.changeset/empty-moons-stick.md b/.changeset/empty-moons-stick.md new file mode 100644 index 000000000000..586026c0b090 --- /dev/null +++ b/.changeset/empty-moons-stick.md @@ -0,0 +1,6 @@ +--- +"@gradio/app": patch +"gradio": patch +--- + +feat:Support Bash in Api Recorder diff --git a/.config/.prettierignore b/.config/.prettierignore index 34269d090134..40c07570847c 100644 --- a/.config/.prettierignore +++ b/.config/.prettierignore @@ -30,4 +30,5 @@ sweep.yaml **/playwright/.cache/**/* **/theme/src/pollen.css **/venv/** -../js/app/src/api_docs/CodeSnippet.svelte \ No newline at end of file +../js/app/src/api_docs/CodeSnippet.svelte +../js/app/src/api_docs/RecordingSnippet.svelte \ No newline at end of file diff --git a/guides/08_gradio-clients-and-lite/03_querying-gradio-apps-with-curl.md b/guides/08_gradio-clients-and-lite/03_querying-gradio-apps-with-curl.md index e8be790f5645..051f520696ef 100644 --- a/guides/08_gradio-clients-and-lite/03_querying-gradio-apps-with-curl.md +++ b/guides/08_gradio-clients-and-lite/03_querying-gradio-apps-with-curl.md @@ -15,21 +15,34 @@ $ curl -X POST https://abidlabs-en2fr.hf.space/call/predict -H "Content-Type: ap "data": ["Hello, my friend."] }' -> {"event_id": $EVENT_ID} +>> {"event_id": $EVENT_ID} ``` ```bash $ curl -N https://abidlabs-en2fr.hf.space/call/predict/$EVENT_ID -> event: complete -> data: ["Bonjour, mon ami."] +>> event: complete +>> data: ["Bonjour, mon ami."] ``` -Tip: making a prediction and getting a result requires two `curl` requests: a `POST` and a `GET`. The `POST` request returns an `EVENT_ID` and prints it to the console , which is used in the second `GET` request to fetch the results. We'll cover these two steps in more detail in the Guide below. +Note: making a prediction and getting a result requires two `curl` requests: a `POST` and a `GET`. The `POST` request returns an `EVENT_ID` and prints it to the console, which is used in the second `GET` request to fetch the results. You can combine these into a single command using `awk` and `read` to parse the results of the first command and pipe into the second, like this: + +```bash +$ curl -X POST https://abidlabs-en2fr.hf.space/call/predict -H "Content-Type: application/json" -d '{ + "data": ["Hello, my friend."] +}' \ + | awk -F'"' '{ print $4}' \ + | read EVENT_ID; curl -N https://abidlabs-en2fr.hf.space/call/predict/$EVENT_ID + +>> event: complete +>> data: ["Bonjour, mon ami."] +``` + +In the rest of this Guide, we'll explain these two steps in more detail and provide additional examples of querying Gradio apps with `curl`. -**Prerequisites**: For this Guide, you do _not_ need to know the `gradio` library in great detail. However, it is helpful to have general familiarity with Gradio's concepts of input and output components. +**Prerequisites**: For this Guide, you do _not_ need to know how to build Gradio apps in great detail. However, it is helpful to have general familiarity with Gradio's concepts of input and output components. ## Installation @@ -90,7 +103,7 @@ Here: When you make this `POST` request successfully, you will get an event id that is printed to the terminal in this format: ```bash -> {"event_id": $EVENT_ID} +>> {"event_id": $EVENT_ID} ``` This `EVENT_ID` will be needed in the subsequent `curl` request to fetch the results of the prediction. @@ -129,7 +142,7 @@ $ curl -X POST https://private-space.hf.space/call/predict -H "Content-Type: app **Files** -If your Gradio application requires file inputs, you can pass in files as URLs through `curl`. The URL needs to be enclosed in a dictionary in this format: +If you are using `curl` to query a Gradio application that requires file inputs, the files *need* to be provided as URLs, and The URL needs to be enclosed in a dictionary in this format: ```bash {"path": $URL} diff --git a/js/app/src/api_docs/ApiBanner.svelte b/js/app/src/api_docs/ApiBanner.svelte index 1aa27a9686c3..9507ea678dc2 100644 --- a/js/app/src/api_docs/ApiBanner.svelte +++ b/js/app/src/api_docs/ApiBanner.svelte @@ -6,7 +6,6 @@ export let root: string; export let api_count: number; - export let current_language: "python" | "javascript" | "bash"; const dispatch = createEventDispatcher(); @@ -22,15 +21,13 @@ {api_count} API endpoint{#if api_count > 1}s{/if}
- {#if current_language !== "bash"} - - {/if} +
diff --git a/js/app/src/api_docs/ApiDocs.svelte b/js/app/src/api_docs/ApiDocs.svelte index cfcffe40671f..cc5f3bb53e90 100644 --- a/js/app/src/api_docs/ApiDocs.svelte +++ b/js/app/src/api_docs/ApiDocs.svelte @@ -27,6 +27,8 @@ "https://www.gradio.app/guides/getting-started-with-the-js-client"; const py_docs = "https://www.gradio.app/guides/getting-started-with-the-python-client"; + const bash_docs = + "https://www.gradio.app/guides/querying-gradio-apps-with-curl"; const spaces_docs_suffix = "#connecting-to-a-hugging-face-space"; let api_count = dependencies.filter( @@ -95,12 +97,7 @@ {#if info} {#if api_count}
@@ -123,7 +120,7 @@ {/each}
- {#if api_calls.length && current_language !== "bash"} + {#if api_calls.length}

{#if current_language == "python" || current_language == "javascript"} - 1. Install the {current_language} client if you don't already have it installed. + 1. Install the + {current_language} + client (docs) if you don't already have it installed. {:else} 1. Confirm that you have cURL installed on your system. {/if} @@ -174,27 +174,34 @@ placeholder values with your own input data. {#if space_id}If this is a private Space, you may need to pass your Hugging Face token as well (read more).{/if} - {#if current_language == "bash"}Note: making a prediction and - getting a result requires 2 requests: a + + Or + + to automatically generate your API requests. + {#if current_language == "bash"}
 
Note: making a + prediction and getting a result requires + 2 requests: a POST and a GET request. The POST request returns an EVENT_ID, which is used in the second - GET request to fetch the results. - {:else}Or - - to automatically generate your API requests. + GET request to fetch the results. In these snippets, + we've used awk and read to parse the + results, combining these two requests into one command for ease of + use. See curl docs. {/if} // blob in '{label}' {component} component{:else}{represent_value(example_input, python_type.type, "bash")}{#if i < endpoint_parameters.length - 1}, {/if} {/each} -]{"}"}' -

- - - - - -
- -
- -
-
curl -N {root}call/{dependency.api_name}/$EVENT_ID 
+]{"}"}' \ + | awk -F'"' '{"{"} print $4{"}"}' \ + | read EVENT_ID; curl -N {root}call/{dependency.api_name}/$EVENT_ID
diff --git a/js/app/src/api_docs/RecordingSnippet.svelte b/js/app/src/api_docs/RecordingSnippet.svelte index 4d462287d37e..2f0300e6a005 100644 --- a/js/app/src/api_docs/RecordingSnippet.svelte +++ b/js/app/src/api_docs/RecordingSnippet.svelte @@ -10,8 +10,11 @@ export let root: string; export let current_language: "python" | "javascript" | "bash"; - let code: HTMLElement; - let code_text: string; + let python_code: HTMLElement; + let python_code_text: string; + let js_code: HTMLElement; + let bash_code: HTMLElement; + export let api_calls: Payload[] = []; async function get_info(): Promise<{ @@ -26,8 +29,9 @@ let endpoints_info: any; let py_zipped: { call: string; api_name: string }[] = []; let js_zipped: { call: string; api_name: string }[] = []; + let bash_zipped: { call: string; api_name: string }[] = []; - function format_api_call(call: Payload, lang: "py" | "js"): string { + function format_api_call(call: Payload, lang: "py" | "js" | "bash"): string { const api_name = `/${dependencies[call.fn_index].api_name}`; // If an input is undefined (distinct from null) then it corresponds to a State component. let call_data_excluding_state = call.data.filter( @@ -49,12 +53,19 @@ python_type, "py" )}`; + } else if (lang === "js") { + return ` ${param_name}: ${represent_value( + param as string, + python_type, + "js" + )}`; + } else if (lang === "bash") { + return ` ${represent_value( + param as string, + python_type, + "bash" + )}`; } - return ` ${param_name}: ${represent_value( - param as string, - python_type, - "js" - )}`; } return ` ${represent_value(param as string, undefined, lang)}`; }) @@ -63,8 +74,11 @@ if (params) { if (lang === "py") { return `${params},\n`; + } else if (lang === "js") { + return `{\n${params},\n}`; + } else if (lang === "bash") { + return `\n${params}\n`; } - return ` {\n${params},\n}`; } if (lang === "py") { return ""; @@ -81,6 +95,9 @@ let js_api_calls: string[] = api_calls.map((call) => format_api_call(call, "js") ); + let bash_api_calls: string[] = api_calls.map((call) => + format_api_call(call, "bash") + ); let api_names: string[] = api_calls.map( (call) => dependencies[call.fn_index].api_name || "" ); @@ -92,21 +109,26 @@ call, api_name: api_names[index] })); + bash_zipped = bash_api_calls.map((call, index) => ({ + call, + api_name: api_names[index] + })); await tick(); - code_text = code.innerText; + + python_code_text = python_code.innerText; });
- -
- -
-
- {#if current_language === "python"} + {#if current_language === "python"} + +
+ +
+
from gradio_client import Client, file
@@ -119,20 +141,42 @@ client."/{api_name}"
 )
 {/each}
- {:else if current_language === "javascript"} +
+
+ {:else if current_language === "javascript"} + +
+ +
+
import { Client } from "@gradio/client";
 
 const app = await Client.connect("{short_root}");
-{#each js_zipped as { call, api_name }}
-await client.predict(
-	"/{api_name}"
+await client.predict(
+  "/{api_name}"{#if call},{/if}{call});
-						{/each}
{/if} -
+ {/each} +
+
+ {:else if current_language === "bash"} + +
+ +
+
+ {#each bash_zipped as { call, api_name }} +
curl -X POST {short_root}call/{api_name} -s -H "Content-Type: application/json" -d '{"{"} 
+	"data": [{call}]{"}"}' \
+  | awk -F'"' '{"{"} print $4{"}"}' \
+  | read EVENT_ID; curl -N {short_root}call/{api_name}/$EVENT_ID
+
+ {/each} +
+
+ {/if}