{"course":{"slug":"hugging-face","title":"Hugging Face, End to End","url":"https://addaly.com/learn/hugging-face","level":"intermediate","track":"create"},"lesson":{"slug":"gradio-in-forty-lines","title":"Forty lines from nothing to a public URL","url":"https://addaly.com/learn/hugging-face/gradio-in-forty-lines","position":29,"of":75,"minutes":9,"answer":"gr.Interface turns a Python function plus input and output components into a public web application.","keyIdea":"`gr.Interface` turns a Python function plus input and output components into a public web application, and the two things that decide whether strangers can use it are loading the model once at import rather than per request, and shipping examples plus an honest statement of the limits."},"body":{"format":"markdown","text":"## The whole thing\n\nCreate a Space on the Hub (New → Space, SDK: Gradio), and put two files in it.\n\n`requirements.txt`:\n\n```\ntransformers==4.46.2\ntorch==2.5.1\n```\n\n`app.py`:\n\n```python\nimport gradio as gr\nfrom transformers import pipeline\n\nclf = pipeline(\n    \"text-classification\",\n    model=\"cardiffnlp/twitter-roberta-base-sentiment-latest\",\n)\n\ndef classify(text):\n    if not text.strip():\n        return {}\n    scores = clf(text, top_k=None)[0] if isinstance(clf(text, top_k=None)[0], dict) \\\n             else clf(text, top_k=None)\n    return {d[\"label\"]: float(d[\"score\"]) for d in scores}\n\ndemo = gr.Interface(\n    fn=classify,\n    inputs=gr.Textbox(lines=4, label=\"Text\", placeholder=\"Paste a review\"),\n    outputs=gr.Label(num_top_classes=3, label=\"Sentiment\"),\n    title=\"Sentiment, three ways\",\n    description=\"Roberta trained on tweets. English only. Not calibrated.\",\n    examples=[\n        [\"The delivery was late but the food was excellent.\"],\n        [\"Fine, I suppose, if you enjoy waiting.\"],\n    ],\n    flagging_mode=\"never\",\n)\n\nif __name__ == \"__main__\":\n    demo.launch()\n```\n\nCommit both. The Space builds, installs, starts, and gives you a public URL that works on a phone. On free CPU hardware the first build takes a few minutes, most of it downloading torch.\n\n## What `gr.Interface` is doing\n\nIt inspects the function and the component types, builds a form and a results panel, wires the submit handler, handles errors, and exposes a REST endpoint and a queue behind the scenes. You describe inputs and outputs; it builds the application.\n\nThe components you will reach for most:\n\n- `gr.Textbox`, `gr.Number`, `gr.Slider`, `gr.Dropdown`, `gr.Checkbox`: inputs.\n- `gr.Image`, `gr.Audio`, `gr.Video`, `gr.File`: media, with upload and record widgets built in.\n- `gr.Label`: a dictionary of label to score, rendered as bars.\n- `gr.Dataframe`, `gr.JSON`, `gr.Markdown`, `gr.Gallery`, `gr.Plot`: outputs.\n\nPassing a bare string like `\"text\"` instead of `gr.Textbox()` works and is common in tutorials. Use the component object once you want a label, a placeholder or a line count, which is immediately.\n\n## Load the model once, outside the function\n\nIn the script above, `pipeline(...)` runs at import, once, when the Space starts. Put it inside `classify` instead and every single request reloads the weights: turning a 200 ms response into a 30-second one and, on a busy Space, exhausting memory. This is the most common performance bug in beginner Spaces and it is invisible when you test alone.\n\n## The details that make it usable by strangers\n\n**Examples.** `examples=[...]` renders clickable rows. A visitor who does not know what to type will click one; a visitor faced with an empty box leaves. This single argument changes how many people actually try your Space.\n\n**An honest description.** \"English only. Not calibrated.\" in the description costs nothing and prevents somebody deploying your demo against Hindi support tickets. Every limitation you know belongs on the page, not in your head.\n\n**Empty-input handling.** The `if not text.strip()` guard stops the first visitor seeing a red traceback box. Gradio surfaces exceptions in the UI, which is good for you and alarming for them.\n\n**`flagging_mode=\"never\"`.** Flagging writes user submissions to a file on a container that gets destroyed. Unless you have set up storage and said so in a privacy note, turn it off rather than silently collecting text people typed.\n\n## Running it locally first\n\nEverything above runs on your own machine:\n\n```bash\npip install gradio\npython app.py          # http://127.0.0.1:7860\n```\n\nDebug locally where the loop is seconds, and push when it works. `demo.launch(share=True)` gives a temporary public link that tunnels to your laptop: useful for showing somebody something for an hour, and not a deployment, since it dies with the process.\n\n## The free tier, precisely\n\nTwo vCPUs, 16 GB RAM, public, and it sleeps after a period of inactivity, waking on the next visit with a cold start of anything from seconds to a couple of minutes depending on what has to be downloaded. There is no time limit and no card required. For an embedding model, a classifier, an ONNX pipeline or a small Whisper model, this is a free permanent deployment.\n\n## Do this now\n\nShip a Space today, however small. The gap between a notebook and a URL you can send to somebody is the largest gap in this course, and it is forty lines wide. Everything after this lesson is refinement."},"check":{"question":"A Space responds in 200 ms when the developer tests it and takes 30 seconds per request once a few people use it at once. What is the most likely cause?","options":[{"text":"Free CPU hardware throttles under concurrency, so per-request latency rises sharply with the number of active users.","correct":false,"tempting":"Queueing on shared hardware is real but would not multiply a single request's time by more than a hundred."},{"text":"The model is being loaded inside the handler function, so every request re-reads the weights from the cache.","correct":true},{"text":"The Space went to sleep between tests, and the reported time includes the cold start on each wake.","correct":false,"tempting":"A cold start happens once on wake, not on every request while traffic is steady."},{"text":"Gradio's queue serialises requests by default, so users wait for every earlier request to complete.","correct":false,"tempting":"The queue does serialise, which raises waiting time under load but does not lengthen the work itself."}]},"prev":{"slug":"spaces-in-practice","title":"A Space is someone else's computer, already configured","url":"https://addaly.com/learn/hugging-face/spaces-in-practice"},"next":{"slug":"gradio-blocks-and-state","title":"Blocks, when Interface is no longer enough","url":"https://addaly.com/learn/hugging-face/gradio-blocks-and-state"},"authorship":"Founder and series editor: Dr Mustafa Mun. Written by AI models to a written standard. Exam keys checked blind by a second model: 3,665 of 3,666 agreed. Academic review invited.","review":{"status":"Draft, open for academic review"},"cite":"Addaly (2026) 'Forty lines from nothing to a public URL', in Hugging Face, End to End. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/hugging-face/gradio-in-forty-lines (Accessed: 13 October 2026).","licence":{"name":"CC BY-NC-SA 4.0","url":"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"reader":{"schema":1,"title":"Forty lines from nothing to a public URL","courseTitle":"Hugging Face, End to End","module":{"index":4,"slug":"spaces-and-shipping-something","title":"Spaces: putting something in front of people"},"answer":null,"keyIdea":"`gr.Interface` turns a Python function plus input and output components into a public web application, and the two things that decide whether strangers can use it are loading the model once at import rather than per request, and shipping examples plus an honest statement of the limits.","hero":{"kind":"plate","image":null,"alt":null,"caption":null},"blocks":[{"t":"h2","id":"the-whole-thing","runs":[{"text":"The whole thing"}]},{"t":"p","runs":[{"text":"Create a Space on the Hub (New → Space, SDK: Gradio), and put two files in it."}]},{"t":"p","runs":[{"text":"requirements.txt","code":true},{"text":":"}]},{"t":"code","lang":"","label":"Text","text":"transformers==4.46.2\ntorch==2.5.1"},{"t":"p","runs":[{"text":"app.py","code":true},{"text":":"}]},{"t":"code","lang":"python","label":"Python","text":"import gradio as gr\nfrom transformers import pipeline\n\nclf = pipeline(\n    \"text-classification\",\n    model=\"cardiffnlp/twitter-roberta-base-sentiment-latest\",\n)\n\ndef classify(text):\n    if not text.strip():\n        return {}\n    scores = clf(text, top_k=None)[0] if isinstance(clf(text, top_k=None)[0], dict) \\\n             else clf(text, top_k=None)\n    return {d[\"label\"]: float(d[\"score\"]) for d in scores}\n\ndemo = gr.Interface(\n    fn=classify,\n    inputs=gr.Textbox(lines=4, label=\"Text\", placeholder=\"Paste a review\"),\n    outputs=gr.Label(num_top_classes=3, label=\"Sentiment\"),\n    title=\"Sentiment, three ways\",\n    description=\"Roberta trained on tweets. English only. Not calibrated.\",\n    examples=[\n        [\"The delivery was late but the food was excellent.\"],\n        [\"Fine, I suppose, if you enjoy waiting.\"],\n    ],\n    flagging_mode=\"never\",\n)\n\nif __name__ == \"__main__\":\n    demo.launch()"},{"t":"p","runs":[{"text":"Commit both. The Space builds, installs, starts, and gives you a public URL that works on a phone. On free CPU hardware the first build takes a few minutes, most of it downloading torch."}]},{"t":"h2","id":"what-gr-interface-is-doing","runs":[{"text":"What "},{"text":"gr.Interface","code":true},{"text":" is doing"}]},{"t":"p","runs":[{"text":"It inspects the function and the component types, builds a form and a results panel, wires the submit handler, handles errors, and exposes a REST endpoint and a queue behind the scenes. You describe inputs and outputs; it builds the application."}]},{"t":"p","runs":[{"text":"The components you will reach for most:"}]},{"t":"ul","items":[[{"text":"gr.Textbox","code":true},{"text":", "},{"text":"gr.Number","code":true},{"text":", "},{"text":"gr.Slider","code":true},{"text":", "},{"text":"gr.Dropdown","code":true},{"text":", "},{"text":"gr.Checkbox","code":true},{"text":": inputs."}],[{"text":"gr.Image","code":true},{"text":", "},{"text":"gr.Audio","code":true},{"text":", "},{"text":"gr.Video","code":true},{"text":", "},{"text":"gr.File","code":true},{"text":": media, with upload and record widgets built in."}],[{"text":"gr.Label","code":true},{"text":": a dictionary of label to score, rendered as bars."}],[{"text":"gr.Dataframe","code":true},{"text":", "},{"text":"gr.JSON","code":true},{"text":", "},{"text":"gr.Markdown","code":true},{"text":", "},{"text":"gr.Gallery","code":true},{"text":", "},{"text":"gr.Plot","code":true},{"text":": outputs."}]]},{"t":"p","runs":[{"text":"Passing a bare string like "},{"text":"\"text\"","code":true},{"text":" instead of "},{"text":"gr.Textbox()","code":true},{"text":" works and is common in tutorials. Use the component object once you want a label, a placeholder or a line count, which is immediately."}]},{"t":"h2","id":"load-the-model-once-outside-the-function","runs":[{"text":"Load the model once, outside the function"}]},{"t":"p","runs":[{"text":"In the script above, "},{"text":"pipeline(...)","code":true},{"text":" runs at import, once, when the Space starts. Put it inside "},{"text":"classify","code":true},{"text":" instead and every single request reloads the weights: turning a 200 ms response into a 30-second one and, on a busy Space, exhausting memory. This is the most common performance bug in beginner Spaces and it is invisible when you test alone."}]},{"t":"h2","id":"the-details-that-make-it-usable-by-strangers","runs":[{"text":"The details that make it usable by strangers"}]},{"t":"p","runs":[{"text":"Examples.","b":true},{"text":" "},{"text":"examples=[...]","code":true},{"text":" renders clickable rows. A visitor who does not know what to type will click one; a visitor faced with an empty box leaves. This single argument changes how many people actually try your Space."}]},{"t":"p","runs":[{"text":"An honest description.","b":true},{"text":" “English only. Not calibrated.” in the description costs nothing and prevents somebody deploying your demo against Hindi support tickets. Every limitation you know belongs on the page, not in your head."}]},{"t":"p","runs":[{"text":"Empty-input handling.","b":true},{"text":" The "},{"text":"if not text.strip()","code":true},{"text":" guard stops the first visitor seeing a red traceback box. Gradio surfaces exceptions in the UI, which is good for you and alarming for them."}]},{"t":"p","runs":[{"text":"flagging_mode=\"never\"","b":true,"code":true},{"text":".","b":true},{"text":" Flagging writes user submissions to a file on a container that gets destroyed. Unless you have set up storage and said so in a privacy note, turn it off rather than silently collecting text people typed."}]},{"t":"h2","id":"running-it-locally-first","runs":[{"text":"Running it locally first"}]},{"t":"p","runs":[{"text":"Everything above runs on your own machine:"}]},{"t":"code","lang":"bash","label":"Bash","text":"pip install gradio\npython app.py          # http://127.0.0.1:7860"},{"t":"p","runs":[{"text":"Debug locally where the loop is seconds, and push when it works. "},{"text":"demo.launch(share=True)","code":true},{"text":" gives a temporary public link that tunnels to your laptop: useful for showing somebody something for an hour, and not a deployment, since it dies with the process."}]},{"t":"h2","id":"the-free-tier-precisely","runs":[{"text":"The free tier, precisely"}]},{"t":"p","runs":[{"text":"Two vCPUs, 16 GB RAM, public, and it sleeps after a period of inactivity, waking on the next visit with a cold start of anything from seconds to a couple of minutes depending on what has to be downloaded. There is no time limit and no card required. For an embedding model, a classifier, an ONNX pipeline or a small Whisper model, this is a free permanent deployment."}]},{"t":"h2","id":"do-this-now","runs":[{"text":"Do this now"}],"role":"try"},{"t":"p","runs":[{"text":"Ship a Space today, however small. The gap between a notebook and a URL you can send to somebody is the largest gap in this course, and it is forty lines wide. Everything after this lesson is refinement."}]}],"check":{"question":[{"text":"A Space responds in 200 ms when the developer tests it and takes 30 seconds per request once a few people use it at once. What is the most likely cause?"}],"options":[{"text":[{"text":"Free CPU hardware throttles under concurrency, so per-request latency rises sharply with the number of active users."}],"correct":false,"tempting":[{"text":"Queueing on shared hardware is real but would not multiply a single request’s time by more than a hundred."}]},{"text":[{"text":"The model is being loaded inside the handler function, so every request re-reads the weights from the cache."}],"correct":true,"tempting":null},{"text":[{"text":"The Space went to sleep between tests, and the reported time includes the cold start on each wake."}],"correct":false,"tempting":[{"text":"A cold start happens once on wake, not on every request while traffic is steady."}]},{"text":[{"text":"Gradio’s queue serialises requests by default, so users wait for every earlier request to complete."}],"correct":false,"tempting":[{"text":"The queue does serialise, which raises waiting time under load but does not lengthen the work itself."}]}],"order":[0,2,3,1],"why":null},"prev":{"slug":"spaces-in-practice","title":"A Space is someone else’s computer, already configured","minutes":9},"next":{"slug":"gradio-blocks-and-state","title":"Blocks, when Interface is no longer enough","minutes":9}}}