Skip to content

Instantly share code, notes, and snippets.

@hamelsmu
Created November 7, 2022 17:53
Show Gist options
  • Save hamelsmu/088381899b3308bdd7437ff5960e23f9 to your computer and use it in GitHub Desktop.
Save hamelsmu/088381899b3308bdd7437ff5960e23f9 to your computer and use it in GitHub Desktop.
A demo of creating a gradio app with nbdev
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"id": "8c68f03e-620c-46a9-a7ec-a6cde27043cd",
"metadata": {},
"source": [
"# Hugging Face Spaces From A Notebook\n",
"\n",
"> A demo of using nbdev with Hugging Face Spaces"
]
},
{
"cell_type": "markdown",
"id": "96483373-4ae1-49b2-85ed-ceee8456df19",
"metadata": {},
"source": [
"## 1. Create a Gradio-enabled Space on Hugging Face\n",
"\n",
"The first step is to create a space and select the appropriate sdk (which is Gradio in this example), per [these instructions](https://huggingface.co/docs/hub/spaces-overview#creating-a-new-space):"
]
},
{
"cell_type": "markdown",
"id": "b34d7ec6-69b8-48c4-a68b-fad6db3c2fab",
"metadata": {},
"source": [
"![](./create_space.png)"
]
},
{
"cell_type": "markdown",
"id": "c25e8e7a-52d9-4305-a107-ba03e3d6a5f3",
"metadata": {},
"source": [
"After you are done creating the space, **clone the repo per the instructions provided in the app.** In this example, I ran the command `git clone https://huggingface.co/spaces/hamel/hfspace_demo`."
]
},
{
"cell_type": "markdown",
"id": "ff26114c-329b-4a97-98b5-c652554b0114",
"metadata": {},
"source": [
"## 2. Make an app with Gradio"
]
},
{
"cell_type": "markdown",
"id": "14a884fc-36e2-43ec-8e42-ca2903aaa4de",
"metadata": {},
"source": [
"Below, we will create a [gradio](https://gradio.app/) app in a notebook and show you how to deploy it to [Hugging Face Spaces](https://huggingface.co/docs/hub/spaces).\n",
"\n",
"First, lets specify the libraries we need, which in this case are `gradio` and `fastcore`:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e5e5d597-19ad-46e5-81ad-8f646d8a1c21",
"metadata": {},
"outputs": [],
"source": [
"#|export\n",
"import gradio as gr\n",
"from fastcore.net import urljson, HTTPError"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "38a4389f-ef53-4626-a6f5-a859354f854b",
"metadata": {},
"outputs": [],
"source": [
"#|export\n",
"def size(repo:str):\n",
" \"Returns the size in GB of a HuggingFace Dataset.\"\n",
" url = f'https://huggingface.co/api/datasets/{repo}'\n",
" try: resp = urljson(f'{url}/treesize/main')\n",
" except HTTPError: return f'Did not find repo: {url}'\n",
" gb = resp['size'] / 1e9\n",
" return f'{gb:.2f} GB'"
]
},
{
"cell_type": "markdown",
"id": "9ff9f84d-7744-46ad-80ed-2cf1fa6d0643",
"metadata": {},
"source": [
"`size` take as an input a [Hugging Face Dataset](https://huggingface.co/docs/datasets/index) repo and returns the total size in GB of the data.\n",
"\n",
"For example, we can check the size of [tglcourse/CelebA-faces-cropped-128](https://huggingface.co/datasets/tglcourse/CelebA-faces-cropped-128) like so:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "95bc32b8-d8ff-4761-a2d7-0880c51d0a42",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'5.49 GB'"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"size(\"tglcourse/CelebA-faces-cropped-128\")"
]
},
{
"cell_type": "markdown",
"id": "cb13747b-ea48-4146-846d-deb9e855d32d",
"metadata": {},
"source": [
"You can construct a simple UI with the `gradio.interface` and then call the `launch` method of that interface to display a preview in a notebook. This is a great way to test your app to see if it works"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7b20e2a1-b622-4970-9069-0202ce10a2ce",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Running on local URL: http://127.0.0.1:7860\n",
"\n",
"To create a public link, set `share=True` in `launch()`.\n"
]
},
{
"data": {
"text/html": [
"<div><iframe src=\"http://127.0.0.1:7860/\" width=\"500\" height=\"500\" allow=\"autoplay; camera; microphone; clipboard-read; clipboard-write;\" frameborder=\"0\" allowfullscreen></iframe></div>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"(<gradio.routes.App>, 'http://127.0.0.1:7860/', None)"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#|export\n",
"iface = gr.Interface(fn=size, inputs=gr.Text(value=\"tglcourse/CelebA-faces-cropped-128\"), outputs=\"text\")\n",
"iface.launch(width=500)"
]
},
{
"cell_type": "markdown",
"id": "59926b18-a9af-4387-9fcc-f88e588da577",
"metadata": {},
"source": [
"Note how running the `launch()` method in a notebook runs a webserver in the background. Below, we call the `close()` method to close the webserver."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "39d7be72-9389-42cf-91b1-78e8f4bbd083",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Closing server running on port: 7860\n"
]
}
],
"source": [
"# this is only necessary in a notebook\n",
"iface.close()"
]
},
{
"cell_type": "markdown",
"id": "249b2cd7-3123-45bf-945f-882b8a964cf5",
"metadata": {},
"source": [
"## 3. Converting This Notebook Into A Gradio App"
]
},
{
"cell_type": "markdown",
"id": "5c18ca6e-8de8-49e1-b95a-304070bbc171",
"metadata": {},
"source": [
"In order to host this code on Hugging Faces spaces, you will export parts of this notebook to a script named `app.py`. That is what the special `#|export` comment that you have seen in cells above do! You can export code from this notebook like so:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6706d92c-5785-4f09-9773-b9a944c493a5",
"metadata": {},
"outputs": [],
"source": [
"from nbdev.export import nb_export\n",
"nb_export('app.ipynb', lib_path='.', name='app')"
]
},
{
"cell_type": "markdown",
"id": "0182403f-d1d6-48c0-8e66-46aefb23a9ab",
"metadata": {},
"source": [
"<div>\n",
"<link rel=\"stylesheet\" href=\"https://gradio.s3-us-west-2.amazonaws.com/2.6.5/static/bundle.css\">\n",
"<div id=\"target\"></div>\n",
"<script src=\"https://gradio.s3-us-west-2.amazonaws.com/2.6.5/static/bundle.js\"></script>\n",
"<script>\n",
"launchGradioFromSpaces(\"abidlabs/question-answering\", \"#target\")\n",
"</script>\n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "84d5fd19-7880-459c-8382-b3574ed11141",
"metadata": {},
"source": [
"### Understanding what is generated"
]
},
{
"cell_type": "markdown",
"id": "9ea562e7-b67a-45df-b822-2f4528a307c2",
"metadata": {},
"source": [
"Notice how the contents of app.py only contains the exported cells from this notebook:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4bae6a5c-58bc-4a0f-9aac-34c092150fdc",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"\u001b[0;31m# AUTOGENERATED! DO NOT EDIT! File to edit: app.ipynb.\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m\u001b[0;31m# %% auto 0\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m\u001b[0m__all__\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m'iface'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'size'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m\u001b[0;31m# %% app.ipynb 6\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m\u001b[0;32mimport\u001b[0m \u001b[0mgradio\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mgr\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m\u001b[0;32mfrom\u001b[0m \u001b[0mfastcore\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnet\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0murljson\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mHTTPError\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m\u001b[0;31m# %% app.ipynb 7\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m\u001b[0;32mdef\u001b[0m \u001b[0msize\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrepo\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0mstr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m \u001b[0;34m\"Returns the size in GB of a HuggingFace Dataset.\"\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m \u001b[0murl\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34mf'https://huggingface.co/api/datasets/{repo}'\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mresp\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0murljson\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf'{url}/treesize/main'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mHTTPError\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;34mf'Did not find repo: {url}'\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m \u001b[0mgb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mresp\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'size'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0;36m1e9\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;34mf'{gb:.2f} GB'\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m\u001b[0;31m# %% app.ipynb 11\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m\u001b[0miface\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mgr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mInterface\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfn\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msize\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minputs\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mgr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mText\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"tglcourse/CelebA-faces-cropped-128\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moutputs\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"text\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m\u001b[0miface\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlaunch\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mwidth\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m500\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%pycat app.py"
]
},
{
"cell_type": "markdown",
"id": "a081bb0f-5cad-4b99-962b-4dd49cee61a2",
"metadata": {},
"source": [
"### Fill out `requirements.txt`\n",
"\n",
"You must supply a requirements.txt file so the gradio app knows how to build your dependencies. In this example, the only depdency other than gradio is `fastcore`. You don't need to specify gradio itself as a depdendency in `requirements.txt` so our `requirements.txt` file has only one dependency:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0b611d9c-d262-4124-9e9e-4fe754ac4378",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"fastcore"
]
}
],
"source": [
"!cat requirements.txt"
]
},
{
"cell_type": "markdown",
"id": "f15d9c78-1f55-449e-8058-9af1832367a0",
"metadata": {},
"source": [
"## 4. Launch Your Gradio App\n",
"\n",
"To launch your gradio app, you need to commit the changes in the Hugging Face repo:\n",
"\n",
"```\n",
"git add -A; git commit -m \"Add application files\"; git push\n",
"```"
]
},
{
"cell_type": "markdown",
"id": "fa661f93-73b4-465a-9c22-cc38197505cb",
"metadata": {},
"source": [
"## 5. Voilà! Enjoy your Gradio App"
]
},
{
"cell_type": "markdown",
"id": "9b20ff94-6842-4078-9ec1-be740944e721",
"metadata": {},
"source": [
"After a couple of minutes, you will see your app published! This app is published at https://huggingface.co/spaces/hamel/hfspace_demo."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "52bacbff-63fc-492e-805c-6252c1ce2150",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment