百度TTS語音
個(gè)人嘗試代碼倉庫:https://gitee.com/enzoism/chrome_tampermonkey
鳴謝:感謝每一位無私奉獻(xiàn)的傳道者,在此不一一具名!
1-學(xué)習(xí)目標(biāo)
- 1)了解百度TTS語音
- 2)使用百度TTS語音
2-參考網(wǎng)址
- 個(gè)人嘗試代碼倉庫:https://gitee.com/enzoism/chrome_tampermonkey
1-應(yīng)用列表查看地址:https://console.bce.baidu.com/ai/#/ai/speech/app/list
2-AccessToken接口文檔:https://ai.baidu.com/ai-doc/REFERENCE/Ck3dwjhhu
3-音頻實(shí)時(shí)接口文檔:https://cloud.baidu.com/doc/SPEECH/s/Klbxern8v
4-短語音識別API文檔:https://cloud.baidu.com/doc/SPEECH/s/Jlbxdezuf
3-執(zhí)行過程記錄
1-TTS市場現(xiàn)狀
2024-12-01 目前應(yīng)該是ChatTTS的呼聲最高,但是為了不引入新的學(xué)習(xí)成本,暫時(shí)不考慮使用ChatTTS,直接使用在線API可以滿足我的需求?。ò俣鹊腡TS有太多的AI味,在這個(gè)時(shí)間節(jié)點(diǎn)上,百度可能還是沒有把重心放在這些細(xì)節(jié)上)
2-Tampermonkey
已經(jīng)完成整體的功能,可以直接復(fù)制當(dāng)前腳本到Tampermonkey,選中文字即可進(jìn)行語音播報(bào)
// ==UserScript==
// @name Text to Speech using Baidu API
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Convert selected text to speech using Baidu Text-to-Speech API
// @author Your name
// @match *://*/*
// @grant GM_xmlhttpRequest
// @grant GM_setValue
// @grant GM_getValue
// ==/UserScript==
(function() {
'use strict';
// 配置信息 - 需要替換成你的百度API密鑰信息
const API_KEY = '44kNzmCeZNnLHoUcNiGYnyI7';
const SECRET_KEY = '7sNV1osooTqJliQB1aHB5lJKEKlLrg5f';
let access_token = '';
// 獲取access_token的函數(shù)
async function getAccessToken() {
const url = `https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=${API_KEY}&client_secret=${SECRET_KEY}`;
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: 'POST',
url: url,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
onload: function(response) {
if (response.status === 200) {
try {
const data = JSON.parse(response.responseText);
if (data.access_token) {
access_token = data.access_token;
GM_setValue('access_token', access_token);
resolve(access_token);
} else {
console.error('獲取access_token失敗: 返回?cái)?shù)據(jù)格式錯(cuò)誤', data);
reject(new Error('獲取access_token失敗: 返回?cái)?shù)據(jù)格式錯(cuò)誤'));
}
} catch (error) {
console.error('解析access_token響應(yīng)失敗:', error);
reject(error);
}
} else {
console.error('獲取access_token失敗:', response.status, response.responseText);
reject(new Error(`獲取access_token失敗: ${response.status}`));
}
},
onerror: function(error) {
console.error('請求access_token失敗:', error);
reject(error);
}
});
});
}
// 文字轉(zhuǎn)語音的函數(shù)
async function textToSpeech(text, params = {}) {
if (!access_token) {
access_token = GM_getValue('access_token') || await getAccessToken();
}
if (!access_token) {
alert('無法獲取access_token,請檢查API配置');
return;
}
const url = `https://tsn.baidu.com/text2audio`;
const requestParams = new URLSearchParams({
tex: encodeURIComponent(text),
tok: access_token,
cuid: 'tampermonkey_tts',
ctp: 1,
lan: 'zh',
spd: params.spd || 5,
pit: params.pit || 5,
vol: params.vol || 5,
per: params.per || 0,
aue: 3
});
try {
GM_xmlhttpRequest({
method: 'GET',
url: `${url}?${requestParams.toString()}`,
responseType: 'blob',
onload: function(response) {
if (response.status === 200) {
const blob = response.response;
const audio = new Audio(URL.createObjectURL(blob));
audio.play().catch(error => {
console.error('播放音頻失敗:', error);
alert('播放音頻失敗,請重試');
});
} else {
console.error('語音合成請求失敗:', response.status);
alert('語音合成失敗,請重試');
}
},
onerror: function(error) {
console.error('請求失敗:', error);
alert('請求失敗,請重試');
}
});
} catch (error) {
console.error('語音合成出錯(cuò):', error);
alert('語音合成出錯(cuò),請重試');
}
}
// 創(chuàng)建控制面板
function createControlPanel() {
const panel = document.createElement('div');
panel.style.position = 'fixed';
panel.style.bottom = '80px';
panel.style.right = '20px';
panel.style.zIndex = '9999';
panel.style.backgroundColor = 'white';
panel.style.padding = '10px';
panel.style.border = '1px solid #ccc';
panel.style.borderRadius = '5px';
panel.style.display = 'none';
// 語速控制
const speedControl = document.createElement('div');
speedControl.innerHTML = `
<label>語速(0-15):
<input type="range" min="0" max="15" value="5" id="tts-speed">
<span id="speed-value">5</span>
</label>
`;
// 音量控制
const volumeControl = document.createElement('div');
volumeControl.innerHTML = `
<label>音量(0-15):
<input type="range" min="0" max="15" value="5" id="tts-volume">
<span id="volume-value">5</span>
</label>
`;
// 音調(diào)控制
const pitchControl = document.createElement('div');
pitchControl.innerHTML = `
<label>音調(diào)(0-15):
<input type="range" min="0" max="15" value="5" id="tts-pitch">
<span id="pitch-value">5</span>
</label>
`;
// 發(fā)音人選擇
const personControl = document.createElement('div');
personControl.innerHTML = `
<label>發(fā)音人:
<select id="tts-person">
<option value="0">女聲</option>
<option value="1">男聲</option>
<option value="3">度逍遙</option>
<option value="4">度丫丫</option>
</select>
</label>
`;
panel.appendChild(speedControl);
panel.appendChild(volumeControl);
panel.appendChild(pitchControl);
panel.appendChild(personControl);
// 添加事件監(jiān)聽
['speed', 'volume', 'pitch'].forEach(param => {
const input = panel.querySelector(`#tts-${param}`);
const value = panel.querySelector(`#${param}-value`);
input.addEventListener('input', () => {
value.textContent = input.value;
GM_setValue(`tts-${param}`, input.value);
});
});
panel.querySelector('#tts-person').addEventListener('change', (e) => {
GM_setValue('tts-person', e.target.value);
});
document.body.appendChild(panel);
return panel;
}
// 創(chuàng)建懸浮按鈕
function createFloatingButton() {
const button = document.createElement('button');
button.innerHTML = '朗讀選中文本';
button.style.position = 'fixed';
button.style.bottom = '20px';
button.style.right = '20px';
button.style.zIndex = '9999';
button.style.padding = '10px';
button.style.backgroundColor = '#4CAF50';
button.style.color = 'white';
button.style.border = 'none';
button.style.borderRadius = '5px';
button.style.cursor = 'pointer';
const settingsButton = document.createElement('button');
settingsButton.innerHTML = '??';
settingsButton.style.position = 'fixed';
settingsButton.style.bottom = '20px';
settingsButton.style.right = '140px';
settingsButton.style.zIndex = '9999';
settingsButton.style.padding = '10px';
settingsButton.style.backgroundColor = '#2196F3';
settingsButton.style.color = 'white';
settingsButton.style.border = 'none';
settingsButton.style.borderRadius = '5px';
settingsButton.style.cursor = 'pointer';
const panel = createControlPanel();
settingsButton.addEventListener('click', function() {
panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
});
button.addEventListener('click', function() {
const selectedText = window.getSelection().toString().trim();
if (selectedText) {
const params = {
spd: parseInt(GM_getValue('tts-speed', 9)),
vol: parseInt(GM_getValue('tts-volume', 5)),
pit: parseInt(GM_getValue('tts-pitch', 5)),
per: parseInt(GM_getValue('tts-person', 0))
};
textToSpeech(selectedText, params);
} else {
alert('請先選擇要朗讀的文本');
}
});
document.body.appendChild(button);
document.body.appendChild(settingsButton);
}
// 初始化
createFloatingButton();
})();
3-Python版本
Python3.8.5版本可運(yùn)行
import requests
import json
import base64
from urllib.parse import quote
import os
from playsound import playsound
class BaiduTTS:
def __init__(self):
# API配置信息
self.API_KEY = '44kNzmCeZNnLHoUcNiGYnyI7'
self.SECRET_KEY = '7sNV1osooTqJliQB1aHB5lJKEKlLrg5f'
self.access_token = None
def get_access_token(self):
"""獲取access_token"""
url = f"https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={self.API_KEY}&client_secret={self.SECRET_KEY}"
response = requests.post(url)
if response.status_code == 200:
result = response.json()
self.access_token = result['access_token']
return self.access_token
else:
print(f"獲取access_token失敗: {response.status_code}")
return None
def text_to_speech(self, text, params=None):
"""文字轉(zhuǎn)語音"""
if not self.access_token:
self.access_token = self.get_access_token()
if not self.access_token:
print("無法獲取access_token")
return False
# 默認(rèn)參數(shù)
default_params = {
'spd': 9, # 語速,取值0-15
'pit': 5, # 音調(diào),取值0-15
'vol': 5, # 音量,取值0-15
'per': 0, # 發(fā)音人,0為女聲,1為男聲,3為度逍遙,4為度丫丫
}
# 更新參數(shù)
if params:
default_params.update(params)
url = "https://tsn.baidu.com/text2audio"
params = {
'tex': quote(text),
'tok': self.access_token,
'cuid': 'python_tts',
'ctp': 1,
'lan': 'zh',
'aue': 3, # mp3格式
**default_params
}
try:
response = requests.get(url, params=params)
# 檢查是否返回音頻數(shù)據(jù)
if response.headers['Content-Type'].startswith('audio/'):
# 保存音頻文件
audio_file = "output.mp3"
with open(audio_file, 'wb') as f:
f.write(response.content)
print(f"已保存音頻文件: {audio_file}")
# 播放音頻
playsound(audio_file)
return True
else:
error_msg = response.json()
print(f"轉(zhuǎn)換失敗: {error_msg}")
return False
except Exception as e:
print(f"請求失敗: {str(e)}")
return False
def main():
# 使用示例
tts = BaiduTTS()
# 要轉(zhuǎn)換的文本
text = input("請輸入要轉(zhuǎn)換的文字: ")
# 可選:自定義參數(shù)
params = {
'spd': 9, # 語速
'pit': 5, # 音調(diào)
'vol': 5, # 音量
'per': 0 # 發(fā)音人
}
# 執(zhí)行轉(zhuǎn)換
tts.text_to_speech(text, params)
if __name__ == "__main__":
main()
4-其他知識補(bǔ)充
1-TTS發(fā)展歷史
TTS(Text-to-Speech,文本轉(zhuǎn)語音)技術(shù)的發(fā)展歷史可以追溯到20世紀(jì)50年代,經(jīng)歷了多個(gè)階段的技術(shù)進(jìn)步和創(chuàng)新。以下是TTS技術(shù)發(fā)展的主要里程碑:
1. 早期研究(20世紀(jì)50年代至70年代)
- 早期嘗試:最早的TTS系統(tǒng)開始于20世紀(jì)50年代。研究人員嘗試通過機(jī)械設(shè)備和簡單的聲音合成器來生成語音。
- 基礎(chǔ)研究:在20世紀(jì)60年代和70年代,主要集中在語音合成的基本原理和方法上,如共振峰合成(Formant Synthesis),通過模擬人類聲道的共振特性來生成語音。
2. 數(shù)字信號處理時(shí)代(20世紀(jì)80年代至90年代)
- 數(shù)字信號處理技術(shù):隨著數(shù)字信號處理(DSP)技術(shù)的發(fā)展,TTS系統(tǒng)開始使用計(jì)算機(jī)來處理和生成語音。這種方法提高了語音合成的質(zhì)量和效率。
- 規(guī)則合成器:出現(xiàn)了基于規(guī)則的合成器,這些系統(tǒng)通過一系列規(guī)則將文本轉(zhuǎn)換為語音。例如,線性預(yù)測編碼(LPC)技術(shù)被廣泛應(yīng)用于語音合成。
- 有限狀態(tài)機(jī):有限狀態(tài)機(jī)(FSM)被用于文本分析和語音合成,這種方法簡化了復(fù)雜文本的處理。
3. 統(tǒng)計(jì)方法和數(shù)據(jù)驅(qū)動技術(shù)(21世紀(jì)初)
- 統(tǒng)計(jì)語音合成:2000年后,統(tǒng)計(jì)方法開始主導(dǎo)TTS技術(shù)的研究。這些方法依賴于大量的語音數(shù)據(jù)和文本數(shù)據(jù),通過機(jī)器學(xué)習(xí)算法來生成語音。梅爾頻率倒譜系數(shù)(MFCC)和隱馬爾可夫模型(HMM)等技術(shù)被廣泛應(yīng)用。
- 語音庫和TTS系統(tǒng):出現(xiàn)了基于語音庫的TTS系統(tǒng),這些系統(tǒng)使用預(yù)先錄制的語音片段來生成自然語音。例如,單元選擇合成(Unit Selection Synthesis)通過選擇和拼接預(yù)先錄制的語音單元來生成語音。
4. 深度學(xué)習(xí)和神經(jīng)網(wǎng)絡(luò)時(shí)代(2010年至今)
- 神經(jīng)網(wǎng)絡(luò)TTS:隨著深度學(xué)習(xí)技術(shù)的發(fā)展,神經(jīng)網(wǎng)絡(luò)在TTS中的應(yīng)用迅速增長。遞歸神經(jīng)網(wǎng)絡(luò)(RNN)、長短期記憶網(wǎng)絡(luò)(LSTM)和變分自編碼器(VAE)等技術(shù)被用于生成更加自然和流暢的語音。
- 端到端模型:出現(xiàn)了端到端TTS模型,這些模型直接從文本生成語音,簡化了處理流程。例如,WaveNet、Tacotron和Transformer等模型顯著提高了語音合成的質(zhì)量。
- 多語言和個(gè)性化TTS:現(xiàn)代TTS系統(tǒng)支持多語言和個(gè)性化語音合成。用戶可以選擇不同的語音風(fēng)格和角色,甚至可以定制自己的語音模型。
5. 當(dāng)前趨勢和未來展望
- 低資源語言支持:為了讓更多人受益于TTS技術(shù),研究人員正在開發(fā)低資源語言的TTS系統(tǒng),這些系統(tǒng)可以在數(shù)據(jù)有限的情況下仍然生成高質(zhì)量的語音。
- 實(shí)時(shí)TTS:隨著硬件和算法的進(jìn)步,實(shí)時(shí)TTS系統(tǒng)的性能不斷提升,使得語音合成的延遲大大降低。
- 多模態(tài)TTS:結(jié)合其他感知模態(tài)(如視覺和觸覺)的多模態(tài)TTS系統(tǒng)正在研究中,以提供更加豐富的用戶體驗(yàn)。
總的來說,TTS技術(shù)從早期的簡單合成發(fā)展到了現(xiàn)在的深度學(xué)習(xí)驅(qū)動的自然語音生成,不斷推動著人機(jī)交互和無障礙通信的發(fā)展。
2-TTS目前的發(fā)展
1-深度學(xué)習(xí)和神經(jīng)網(wǎng)絡(luò)時(shí)代(2010年至今)
- 神經(jīng)網(wǎng)絡(luò)TTS
- 技術(shù)應(yīng)用:RNN, LSTM, VAE
- 目標(biāo):自然流暢的語音
- 端到端模型
- 模型:WaveNet, Tacotron, Transformer
- 優(yōu)勢:簡化流程,提高質(zhì)量
- 多語言和個(gè)性化TTS
- 支持:多語言,個(gè)性化語音
- 功能:選擇語音風(fēng)格和角色,定制語音模型
2-當(dāng)前趨勢和未來展望
- 低資源語言支持
- 目標(biāo):數(shù)據(jù)有限下生成高質(zhì)量語音
- 實(shí)時(shí)TTS
- 進(jìn)展:硬件和算法進(jìn)步
- 結(jié)果:降低延遲
- 多模態(tài)TTS
- 方向:結(jié)合視覺和觸覺
- 目標(biāo):豐富用戶體驗(yàn)
