録音をアップロードして音声を作成し、Qwen-Omni または Qwen-Omni-Realtime の会話で使用できます。このガイドでは、対応言語、音声の要件、クローニング手順、課金、音声の管理について説明します。
リクエストパラメーター、レスポンス、エラーについては、音声クローニング API リファレンス を参照してください。
重要このドキュメントでは、Qwen-Omni と Qwen-Omni-Realtime の音声クローニング API について説明します。音声合成モデルについては、音声クローニングユーザーガイド を参照してください。
重要中国(北京)およびシンガポールリージョンでは、ワークスペース固有のドメインを使用できます。これらのドメインは推論のパフォーマンスと安定性を向上させます。次のドメインへの移行を推奨します。
- 中国 (北京):
https://dashscope.aliyuncs.comからhttps://{WorkspaceId}.cn-beijing.maas.aliyuncs.com - シンガポール:
https://dashscope-intl.aliyuncs.comからhttps://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com
{WorkspaceId} は、Alibaba Cloud Model Studio コンソールの Workspace Details ページで確認できます。従来のドメインも引き続き使用できます。
音声の要件
録音の品質はクローニングの結果に影響します。
システム音声と音声クローニングでは、対応する方言が異なります。次の表は、音声クローニングに対応する言語と方言を示します。システム音声については、音声一覧 を参照してください。
項目 | 要件 |
|---|---|
対応形式 | WAV(16 ビット)、MP3、M4A |
長さ | 10~20 秒を推奨します。最大: 60 秒。 |
ファイルサイズ | < 10 MB |
サンプルレート | >= 24 kHz |
チャンネル数 | モノラル |
内容 | 背景音のない、連続した明瞭な発話を少なくとも 3 秒間含めてください。残りの部分には短い間(<=2 秒)を含めることができます。音声全体を通じて、BGM、ノイズ、他の人の声を避けてください。通常の話し声を入力として使用し、楽曲や歌唱音声はアップロードしないでください。 |
言語 | 中国語(zh)、英語(en)、ドイツ語(de)、イタリア語(it)、ポルトガル語(pt)、スペイン語(es)、日本語(ja)、韓国語(ko)、フランス語(fr)、ロシア語(ru)、タイ語(th)、インドネシア語(id)、アラビア語(ar)、チェコ語(cs)、デンマーク語(da)、オランダ語(nl)、フィンランド語(fi)、ヘブライ語(he)、ヒンディー語(hi)、アイスランド語(is)、マレー語(ms)、ノルウェー語(no)、ペルシャ語(fa)、ポーランド語(pl)、スウェーデン語(sv)、タガログ語(tl)、トルコ語(tr)、ウルドゥー語(ur)、ベトナム語(vi) 中国語の方言: Dongbei、Shannxi、Sichuan、Henan、Changsha、Tianjin、Hangzhou、Liaoning、Shenyang、Anshan |
クイックスタート
1. ワークフロー
音声を作成してから、モデル呼び出しで使用します。
-
音声の作成
音声の作成 API を呼び出し、音声クリップをアップロードします。システムは音声を分析し、カスタムのクローン音声を作成します。この手順では、音声を使用する omni モデルを指定するために、
target_modelを必ず設定してください。すでに音声を作成している場合は、この手順をスキップして次に進めます。音声の一覧取得 API を呼び出すと、既存の音声を確認できます。
-
会話で音声を使用する
作成した音声を指定して、Omni API(リアルタイムまたは非リアルタイム)を呼び出します。Omni モデルは
target_modelと一致する必要があります。
2. モデルの設定と前提条件
モデルを選択し、前提条件を満たしてください。
モデルの設定
音声クローニングには、次の 2 つのモデルが必要です。
-
音声クローニングモデル:qwen-voice-enrollment
-
音声を使用する Omni モデル:
- qwen3.8-omni-flash-realtime
- qwen3.5-omni-plus-realtime
- qwen3.5-omni-flash-realtime
- qwen3.5-omni-plus
- qwen3.5-omni-flash
前提条件
- API キーの取得:API キーの取得 を参照してください。セキュリティのため、API キーは環境変数に設定してください。
- SDK のインストール:最新の DashScope SDK のインストール を参照してください。
- クローニング用の音声の準備:音声の要件 を満たす音声を用意してください。
3. エンドツーエンドの例
この例では、音声をクローニングし、その音声を会話で使用します。
重要な原則:クローニング時に指定した target_model は、その後の Omni API 呼び出しで指定するモデルと一致する必要があります。一致しない場合、合成は失敗します。サンプルファイル voice.mp3 を自分の音声に置き換えてください。
リアルタイム
Qwen-Omni-Realtime モデルに適用されます。Qwen-Omni-Realtime を参照してください。
# Requirements: dashscope >= 1.26.5, pyaudio
import os
import requests
import base64
import pathlib
import time
import pyaudio
from dashscope.audio.qwen_omni import MultiModality, OmniRealtimeCallback, OmniRealtimeConversation
import dashscope
# China (Beijing) region. Replace {WorkspaceId} with your Bailian workspace ID. URLs vary by region.
dashscope.base_http_api_url = "https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api/v1"
# ======= Configuration =======
DEFAULT_TARGET_MODEL = "qwen3.8-omni-flash-realtime" # Must be the same model for cloning and conversation
DEFAULT_PREFERRED_NAME = "guanyu"
DEFAULT_AUDIO_MIME_TYPE = "audio/mpeg"
VOICE_FILE_PATH = "voice.mp3" # Path to the local audio file for voice cloning
def create_voice(file_path: str,
target_model: str = DEFAULT_TARGET_MODEL,
preferred_name: str = DEFAULT_PREFERRED_NAME,
audio_mime_type: str = DEFAULT_AUDIO_MIME_TYPE) -> str:
"""
Create a custom voice and return the voice parameter.
"""
# API keys differ between the Singapore and Beijing regions. Get an API key: https://www.alibabacloud.com/help/model-studio/get-api-key
# If you haven't set an environment variable, replace the following line with: api_key = "sk-xxx"
api_key = os.getenv("DASHSCOPE_API_KEY")
file_path_obj = pathlib.Path(file_path)
if not file_path_obj.exists():
raise FileNotFoundError(f"Audio file not found: {file_path}")
base64_str = base64.b64encode(file_path_obj.read_bytes()).decode()
data_uri = f"data:{audio_mime_type};base64,{base64_str}"
# The following is the Singapore region URL. Replace {WorkspaceId} with your actual workspace ID. URLs vary by region.
url = "https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api/v1/services/audio/tts/customization"
payload = {
"model": "qwen-voice-enrollment",
"parameters": {"voice_clone_mode": "normal"},
"input": {
"action": "create",
"target_model": target_model,
"preferred_name": preferred_name,
"audio": {"data": data_uri}
}
}
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
resp = requests.post(url, json=payload, headers=headers)
if resp.status_code != 200:
raise RuntimeError(f"Failed to create voice: {resp.status_code}, {resp.text}")
try:
return resp.json()["output"]["voice"]
except (KeyError, ValueError) as e:
raise RuntimeError(f"Failed to parse voice response: {e}")
class SimpleCallback(OmniRealtimeCallback):
def __init__(self, pya):
self.pya = pya
self.out = None
def on_open(self):
self.out = self.pya.open(
format=pyaudio.paInt16,
channels=1,
rate=24000,
output=True
)
def on_event(self, response):
if response['type'] == 'response.audio.delta':
self.out.write(base64.b64decode(response['delta']))
elif response['type'] == 'conversation.item.input_audio_transcription.completed':
print(f"[User] {response['transcript']}")
elif response['type'] == 'response.audio_transcript.done':
print(f"[LLM] {response['transcript']}")
if __name__ == '__main__':
# If you haven't set an environment variable, replace the following line with: dashscope.api_key = "sk-xxx"
dashscope.api_key = os.getenv("DASHSCOPE_API_KEY")
# The following is the Singapore region URL. Replace {WorkspaceId} with your actual workspace ID. URLs vary by region.
url = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/realtime"
# Step 1: Clone a voice
voice = create_voice(VOICE_FILE_PATH)
print(f"Voice cloning complete. Voice: {voice}")
# Step 2: Start a real-time conversation with the cloned voice
pya = pyaudio.PyAudio()
callback = SimpleCallback(pya)
conv = OmniRealtimeConversation(model=DEFAULT_TARGET_MODEL, callback=callback, url=url)
conv.connect()
conv.update_session(
output_modalities=[MultiModality.AUDIO, MultiModality.TEXT],
voice=voice # Use the cloned voice
)
mic = pya.open(format=pyaudio.paInt16, channels=1, rate=16000, input=True)
print("Conversation started. Speak into your microphone (Ctrl+C to exit)...")
try:
while True:
audio_data = mic.read(3200, exception_on_overflow=False)
conv.append_audio(base64.b64encode(audio_data).decode())
time.sleep(0.01)
except KeyboardInterrupt:
conv.close()
mic.close()
callback.out.close()
pya.terminate()
print("\nConversation ended")
import com.alibaba.dashscope.audio.omni.*;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import javax.sound.sampled.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
public class Main {
// ===== Constants =====
// Use the same model for voice cloning and real-time conversation
private static final String TARGET_MODEL = "qwen3.8-omni-flash-realtime";
private static final String PREFERRED_NAME = "guanyu";
// Relative path to the local audio file for voice cloning
private static final String AUDIO_FILE = "voice.mp3";
private static final String AUDIO_MIME_TYPE = "audio/mpeg";
// Generate a data URI
public static String toDataUrl(String filePath) throws IOException {
byte[] bytes = Files.readAllBytes(Paths.get(filePath));
String encoded = Base64.getEncoder().encodeToString(bytes);
return "data:" + AUDIO_MIME_TYPE + ";base64," + encoded;
}
// Call the API to create a voice
public static String createVoice() throws Exception {
// The API keys for the Singapore and Beijing regions are different. Get an API key: https://www.alibabacloud.com/help/model-studio/get-api-key
// If you haven't configured the environment variable, replace the following line with: String apiKey = "sk-xxx"
String apiKey = System.getenv("DASHSCOPE_API_KEY");
String jsonPayload =
"{"
+ "\"model\": \"qwen-voice-enrollment\","
+ "\"parameters\": {\"voice_clone_mode\": \"normal\"},"
+ "\"input\": {"
+ "\"action\": \"create\","
+ "\"target_model\": \"" + TARGET_MODEL + "\","
+ "\"preferred_name\": \"" + PREFERRED_NAME + "\","
+ "\"audio\": {"
+ "\"data\": \"" + toDataUrl(AUDIO_FILE) + "\""
+ "}"
+ "}"
+ "}";
// The following is the Singapore region URL. Replace {WorkspaceId} with your actual workspace ID. URLs vary by region.
String url = "https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api/v1/services/audio/tts/customization";
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Authorization", "Bearer " + apiKey);
con.setRequestProperty("Content-Type", "application/json");
con.setDoOutput(true);
try (OutputStream os = con.getOutputStream()) {
os.write(jsonPayload.getBytes(StandardCharsets.UTF_8));
}
int status = con.getResponseCode();
try (BufferedReader br = new BufferedReader(
new InputStreamReader(status >= 200 && status < 300 ? con.getInputStream() : con.getErrorStream(),
StandardCharsets.UTF_8))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
response.append(line);
}
if (status == 200) {
JsonObject jsonObj = new Gson().fromJson(response.toString(), JsonObject.class);
return jsonObj.getAsJsonObject("output").get("voice").getAsString();
}
throw new IOException("Failed to create voice: " + status + " - " + response);
}
}
// Simple audio player
static class SimpleAudioPlayer {
private final SourceDataLine line;
private final Queue<byte[]> audioQueue = new ConcurrentLinkedQueue<>();
private final Thread playerThread;
private final AtomicBoolean shouldStop = new AtomicBoolean(false);
public SimpleAudioPlayer() throws LineUnavailableException {
AudioFormat format = new AudioFormat(24000, 16, 1, true, false);
line = AudioSystem.getSourceDataLine(format);
line.open(format);
line.start();
playerThread = new Thread(() -> {
while (!shouldStop.get()) {
byte[] audio = audioQueue.poll();
if (audio != null) {
line.write(audio, 0, audio.length);
} else {
try { Thread.sleep(10); } catch (InterruptedException ignored) {}
}
}
}, "AudioPlayer");
playerThread.start();
}
public void play(String base64Audio) {
audioQueue.add(Base64.getDecoder().decode(base64Audio));
}
public void close() {
shouldStop.set(true);
try { playerThread.join(1000); } catch (InterruptedException ignored) {}
line.drain();
line.close();
}
}
public static void main(String[] args) {
try {
// 1. Voice cloning: create a custom voice
String voice = createVoice();
System.out.println("Voice cloning complete. Voice: " + voice);
// 2. Use the cloned voice in a real-time conversation
SimpleAudioPlayer player = new SimpleAudioPlayer();
AtomicBoolean shouldStop = new AtomicBoolean(false);
OmniRealtimeParam param = OmniRealtimeParam.builder()
.model(TARGET_MODEL)
// The API keys for the Singapore and Beijing regions are different. Get an API key: https://www.alibabacloud.com/help/model-studio/get-api-key
// If you haven't configured the environment variable, replace the following line with: .apikey("sk-xxx")
.apikey(System.getenv("DASHSCOPE_API_KEY"))
// The following is the Singapore region URL. Replace {WorkspaceId} with your actual workspace ID. URLs vary by region.
.url("wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/realtime")
.build();
OmniRealtimeConversation conversation = new OmniRealtimeConversation(param, new OmniRealtimeCallback() {
@Override public void onOpen() { System.out.println("Connection established"); }
@Override public void onClose(int code, String reason) {
System.out.println("Connection closed (" + code + "): " + reason);
shouldStop.set(true);
}
@Override public void onEvent(JsonObject event) {
String type = event.get("type").getAsString();
if ("response.audio.delta".equals(type)) {
player.play(event.get("delta").getAsString());
} else if ("conversation.item.input_audio_transcription.completed".equals(type)) {
System.out.println("[User] " + event.get("transcript").getAsString());
} else if ("response.audio_transcript.done".equals(type)) {
System.out.println("[LLM] " + event.get("transcript").getAsString());
}
}
});
conversation.connect();
conversation.updateSession(OmniRealtimeConfig.builder()
.modalities(Arrays.asList(OmniRealtimeModality.AUDIO, OmniRealtimeModality.TEXT))
.voice(voice) // Use the cloned custom voice
.enableTurnDetection(true)
.enableInputAudioTranscription(true)
.build()
);
System.out.println("Conversation started. Speak into the microphone (Ctrl+C to exit)...");
AudioFormat format = new AudioFormat(16000, 16, 1, true, false);
TargetDataLine mic = AudioSystem.getTargetDataLine(format);
mic.open(format);
mic.start();
ByteBuffer buffer = ByteBuffer.allocate(3200);
while (!shouldStop.get()) {
int bytesRead = mic.read(buffer.array(), 0, buffer.capacity());
if (bytesRead > 0) {
conversation.appendAudio(Base64.getEncoder().encodeToString(buffer.array()));
}
Thread.sleep(20);
}
conversation.close(1000, "Normal exit");
player.close();
mic.close();
System.out.println("\nConversation ended");
} catch (NoApiKeyException e) {
System.err.println("API KEY not found. Set the DASHSCOPE_API_KEY environment variable.");
} catch (Exception e) {
e.printStackTrace();
}
System.exit(0);
}
}
非リアルタイム
Qwen3.5-Omni モデルに適用されます。非リアルタイム(Qwen-Omni) を参照してください。
# Requirements: dashscope >= 1.23.9, soundfile, numpy
import os
import requests
import base64
import pathlib
import numpy as np
import soundfile as sf
import dashscope
# China (Beijing) region. Replace {WorkspaceId} with your Bailian workspace ID. URLs vary by region.
dashscope.base_http_api_url = "https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api/v1"
# ======= Configuration =======
DEFAULT_TARGET_MODEL = "qwen3.5-omni-plus" # Voice cloning and non-realtime calls must use the same model
DEFAULT_PREFERRED_NAME = "guanyu"
DEFAULT_AUDIO_MIME_TYPE = "audio/mpeg"
VOICE_FILE_PATH = "voice.mp3" # Path to the local audio file for voice cloning
def create_voice(file_path: str,
target_model: str = DEFAULT_TARGET_MODEL,
preferred_name: str = DEFAULT_PREFERRED_NAME,
audio_mime_type: str = DEFAULT_AUDIO_MIME_TYPE) -> str:
"""
Create a custom voice and return the voice parameter.
"""
# API keys differ between Singapore and Beijing regions. Get an API key: https://www.alibabacloud.com/help/model-studio/get-api-key
# If the environment variable is not configured, replace the following line with: api_key = "sk-xxx"
api_key = os.getenv("DASHSCOPE_API_KEY")
file_path_obj = pathlib.Path(file_path)
if not file_path_obj.exists():
raise FileNotFoundError(f"Audio file not found: {file_path}")
base64_str = base64.b64encode(file_path_obj.read_bytes()).decode()
data_uri = f"data:{audio_mime_type};base64,{base64_str}"
# The following is the Singapore region URL. Replace {WorkspaceId} with your actual workspace ID. URLs vary by region.
url = "https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api/v1/services/audio/tts/customization"
payload = {
"model": "qwen-voice-enrollment",
"input": {
"action": "create",
"target_model": target_model,
"preferred_name": preferred_name,
"audio": {"data": data_uri}
}
}
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
resp = requests.post(url, json=payload, headers=headers)
if resp.status_code != 200:
raise RuntimeError(f"Failed to create voice: {resp.status_code}, {resp.text}")
try:
return resp.json()["output"]["voice"]
except (KeyError, ValueError) as e:
raise RuntimeError(f"Failed to parse voice response: {e}")
if __name__ == '__main__':
# The following is the Singapore region URL. Replace {WorkspaceId} with your actual workspace ID. URLs vary by region.
dashscope.base_http_api_url = 'https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api/v1'
# 1. Voice cloning: create a custom voice
voice = create_voice(VOICE_FILE_PATH)
print(f"Voice cloning complete. Voice: {voice}")
# 2. Non-realtime conversation with the cloned voice
messages = [{"role": "user", "content": [{"text": "Hello, please introduce yourself"}]}]
response = dashscope.MultiModalConversation.call(
# If the environment variable is not configured, replace with: api_key="sk-xxx"
api_key=os.getenv("DASHSCOPE_API_KEY"),
model=DEFAULT_TARGET_MODEL,
messages=messages,
modalities=["text", "audio"],
audio={"voice": voice, "format": "wav"}, # Use the cloned voice
stream=True
)
print("Model response:")
audio_base64_string = ""
for r in response:
try:
content = r.output.choices[0].message.content
for item in content:
if isinstance(item, dict):
if "audio" in item:
audio_base64_string += item["audio"].get("data", "")
elif "text" in item:
print(item["text"], end="")
except Exception:
pass
if audio_base64_string:
wav_bytes = base64.b64decode(audio_base64_string)
audio_np = np.frombuffer(wav_bytes, dtype=np.int16)
sf.write("audio_cloned.wav", audio_np, samplerate=24000)
print("\nAudio saved to: audio_cloned.wav")
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class Main {
// ===== Constants =====
// Voice cloning and non-realtime calls must use the same model
private static final String TARGET_MODEL = "qwen3.5-omni-plus";
private static final String PREFERRED_NAME = "guanyu";
// Path to the local audio file for voice cloning
private static final String AUDIO_FILE = "voice.mp3";
private static final String AUDIO_MIME_TYPE = "audio/mpeg";
// Write PCM data as a standard WAV file
public static void writeWav(String path, byte[] pcmData, int sampleRate) throws IOException {
int channels = 1, bitsPerSample = 16;
int byteRate = sampleRate * channels * bitsPerSample / 8;
int blockAlign = channels * bitsPerSample / 8;
ByteBuffer header = ByteBuffer.allocate(44).order(ByteOrder.LITTLE_ENDIAN);
header.put("RIFF".getBytes()); header.putInt(36 + pcmData.length);
header.put("WAVE".getBytes()); header.put("fmt ".getBytes());
header.putInt(16); header.putShort((short) 1); header.putShort((short) channels);
header.putInt(sampleRate); header.putInt(byteRate);
header.putShort((short) blockAlign); header.putShort((short) bitsPerSample);
header.put("data".getBytes()); header.putInt(pcmData.length);
try (FileOutputStream fos = new FileOutputStream(path)) {
fos.write(header.array());
fos.write(pcmData);
}
}
// Generate a data URI from a file
public static String toDataUrl(String filePath) throws IOException {
byte[] bytes = Files.readAllBytes(Paths.get(filePath));
String encoded = Base64.getEncoder().encodeToString(bytes);
return "data:" + AUDIO_MIME_TYPE + ";base64," + encoded;
}
// Call the API to create a voice
public static String createVoice() throws Exception {
// API keys differ between Singapore and Beijing regions. Get an API key: https://www.alibabacloud.com/help/model-studio/get-api-key
// If the environment variable is not configured, replace the following line with: String apiKey = "sk-xxx"
String apiKey = System.getenv("DASHSCOPE_API_KEY");
String jsonPayload =
"{"
+ "\"model\": \"qwen-voice-enrollment\","
+ "\"input\": {"
+ "\"action\": \"create\","
+ "\"target_model\": \"" + TARGET_MODEL + "\","
+ "\"preferred_name\": \"" + PREFERRED_NAME + "\","
+ "\"audio\": {"
+ "\"data\": \"" + toDataUrl(AUDIO_FILE) + "\""
+ "}"
+ "}"
+ "}";
// The following is the Singapore region URL. Replace {WorkspaceId} with your actual workspace ID. URLs vary by region.
String url = "https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api/v1/services/audio/tts/customization";
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Authorization", "Bearer " + apiKey);
con.setRequestProperty("Content-Type", "application/json");
con.setDoOutput(true);
try (OutputStream os = con.getOutputStream()) {
os.write(jsonPayload.getBytes(StandardCharsets.UTF_8));
}
int status = con.getResponseCode();
try (BufferedReader br = new BufferedReader(
new InputStreamReader(status >= 200 && status < 300 ? con.getInputStream() : con.getErrorStream(),
StandardCharsets.UTF_8))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
response.append(line);
}
if (status == 200) {
JsonObject jsonObj = new Gson().fromJson(response.toString(), JsonObject.class);
return jsonObj.getAsJsonObject("output").get("voice").getAsString();
}
throw new IOException("Failed to create voice: " + status + " - " + response);
}
}
public static void main(String[] args) {
try {
// API keys differ between Singapore and Beijing regions. Get an API key: https://www.alibabacloud.com/help/model-studio/get-api-key
// If the environment variable is not configured, replace the following line with: String apiKey = "sk-xxx"
String apiKey = System.getenv("DASHSCOPE_API_KEY");
// 1. Voice cloning: create a custom voice
String voice = createVoice();
System.out.println("Voice cloning complete. Voice: " + voice);
// 2. Non-realtime conversation with the cloned voice (OpenAI-compatible API)
String requestBody = "{"
+ "\"model\": \"" + TARGET_MODEL + "\","
+ "\"messages\": [{\"role\": \"user\", \"content\": \"Hello, please introduce yourself\"}],"
+ "\"modalities\": [\"text\", \"audio\"],"
+ "\"audio\": {\"voice\": \"" + voice + "\", \"format\": \"wav\"},"
+ "\"stream\": true,"
+ "\"stream_options\": {\"include_usage\": true}"
+ "}";
// The following is the Singapore region URL. Replace {WorkspaceId} with your actual workspace ID. URLs vary by region.
String url = "https://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1/chat/completions";
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Authorization", "Bearer " + apiKey);
con.setRequestProperty("Content-Type", "application/json");
con.setDoOutput(true);
try (OutputStream os = con.getOutputStream()) {
os.write(requestBody.getBytes(StandardCharsets.UTF_8));
}
// 3. Parse streaming SSE response
StringBuilder audioBase64 = new StringBuilder();
System.out.println("Model response:");
try (BufferedReader br = new BufferedReader(
new InputStreamReader(con.getInputStream(), StandardCharsets.UTF_8))) {
String line;
while ((line = br.readLine()) != null) {
if (!line.startsWith("data: ") || line.equals("data: [DONE]")) continue;
String json = line.substring(6);
JsonObject chunk = new Gson().fromJson(json, JsonObject.class);
if (!chunk.has("choices") || chunk.getAsJsonArray("choices").size() == 0) continue;
JsonObject delta = chunk.getAsJsonArray("choices").get(0)
.getAsJsonObject().getAsJsonObject("delta");
if (delta.has("content") && !delta.get("content").isJsonNull()) {
System.out.print(delta.get("content").getAsString());
}
if (delta.has("audio") && !delta.get("audio").isJsonNull()) {
JsonObject audio = delta.getAsJsonObject("audio");
if (audio.has("data")) {
audioBase64.append(audio.get("data").getAsString());
}
}
}
}
// 4. Save audio file (API returns raw PCM data, WAV header required)
if (audioBase64.length() > 0) {
byte[] pcmBytes = Base64.getDecoder().decode(audioBase64.toString());
writeWav("audio_cloned.wav", pcmBytes, 24000);
System.out.println("\nAudio saved to: audio_cloned.wav");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
音声のクォータと自動削除
総数の上限:1 アカウントあたり 1,000 件の音声です。
この API には、音声数を取得するエンドポイントはありません。音声の一覧取得 API を呼び出して音声数を数えてください。
自動削除:1 年間使用されなかった音声は自動的に削除されます。
課金
音声クローニングとモデル呼び出しは、個別に課金されます。
-
音声クローニング:音声の作成 は、1 件あたり $0.01 です。作成リクエストが失敗した場合は課金されません。
注記無料クォータ(中国サイトの北京リージョンおよび国際サイトのシンガポールリージョンのみ):
- Model Studio の有効化から 90 日以内は、1,000 件の音声を無料で作成できます。
- 作成に失敗した場合、無料クォータは消費されません。
- 音声を削除しても、無料クォータは回復しません。
- 無料クォータを使い切るか、90 日の有効期間が終了すると、音声の作成は 1 件あたり $0.01 で課金されます。
-
クローン音声を使用した会話は、モデルのトークン使用量に基づいて課金されます。モデル推論の料金 を参照してください。
著作権と法令遵守
提供する音声の権利保有と適法な使用については、お客様が責任を負います。サービス契約 をお読みください。
録音ガイド
録音機器
ノイズキャンセリングマイクを使用するか、静かな環境でスマートフォンを口元に近づけて録音してください。
録音環境
場所
- 10 平方メートル以下の、小さく閉じられた空間で録音してください。
- 吸音フォーム、カーペット、カーテンなど、音を吸収する素材がある部屋を選んでください。
- 残響の大きい広いホール、会議室、教室は避けてください。
ノイズの抑制
- 屋外の騒音:ドアと窓を閉めて、交通、工事、その他の外部の音を遮断してください。
- 室内の騒音:エアコン、扇風機、蛍光灯の安定器の電源を切ってください。
- スマートフォンで環境音を録音し、大きな音量で再生して、気づきにくい騒音源を確認してください。
残響の抑制
- 残響があると、音声がこもり、明瞭さが低下します。
- 滑らかな表面からの反射を減らしてください。カーテンを閉め、クローゼットの扉を開け、机や棚を衣服や毛布で覆います。
- 本棚や布張りの家具など、形が不規則な物を利用して音を拡散反射させてください。
録音原稿の準備
- 原稿は、対象のユースケースに合わせて作成してください。たとえば、カスタマーサービス向けなら、接客会話のスタイルを使用します。
- 政治、ポルノ、暴力に関する内容など、センシティブまたは違法な内容を原稿に含めないでください。これらが含まれていると、クローニングは失敗します。
- 「こんにちは」や「はい」などの短いフレーズは避けてください。完全な文章を使用してください。
- 意味のつながりを保ち、読み上げ時に頻繁に間を空けないでください。少なくとも 3 秒間、途切れずに発話することを推奨します。
- 親しみやすさや真剣さなど、目的の感情を表現できます。自然な口調を保ち、過度な演技は避けてください。
推奨手順
一般的な寝室を例にすると、次の手順になります。
- ドアと窓を閉めて、外部の騒音を遮断します。
- エアコン、扇風機、その他の電化製品の電源を切ります。
- カーテンを閉めて、ガラス面からの反射を減らします。
- 机の表面を衣服や毛布で覆い、机からの反射を減らします。
- 原稿を練習し、キャラクターの口調を決めて、自然に話します。
- 破裂音によるひずみや信号の低下を防ぐため、録音機器から約 10 cm の距離を保ってください。