DEV Community

VoiceDeveloper
VoiceDeveloper

Posted on

Deploy a Voice Cloning Demo App: From Code to Live Website

Why Voice Cloning is the Next Big Thing

If you’ve ever played around with text‑to‑speech (TTS) APIs, you know how far the tech has come. Modern voice AI can not only read your words aloud—it can clone a specific speaker’s timbre, cadence, and emotion. That opens doors for personalized audiobooks, interactive voice assistants, and even rapid prototyping of voice‑overs for videos.

In this post I’ll walk you through a complete, end‑to‑end demo: a tiny web app that lets you type a sentence, choose a cloned voice, and instantly hear the result. We’ll use the ElevenLabs API for the heavy lifting (the voice synthesis engine) and then spin the app up on a live site with Bluehost, an easy‑to‑use and affordable hosting provider.

TL;DR – Code the app locally, push it to Bluehost, and you’ll have a public URL that anyone can test in seconds.


What You’ll Need

Item Why
ElevenLabs API key Provides access to state‑of‑the‑art voice cloning. Grab yours here: https://try.elevenlabs.io/kr07zfuqn1bp
Python 3.9+ We’ll build a Flask backend.
Git To push the code to your Bluehost account.
A Bluehost account The recommended host for this tutorial. Sign up at https://bluehost.sjv.io/5k0d52 – the process is quick and the price is friendly for hobby projects.

1. Set Up the ElevenLabs API

ElevenLabs offers a RESTful API that accepts plain text and a voice ID, then returns an MP3 stream. First, sign up for a free trial using the link above. Once you have your API key, you’ll also need a voice ID for the clone you want to use. You can fetch a list of available voices with a simple curl request:

curl -H "xi-api-key: YOUR_ELEVENLABS_API_KEY" \
     https://api.elevenlabs.io/v1/voices
Enter fullscreen mode Exit fullscreen mode

Pick the voice_id you like (e.g., EXAMPLE_VOICE_ID) and keep it handy.


2. Build the Demo Backend (Flask)

Create a new folder and initialise a virtual environment:

mkdir voice-clone-demo && cd voice-clone-demo
python -m venv venv
source venv/bin/activate   # Windows: venv\Scripts\activate
pip install Flask requests python-dotenv
Enter fullscreen mode Exit fullscreen mode

Create a .env file to store secrets:

ELEVENLABS_API_KEY=YOUR_ELEVENLABS_API_KEY
DEFAULT_VOICE_ID=YOUR_VOICE_ID
Enter fullscreen mode Exit fullscreen mode

Now add app.py:

import os
from flask import Flask, request, send_file, jsonify
import requests
from io import BytesIO
from dotenv import load_dotenv

load_dotenv()
app = Flask(__name__)

ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY")
DEFAULT_VOICE_ID = os.getenv("DEFAULT_VOICE_ID")
ELEVENLABS_ENDPOINT = "https://api.elevenlabs.io/v1/text-to-speech"

def synthesize(text, voice_id=DEFAULT_VOICE_ID):
    url = f"{ELEVENLABS_ENDPOINT}/{voice_id}"
    headers = {
        "xi-api-key": ELEVENLABS_API_KEY,
        "Content-Type": "application/json"
    }
    payload = {
        "text": text,
        "voice_settings": {
            "stability": 0.75,
            "similarity_boost": 0.75
        }
    }
    response = requests.post(url, json=payload, headers=headers)
    response.raise_for_status()
    return BytesIO(response.content)

@app.route("/api/speak", methods=["POST"])
def speak():
    data = request.get_json()
    text = data.get("text", "")
    voice_id = data.get("voice_id", DEFAULT_VOICE_ID)

    if not text:
        return jsonify({"error": "No text provided"}), 400

    audio_io = synthesize(text, voice_id)
    return send_file(
        audio_io,
        mimetype="audio/mpeg",
        as_attachment=False,
        download_name="speech.mp3"
    )

@app.route("/")
def index():
    return """
    <h1>Voice Cloning Demo</h1>
    <form id="form">
      <textarea name="text" rows="4" cols="50" placeholder="Enter text..."></textarea><br/>
      <button type="submit">Speak</button>
    </form>
    <audio id="player" controls></audio>
    <script>
      const form = document.getElementById('form');
      const player = document.getElementById('player');
      form.onsubmit = async e => {
        e.preventDefault();
        const text = form.text.value;
        const res = await fetch('/api/speak', {
          method: 'POST',
          headers: {'Content-Type':'application/json'},
          body: JSON.stringify({text})
        });
        const blob = await res.blob();
        player.src = URL.createObjectURL(blob);
      };
    </script>
    """
Enter fullscreen mode Exit fullscreen mode

Run it locally to make sure everything works:

export FLASK_APP=app.py
flask run
Enter fullscreen mode Exit fullscreen mode

Navigate to http://127.0.0.1:5000, type a sentence, and hit Speak. You should hear the cloned voice instantly. If you encounter a 401 error, double‑check that your API key is correct.


3. Preparing for Deployment

a. Create a requirements.txt

pip freeze > requirements.txt
Enter fullscreen mode Exit fullscreen mode

b. Add a Procfile (for platforms that read it)

web: gunicorn app:app
Enter fullscreen mode Exit fullscreen mode

Note – Bluehost’s shared hosting doesn’t use Procfile, but having one handy makes the switch to a VPS or other PaaS painless.

c. Commit everything

git init
git add .
git commit -m "Initial voice clone demo"
Enter fullscreen mode Exit fullscreen mode

4. Deploy to Bluehost

Why Bluehost?

Bluehost offers one‑click Python app support, free SSL, and a straightforward cPanel interface. For a small demo, the shared plan (starting at just a few dollars a month) is more than enough. You can get started here: https://bluehost.sjv.io/5k0d52

Step‑by‑step

  1. Create a new site – In your Bluehost dashboard, click “Create Site” and choose Python as the runtime.
  2. Connect via Git – Bluehost provides a Git deployment URL (e.g., git@ssh.bluehost.com:username/repo.git). Add it as a remote:
   git remote add bluehost git@ssh.bluehost.com:username/repo.git
   git push bluehost master
Enter fullscreen mode Exit fullscreen mode
  1. Install dependencies – In the “Python App” section of cPanel, click “Enter Virtual Environment” and run:
   pip install -r requirements.txt
Enter fullscreen mode Exit fullscreen mode
  1. Set the entry point – Tell Bluehost which file to run. Usually you set the Application Startup File to app.py and the Application Object to app.

  2. Add environment variables – Use the “Environment Variables” UI to add ELEVENLABS_API_KEY and DEFAULT_VOICE_ID. This keeps secrets out of the repo.

  3. Enable HTTPS – Bluehost automatically provisions a free Let’s Encrypt certificate. Your site will be reachable at https://yourdomain.com.

  4. Test the live endpoint – Open the URL in a browser, type some text, and enjoy the cloned voice streaming from a production server.

That’s it! In less than an hour you’ve turned a local Flask script into a public demo site.


5. Tweaking the Experience

  • Multiple Voices – Fetch the voice list via the ElevenLabs API and populate a <select> dropdown in the front‑end. Pass the chosen voice_id in the JSON payload to /api/speak.
  • Caching – For repeated phrases, cache the MP3 bytes in a Redis instance (Bluehost offers Redis on higher plans) to reduce API calls and save credits.
  • Styling – Add a little CSS or integrate a UI framework like Tailwind to make the demo look polished.

6. Common Pitfalls & How to Fix Them

Symptom Likely Cause Fix
401 Unauthorized from ElevenLabs Wrong or missing API key Verify the key in the Bluehost env vars.
“Error: cannot import name gunicorn” Dependency not installed Run pip install gunicorn locally and push the updated requirements.txt.
No audio plays on the browser CORS or MIME mismatch Ensure the Flask route returns audio/mpeg and that the <audio> tag’s src is set via URL.createObjectURL.
Site never loads after push Process not started In Bluehost’s Python App panel, click Restart after each push.

7. Scaling Beyond the Demo

If you ever outgrow the shared plan (e.g., you need more concurrent requests or want to run background jobs), Bluehost lets you upgrade to a VPS with full root access. The same code works—just swap the gunicorn command into a systemd service or use Docker if you prefer.


Wrap‑Up

You now have a complete voice cloning web app that:

  1. Leverages the cutting‑edge ElevenLabs TTS engine.
  2. Runs on a cheap, beginner‑friendly Bluehost server.
  3. Is ready for anyone to try out with a single URL.

Give it a spin, experiment with different voices, and maybe embed the endpoint into a larger project (e.g., a Discord bot or an interactive story engine). The sky’s the limit when you combine modern AI with simple cloud hosting.


Ready to hear your own voice clone in action? Grab an ElevenLabs API key here: https://try.elevenlabs.io/kr07zfuqn1bp and spin up your live demo on Bluehost today: https://bluehost.sjv.io/5k0d52. Happy coding!

Top comments (0)