接口更新:支持直接返回srt字幕内容,详见文档!2025.12.29
欢迎使用我们的微软TTS API服务。本文档旨在帮助开发者快速理解和集成我们的文本转语音接口。请在开始前仔细阅读,特别是关于认证授权的部分。
准备工作 (Prerequisites)
在调用任何接口之前,您需要准备好您在本站的用户名和密码。请注意,请勿使用注册邮箱作为user参数,应使用您的用户名。
核心概念:认证与授权
为了保障接口安全,我们所有的请求都需要进行签名和加密验证。
-
时间戳 (Timestamp):所有接口都需要一个13位的毫秒级时间戳,参数名为 ts。
-
签名 (Sign):部分接口需要对请求进行签名,签名算法为 md5(username + ts)。
-
授权头 (Authorization Header):queryorder 和 mstts 接口需要在HTTP请求头中加入 Authorization 字段。该字段的值是通过 AES 加密生成
-
模式:ECB
-
填充:PKCS7
-
密钥 (Key):一个16位的自定义字符串,在首次获取token时生成或指定。
-
待加密数据:一个包含user, token, ts的JSON字符串。
-
API 接口详解
基础URL (Base URL):
1. 获取Token (/gettoken)
此接口用于获取后续接口调用所需的 token 和 key。
接口地址:/gettoken
请求方法:POST
请求参数 (data):
-
user (string): 您的网站用户名。
-
psw (string): 您的网站密码。
-
type (integer): 操作类型。0表示获取token,1表示更新key和token。
-
key (string, optional): 16位自定义密钥。如果留空,系统将为您随机生成一个(建议自动生成,更安全)。
-
ts (string): 13位时间戳。
-
sign (string): 签名,计算方式为 md5(user + ts)。
返回数据示例:
{ "code": 0, "maxChar": 20000000, "date": "2024-12-31", "charNum": 3015, "key": "your_16_bit_key", "token": "your_generated_token", "msg": "success" }
2. 查询套餐信息 (/queryorder)
查询您当前账户的字符套餐余量和到期时间。
-
接口地址:/queryorder
-
请求方法:POST
-
请求头 (Headers):Authorization: 经过AES加密后的授权字符串。
-
请求参数 (data):user (string): 您的网站用户名。ts (string): 13位时间戳。sign (string): 签名,计算方式为 md5(user + ts)。
-
返回数据示例:
{ "code": 0, "maxChar": 20000000, "date": "2024-12-31", "charNum": 3015, "msg": "success" }
3. 微软TTS语音合成 (/mstts)
核心接口,用于将SSML文本合成为语音。
-
接口地址:/mstts
-
请求方法:POST
-
请求头 (Headers):Authorization: 经过AES加密后的授权字符串。
-
请求参数 (PostData, JSON格式):
-
user (string): 您的网站用户名。
-
srt(boolean):是否返回经 Base64编码 的 srt字幕 内容
-
quality(string):合成音频音质选项,因涉及服务器流量问题暂未开放,默认音频格式质量:audio-24khz-48kbitrate-mono-mp3,此参数留空即可,后续开放等待通知
-
ssml (string): 经过 Base64编码 的 SSML文本。注意:单次请求的原文长度不能超过2000字符。
-
ts (string): 13位时间戳。
-
sign (string): 签名,计算方式为 md5(user + ts)。
-
-
返回数据示例:
{ "code": 0, "msg": "success", "srt": "...",(base64编码的srt字幕内容数据)" "base64audio": "UklGRiQ... (base64编码的mp3音频数据)", "charNum": 3515, "maxChar": 20000000 }
您只需将 base64audio 字段的内容进行Base64解码,即可得到mp3音频文件,将srt 字段内容进行Base64解码,即可得到srt字幕文本内容(请求参数srt为false时,srt内容为空)。
重要注意事项
-
启用重定向:所有接口请求都必须启用HTTP重定向(allow_redirects=True)。
-
并发限制:接口限制最高并发为 3次/秒。超过此限制服务器将触发10分钟限制访问,返回 429 状态码,若一直开启无限制并发,将作封号处理。
-
SSML文档:关于如何编写SSML以控制语音情感、停顿、多角色发音等高级功能,请参考 。
API 快速测试工具
为了方便您在编码前快速验证接口的有效性,我们提供了API测试工具。您可以在页面顶部免费下载。
-
获取token:/gettoken

-
套餐查询: /queryOrder

-
微软TTS语音合成:/mstts

Python API 调用完整示例代码
以下是一个完整的Python示例,演示了从获取Token到最终合成语音的全过程。您需要安装 requests 和 pycryptodome 库。
""" MSTTS API 接口调用示例 支持 gettoken、queryorder、mstts 三个接口 """ import requests import hashlib import time import base64 import json from Crypto.Cipher import AES from Crypto.Util.Padding import pad # =============== 配置区域 =============== API_BASE_URL = "http://47.96.88.233:2048/" USERNAME = "" # 填写用户名 PASSWORD = "" # 填写密码 # ======================================== def md5(text: str) -> str: """计算MD5哈希""" return hashlib.md5(text.encode()).hexdigest() def aes_encrypt(text: str, key: str) -> str: """AES-128-ECB 加密""" cipher = AES.new(key.encode('utf-8'), AES.MODE_ECB) padded = pad(text.encode('utf-8'), AES.block_size) encrypted = cipher.encrypt(padded) return base64.b64encode(encrypted).decode('utf-8') class MSTTSClient: def __init__(self, base_url: str, username: str, password: str): self.base_url = base_url.rstrip('/') self.username = username self.password = password self.token = None self.key = None def get_token(self, force_new: bool = False) -> dict: """ 获取Token :param force_new: 是否强制生成新token :return: API响应 """ ts = str(int(time.time())) sign = md5(f"{self.username}{ts}") data = { "user": self.username, "psw": self.password, "type": "1" if force_new else "0", "key": "", # 留空让服务端生成 "ts": ts, "sign": sign } response = requests.post(f"{self.base_url}/gettoken", json=data,allow_redirects=True) response = requests.post(response.url, json=data) result = response.json() if result.get("code") == 0: self.token = result.get("token") self.key = result.get("key") print(f"[gettoken] 成功! 额度: {result.get('charNum')}/{result.get('maxChar')}, 到期: {result.get('date')}") else: print(f"[gettoken] 失败: {result.get('msg')}") return result def _get_authorization(self) -> str: """生成Authorization头""" if not self.token or not self.key: raise ValueError("请先调用 get_token() 获取token") auth_data = json.dumps({ "user": self.username, "token": self.token }) return aes_encrypt(auth_data, self.key) def query_order(self) -> dict: """ 查询订单/额度信息 :return: API响应 """ if not self.key: raise ValueError("请先调用 get_token() 获取token") ts = str(int(time.time())) sign = md5(f"{self.username}{ts}") headers = { "Authorization": self._get_authorization() } data = { "user": self.username, "ts": ts, "sign": sign } response = requests.post(f"{self.base_url}/queryorder", headers=headers,allow_redirects=True) response = requests.post(response.url, headers=headers,json=data) result = response.json() if result.get("code") == 0: print(f"[queryorder] 成功! 额度: {result.get('charNum')}/{result.get('maxChar')}, 到期: {result.get('date')}") else: print(f"[queryorder] 失败: {result.get('msg')}") return result def synthesize(self, ssml: str, srt: bool = False,quality: str = "audio-24khz-48kbitrate-mono-mp3") -> dict: """ 文字转语音合成 :param text: 要合成的ssml :return: API响应,包含base64音频和srt字幕 """ if not self.key: raise ValueError("请先调用 get_token() 获取token") # 构建SSML ts = str(int(time.time())) sign = md5(f"{self.username}{ts}") headers = { "Authorization": self._get_authorization() } data = { "user": self.username, "srt" : srt, "quality": quality, #audio-24khz-48kbitrate-mono-mp3 暂未开放,参数留空即可 "ssml": base64.b64encode(ssml.encode('utf-8')).decode('utf-8'), "ts": ts, "sign": sign } response = requests.post(f"{self.base_url}/mstts", json=data, headers=headers,allow_redirects=True) response = requests.post(response.url, headers=headers,json=data) result = response.json() if result.get("code") == 0: print(f"[mstts] 合成成功! 已用: {result.get('charNum')}/{result.get('maxChar')}") # 保存音频 audio_data = base64.b64decode(result.get("base64audio", "")) if audio_data: with open("output.mp3", "wb") as f: f.write(audio_data) print(f"[mstts] 音频已保存: output.mp3 ({len(audio_data)} bytes)") # 保存字幕 srt_base64 = result.get("srt", "") if srt_base64: srt_data = base64.b64decode(srt_base64).decode('utf-8') with open("output.srt", "w", encoding="utf-8") as f: f.write(srt_data) print(f"[mstts] 字幕已保存: output.srt") else: print(f"[mstts] 合成失败: {result.get('msg')}") return result # =============== 使用示例 =============== if __name__ == "__main__": # 检查配置 if not USERNAME or not PASSWORD: print("请先在配置区域填写用户名和密码!") exit(1) # 创建客户端 client = MSTTSClient(API_BASE_URL, USERNAME, PASSWORD) # 1. 获取Token print("\n=== 步骤1: 获取Token ===") token_result = client.get_token() if token_result.get("code") != 0: print("获取Token失败,请检查用户名密码") exit(1) # 2. 查询订单信息 print("\n=== 步骤2: 查询订单 ===") client.query_order() # 3. 文字转语音 print("\n=== 步骤3: 文字转语音 ===") ssml = '''<speak xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xmlns:emo="http://www.w3.org/2009/10/emotionml" version="1.0" xml:lang="en-US"><voice name="en-US-AriaNeural"><mstts:express-as style="Cheerful">"That’s remarkable! You’re a genius!"</mstts:express-as>Mom said to her son.</voice><voice name="en-US-JennyNeural">Customize output by <prosody rate="-40.00%"> slowing-down the speed rate.</prosody></voice><voice name="en-US-GuyNeural">Add a break <break time="600ms" /> between words.</voice><voice name="en-GB-SoniaNeural">You can pronounce it <say-as interpret-as="spell">ASAP </say-as>or <sub alias="as soon as possible">ASAP</sub>.</voice><voice name="zh-CN-XiaoxiaoNeural"><s /><mstts:express-as style="chat">可以通过停顿里的高级功能“No break”,解决<phoneme alphabet="sapi" ph="fen 1 ci 2">分词</phoneme>引起的多余停顿问题。</mstts:express-as><s /><mstts:express-as style="chat">也可以合成多角色多情感的有声<prosody contour="(49%, -40%)">书</prosody>,例如:</mstts:express-as></voice><voice name="zh-CN-YunyeNeural">黛玉冷笑道:</voice><voice name="zh-CN-XiaoxiaoNeural"><s /><mstts:express-as style="disgruntled">“我说呢,亏了绊住,不然,早就飞了来了。”</mstts:express-as><s /> </voice><voice name="zh-CN-YunyeNeural">宝玉道:</voice><voice name="zh-CN-YunxiNeural">“只许和你玩,替你解闷。不过偶然到他那里,就说这些闲话。”</voice><voice name="zh-CN-XiaoxiaoNeural"><mstts:express-as style="angry">”好没意思的话!去不去,关我什么事儿?又没叫你替我解闷儿,还许你<mstts:ttsbreak strength="none" />从此<prosody contour="(24%, +49%) (59%, -2%)">不</prosody><prosody rate="-15.00%" contour="(24%, +49%) (59%, -2%)">理</prosody><prosody contour="(24%, +49%) (59%, -2%)">我呢</prosody>!”</mstts:express-as></voice><voice name="zh-CN-YunyeNeural"><s />说着,便赌气回房去了。</voice></speak>''' client.synthesize( ssml=ssml, srt=True, quality="" #音质选项,暂未开放,参数留空即可 ) print("\n=== 完成 ===")

评论(0)