Por padrão, o SDK conecta-se ao endpoint da região de Beijing. Para usar uma região diferente, defina Constants.baseWebsocketApiUrl antes de inicializar o SDK.
Singapore
China (Beijing)
wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inferenceSubstitua {WorkspaceId} pelo seu workspace ID real.
wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/inferenceSubstitua {WorkspaceId} pelo seu workspace ID real.
Alternar para a região de Singapore:
Copy
import com.alibaba.dashscope.utils.Constants;// Set this before any SDK initializationConstants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
O Alibaba Cloud Model Studio lançou domínios específicos por workspace para as regiões China (Beijing) e Singapore. Os novos domínios dedicados oferecem desempenho superior e maior estabilidade nas solicitações de inferência. Recomendamos migrar para os novos domínios:
China (Beijing): de dashscope.aliyuncs.com para {WorkspaceId}.cn-beijing.maas.aliyuncs.com
Singapore: de dashscope-intl.aliyuncs.com para {WorkspaceId}.ap-southeast-1.maas.aliyuncs.com
Substitua {WorkspaceId} pelo seu Workspace ID real. Os domínios existentes permanecem totalmente funcionais.
call() - Síntese sem streaming ou streaming unidirecional
Assinatura do método:
Copy
public ByteBuffer call(String text)
Parâmetros:
Parâmetro
Tipo
Obrigatório
Descrição
text
String
Sim
Texto a sintetizar. Comprimento máximo: 20.000 caracteres.
Valor de retorno: ByteBuffer ou null. Em chamadas sem streaming, retorna os dados de áudio completos. Em chamadas com streaming unidirecional, este método retorna null; o áudio é entregue via callback.
Descrição: Cancela a tarefa atual de síntese de fala com streaming bidirecional. Após a chamada deste método, o SDK encerra imediatamente a tarefa atual. Inicie uma nova tarefa de síntese na mesma conexão sem reinicializar a instância de SpeechSynthesizer.
Requisito de versão: Este recurso requer Java SDK 2.22.26 ou posterior.
Limitações do modelo:
China (Beijing): Todos os modelos Qwen-Audio-TTS suportam este recurso. Modelos CosyVoice requerem versão v2 ou posterior.
Singapore: Todos os modelos Qwen-Audio-TTS suportam este recurso. Modelos CosyVoice não suportam este recurso.
callAsFlowable() - Síntese com streaming unidirecional (reativo)
Assinatura do método:
Copy
public Flowable<SpeechSynthesisResult> callAsFlowable(String text)
Parâmetros:
Parâmetro
Tipo
Obrigatório
Descrição
text
String
Sim
Texto a sintetizar.
Valor de retorno: Stream reativo Flowable<!--@xref {"id":"xref-flowable-result1","data-node":"5490310","href":"#sec-7m5k9p2r","data-tag":"xref"}-->SpeechSynthesisResult>.
streamingCallAsFlowable() - Síntese com streaming bidirecional (reativo)
Assinatura do método:
Copy
public Flowable<SpeechSynthesisResult> streamingCallAsFlowable(Flowable<String> textStream)
Parâmetros:
Parâmetro
Tipo
Obrigatório
Descrição
textStream
Flowable<String>
Sim
Stream reativo de texto.
Valor de retorno: Stream reativo Flowable<!--@xref {"id":"xref-flowable-result2","data-node":"5490310","href":"#sec-7m5k9p2r","data-tag":"xref"}-->SpeechSynthesisResult>.
getFirstPackageDelay() - Obter latência do primeiro pacote
Assinatura do método:
Copy
public long getFirstPackageDelay()
Valor de retorno: long. Latência do primeiro pacote em milissegundos, medida do envio do primeiro segmento de texto até o recebimento do primeiro pacote de áudio.
Vozes clonadas: Vozes personalizadas criadas via clonagem de voz
Vozes personalizadas: Vozes personalizadas criadas via design de voz
format(SpeechSynthesisAudioFormat)
enum
Não
Formato de codificação de áudio e taxa de amostragem.Padrão: SpeechSynthesisAudioFormat.MP3_22050HZ_MONO_256KBPS.Pacote SpeechSynthesisAudioFormat: com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisAudioFormat.
volume(int)
int
Não
Nível de volume.Valor padrão: 50.Valores válidos: [0, 100].
speechRate(float)
float
Não
Velocidade da fala.Valor padrão: 1,0.Valores válidos: [0,5, 2,0].
pitchRate(float)
float
Não
Tom da voz.Valor padrão: 1,0.Valores válidos: [0,5, 2,0].
enableWordTimestamp(boolean)
boolean
Não
Define se os carimbos de data/hora no nível de palavra devem ser ativados.Valor padrão: false.Disponível apenas no modo de saída em streaming. Vozes suportadas: vozes clonadas de qwen-audio-3.0-tts-plus, qwen-audio-3.0-tts-flash, cosyvoice-v3.5-plus, cosyvoice-v3.5-flash, cosyvoice-v3-flash, cosyvoice-v3-plus e cosyvoice-v2, além de vozes do sistema marcadas como suportadas em Qwen-Audio-TTS voice list e CosyVoice Voice list. Vozes clonadas de outros modelos não suportam este recurso.
seed(int)
int
Não
Semente aleatória para controlar variações na saída da síntese. Se a versão do modelo, texto, voz e demais parâmetros permanecerem inalterados, usar a mesma semente produz resultados idênticos.Valor padrão: 0.Valores válidos: [0, 65535].Para versões do SDK anteriores a 2.21.7, defina seed por meio de parâmetros adicionais.
languageHints(List<String>)
List<String>
Não
Este parâmetro é um array, mas a versão atual processa apenas o primeiro elemento. Passe um único valor.
Este parâmetro especifica o idioma-alvo da síntese de fala e não se relaciona ao idioma da amostra de áudio usada na clonagem de voz. Para definir o idioma de source de uma tarefa de clonagem, consulte a referência da API de clonagem de voz.
Especifica o idioma-alvo da síntese de fala para melhorar a qualidade da saída.Use este parâmetro quando a pronúncia de dígitos, expansão de abreviações, leitura de símbolos ou síntese de idiomas minoritários não atender às expectativas. Exemplos:
Pronúncia inesperada de dígitos: "olá, isto é 110" é lido como "olá, isto é um zero" em vez da pronúncia chinesa esperada
Pronúncia imprecisa de símbolos: "@" é lido como o equivalente chinês em vez de "at"
Baixa qualidade na síntese de idiomas minoritários, com resultados pouco naturais
Valores válidos:
zh: Chinês
en: Inglês
fr: Francês
de: Alemão
ja: Japonês
ko: Coreano
ru: Russo
pt: Português
th: Tailandês
id: Indonésio
vi: Vietnamita
es: Espanhol
it: Italiano
ms: Malaio
fil: Filipino
ar: Árabe
instruction(String)
String
Não
Controla características da síntese, como dialeto, emoção ou estilo de fala.Para detalhes de uso, consulte Instruction control.
hotFix(ParamHotFix)
ParamHotFix
Não
Configura correções de pronúncia e substituições de texto aplicadas antes da síntese.This feature isn't supported by qwen-audio-3.0-tts-plus, qwen-audio-3.0-tts-flash, or cosyvoice-v2.Parâmetros:
pronunciation: Pronúncia personalizada. Especifica anotações pinyin para palavras a fim de corrigir pronúncias padrão imprecisas.
replace: Substituição de texto. Substitui palavras especificadas pelo texto-alvo antes da síntese. O texto substituído torna-se a entrada efetiva da síntese.
Exemplo:
Copy
List<ParamHotFix.PronunciationItem> pronunciationItems = new ArrayList<>();pronunciationItems.add(new ParamHotFix.PronunciationItem("weather", "tian1 qi4"));List<ParamHotFix.ReplaceItem> replaceItems = new ArrayList<>();replaceItems.add(new ParamHotFix.ReplaceItem("today", "gold day"));ParamHotFix paramHotFix = new ParamHotFix();paramHotFix.setPronunciation(pronunciationItems);paramHotFix.setReplace(replaceItems);SpeechSynthesisParam param = SpeechSynthesisParam.builder() .model("qwen-audio-3.0-tts-flash") // Model .voice("longanhuan_v3.6") // Voice .hotFix(paramHotFix) .build();
Taxa de bits de áudio em kbps. Quando o formato de áudio for mp3 ou opus, use bit_rate para ajustar a taxa de bits.
Valor padrão: 32.
Valores válidos: [6, 510].
enable_aigc_tag
boolean
Não
Define se uma marca d'água AIGC deve ser incorporada ao áudio gerado. Quando definido como true, a marca d'água é inserida em arquivos de áudio dos formatos suportados (wav/mp3/opus).
Valor padrão: false.
Apenas qwen-audio-3.0-tts-plus, qwen-audio-3.0-tts-flash, cosyvoice-v3-flash, cosyvoice-v3-plus e cosyvoice-v2 suportam este recurso.
aigc_propagator
String
Não
Define o campo ContentPropagator na marca d'água AIGC, identificando o propagador do conteúdo. Só entra em vigor quando enable_aigc_tag é true.
Valor padrão: UID da Alibaba Cloud.
Apenas qwen-audio-3.0-tts-plus, qwen-audio-3.0-tts-flash, cosyvoice-v3-flash, cosyvoice-v3-plus e cosyvoice-v2 suportam este recurso.
aigc_propagate_id
String
Não
Define o campo PropagateID na marca d'água AIGC, identificando exclusivamente uma ação de propagação específica. Só entra em vigor quando enable_aigc_tag é true.
Valor padrão: ID da solicitação atual de síntese de fala.
Apenas qwen-audio-3.0-tts-plus, qwen-audio-3.0-tts-flash, cosyvoice-v3-flash, cosyvoice-v3-plus e cosyvoice-v2 suportam este recurso.
enable_markdown_filter
boolean
Não
Apenas vozes clonadas de cosyvoice-v3-flash suportam este recurso.
Ative se a filtragem de Markdown deve ser ativada. Quando ativada, o sistema remove automaticamente os símbolos de marcação Markdown do texto de entrada antes da síntese, evitando que sejam lidos em voz alta.
Acionado ao receber um evento de síntese. Contém o quadro de áudio, informações de carimbo de data/hora e dados de saída (tipo de evento, texto original, etc.).
Valor de retorno: com.google.gson.JsonObject, contendo as informações de saída do evento de síntese, incluindo tipo de evento e conteúdo textual. Requer SDK versão >= 2.22.0.
getOutput() retorna um JsonObject que encapsula as informações de saída do evento de síntese. Recupere-o no callback onEvent ou no stream Flowable. Ele contém os seguintes campos:
Campo
Tipo
Descrição
type
String
Tipo de evento. Valores possíveis: sentence-begin (início da sentença; retorna o texto a sintetizar), sentence-synthesis (síntese de áudio em andamento; retorna um bloco de dados de áudio), sentence-end (fim da sentença; retorna conteúdo textual e carimbos de data/hora no nível de palavra).
original_text
String
Texto original da sentença atual. Retornado nos eventos sentence-begin e sentence-end.
sentence
JsonObject
Informações da sentença, contendo o índice da sentença (index) e carimbos de data/hora no nível de palavra (words). O evento sentence-end inclui informações completas de carimbo de data/hora no nível de palavra.
Sem streaming: Chamada bloqueante que envia o texto completo de uma vez e retorna diretamente o áudio integral. Ideal para síntese de fala de textos curtos.
Streaming unidirecional: Chamada não bloqueante que envia o texto completo de uma vez e entrega dados de áudio (potencialmente em blocos) via função de callback. Ideal para cenários de texto curto que exigem baixa latência.
Streaming bidirecional: Chamada não bloqueante que envia texto em vários segmentos e entrega áudio sintetizado incrementalmente via função de callback em tempo real. Ideal para cenários de texto longo que exigem baixa latência.
O comprimento do texto por solicitação não deve exceder 20.000 caracteres.
Reinicialize a instância de SpeechSynthesizer antes de cada chamada ao método call.
Copy
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;import com.alibaba.dashscope.utils.Constants;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.nio.ByteBuffer;public class Main { // Model private static String model = "qwen-audio-3.0-tts-flash"; // Voice private static String voice = "longanhuan_v3.6"; public static void streamAudioDataToSpeaker() { // Request parameters SpeechSynthesisParam param = SpeechSynthesisParam.builder() // The API Keys for the Singapore and Beijing regions are different. Get an API Key: https://www.alibabacloud.com/help/en/model-studio/get-api-key // If the environment variable is not configured, replace the following line with your Model Studio API Key: .apiKey("sk-xxx") .apiKey(System.getenv("DASHSCOPE_API_KEY")) .model(model) // Model .voice(voice) // Voice .build(); // Synchronous mode: disable callback (second parameter is null) SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null); ByteBuffer audio = null; try { // Block until audio is returned audio = synthesizer.call("What's the weather like today?"); } catch (Exception e) { throw new RuntimeException(e); } finally { // Close the WebSocket connection after the task is completed synthesizer.getDuplexApi().close(1000, "bye"); } if (audio != null) { // Save the audio data to a local file "output.mp3" File file = new File("output.mp3"); // The first text transmission requires establishing a WebSocket connection, so the first packet latency includes the connection setup time System.out.println( "[Metric] requestId: " + synthesizer.getLastRequestId() + ", first packet latency (ms): " + synthesizer.getFirstPackageDelay()); try (FileOutputStream fos = new FileOutputStream(file)) { fos.write(audio.array()); } catch (IOException e) { throw new RuntimeException(e); } } } public static void main(String[] args) { // The following configuration is for the Singapore region. Replace "{WorkspaceId}" with your actual workspace ID. The configuration varies by region. Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference"; streamAudioDataToSpeaker(); System.exit(0); }}
O comprimento do texto por solicitação não deve exceder 20.000 caracteres.
Reinicialize a instância de SpeechSynthesizer antes de cada chamada ao método call.
Copy
import com.alibaba.dashscope.audio.tts.SpeechSynthesisResult;import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;import com.alibaba.dashscope.common.ResultCallback;import com.alibaba.dashscope.utils.Constants;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;import java.util.concurrent.CountDownLatch;class TimeUtils { private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); public static String getTimestamp() { return LocalDateTime.now().format(formatter); }}public class Main { // Model private static String model = "qwen-audio-3.0-tts-flash"; // Voice private static String voice = "longanhuan_v3.6"; public static void streamAudioDataToSpeaker() { CountDownLatch latch = new CountDownLatch(1); // Implement the ResultCallback interface ResultCallback<SpeechSynthesisResult> callback = new ResultCallback<SpeechSynthesisResult>() { @Override public void onEvent(SpeechSynthesisResult result) { if (result.getAudioFrame() != null) { // Implement the logic to save audio data locally here System.out.println(TimeUtils.getTimestamp() + " Audio received"); } // Get output information, including event type and original text if (result.getOutput() != null && result.getOutput().has("type")) { System.out.println("Event type: " + result.getOutput().get("type").getAsString() + ", Original text: " + (result.getOutput().has("original_text") ? result.getOutput().get("original_text").getAsString() : "")); } } @Override public void onComplete() { System.out.println(TimeUtils.getTimestamp() + " Complete received, speech synthesis finished"); latch.countDown(); } @Override public void onError(Exception e) { System.out.println("Exception occurred: " + e.toString()); latch.countDown(); } }; // Request parameters SpeechSynthesisParam param = SpeechSynthesisParam.builder() // The API Keys for the Singapore and Beijing regions are different. Get an API Key: https://www.alibabacloud.com/help/en/model-studio/get-api-key // If the environment variable is not configured, replace the following line with your Model Studio API Key: .apiKey("sk-xxx") .apiKey(System.getenv("DASHSCOPE_API_KEY")) .model(model) // Model .voice(voice) // Voice .build(); // Passing "callback" as the second parameter enables asynchronous mode SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, callback); // Non-blocking call that returns null immediately (actual results are delivered asynchronously via the callback interface). Binary audio is received in real time through the onEvent method of the callback interface try { synthesizer.call("What's the weather like today?"); // Wait for synthesis to complete latch.await(); // Wait for playback thread to finish playing } catch (Exception e) { throw new RuntimeException(e); } finally { // Close the WebSocket connection after the task is completed synthesizer.getDuplexApi().close(1000, "bye"); } // The first text transmission requires establishing a WebSocket connection, so the first packet latency includes the connection setup time System.out.println( "[Metric] requestId: " + synthesizer.getLastRequestId() + ", first packet latency (ms): " + synthesizer.getFirstPackageDelay()); } public static void main(String[] args) { // The following configuration is for the Singapore region. Replace "{WorkspaceId}" with your actual workspace ID. The configuration varies by region. Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference"; streamAudioDataToSpeaker(); System.exit(0); }}
O comprimento do texto por chamada individual não deve exceder 20.000 caracteres, e o comprimento acumulado do texto em todas as chamadas não deve ultrapassar 200.000 caracteres.
Durante a entrada em streaming, chame streamingCall várias vezes para enviar segmentos de texto em ordem. O servidor divide automaticamente o texto recebido em sentenças:
Sentenças completas são sintetizadas imediatamente.
Sentenças incompletas ficam em buffer até formarem uma sentença completa.
Ao chamar streamingComplete, o servidor força a síntese de todos os segmentos de texto recebidos ainda não processados, incluindo sentenças incompletas.
O intervalo entre segmentos de texto consecutivos não deve exceder 23 segundos; ultrapassar esse limite aciona uma exceção de "tempo limite de solicitação após 23 segundos".Se não houver texto pendente, chame streamingComplete prontamente para encerrar a tarefa.
Sempre chame o método streamingComplete. Caso contrário, segmentos de texto finais podem não ser convertidos em fala.
O servidor impõe um tempo limite de 23 segundos que não pode ser alterado no lado do cliente.
Copy
import com.alibaba.dashscope.audio.tts.SpeechSynthesisResult;import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisAudioFormat;import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;import com.alibaba.dashscope.common.ResultCallback;import com.alibaba.dashscope.utils.Constants;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;class TimeUtils { private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); public static String getTimestamp() { return LocalDateTime.now().format(formatter); }}public class Main { private static String[] textArray = {"Streaming text-to-speech SDK, ", "can convert input text ", "into audio binary data. ", "Compared to non-streaming speech synthesis, ", "streaming synthesis offers better real-time performance. ", "While users input text, ", "they can hear nearly synchronous audio output, ", "greatly enhancing the interactive experience ", "and reducing user wait time. ", "It is suitable for calling large-scale ", "language models (LLMs) to ", "perform speech synthesis ", "with streaming text input."}; private static String model = "qwen-audio-3.0-tts-flash"; // Model private static String voice = "longanhuan_v3.6"; // Voice public static void streamAudioDataToSpeaker() { // Configure the callback function ResultCallback<SpeechSynthesisResult> callback = new ResultCallback<SpeechSynthesisResult>() { @Override public void onEvent(SpeechSynthesisResult result) { // System.out.println("Message received: " + result); if (result.getAudioFrame() != null) { // Implement the logic to process audio data here System.out.println(TimeUtils.getTimestamp() + " Audio received"); } } @Override public void onComplete() { System.out.println(TimeUtils.getTimestamp() + " Complete received, speech synthesis finished"); } @Override public void onError(Exception e) { System.out.println("Exception occurred: " + e.toString()); } }; // Request parameters SpeechSynthesisParam param = SpeechSynthesisParam.builder() // The API Keys for the Singapore and Beijing regions are different. Get an API Key: https://www.alibabacloud.com/help/en/model-studio/get-api-key // If the environment variable is not configured, replace the following line with your Model Studio API Key: .apiKey("sk-xxx") .apiKey(System.getenv("DASHSCOPE_API_KEY")) .model(model) .voice(voice) .format(SpeechSynthesisAudioFormat .PCM_22050HZ_MONO_16BIT) // Use PCM or MP3 for streaming synthesis .build(); SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, callback); // The call method with Callback will not block the current thread try { for (String text : textArray) { // Send text fragments and receive binary audio in real time through the onEvent method of the callback interface synthesizer.streamingCall(text); } // Wait for streaming speech synthesis to finish synthesizer.streamingComplete(); } catch (Exception e) { throw new RuntimeException(e); } finally { // Close the WebSocket connection after the task is completed synthesizer.getDuplexApi().close(1000, "bye"); } // The first text transmission requires establishing a WebSocket connection, so the first packet latency includes the connection setup time System.out.println( "[Metric] requestId: " + synthesizer.getLastRequestId() + ", first packet latency (ms): " + synthesizer.getFirstPackageDelay()); } public static void main(String[] args) { // The following configuration is for the Singapore region. Replace "{WorkspaceId}" with your actual workspace ID. The configuration varies by region. Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference"; streamAudioDataToSpeaker(); System.exit(0); }}
Flowable é um tipo RxJava que representa um stream reativo com suporte a backpressure. Para mais informações, consulte a documentação do RxJava Flowable.Antes de usar Flowable, certifique-se de integrar a biblioteca RxJava e compreender os conceitos básicos de programação reativa.O comprimento do texto por chamada individual não deve exceder 20.000 caracteres, e o comprimento acumulado do texto em todas as chamadas não deve ultrapassar 200.000 caracteres.
Chamadas com streaming unidirecional
Chamadas com streaming bidirecional
O exemplo a seguir mostra como usar a interface blockingForEach de um objeto Flowable para recuperar cada objeto SpeechSynthesisResult transmitido de forma bloqueante.
Copy
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;import com.alibaba.dashscope.exception.NoApiKeyException;import com.alibaba.dashscope.utils.Constants;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;class TimeUtils { private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); public static String getTimestamp() { return LocalDateTime.now().format(formatter); }}public class Main { private static String model = "qwen-audio-3.0-tts-flash"; // Model private static String voice = "longanhuan_v3.6"; // Voice public static void streamAudioDataToSpeaker() throws NoApiKeyException { // Request parameters SpeechSynthesisParam param = SpeechSynthesisParam.builder() // The API Keys for the Singapore and Beijing regions are different. Get an API Key: https://www.alibabacloud.com/help/en/model-studio/get-api-key // If the environment variable is not configured, replace the following line with your Model Studio API Key: .apiKey("sk-xxx") .apiKey(System.getenv("DASHSCOPE_API_KEY")) .model(model) // Model .voice(voice) // Voice .build(); SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null); synthesizer.callAsFlowable("What's the weather like today?").blockingForEach(result -> { if (result.getAudioFrame() != null) { // Implement the logic to process audio data here System.out.println(TimeUtils.getTimestamp() + " Audio received"); } // Get output information, including event type and original text if (result.getOutput() != null && result.getOutput().has("type")) { System.out.println("Event type: " + result.getOutput().get("type").getAsString() + ", Original text: " + (result.getOutput().has("original_text") ? result.getOutput().get("original_text").getAsString() : "")); } }); // Close the WebSocket connection after the task is completed synthesizer.getDuplexApi().close(1000, "bye"); // The first text transmission requires establishing a WebSocket connection, so the first packet latency includes the connection setup time System.out.println( "[Metric] requestId: " + synthesizer.getLastRequestId() + ", first packet latency (ms): " + synthesizer.getFirstPackageDelay()); } public static void main(String[] args) throws NoApiKeyException { // The following configuration is for the Singapore region. Replace "{WorkspaceId}" with your actual workspace ID. The configuration varies by region. Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference"; streamAudioDataToSpeaker(); System.exit(0); }}
O exemplo a seguir mostra como usar um objeto Flowable como parâmetro de entrada para streaming de texto e utilizar a interface blockingForEach do objeto Flowable retornado para recuperar cada objeto SpeechSynthesisResult transmitido de forma bloqueante.
Copy
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;import com.alibaba.dashscope.exception.NoApiKeyException;import com.alibaba.dashscope.utils.Constants;import io.reactivex.BackpressureStrategy;import io.reactivex.Flowable;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;class TimeUtils { private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); public static String getTimestamp() { return LocalDateTime.now().format(formatter); }}public class Main { private static String[] textArray = {"Streaming text-to-speech SDK, ", "can convert input text ", "into audio binary data. ", "Compared to non-streaming speech synthesis, ", "streaming synthesis offers better real-time performance. ", "While users input text, ", "they can hear nearly synchronous audio output, ", "greatly enhancing the interactive experience ", "and reducing user wait time. ", "It is suitable for calling large-scale ", "language models (LLMs) to ", "perform speech synthesis ", "with streaming text input."}; private static String model = "qwen-audio-3.0-tts-flash"; private static String voice = "longanhuan_v3.6"; public static void streamAudioDataToSpeaker() throws NoApiKeyException { // Simulate streaming input Flowable<String> textSource = Flowable.create(emitter -> { new Thread(() -> { for (int i = 0; i < textArray.length; i++) { emitter.onNext(textArray[i]); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } emitter.onComplete(); }).start(); }, BackpressureStrategy.BUFFER); // Request parameters SpeechSynthesisParam param = SpeechSynthesisParam.builder() // The API Keys for the Singapore and Beijing regions are different. Get an API Key: https://www.alibabacloud.com/help/en/model-studio/get-api-key // If the environment variable is not configured, replace the following line with your Model Studio API Key: .apiKey("sk-xxx") .apiKey(System.getenv("DASHSCOPE_API_KEY")) .model(model) // Model .voice(voice) // Voice .build(); SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null); synthesizer.streamingCallAsFlowable(textSource).blockingForEach(result -> { if (result.getAudioFrame() != null) { // Implement the logic to play audio here System.out.println( TimeUtils.getTimestamp() + " Binary audio size: " + result.getAudioFrame().capacity()); } // Get output information, including event type and original text if (result.getOutput() != null && result.getOutput().has("type")) { System.out.println("Event type: " + result.getOutput().get("type").getAsString() + ", Original text: " + (result.getOutput().has("original_text") ? result.getOutput().get("original_text").getAsString() : "")); } }); synthesizer.getDuplexApi().close(1000, "bye"); // The first text transmission requires establishing a WebSocket connection, so the first packet latency includes the connection setup time System.out.println( "[Metric] requestId: " + synthesizer.getLastRequestId() + ", first packet latency (ms): " + synthesizer.getFirstPackageDelay()); } public static void main(String[] args) throws NoApiKeyException { // The following configuration is for the Singapore region. Replace "{WorkspaceId}" with your actual workspace ID. The configuration varies by region. Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference"; streamAudioDataToSpeaker(); System.exit(0); }}
O DashScope Java SDK usa pool de conexões OkHttp3 para reduzir a sobrecarga causada pelo estabelecimento repetido de conexões. Para mais informações, consulte High-concurrency best practices.