Synthétisez de la parole avec Qwen-Audio-TTS/CosyVoice à l'aide du SDK Java DashScope.
Guide d'utilisation : Pour une présentation des modèles et des recommandations de sélection, consultez la rubrique Synthèse vocale.
Points de terminaison du service
Par défaut, le SDK se connecte au point de terminaison de la région de Pékin. Pour utiliser une autre région, définissez Constants.baseWebsocketApiUrl avant d'initialiser le SDK.
Singapore
wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference
Remplacez {WorkspaceId} par votre ID d'espace de travail réel.
China (Beijing)
wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/inference
Remplacez {WorkspaceId} par votre ID d'espace de travail réel.
Basculer vers la région de Singapour :
import com.alibaba.dashscope.utils.Constants;
// Set this before any SDK initialization
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
ImportantAlibaba Cloud Model Studio a publié des domaines spécifiques aux espaces de travail pour les régions Chine (Pékin) et Singapour. Ces nouveaux domaines dédiés offrent de meilleures performances et une stabilité accrue pour les requêtes d'inférence. Nous vous recommandons de migrer vers ces nouveaux domaines :
- Chine (Pékin) : passez de
dashscope.aliyuncs.comà{WorkspaceId}.cn-beijing.maas.aliyuncs.com - Singapour : passez de
dashscope-intl.aliyuncs.comà{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com
Remplacez {WorkspaceId} par votre ID d'espace de travail réel. Les domaines existants restent entièrement fonctionnels.
SpeechSynthesizer
Package : com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer
Constructeur
public SpeechSynthesizer(SpeechSynthesisParam param, ResultCallback<SpeechSynthesisResult> callback)
Paramètres :
param: Paramètres de synthèse vocale, construits avec SpeechSynthesisParam.builder()callback: Rappel pour les appels en streaming. Transmettez la valeur null pour les appels sans streaming.
call() - Synthèse sans streaming ou en streaming unidirectionnel
Signature de la méthode :
public ByteBuffer call(String text)
Paramètres :
Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
text | String | Oui | Texte à synthétiser. Longueur maximale : 20 000 caractères. |
Valeur de retour : ByteBuffer ou null. Pour les appels sans streaming, renvoie les données audio complètes. Pour les appels en streaming unidirectionnel, cette méthode renvoie null ; l'audio est transmis via le rappel.
streamingCall() - Synthèse en streaming bidirectionnel
Signature de la méthode :
public void streamingCall(String text)
Paramètres :
Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
text | String | Oui | Texte à synthétiser. Longueur maximale : 20 000 caractères. Vous pouvez appeler cette méthode plusieurs fois pour ajouter du texte. |
streamingComplete() - Terminer le streaming bidirectionnel
Signature de la méthode :
public void streamingComplete()
Met fin à l'appel en streaming bidirectionnel et notifie au serveur que tout le texte a été envoyé.
streamingCancel() - Annuler le streaming bidirectionnel
Signature de la méthode :
public void streamingCancel()
Description : Annule la tâche de synthèse vocale en streaming bidirectionnel en cours. Après avoir appelé cette méthode, le SDK met immédiatement fin à la tâche actuelle. Vous pouvez démarrer une nouvelle tâche de synthèse sur la même connexion sans réinitialiser l'instance SpeechSynthesizer.
ImportantExigence de version : Cette fonctionnalité nécessite le SDK Java 2.22.26 ou une version ultérieure.
ImportantLimitations du modèle :
- Chine (Pékin) : Tous les modèles Qwen-Audio-TTS prennent en charge cette fonctionnalité. Les modèles CosyVoice nécessitent la version v2 ou ultérieure.
- Singapour : Tous les modèles Qwen-Audio-TTS prennent en charge cette fonctionnalité. Les modèles CosyVoice ne prennent pas en charge cette fonctionnalité.
callAsFlowable() - Synthèse en streaming unidirectionnel (réactif)
Signature de la méthode :
public Flowable<SpeechSynthesisResult> callAsFlowable(String text)
Paramètres :
Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
text | String | Oui | Texte à synthétiser. |
Valeur de retour : Flux réactif Flowable<SpeechSynthesisResult>.
streamingCallAsFlowable() - Synthèse en streaming bidirectionnel (réactif)
Signature de la méthode :
public Flowable<SpeechSynthesisResult> streamingCallAsFlowable(Flowable<String> textStream)
Paramètres :
Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
textStream | Flowable<String> | Oui | Flux réactif de texte. |
Valeur de retour : Flux réactif Flowable<SpeechSynthesisResult>.
getDuplexApi().close() - Fermer la connexion WebSocket
Signature de la méthode :
public boolean getDuplexApi().close(int code, String reason)
Paramètres :
Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
code | int | Oui | Code de fermeture. |
reason | String | Oui | Motif de fermeture. |
Valeur de retour : boolean. Renvoie true si la connexion a été fermée avec succès, false dans le cas contraire.
getLastRequestId() - Obtenir l'ID de requête
Signature de la méthode :
public String getLastRequestId()
Valeur de retour : String, l'ID de requête.
getFirstPackageDelay() - Obtenir la latence du premier paquet
Signature de la méthode :
public long getFirstPackageDelay()
Valeur de retour : long. La latence du premier paquet en millisecondes, mesurée entre l'envoi du premier segment de texte et la réception du premier paquet audio.
SpeechSynthesisParam
Package : com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam
Exemple :
SpeechSynthesisParam param = SpeechSynthesisParam.builder()
.model("qwen-audio-3.0-tts-flash") // Model
.voice("longanhuan_v3.6") // Voice
.format(SpeechSynthesisAudioFormat.WAV_8000HZ_MONO_16BIT) // Audio encoding format and sample rate
.volume(50) // Volume. Value range: [0, 100]
.speechRate(1.0f) // Speech rate. Value range: [0.5, 2]
.pitchRate(1.0f) // Pitch. Value range: [0.5, 2]
.build();
Méthodes de construction
| Méthode | Type de paramètre | Obligatoire | Description |
|---|---|---|---|
| String | Oui | Le nom du modèle. |
| String | Oui | voice La voix utilisée pour la synthèse vocale.
|
| enum | Non | Format d'encodage audio et fréquence d'échantillonnage. Valeur par défaut : SpeechSynthesisAudioFormat.MP3_22050HZ_MONO_256KBPS. Package SpeechSynthesisAudioFormat : |
| int | Non | Le niveau de volume. Valeur par défaut : 50. Plage de valeurs valides : [0, 100]. |
| float | Non | La vitesse de parole. Valeur par défaut : 1,0. Plage de valeurs valides : [0,5, 2,0]. |
| float | Non | La hauteur tonale. Valeur par défaut : 1,0. Plage de valeurs valides : [0,5, 2,0]. |
| boolean | Non | Indique s'il faut activer les horodatages au niveau des mots. Valeur par défaut : false. Disponible uniquement en mode de sortie en continu (streaming). Voix prises en charge : voix clonées 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 et cosyvoice-v2, ainsi que les voix système indiquées comme prises en charge dans la liste des voix Qwen-Audio-TTS et la liste des voix CosyVoice. Les voix clonées d'autres modèles ne prennent pas en charge cette fonctionnalité. |
| int | Non | Une graine aléatoire permettant de contrôler la variation dans le résultat de la synthèse. Lorsque la version du modèle, le texte, la voix et les autres paramètres restent inchangés, l'utilisation de la même graine produit des résultats identiques. Valeur par défaut : 0. Plage de valeurs valides : [0, 65535]. Pour les versions du SDK antérieures à la 2.21.7, définissez |
| List<String> | Non | Important
Spécifie la langue cible de la synthèse vocale afin d'améliorer la qualité du résultat. Utilisez ce paramètre lorsque la prononciation des chiffres, le développement des abréviations, la lecture des symboles ou la synthèse dans des langues minoritaires ne donnent pas le résultat escompté. Par exemple :
Valeurs valides :
|
| String | Non | Contrôle les caractéristiques de la synthèse, telles que le dialecte, l'émotion ou le style d'élocution. Pour plus de détails sur l'utilisation, consultez la section Contrôle par instruction. |
| ParamHotFix | Non | Configure les corrections de prononciation et les remplacements de texte appliqués avant la synthèse. Cette fonctionnalité n'est pas prise en charge par qwen-audio-3,0-tts-plus, qwen-audio-3,0-tts-flash ni cosyvoice-v2. Paramètres :
Exemple : |
| String, Object | Non | Définit les paramètres supplémentaires. |
| Map | Non | Définit les paramètres supplémentaires. |
Paramètres supplémentaires
Définissez ces paramètres via parameter() ou parameters().
Exemple :
SpeechSynthesisParam param = SpeechSynthesisParam.builder()
.model("qwen-audio-3.0-tts-flash")
.voice("longanhuan_v3.6")
.parameter("enable_markdown_filter", true)
.build();
| Parameter | Type | Required | Description |
|---|---|---|---|
| integer | No | Débit binaire audio en kbps. Lorsque le format audio est mp3 ou opus, utilisez Valeur par défaut : 32. Valeurs valides : [6, 510]. |
| boolean | No | Indique s'il faut intégrer un filigrane AIGC dans l'audio généré. Lorsqu'elle est définie sur true, cette option intègre le filigrane dans les fichiers audio aux formats pris en charge (wav/mp3/opus). Valeur par défaut : false. Seuls qwen-audio-3,0-tts-plus, qwen-audio-3,0-tts-flash, cosyvoice-v3-flash, cosyvoice-v3-plus et cosyvoice-v2 prennent en charge cette fonctionnalité. |
| String | No | Définit le champ Valeur par défaut : UID Alibaba Cloud. Seuls qwen-audio-3,0-tts-plus, qwen-audio-3,0-tts-flash, cosyvoice-v3-flash, cosyvoice-v3-plus et cosyvoice-v2 prennent en charge cette fonctionnalité. |
| String | No | Définit le champ Valeur par défaut : ID de la demande de synthèse vocale actuelle. Seuls qwen-audio-3,0-tts-plus, qwen-audio-3,0-tts-flash, cosyvoice-v3-flash, cosyvoice-v3-plus et cosyvoice-v2 prennent en charge cette fonctionnalité. |
| boolean | No | ImportantSeules les voix clonées de cosyvoice-v3-flash prennent en charge cette fonctionnalité. Indique s'il faut activer le filtrage Markdown. Lorsque cette option est activée, le système supprime automatiquement les symboles de balisage Markdown du texte d'entrée avant la synthèse, afin d'éviter qu'ils ne soient lus à haute voix. Valeur par défaut : false. Valeurs valides :
|
ResultCallback
Package : com.alibaba.dashscope.common.ResultCallback
onEvent() - Réception des données audio
Signature de la méthode :
public void onEvent(SpeechSynthesisResult result)
Paramètres :
Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
result | Oui | Déclenché à la réception d'un événement de synthèse. Contient la trame audio, les informations d'horodatage et les données de sortie (type d'événement, texte original, etc.). |
onComplete() - Fin de la synthèse
Signature de la méthode :
public void onComplete()
Déclenché lorsque la synthèse vocale est terminée.
onError() - Gestion des erreurs
Signature de la méthode :
public void onError(Exception e)
Paramètres :
Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
e | Exception | Oui | Déclenché en cas d'erreur. Contient les informations relatives à l'exception. |
SpeechSynthesisResult
Package : com.alibaba.dashscope.audio.tts.SpeechSynthesisResult
getAudioFrame() - Obtention d'une trame audio
Signature de la méthode :
public ByteBuffer getAudioFrame()
Valeur de retour : ByteBuffer, la trame de données audio.
getTimestamp() - Obtention des informations d'horodatage
Signature de la méthode :
public Sentence getTimestamp()
Valeur de retour : Sentence, les informations d'horodatage.
getOutput() - Obtention des informations de sortie
Signature de la méthode :
public JsonObject getOutput()
Valeur de retour : com.google.gson.JsonObject, les informations de sortie de l'événement de synthèse, contenant le type d'événement et le contenu textuel. Nécessite une version du SDK >= 2.22.0.
Informations d'horodatage au niveau de la phrase (Sentence)
Sentence encapsule les informations d'horodatage au niveau de la phrase.
getBeginTime() - Obtention de l'heure de début de la phrase
Signature de la méthode :
public int getBeginTime()
Valeur de retour : Heure de début de la phrase, en millisecondes.
getEndTime() - Obtention de l'heure de fin de la phrase
Signature de la méthode :
public int getEndTime()
Valeur de retour : Heure de fin de la phrase, en millisecondes.
getWords() - Obtention des horodatages au niveau des mots
Signature de la méthode :
public List<Word> getWords()
Valeur de retour : Une List d'objets Word contenant les informations d'horodatage au niveau des mots. Peut être vide.
Informations d'horodatage au niveau du mot (Word)
Word encapsule les informations d'horodatage au niveau du mot.
getBeginTime() - Obtention de l'heure de début du mot
Signature de la méthode :
public int getBeginTime()
Valeur de retour : Heure de début du mot, en millisecondes.
getEndTime() - Obtention de l'heure de fin du mot
Signature de la méthode :
public int getEndTime()
Valeur de retour : Heure de fin du mot, en millisecondes.
getText() - Obtention du texte
Signature de la méthode :
public String getText()
Valeur de retour : String, le contenu textuel.
getPhonemes() - Obtention des horodatages au niveau des phonèmes
Signature de la méthode :
public List<Phoneme> getPhonemes()
Valeur de retour : Une List d'objets Phoneme contenant les informations d'horodatage au niveau des phonèmes. Peut être vide.
Informations d'horodatage au niveau du phonème (Phoneme)
Phoneme encapsule les informations d'horodatage au niveau du phonème.
getBeginTime() - Obtention de l'heure de début du phonème
Signature de la méthode :
public int getBeginTime()
Valeur de retour : Heure de début du phonème, en millisecondes.
getEndTime() - Obtention de l'heure de fin du phonème
Signature de la méthode :
public int getEndTime()
Valeur de retour : Heure de fin du phonème, en millisecondes.
getText() - Obtention du texte
Signature de la méthode :
public String getText()
Valeur de retour : String, le contenu textuel.
getTone() - Obtention du ton
Signature de la méthode :
public int getTone()
Valeur de retour : La valeur du ton.
- En anglais, 0, 1 et 2 représentent respectivement l'absence d'accentuation, l'accentuation primaire et l'accentuation secondaire.
- En pinyin chinois, 1, 2, 3, 4 et 5 représentent respectivement les premier, deuxième, troisième, quatrième tons et le ton neutre.
Informations de sortie (output)
getOutput() renvoie un JsonObject qui encapsule les informations de sortie de l'événement de synthèse. Récupérez-le dans le rappel onEvent ou dans le flux Flowable. Il contient les champs suivants :
Champ | Type | Description |
|---|---|---|
type | String | Type d'événement. Valeurs possibles : |
original_text | String | Texte original de la phrase actuelle. Renvoyé dans les événements |
sentence | JsonObject | Informations sur la phrase, contenant l'index de la phrase ( |
Exemples de code
Le SDK prend en charge les modes de synthèse suivants :
- Non streaming : appel bloquant qui transmet l'intégralité du texte en une seule fois et renvoie directement le fichier audio complet. Cette méthode convient particulièrement à la synthèse vocale de textes courts.
- Streaming unidirectionnel : appel non bloquant qui transmet l'intégralité du texte en une seule fois et fournit les données audio (potentiellement par blocs) via une fonction de rappel. Plus adapté aux scénarios de textes courts nécessitant une faible latence.
- Streaming bidirectionnel : appel non bloquant qui envoie le texte en plusieurs segments et délivre l'audio synthétisé de manière incrémentielle via une fonction de rappel en temps réel. Conçu pour les scénarios de textes longs exigeant une faible latence.
Appels non streaming
La longueur du texte par requête ne doit pas dépasser 20 000 caractères.
ImportantRéinitialisez l'instance SpeechSynthesizer avant chaque appel à la méthode call.
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);
}
}
Appels en streaming unidirectionnel
La longueur du texte par requête ne doit pas dépasser 20 000 caractères.
ImportantRéinitialisez l'instance SpeechSynthesizer avant chaque appel à la méthode call.
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);
}
}
Appels en streaming bidirectionnel
La longueur du texte pour chaque appel individuel ne doit pas dépasser 20 000 caractères, et la longueur cumulée du texte sur l'ensemble des appels ne doit pas excéder 200 000 caractères.
-
Pendant l'entrée en streaming, appelez
streamingCallplusieurs fois pour soumettre les segments de texte dans l'ordre. Le serveur divise automatiquement le texte reçu en phrases :- Les phrases complètes sont synthétisées immédiatement.
- Les phrases incomplètes sont mises en mémoire tampon jusqu'à ce qu'elles forment une phrase complète.
Lorsque
streamingCompleteest appelé, le serveur force la synthèse de tous les segments de texte reçus mais non traités, y compris les phrases incomplètes. -
L'intervalle entre deux segments de texte consécutifs ne doit pas dépasser 23 secondes ; le dépassement de cette limite déclenche une exception « request timeout after 23 seconds ».
S'il n'y a aucun texte en attente, appelez
streamingCompleterapidement pour terminer la tâche.ImportantAppelez toujours la méthode
streamingComplete. Sinon, les derniers segments de texte risquent de ne pas être convertis en parole.Le serveur applique un délai d'expiration de 23 secondes qui ne peut pas être modifié côté client.
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);
}
}
Appels basés sur Flowable
Flowable est un type RxJava représentant un flux réactif compatible avec la contre-pression (backpressure). Pour plus d'informations, consultez la documentation RxJava Flowable.
Avant d'utiliser Flowable, assurez-vous que la bibliothèque RxJava est intégrée et que vous maîtrisez les bases de la programmation réactive.
La longueur du texte pour chaque appel individuel ne doit pas dépasser 20 000 caractères, et la longueur cumulative du texte pour l'ensemble des appels ne doit pas excéder 200 000 caractères.
Appels en streaming unidirectionnel
L'exemple suivant illustre l'utilisation de l'interface blockingForEach d'un objet Flowable pour récupérer chaque objet SpeechSynthesisResult diffusé en streaming, de manière bloquante.
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);
}
}
Appels en streaming bidirectionnel
L'exemple ci-dessous montre comment utiliser un objet Flowable comme paramètre d'entrée pour la diffusion de texte en streaming, puis exploiter l'interface blockingForEach de l'objet Flowable renvoyé afin de récupérer chaque objet SpeechSynthesisResult transmis, de manière bloquante.
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);
}
}
Appels à forte concurrence
Le SDK Java DashScope s'appuie sur le pool de connexions OkHttp3 pour réduire la surcharge liée à l'établissement répété de connexions. Pour en savoir plus, reportez-vous aux bonnes pratiques pour les appels à forte concurrence.