Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этой статье мы представим лучшие практики по снижению задержки синтеза текста в речь и обеспечению оптимальной производительности для конечных пользователей.
Обычно задержка измерятся параметрами first byte latency и finish latency следующим образом:
| Задержка | Описание | Ключ свойства SpeechSynthesisResult |
|---|---|---|
first byte client latency |
Указывает задержку времени между началом синтеза и первым блоком звука, полученным на клиенте, включая задержку сети. | SpeechServiceResponse_SynthesisFirstByteLatencyMs |
finish client latency |
Указывает задержку времени между началом синтеза и получением всего синтезированного звука на клиенте, включая задержку сети. | SpeechServiceResponse_SynthesisFinishLatencyMs |
network latency |
Задержка сети между клиентом и службой TTS Azure. | SpeechServiceResponse_SynthesisNetworkLatencyMs |
first byte service latency |
Указывает задержку времени между получением службой Azure TTS запроса на синтез и возвратом первого блока звука. | SpeechServiceResponse_SynthesisServiceLatencyMs |
В пакете SDK для службы "Речь" значения длительности задержки находятся в коллекции свойств SpeechSynthesisResult. Эти значения показаны в образце кода ниже.
var result = await synthesizer.SpeakTextAsync(text);
Console.WriteLine($"first byte client latency: \t{result.Properties.GetProperty(PropertyId.SpeechServiceResponse_SynthesisFirstByteLatencyMs)} ms");
Console.WriteLine($"finish client latency: \t{result.Properties.GetProperty(PropertyId.SpeechServiceResponse_SynthesisFinishLatencyMs)} ms");
Console.WriteLine($"network latency: \t{result.Properties.GetProperty(PropertyId.SpeechServiceResponse_SynthesisNetworkLatencyMs)} ms");
Console.WriteLine($"first byte service latency: \t{result.Properties.GetProperty(PropertyId.SpeechServiceResponse_SynthesisServiceLatencyMs)} ms");
// you can also get the result id, and send to us when you need help for diagnosis
var resultId = result.ResultId;
| Задержка | Описание | Ключ свойства SpeechSynthesisResult |
|---|---|---|
first byte client latency |
Указывает задержку времени между началом синтеза и первым блоком звука, полученным на клиенте, включая задержку сети. | SpeechServiceResponse_SynthesisFirstByteLatencyMs |
finish client latency |
Указывает задержку времени между началом синтеза и получением всего синтезированного звука на клиенте, включая задержку сети. | SpeechServiceResponse_SynthesisFinishLatencyMs |
network latency |
Задержка сети между клиентом и службой TTS Azure. | SpeechServiceResponse_SynthesisNetworkLatencyMs |
first byte service latency |
Указывает задержку времени между получением службой Azure TTS запроса на синтез и возвратом первого блока звука. | SpeechServiceResponse_SynthesisServiceLatencyMs |
SDK для речи измеряет задержки и помещает их в набор свойств SpeechSynthesisResult. Чтобы получить значения, см. следующий код.
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));
auto firstByteLatency = std::stoi(result->Properties.GetProperty(PropertyId::SpeechServiceResponse_SynthesisNetworkLatencyMs));
auto firstByteLatency = std::stoi(result->Properties.GetProperty(PropertyId::SpeechServiceResponse_SynthesisServiceLatencyMs));
// you can also get the result id, and send to us when you need help for diagnosis
auto resultId = result->ResultId;
| Задержка | Описание | Ключ свойства SpeechSynthesisResult |
|---|---|---|
first byte client latency |
Указывает задержку времени между началом синтеза и первым блоком звука, полученным на клиенте, включая задержку сети. | SpeechServiceResponse_SynthesisFirstByteLatencyMs |
finish client latency |
Указывает задержку времени между началом синтеза и получением всего синтезированного звука на клиенте, включая задержку сети. | SpeechServiceResponse_SynthesisFinishLatencyMs |
network latency |
Задержка сети между клиентом и службой TTS Azure. | SpeechServiceResponse_SynthesisNetworkLatencyMs |
first byte service latency |
Указывает задержку времени между получением службой Azure TTS запроса на синтез и возвратом первого блока звука. | SpeechServiceResponse_SynthesisServiceLatencyMs |
SDK для речи измеряет задержки и помещает их в набор свойств SpeechSynthesisResult. Чтобы получить значения, см. следующий код.
SpeechSynthesisResult result = synthesizer.SpeakTextAsync(text).get();
System.out.println("first byte client latency: \t" + result.getProperties().getProperty(PropertyId.SpeechServiceResponse_SynthesisFirstByteLatencyMs) + " ms.");
System.out.println("finish client latency: \t" + result.getProperties().getProperty(PropertyId.SpeechServiceResponse_SynthesisFinishLatencyMs) + " ms.");
System.out.println("network latency: \t" + result.getProperties().getProperty(PropertyId.SpeechServiceResponse_SynthesisNetworkLatencyMs) + " ms.");
System.out.println("first byte service latency: \t" + result.getProperties().getProperty(PropertyId.SpeechServiceResponse_SynthesisServiceLatencyMs) + " ms.");
// you can also get the result id, and send to us when you need help for diagnosis
String resultId = result.getResultId();
| Задержка | Описание | Ключ свойства SpeechSynthesisResult |
|---|---|---|
first byte client latency |
Указывает задержку времени между началом синтеза и первым блоком звука, полученным на клиенте, включая задержку сети. | SpeechServiceResponse_SynthesisFirstByteLatencyMs |
finish client latency |
Указывает задержку времени между началом синтеза и получением всего синтезированного звука на клиенте, включая задержку сети. | SpeechServiceResponse_SynthesisFinishLatencyMs |
network latency |
Задержка сети между клиентом и службой TTS Azure. | SpeechServiceResponse_SynthesisNetworkLatencyMs |
first byte service latency |
Указывает задержку времени между получением службой Azure TTS запроса на синтез и возвратом первого блока звука. | SpeechServiceResponse_SynthesisServiceLatencyMs |
SDK для речи измеряет задержки и помещает их в набор свойств SpeechSynthesisResult. Чтобы получить значения, см. следующий код.
result = synthesizer.speak_text_async(text).get()
first_byte_client_latency = int(result.properties.get_property(speechsdk.PropertyId.SpeechServiceResponse_SynthesisFirstByteLatencyMs))
finished_client_latency = int(result.properties.get_property(speechsdk.PropertyId.SpeechServiceResponse_SynthesisFinishLatencyMs))
network_latency = int(result.properties.get_property(speechsdk.PropertyId.SpeechServiceResponse_SynthesisNetworkLatencyMs))
first_byte_service_latency = int(result.properties.get_property(speechsdk.PropertyId.SpeechServiceResponse_SynthesisServiceLatencyMs))
# you can also get the result id, and send to us when you need help for diagnosis
result_id = result.result_id
| Задержка | Описание | Ключ свойства SPXSpeechSynthesisResult |
|---|---|---|
first byte client latency |
Указывает задержку времени между началом синтеза и первым блоком звука, полученным на клиенте, включая задержку сети. | SPXSpeechServiceResponseSynthesisFirstByteLatencyMs |
finish client latency |
Указывает задержку времени между началом синтеза и получением всего синтезированного звука на клиенте, включая задержку сети. | SPXSpeechServiceResponseSynthesisFinishLatencyMs |
network latency |
Задержка сети между клиентом и службой TTS Azure. | SPXSpeechServiceResponseSynthesisNetworkLatencyMs |
first byte service latency |
Указывает задержку времени между получением службой Azure TTS запроса на синтез и возвратом первого блока звука. | SPXSpeechServiceResponseSynthesisServiceLatencyMs |
SDK для речи измеряет задержки и помещает их в набор свойств SPXSpeechSynthesisResult. Чтобы получить значения, см. следующий код.
SPXSpeechSynthesisResult *speechResult = [speechSynthesizer speakText:text];
int firstByteClientLatency = [intString [speechResult.properties getPropertyById:SPXSpeechServiceResponseSynthesisFirstByteLatencyMs]];
int finishedClientLatency = [intString [speechResult.properties getPropertyById:SPXSpeechServiceResponseSynthesisFinishLatencyMs]];
int networkLatency = [intString [speechResult.properties getPropertyById:SPXSpeechServiceResponseSynthesisNetworkLatencyMs]];
int firstByteServiceLatency = [intString [speechResult.properties getPropertyById:SPXSpeechServiceResponseSynthesisServiceLatencyMs]];
// you can also get the result id, and send to us when you need help for diagnosis
NSString *resultId = result.resultId;
Первая задержка байтов ниже, чем задержка завершения в большинстве случаев. Задержка первого байта не зависит от длины текста, а задержка завершения растет по мере увеличения этой длины.
В идеальном случае требуется минимизировать задержку для пользователя (время перед тем, как пользователь услышит звук) до времени однократного прохождения сетевого маршрута плюс задержка первого звукового фрагмента от службы синтеза речи.
Стриминг
Потоковая передача — важнейший фактор снижения задержки. Клиентский код может начать воспроизведение при получении первого звукового фрагмента. В сценарии обслуживания вы можете сразу пересылать клиентам звуковые фрагменты, не дожидаясь формирования всего звукового пакета.
Для реализации потоковой передачи можно использовать PullAudioOutputStream, PushAudioOutputStream, Synthesizing событие и AudioDataStream пакета SDK службы "Речь".
Рассмотрим AudioDataStream в качестве примера:
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.");
}
}
}
}
Для активации потоковой передачи можно использовать PullAudioOutputStream, PushAudioOutputStream, Synthesizingсобытие и AudioDataStream из Speech SDK.
Рассмотрим AudioDataStream в качестве примера:
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;
}
Для активации потоковой передачи можно использовать PullAudioOutputStream, PushAudioOutputStream, Synthesizingсобытие и AudioDataStream из Speech SDK.
Рассмотрим AudioDataStream в качестве примера:
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);
}
Для активации потоковой передачи можно использовать PullAudioOutputStream, PushAudioOutputStream, Synthesizingсобытие и AudioDataStream из Speech SDK.
Рассмотрим AudioDataStream в качестве примера:
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)
Для активации потоковой передачи можно использовать SPXPullAudioOutputStream, SPXPushAudioOutputStream, Synthesizingсобытие и SPXAudioDataStream из Speech SDK.
Рассмотрим AudioDataStream в качестве примера:
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
}
Предварительное подключение и повторное использование SpeechSynthesizer
SDK "Речь" использует WebSocket для обмена данными со службой.
В идеале задержка сети должна составлять время одного сетевого маршрута (RTT).
Если подключение установлено недавно, задержка сети включает дополнительное время для установки подключения.
Для установки подключения WebSocket требуется подтверждение TCP, подтверждение SSL, HTTP-подключение и обновление протокола, что ведет к появлению задержки.
Чтобы избежать задержки подключения, рекомендуется предварительно подключить и повторно использовать SpeechSynthesizer.
Предварительное подключение
Чтобы предварительно подключиться, установите подключение к службе "Речь", когда вы знаете, что подключение необходимо в ближайшее время. Например, если вы создаете бот речи в клиенте, вы можете предварительно подключиться к службе синтеза речи, когда пользователь начнет говорить, и вызвать SpeakTextAsync , когда текст ответа бота готов.
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];
Примечание.
Если текст доступен, просто вызовите SpeakTextAsync, чтобы синтезировать аудио. Пакет SDK обеспечит подключение.
Повторное использование синтезатора речи
Снизить задержку подключения также можно путем повторного использования SpeechSynthesizer, чтобы не создавать новый объект SpeechSynthesizer для каждой операции синтеза.
Рекомендуется использовать пул объектов в сценарии службы. **
См. пример кода для
Передача сжатого звука по сети
Когда сеть нестабильна или доступна ограниченная пропускная способность, размер полезных данных также влияет на задержку. В то же время сжатие аудио позволяет уменьшить нагрузку на пропускную способность сети, что особенно важно для мобильных пользователей.
Поддерживается множество форматов сжатия, включая opus, webm, mp3, silk и т. п. (полный список см. в разделе SpeechSynthesisOutputFormat).
Например, скорость для формата Riff24Khz16BitMonoPcm составляет 384 кбит/с, а для Audio24Khz48KBitRateMonoMp3 — всего 48 кбит/с.
Speech SDK автоматически использует сжатый формат для передачи, когда установлен выходной pcm формат.
В Linux и Windows для включения этой функции потребуется GStreamer.
Инструкции по установке и настройке пакета SDK для службы "Речь" см. GStreamer.
Для Android, iOS и macOS дополнительная конфигурация не требуется, начиная с версии 1.20.
Потоковая трансляция вводимого текста
Потоковая передача текста позволяет обрабатывать текст в режиме реального времени для быстрого создания звука. Это идеально подходит для динамической вокализации текста, например чтения выходных данных из моделей ИИ, таких как GPT в режиме реального времени. Эта функция сводит к минимуму задержку и повышает гибкость и скорость отклика звуковых выходных данных, что делает его идеальным для интерактивных приложений, трансляций и адаптивных диалогов на основе искусственного интеллекта.
Использование потоковой передачи текста
Потоковая передача текста поддерживается в C#, C++ и Python с использованием Speech SDK.
Чтобы использовать функцию потоковой передачи текста, подключитесь к конечной точке websocket версии 2: wss://{region}.tts.speech.microsoft.com/cognitiveservices/websocket/v2
См. пример кода для настройки конечной точки:
// 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"));
Ключевые шаги
Создайте запрос текстового потока: используйте
SpeechSynthesisRequestInputType.TextStreamдля запуска текстового потока.Задайте глобальные свойства: настройте такие параметры, как формат вывода и имя голоса напрямую, так как функция обрабатывает частичные текстовые входные данные и не поддерживает SSML. Ознакомьтесь со следующим примером кода, чтобы узнать, как задать их. Голоса OpenAI text to speech не поддерживаются функцией потоковой передачи текста. См. эту таблицу языков для полной поддержки языка.
// Set output format speechConfig.SetSpeechSynthesisOutputFormat(SpeechSynthesisOutputFormat.Raw24Khz16BitMonoPcm); // Set a voice name SpeechConfig.SetProperty(PropertyId.SpeechServiceConnection_SynthVoice, "en-US-AvaMultilingualNeural");Потоковая передача текста: для каждого фрагмента текста, созданного из модели GPT, используйте
request.InputStream.Write(text);для отправки текста в поток.Закройте поток: после завершения выходных данных модели GPT закройте поток с помощью
request.InputStream.Close();.
Подробные сведения о реализации см. в коде sample на GitHub
Чтобы использовать функцию потоковой передачи текста, подключитесь к конечной точке websocket версии 2: wss://{region}.tts.speech.microsoft.com/cognitiveservices/websocket/v2
См. пример кода для настройки конечной точки:
# 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"))
Ключевые шаги
Создайте запрос текстового потока: используйте
speechsdk.SpeechSynthesisRequestInputType.TextStreamдля запуска текстового потока.Задайте глобальные свойства: настройте такие параметры, как формат вывода и имя голоса напрямую, так как функция обрабатывает частичные текстовые входные данные и не поддерживает SSML. Ознакомьтесь со следующим примером кода, чтобы узнать, как задать их. Голоса OpenAI text to speech не поддерживаются функцией потоковой передачи текста. См. эту таблицу языков для полной поддержки языка.
# set a voice name speech_config.speech_synthesis_voice_name = "en-US-AvaMultilingualNeural"Потоковая передача текста: для каждого фрагмента текста, созданного из модели GPT, используйте
request.input_stream.write(text)для отправки текста в поток.Закройте поток: после завершения выходных данных модели GPT закройте поток с помощью
request.input_stream.close().
Подробные сведения о реализации см. в коде sample на GitHub.
Пример кода C++ сейчас недоступен. Пример кода, демонстрирующий использование потоковой передачи текста, см. в следующих примерах:
Пример кода, демонстрирующий использование потоковой передачи текста, см. в следующих примерах:
Пример кода, демонстрирующий использование потоковой передачи текста, см. в следующих примерах:
Другие советы
Кэширование CRL-файлов
Пакет SDK "Речь" использует файлы списков отзыва сертификатов (CRL) для проверки сертификата. Хранение CRL-файлов в кэше до истечения срока их действия помогает избежать их повторной загрузки каждый раз. Дополнительные сведения см. в статье Настройка OpenSSL для Linux.
Используйте последнюю версию пакета SDK для преобразования речи
Мы продолжаем улучшать производительность Speech SDK, поэтому старайтесь использовать его последнюю версию в вашем приложении.
Советы в отношении нагрузочного теста
С помощью нагрузочного теста можно проверить емкость и задержку службы синтеза речи. Ниже приведены некоторые рекомендации.
- Служба синтеза речи имеет возможность автоматического масштабирования, но это требует времени для масштабирования в ширину. Если одновременное выполнение увеличивается за короткий промежуток времени, клиент может столкнуться с высокой задержкой или получить
429код ошибки (слишком много запросов). Поэтому мы рекомендуем пошагово увеличивать параллелизм в ходе нагрузочного теста. Дополнительные сведения см. в этой статье, особенно этот пример шаблонов рабочей нагрузки. - В нашем примере можно использовать пул объектов (C# и Java) для нагрузочного теста и получения чисел задержки. Вы можете изменить шаги и параллелизм тестов в примере в соответствии с целевым параллелизмом.
- Служба имеет ограничение квоты на основе реального трафика, поэтому если вы хотите выполнить нагрузочный тест с параллелизмом выше реального трафика, подключитесь перед тестом.
Следующие шаги
- Смотрите примеры на GitHub