DEV Community

VoiceDeveloper
VoiceDeveloper

Posted on

Building a Voice AI Portfolio Site That Gets You Hired

Why a Voice‑AI Portfolio Will Get You Hired

If you’re a developer who’s already tinkered with NLP or speech‑to‑text, a portfolio that showcases real‑time text‑to‑speech (TTS) and voice cloning can set you apart from the crowd. Recruiters love to see that you can build production‑ready pipelines that turn text into natural‑sounding audio, especially in a world where voice assistants and chat‑bots are becoming standard in every product.

Below is a step‑by‑step guide to building a minimal yet impressive voice‑AI portfolio site. We’ll walk through the stack, show how to hook up a TTS service, add voice cloning, and finally deploy it on an affordable, beginner‑friendly host.


The Stack: What You’ll Need

Layer Tool Why
Backend Python (Flask) Lightweight, great for quick REST APIs
TTS & Voice Cloning ElevenLabs State‑of‑the‑art neural voices, easy API
Frontend React Simple UI, fast dev experience
Hosting Bluehost One‑click WordPress + easy VPS, $3‑$5/month
Domain Namecheap / GoDaddy Cheap, auto‑renew, good DNS

Pro tip: If you’re comfortable with Node.js, swap Flask for Express and keep the same API calls – the code is almost identical.


1. Set Up the ElevenLabs Account

ElevenLabs offers a generous free tier and a straightforward API. Sign up here: https://try.elevenlabs.io/kr07zfuqn1bp.

After creating an account, grab your API key from the dashboard. We’ll use this in our backend to authenticate requests.


2. Build a Tiny Flask API

Create a new folder voice-backend and run:

python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate
pip install flask requests
Enter fullscreen mode Exit fullscreen mode

Create app.py:

from flask import Flask, request, jsonify
import requests
import os

app = Flask(__name__)

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

@app.route("/synthesize", methods=["POST"])
def synthesize():
    data = request.get_json()
    text = data.get("text", "")
    voice_id = data.get("voice_id", "Rachel")  # default voice

    payload = {
        "text": text,
        "voice_settings": {"stability": 0.5, "similarity_boost": 0.75}
    }

    headers = {
        "xi-api-key": ELEVENLABS_API_KEY,
        "Content-Type": "application/json"
    }

    resp = requests.post(ELEVENLABS_URL, json=payload, headers=headers)
    if resp.status_code != 200:
        return jsonify({"error": resp.text}), resp.status_code

    # ElevenLabs returns raw audio bytes
    return resp.content, 200, {"Content-Type": "audio/mpeg"}

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)
Enter fullscreen mode Exit fullscreen mode

Tip: Store your API key securely. In production, use environment variables or a secrets manager.

Run the server:

export ELEVENLABS_API_KEY="your_api_key_here"
python app.py
Enter fullscreen mode Exit fullscreen mode

Your endpoint http://localhost:5000/synthesize now accepts POST requests with JSON payload {"text": "Hello world"} and streams back an MP3.


3. Add Voice Cloning (Optional)

If you want to demo a custom voice, ElevenLabs also supports voice cloning. The flow is:

  1. Upload an audio sample (at least 30 seconds).
  2. Let the model train (a few minutes).
  3. Use the returned voice_id in your synth calls.

Sample curl to upload a sample:

curl -X POST "https://api.elevenlabs.io/v1/voices" \
  -H "xi-api-key: $ELEVENLABS_API_KEY" \
  -F "audio=@/path/to/sample.wav" \
  -F "name=MyCustomVoice"
Enter fullscreen mode Exit fullscreen mode

The response gives you a voice_id. Use that in the voice_id field when calling /synthesize.

Pro tip: Store the custom voice_id in a config file or database so you can swap voices without touching code.


4. Build a React Frontend

Create a new React app (using Vite or Create‑React‑App). Inside src/App.js:

import { useState } from "react";

export default function App() {
  const [text, setText] = useState("");
  const [audioUrl, setAudioUrl] = useState("");

  const synthesize = async () => {
    const res = await fetch("/api/synthesize", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ text })
    });

    if (!res.ok) {
      alert("Error synthesizing");
      return;
    }

    const blob = await res.blob();
    setAudioUrl(URL.createObjectURL(blob));
  };

  return (
    <div style={{ padding: "2rem" }}>
      <h1>Voice AI Portfolio Demo</h1>
      <textarea
        rows="4"
        value={text}
        onChange={(e) => setText(e.target.value)}
        placeholder="Type something..."
        style={{ width: "100%" }}
      />
      <button onClick={synthesize}>Speak!</button>
      {audioUrl && (
        <div style={{ marginTop: "1rem" }}>
          <audio controls src={audioUrl} />
        </div>
      )}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Proxy Setup (React dev server):

Add to vite.config.js:

export default defineConfig({
  server: {
    proxy: {
      "/api": "http://localhost:5000"
    }
  }
});
Enter fullscreen mode Exit fullscreen mode

Now, running npm run dev will give you a live preview at localhost:5173. When you type text and hit “Speak!”, the request goes to your Flask backend, which streams back a natural‑sounding MP3.


5. Deploy with Bluehost

Bluehost is the easy, affordable way to deploy a small web app. Here’s a quick checklist:

  1. Sign up: https://bluehost.sjv.io/5k0d52. The link offers a discounted introductory rate.
  2. Choose a plan: For a portfolio, the “Basic” plan ($3.95/month) is enough. It gives you a free domain for the first year and 50 GB of storage.
  3. Upload your code:
    • Use Bluehost’s cPanel → File Manager or an FTP client.
    • Place the Flask app under /public_html/voice-backend.
    • Install Python via cPanel’s “Setup Python App” and set the entry point to app.py.
  4. Set environment variables: In the Python app interface, add ELEVENLABS_API_KEY with your secret.
  5. Domain: Point your custom domain (e.g., voiceportfolio.com) to Bluehost’s nameservers (the same link gives you DNS info).
  6. SSL: Bluehost includes free Let’s Encrypt SSL, so your site will be HTTPS out of the box.

Why Bluehost?

  • One‑click WordPress installs (great if you want a blog side‑by‑side).
  • 24/7 support and a user‑friendly interface for beginners.
  • Cheap, reliable uptime – perfect for a portfolio that recruiters will visit.

6. Test, Iterate, and Showcase

  • Unit test your Flask route with pytest or unittest.
  • Measure latency: ElevenLabs is fast, but network hops add a few milliseconds. Use Chrome DevTools or curl -w "@curl-format.txt" to log timings.
  • Add UI polish: Use Tailwind CSS or Bootstrap to make the page look professional.
  • Add a “Demo” button that pre‑loads a short script (e.g., “Hello, I’m a voice‑AI developer”) so recruiters can hit “Speak!” right away.
  • Export a video: Record the page and voice playback. Upload it to YouTube or Vimeo and link it from your LinkedIn profile.

7. Next Steps

  1. Add more voices: Use ElevenLabs’ voice catalog to demo multiple accents or languages.
  2. Implement a “Voice Clone” UI: Let users upload a short clip and see the result.
  3. Deploy on a VPS: For more control, switch to a DigitalOcean droplet or AWS Lightsail and use Nginx + Gunicorn.
  4. Add analytics: Use Google Analytics to see how many times the “Speak” button is pressed.
  5. Write a blog post: Explain the architecture, share code, and link back to your deployed site.

Call to Action

Ready to show recruiters that you can turn text into lifelike speech?

Build, deploy, and let the voice speak for you. Happy coding!

Top comments (0)