SSML 與 LaTeX
通過 SSML(Speech Synthesis Markup Language)標記語言,可以精細控制語速、停頓、發音等語音特徵;通過 LaTeX 方程式朗讀功能,可以將數學公式轉換為自然語音。這兩項功能均適用於 CosyVoice 模型。
概述
SSML(Speech Synthesis Markup Language)是一種基於 XML 的語音合成標記語言。在文本中嵌入 SSML 標籤後,可以精細控制語速、語調、停頓和音量等語音特徵,也可以添加背景音樂和音效,實現更豐富的語音表達效果。
CosyVoice 還支援解析文本中嵌入的 LaTeX 方程式,並按照符合中文閱讀習慣的方式將其朗讀出來,適用於線上教育、有聲讀物等包含數學公式的情境。例如,輸入文本 “這是一道一元二次方程的求根公式:$x = \frac{-b \pm \sqrt{b^2-4ac}}{2a}$” 時,模型會將公式朗讀為 “x等於負b加減根號下b的平方減四ac,分之二a”。
典型應用情境包括:
-
有聲讀物:靈活控制停頓和語速,搭配背景音樂增強沉浸感
-
智能客服:通過
<say-as>標籤確保電話號碼、日期等資訊的準確朗讀 -
多語種播報:使用
<phoneme>標籤精確指定外文發音 -
線上教育:通過 LaTeX 方程式朗讀功能將數學公式轉為自然語音
兩項功能均適用於 CosyVoice 模型系列。如需瞭解各模型的選型建議,請參見語音合成。
SSML 標記語言
使用限制
-
模型:僅 cosyvoice-v3.5-flash、cosyvoice-v3.5-plus、cosyvoice-v3-flash、cosyvoice-v3-plus 和 cosyvoice-v2 模型支援 SSML。
-
音色:僅複刻音色以及CosyVoice音色列表中標註為支援 SSML 的系統音色可用。
-
介面:僅以下介面支援 SSML:
-
Java SDK(2.20.3 及以上版本):支援非流式調用和單向流式調用
-
Python SDK(1.23.4 及以上版本):支援非流式調用和單向流式調用
-
WebSocket API:需將參數
enable_ssml設定為true,且只允許發送一次 continue-task 事件
-
快速開始
以下樣本展示如何使用 SSML 控制語速進行語音合成。運行前,請完成以下準備工作:
cosyvoice-v3.5-plus 和 cosyvoice-v3.5-flash 模型目前僅在北京地區可用,專用於聲音複刻情境(不提供系統音色)。使用前,請先參見聲音複刻建立目標音色。
Java SDK
非流式調用
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;
/**
* SSML功能說明:
* 1. 只有非流式調用和單向流式調用支援SSML功能
* 2. 只有cosyvoice-v3-flash、cosyvoice-v3-plus和cosyvoice-v2模型的複刻音色以及音色列表中標記為支援SSML的系統音色支援SSML功能(例如cosyvoice-v3-flash模型的longanyang音色)
*/
public class Main {
private static String model = "cosyvoice-v3-flash";
private static String voice = "longanyang";
public static void main(String[] args) {
// 以下為新加坡地區URL,調用時請將WorkspaceId替換為真實的業務空間ID,各地區的URL不同。
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
streamAudioDataToSpeaker();
System.exit(0);
}
public static void streamAudioDataToSpeaker() {
SpeechSynthesisParam param =
SpeechSynthesisParam.builder()
// 新加坡地區和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
// 若沒有配置環境變數,請用百鍊API Key將下行替換為:.apiKey("sk-xxx")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model(model)
.voice(voice)
.build();
SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null);
ByteBuffer audio = null;
try {
// 非流式調用,阻塞直至音頻返回
// 特殊字元需要進行轉義
audio = synthesizer.call("<speak rate=\"2\">我的語速比正常人快。</speak>");
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
// 任務結束關閉websocket串連
synthesizer.getDuplexApi().close(1000, "bye");
}
if (audio != null) {
// 將音頻資料儲存到本地檔案“output.mp3”中
File file = new File("output.mp3");
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(audio.array());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// 首次發送文本時需建立 WebSocket 串連,因此首包延遲會包含串連建立的耗時
System.out.println(
"[Metric] requestId為:"
+ synthesizer.getLastRequestId()
+ "首包延遲(毫秒)為:"
+ synthesizer.getFirstPackageDelay());
}
}
單向流式調用
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.io.FileOutputStream;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
/**
* SSML功能說明:
* 1. 只有非流式調用和單向流式調用支援SSML功能
* 2. 只有cosyvoice-v3-flash、cosyvoice-v3-plus和cosyvoice-v2模型的複刻音色以及音色列表中標記為支援SSML的系統音色支援SSML功能(例如cosyvoice-v3-flash模型的longanyang音色)
*/
public class Main {
private static String model = "cosyvoice-v3-flash";
private static String voice = "longanyang";
public static void main(String[] args) {
// 以下為新加坡地區URL,調用時請將WorkspaceId替換為真實的業務空間ID,各地區的URL不同。
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
streamAudioDataToSpeaker();
System.out.println("音頻已儲存到 output.mp3 檔案中");
System.exit(0);
}
public static void streamAudioDataToSpeaker() {
CountDownLatch latch = new CountDownLatch(1);
final FileOutputStream[] fileOutputStream = new FileOutputStream[1];
try {
fileOutputStream[0] = new FileOutputStream("output.mp3");
} catch (IOException e) {
System.err.println("無法建立輸出檔案: " + e.getMessage());
return;
}
// 實現回調介面ResultCallback
ResultCallback<SpeechSynthesisResult> callback = new ResultCallback<SpeechSynthesisResult>() {
@Override
public void onEvent(SpeechSynthesisResult result) {
if (result.getAudioFrame() != null) {
// 將音頻資料寫入本地檔案
try {
byte[] audioData = result.getAudioFrame().array();
fileOutputStream[0].write(audioData);
fileOutputStream[0].flush();
} catch (IOException e) {
System.err.println("寫入音頻資料失敗: " + e.getMessage());
}
}
}
@Override
public void onComplete() {
System.out.println("收到Complete,語音合成結束");
closeFileOutputStream(fileOutputStream[0]);
latch.countDown();
}
@Override
public void onError(Exception e) {
System.out.println("出現異常:" + e.toString());
closeFileOutputStream(fileOutputStream[0]);
latch.countDown();
}
};
SpeechSynthesisParam param =
SpeechSynthesisParam.builder()
// 新加坡地區和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
// 若沒有配置環境變數,請用百鍊API Key將下行替換為:.apiKey("sk-xxx")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model(model)
.voice(voice)
.format(SpeechSynthesisAudioFormat.MP3_22050HZ_MONO_256KBPS)
.build();
SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, callback);
try {
// 單向流式調用,立即返回null(實際結果通過回調介面非同步傳遞),在回調介面的onEvent方法中即時擷取二進位音頻
// 特殊字元需要進行轉義
synthesizer.call("<speak rate=\"2\">我的語速比正常人快。</speak>");
// 等待合成完成
latch.await();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
// 任務結束後關閉websocket串連
try {
synthesizer.getDuplexApi().close(1000, "bye");
} catch (Exception e) {
System.err.println("關閉WebSocket串連失敗: " + e.getMessage());
}
// 確保檔案流被關閉
closeFileOutputStream(fileOutputStream[0]);
}
// 首次發送文本時需建立 WebSocket 串連,因此首包延遲會包含串連建立的耗時
System.out.println(
"[Metric] requestId為:"
+ synthesizer.getLastRequestId()
+ ",首包延遲(毫秒)為:"
+ synthesizer.getFirstPackageDelay());
}
private static void closeFileOutputStream(FileOutputStream fileOutputStream) {
try {
if (fileOutputStream != null) {
fileOutputStream.close();
}
} catch (IOException e) {
System.err.println("關閉檔案流失敗: " + e.getMessage());
}
}
}
Python SDK
非流式調用
# coding=utf-8
# SSML功能說明:
# 1. 只有非流式調用和單向流式調用支援SSML功能
# 2. 只有cosyvoice-v3-flash、cosyvoice-v3-plus和cosyvoice-v2模型的複刻音色以及音色列表中標記為支援SSML的系統音色支援SSML功能(例如cosyvoice-v3-flash模型的longanyang音色)
import dashscope
from dashscope.audio.tts_v2 import *
import os
# 新加坡地區和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
# 若沒有配置環境變數,請用百鍊API Key將下行替換為:dashscope.api_key = "sk-xxx"
dashscope.api_key = os.environ.get('DASHSCOPE_API_KEY')
# 以下為新加坡地區URL,調用時請將WorkspaceId替換為真實的業務空間ID,各地區的URL不同。
dashscope.base_websocket_api_url='wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference'
# 模型
model = "cosyvoice-v3-flash"
# 音色
voice = "longanyang"
# 執行個體化SpeechSynthesizer,並在構造方法中傳入模型(model)、音色(voice)等請求參數
synthesizer = SpeechSynthesizer(model=model, voice=voice)
# 非流式調用,阻塞直至音頻返回
# 特殊字元需要進行轉義
audio = synthesizer.call("<speak rate=\"2\">我的語速比正常人快。</speak>")
# 將音頻儲存至本地
with open('output.mp3', 'wb') as f:
f.write(audio)
# 首次發送文本時需建立 WebSocket 串連,因此首包延遲會包含串連建立的耗時
print('[Metric] requestId為:{},首包延遲為:{}毫秒'.format(
synthesizer.get_last_request_id(),
synthesizer.get_first_package_delay()))
單向流式調用
# coding=utf-8
# SSML功能說明:
# 1. 只有非流式調用和單向流式調用支援SSML功能
# 2. 只有cosyvoice-v3-flash、cosyvoice-v3-plus和cosyvoice-v2模型的複刻音色以及音色列表中標記為支援SSML的系統音色支援SSML功能(例如cosyvoice-v3-flash模型的longanyang音色)
import dashscope
from dashscope.audio.tts_v2 import *
import os
from datetime import datetime
def get_timestamp():
now = datetime.now()
formatted_timestamp = now.strftime("[%Y-%m-%d %H:%M:%S.%f]")
return formatted_timestamp
# 新加坡地區和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
# 若沒有配置環境變數,請用百鍊API Key將下行替換為:dashscope.api_key = "sk-xxx"
dashscope.api_key = os.environ.get('DASHSCOPE_API_KEY')
# 以下為新加坡地區URL,調用時請將WorkspaceId替換為真實的業務空間ID,各地區的URL不同。
dashscope.base_websocket_api_url='wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference'
# 模型
model = "cosyvoice-v3-flash"
# 音色
voice = "longanyang"
# 定義回調介面
class Callback(ResultCallback):
_player = None
_stream = None
def on_open(self):
# 開啟輸出檔案,準備寫入音頻資料
self.file = open("output.mp3", "wb")
print("串連建立:" + get_timestamp())
def on_complete(self):
print("語音合成完成,所有合成結果已被接收:" + get_timestamp())
if hasattr(self, 'file') and self.file:
self.file.close()
self
# 首次發送文本時需建立 WebSocket 串連,因此首包延遲會包含串連建立的耗時
print('[Metric] requestId為:{},首包延遲為:{}毫秒'.format(
self.synthesizer.get_last_request_id(),
self.synthesizer.get_first_package_delay()))
def on_error(self, message: str):
print(f"語音合成出現異常:{message}")
if hasattr(self, 'file') and self.file:
self.file.close()
def on_close(self):
print("串連關閉:" + get_timestamp())
if hasattr(self, 'file') and self.file:
self.file.close()
def on_event(self, message):
pass
def on_data(self, data: bytes) -> None:
print(get_timestamp() + " 二進位音頻長度為:" + str(len(data)))
# 將音頻資料寫入檔案
self.file.write(data)
callback = Callback()
# 執行個體化SpeechSynthesizer,並在構造方法中傳入模型(model)、音色(voice)等請求參數
synthesizer = SpeechSynthesizer(
model=model,
voice=voice,
callback=callback,
)
# 將synthesizer執行個體賦值給callback,以便在on_complete中使用
callback.synthesizer = synthesizer
# 單向流式調用,發送待合成文本,在回調介面的on_data方法中即時擷取二進位音頻
# 特殊字元需要進行轉義
synthesizer.call("<speak rate=\"2\">我的語速比正常人快。</speak>")
WebSocket API
Go
// SSML功能說明:
// 1. 在發送run-task指令時,將參數enable_ssml設定為true,以開啟SSML支援
// 2. 通過continue-task指令發送包含SSML的文本,且只允許發送一次continue-task指令
// 3. 只有cosyvoice-v3-flash、cosyvoice-v3-plus和cosyvoice-v2模型的複刻音色以及音色列表中標記為支援SSML的系統音色支援SSML功能(例如cosyvoice-v3-flash模型的longanyang音色)
package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
"strings"
"time"
"github.com/google/uuid"
"github.com/gorilla/websocket"
)
const (
// 以下為新加坡地區URL,調用時請將WorkspaceId替換為真實的業務空間ID,各地區的URL不同。
wsURL = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference/"
outputFile = "output.mp3"
)
func main() {
// 新加坡和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
// 若沒有配置環境變數,請用百鍊API Key將下行替換為:apiKey := "sk-xxx"
apiKey := os.Getenv("DASHSCOPE_API_KEY")
// 清空輸出檔案
os.Remove(outputFile)
os.Create(outputFile)
// 串連WebSocket
header := make(http.Header)
header.Add("X-DashScope-DataInspection", "enable")
header.Add("Authorization", fmt.Sprintf("bearer %s", apiKey))
conn, resp, err := websocket.DefaultDialer.Dial(wsURL, header)
if err != nil {
if resp != nil {
fmt.Printf("串連失敗 HTTP狀態代碼: %d\n", resp.StatusCode)
}
fmt.Println("串連失敗:", err)
return
}
defer conn.Close()
// 產生任務ID
taskID := uuid.New().String()
fmt.Printf("產生任務ID: %s\n", taskID)
// 發送run-task指令
runTaskCmd := map[string]interface{}{
"header": map[string]interface{}{
"action": "run-task",
"task_id": taskID,
"streaming": "duplex",
},
"payload": map[string]interface{}{
"task_group": "audio",
"task": "tts",
"function": "SpeechSynthesizer",
"model": "cosyvoice-v3-flash",
"parameters": map[string]interface{}{
"text_type": "PlainText",
"voice": "longanyang",
"format": "mp3",
"sample_rate": 22050,
"volume": 50,
"rate": 1,
"pitch": 1,
// 如果enable_ssml設為true,只允許發送一次continue-task指令,否則會報錯“Text request limit violated, expected 1.”
"enable_ssml": true,
},
"input": map[string]interface{}{},
},
}
runTaskJSON, _ := json.Marshal(runTaskCmd)
fmt.Printf("發送run-task指令: %s\n", string(runTaskJSON))
err = conn.WriteMessage(websocket.TextMessage, runTaskJSON)
if err != nil {
fmt.Println("發送run-task失敗:", err)
return
}
textSent := false
// 處理訊息
for {
messageType, message, err := conn.ReadMessage()
if err != nil {
fmt.Println("讀取訊息失敗:", err)
break
}
// 處理二進位訊息
if messageType == websocket.BinaryMessage {
fmt.Printf("收到二進位訊息,長度: %d\n", len(message))
file, _ := os.OpenFile(outputFile, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
file.Write(message)
file.Close()
continue
}
// 處理簡訊
messageStr := string(message)
fmt.Printf("收到簡訊: %s\n", strings.ReplaceAll(messageStr, "\n", ""))
// 簡單解析JSON擷取event類型
var msgMap map[string]interface{}
if json.Unmarshal(message, &msgMap) == nil {
if header, ok := msgMap["header"].(map[string]interface{}); ok {
if event, ok := header["event"].(string); ok {
fmt.Printf("事件類型: %s\n", event)
switch event {
case "task-started":
fmt.Println("=== 收到task-started事件 ===")
if !textSent {
// 發送 continue-task 指令,使用SSML功能時,該指令只允許發送一次
continueTaskCmd := map[string]interface{}{
"header": map[string]interface{}{
"action": "continue-task",
"task_id": taskID,
"streaming": "duplex",
},
"payload": map[string]interface{}{
"input": map[string]interface{}{
// 特殊字元需要進行轉義
"text": "<speak rate=\"2\">我的語速比正常人快。</speak>",
},
},
}
continueTaskJSON, _ := json.Marshal(continueTaskCmd)
fmt.Printf("發送continue-task指令: %s\n", string(continueTaskJSON))
err = conn.WriteMessage(websocket.TextMessage, continueTaskJSON)
if err != nil {
fmt.Println("發送continue-task失敗:", err)
return
}
textSent = true
// 延遲發送finish-task
time.Sleep(500 * time.Millisecond)
// 發送finish-task指令
finishTaskCmd := map[string]interface{}{
"header": map[string]interface{}{
"action": "finish-task",
"task_id": taskID,
"streaming": "duplex",
},
"payload": map[string]interface{}{
"input": map[string]interface{}{},
},
}
finishTaskJSON, _ := json.Marshal(finishTaskCmd)
fmt.Printf("發送finish-task指令: %s\n", string(finishTaskJSON))
err = conn.WriteMessage(websocket.TextMessage, finishTaskJSON)
if err != nil {
fmt.Println("發送finish-task失敗:", err)
return
}
}
case "task-finished":
fmt.Println("=== 任務完成 ===")
return
case "task-failed":
fmt.Println("=== 任務失敗 ===")
if header["error_message"] != nil {
fmt.Printf("錯誤資訊: %s\n", header["error_message"])
}
return
case "result-generated":
fmt.Println("收到result-generated事件")
}
}
}
}
}
}
C#
using System.Net.WebSockets;
using System.Text;
using System.Text.Json;
// SSML功能說明:
// 1. 在發送run-task指令時,將參數enable_ssml設定為true,以開啟SSML支援
// 2. 通過continue-task指令發送包含SSML的文本,且只允許發送一次continue-task指令
// 3. 只有cosyvoice-v3-flash、cosyvoice-v3-plus和cosyvoice-v2模型的複刻音色以及音色列表中標記為支援SSML的系統音色支援SSML功能(例如cosyvoice-v3-flash模型的longanyang音色)
class Program {
// 新加坡和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
// 若沒有配置環境變數,請用百鍊API Key將下行替換為:private static readonly string ApiKey = "sk-xxx"
private static readonly string ApiKey = Environment.GetEnvironmentVariable("DASHSCOPE_API_KEY") ?? throw new InvalidOperationException("DASHSCOPE_API_KEY environment variable is not set.");
// 以下為新加坡地區URL,調用時請將WorkspaceId替換為真實的業務空間ID,各地區的URL不同。
private const string WebSocketUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference/";
// 輸出檔案路徑
private const string OutputFilePath = "output.mp3";
// WebSocket用戶端
private static ClientWebSocket _webSocket = new ClientWebSocket();
// 取消令牌源
private static CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
// 任務ID
private static string? _taskId;
// 任務是否已啟動
private static TaskCompletionSource<bool> _taskStartedTcs = new TaskCompletionSource<bool>();
static async Task Main(string[] args) {
try {
// 清空輸出檔案
ClearOutputFile(OutputFilePath);
// 串連WebSocket服務
await ConnectToWebSocketAsync(WebSocketUrl);
// 啟動接收訊息的任務
Task receiveTask = ReceiveMessagesAsync();
// 發送run-task指令
_taskId = GenerateTaskId();
await SendRunTaskCommandAsync(_taskId);
// 等待task-started事件
await _taskStartedTcs.Task;
// 發送 continue-task 指令,使用SSML功能時,該指令只允許發送一次
// 特殊字元需要進行轉義
await SendContinueTaskCommandAsync("<speak rate=\"2\">我的語速比正常人快。</speak>");
// 發送finish-task指令
await SendFinishTaskCommandAsync(_taskId);
// 等待接收任務完成
await receiveTask;
Console.WriteLine("任務完成,串連已關閉。");
} catch (OperationCanceledException) {
Console.WriteLine("任務被取消。");
} catch (Exception ex) {
Console.WriteLine($"發生錯誤:{ex.Message}");
} finally {
_cancellationTokenSource.Cancel();
_webSocket.Dispose();
}
}
private static void ClearOutputFile(string filePath) {
if (File.Exists(filePath)) {
File.WriteAllText(filePath, string.Empty);
Console.WriteLine("輸出檔案已清空。");
} else {
Console.WriteLine("輸出檔案不存在,無需清空。");
}
}
private static async Task ConnectToWebSocketAsync(string url) {
var uri = new Uri(url);
if (_webSocket.State == WebSocketState.Connecting || _webSocket.State == WebSocketState.Open) {
return;
}
// 設定WebSocket串連的頭部資訊
_webSocket.Options.SetRequestHeader("Authorization", $"bearer {ApiKey}");
_webSocket.Options.SetRequestHeader("X-DashScope-DataInspection", "enable");
try {
await _webSocket.ConnectAsync(uri, _cancellationTokenSource.Token);
Console.WriteLine("已成功串連到WebSocket服務。");
} catch (OperationCanceledException) {
Console.WriteLine("WebSocket串連被取消。");
} catch (Exception ex) {
Console.WriteLine($"WebSocket串連失敗: {ex.Message}");
throw;
}
}
private static async Task SendRunTaskCommandAsync(string taskId) {
var command = CreateCommand("run-task", taskId, "duplex", new {
task_group = "audio",
task = "tts",
function = "SpeechSynthesizer",
model = "cosyvoice-v3-flash",
parameters = new
{
text_type = "PlainText",
voice = "longanyang",
format = "mp3",
sample_rate = 22050,
volume = 50,
rate = 1,
pitch = 1,
// 如果enable_ssml設為true,只允許發送一次continue-task指令,否則會報錯“Text request limit violated, expected 1.”
enable_ssml = true
},
input = new { }
});
await SendJsonMessageAsync(command);
Console.WriteLine("已發送run-task指令。");
}
private static async Task SendContinueTaskCommandAsync(string text) {
if (_taskId == null) {
throw new InvalidOperationException("任務ID未初始化。");
}
var command = CreateCommand("continue-task", _taskId, "duplex", new {
input = new {
text
}
});
await SendJsonMessageAsync(command);
Console.WriteLine("已發送continue-task指令。");
}
private static async Task SendFinishTaskCommandAsync(string taskId) {
var command = CreateCommand("finish-task", taskId, "duplex", new {
input = new { }
});
await SendJsonMessageAsync(command);
Console.WriteLine("已發送finish-task指令。");
}
private static async Task SendJsonMessageAsync(string message) {
var buffer = Encoding.UTF8.GetBytes(message);
try {
await _webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, _cancellationTokenSource.Token);
} catch (OperationCanceledException) {
Console.WriteLine("訊息發送被取消。");
}
}
private static async Task ReceiveMessagesAsync() {
while (_webSocket.State == WebSocketState.Open) {
var response = await ReceiveMessageAsync();
if (response != null) {
var eventStr = response.RootElement.GetProperty("header").GetProperty("event").GetString();
switch (eventStr) {
case "task-started":
Console.WriteLine("任務已啟動。");
_taskStartedTcs.TrySetResult(true);
break;
case "task-finished":
Console.WriteLine("任務已完成。");
_cancellationTokenSource.Cancel();
break;
case "task-failed":
Console.WriteLine("任務失敗:" + response.RootElement.GetProperty("header").GetProperty("error_message").GetString());
_cancellationTokenSource.Cancel();
break;
default:
// result-generated可在此處理
break;
}
}
}
}
private static async Task<JsonDocument?> ReceiveMessageAsync() {
var buffer = new byte[1024 * 4];
var segment = new ArraySegment<byte>(buffer);
try {
WebSocketReceiveResult result = await _webSocket.ReceiveAsync(segment, _cancellationTokenSource.Token);
if (result.MessageType == WebSocketMessageType.Close) {
await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", _cancellationTokenSource.Token);
return null;
}
if (result.MessageType == WebSocketMessageType.Binary) {
// 處理位元據
Console.WriteLine("接收到位元據...");
// 將位元據儲存到檔案
using (var fileStream = new FileStream(OutputFilePath, FileMode.Append)) {
fileStream.Write(buffer, 0, result.Count);
}
return null;
}
string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
return JsonDocument.Parse(message);
} catch (OperationCanceledException) {
Console.WriteLine("訊息接收被取消。");
return null;
}
}
private static string GenerateTaskId() {
return Guid.NewGuid().ToString("N").Substring(0, 32);
}
private static string CreateCommand(string action, string taskId, string streaming, object payload) {
var command = new {
header = new {
action,
task_id = taskId,
streaming
},
payload
};
return JsonSerializer.Serialize(command);
}
}
PHP
範例程式碼目錄結構為:
my-php-project/
├── composer.json
├── vendor/
└── index.php
composer.json內容如下,相關依賴的版本號碼請根據實際情況自行決定:
{
"require": {
"react/event-loop": "^1.3",
"react/socket": "^1.11",
"react/stream": "^1.2",
"react/http": "^1.1",
"ratchet/pawl": "^0.4"
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}
index.php內容如下:
<!-- SSML功能說明: -->
<!-- 1. 在發送run-task指令時,將參數enable_ssml設定為true,以開啟SSML支援 -->
<!-- 2. 通過continue-task指令發送包含SSML的文本,且只允許發送一次continue-task指令 -->
<!-- 3. 只有cosyvoice-v3-flash、cosyvoice-v3-plus和cosyvoice-v2模型的複刻音色以及音色列表中標記為支援SSML的系統音色支援SSML功能(例如cosyvoice-v3-flash模型的longanyang音色) -->
<?php
require __DIR__ . '/vendor/autoload.php';
use Ratchet\Client\Connector;
use React\EventLoop\Loop;
use React\Socket\Connector as SocketConnector;
// 新加坡和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
// 若沒有配置環境變數,請用百鍊API Key將下行替換為:$api_key = "sk-xxx"
$api_key = getenv("DASHSCOPE_API_KEY");
// 以下為新加坡地區URL,調用時請將WorkspaceId替換為真實的業務空間ID,各地區的URL不同。
$websocket_url = 'wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference/'; // WebSocket伺服器位址
$output_file = 'output.mp3'; // 輸出檔案路徑
$loop = Loop::get();
if (file_exists($output_file)) {
// 清空檔案內容
file_put_contents($output_file, '');
}
// 建立自訂的連接器
$socketConnector = new SocketConnector($loop, [
'tcp' => [
'bindto' => '0.0.0.0:0',
],
'tls' => [
'verify_peer' => false,
'verify_peer_name' => false,
],
]);
$connector = new Connector($loop, $socketConnector);
$headers = [
'Authorization' => 'bearer ' . $api_key,
'X-DashScope-DataInspection' => 'enable'
];
$connector($websocket_url, [], $headers)->then(function ($conn) use ($loop, $output_file) {
echo "串連到WebSocket伺服器\n";
// 產生任務ID
$taskId = generateTaskId();
// 發送 run-task 指令
sendRunTaskMessage($conn, $taskId);
// 定義發送 continue-task 指令的函數
$sendContinueTask = function() use ($conn, $loop, $taskId) {
// 發送 continue-task 指令,使用SSML功能時,該指令只允許發送一次
$continueTaskMessage = json_encode([
"header" => [
"action" => "continue-task",
"task_id" => $taskId,
"streaming" => "duplex"
],
"payload" => [
"input" => [
// 特殊字元需要進行轉義
"text" => "<speak rate=\"2\">我的語速比正常人快。</speak>"
]
]
]);
$conn->send($continueTaskMessage);
// 發送 finish-task 指令
sendFinishTaskMessage($conn, $taskId);
};
// 標記是否收到 task-started 事件
$taskStarted = false;
// 監聽訊息
$conn->on('message', function($msg) use ($conn, $sendContinueTask, $loop, &$taskStarted, $taskId, $output_file) {
if ($msg->isBinary()) {
// 寫入位元據到本地檔案
file_put_contents($output_file, $msg->getPayload(), FILE_APPEND);
} else {
// 處理非二進位訊息
$response = json_decode($msg, true);
if (isset($response['header']['event'])) {
handleEvent($conn, $response, $sendContinueTask, $loop, $taskId, $taskStarted);
} else {
echo "未知的訊息格式\n";
}
}
});
// 監聽串連關閉
$conn->on('close', function($code = null, $reason = null) {
echo "串連已關閉\n";
if ($code !== null) {
echo "關閉代碼: " . $code . "\n";
}
if ($reason !== null) {
echo "關閉原因:" . $reason . "\n";
}
});
}, function ($e) {
echo "無法串連:{$e->getMessage()}\n";
});
$loop->run();
/**
* 產生任務ID
* @return string
*/
function generateTaskId(): string {
return bin2hex(random_bytes(16));
}
/**
* 發送 run-task 指令
* @param $conn
* @param $taskId
*/
function sendRunTaskMessage($conn, $taskId) {
$runTaskMessage = json_encode([
"header" => [
"action" => "run-task",
"task_id" => $taskId,
"streaming" => "duplex"
],
"payload" => [
"task_group" => "audio",
"task" => "tts",
"function" => "SpeechSynthesizer",
"model" => "cosyvoice-v3-flash",
"parameters" => [
"text_type" => "PlainText",
"voice" => "longanyang",
"format" => "mp3",
"sample_rate" => 22050,
"volume" => 50,
"rate" => 1,
"pitch" => 1,
// 如果enable_ssml設為true,只允許發送一次continue-task指令,否則會報錯“Text request limit violated, expected 1.”
"enable_ssml" => true
],
"input" => (object) []
]
]);
echo "準備發送run-task指令: " . $runTaskMessage . "\n";
$conn->send($runTaskMessage);
echo "run-task指令已發送\n";
}
/**
* 讀取音頻檔案
* @param string $filePath
* @return bool|string
*/
function readAudioFile(string $filePath) {
$voiceData = file_get_contents($filePath);
if ($voiceData === false) {
echo "無法讀取音頻檔案\n";
}
return $voiceData;
}
/**
* 分割音頻資料
* @param string $data
* @param int $chunkSize
* @return array
*/
function splitAudioData(string $data, int $chunkSize): array {
return str_split($data, $chunkSize);
}
/**
* 發送 finish-task 指令
* @param $conn
* @param $taskId
*/
function sendFinishTaskMessage($conn, $taskId) {
$finishTaskMessage = json_encode([
"header" => [
"action" => "finish-task",
"task_id" => $taskId,
"streaming" => "duplex"
],
"payload" => [
"input" => (object) []
]
]);
echo "準備發送finish-task指令: " . $finishTaskMessage . "\n";
$conn->send($finishTaskMessage);
echo "finish-task指令已發送\n";
}
/**
* 處理事件
* @param $conn
* @param $response
* @param $sendContinueTask
* @param $loop
* @param $taskId
* @param $taskStarted
*/
function handleEvent($conn, $response, $sendContinueTask, $loop, $taskId, &$taskStarted) {
switch ($response['header']['event']) {
case 'task-started':
echo "任務開始,發送continue-task指令...\n";
$taskStarted = true;
// 發送 continue-task 指令
$sendContinueTask();
break;
case 'result-generated':
// 忽略result-generated事件
break;
case 'task-finished':
echo "任務完成\n";
$conn->close();
break;
case 'task-failed':
echo "任務失敗\n";
echo "錯誤碼:" . $response['header']['error_code'] . "\n";
echo "錯誤資訊:" . $response['header']['error_message'] . "\n";
$conn->close();
break;
case 'error':
echo "錯誤:" . $response['payload']['message'] . "\n";
break;
default:
echo "未知事件:" . $response['header']['event'] . "\n";
break;
}
// 如果任務已完成,關閉串連
if ($response['header']['event'] == 'task-finished') {
// 等待1秒以確保所有資料都已傳輸完畢
$loop->addTimer(1, function() use ($conn) {
$conn->close();
echo "用戶端關閉串連\n";
});
}
// 如果沒有收到 task-started 事件,關閉串連
if (!$taskStarted && in_array($response['header']['event'], ['task-failed', 'error'])) {
$conn->close();
}
}
Node.js
需安裝相關依賴:
npm install ws
npm install uuid
範例程式碼如下:
// SSML功能說明:
// 1. 在發送run-task指令時,將參數enable_ssml設定為true,以開啟SSML支援
// 2. 通過continue-task指令發送包含SSML的文本,且只允許發送一次continue-task指令
// 3. 只有cosyvoice-v3-flash、cosyvoice-v3-plus和cosyvoice-v2模型的複刻音色以及音色列表中標記為支援SSML的系統音色支援SSML功能(例如cosyvoice-v3-flash模型的longanyang音色)
import fs from 'fs';
import WebSocket from 'ws';
import { v4 as uuid } from 'uuid'; // 用於產生UUID
// 新加坡和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
// 若沒有配置環境變數,請用百鍊API Key將下行替換為:const apiKey = "sk-xxx"
const apiKey = process.env.DASHSCOPE_API_KEY;
// 以下為新加坡地區URL,調用時請將WorkspaceId替換為真實的業務空間ID,各地區的URL不同。
const url = 'wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference/';
// 輸出檔案路徑
const outputFilePath = 'output.mp3';
// 清空輸出檔案
fs.writeFileSync(outputFilePath, '');
// 建立WebSocket用戶端
const ws = new WebSocket(url, {
headers: {
Authorization: `bearer ${apiKey}`,
'X-DashScope-DataInspection': 'enable'
}
});
let taskStarted = false;
let taskId = uuid();
ws.on('open', () => {
console.log('已串連到WebSocket伺服器');
// 發送run-task指令
const runTaskMessage = JSON.stringify({
header: {
action: 'run-task',
task_id: taskId,
streaming: 'duplex'
},
payload: {
task_group: 'audio',
task: 'tts',
function: 'SpeechSynthesizer',
model: 'cosyvoice-v3-flash',
parameters: {
text_type: 'PlainText',
voice: 'longanyang', // 音色
format: 'mp3', // 音頻格式
sample_rate: 22050, // 採樣率
volume: 50, // 音量
rate: 1, // 語速
pitch: 1, // 音調
enable_ssml: true // 是否開啟SSML功能。如果enable_ssml設為true,只允許發送一次continue-task指令,否則會報錯“Text request limit violated, expected 1.”
},
input: {}
}
});
ws.send(runTaskMessage);
console.log('已發送run-task訊息');
});
const fileStream = fs.createWriteStream(outputFilePath, { flags: 'a' });
ws.on('message', (data, isBinary) => {
if (isBinary) {
// 寫入位元據到檔案
fileStream.write(data);
} else {
const message = JSON.parse(data);
switch (message.header.event) {
case 'task-started':
taskStarted = true;
console.log('任務已開始');
// 發送continue-task指令
sendContinueTasks(ws);
break;
case 'task-finished':
console.log('任務已完成');
ws.close();
fileStream.end(() => {
console.log('檔案流已關閉');
});
break;
case 'task-failed':
console.error('任務失敗:', message.header.error_message);
ws.close();
fileStream.end(() => {
console.log('檔案流已關閉');
});
break;
default:
// 可以在這裡處理result-generated
break;
}
}
});
function sendContinueTasks(ws) {
if (taskStarted) {
// 發送 continue-task 指令,使用SSML功能時,該指令只允許發送一次
const continueTaskMessage = JSON.stringify({
header: {
action: 'continue-task',
task_id: taskId,
streaming: 'duplex'
},
payload: {
input: {
// 特殊字元需要進行轉義
text: '<speak rate="2">我的語速比正常人快。</speak>'
}
}
});
ws.send(continueTaskMessage);
// 發送finish-task指令
const finishTaskMessage = JSON.stringify({
header: {
action: 'finish-task',
task_id: taskId,
streaming: 'duplex'
},
payload: {
input: {}
}
});
ws.send(finishTaskMessage);
}
}
ws.on('close', () => {
console.log('已斷開與WebSocket伺服器的串連');
});
Java
如您使用Java程式設計語言,建議採用Java DashScope SDK進行開發,詳情請參見Java SDK。
以下是Java WebSocket的調用樣本。在運行樣本前,請確保已匯入以下依賴:
-
Java-WebSocket -
jackson-databind
推薦您使用Maven或Gradle管理依賴包,其配置如下:
pom.xml
<dependencies>
<!-- WebSocket Client -->
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.5.3</version>
</dependency>
<!-- JSON Processing -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
</dependency>
</dependencies>
build.gradle
// 省略其它代碼
dependencies {
// WebSocket Client
implementation 'org.java-websocket:Java-WebSocket:1.5.3'
// JSON Processing
implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.0'
}
// 省略其它代碼
Java代碼如下:
import com.fasterxml.jackson.databind.ObjectMapper;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.*;
/**
* SSML功能說明:
* 1. 在發送run-task指令時,將參數enable_ssml設定為true,以開啟SSML支援
* 2. 通過continue-task指令發送包含SSML的文本,且只允許發送一次continue-task指令
* 3. 只有cosyvoice-v3-flash、cosyvoice-v3-plus和cosyvoice-v2模型的複刻音色以及音色列表中標記為支援SSML的系統音色支援SSML功能(例如cosyvoice-v3-flash模型的longanyang音色)
*/
public class TTSWebSocketClient extends WebSocketClient {
private final String taskId = UUID.randomUUID().toString();
private final String outputFile = "output_" + System.currentTimeMillis() + ".mp3";
private boolean taskFinished = false;
public TTSWebSocketClient(URI serverUri, Map<String, String> headers) {
super(serverUri, headers);
}
@Override
public void onOpen(ServerHandshake serverHandshake) {
System.out.println("串連成功");
// 發送run-task指令
// 如果enable_ssml設為true,只允許發送一次continue-task指令,否則會報錯“Text request limit violated, expected 1.”
String runTaskCommand = "{ \"header\": { \"action\": \"run-task\", \"task_id\": \"" + taskId + "\", \"streaming\": \"duplex\" }, \"payload\": { \"task_group\": \"audio\", \"task\": \"tts\", \"function\": \"SpeechSynthesizer\", \"model\": \"cosyvoice-v3-flash\", \"parameters\": { \"text_type\": \"PlainText\", \"voice\": \"longanyang\", \"format\": \"mp3\", \"sample_rate\": 22050, \"volume\": 50, \"rate\": 1, \"pitch\": 1, \"enable_ssml\": true }, \"input\": {} }}";
send(runTaskCommand);
}
@Override
public void onMessage(String message) {
System.out.println("收到服務端返回的訊息:" + message);
try {
// Parse JSON message
Map<String, Object> messageMap = new ObjectMapper().readValue(message, Map.class);
if (messageMap.containsKey("header")) {
Map<String, Object> header = (Map<String, Object>) messageMap.get("header");
if (header.containsKey("event")) {
String event = (String) header.get("event");
if ("task-started".equals(event)) {
System.out.println("收到服務端返回的task-started事件");
// 發送 continue-task 指令,使用SSML功能時,該指令只允許發送一次
// 特殊字元需要進行轉義
sendContinueTask("<speak rate=\\\"2\\\">我的語速比正常人快。</speak>");
// 發送finish-task指令
sendFinishTask();
} else if ("task-finished".equals(event)) {
System.out.println("收到服務端返回的task-finished事件");
taskFinished = true;
closeConnection();
} else if ("task-failed".equals(event)) {
System.out.println("任務失敗:" + message);
closeConnection();
}
}
}
} catch (Exception e) {
System.err.println("出現異常:" + e.getMessage());
}
}
@Override
public void onMessage(ByteBuffer message) {
System.out.println("收到的二進位音頻資料大小為:" + message.remaining());
try (FileOutputStream fos = new FileOutputStream(outputFile, true)) {
byte[] buffer = new byte[message.remaining()];
message.get(buffer);
fos.write(buffer);
System.out.println("音頻資料已寫入本地檔案" + outputFile + "中");
} catch (IOException e) {
System.err.println("音頻資料寫入本地檔案失敗:" + e.getMessage());
}
}
@Override
public void onClose(int code, String reason, boolean remote) {
System.out.println("串連關閉:" + reason + " (" + code + ")");
}
@Override
public void onError(Exception ex) {
System.err.println("報錯:" + ex.getMessage());
ex.printStackTrace();
}
private void sendContinueTask(String text) {
String command = "{ \"header\": { \"action\": \"continue-task\", \"task_id\": \"" + taskId + "\", \"streaming\": \"duplex\" }, \"payload\": { \"input\": { \"text\": \"" + text + "\" } }}";
send(command);
}
private void sendFinishTask() {
String command = "{ \"header\": { \"action\": \"finish-task\", \"task_id\": \"" + taskId + "\", \"streaming\": \"duplex\" }, \"payload\": { \"input\": {} }}";
send(command);
}
private void closeConnection() {
if (!isClosed()) {
close();
}
}
public static void main(String[] args) {
try {
// 新加坡和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
// 若沒有配置環境變數,請用百鍊API Key將下行替換為:String apiKey = "sk-xxx"
String apiKey = System.getenv("DASHSCOPE_API_KEY");
if (apiKey == null || apiKey.isEmpty()) {
System.err.println("請設定 DASHSCOPE_API_KEY 環境變數");
return;
}
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", "bearer " + apiKey);
// 以下為新加坡地區URL,調用時請將WorkspaceId替換為真實的業務空間ID,各地區的URL不同。
TTSWebSocketClient client = new TTSWebSocketClient(new URI("wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference/"), headers);
client.connect();
while (!client.isClosed() && !client.taskFinished) {
Thread.sleep(1000);
}
} catch (Exception e) {
System.err.println("串連WebSocket服務失敗:" + e.getMessage());
e.printStackTrace();
}
}
}
Python
如您使用Python程式設計語言,建議採用Python DashScope SDK進行開發,詳情請參見Python SDK。
以下是Python WebSocket的調用樣本。在運行樣本前,請確保通過如下方式匯入依賴:
pip uninstall websocket-client
pip uninstall websocket
pip install websocket-client
請不要將運行範例程式碼的Python檔案命名為“websocket.py”,否則會報錯(AttributeError: module 'websocket' has no attribute 'WebSocketApp'. Did you mean: 'WebSocket'?)。
# SSML功能說明:
# 1. 在發送run-task指令時,將參數enable_ssml設定為true,以開啟SSML支援
# 2. 通過continue-task指令發送包含SSML的文本,且只允許發送一次continue-task指令
# 3. 只有cosyvoice-v3-flash、cosyvoice-v3-plus和cosyvoice-v2模型的複刻音色以及音色列表中標記為支援SSML的系統音色支援SSML功能(例如cosyvoice-v3-flash模型的longanyang音色)
import websocket
import json
import uuid
import os
import time
class TTSClient:
def __init__(self, api_key, uri):
"""
初始化 TTSClient 執行個體
參數:
api_key (str): 鑒權用的 API Key
uri (str): WebSocket 服務地址
"""
self.api_key = api_key # 替換為你的 API Key
self.uri = uri # 替換為你的 WebSocket 地址
self.task_id = str(uuid.uuid4()) # 產生唯一任務 ID
self.output_file = f"output_{int(time.time())}.mp3" # 輸出音頻檔案路徑
self.ws = None # WebSocketApp 執行個體
self.task_started = False # 是否收到 task-started
self.task_finished = False # 是否收到 task-finished / task-failed
def on_open(self, ws):
"""
WebSocket 串連建立時回呼函數
發送 run-task 指令開啟語音合成任務
"""
print("WebSocket 已串連")
# 構造 run-task 指令
run_task_cmd = {
"header": {
"action": "run-task",
"task_id": self.task_id,
"streaming": "duplex"
},
"payload": {
"task_group": "audio",
"task": "tts",
"function": "SpeechSynthesizer",
"model": "cosyvoice-v3-flash",
"parameters": {
"text_type": "PlainText",
"voice": "longanyang",
"format": "mp3",
"sample_rate": 22050,
"volume": 50,
"rate": 1,
"pitch": 1,
# 如果enable_ssml設為True,只允許發送一次continue-task指令,否則會報錯“Text request limit violated, expected 1.”
"enable_ssml": True
},
"input": {}
}
}
# 發送 run-task 指令
ws.send(json.dumps(run_task_cmd))
print("已發送 run-task 指令")
def on_message(self, ws, message):
"""
接收到訊息時的回呼函數
區分文本和二進位訊息處理
"""
if isinstance(message, str):
# 處理 JSON 簡訊
try:
msg_json = json.loads(message)
print(f"收到 JSON 訊息: {msg_json}")
if "header" in msg_json:
header = msg_json["header"]
if "event" in header:
event = header["event"]
if event == "task-started":
print("任務已啟動")
self.task_started = True
# 發送 continue-task 指令,使用SSML功能時,該指令只允許發送一次
# 特殊字元需要進行轉義
self.send_continue_task("<speak rate=\"2\">我的語速比正常人快。</speak>")
# continue-task 發送完成後發送 finish-task
self.send_finish_task()
elif event == "task-finished":
print("任務已完成")
self.task_finished = True
self.close(ws)
elif event == "task-failed":
error_msg = msg_json.get("error_message", "未知錯誤")
print(f"任務失敗: {error_msg}")
self.task_finished = True
self.close(ws)
except json.JSONDecodeError as e:
print(f"JSON 解析失敗: {e}")
else:
# 處理二進位訊息(音頻資料)
print(f"收到二進位訊息,大小: {len(message)} 位元組")
with open(self.output_file, "ab") as f:
f.write(message)
print(f"已將音頻資料寫入本地檔案{self.output_file}中")
def on_error(self, ws, error):
"""發生錯誤時的回調"""
print(f"WebSocket 出錯: {error}")
def on_close(self, ws, close_status_code, close_msg):
"""串連關閉時的回調"""
print(f"WebSocket 已關閉: {close_msg} ({close_status_code})")
def send_continue_task(self, text):
"""發送 continue-task 指令,附帶要合成的常值內容"""
cmd = {
"header": {
"action": "continue-task",
"task_id": self.task_id,
"streaming": "duplex"
},
"payload": {
"input": {
"text": text
}
}
}
self.ws.send(json.dumps(cmd))
print(f"已發送 continue-task 指令,常值內容: {text}")
def send_finish_task(self):
"""發送 finish-task 指令,結束語音合成任務"""
cmd = {
"header": {
"action": "finish-task",
"task_id": self.task_id,
"streaming": "duplex"
},
"payload": {
"input": {}
}
}
self.ws.send(json.dumps(cmd))
print("已發送 finish-task 指令")
def close(self, ws):
"""主動關閉串連"""
if ws and ws.sock and ws.sock.connected:
ws.close()
print("已主動關閉串連")
def run(self):
"""啟動 WebSocket 用戶端"""
# 佈建要求頭部(鑒權)
header = {
"Authorization": f"bearer {self.api_key}",
"X-DashScope-DataInspection": "enable"
}
# 建立 WebSocketApp 執行個體
self.ws = websocket.WebSocketApp(
self.uri,
header=header,
on_open=self.on_open,
on_message=self.on_message,
on_error=self.on_error,
on_close=self.on_close
)
print("正在監聽 WebSocket 訊息...")
self.ws.run_forever() # 啟動長串連監聽
# 樣本使用方式
if __name__ == "__main__":
# 新加坡和北京地區的API Key不同。擷取API Key:https://www.alibabacloud.com/help/zh/model-studio/get-api-key
# 若沒有配置環境變數,請用百鍊API Key將下行替換為:API_KEY = "sk-xxx"
API_KEY = os.environ.get("DASHSCOPE_API_KEY")
# 以下為新加坡地區URL,調用時請將WorkspaceId替換為真實的業務空間ID,各地區的URL不同。
SERVER_URI = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference/"
client = TTSClient(API_KEY, SERVER_URI)
client.run()
標籤參考
阿里巴巴語音合成服務的 SSML 實現參考了 W3C SSML 1.0 規範,但更注重實際業務適配。因此,該服務並未支援所有標準標籤,而是結合實際情境實現了最常用的標籤集合。
-
使用 SSML 功能時,所有常值內容必須包含在
<speak></speak>標籤內。 -
支援多個
<speak>標籤並列使用(如:<speak></speak><speak></speak>),但不支援嵌套結構(如:<speak><speak></speak></speak>)。 -
在編碼時,如果標籤內的文本包含 XML 特殊字元,需要進行字元轉義。常見特殊字元及其轉義形式如下:
-
"(雙引號) →" -
'(單引號/撇號) →' -
&(表示“和”的符號) →& -
<(小於符號) → < -
>(大於符號) → >
-
<speak>:根節點
-
描述
<speak>是所有 SSML 標籤的根節點。使用 SSML 功能時,常值內容必須包含在<speak></speak>標籤之間。 -
文法
<speak>需要使用SSML功能的文本</speak> -
屬性
屬性名稱
屬性類型
是否必選
描述
voice
String
否
指定發音人(音色)。
該屬性的優先順序高於介面請求參數
voice指定的發音人。-
取值範圍:具體的音色,詳情請參見cosyvoice-v2音色。
-
樣本:
<speak voice="longcheng_v2"> 我是男聲。 </speak>
rate
String
否
指定語速。該屬性的優先順序高於介面請求參數
speech_rate指定的語速。-
取值範圍:[0.5,2]之間的小數
-
預設值:1
-
大於1表示加快語速
-
小於1表示減慢語速
-
-
樣本:
<speak rate="2"> 我的語速比正常人快。 </speak>
pitch
String
否
指定音高(語調)。該屬性的優先順序高於介面請求參數
pitch_rate指定的音高。-
取值範圍:[0.5,2]之間的小數
-
預設值:1
-
大於1表示升高音高
-
小於1表示降低音高
-
-
樣本:
<speak pitch="0.5"> 我的音高卻比別人低。 </speak>
volume
String
否
指定音量。該屬性的優先順序高於介面請求參數
volume指定的音量。-
取值範圍:[0,100]之間的整數
-
預設值:50
-
大於50表示增大音量
-
小於50表示減小音量
-
-
樣本:
<speak volume="80"> 我的音量也很大。 </speak>
effect
String
否
指定音效。
-
取值範圍:
-
robot:機器人音效
-
lolita:蘿莉音效
-
lowpass:低通音效
-
echo:回聲音效
-
eq:均衡器(進階)
-
lpfilter:低通濾波器(進階)
-
hpfilter:高通濾波器(進階)
說明-
eq、lpfilter 和 hpfilter 是進階音效類型,可通過
effectValue參數自訂具體效果。 -
每個 SSML 標籤僅支援配置一種音效,不允許同時設定多個
effect屬性。 -
啟用音效功能會增加合成延時。
-
-
樣本:
<speak effect="robot"> 你喜歡機器人瓦力嗎? </speak>
effectValue
String
否
用於進一步配置音效(
effect參數)的具體效果,適用於 eq、lpfilter、hpfilter 三種進階音效類型。-
取值範圍:
-
eq(均衡器):系統預設支援8個頻率等級,對應頻率如下:[“40 Hz”,“100 Hz”, “200 Hz”, “400 Hz”, “800 Hz”, “1600 Hz”, “4000 Hz”, “12000 Hz”]。
每個頻段的頻寬均為 1.0q。
通過
effectValue參數指定每個頻段的增益值:該參數為由 8 個整數組成的字串,數值範圍為 [-20, 20],數字之間用空格分隔。數值為0表示不調整對應頻率的增益。例如:
effectValue="1 1 1 1 1 1 1 1" -
lpfilter(低通濾波器):指定低通濾波器的截止頻率,取值為 (0, 目標採樣率/2] 之間的整數。例如 effectValue="800"。 -
hpfilter(高通濾波器):指定高通濾波器的截止頻率,取值為 (0, 目標採樣率/2] 之間的整數。例如 effectValue="1200"。
-
-
樣本:
<speak effect="eq" effectValue="1 -20 1 1 1 1 20 1"> 你喜歡機器人瓦力嗎? </speak> <speak effect="lpfilter" effectValue="1200"> 你喜歡機器人瓦力嗎? </speak> <speak effect="hpfilter" effectValue="1200"> 你喜歡機器人瓦力嗎? </speak>
bgm
String
否
為合成語音添加背景音樂。背景音檔案需儲存在阿里雲 OSS 上(請參見上傳檔案),且 Bucket 至少需要具備公用讀取許可權。
如果背景音樂 URL 中包含 XML 特殊字元(如
&,<,>等),需進行字元轉義處理。-
音頻要求:
背景音檔案大小無上限,但檔案越大下載耗時越長。如果合成語音的時間長度超過背景音時間長度,背景音將自動迴圈播放。
-
採樣率:16kHz
-
聲道數:單聲道
-
檔案格式:WAV
若原始音頻非 WAV 格式,可使用
ffmpeg工具進行轉換:ffmpeg -i 輸入音頻 -acodec pcm_s16le -ac 1 -ar 16000 輸出.wav -
位元深度:16位
-
-
樣本:
<speak bgm="http://nls.alicdn.com/bgm/2.wav" backgroundMusicVolume="30" rate="-500" volume="40"> <break time="2s"/> 陰崖老木蒼蒼煙 <break time="700ms"/> 雨聲猶在竹林間 <break time="700ms"/> 綿蕝固知裨國計 <break time="700ms"/> 綿州風物總堪憐 <break time="2s"/> </speak>
重要上傳音訊著作權責任由您自行承擔。
backgroundMusicVolume
String
否
指定背景音樂的音量。需與
bgm屬性搭配使用。 -
-
標籤關係
<speak> 標籤可以包含文本和以下子標籤:
-
更多樣本
-
空屬性
<speak> 需要調用SSML標籤的文本 </speak> -
屬性群組合(空格分隔)
<speak rate="200" pitch="-100" volume="80"> 所以放在一起,我的聲音是這樣的。 </speak>
-
<break>:控制停頓時間
-
描述
在語音合成過程中插入一段靜默停頓,類比自然說話中的間歇。支援秒(s)和毫秒(ms)兩種單位。
-
文法
# 空屬性 <break/> # 帶time屬性 <break time="string"/> -
屬性
說明不帶屬性的 <break> 標籤預設停頓時間長度為 1 秒。
屬性名稱
屬性類型
是否必選
描述
time
String
否
設定停頓時間長度,支援秒和毫秒兩種單位(如 “2s” 或 “50ms”)。
-
取值範圍:
-
以秒(s)為單位,取值範圍為[1, 10]之間的整數
-
以毫秒(ms)為單位,取值範圍為[50, 10000]之間的整數
-
-
樣本:
<speak> 請閉上眼睛休息一下<break time="500ms"/>好了,請睜開眼睛。 </speak>
重要連續使用多個
<break>標籤時,總停頓時間長度為各標籤時間的累加值。如果總時間長度超過 10 秒,則僅保留前 10 秒。例如以下 SSML 中,
<break>標籤累計時間長度為 15 秒,超過 10 秒上限,實際停頓將被截斷為 10 秒:<speak> 請閉上眼睛休息一下<break time="5s"/><break time="5s"/><break time="5s"/>好了,請睜開眼睛。 </speak> -
-
標籤關係
<break> 是自閉合標籤,不能包含任何子標籤。
<sub>:替換文本
-
描述
將指定文本替換為更適合朗讀的內容。例如,將 “W3C” 朗讀為 “網路通訊協定標準”。
-
文法
<sub alias="string"></sub> -
屬性
屬性名稱
屬性類型
是否必選
描述
alias
String
是
指定用於替代原文本的朗讀內容。
樣本:
<speak> <sub alias="網路通訊協定標準">W3C</sub> </speak> -
標籤關係
<sub> 標籤內只能包含純文字。
<phoneme>:指定發音(拼音/音標)
-
描述
精確控制文本的發音方式。中文可通過拼音指定讀音,英文可使用 CMU 音標。適用於多音字消歧和外語發音等情境。
-
文法
<phoneme alphabet="string" ph="string">文本</phoneme> -
屬性
屬性名稱
屬性類型
是否必選
描述
alphabet
String
是
指定發音類型:拼音(對應中文)或音標(對應英文)。
取值範圍:
-
"py":拼音
-
"cmu":音標,參見The CMU Pronouncing Dictionary
ph
String
是
指定具體的拼音或音標。使用規則如下:
-
多個漢字的拼音之間用空格分隔,拼音個數必須與漢字數量一致。
-
每個拼音由發音部分和音調組成,其中音調為
1到5的整數,5表示輕聲。 -
樣本:
<speak> 去<phoneme alphabet="py" ph="dian3 dang4 hang2">典當行</phoneme>把這個玩意<phoneme alphabet="py" ph="dang4 diao4">當掉</phoneme> </speak> <speak> How to spell <phoneme alphabet="cmu" ph="S AY N">sin</phoneme>? </speak>
-
-
標籤關係
<phoneme> 標籤內只能包含純文字。
<soundEvent>:插入一段外部聲音(鈴聲、貓叫等)
-
描述
在語音中的指定位置插入音效檔案(如提示音、環境音等),增強語音表達的豐富性。
-
文法
<soundEvent src="URL"/> -
屬性
屬性名稱
屬性類型
是否必選
描述
src
String
是
指定外部音頻檔案的 URL。
音頻檔案需儲存在阿里雲 OSS 上(請參見上傳檔案),且 Bucket 至少需要具備公用讀取許可權。如果 URL 中包含 XML 特殊字元(如
&,<,>等),需進行字元轉義處理。-
音頻要求:
-
採樣率:16kHz
-
聲道數:單聲道
-
檔案格式:WAV
若原始音頻非 WAV 格式,可使用
ffmpeg工具進行轉換:ffmpeg -i 輸入音頻 -acodec pcm_s16le -ac 1 -ar 16000 輸出.wav
-
檔案大小:不超過2MB
-
位元深度:16位
-
-
樣本:
<speak> 一匹馬受了驚嚇<soundEvent src="http://nls.alicdn.com/sound-event/horse-neigh.wav"/>人們四散躲避 </speak>
重要您需要對上傳的音頻著作權承擔相應的法律責任。
-
-
標籤關係
<soundEvent> 是自閉合標籤,不能包含任何子標籤。
<say-as>:設定文本的讀法(數字、日期、電話號碼等)
-
描述
指定文本的內容類型(如數字、日期、電話號碼等),系統將按照對應類型的規範讀法進行朗讀。
-
文法
<say-as interpret-as="string">文本</say-as> -
屬性
屬性名稱
屬性類型
是否必選
描述
interpret-as
String
是
指定標籤內文本的內容類型。
取值範圍:
-
cardinal:按整數或小數的標準讀法朗讀
-
digits:按數字逐個讀出(如:123 → 一二三)
-
telephone:按電話號碼的標準方式逐位讀出
-
name:按人名的標準讀法朗讀
-
address:按地址的標準方式朗讀
-
id:按標識符(如賬戶名、暱稱)的標準方式朗讀
-
characters:逐字元朗讀標籤內的文本
-
punctuation:將標籤內的標點符號讀出名稱
-
date:按日期格式的標準讀法朗讀
-
time:按時間格式的標準方式朗讀
-
currency:按貨幣金額的標準讀法朗讀
-
measure:按計量單位的標準方式朗讀
-
-
各<say-as>類型支援範圍
-
cardinal
格式
樣本
中文輸出
說明
數字串
145
一百四十五
整數輸入範圍:20位以內的正負整數,[-99999999999999999999,99999999999999999999]。
小數輸入範圍:對小數點後小數的位元沒有特殊限制,建議不超過10位。
負號+數字串
-145
負一百四十五
以逗號分隔3位元字串
10,000
一萬
負號+以逗號分隔3位元字串
-10,124
負一萬一百二十四
數字串+小數點+2個零
10.00
十
負號+數字串+小數點+2個零
-110.00
負一百一十
數字串+小數點+數字串
79.090
七十九點零九零
負號+數字串+小數點+數字串
-79.001
負七十九點零零一
格式
樣本
英文輸出
說明
數字串
145
one hundred forty five
整數輸入範圍:13位以內的正負整數,[-999999999999,999999999999]。
小數輸入範圍:對小數點後小數的位元沒有特殊限制,建議不超過10位。
以零開頭的數字串
0145
one hundred forty five
負號+數字串
-145
minus hundred forty five
以逗號分隔三位元字串
60,000
sixty thousand
負號+以逗號分隔三位元字串
-208,000
minus two hundred eight thousand
數字串+小數點+零
12.00
twelve
數字串+小數點+數字串
12.34
twelve point three four
以逗號分隔三位元字串+小數點+數字串
1,000.1
one thousand point one
負號+數字串+小數點+數字串
-12.34
minus twelve point three four
負號+以逗號分隔三位元字串+小數點+數字串
-1,000.1
minus one thousand point one
(以逗號分隔三位)數字串+連詞符+(以逗號分隔三位)數字
1-1,000
one to one thousand
其他預設讀法
012.34
twelve point three four
無
1/2
one half
-3/4
minus three quarters
5.1/6
five point one over six
-3 1/2
minus three and a half
1,000.3^3
one thousand point three to the power of three
3e9.1
three times ten to the power of nine point one
23.10%
twenty three point one percent
-
digits
格式
樣本
中文輸出
說明
數字串
129090909
一二九零九零九零九
對數字串的長度沒有特殊限制,建議不超過20位。
當數字串超過10位時,每個數字後插入停頓。
格式
樣本
英文輸出
說明
數字串
12034
one two zero three four
對數字串的長度沒有特殊限制,建議不超過20位。
當數字串以空格或連詞符分組時,分組之間會插入逗號而產生適當停頓,支援最長5個分組。
數字串+空格或連詞符+數字串+空格或連詞符+數字串+空格或連詞符+數字串
1-23-456 7890
one, two three, four five six, seven eight nine zero
-
telephone
格式
樣本
中文輸出
說明
有線電話號
4930286
四九三 零二八六
支援7~8位有線電話號,支援空格和“-”作為分隔字元。
其中,7位有線電話號支援“3-4”的數字分隔方式;8位有線電話號支援“4-4”的數字分隔方式。
493 0286
四九三 零二八六
493-0286
四九三 零二八六
62552560
六二五五 二五六零
6255 2560
六二五五 二五六零
6255-2560
六二五五 二五六零
有線電話號+分機號
4930286-109
四九三 零二八六 轉么零九
支援1~4位分機號。
4930286轉109
四九三 零二八六 轉么零九
4930286分機109
四九三 零二八六 分機么零九
4930286分機號109
四九三 零二八六 分機號么零九
區號+有線電話號
01062552560
零么零 六二五五 二五六零
支援區號:010、02x、03xx、04xx、05xx、07xx、08xx、09xx。
010 62552560
零么零 六二五五 二五六零
010 6255 2560
零么零 六二五五 二五六零
010 6255-2560
零么零 六二五五 二五六零
010-62552560
零么零 六二五五 二五六零
010-6255-2560
零么零 六二五五 二五六零
(010)62552560
零么零 六二五五 二五六零
03198907098
零三么九 八九零 七零九八
0319-8907098
三么九 八九零 七零九八
區號+有線電話號+分機號
010 62552560-109
零么零 六二五五 二五六零 轉么零九
無
010-62552560-109
零么零 六二五五 二五六零 轉么零九
(010)62552560-109
零么零 六二五五 二五六零 轉么零九
(010)62552560轉109
零么零 六二五五 二五六零 轉么零九
(010)62552560分機109
零么零 六二五五 二五六零 分機么零九
(010)62552560分機號109
零么零 六二五五 二五六零 分機號么零九
國家代碼+區號+有線電話號
86-010-62791627
八六 零么零 六二七九 么六二七
支援國家代碼:86、 (86)、+86、(+86)、0086。並統一讀為“八六”。
(86)10-62791627
八六 么零 六二七九 么六二七
+86-010-62791627
八六 零么零 六二七九 么六二七
0086-10-62791627
八六 么零 六二七九 么六二七
(+86)-10-6279 1627
八六 么零 六二七九 么六二七
國家代碼+區號+有線電話號+分機號
(86)21-58118818-207
八六 二么 五八么么 八八么八 轉二零七
無
(86)021-5811-8818-207
八六 零二么 五八么么 八八么八 轉二零七
(86)021-58118818轉207
八六 零二么 五八么么 八八么八 轉二零七
(86)21-5811-8818分機207
八六 二么 五八么么 八八么八 分機二零七
+86-021-58118818分機號207
八六 零二么 五八么么 八八么八分機號二零七
手機號
139 0000 5678
么三九 零零零零 五六七八
支援11位手機號,支援3-3-5、3-4-4兩種數字分隔方式
139-000-05678
么三九 零零零 零五六七八
139 000 05678
么三九 零零零 零五六七八
國家代碼+手機號
+86-13900005678
八六 么三九 零零零零 五六七八
無
(+86)-139-0000-5678
八六 么三九 零零零零 五六七八
+8613900005678
八六 么三九 零零零零 五六七八
0086-139 000 05678
八六 么三九 零零零 零五六七八
服務號
123
么二三
-
支援常用的服務號。
-
支援以400/800開頭的10位服務號,支援以“3-3-4”的數字分隔方式。
-
支援以12530/17951/12593開頭的16位號碼。
95678
九五六七八
4008110510
四零零 八么么 零五么零
800-810-8888
八零零 八么零 八八八八
1253013520638377
么二五三零 么三五 二零六三 八三七七
其他
(86)(21)9899-80800-0909
八六 二么 九八九九 八零八零零 零九零九
支援“數字串+分隔字元(左右括弧、-)”方式。
格式
樣本
英文輸出
說明
數字串
12034
one two oh three four
對數字串的長度沒有特殊限制,建議不超過20位。當數字串以空格或連詞符分組時,分組之間會插入逗號而產生適當停頓,支援最長5個分組。
數字串+空格或連詞符+數字串+空格或連詞符+數字串
1-23-456 7890
one, two three, four five six, seven eight nine oh
加號+數字串+空格或連詞符+數字串
+43-211-0567
plus four three, two one one, oh five six seven
左括弧+數字串+右括弧+空格+數字串+空格或連詞符+數字串
(21) 654-3210
(two one) six five four, three two one oh
-
-
address
格式
樣本
中文輸出
說明
常用地址格式
元和鎮嘉元30-9
元和鎮嘉元三十杠九
支援常用地址格式。此處地址指標準的郵寄地址。
市台路388弄1107-1108號
市台路三八八弄么么零七杠么么零八號
華潤二十四城六期錦雲府3-1-3205
華潤二十四城六期錦雲府三杠一杠三二零五
聖華名都大廈2幢2006室
聖華名都大廈二幢二零零六室
五常街道庭院5幢4單元201
五常街道庭院五幢四單元二零么
芙蓉江路150弄19號
芙蓉江路么五零弄十九號
英文文本不支援該標籤。
-
id
格式
樣本
輸出
說明
字串
dell0101
D E L L 零 一 零 一
大小寫英文字元、阿拉伯數字0~9、底線。
輸出的空格表示每個字元之間插入停頓,即字元一個一個地讀。
myid_1998
M Y I D 底線 一 九 九 八
AiTest
A I T E S T
英文文本該標籤功能同標籤characters。
-
characters
格式
樣本
中文輸出
說明
字串
ISBN 1-001-099098-1
I S B N 一 杠 零 零 一 杠 零 九 九 零 九 八 杠 一
支援中文漢字、大小寫英文字元、阿拉伯數字0~9以及部分全形和半形字元。
輸出的空格表示每個字元之間插入停頓,即字元一個一個地讀。標籤內的文本如果包含XML的特殊字元,需要做字元轉義。
x10b2345_u
x 一 零 b 二 三 四 五 底線 u
v1.0.1
v 一 點 零 點 一
版本號碼2.0
版本號碼二 點 零
蘇M MA000
蘇M M A 零 零 零
空中巴士A330
空中巴士A 三 三 零
型號s01 s02和s03
型號s 零 一 s 零二 和s 零 三
空中巴士A330
空中巴士A 三 三 零
αβγ
阿爾法 貝塔 伽瑪
格式
樣本
英文輸出
說明
字串
*b+3$.c-0'=α
asterisk B plus three dollar dot C dash zero apostrophe equals alpha
支援中文漢字、大小寫英文字元、阿拉伯數字0~9以及部分全形和半形字元。
輸出的空格表示每個字元之間插入停頓,即字元一個一個地讀。
標籤內的文本如果包含XML的特殊字元,需要做字元轉義。
-
punctuation
格式
樣本
中文輸出
說明
標點符號
…
省略符號
支援常見中英文標點。輸出的空格表示每個字元之間插入停頓,即字元一個一個地讀。
標籤內的文本如果包含XML的特殊字元,需要做字元轉義。
……
省略符號
!"#$%&
歎號 雙引號 井號 dollar 百分比符號 and
‘()*+
單引號 左括弧 右括弧 星號 加號
,-./:;
逗號 杠 點 斜杠 冒號 分號
<=>?@
小於 等號 大於 問號 at
[\]^_
左方括弧 反斜線 右方括弧 脫字元 底線
英文文本該標籤功能同標籤characters。
-
date
格式
樣本
中文輸出
說明
xx年
71年
七一年
支援2位和4位年份。其中:
-
2位年份支援60年~99年、00年~09年、10年~19年。
-
4位年份支援1000年~1999年、2000年~2099年。
04年
零四年
19年
一九年
1011年
一零一一年
1998年
一九九八年
2008年
二零零八年
xx年xx月
98年4月
九八年四月
當月份為1到9月時,支援開頭帶“0”和不帶“0”兩種寫法。例如“1908年4月”和“1908年04月”。
1998年04月
一九九八年四月
08年8月
零八年八月
2008年8月
二零零八年八月
xx年xx月xx日xx年xx月xx號
98年4月23日
九八年四月二十三日
當日期為1到9日時,支援開頭帶“0”和不帶“0”兩種寫法。例如“1908年4月8日”和“1908年04月08日”。
1998年04月23日
一九九八年四月二十三日
08年8月8號
零八年八月八號
2008年08月08號
二零零八年八月八號
xx年xx月xx日xx年xx月xx號
98年4月23日
九八年四月二十三日
當日期為1到9日時,支援開頭帶“0”和不“0”兩種寫法。例如“1908年4月8日”和“1908年04月08日”。
1998年04月23日
一九九八年四月二十三日
08年8月8號
零八年八月八號
2008年08月08號
二零零八年八月八號
xx月xx號
3月20日
三月二十日
無
08月07號
八月七號
年月縮寫
2018/08
二零一八年八月
支援“/”、“-”、“.”作為縮寫的分隔字元。
2018-08
二零一八年八月
2018.08
二零一八年八月
年月日縮寫
2018/08/08
二零一八年八月八日
2018-8-8
二零一八年八月八日
2018.08.08
二零一八年八月八日
xx年xx月xx日~xx年xx月xx日xx年xx月xx號~xx年xx月xx號
04年9月1日~30日
零四年九月一日至三十日
支援“~”、“-”作為“至”的縮寫標誌。
2004年09月01號-2008年06月08號
二零零四年九月一號至二零零八年六月八號
xx年xx月xx日~xx日xx年xx月xx號~xx號
04年9月1日~30日
零四年九月一日至三十日
2004年09月01號-2008年06月08號
二零零四年九月一號至二零零八年六月八號
xx年xx月~xx年xx月
01年04月~10年04月
零一年四月至一零年四月
2001年04月~2010年04月
二零零一年四月至二零一零年四月
xx月xx日~xx月xx日xx月xx號~xx月xx號
10月1日~10月7日
十月一日至十月七日
10月01號~10月07號
十月一號至十月七號
xx月xx日~xx日xx月xx號~xx號
10月1日~7日
十月一日至七日
10月01號~07號
十月一號至七號
年月日縮寫~年月日縮寫
2018/03/03~2019/01/01
二零一八年三月三日至二零一九年一月一日
支援“/”、“.”作為縮寫的分隔字元,支援“~”、“-”作為“至”的縮寫標誌。
1997.9.9~1998.9.9
一九九七年九月九日至一九九八年九月九日
月日縮寫~月日縮寫
10/20~10/31
十月二十日至十月三十一日
xx~xx月xx月~xx月
1~10月
一至十月
1月~10月
一月至十月
月日年縮寫
10/20/2018
二零一八年十月二十日
僅支援4位的年份,僅支援“/”作為日期的分隔字元,僅支援“月/日/年”的書寫方式。
格式
樣本
英文輸出
說明
四位元字/兩位元字或四位元字-兩位元字
2000/01
two thousand, oh one
跨年度。
1900-01
nineteen hundred, oh one
2001-02
twenty oh one, oh two
2019-20
twenty nineteen, twenty
1998-99
nineteen ninety eight, ninety nine
1999-00
nineteen ninety nine, oh oh
以1或2開頭的四位元字
2000
two thousand
四位元字年份。
1900
nineteen hundred
1905
nineteen oh five
2021
twenty twenty one
星期幾-星期幾
或
星期幾~星期幾
或
星期幾&星期幾
mon-wed
monday to wednesday
星期幾的範圍標籤內的文本如果包含XML的特殊字元,需要做字元轉義。
tue~fri
tuesday to friday
sat&sun
saturday and sunday
DD-DD MMM, YYYY
或
DD~DD MMM, YYYY
或
DD&DD MMM, YYYY
19-20 Jan, 2000
the nineteen to the twentieth of january two thousand
DD表示兩位元字日期,MMM表示月份的三字母縮寫或完整單詞,YYYY表示以1或2開頭的四位元字年份。
01 ~ 10 Jul, 2020
the first to the tenth of july twenty twenty
05&06 Apr, 2009
the fifth and the sixth of april two thousand nine
MMM DD-DD
或
MMM DD~DD
或
MMM DD&DD
Feb 01 - 03
feburary the first to the third
MMM表示月份的三字母縮寫或完整單詞,DD表示兩位元字日期。
Aug 10~20
august the tenth to the twentieth
Dec 11&12
december the eleventh and the twelfth
MMM-MMM
或
MMM~MMM
或
MMM&MMM
Jan-Jun
january to june
MMM表示月份的三字母縮寫或完整單詞。
jul ~ dec
july to december
sep&oct
september and october
YYYY-YYYY
或
YYYY~YYYY
1990 - 2000
nineteen ninety to two thousand
YYYY表示以1或2開頭的四位元字年份。
2001~2021
two thousand one to twenty twenty one
WWW DD MMM YYYY
Sun 20 Nov 2011
sunday the twentieth of november twenty eleven
WWW表示星期幾的三字母縮寫或完整單詞,DD表示兩位元字日期,MMM表示月份的三字母縮寫或完整單詞,MM表示兩位元字月份(或三字母縮寫或完整單詞),YYYY表示以1或2開頭的四位元字年份。
WWW DD MMM
Sun 20 Nov
sunday the twentieth of november
WWW MMM DD YYYY
Sun Nov 20 2011
sunday november the twentieth twenty eleven
WWW MMM DD
Sun Nov 20
sunday november the twentieth
WWW YYYY-MM-DD
Sat 2010-10-01
aturday october the first twenty ten
WWW YYYY/MM/DD
Sat 2010/10/01
saturday october the first twenty ten
WWW MM/DD/YYYY
Sun 11/20/2011
sunday november the twentieth twenty eleven
MM/DD/YYYY
11/20/2011
november the twentieth twenty eleven
YYYY
1998
nineteen ninety eight
其他預設讀法
10 Mar, 2001
the tenth of march two thousand one
無
10 Mar
the tenth of march
Mar 2001
march two thousand one
Fri. 10/Mar/2001
friday the tenth of march two thousand one
Mar 10th, 2001
march the tenth two thousand one
Mar 10
march the tenth
2001/03/10
march the tenth two thousand one
2001-03-10
march the tenth two thousand one
2000s
two thousands
2010's
twenty tens
1900's
nineteen hundreds
1990s
nineteen nineties
-
-
time
格式
樣本
中文輸出
說明
時刻
12:00
十二點
支援常用時間和時間範圍格式。
12:00:00點
十二點
10:20分
十點二十分
10:20:30
十點二十分三十秒
09:18:14
九點十八分十四秒
時刻~時刻
11:00~12:00
十一點到十二點
09:00-14:00
九點到十四點
11:00~11:30
十一點到十一點三十分
11:00-12:18
十一點到十二點十八分
10:30~11:00
十點三十分到十一點
09:28-10:00
九點二十八分到十點
10:20~11:20
十點二十分到十一點二十分
06:00~08:00
六點到八點
上午10:20~下午13:30
上午十點二十分到下午十三點三十分
時間縮寫
5:00 am
淩晨五點整
5:30 am
淩晨五點半
5:20:12 am
淩晨五點二十分十二秒
7:00 am
上午七點整
7:30 AM
上午七點半
7:20:12 a.m.
上午七點二十分十二秒
07:08:12 A.M.
上午七點零八分十二秒
5:00 pm
下午五點整
5:30 PM
下午五點半
5:20:12 p.m.
下午五點二十分十二秒
05:09:12 P.M.
下午五點零九分十二秒
9:00 pm
晚上九點整
9:30 pm
晚上九點半
9:20:12 PM
晚上九點二十分十二秒
9:02:12 P.M.
晚上九點零二分十二秒
12:00 pm
中午十二點整
12:30 p.m.
中午十二點半
12:20:12 PM
中午十二點二十分十二秒
格式
樣本
英文輸出
說明
HH:MM AM或PM
09:00 AM
nine A M
HH表示一或兩位元字小時,MM表示兩位元字分鐘,AM/PM表示上/下午。
09:03 PM
nine oh three P M
09:13 p.m.
nine thirteen p m
HH:MM
21:00
twenty one hundred
HHMM
100
one oclock
時刻-時刻
8:00 am - 05:30 pm
eight a m to five p m
支援常見時間格式和範圍。
7:05~10:15 AM
seven oh five to ten fifteen A M
09:00-13:00
nine oclock to thirteen hundred
-
currency
格式
樣本
中文輸出
說明
數字+金額標識符
12.00 RMB
十二人民幣
支援AUD(澳幣) 、CAD(加元)、 HKD(港幣)、JPY(日元)、USD(美元)、CHF(瑞士法郎)、NOK(挪威克朗)、SEK(瑞典克朗)、GBP(英鎊)、 RMB(人民幣)、CNY(元)和EUR(歐元)。
支援的數字格式包括:整數、小數以及以逗號分隔的國際寫法。
12.50 RMB
十二點五零人民幣
12,000,000 RMB
一千二百萬人民幣
12,000,000.00 RMB
一千二百萬人民幣
12,000.35 RMB
一萬兩千點三五人民幣
金額標識符+數字
$12
十二美元
支援 CAD(加元)、 $(美元)、Fr(法郎)、kr(丹麥幣)、 £(英鎊)、¥(元)和 €(歐元)。
支援的數字格式包括:整數、小數以及以逗號分隔的國際寫法。
$12.00
十二美元
$12.12
二點一二美元
$12,000
一萬兩千美元
$12,000.00
一萬兩千美元
$12,000.99
一萬兩千點九九美元
其他預設讀法
1213
一千二百一十三
無
1213 KML
一千二百一十三K M L
1213.00 KML
一千二百一十三K M L
1213.9 KML
一千二百一十三點九K M L
1,000 KML
一千K M L
1,000.00 KML
一千K M L
1,000.98 KML
一千點九八K M L
12,000
一萬兩千
格式
樣本
英文輸出
說明
數字+金額識別符
1.00 RMB
one yuan
支援的數字格式:整數、小數以及以逗號分隔的國際寫法。
支援的金額識別符:
CN¥ (yuan)
CNY (yuan)
RMB (yuan)
AUD (australian dollar)
CAD (canadian dollar)
CHF (swiss franc)
DKK (danish krone)
EUR (euro)
GBP (british pound)
HKD (Hong Kong(China) dollar)
JPY (japanese yen)
NOK (norwegian krone)
SEK (swedish krona)
SGD (singapore dollar)
USD (united states dollar)
2.02 CNY
two point zero two yuan
1,000.23 CN¥
one thousand point two three yuan
1.01 SGD
one singapore dollar and one cent
2.01 CAD
two canadian dollars and one cent
3.1 HKD
three hong kong dollars and ten cents
1,000.00 EUR
one thousand euros
金額識別符+數字
US$ 1.00
one US dollar
支援的數字格式:整數、小數以及以逗號分隔的國際寫法。
支援的金額識別符:
US$ (US dollar)
CA$ (Canadian dollar)
AU$ (Australian dollar)
SG$ (Singapore dollar)
HK$ (Hong Kong dollar)
C$ (Canadian dollar)
A$ (Australian dollar)
$ (dollar)
£ (pound)
€ (euro)
CN¥ (yuan)
CNY (yuan)
RMB (yuan)
AUD (australian dollar)
CAD (canadian dollar)
CHF (swiss franc)
DKK (danish krone)
EUR (euro)
GBP (british pound)
HKD (Hong Kong(China) dollar)
JPY (japanese yen)
NOK (norwegian krone)
SEK (swedish krona)
SGD (singapore dollar)
USD (united states dollar)
$0.01
one cent
JPY 1.01
one japanese yen and one sen
£1.1
one pound and ten pence
€2.01
two euros and one cent
USD 1,000
one thousand united states dollars
數字+量詞+金額識別符
或
金額識別符+數字+量詞
1.23 Tn RMB
one point two three trillion yuan
支援的量詞格式包括:
thousand
million
billion
trillion
Mil (million)
mil (million)
Bil (billion)
bil (billion)
MM (million)
Bn (billion)
bn (billion)
Tn (trillion)
tn (trillion)
K(thousand)
k (thousand)
M (million)
m (million)
$1.2 K
one point two thousand dollars
-
measure
格式
樣本
中文輸出
說明
數字+中文單位
2片
兩片
支援常見中文單位及單位縮寫。
120公頃
一百二十公頃
100多毫克
一百多毫克
100來米
一百來米
100餘人
一百餘人
1厘米20毫米
一厘米二十毫米
120.00平方公裡
一百二十平方公裡
數字+單位縮寫
120.56 cm²
一百二十點五六平方厘米
120 ㎡ 56 cm²
一百二十平方米五十六平方厘米
100 m 12 cm 6 mm
一百米十二厘米六毫米
範圍
10~15 kg
十至十五千克
10.24~789.82畝
十點二四至七百八十九點八二畝
10米~15米
十米至十五米
10.24 cm~19.08 cm
十點二四厘米至十九點零八厘米
數字+單位+"/"+單位
10元/斤
十元每斤
199~299元/件
一百九十九至二百九十九元每件
299.99元/g~399.99元/g
二百九十九點九九元每克至三百九十九點九九元每克
其他預設讀法
12紮
十二紮
30 rm
三十r m
4萬萬同胞
四萬萬同胞
12.897微克
十二點八九七微克
格式
樣本
英文輸出
說明
數字+計量單位
1.0 kg
one kilogram
支援的數字格式:整數、小數以及以逗號分隔的國際寫法。
支援常見單位縮寫。
1,234.01 km
one thousand two hundred thirty four point zero one kilometres.
計量單位
mm2
square millimetre
-
<say-as>常見符號讀法如下表所示。
符號
中文讀法
英文讀法
!
歎號
exclamation mark
“
雙引號
double quote
#
井號
pound
$
dollar
dollar
%
百分比符號
percent
&
and
and
‘
單引號
left quote
(
左括弧
left parenthesis
)
右括弧
right parenthesis
*
星
asterisk
+
加
plus
,
逗號
comma
-
杠
dash
.
點
dot
/
斜杠
slash
:
零冒號
solon
;
分號
semicolon
<
小於
less than
=
等號
equals
>
大於
greater than
?
問號
question mark
@
at
at
[
左方括弧
left bracket
\
反斜線
back slash
]
右方括弧
right bracket
^
脫字元
caret
_
底線
underscore
`
反引號
back quote
{
左花括弧
left brace
|
豎線
vertical bar
}
右花括弧
right brace
~
波浪線
tilde
!
歎號
exclamation mark
“
左雙引號
left double quote
”
右雙引號
right double qute
‘
左單引號
left quote
’
右單引號
right quote
(
左括弧
left parenthesis
)
右括弧
right parenthesis
,
逗號
comma
。
句號
full stop
—
杠
em dash
:
冒號
colon
;
分號
semicolon
?
問號
question mark
、
頓號
enumeration comma
…
省略符號
ellipsis
……
省略符號
ellipsis
《
左>形箭號
left guillemet
》
右>形箭號
right guillemet
¥
人民幣符號
yuan
≥
大於等於
greater than or equal to
≤
小於等於
less than or equal to
≠
不等於
not equal
≈
約等於
approximately equal
±
加減
plus or minus
×
乘
times
π
派
pi
Α
阿爾法
alpha
Β
貝塔
beta
Γ
伽瑪
gamma
Δ
德爾塔
delta
Ε
艾普西龍
epsilon
Ζ
捷塔
zeta
Θ
西塔
theta
Ι
艾歐塔
iota
Κ
喀帕
kappa
∧
拉姆達
lambda
Μ
繆
mu
Ν
拗
nu
Ξ
克西
ksi
Ο
歐麥克輪
omicron
∏
派
pi
Ρ
柔
rho
∑
西格瑪
sigma
Τ
套
tau
Υ
宇普西龍
upsilon
Φ
fai
phi
Χ
器
chi
Ψ
普賽
psi
Ω
歐米伽
omega
α
阿爾法
alpha
β
貝塔
beta
γ
伽瑪
gamma
δ
德爾塔
delta
ε
艾普西龍
epsilon
ζ
捷塔
zeta
η
依塔
eta
θ
西塔
theta
ι
艾歐塔
iota
κ
喀帕
kappa
λ
拉姆達
lambda
μ
繆
mu
ν
拗
nu
ξ
克西
ksi
ο
歐麥克輪
omicron
π
派
pi
ρ
柔
rho
σ
西格瑪
sigma
τ
套
tau
υ
宇普西龍
upsilon
φ
fai
phi
χ
器
chi
ψ
普賽
psi
ω
歐米伽
omega
-
<say-as>常見計量單位如下表所示。
格式
類別
中文樣本
英文樣本
縮寫
長度
nm(納米)、μm(微米)、 mm(毫米)、cm(厘米)、m(米)、km(千米)、ft(英尺)、in(英寸)
nm (nanometre), μm (micrometre), mm (millimetre), cm (centimetre), m (metre), km (kilometre), ft (foot), in (inch)
面積
cm²(平方厘米)、㎡(平方米)、km²(平方千米)、SqFt(平方英尺)
cm² (square centimetre), ㎡ (square metre), km2 (square kilometre), SqFt (square foot)
體積
cm³(立方厘米)、m³(立方米)、km³(立方千米)、mL(毫升)、L(升)、gallon(加侖)
cm³ (cubic centimetre), m³ (cubic metre), km3 (cubic kilometre), mL (millilitre), L (millilitre), gal (gallon)
重量
μg(微克)、mg(毫克)、g(克)、kg(千克)
μg (microgram), mg (microgram), g (gram), kg (kilogram)
時間
min(分)、sec(秒)、ms(毫秒)
min (minute), sec (second), ms (millisecond)
電磁
μA(微安)、mA(毫安)、Ω(歐姆)、Hz(赫茲)、kHz(千赫茲)、MHz(兆赫茲)、GHz(吉赫茲)、V(伏)、kV(千伏)、kWh(千瓦時)
μA (microamp), mA (milliamp), Hz (hertz), kHz (kilohertz), MHz (megahertz), GHz (gigahertz), V (volt), kV (kilovolt), kWh (kilowatt hour)
聲音
dB(分貝)
dB (decibel)
氣壓
Pa(帕)、kPa(千帕)、Mpa(兆帕)
Pa (pascal), kPa (kilopascal), MPa (megapascal)
其他常見單位
支援不限於上述類別的中文單位,例如“米”、“秒”、“美元”、“毫升每瓶”等。以及中文量詞,例如“架”、“場”、“頭”、“部”、“盆”等。
支援不限於上述類別的計量單位,例如 tsp (teaspoon), rpm (round per minute), KB (kilobyte), mmHg (milimetre of mercury) 等。
-
-
標籤關係
<say-as>標籤可以包括文本及<vhml/>。
-
樣本
-
cardinal
<speak> <say-as interpret-as="cardinal">12345</say-as> </speak><speak> <say-as interpret-as="cardinal">10234</say-as> </speak> -
digits
<speak> <say-as interpret-as="digits">12345</say-as> </speak><speak> <say-as interpret-as="digits">10234</say-as> </speak> -
telephone
<speak> <say-as interpret-as="telephone">12345</say-as> </speak><speak> <say-as interpret-as="telephone">10234</say-as> </speak> -
name
<speak> 她的曾用名是<say-as interpret-as="name">曾小凡</say-as> </speak> -
address
<speak> <say-as interpret-as="address">富路國際1號樓3單元304</say-as> </speak> -
id
<speak> <say-as interpret-as="id">myid_1998</say-as> </speak> -
characters
<speak> <say-as interpret-as="characters">希臘字母αβ</say-as> </speak><speak> <say-as interpret-as="characters">*b+3.c$=α</say-as> </speak> -
punctuation
<speak> <say-as interpret-as="punctuation"> -./:;</say-as> </speak> -
date
<speak> <say-as interpret-as="date">1000-10-10</say-as> </speak><speak> <say-as interpret-as="date">10-01-2020</say-as> </speak> -
time
<speak> <say-as interpret-as="time">5:00am</say-as> </speak><speak> <say-as interpret-as="time">0500</say-as> </speak> -
currency
<speak> <say-as interpret-as="currency">13,000,000.00RMB</say-as> </speak><speak> <say-as interpret-as="currency">$1,000.01</say-as> </speak> -
measure
<speak> <say-as interpret-as="measure">100m12cm6mm</say-as> </speak><speak> <say-as interpret-as="measure">1,000.01kg</say-as> </speak>
-
LaTeX 方程式轉語音(僅支援中文)
使用限制
-
語種限制:僅支援中文。
-
內容限制:公式內容必須在支援的標籤與符號範圍內。不支援 Markdown 格式的數學公式(如
```math ... ```)。分隔字元內應僅包含公式內容,混入非公式文本可能導致朗讀不準確。 -
模型限制:僅支援
cosyvoice-v3.5-plus、cosyvoice-v3.5-flash、cosyvoice-v3-plus、cosyvoice-v3-flash和cosyvoice-v2模型。
使用方法
將文本中的數學公式用分隔字元包裹後,調用語音合成 API 即可實現公式朗讀。
支援的分隔字元(任選一種,效果相同):
-
$...$ -
$$...$$ -
\(...\) -
\[...\]
樣本輸入:
這是一道一元二次方程的求根公式:$x = \frac{-b \pm \sqrt{b^2-4ac}}{2a}$,請仔細計算。
在 JSON 請求體或程式設計語言的字串中,反斜線 \ 是逸出字元,需要寫成雙反斜線 \\。例如,LaTeX 命令 \frac 在代碼中應寫作 \\frac。
快速開始
以下樣本展示如何合成包含 LaTeX 方程式的文本。
Python
# coding=utf-8
import os
import dashscope
from dashscope.audio.tts_v2 import *
# 若沒有配置環境變數,請用百鍊API Key將下行替換為:dashscope.api_key = "sk-xxx"
dashscope.api_key = os.environ.get('DASHSCOPE_API_KEY')
# 以下為新加坡地區URL,調用時請將WorkspaceId替換為真實的業務空間ID,各地區的URL不同。
dashscope.base_websocket_api_url='wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference'
model = "cosyvoice-v3-flash"
voice = "longanyang"
synthesizer = SpeechSynthesizer(model=model, voice=voice)
# 公式中的反斜線需要轉義為 \\
audio = synthesizer.call("這是一道一元二次方程的求根公式:$x = \\frac{-b \\pm \\sqrt{b^2-4ac}}{2a}$,請仔細計算。")
with open('output.mp3', 'wb') as f:
f.write(audio)
print('requestId: {}'.format(synthesizer.get_last_request_id()))
支援的標籤與符號
下表列出了當前支援的 LaTeX 標籤與符號。
基礎數學
|
標籤或符號 |
作用 |
公式內容樣本 |
待合成文本樣本 |
讀法 |
|
+ |
加 |
2 + 3 = 5 |
$2 + 3 = 5$ |
二加三等於五 |
|
- |
減 |
3 - 2 = 1 |
$3 - 2 = 1$ |
三減二等於一 |
|
\pm |
加減 |
\pm 1 \pm 2 |
$\pm 1\pm 2$ |
正負一加減二 |
|
正負 |
||||
|
\times |
乘 |
2 \times 3 = 6 |
$2 \times 3 = 6$ |
二乘三等於六 |
|
× |
2 × 3 = 6 |
$$2 × 3 = 6$$ |
||
|
* |
2 * 3 = 6 |
\(2 * 3 = 6\) |
||
|
\div |
除 |
6\div2=3 |
\[6\div2=3\] |
六除二等於三 |
|
÷ |
6÷2=3 |
$6÷2=3$ |
||
|
/ |
6/2=3 |
$6/2=3$ |
||
|
= |
等於 |
3+5=8 |
$3+5=8$ |
三加五等於八 |
|
< |
小於 |
1< 2 |
$1< 2$ |
一小於二 |
|
≤ |
小於等於 |
3≤5 |
$3≤5$ |
三小於等於五 |
|
<= |
3<=5 |
$3<=5$ |
||
|
\leq |
3\leq5 |
$3\leq 5$ |
||
|
\le |
3\le5 |
$3\le 5$ |
||
|
\leqq |
3\leqq5 |
$3\leqq 5$ |
||
|
\leqslant |
3\leqslant5 |
$3\leqslant 5$ |
||
|
> |
大於 |
2>1 |
$2>1$ |
二大於一 |
|
≥ |
大於等於 |
5≥3 |
$5≥3$ |
五大於等於三 |
|
>= |
5>=3 |
$5>=3$ |
||
|
\geq |
5\geq3 |
$5\geq 3$ |
||
|
\ge |
5\ge3 |
$5\ge 3$ |
||
|
\geqq |
5\geqq3 |
$5\geqq 3$ |
||
|
\geqslant |
5\geqslant3 |
$5\geqslant 3$ |
||
|
\frac |
分數 |
2\frac3 |
$\frac {2}{3}$ |
三分之二 |
|
^ |
次方 |
2^1 |
$2^{1}$ |
二的一次方 |
|
\sqrt |
開根 |
\sqrt{9} = 3 |
$\sqrt {9} = 3$ |
根號下九等於三 |
|
\sqrt[3]{8} = 2 |
$\sqrt[3]{8} = 2$ |
三次根號下八等於二 |
||
|
\% |
百分比 |
5\% |
$5\%$ |
百分之五 |
|
| |
絕對值 |
∣3∣=3 |
$|3| =3$ |
絕對值三的絕對值等於三 |
|
\vert |
3\vert=3 |
$\vert 3\vert =3$ |
絕對值三絕對值等於三 |
|
|
\lg |
對數 |
lg {10} |
$\lg {10}$ |
log十 |
|
\log |
對數 |
\log{5} |
$\log{5}$ |
log五 |
|
\ln |
自然對數 |
\lnX |
$ln {10}$ |
LN十 |
|
! |
階乘 |
5! |
$5!$ |
五的階乘 |
|
() |
括弧 |
(2+1) |
$(2+1)$ |
括弧內二加一 |
|
\{ \} |
$\{2+1\}$ |
大括弧二加一反大括弧 |
特殊數學符號
|
標籤或符號 |
轉換 |
公式內容樣本 |
待合成文本樣本 |
讀法 |
|
\alpha |
alpha |
\alpha |
$\alpha$ |
α
|
|
\Alpha |
\Alpha |
$\Alpha$ |
||
|
\beta |
beta |
\beta |
$\beta$ |
β
|
|
\Beta |
\Beta |
$\Beta$ |
||
|
\gamma |
gamma |
\gamma |
$\gamma$ |
γ
|
|
\Gamma |
\Gamma |
$\Gamma$ |
||
|
\delta |
delta |
\delta |
$\delta$ |
Δ
|
|
\Delta |
\Delta |
$\Delta$ |
||
|
\infty |
無窮大(中) |
\infty |
$\infty$ |
無窮大
|
|
∞ |
infty (英) |
∞ |
$∞$ |
幾何
|
標籤或符號 |
作用 |
公式內容樣本 |
公式輸入樣本 |
讀法 |
|
\pi |
派 |
\pi=3.14159 |
$\pi =3.14159$ |
派等於三點一四一五九 |
|
\sin (sine |
三角函數 |
\sin (sine30^\circ=1\frac2 |
$\sin 30^\circ =\frac {1}{2}$ |
sine三十度等於二分之一 |
|
\cos (cosine |
$\cos 30^\circ =\frac {\sqrt {2}}{2}$ |
cosine三十度等於二分之根號下二 |
||
|
\tan (tangent |
$\tan 30^\circ =\frac {\sin 30^\circ}{\cos 30^\circ}$ |
tangent三十度等於cosine三十度分之sine三十度 |
||
|
\csc (cosecant |
$\csc A$ |
cosecant A |
||
|
\sec (secant |
$\sec A$ |
secant A |
||
|
\cot (cotangent |
$\cot A$ |
cotangent A |
||
|
\angle |
角 |
\angle AB |
$\angle AB$ |
角A B |
|
∠ |
∠AB |
$∠AB$ |
||
|
^\circ |
度 |
∠AB = 30^\circ |
$∠AB = 30^\circ$ |
角A B 等於三十度 |
|
\odot |
圓 |
\odot |
$\odot$ |
圓 |
|
\overset\frown |
弧 |
\overset\frown {BC} |
$\overset\frown {BC}$ |
弧BC |
|
\rm{Rt} |
直角 |
\because \rm{Rt}\triangle ABC |
$\because \rm{Rt}\triangle ABC$ |
因為直角三角形ABC |
|
\mathrm{Rt} |
\therefore AB \perp BC |
$\therefore AB \perp BC$ |
所以AB垂直於BC |
|
|
\triangle |
三角形 |
\triangleABC |
$\triangle ABC$ |
三角形ABC |
|
△ |
△ABC |
$△ABC$ |
||
|
\parallelogram |
平行四邊形 |
\parallelogramABCD |
$\parallelogram ABCD$ |
平行四邊形ABCD |
|
\perp |
垂直 |
AB \perp BC |
$AB \perp BC$ |
A B 垂直於 B C |
|
\bot |
AB \bot BC |
$AB \bot BC$ |
||
|
⊥ |
AB ⊥ BC |
$AB ⊥ BC$ |
||
|
\parallel |
平行 |
A\parallel B |
$A\parallel B$ |
A平行於B |
|
\equalparallel |
平行且相等於 |
A\equalparallel B |
$A\equalparallel B$ |
A平行且相等於B |
|
\cong |
全等 |
△ABC\cong△DEF |
$△ABC\cong△DEF$ |
三角形ABC全等於三角形DEF |
條件
|
標籤或符號 |
作用 |
公式內容樣本 |
公式輸入樣本 |
讀法 |
|
\implies |
推出 |
\implies 1+1=2 |
$\implies 1+1=2$ |
推出一加一等於二 |
|
\iff |
等價 |
p\iffq |
$p\iffq$ |
p等價q |
|
\because |
因為 |
\because a = b \therefore b=a |
$\because a = b \therefore b=a$ |
因為a等於b所以b等於a |
|
\therefore |
所以 |
單位
單位需要使用 \unit、\quantity、\mathit、\mathrm 或 \rm 標籤進行包裹。例如:\unit{cm}。
|
標籤或符號 |
讀法 |
公式內容樣本 |
公式輸入樣本 |
讀法 |
|
mm |
毫米 |
5\quantity{mm} |
$5\quantity{mm}$ |
五毫米 |
|
cm |
厘米 |
5\quantity{cm} |
$5\quantity{cm}$ |
五厘米 |
|
dm |
分米 |
5\quantity{dm} |
$5\quantity{dm}$ |
五分米 |
|
m |
米 |
5\quantity{m} |
$5\quantity{m}$ |
五米 |
|
km |
千米 |
5\quantity{km} |
$5\quantity{km}$ |
五千米 |
|
g |
克 |
5\quantity{g} |
$5\quantity{g}$ |
五克 |
|
kg |
千克 |
5\quantity{kg} |
$5\quantity{kg}$ |
五千克 |
|
t |
噸 |
5\quantity{t} |
$5\quantity{t}$ |
五噸 |
|
mm^2 |
平方毫米 |
5\quantity{mm^2} |
$5\quantity{mm^2}$ |
五平方毫米 |
|
cm^2 |
平方厘米 |
5\quantity{cm^2} |
$5\quantity{cm^2}$ |
五平方厘米 |
|
dm^2 |
平方分米 |
5\quantity{dm^2} |
$5\quantity{dm^2}$ |
五平方分米 |
|
m^2 |
平方米 |
5\quantity{m^2} |
$5\quantity{m^2}$ |
五平方米 |
|
km^2 |
平方千米 |
5\quantity{km^2} |
$5\quantity{km^2}$ |
五平方千米 |
|
mm^3 |
立方毫米 |
5\quantity{mm^3} |
$5\quantity{mm^3}$ |
五立方毫米 |
|
cm^3 |
立方厘米 |
5\quantity{cm^3} |
$5\quantity{cm^3}$ |
五立方厘米 |
|
dm^3 |
立方分米 |
5\quantity{dm^3} |
$5\quantity{dm^3}$ |
五立方分米 |
|
m^3 |
立方米 |
5\quantity{m^3} |
$5\quantity{m^3}$ |
五立方米 |
|
km^3 |
立方千米 |
5\quantity{km^3} |
$5\quantity{km^3}$ |
五立方千米 |
|
ml |
毫升 |
5\quantity{ml} |
$5\quantity{ml}$ |
五毫升 |
|
s |
秒 |
5\quantity{s} |
$5\quantity{s}$ |
五秒 |
|
min |
分鐘 |
5\quantity{min} |
$5\quantity{min}$ |
五分 |
|
h |
小時 |
5\quantity{h} |
$5\quantity{h}$ |
五小時 |
|
km/h |
千米每小時 |
5\quantity{km/h} |
$5\quantity{km/h}$ |
五千米每小時 |
|
g/l |
克每升 |
5\quantity{g/l} |
$5\quantity{g/l}$ |
五克每升 |
常見問題
公式沒有被正確朗讀,如何排查?
請依次檢查以下幾點:
-
確認分隔字元正確:公式是否已使用
$...$、$$...$$、\(...\)或\[...\]正確包裹。 -
確認公式內容:公式中是否包含當前不支援的標籤或符號。
-
確認轉義正確:通過 API 發送請求時,公式中的
\是否已正確轉義為\\。
如何在代碼中正確處理 LaTeX 方程式的反斜線?
在大多數程式設計語言(如 Python、Java、JavaScript)的字串和 JSON 資料中,反斜線 \ 是逸出字元。要表示一個實際的 \,需要使用 \\。例如,LaTeX 命令 \frac 在代碼中應寫作 \\frac。