{"guide": {"name": "fastapi-app-with-the-gradio-client", "category": "gradio-clients-and-lite", "pretty_category": "Gradio Clients And Lite", "guide_index": 7, "absolute_index": 54, "pretty_name": "Fastapi App With The Gradio Client", "content": "# Building a Web App with the Gradio Python Client\n\n\n\nIn this blog post, we will demonstrate how to use the `gradio_client` [Python library](getting-started-with-the-python-client/), which enables developers to make requests to a Gradio app programmatically, by creating an end-to-end example web app using FastAPI. The web app we will be building is called \"Acapellify,\" and it will allow users to upload video files as input and return a version of that video without instrumental music. It will also display a gallery of generated videos.\n\n**Prerequisites**\n\nBefore we begin, make sure you are running Python 3.9 or later, and have the following libraries installed:\n\n- `gradio_client`\n- `fastapi`\n- `uvicorn`\n\nYou can install these libraries from `pip`:\n\n```bash\n$ pip install gradio_client fastapi uvicorn\n```\n\nYou will also need to have ffmpeg installed. You can check to see if you already have ffmpeg by running in your terminal:\n\n```bash\n$ ffmpeg version\n```\n\nOtherwise, install ffmpeg [by following these instructions](https://www.hostinger.com/tutorials/how-to-install-ffmpeg).\n\n## Step 1: Write the Video Processing Function\n\nLet's start with what seems like the most complex bit -- using machine learning to remove the music from a video.\n\nLuckily for us, there's an existing Space we can use to make this process easier: [https://huggingface.co/spaces/abidlabs/music-separation](https://huggingface.co/spaces/abidlabs/music-separation). This Space takes an audio file and produces two separate audio files: one with the instrumental music and one with all other sounds in the original clip. Perfect to use with our client!\n\nOpen a new Python file, say `main.py`, and start by importing the `Client` class from `gradio_client` and connecting it to this Space:\n\n```py\nfrom gradio_client import Client, handle_file\n\nclient = Client(\"abidlabs/music-separation\")\n\ndef acapellify(audio_path):\n result = client.predict(handle_file(audio_path), api_name=\"/predict\")\n return result[0]\n```\n\nThat's all the code that's needed -- notice that the API endpoints returns two audio files (one without the music, and one with just the music) in a list, and so we just return the first element of the list.\n\n---\n\n**Note**: since this is a public Space, there might be other users using this Space as well, which might result in a slow experience. You can duplicate this Space with your own [Hugging Face token](https://huggingface.co/settings/tokens) and create a private Space that only you have will have access to and bypass the queue. To do that, simply replace the first two lines above with:\n\n```py\nfrom gradio_client import Client\n\nclient = Client.duplicate(\"abidlabs/music-separation\", hf_token=YOUR_HF_TOKEN)\n```\n\nEverything else remains the same!\n\n---\n\nNow, of course, we are working with video files, so we first need to extract the audio from the video files. For this, we will be using the `ffmpeg` library, which does a lot of heavy lifting when it comes to working with audio and video files. The most common way to use `ffmpeg` is through the command line, which we'll call via Python's `subprocess` module:\n\nOur video processing workflow will consist of three steps:\n\n1. First, we start by taking in a video filepath and extracting the audio using `ffmpeg`.\n2. Then, we pass in the audio file through the `acapellify()` function above.\n3. Finally, we combine the new audio with the original video to produce a final acapellified video.\n\nHere's the complete code in Python, which you can add to your `main.py` file:\n\n```python\nimport subprocess\n\ndef process_video(video_path):\n old_audio = os.path.basename(video_path).split(\".\")[0] + \".m4a\"\n subprocess.run(['ffmpeg', '-y', '-i', video_path, '-vn', '-acodec', 'copy', old_audio])\n\n new_audio = acapellify(old_audio)\n\n new_video = f\"acap_{video_path}\"\n subprocess.call(['ffmpeg', '-y', '-i', video_path, '-i', new_audio, '-map', '0:v', '-map', '1:a', '-c:v', 'copy', '-c:a', 'aac', '-strict', 'experimental', f\"static/{new_video}\"])\n return new_video\n```\n\nYou can read up on [ffmpeg documentation](https://ffmpeg.org/ffmpeg.html) if you'd like to understand all of the command line parameters, as they are beyond the scope of this tutorial.\n\n## Step 2: Create a FastAPI app (Backend Routes)\n\nNext up, we'll create a simple FastAPI app. If you haven't used FastAPI before, check out [the great FastAPI docs](https://fastapi.tiangolo.com/). Otherwise, this basic template, which we add to `main.py`, will look pretty familiar:\n\n```python\nimport os\nfrom fastapi import FastAPI, File, UploadFile, Request\nfrom fastapi.responses import HTMLResponse, RedirectResponse\nfrom fastapi.staticfiles import StaticFiles\nfrom fastapi.templating import Jinja2Templates\n\napp = FastAPI()\nos.makedirs(\"static\", exist_ok=True)\napp.mount(\"/static\", StaticFiles(directory=\"static\"), name=\"static\")\ntemplates = Jinja2Templates(directory=\"templates\")\n\nvideos = []\n\n@app.get(\"/\", response_class=HTMLResponse)\nasync def home(request: Request):\n return templates.TemplateResponse(\n \"home.html\", {\"request\": request, \"videos\": videos})\n\n@app.post(\"/uploadvideo/\")\nasync def upload_video(video: UploadFile = File(...)):\n video_path = video.filename\n with open(video_path, \"wb+\") as fp:\n fp.write(video.file.read())\n\n new_video = process_video(video.filename)\n videos.append(new_video)\n return RedirectResponse(url='/', status_code=303)\n```\n\nIn this example, the FastAPI app has two routes: `/` and `/uploadvideo/`.\n\nThe `/` route returns an HTML template that displays a gallery of all uploaded videos.\n\nThe `/uploadvideo/` route accepts a `POST` request with an `UploadFile` object, which represents the uploaded video file. The video file is \"acapellified\" via the `process_video()` method, and the output video is stored in a list which stores all of the uploaded videos in memory.\n\nNote that this is a very basic example and if this were a production app, you will need to add more logic to handle file storage, user authentication, and security considerations.\n\n## Step 3: Create a FastAPI app (Frontend Template)\n\nFinally, we create the frontend of our web application. First, we create a folder called `templates` in the same directory as `main.py`. We then create a template, `home.html` inside the `templates` folder. Here is the resulting file structure:\n\n```csv\n\u251c\u2500\u2500 main.py\n\u251c\u2500\u2500 templates\n\u2502 \u2514\u2500\u2500 home.html\n```\n\nWrite the following as the contents of `home.html`:\n\n```html\n<!DOCTYPE html> <html> <head> <title>Video Gallery</title>\n<style> body { font-family: sans-serif; margin: 0; padding: 0;\nbackground-color: #f5f5f5; } h1 { text-align: center; margin-top: 30px;\nmargin-bottom: 20px; } .gallery { display: flex; flex-wrap: wrap;\njustify-content: center; gap: 20px; padding: 20px; } .video { border: 2px solid\n#ccc; box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2); border-radius: 5px; overflow:\nhidden; width: 300px; margin-bottom: 20px; } .video video { width: 100%; height:\n200px; } .video p { text-align: center; margin: 10px 0; } form { margin-top:\n20px; text-align: center; } input[type=\"file\"] { display: none; } .upload-btn {\ndisplay: inline-block; background-color: #3498db; color: #fff; padding: 10px\n20px; font-size: 16px; border: none; border-radius: 5px; cursor: pointer; }\n.upload-btn:hover { background-color: #2980b9; } .file-name { margin-left: 10px;\n} </style> </head> <body> <h1>Video Gallery</h1> {% if videos %}\n<div class=\"gallery\"> {% for video in videos %} <div class=\"video\">\n<video controls> <source src=\"{{ url_for('static', path=video) }}\"\ntype=\"video/mp4\"> Your browser does not support the video tag. </video>\n<p>{{ video }}</p> </div> {% endfor %} </div> {% else %} <p>No\nvideos uploaded yet.</p> {% endif %} <form action=\"/uploadvideo/\"\nmethod=\"post\" enctype=\"multipart/form-data\"> <label for=\"video-upload\"\nclass=\"upload-btn\">Choose video file</label> <input type=\"file\"\nname=\"video\" id=\"video-upload\"> <span class=\"file-name\"></span> <button\ntype=\"submit\" class=\"upload-btn\">Upload</button> </form> <script> //\nDisplay selected file name in the form const fileUpload =\ndocument.getElementById(\"video-upload\"); const fileName =\ndocument.querySelector(\".file-name\"); fileUpload.addEventListener(\"change\", (e)\n=> { fileName.textContent = e.target.files[0].name; }); </script> </body>\n</html>\n```\n\n## Step 4: Run your FastAPI app\n\nFinally, we are ready to run our FastAPI app, powered by the Gradio Python Client!\n\nOpen up a terminal and navigate to the directory containing `main.py`. Then run the following command in the terminal:\n\n```bash\n$ uvicorn main:app\n```\n\nYou should see an output that looks like this:\n\n```csv\nLoaded as API: https://abidlabs-music-separation.hf.space \u2714\nINFO: Started server process [1360]\nINFO: Waiting for application startup.\nINFO: Application startup complete.\nINFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\nAnd that's it! Start uploading videos and you'll get some \"acapellified\" videos in response (might take seconds to minutes to process depending on the length of your videos). Here's how the UI looks after uploading two videos:\n\n![](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/gradio-guides/acapellify.png)\n\nIf you'd like to learn more about how to use the Gradio Python Client in your projects, [read the dedicated Guide](/guides/getting-started-with-the-python-client/).\n", "tags": ["CLIENT", "API", "WEB APP"], "spaces": [], "url": "/guides/fastapi-app-with-the-gradio-client/", "contributor": null}} |