HTML 版本
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文本转语音并播放</title>
</head>
<body>
<h1>文本转语音并播放</h1>
<label for="textInput">请输入文本:</label><br>
<textarea id="textInput" rows="4" cols="50"></textarea><br><br>
<label for="filterChinese">只显示中文语音?</label>
<input type="checkbox" id="filterChinese" checked><br><br>
<label for="voiceSelect">选择语音(音色):</label>
<select id="voiceSelect"></select><br><br>
<button id="startButton">开始朗读</button>
<button id="stopButton">停止朗读</button>
<script>
// 获取可用的语音并填充选择框
function populateVoiceList() {
const voices = speechSynthesis.getVoices();
const voiceSelect = document.getElementById('voiceSelect');
const filterChinese = document.getElementById('filterChinese').checked;
voiceSelect.innerHTML = ''; // 清空现有选项
// 支持所有语音(更多音色),或可选过滤中文
let filteredVoices = voices;
if (filterChinese) {
filteredVoices = voices.filter(voice => voice.lang.startsWith('zh-')); // 支持 zh-CN, zh-TW 等
}
console.log('可用语音列表:', filteredVoices); // 调试:打印到控制台
if (filteredVoices.length === 0) {
// 如果没有语音,显示提示
const option = document.createElement('option');
option.textContent = '无可用语音(请安装TTS引擎)';
option.disabled = true;
voiceSelect.appendChild(option);
alert('未检测到任何可用语音。请确保系统已安装TTS语音包,并在浏览器中刷新页面。');
return;
}
// 将语音填充到下拉框
filteredVoices.forEach((voice) => {
const option = document.createElement('option');
option.value = voice.name;
option.textContent = `${voice.name} (${voice.lang})`; // 显示名称和语言,便于选择
voiceSelect.appendChild(option);
});
}
// 创建朗读函数
function speak(text, selectedVoice) {
const utterance = new SpeechSynthesisUtterance(text);
utterance.voice = selectedVoice; // 设置选择的音色
utterance.lang = selectedVoice ? selectedVoice.lang : 'zh-CN'; // 自动匹配语言
// 启动语音合成
speechSynthesis.speak(utterance);
}
// 执行朗读
document.getElementById('startButton').addEventListener('click', () => {
const textInput = document.getElementById('textInput').value.trim();
const selectedVoiceName = document.getElementById('voiceSelect').value;
const voices = speechSynthesis.getVoices();
const selectedVoice = voices.find(voice => voice.name === selectedVoiceName);
if (!textInput) {
alert('请输入文本');
return;
}
if (!selectedVoice) {
alert('请选择一个有效语音');
return;
}
speak(textInput, selectedVoice);
});
// 停止朗读
document.getElementById('stopButton').addEventListener('click', () => {
speechSynthesis.cancel(); // 停止当前语音播放
});
// 复选框变化时重新填充语音列表
document.getElementById('filterChinese').addEventListener('change', populateVoiceList);
// 初始化并填充可用的语音列表
populateVoiceList();
// 在语音列表加载完后,重新填充语音选择框
if (speechSynthesis.onvoiceschanged !== undefined) {
speechSynthesis.onvoiceschanged = populateVoiceList;
}
</script>
</body>
</html>
python 批量生成
import pyttsx3
import os
import sys
def populate_voice_list():
engine = pyttsx3.init()
voices = engine.getProperty('voices')
# 过滤中文语音(假设语言代码包含 'zh')
chinese_voices = [voice for voice in voices if any('zh' in lang.lower() for lang in voice.languages)]
return engine, chinese_voices
def generate_audio_from_lines(engine, chinese_voices, text_file):
# 检查文本文件是否存在
if not os.path.exists(text_file):
print(f"文件 {text_file} 不存在。")
sys.exit(1)
# 逐行读取文本文件
with open(text_file, 'r', encoding='utf-8') as file:
lines = file.readlines()
if not lines:
print("文件中没有文本内容。")
sys.exit(1)
# 检查是否有中文语音
if not chinese_voices:
print("未找到中文语音。请确保系统已安装中文TTS语音引擎。")
sys.exit(1)
# 用户选择语音(只选择一次,用于所有行)
print("可用中文语音:")
for idx, voice in enumerate(chinese_voices):
print(f"{idx + 1}: {voice.name} (语言: {', '.join(voice.languages)})")
try:
voice_index = int(input("请输入选择的语音编号(用于所有行):")) - 1
if voice_index < 0 or voice_index >= len(chinese_voices):
raise ValueError
selected_voice = chinese_voices[voice_index]
except ValueError:
print("无效选择,使用默认语音。")
selected_voice = chinese_voices[0] # 默认使用第一个中文语音
# 设置所选语音
engine.setProperty('voice', selected_voice.id)
# 为每一行文本生成音频并保存到当前文件夹
for i, line in enumerate(lines):
text = line.strip()
if not text:
continue # 跳过空行
# 打印当前文本,便于调试
print(f"处理第 {i + 1} 行文本: {text}")
# 为每行文本生成一个唯一的音频文件名
output_file = os.path.join(os.getcwd(), f'speech_output_{i + 1}.wav')
try:
print(f"正在队列中添加第 {i + 1} 行音频...")
engine.save_to_file(text, output_file)
except Exception as e:
print(f"添加第 {i + 1} 行音频时出错: {e}")
continue
# 在循环外调用 runAndWait,处理所有队列
try:
print("开始处理所有音频队列...")
engine.runAndWait()
print("所有音频生成完成。")
except Exception as e:
print(f"处理音频队列时出错: {e}")
# 打印保存的文件(因为现在一次性生成,无法在循环中打印完成)
for i, line in enumerate(lines):
if line.strip():
output_file = os.path.join(os.getcwd(), f'speech_output_{i + 1}.wav')
print(f"音频已保存为 {output_file}")
def main():
# 指定文本文件路径
text_file = r"D:\test\1.txt"
# 获取可用的语音
engine, chinese_voices = populate_voice_list()
# 为每行文本生成音频
generate_audio_from_lines(engine, chinese_voices, text_file)
if __name__ == "__main__":
main()
Python edge-tts
import subprocess
import sys
import os
import asyncio
import random
import tempfile
# 安装 edge-tts 库
def install_edge_tts():
try:
subprocess.check_call([sys.executable, "-m", "pip", "install", "edge-tts"])
print("✅ edge-tts 安装成功!")
except subprocess.CalledProcessError as e:
print(f"❌ 安装 edge-tts 失败: {e}")
# 检查是否已安装 edge-tts
try:
import edge_tts
except ImportError:
print("edge-tts 未安装,正在安装...")
install_edge_tts()
else:
print("edge-tts 已安装。")
from edge_tts import list_voices, Communicate # Explicit imports for reliability
# Function to list Chinese voices
async def list_chinese_voices():
voices = await list_voices()
chinese_voices = [voice for voice in voices if 'zh' in voice['Locale'].lower()]
chinese_voices.sort(key=lambda v: v['ShortName']) # Optional: sort for consistency
return chinese_voices
# Function to convert text to speech with a random voice
async def text_to_speech_with_random_voice(text, chinese_voices, file_path, line_number):
if not text.strip():
return None, "Please enter text to convert."
# Select a random voice
random_voice = random.choice(chinese_voices)
voice_short_name = random_voice['ShortName']
rate_str = "+0%" # Default rate, can be adjusted as needed
pitch_str = "+0Hz" # Default pitch, can be adjusted as needed
communicate = Communicate(text, voice_short_name, rate=rate_str, pitch=pitch_str)
# Get the directory where the txt file is located
directory = os.path.dirname(file_path)
# Save speech to MP3 file with the voice short name appended to the filename
output_filename = f"line_{line_number}_{voice_short_name}.mp3"
output_path = os.path.join(directory, output_filename)
await communicate.save(output_path)
return output_path, None
# Function to process the text file and generate audio for each line
async def process_text_file(file_path, chinese_voices):
if not os.path.exists(file_path):
print(f"File '{file_path}' does not exist.")
return
with open(file_path, 'r', encoding='utf-8') as file:
lines = file.readlines()
for i, line in enumerate(lines, start=1):
line = line.strip() # Remove leading/trailing spaces
if line:
audio_path, warning = await text_to_speech_with_random_voice(line, chinese_voices, file_path, i)
if warning:
print(f"Warning for line {i}: {warning}")
else:
print(f"Audio for line {i} saved at: {audio_path}")
else:
print(f"Line {i} is empty, skipping...")
# Main function to generate audio from a text file
async def main():
# Specify the path to the text file
file_path = r'd:\51.txt' # Change this to your file path
# List Chinese voices
chinese_voices = await list_chinese_voices()
if not chinese_voices:
print("No Chinese voices available.")
return
# Process the text file and generate audio
await process_text_file(file_path, chinese_voices)
# Run the main function
if __name__ == "__main__":
asyncio.run(main())
❤️ 转载文章请注明出处,谢谢!❤️