रीयल-टाइम में ऑडियो जनरेट करें

यह गाइड बताती है कि WebSocket कनेक्शन के ज़रिए रीयल-टाइम में ऑडियो कैसे जनरेट करें।

WebSocket स्ट्रीमिंग, एक ही लंबे समय तक बने रहने वाले कनेक्शन पर डेटा भेजने और पाने की विधि है। यह विधि रियल-टाइम ऐप्लिकेशन के लिए उपयोगी है, जहाँ उपलब्ध होते ही आपको ऑडियो डेटा स्ट्रीम करना हो।

अगर आप ElevenLabs टेक्स्ट टू स्पीच API के WebSocket कनेक्शन की लेटेंसी (पहला बाइट मिलने का समय) जल्दी से टेस्ट करना चाहते हैं, तो npm के ज़रिए elevenlabs-latency इंस्टॉल करें और यहाँ दिए गए निर्देशों का पालन करें।

WebSockets टेक्स्ट टू स्पीच और Agents Platform के लिए उपलब्ध हैं। यह गाइड टेक्स्ट टू स्पीच WebSocket (/v1/text-to-speech/{voice_id}/stream-input) के बारे में है। वह endpoint नहीं eleven_v3 मॉडल को सपोर्ट करता है। WebSocket पर Eleven v3 डायलॉग के लिए रियलटाइम टेक्स्ट टू डायलॉग और टेक्स्ट टू स्पीच बनाम टेक्स्ट टू डायलॉग WebSockets देखें।

आवश्यकताएँ

  • API key वाला ElevenLabs अकाउंट (अपनी API key ढूँढने का तरीका यहाँ देखें)।
  • आपके कंप्यूटर पर Python या Node.js (या कोई अन्य JavaScript runtime) इंस्टॉल होना चाहिए

सेटअप

ज़रूरी dependencies इंस्टॉल करें:

pip install python-dotenv
pip install websockets

इसके बाद, अपनी प्रोजेक्ट डायरेक्टरी में .env फ़ाइल बनाएँ और अपनी API key जोड़ें:

.env
ELEVENLABS_API_KEY=your_elevenlabs_api_key_here

WebSocket कनेक्शन शुरू करें

वॉइस लाइब्रेरी से वॉइस और इस्तेमाल करने के लिए टेक्स्ट टू स्पीच मॉडल चुनने के बाद, टेक्स्ट टू स्पीच API से WebSocket कनेक्शन शुरू करें।

import os
from dotenv import load_dotenv
import websockets
# Load the API key from the .env file
load_dotenv()
ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY")
voice_id = 'Xb7hH8MSUJpSbSDYk0k2'
# For use cases where latency is important, we recommend using the 'eleven_flash_v2_5' model.
model_id = 'eleven_flash_v2_5'
async def text_to_speech_ws_streaming(voice_id, model_id):
uri = f"wss://api.elevenlabs.io/v1/text-to-speech/{voice_id}/stream-input?model_id={model_id}"
async with websockets.connect(uri) as websocket:
...

इनपुट टेक्स्ट भेजें

WebSocket कनेक्शन खुलने पर, पहले वॉइस सेटिंग्स सेट करें। फिर API को टेक्स्ट मैसेज भेजें।

async def text_to_speech_ws_streaming(voice_id, model_id):
async with websockets.connect(uri) as websocket:
await websocket.send(json.dumps({
"text": " ",
"voice_settings": {"stability": 0.5, "similarity_boost": 0.8, "use_speaker_boost": False},
"generation_config": {
"chunk_length_schedule": [120, 160, 250, 290]
},
"xi_api_key": ELEVENLABS_API_KEY,
}))
text = "The twilight sun cast its warm golden hues upon the vast rolling fields, saturating the landscape with an ethereal glow. Silently, the meandering brook continued its ceaseless journey, whispering secrets only the trees seemed privy to."
await websocket.send(json.dumps({"text": text}))
# Send empty string to indicate the end of the text sequence which will close the WebSocket connection
await websocket.send(json.dumps({"text": ""}))

ऑडियो को फ़ाइल में सेव करें

WebSocket कनेक्शन से आने वाला मैसेज पढ़ें और ऑडियो chunks को लोकल फ़ाइल में लिखें।

import asyncio
async def write_to_local(audio_stream):
"""Write the audio encoded in base64 string to a local mp3 file."""
with open(f'./output/test.mp3', "wb") as f:
async for chunk in audio_stream:
if chunk:
f.write(chunk)
async def listen(websocket):
"""Listen to the websocket for audio data and stream it."""
while True:
try:
message = await websocket.recv()
data = json.loads(message)
if data.get("audio"):
yield base64.b64decode(data["audio"])
elif data.get('isFinal'):
break
except websockets.exceptions.ConnectionClosed:
print("Connection closed")
break
async def text_to_speech_ws_streaming(voice_id, model_id):
async with websockets.connect(uri) as websocket:
...
# Add listen task to submit the audio chunks to the write_to_local function
listen_task = asyncio.create_task(write_to_local(listen(websocket)))
await listen_task
asyncio.run(text_to_speech_ws_streaming(voice_id, model_id))

स्क्रिप्ट चलाएँ

अपने टर्मिनल में नीचे दिया गया कमांड चलाकर स्क्रिप्ट चला सकते हैं। एक mp3 ऑडियो फ़ाइल output डायरेक्टरी में सेव हो जाएगी।

python text-to-speech-websocket.py

एडवांस्ड कॉन्फ़िगरेशन

WebSockets में कुछ एडवांस्ड सेटिंग्स होती हैं, जिनसे आप अपने रियल-टाइम ऑडियो जनरेशन को बेहतर ढंग से ट्यून कर सकते हैं।

बफ़रिंग

रियल-टाइम ऑडियो बनाते समय, दो अहम बातों को ध्यान में रखना चाहिए: Time To First Byte (TTFB) और बफ़रिंग। उच्च गुणवत्ता वाला ऑडियो बनाने और संदर्भ समझने के लिए, मॉडल को एक निश्चित मात्रा में इनपुट टेक्स्ट चाहिए। WebSocket कनेक्शन में जितना ज़्यादा टेक्स्ट भेजा जाता है, ऑडियो की गुणवत्ता उतनी ही बेहतर होती है। थ्रेशहोल्ड पूरा न होने पर, मॉडल टेक्स्ट को बफ़र में जोड़ता है और बफ़र भरने पर ऑडियो बनाता है।

लेटेंसी के लिहाज़ से, TTFB वह समय है जो ऑडियो का पहला बाइट क्लाइंट तक भेजने में लगता है। यह महत्वपूर्ण है क्योंकि इससे ऑडियो की महसूस होने वाली लेटेंसी प्रभावित होती है। इसलिए, गुणवत्ता और लेटेंसी के बीच संतुलन बनाने के लिए आप बफ़र साइज़ नियंत्रित करना चाह सकते हैं।

इसे मैनेज करने के लिए, WebSocket कनेक्शन शुरू करते समय या टेक्स्ट भेजते समय chunk_length_schedule पैरामीटर इस्तेमाल कर सकते हैं। यह पैरामीटर integers की एक array है, जो ऑडियो बनाने से पहले मॉडल को भेजे जाने वाले characters की संख्या बताती है। उदाहरण के लिए, अगर आप chunk_length_schedule को [120, 160, 250, 290] पर सेट करते हैं, तो मॉडल क्रमशः 120, 160, 250 और 290 characters भेजे जाने के बाद ऑडियो बनाएगा।

यहाँ chunk_length_schedule की डिफ़ॉल्ट सेटिंग के साथ इसका उदाहरण है:

ऊपर दिए गए डायग्राम में, सर्वर को दूसरा मैसेज भेजने के बाद ही ऑडियो बनता है। ऐसा इसलिए है क्योंकि पहला मैसेज 120 characters की थ्रेशहोल्ड से कम है, जबकि दूसरा मैसेज characters की कुल संख्या को थ्रेशहोल्ड से ऊपर ले जाता है। तीसरा मैसेज 160 characters की थ्रेशहोल्ड से ऊपर है, इसलिए ऑडियो तुरंत बनाकर क्लाइंट को वापस भेज दिया जाता है।

WebSocket कनेक्शन शुरू करते समय या टेक्स्ट भेजते समय chunk_length_schedule के लिए कस्टम वैल्यू दे सकते हैं।

await websocket.send(json.dumps({
"text": text,
"generation_config": {
# Generate audio after 50, 120, 160, and 290 characters have been sent
"chunk_length_schedule": [50, 120, 160, 290]
},
"xi_api_key": ELEVENLABS_API_KEY,
}))

अगर आप ऑडियो को तुरंत वापस भेजना चाहते हैं, तो बफ़र खाली करने और बफ़र में मौजूद टेक्स्ट का ऑडियो बनाने के लिए flush: true इस्तेमाल कर सकते हैं। उदाहरण के लिए, यह तब उपयोगी है जब आप किसी दस्तावेज़ के अंत तक पहुँच गए हों और आखिरी सेक्शन के लिए ऑडियो बनाना चाहते हों।

मैसेज में flush: true सेट करके इसे हर मैसेज के लिए अलग से निर्दिष्ट किया जा सकता है।

await websocket.send(json.dumps({"text": "Generate this audio immediately.", "flush": True}))

इसके अलावा, WebSocket बंद करने पर बफ़र में मौजूद किसी भी टेक्स्ट का ऑडियो अपने-आप बनाया जाएगा।

वॉइस सेटिंग्स

WebSocket कनेक्शन शुरू करते समय, आप बाद में होने वाले जनरेशन के लिए वॉइस सेटिंग्स तय कर सकते हैं। इससे आप बने हुए ऑडियो की स्पीड, स्थिरता और वॉइस की अन्य विशेषताओं को नियंत्रित कर सकते हैं।

await websocket.send(json.dumps({
"text": text,
"voice_settings": {"stability": 0.5, "similarity_boost": 0.8, "use_speaker_boost": False},
}))

मैसेज में अलग voice_settings देकर इसे हर मैसेज के लिए अलग से बदला जा सकता है।

उच्चारण शब्दकोश

आप खास शब्दों या वाक्यांशों के उच्चारण को नियंत्रित करने के लिए उच्चारण शब्दकोश इस्तेमाल कर सकते हैं। यह कुछ शब्दों का सही उच्चारण सुनिश्चित करने या खास शब्दों अथवा वाक्यांशों पर ज़ोर देने में उपयोगी हो सकता है।

voice_settings और generation_config से अलग, उच्चारण शब्दकोश “Initialize Connection” मैसेज में ही देने होते हैं। अधिक जानकारी के लिए API रेफरेंस देखें।

WebSockets के साथ phoneme-आधारित उच्चारण शब्दकोश इस्तेमाल करते समय, आपको WebSocket URI में query parameter के रूप में enable_ssml_parsing=true जोड़ना होगा। उदाहरण:

wss://api.elevenlabs.io/v1/text-to-speech/{voice_id}/stream-input?model_id={model_id}&enable_ssml_parsing=true

सर्वोत्तम तरीका

  • हमारा सुझाव है कि generation_config में chunk_length_schedule की डिफ़ॉल्ट सेटिंग इस्तेमाल करें।
  • रियल-टाइम कन्वर्सेशनल एजेंट ऐप्लिकेशन बनाते समय, समय पर ऑडियो जनरेशन सुनिश्चित करने के लिए बातचीत के टर्न के अंत में टेक्स्ट के साथ flush: true इस्तेमाल करें।
  • अगर डिफ़ॉल्ट सेटिंग आपके उपयोग के मामले में सबसे अच्छी लेटेंसी नहीं देती, तो आप chunk_length_schedule बदल सकते हैं। हालाँकि, ध्यान रखें कि इस बदलाव से लेटेंसी कम करने पर गुणवत्ता कम हो सकती है।

सुझाव

  • WebSocket कनेक्शन 20 सेकंड की निष्क्रियता के बाद अपने-आप बंद हो जाएगा। कनेक्शन खुला रखने के लिए, आप एक single space character " " भेज सकते हैं। ध्यान दें कि इस स्ट्रिंग में space होना चाहिए, क्योंकि पूरी तरह खाली स्ट्रिंग "" भेजने पर WebSocket बंद हो जाएगा।
  • आखिरी टेक्स्ट मैसेज भेजने के बाद WebSocket कनेक्शन बंद करने के लिए एक खाली स्ट्रिंग भेजें।
  • टेक्स्ट के हर शब्द के word-level timestamps पाने के लिए आप alignment इस्तेमाल कर सकते हैं। यह वीडियो में ऑडियो को टेक्स्ट के साथ संरेखित करने या सटीक टाइमिंग वाले अन्य ऐप्लिकेशन के लिए उपयोगी हो सकता है। अधिक जानकारी के लिए API रेफरेंस देखें।

आगे के चरण