Kortare svarstid för talsyntes med hjälp av Tal-SDK
I den här artikeln introducerar vi metodtipsen för att sänka svarstiden för text till talsyntes och ge slutanvändarna bästa prestanda.
Normalt mäter vi svarstiden first byte latency
efter och finish latency
, enligt följande:
Svarstid | beskrivning | SpeechSynthesisResult-egenskapsnyckel |
---|---|---|
svarstid för första byte | Anger tidsfördröjningen mellan starten av syntesaktiviteten och mottagandet av den första delen av ljuddata. | SpeechServiceResponse_SynthesisFirstByteLatencyMs |
slutför svarstid | Anger tidsfördröjningen mellan starten av syntesaktiviteten och mottagandet av hela syntetiserade ljuddata. | SpeechServiceResponse_SynthesisFinishLatencyMs |
Speech SDK placerar svarstidsvaraktigheterna i samlingen SpeechSynthesisResult
Egenskaper för . Följande exempelkod visar dessa värden.
var result = await synthesizer.SpeakTextAsync(text);
Console.WriteLine($"first byte latency: \t{result.Properties.GetProperty(PropertyId.SpeechServiceResponse_SynthesisFirstByteLatencyMs)} ms");
Console.WriteLine($"finish latency: \t{result.Properties.GetProperty(PropertyId.SpeechServiceResponse_SynthesisFinishLatencyMs)} ms");
// you can also get the result id, and send to us when you need help for diagnosis
var resultId = result.ResultId;
Svarstid | beskrivning | SpeechSynthesisResult-egenskapsnyckel |
---|---|---|
first byte latency |
Anger tidsfördröjningen mellan syntesen startar och det första ljudsegmentet tas emot. | SpeechServiceResponse_SynthesisFirstByteLatencyMs |
finish latency |
Anger tidsfördröjningen mellan att syntesen startar och att hela det syntetiserade ljudet tas emot. | SpeechServiceResponse_SynthesisFinishLatencyMs |
Speech SDK mätte svarstiderna och placerar dem i egenskapspåsen för SpeechSynthesisResult
. Se följande koder för att hämta dem.
auto result = synthesizer->SpeakTextAsync(text).get();
auto firstByteLatency = std::stoi(result->Properties.GetProperty(PropertyId::SpeechServiceResponse_SynthesisFirstByteLatencyMs));
auto finishedLatency = std::stoi(result->Properties.GetProperty(PropertyId::SpeechServiceResponse_SynthesisFinishLatencyMs));
// you can also get the result id, and send to us when you need help for diagnosis
auto resultId = result->ResultId;
Svarstid | beskrivning | SpeechSynthesisResult-egenskapsnyckel |
---|---|---|
first byte latency |
Anger tidsfördröjningen mellan syntesen startar och det första ljudsegmentet tas emot. | SpeechServiceResponse_SynthesisFirstByteLatencyMs |
finish latency |
Anger tidsfördröjningen mellan att syntesen startar och att hela det syntetiserade ljudet tas emot. | SpeechServiceResponse_SynthesisFinishLatencyMs |
Speech SDK mätte svarstiderna och placerar dem i egenskapspåsen för SpeechSynthesisResult
. Se följande koder för att hämta dem.
SpeechSynthesisResult result = synthesizer.SpeakTextAsync(text).get();
System.out.println("first byte latency: \t" + result.getProperties().getProperty(PropertyId.SpeechServiceResponse_SynthesisFirstByteLatencyMs) + " ms.");
System.out.println("finish latency: \t" + result.getProperties().getProperty(PropertyId.SpeechServiceResponse_SynthesisFinishLatencyMs) + " ms.");
// you can also get the result id, and send to us when you need help for diagnosis
String resultId = result.getResultId();
Svarstid | beskrivning | SpeechSynthesisResult-egenskapsnyckel |
---|---|---|
first byte latency |
Anger tidsfördröjningen mellan syntesen startar och det första ljudsegmentet tas emot. | SpeechServiceResponse_SynthesisFirstByteLatencyMs |
finish latency |
Anger tidsfördröjningen mellan att syntesen startar och att hela det syntetiserade ljudet tas emot. | SpeechServiceResponse_SynthesisFinishLatencyMs |
Speech SDK mätte svarstiderna och placerar dem i egenskapspåsen för SpeechSynthesisResult
. Se följande koder för att hämta dem.
result = synthesizer.speak_text_async(text).get()
first_byte_latency = int(result.properties.get_property(speechsdk.PropertyId.SpeechServiceResponse_SynthesisFirstByteLatencyMs))
finished_latency = int(result.properties.get_property(speechsdk.PropertyId.SpeechServiceResponse_SynthesisFinishLatencyMs))
# you can also get the result id, and send to us when you need help for diagnosis
result_id = result.result_id
Svarstid | beskrivning | Egenskapsnyckeln SPXSpeechSynthesisResult |
---|---|---|
first byte latency |
Anger tidsfördröjningen mellan syntesen startar och det första ljudsegmentet tas emot. | SPXSpeechServiceResponseSynthesisFirstByteLatencyMs |
finish latency |
Anger tidsfördröjningen mellan att syntesen startar och att hela det syntetiserade ljudet tas emot. | SPXSpeechServiceResponseSynthesisFinishLatencyMs |
Speech SDK mätte svarstiderna och placerar dem i egenskapspåsen för SPXSpeechSynthesisResult
. Se följande koder för att hämta dem.
SPXSpeechSynthesisResult *speechResult = [speechSynthesizer speakText:text];
int firstByteLatency = [intString [speechResult.properties getPropertyById:SPXSpeechServiceResponseSynthesisFirstByteLatencyMs]];
int finishedLatency = [intString [speechResult.properties getPropertyById:SPXSpeechServiceResponseSynthesisFinishLatencyMs]];
// you can also get the result id, and send to us when you need help for diagnosis
NSString *resultId = result.resultId;
Den första bytefördröjningen är i de flesta fall lägre än svarstiden för slut. Den första bytefördröjningen är oberoende av textlängd, medan svarstiden för slut ökar med textlängd.
Helst vill vi minimera svarstiden för användaranvändarna (svarstiden innan användaren hör ljudet) till en restid för nätverksvägen plus den första svarstiden för ljudsegmentet i talsyntestjänsten.
Strömning
Direktuppspelning är avgörande för att minska svarstiden. Klientkoden kan starta uppspelningen när det första ljudsegmentet tas emot. I ett tjänstscenario kan du vidarebefordra ljudsegment direkt till dina klienter, i stället för att vänta på hela ljudet.
Du kan använda PullAudioOutputStream
händelsen , PushAudioOutputStream
Synthesizing
och AudioDataStream
Speech SDK för att aktivera strömning.
Ta AudioDataStream
som exempel:
using (var synthesizer = new SpeechSynthesizer(config, null as AudioConfig))
{
using (var result = await synthesizer.StartSpeakingTextAsync(text))
{
using (var audioDataStream = AudioDataStream.FromResult(result))
{
byte[] buffer = new byte[16000];
uint filledSize = 0;
while ((filledSize = audioDataStream.ReadData(buffer)) > 0)
{
Console.WriteLine($"{filledSize} bytes received.");
}
}
}
}
Du kan använda PullAudioOutputStream
händelsen , PushAudioOutputStream
Synthesizing
och AudioDataStream
Speech SDK för att aktivera strömning.
Ta AudioDataStream
som exempel:
auto synthesizer = SpeechSynthesizer::FromConfig(config, nullptr);
auto result = synthesizer->SpeakTextAsync(text).get();
auto audioDataStream = AudioDataStream::FromResult(result);
uint8_t buffer[16000];
uint32_t filledSize = 0;
while ((filledSize = audioDataStream->ReadData(buffer, sizeof(buffer))) > 0)
{
cout << filledSize << " bytes received." << endl;
}
Du kan använda PullAudioOutputStream
händelsen , PushAudioOutputStream
Synthesizing
och AudioDataStream
Speech SDK för att aktivera strömning.
Ta AudioDataStream
som exempel:
SpeechSynthesizer synthesizer = new SpeechSynthesizer(config, null);
SpeechSynthesisResult result = synthesizer.StartSpeakingTextAsync(text).get();
AudioDataStream audioDataStream = AudioDataStream.fromResult(result);
byte[] buffer = new byte[16000];
long filledSize = audioDataStream.readData(buffer);
while (filledSize > 0) {
System.out.println(filledSize + " bytes received.");
filledSize = audioDataStream.readData(buffer);
}
Du kan använda PullAudioOutputStream
händelsen , PushAudioOutputStream
Synthesizing
och AudioDataStream
Speech SDK för att aktivera strömning.
Ta AudioDataStream
som exempel:
speech_synthesizer = speechsdk.SpeechSynthesizer(speech_config=speech_config, audio_config=None)
result = speech_synthesizer.start_speaking_text_async(text).get()
audio_data_stream = speechsdk.AudioDataStream(result)
audio_buffer = bytes(16000)
filled_size = audio_data_stream.read_data(audio_buffer)
while filled_size > 0:
print("{} bytes received.".format(filled_size))
filled_size = audio_data_stream.read_data(audio_buffer)
Du kan använda SPXPullAudioOutputStream
händelsen , SPXPushAudioOutputStream
Synthesizing
och SPXAudioDataStream
Speech SDK för att aktivera strömning.
Ta AudioDataStream
som exempel:
SPXSpeechSynthesizer *synthesizer = [[SPXSpeechSynthesizer alloc] initWithSpeechConfiguration:speechConfig audioConfiguration:nil];
SPXSpeechSynthesisResult *speechResult = [synthesizer startSpeakingText:inputText];
SPXAudioDataStream *stream = [[SPXAudioDataStream alloc] initFromSynthesisResult:speechResult];
NSMutableData* data = [[NSMutableData alloc]initWithCapacity:16000];
while ([stream readData:data length:16000] > 0) {
// Read data here
}
Föransluta och återanvända SpeechSynthesizer
Speech SDK använder en websocket för att kommunicera med tjänsten.
Helst bör nätverksfördröjningen vara en restid (RTT).
Om anslutningen har upprättats nyligen inkluderar nätverksfördröjningen extra tid för att upprätta anslutningen.
Etableringen av en websocket-anslutning kräver TCP-handskakning, SSL-handskakning, HTTP-anslutning och protokolluppgradering, vilket medför tidsfördröjning.
För att undvika anslutningsfördröjningen rekommenderar vi att du ansluter och återanvänder SpeechSynthesizer
.
Föranslutning
För att ansluta i förväg upprättar du en anslutning till Speech-tjänsten när du vet att anslutningen behövs snart. Om du till exempel skapar en talrobot i klienten kan du föransluta till talsyntestjänsten när användaren börjar prata och anropa SpeakTextAsync
när robotens svarstext är klar.
using (var synthesizer = new SpeechSynthesizer(uspConfig, null as AudioConfig))
{
using (var connection = Connection.FromSpeechSynthesizer(synthesizer))
{
connection.Open(true);
}
await synthesizer.SpeakTextAsync(text);
}
auto synthesizer = SpeechSynthesizer::FromConfig(config, nullptr);
auto connection = Connection::FromSpeechSynthesizer(synthesizer);
connection->Open(true);
SpeechSynthesizer synthesizer = new SpeechSynthesizer(speechConfig, (AudioConfig) null);
Connection connection = Connection.fromSpeechSynthesizer(synthesizer);
connection.openConnection(true);
synthesizer = speechsdk.SpeechSynthesizer(config, None)
connection = speechsdk.Connection.from_speech_synthesizer(synthesizer)
connection.open(True)
SPXSpeechSynthesizer* synthesizer = [[SPXSpeechSynthesizer alloc]initWithSpeechConfiguration:self.speechConfig audioConfiguration:nil];
SPXConnection* connection = [[SPXConnection alloc]initFromSpeechSynthesizer:synthesizer];
[connection open:true];
Kommentar
Om texten är tillgänglig anropar du SpeakTextAsync
bara för att syntetisera ljudet. SDK:et hanterar anslutningen.
Återanvända SpeechSynthesizer
Ett annat sätt att minska anslutningsfördröjningen SpeechSynthesizer
är att återanvända så att du inte behöver skapa en ny SpeechSynthesizer
för varje syntes.
Vi rekommenderar att du använder objektpoolen i tjänstscenariot. Se vår exempelkod för C# och Java.
Överföra komprimerat ljud via nätverket
När nätverket är instabilt eller med begränsad bandbredd påverkar nyttolaststorleken också svarstiden. Samtidigt hjälper ett komprimerat ljudformat till att spara användarnas nätverksbandbredd, vilket är särskilt värdefullt för mobila användare.
Vi stöder många komprimerade format, inklusive opus
, webm
, mp3
, silk
och så vidare, se den fullständiga listan i SpeechSynthesisOutputFormat.
Till exempel är bithastigheten Riff24Khz16BitMonoPcm
för formatet 384 kbps, medan Audio24Khz48KBitRateMonoMp3
endast kostar 48 kbps.
Speech SDK använder automatiskt ett komprimerat format för överföring när ett pcm
utdataformat anges.
För Linux och Windows GStreamer
krävs för att aktivera den här funktionen.
Se den här instruktionen för att installera och konfigurera GStreamer
för Speech SDK.
För Android, iOS och macOS behövs ingen extra konfiguration från och med version 1.20.
Direktuppspelning av indatatext
Textuppspelning möjliggör textbearbetning i realtid för snabb ljudgenerering. Det är perfekt för dynamisk textsång, till exempel att läsa utdata från AI-modeller som GPT i realtid. Den här funktionen minimerar svarstiden och förbättrar smidigheten och svarstiden för ljudutdata, vilket gör den idealisk för interaktiva program, livehändelser och dynamiska AI-drivna dialoger.
Så här använder du textuppspelning
Textströmning stöds i C#, C++ och Python med Speech SDK.
Om du vill använda funktionen för textströmning ansluter du till websocket V2-slutpunkten: wss://{region}.tts.speech.microsoft.com/cognitiveservices/websocket/v2
Se exempelkoden för att ange slutpunkten:
// IMPORTANT: MUST use the websocket v2 endpoint
var ttsEndpoint = $"wss://{Environment.GetEnvironmentVariable("AZURE_TTS_REGION")}.tts.speech.microsoft.com/cognitiveservices/websocket/v2";
var speechConfig = SpeechConfig.FromEndpoint(
new Uri(ttsEndpoint),
Environment.GetEnvironmentVariable("AZURE_TTS_API_KEY"));
Viktiga steg
Skapa en textströmsbegäran: Använd
SpeechSynthesisRequestInputType.TextStream
för att initiera en textström.Ange globala egenskaper: Justera inställningar som utdataformat och röstnamn direkt, eftersom funktionen hanterar partiella textindata och inte stöder SSML. Se följande exempelkod för instruktioner om hur du anger dem. OpenAI-text till talröster stöds inte av funktionen för textströmning. Se den här språktabellen för fullständigt språkstöd.
// Set output format speechConfig.SetSpeechSynthesisOutputFormat(SpeechSynthesisOutputFormat.Raw24Khz16BitMonoPcm); // Set a voice name SpeechConfig.SetProperty(PropertyId.SpeechServiceConnection_SynthVoice, "en-US-AvaMultilingualNeural");
Strömma din text: För varje textsegment som genereras från en GPT-modell använder du
request.InputStream.Write(text);
för att skicka texten till strömmen.Stäng strömmen: När GPT-modellen har slutfört sina utdata stänger du strömmen med .
request.InputStream.Close();
Detaljerad implementering finns i exempelkoden på GitHub
Om du vill använda funktionen för textströmning ansluter du till websocket V2-slutpunkten: wss://{region}.tts.speech.microsoft.com/cognitiveservices/websocket/v2
Se exempelkoden för att ange slutpunkten:
# IMPORTANT: MUST use the websocket v2 endpoint
speech_config = speechsdk.SpeechConfig(endpoint=f"wss://{os.getenv('AZURE_TTS_REGION')}.tts.speech.microsoft.com/cognitiveservices/websocket/v2",
subscription=os.getenv("AZURE_TTS_API_KEY"))
Viktiga steg
Skapa en textströmsbegäran: Använd
speechsdk.SpeechSynthesisRequestInputType.TextStream
för att initiera en textström.Ange globala egenskaper: Justera inställningar som utdataformat och röstnamn direkt, eftersom funktionen hanterar partiella textindata och inte stöder SSML. Se följande exempelkod för instruktioner om hur du anger dem. OpenAI-text till talröster stöds inte av funktionen för textströmning. Se den här språktabellen för fullständigt språkstöd.
# set a voice name speech_config.speech_synthesis_voice_name = "en-US-AvaMultilingualNeural"
Strömma din text: För varje textsegment som genereras från en GPT-modell använder du
request.input_stream.write(text)
för att skicka texten till strömmen.Stäng strömmen: När GPT-modellen har slutfört sina utdata stänger du strömmen med .
request.input_stream.close()
Detaljerad implementering finns i exempelkoden på GitHub.
C++-exempelkoden är inte tillgänglig nu. Exempelkoden som visar hur du använder textuppspelning finns i:
Exempelkoden som visar hur du använder textuppspelning finns i:
Exempelkoden som visar hur du använder textuppspelning finns i:
Andra tips
Cachelagrade CRL-filer
Speech SDK använder CRL-filer för att kontrollera certifieringen. Genom att cachelagra CRL-filerna tills den har upphört att gälla kan du undvika att ladda ned CRL-filer varje gång. Mer information finns i Så här konfigurerar du OpenSSL för Linux.
Använda senaste Speech SDK
Vi förbättrar hela tiden prestanda för Tal-SDK, så försök att använda den senaste Tal-SDK-versionen i ditt program.
Läs in testguiden
Du kan använda belastningstest för att testa talsyntestjänstens kapacitet och svarstid. Här följer några riktlinjer:
- Talsyntestjänsten har möjlighet att autoskala, men det tar tid att skala ut. Om samtidigheten ökar på kort tid kan klienten få lång svarstid eller
429
felkod (för många begäranden). Därför rekommenderar vi att du ökar samtidigheten steg för steg i belastningstestet. Mer information finns i den här artikeln , särskilt det här exemplet på arbetsbelastningsmönster. - Du kan använda vårt exempel med hjälp av objektpoolen (C# och Java) för belastningstest och för att hämta svarstidsnumren. Du kan ändra testsvängarna och samtidigheten i exemplet för att uppfylla målets samtidighet.
- Tjänsten har en kvotbegränsning baserat på den verkliga trafiken, och om du vill utföra belastningstest med samtidigheten högre än din verkliga trafik ansluter du före testet.
Nästa steg
- Se exemplen på GitHub