#!/usr/bin/python3 # -*- coding: utf-8 -*- import argparse import asyncio from functools import partial import json import logging from pathlib import Path import platform from typing import List import uuid from project_settings import project_path, log_directory, temp_directory, edge_tts_temp_directory import log log.setup(log_directory=log_directory) import aiofiles import anyio import edge_tts import gradio as gr import librosa from scipy.io import wavfile import spacy from toolbox.os.command import Command main_logger = logging.getLogger("main") def get_args(): parser = argparse.ArgumentParser() parser.add_argument( "--example_wav_dir", default=(project_path / "data/examples").as_posix(), type=str ) args = parser.parse_args() return args async def edge_tts_get_speakers() -> List[str]: edge_tts_speakers_choices = list() voices = await edge_tts.list_voices() for voice in voices: short_name = voice["ShortName"] edge_tts_speakers_choices.append(short_name) return edge_tts_speakers_choices async def edge_tts_text_to_speech(text: str, speaker: str, audio_dir: Path = edge_tts_temp_directory): # tts main_logger.info(f"edge tts; speaker: {speaker}; text: {text}") communicate = edge_tts.Communicate(text, speaker) # save audio audio_dir.mkdir(parents=True, exist_ok=True) audio_file = audio_dir / "{}.wav".format(uuid.uuid4()) audio_file = audio_file.as_posix() record_file = audio_dir / "edge_tts.jsonl" try: await communicate.save(audio_file) except edge_tts.exceptions.NoAudioReceived: audio_file = None # save record async with aiofiles.open(record_file.as_posix(), "a+", encoding="utf-8") as f: row = json.dumps({ "text": text, "speaker": speaker, "filename": audio_file, }, ensure_ascii=False) await f.write("{}\n".format(row)) return audio_file spacy_model = spacy.load("zh_core_web_sm") async def e_book_reading(txt_file: str, speaker: str): txt_file = Path(txt_file) audio_dir = temp_directory / "e_book_reading" / txt_file.stem / speaker while True: async with aiofiles.open(txt_file.as_posix(), "r", encoding="utf-8") as f: data = await f.read() doc = spacy_model(data) for sentence in doc.sents: text = sentence.text.strip() if len(text) == 0: continue filename = await edge_tts_text_to_speech(text=text, speaker=speaker, audio_dir=audio_dir) # sample_rate, signal = wavfile.read(filename) signal, sample_rate = librosa.load(filename) duration = len(signal) / sample_rate yield filename await asyncio.sleep(duration) def shell(cmd: str): return Command.popen(cmd) def main(): args = get_args() title = "## 电子书阅读." loop = asyncio.get_event_loop() edge_tts_speakers_choices = loop.run_until_complete(edge_tts_get_speakers()) # blocks with gr.Blocks() as blocks: gr.Markdown(value=title) with gr.Tabs(): with gr.TabItem("Edge TTS"): edge_tts_text = gr.Textbox(value="学而时习之,不亦悦乎。", lines=4, max_lines=50, label="text") edge_tts_speaker = gr.Dropdown(choices=edge_tts_speakers_choices, value="zh-CN-XiaoxiaoNeural", label="speakers") edge_tts_audio = gr.Audio(type="filepath", label="audio", autoplay=True) edge_tts_button = gr.Button(value="edge_tts", variant="primary") edge_tts_button.click( edge_tts_text_to_speech, inputs=[ edge_tts_text, edge_tts_speaker, ], outputs=[ edge_tts_audio ], ) with gr.TabItem("Ebook Reading"): e_book_reading_file = gr.File( value=(project_path / "data/e_book/confucianism/the_analects/the_analects.txt").as_posix(), label="txt" ) e_book_reading_speaker = gr.Dropdown(choices=edge_tts_speakers_choices, value="zh-CN-XiaoxiaoNeural", label="speakers") e_book_reading_audio = gr.Audio(type="filepath", label="audio", streaming=True) e_book_reading_button = gr.Button(value="e_book_reading", variant="primary") e_book_reading_button.click( e_book_reading, inputs=[ e_book_reading_file, e_book_reading_speaker, ], outputs=[ e_book_reading_audio ], ) with gr.TabItem("shell"): shell_text = gr.Textbox(label="cmd") shell_button = gr.Button("run") shell_output = gr.Textbox(label="output") shell_button.click( shell, inputs=[ shell_text, ], outputs=[ shell_output ], ) launch = partial( blocks.queue().launch, share=False if platform.system() == "Windows" else False, server_name="127.0.0.1" if platform.system() == "Windows" else "0.0.0.0", server_port=7860, ) anyio.run( launch, backend="asyncio" ) return if __name__ == "__main__": main()