Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
3107ab9
changes
aliabid94 Oct 13, 2022
352ca30
change
aliabid94 Oct 13, 2022
dc3930e
changes
aliabid94 Oct 13, 2022
f9c0bee
changes
aliabid94 Oct 13, 2022
861e610
changes
aliabid94 Oct 13, 2022
7bc9ee6
Update colab.html
aliabid94 Oct 13, 2022
9f51aa3
update version
abidlabs Oct 13, 2022
782a2a2
changes
aliabid94 Oct 18, 2022
90ebf80
changes
aliabid94 Oct 18, 2022
b9d945b
Update gradio/templates/colab.html
aliabid94 Oct 18, 2022
cca6af4
changes
aliabid94 Oct 18, 2022
0c78d1b
changes
aliabid94 Oct 18, 2022
d366385
changers
aliabid94 Oct 18, 2022
aae670f
changes
aliabid94 Oct 31, 2022
e0f74e4
changes
aliabid94 Oct 31, 2022
384f37a
changes
aliabid94 Oct 31, 2022
93cf890
changes
aliabid94 Nov 1, 2022
6c341fb
changes
aliabid94 Nov 1, 2022
7324d0d
changes
aliabid94 Nov 1, 2022
f75b0a1
changes
aliabid94 Nov 1, 2022
7da5ef2
changes
aliabid94 Nov 1, 2022
4a26ff0
changes
aliabid94 Nov 1, 2022
fd0dc55
changes
aliabid94 Nov 1, 2022
4551e21
changes
aliabid94 Nov 1, 2022
5bb670e
changes
aliabid94 Nov 1, 2022
99204bd
changes
aliabid94 Nov 1, 2022
8a8f12f
changes
aliabid94 Nov 1, 2022
01f892f
changes
aliabid94 Nov 1, 2022
a70c64e
changes
aliabid94 Nov 1, 2022
0ca1f6f
changes
aliabid94 Nov 1, 2022
a80a307
changes
aliabid94 Nov 1, 2022
5047a67
changes
aliabid94 Nov 1, 2022
b386769
changes
aliabid94 Nov 1, 2022
fc37ca2
changes
aliabid94 Nov 1, 2022
03e48d7
changes
aliabid94 Nov 1, 2022
2146db4
Merge remote-tracking branch 'origin' into rename_api_for_colab
aliabid94 Nov 1, 2022
7a13c82
changes
aliabid94 Nov 1, 2022
8468da8
changes
aliabid94 Nov 1, 2022
83793ea
changes
aliabid94 Nov 1, 2022
17c6835
revert
aliabid94 Nov 1, 2022
80217d0
changes
aliabid94 Nov 1, 2022
d6c8896
changes
aliabid94 Nov 1, 2022
abf30b4
changes
aliabid94 Nov 1, 2022
1daa67f
Merge branch 'main' into rename_api_for_colab
abidlabs Nov 1, 2022
28a0afa
strings
abidlabs Nov 2, 2022
87e4320
formatting
abidlabs Nov 2, 2022
02a4c8b
changes
aliabid94 Nov 3, 2022
2871509
changes
aliabid94 Nov 3, 2022
b252da4
changes
aliabid94 Nov 3, 2022
be28836
changes
aliabid94 Nov 3, 2022
5aad65c
changes
aliabid94 Nov 3, 2022
80b3a0e
changes
aliabid94 Nov 3, 2022
84867d1
changes
aliabid94 Nov 3, 2022
83946ee
changes
aliabid94 Nov 3, 2022
7ca1819
changes
aliabid94 Nov 3, 2022
b16d6b1
changes
aliabid94 Nov 3, 2022
7e8bd26
Merge branch 'main' into rename_api_for_colab
aliabid94 Nov 3, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ No changes to highlight.
* Carousel component is now deprecated by [@abidlabs](https://github.com/abidlabs) in [PR 2434](https://github.com/gradio-app/gradio/pull/2434)
* Build Gradio from source in ui tests by by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 2440](https://github.com/gradio-app/gradio/pull/2440)
* Change "return ValueError" to "raise ValueError" by [@vzakharov](https://github.com/vzakharov) in [PR 2445](https://github.com/gradio-app/gradio/pull/2445)
* Gradio is now embedded directly in colab without requiring the share link by [@aliabid94](https://github.com/aliabid94) in [PR 2455](https://github.com/gradio-app/gradio/pull/2455)
* Stops a gradio launch from hogging a port even after it's been killed [@aliabid94](https://github.com/aliabid94) in [PR 2453](https://github.com/gradio-app/gradio/pull/2453)
* Fix embedded interfaces on touch screen devices by [@aliabd](https://github.com/aliabd) in [PR 2457](https://github.com/gradio-app/gradio/pull/2457)
* Upload all demos to spaces by [@aliabd](https://github.com/aliabd) in [PR 2281](https://github.com/gradio-app/gradio/pull/2281)
Expand Down
78 changes: 46 additions & 32 deletions gradio/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from typing import TYPE_CHECKING, Any, AnyStr, Callable, Dict, List, Optional, Tuple

import anyio
import pkg_resources
import requests
from anyio import CapacityLimiter

Expand Down Expand Up @@ -147,6 +148,8 @@ def set_event_trigger(
if not isinstance(outputs, list):
outputs = [outputs]
Context.root_block.fns.append(BlockFunction(fn, preprocess, postprocess))
if queue:
Context.root_block.has_any_queue = True
if api_name is not None:
api_name_ = utils.append_unique_suffix(
api_name, [dep["api_name"] for dep in Context.root_block.dependencies]
Expand Down Expand Up @@ -433,6 +436,7 @@ def __init__(
self.save_to = None
self.theme = theme
self.requires_permissions = False # TODO: needs to be implemented
self.has_any_queue = False
self.encrypt = False
self.share = False
self.enable_queue = None
Expand Down Expand Up @@ -487,18 +491,6 @@ def __init__(
}
utils.initiated_analytics(data)

@property
def share(self):
return self._share

@share.setter
def share(self, value: Optional[bool]):
# If share is not provided, it is set to True when running in Google Colab, or False otherwise
if value is None:
self._share = True if utils.colab_check() else False
else:
self._share = value

@classmethod
def from_config(cls, config: dict, fns: List[Callable]) -> Blocks:
"""Factory method that creates a Blocks from a config and list of functions."""
Expand Down Expand Up @@ -960,6 +952,8 @@ def queue(
demo.queue(concurrency_count=3)
demo.launch()
"""
if default_enabled:
self.has_any_queue = True
self.enable_queue = default_enabled
self._queue = queue.Queue(
live_updates=status_update_rate == "auto",
Expand Down Expand Up @@ -1080,7 +1074,6 @@ def reverse(text):
)

self.config = self.get_config_file()
self.share = share
self.encrypt = encrypt
self.max_threads = max(
self._queue.max_thread_count if self.enable_queue else 0, max_threads
Expand Down Expand Up @@ -1127,26 +1120,38 @@ def reverse(text):
)
utils.launch_counter()

self.is_colab = utils.colab_check()
self.share = (
share
if share is not None
else True
if self.is_colab and self.has_any_queue
Comment thread
aliabid94 marked this conversation as resolved.
Outdated
else False
)

# If running in a colab or not able to access localhost,
# a shareable link must be created.
is_colab = utils.colab_check()
if is_colab or (_frontend and not networking.url_ok(self.local_url)):
if not self.share:
raise ValueError(
"When running in Google Colab or when localhost is not accessible, a shareable link must be created. Please set share=True."
)
if is_colab and not quiet:
if debug:
print(strings.en["COLAB_DEBUG_TRUE"])
else:
print(strings.en["COLAB_DEBUG_FALSE"])
else:
print(
strings.en["RUNNING_LOCALLY_SEPARATED"].format(
self.protocol, self.server_name, self.server_port
)

if self.is_colab and not quiet:
if debug:
print(strings.en["COLAB_DEBUG_TRUE"])
else:
print(strings.en["COLAB_DEBUG_FALSE"])

if self.is_colab and self.has_any_queue and not self.share:
raise ValueError(
"When using queueing in Colab, a shareable link must be created. Please set share=True."
)
if is_colab and self.requires_permissions:
if _frontend and (not networking.url_ok(self.local_url)) and (not self.share):
raise ValueError(
"When localhost is not accessible, a shareable link must be created. Please set share=True."
)
print(
strings.en["RUNNING_LOCALLY_SEPARATED"].format(
self.protocol, self.server_name, self.server_port
)
)
if self.is_colab and self.requires_permissions:
print(strings.en["MEDIA_PERMISSIONS_IN_COLAB"])

if self.share:
Expand Down Expand Up @@ -1188,12 +1193,21 @@ def reverse(text):

if self.share:
while not networking.url_ok(self.share_url):
time.sleep(1)
time.sleep(0.2)
display(
HTML(
f'<div><iframe src="{self.share_url}" width="{self.width}" height="{self.height}" allow="autoplay; camera; microphone; clipboard-read; clipboard-write;" frameborder="0" allowfullscreen></iframe></div>'
)
)
elif self.is_colab:
with open(
pkg_resources.resource_filename(
"gradio", "templates/colab.html"
)
) as colab_file:
colab_html = colab_file.read()
colab_html = colab_html.replace("$PORT", str(self.server_port))
display(HTML(colab_html))
else:
display(
HTML(
Expand All @@ -1206,7 +1220,7 @@ def reverse(text):
if getattr(self, "analytics_enabled", False):
data = {
"launch_method": "browser" if inbrowser else "inline",
"is_google_colab": is_colab,
"is_google_colab": self.is_colab,
"is_sharing_on": self.share,
"share_url": self.share_url,
"ip_address": self.ip_address,
Expand Down
4 changes: 3 additions & 1 deletion gradio/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,8 @@ async def run_predict(
)
return output

@app.post("/run/{api_name}", dependencies=[Depends(login_check)])
Comment thread
aliabid94 marked this conversation as resolved.
@app.post("/run/{api_name}/", dependencies=[Depends(login_check)])
@app.post("/api/{api_name}", dependencies=[Depends(login_check)])
@app.post("/api/{api_name}/", dependencies=[Depends(login_check)])
async def predict(
Expand All @@ -328,7 +330,7 @@ async def predict(
if body.fn_index is None:
return JSONResponse(
content={
"error": f"This app has no endpoint /api/{api_name}/."
"error": f"This app has no endpoint /run/{api_name}/."
Copy link
Copy Markdown
Member

@abidlabs abidlabs Oct 13, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like we are migrating from "/api" to "/run" as the official API endpoint. Let's make sure to update the "view API" page as well.

Also this is a bit of an edge case but what happens if a user-supplied api_name includes the string "api". Perhaps we can print a warning to users letting them know that their app will not work inside Colab

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does colab block any call with a substring "api"? Anyways, even if they create a custom named API, the frontend does not use the names API's, so gradio UI will still work fine.

},
status_code=500,
)
Expand Down
27 changes: 27 additions & 0 deletions gradio/templates/colab.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<script>
document.querySelector("base").href = "https://localhost:$PORT";

function rehydrate() {
for (const script of document.querySelectorAll("script")) {
const newScript = document.createElement('script')
newScript.type = script.type;
newScript.src = script.src;
newScript.textContent = script.textContent;
const head = document.getElementsByTagName('head')[0];
if (script.textContent.includes("window.gradio_config =")) {
const config_re = /^\s*window.gradio_config\s*=\s*({[^]+})\s*;\s*$/;
window.gradio_config = JSON.parse(config_re.exec(script.textContent)[1]);
}
head.appendChild(newScript);
newScript.remove();
}
}
fetch(".")
.then((x) => x.text())
.then((html) => {
document.body.innerHTML = html;
})
.then(() => rehydrate()).catch(() => {
document.body.innerHTML = `<h1 color="red">There was a problem running Gradio in colab, please rerun the block with gradio==3.5 and file an issue on GitHub if it doesn't not work.</h1>`;
Comment thread
aliabid94 marked this conversation as resolved.
Outdated
});
</script>
2 changes: 1 addition & 1 deletion gradio/version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.5
3.0.1b150
17 changes: 11 additions & 6 deletions test/test_blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,23 @@ def test_set_share(self):
demo.share = True
self.assertTrue(demo.share)

@patch("gradio.networking.setup_tunnel")
@patch("gradio.utils.colab_check")
def test_set_share_in_colab(self, mock_colab_check):
def test_set_share_in_colab(self, mock_colab_check, mock_setup_tunnel):
mock_colab_check.return_value = True
mock_setup_tunnel.return_value = "http://localhost:7860/"
with gr.Blocks() as demo:
# self.share is False when instantiating the class
self.assertFalse(demo.share)
# default is True, if share is None and colab_check is true
demo.share = None
self.assertTrue(demo.share)
# if set to True, it doesn't change
demo.share = True
# share default is False, if share is None in colab and no queueing
demo.launch(prevent_thread_lock=True)
self.assertFalse(demo.share)
demo.close()
# share becomes true, if share is None in colab with queueing
demo.queue()
demo.launch(prevent_thread_lock=True)
self.assertTrue(demo.share)
demo.close()

def test_xray(self):
def fake_func():
Expand Down
2 changes: 1 addition & 1 deletion test/test_interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def test_launch_colab_share(self, mock_colab_check):
mock_colab_check.return_value = True
interface = Interface(lambda x: x, "textbox", "label")
_, _, share_url = interface.launch(prevent_thread_lock=True)
self.assertIsNotNone(share_url)
self.assertIsNone(share_url)
interface.close()

@mock.patch("gradio.utils.colab_check")
Expand Down
6 changes: 3 additions & 3 deletions ui/packages/app/src/ApiDocs.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,17 @@
class="bg-gray-50 border border-gray-100 dark:bg-gray-800 dark:border-gray-700 p-6 rounded"
>
<h3 class="text-3xl text-amber-500 font-semibold mb-2">
POST /api/{dependency.api_name}
POST /run/{dependency.api_name}
</h3>
<div class="mb-6">
Full URL: <span class="underline"
>{root}api/{dependency.api_name}</span
>{root}run/{dependency.api_name}</span
>
<button
class="ml-1 px-2 py-0.5 rounded bg-gray-200 dark:bg-gray-700"
on:click={() => {
navigator.clipboard.writeText(
root + "api/" + dependency.api_name
root + "run/" + dependency.api_name
);
just_copied = d;
setTimeout(() => {
Expand Down
2 changes: 1 addition & 1 deletion ui/packages/app/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export const fn =
function send_message(fn: number, data: any) {
ws_map.get(fn)?.send(JSON.stringify(data));
}
var ws_endpoint = api_endpoint === "api/" ? location.href : api_endpoint;
var ws_endpoint = api_endpoint === "run/" ? location.href : api_endpoint;
var ws_protocol = ws_endpoint.startsWith("https") ? "wss:" : "ws:";
if (is_space) {
const SPACE_REGEX = /embed\/(.*)\/\+/g;
Expand Down
2 changes: 1 addition & 1 deletion ui/packages/app/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ function mount_app(
});
} else {
let session_hash = Math.random().toString(36).substring(2);
config.fn = fn(session_hash, config.root + "api/", config.is_space);
config.fn = fn(session_hash, config.root + "run/", config.is_space);

new Blocks({
target: wrapper,
Expand Down
4 changes: 2 additions & 2 deletions ui/packages/app/test/blocks_inputs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function mock_demo(page: Page, demo: string) {
}

function mock_api(page: Page, body: Array<unknown>) {
return page.route("**/api/predict/", (route) => {
return page.route("**/run/predict/", (route) => {
const id = JSON.parse(route.request().postData()!).fn_index;
return route.fulfill({
headers: {
Expand All @@ -39,7 +39,7 @@ test("renders the correct elements", async ({ page }) => {
await textboxTwo.fill("dawood");
await Promise.all([
page.click('text="Submit"'),
page.waitForResponse("**/api/predict/")
page.waitForResponse("**/run/predict/")
]);

await expect(await page.getByLabel("Output")).toHaveValue("hi dawood");
Expand Down
4 changes: 2 additions & 2 deletions ui/packages/app/test/blocks_kinematics.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function mock_demo(page: Page, demo: string) {
}

function mock_api(page: Page, body: Array<unknown>) {
return page.route("**/api/predict/", (route) => {
return page.route("**/run/predict/", (route) => {
const id = JSON.parse(route.request().postData()!).fn_index;
return route.fulfill({
headers: {
Expand All @@ -32,6 +32,6 @@ test("renders the correct elements", async ({ page }) => {

await Promise.all([
page.click("button"),
page.waitForResponse("**/api/predict/")
page.waitForResponse("**/run/predict/")
]);
});
2 changes: 1 addition & 1 deletion ui/packages/app/test/blocks_page_load.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function mock_demo(page: Page, demo: string) {
}

function mock_api(page: Page, body: Array<unknown>) {
return page.route("**/api/predict/", (route) => {
return page.route("**/run/predict/", (route) => {
const id = JSON.parse(route.request().postData()!).fn_index;
return route.fulfill({
headers: {
Expand Down
4 changes: 2 additions & 2 deletions ui/packages/app/test/blocks_xray.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function mock_demo(page: Page, demo: string) {
}

function mock_api(page: Page, body: Array<unknown>) {
return page.route("**/api/predict/", (route) => {
return page.route("**/run/predict/", (route) => {
const id = JSON.parse(route.request().postData()!).fn_index;
return route.fulfill({
headers: {
Expand Down Expand Up @@ -65,7 +65,7 @@ test("can run an api request and display the data", async ({ page }) => {

await Promise.all([
run_button.click(),
page.waitForResponse("**/api/predict/")
page.waitForResponse("**/run/predict/")
]);

const json = await page.getByTestId("json").first();
Expand Down
4 changes: 2 additions & 2 deletions ui/packages/app/test/input_output.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function mock_demo(page: Page, demo: string) {
}

function mock_api(page: Page, body: Array<unknown>) {
return page.route("**/api/predict/", (route) => {
return page.route("**/run/predict/", (route) => {
const id = JSON.parse(route.request().postData()!).fn_index;
return route.fulfill({
headers: {
Expand All @@ -35,7 +35,7 @@ test("a component acts as both input and output", async ({ page }) => {
await textbox.fill("test");
await Promise.all([
page.click("button"),
page.waitForResponse("**/api/predict/")
page.waitForResponse("**/run/predict/")
]);
await expect(await textbox).toHaveValue("tset");
});
4 changes: 2 additions & 2 deletions ui/packages/app/test/kitchen_sink.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function mock_demo(page: Page, demo: string) {
}

function mock_api(page: Page, body: Array<unknown>) {
return page.route("**/api/predict/", (route) => {
return page.route("**/run/predict/", (route) => {
const id = JSON.parse(route.request().postData()!).fn_index;
return route.fulfill({
headers: {
Expand Down Expand Up @@ -215,7 +215,7 @@ test("test outputs", async ({ page }) => {

await Promise.all([
submit_button.click(),
page.waitForResponse("**/api/predict/")
page.waitForResponse("**/run/predict/")
]);

const textbox = await page.getByLabel("Textbox").nth(2);
Expand Down
Loading