I am trying to use my PlayHT API in order to add voice to my character. I am using the custom javascript section in advanced options in order to achieve this. I have a very rudimentary understanding of code so that combined with a bit of ChatGPT for help, I ended up with this:

async function getCustomPlayHTVoices() { const apiKey = “Removed for security”; // Your PlayHT API key const userId = “Removed for security”; // Your PlayHT User ID

try { const response = await fetch(“https://api.play.ht/api/v2/cloned-voices”, { headers: { “Authorization”: Bearer ${apiKey}, “X-User-ID”: userId } });

if (!response.ok) throw new Error("Failed to fetch PlayHT voices");

const voices = await response.json();
const customVoices = voices.filter(v => v.name.toLowerCase().includes("arlecchino"));

if (customVoices.length === 0) console.warn("Custom voice 'Arlecchino' not found.");

return customVoices;

} catch (error) { console.error(error); return []; } }

// Populate voice selection dropdown (async () => { const playHTVoices = await getCustomPlayHTVoices(); if (playHTVoices.length === 0) { document.body.innerHTML = “<p>Error fetching PlayHT voices. Check your API key or voice availability.</p>”; return; }

const voiceOptions = playHTVoices .map(v => <option value="${v.id}">${v.name}</option>) .join(“”);

document.body.innerHTML = <p>Please choose a voice:</p> <select id="voiceSelect">${voiceOptions}</select> <br> <button onclick="setVoice()">Submit</button> ;

window.chosenVoiceId = playHTVoices[0].id; // Default voice })();

function setVoice() { window.chosenVoiceId = document.getElementById(“voiceSelect”).value; oc.window.hide(); }

oc.window.show();

// Listen for streamed text and convert it to speech using PlayHT let sentence = “”; oc.thread.on(“StreamingMessage”, async function (data) { for await (let chunk of data.chunks) { sentence += chunk.text;

// Check for end of sentence OR limit to 200 characters to prevent buffering too much text
let endOfSentenceIndex = sentence.search(/[.!?]/);
if (endOfSentenceIndex !== -1 || sentence.length > 200) {
  let sentenceToSpeak = sentence.slice(0, endOfSentenceIndex + 1 || sentence.length);
  console.log("Speaking sentence:", sentenceToSpeak);
  await textToSpeech({ text: sentenceToSpeak, voiceId: window.chosenVoiceId });
  sentence = sentence.slice(endOfSentenceIndex + 1).trim(); // Reset for next sentence
}

} });

// Function to send text to PlayHT API and play the generated audio async function textToSpeech({ text, voiceId }) { const apiKey = “Removed for security”; // Your PlayHT API key const userId = “Removed for security”; // Your PlayHT User ID

try { const response = await fetch(“https://api.play.ht/api/v2/tts/stream”, { method: “POST”, headers: { “Authorization”: Bearer ${apiKey}, “X-User-ID”: userId, “Content-Type”: “application/json” }, body: JSON.stringify({ text: text, voice: voiceId, format: “mp3” }) });

if (!response.ok) throw new Error("Failed to fetch audio from PlayHT");

const result = await response.json();
console.log("PlayHT Response:", result);

if (!result.audioUrl) throw new Error("No audio URL returned from PlayHT");

return new Promise(resolve => {
  const audio = new Audio(result.audioUrl);
  audio.onended = resolve;
  audio.play();
});

} catch (error) { console.error(error); } }

I would also like to understand where I went wrong so please explain if you know the solution. Apologies as well, I can’t get the code to be in a single sheet in preview. I guess that tells me a lot about my ability to code.

  • VioneTM
    link
    English
    11 day ago

    Hi there, I’ve modified your code and here is the working code. Just specify your API Key and User ID on the top variables, then upon loading the custom code, select the voice you want to use.

    • @ProfessorDocOP
      link
      English
      121 hours ago

      Thank you for the help. One thing to note is window.chosenVoiceName = playHTVoices[0].id; I had to put it after the html body due to it not appearing if it was before, but otherwise this works perfectly. Thank you again.