Git Product home page Git Product logo

tts's Introduction

微软tts音频下载解决方案

微软tts 使用 119 种语言和变体,超过 270 种神经语音来吸引全球观众。使用极具表现力和类似人类的声音将你的方案(如文本阅读器和支持语音的助手)变为现实。神经文本到语音转换功能支持若干种话语风格,包括聊天、新闻播报和客户服务,以及各种情感(如快乐和同情)。

官方的demo地址(目前仅有介绍不支持语音合成)

https://azure.microsoft.com/zh-cn/products/cognitive-services/text-to-speech/#overview

项目目的和声明

  • 本项目的目的是解决微软官方的网页版demo,不能直接下载转换后的MP3文件
  • 本项目仅用于学习交流禁止用于商业用途

目前azure的网页版demo已经关闭,python_cli_demo,作为替代方法本仓库简单实现了,通过edge大声朗读接口和microsoft语音合成试用接口,下载合成后MP3文件的python版本(见python_cli_demo文件夹

为了通俗易懂代码没有进行任何不必要的封装,tts.py 和tts2.py在均可独立运行。

如果需要成品软件强烈建议直接下载LokerL大佬编写的成品软件,https://github.com/LokerL/tts-vue/releases

使用方法

使用方法视频版本 https://www.bilibili.com/video/BV13S4y1D7u7

安装依赖

pip install -r requirements.txt

运行

python tts.py --input SSML.xml 
## 或者 
python tts2.py --input SSML.xml

在python_cli_demo目录下 使用python 运行tts.py,通过参数input传入SSML.xml文件的路径

或者可以通过传入output 传入希望保存的文件名

python tts.py --input SSML.xml --output 保存文件名 
# 或者
python tts2.py --input SSML.xml --output 保存文件名 

SSML.xml文件的示例如下

<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="zh-CN-XiaoxiaoNeural">
        <prosody rate="0%" pitch="0%">
        这个是 SSML 语音合成标记语言
        </prosody>
    </voice>
</speak>

接口说明

tts.py 使用edge大声朗读接口(下称edge接口)

接口地址 wss://speech.platform.bing.com/consumer/speech/synthesize/readaloud/edge/v1

tts2.py 使用microsoft语音合成试用接口(下称microsoft接口)

接口地址 https://southeastasia.api.speech.microsoft.com/accfreetrial/texttospeech/acc/v3.0-beta1/vcg/speak

稳定性 是否付费 是否支持说话风格 代码示例
edge接口 免费 tts.py
microsoft接口 免费 tts2.py
azure接口 付费 见官方文档

tts's People

Contributors

skygongque avatar snowman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tts's Issues

报错

Traceback (most recent call last):
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python37-32\lib\site-packages\websockets\legacy\protocol.py", line 944, in transfer_data
message = await self.read_message()
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python37-32\lib\site-packages\websockets\legacy\protocol.py", line 1013, in read_message
frame = await self.read_data_frame(max_size=self.max_size)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python37-32\lib\site-packages\websockets\legacy\protocol.py", line 1088, in read_data_frame
frame = await self.read_frame(max_size)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python37-32\lib\site-packages\websockets\legacy\protocol.py", line 1147, in read_frame
extensions=self.extensions,
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python37-32\lib\site-packages\websockets\legacy\framing.py", line 70, in read
data = await reader(2)
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python37-32\lib\asyncio\streams.py", line 677, in readexactly
raise IncompleteReadError(incomplete, n)
asyncio.streams.IncompleteReadError: 0 bytes read on a total of 2 expected bytes

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "tts.py", line 109, in
asyncio.get_event_loop().run_until_complete(mainSeq(SSML_text, output_path))
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python37-32\lib\asyncio\base_events.py", line 587, in run_until_complete
return future.result()
File "tts.py", line 99, in mainSeq
await transferMsTTSData(SSML_text, outputPath)
File "tts.py", line 78, in transferMsTTSData
response = await websocket.recv()
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python37-32\lib\site-packages\websockets\legacy\protocol.py", line 552, in recv
await self.ensure_open()
File "C:\Users\Administrator\AppData\Local\Programs\Python\Python37-32\lib\site-packages\websockets\legacy\protocol.py", line 920, in ensure_open
raise self.connection_closed_exc()
websockets.exceptions.ConnectionClosedError: no close frame received or sent

tampermonkey 脚本的注入点思考

需要的数据在 synthesizer 的 synthesisCompleted,而 synthesizer 是由 new SpeechSDK.SpeechSynthesizer 产生的实例

首先想到通过劫持 SpeechSynthesizer 的构造函数来替换 new 出来的对象

Object.defineProperty(SpeechSDK, 'SpeechSynthesizer', { get: function () {} })

失败,SpeechSDK.SpeechSynthesizer 本身是 defineProperty 设置的 unconfigurable 的 getter,所以没法用 defineProperty 替换掉(悲)

尝试再朝上一层,在 SpeechSDK 加载之前劫持 defineProperty,以便在设置 SpeechSDK.SpeechSynthesizer 的时候拿到这个属性的操纵权

Object.defineProperty = (() => {
        const defineProperty = Object.defineProperty.bind(Object)
        return (...args) => {
            if (args[1] === 'SpeechSynthesizer') {
              console.log(args)
            }
            return defineProperty(...args)
        }
})()

成功,拿到 SpeechSynthesizer 的 getter,getter 执行返回 SpeechSynthesizer 类,外面是 new 这个类来获得 synthesizer 实例
我们给它在里面直接实例化好,并且用 defineProperty 把 synthesisCompleted 预先设置成 setter,以便在外面对实例设置这个回调的时候,拿到它的参数

    Object.defineProperty = (() => {
        const defineProperty = Object.defineProperty.bind(Object)
        return (...args) => {
            if (args[1] === 'SpeechSynthesizer') args[2].get = (() => {
                // 获得 SpeechSynthesizer 类
                const SpeechSynthesizer = args[2].get()
                return () => {
                    // 构造虚假的构造函数,返回修改后的实例
                    return function (...args) {
                        // 实例化
                        const synthesizer = new SpeechSynthesizer(...args)
                        let synthesisCompleted;
                        // 在实例的 synthesisCompleted 被设置的时候注入
                        defineProperty(synthesizer, 'synthesisCompleted', {
                            configurable: true,
                            get: function () {
                                return synthesisCompleted;
                            },
                            set: function (func) {
                                const proxy = (...args) => {
                                    // 注入点,拿到 privAudioData
                                    console.log(args[1].privResult.privAudioData)
                                    return func(...args)
                                }
                                synthesisCompleted = proxy
                            }
                        })
                        return synthesizer
                    }
                }
            })()
            return defineProperty(...args)
        }
    })()

这样就能直接实现直接注入进 synthesisCompleted 函数了

A50530A0-4080-4EF0-B1A2-E02951B687A8

完整 tampermonkey 脚本:

// ==UserScript==
// @name         New Userscript
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        https://azure.microsoft.com/zh-cn/services/cognitive-services/text-to-speech/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=microsoft.com
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    // Your code here...
    Object.defineProperty = (() => {
        const defineProperty = Object.defineProperty.bind(Object)
        return (...args) => {
            if (args[1] === 'SpeechSynthesizer') args[2].get = (() => {
                const SpeechSynthesizer = args[2].get()
                return () => {
                    return function (...args) {
                        const synthesizer = new SpeechSynthesizer(...args)
                        let synthesisCompleted;
                        defineProperty(synthesizer, 'synthesisCompleted', {
                            configurable: true,
                            get: function () {
                                return synthesisCompleted;
                            },
                            set: function (func) {
                                const proxy = (...args) => {
                                    console.log(args[1].privResult.privAudioData)
                                    return func(...args)
                                }
                                synthesisCompleted = proxy
                            }
                        })
                        return synthesizer
                    }
                }
            })()
            return defineProperty(...args)
        }
    })()
})();

没有触发脚本

如图,地址匹配,但是没有触发脚本,脚本已经装了。

image

命令行模式下能否支持多语句转语音?

比如有一个文本文件,里面有一些句子,然后在命令行通过 --batch-file 之类的参数指定这个文件,将里面的句子按换行符分割,生成多个语音文件,每一行是一个语音文件。

server rejected WebSocket connection: HTTP 200

File "tts/python_cli_demo/tts.py", line 98, in mainSeq
await transferMsTTSData(SSML_text, outputPath)
File "tts/python_cli_demo/tts.py", line 57, in transferMsTTSData
async with websockets.connect(endpoint2) as websocket:
File "/opt/conda/lib/python3.8/site-packages/websockets/legacy/client.py", line 633, in aenter
return await self
File "/opt/conda/lib/python3.8/site-packages/websockets/legacy/client.py", line 650, in await_impl_timeout
return await asyncio.wait_for(self.await_impl(), self.open_timeout)
File "/opt/conda/lib/python3.8/asyncio/tasks.py", line 483, in wait_for
return fut.result()
File "/opt/conda/lib/python3.8/site-packages/websockets/legacy/client.py", line 658, in await_impl
await protocol.handshake(
File "/opt/conda/lib/python3.8/site-packages/websockets/legacy/client.py", line 328, in handshake
raise InvalidStatusCode(status_code, response_headers)
websockets.exceptions.InvalidStatusCode: server rejected WebSocket connection: HTTP 200

接口无法访问了,请问怎么处理呢

ssl错误。

ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1131)

[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)

[root@VM-0-4-centos tts]# python3 tts.py --input SSML.xml
EDAF7465E8A849E49A6CCC470278D035
Traceback (most recent call last):
  File "/data/tts/tts.py", line 119, in <module>
    asyncio.get_event_loop().run_until_complete(mainSeq(SSML_text, output_path))
  File "/usr/local/python3/lib/python3.10/asyncio/base_events.py", line 649, in run_until_complete
    return future.result()
  File "/data/tts/tts.py", line 109, in mainSeq
    await transferMsTTSData(SSML_text, outputPath)
  File "/data/tts/tts.py", line 57, in transferMsTTSData
    async with websockets.connect(endpoint2,extra_headers={
  File "/usr/local/python3/lib/python3.10/site-packages/websockets/legacy/client.py", line 633, in __aenter__
    return await self
  File "/usr/local/python3/lib/python3.10/site-packages/websockets/legacy/client.py", line 650, in __await_impl_timeout__
    return await asyncio.wait_for(self.__await_impl__(), self.open_timeout)
  File "/usr/local/python3/lib/python3.10/asyncio/tasks.py", line 445, in wait_for
    return fut.result()
  File "/usr/local/python3/lib/python3.10/site-packages/websockets/legacy/client.py", line 654, in __await_impl__
    transport, protocol = await self._create_connection()
  File "/usr/local/python3/lib/python3.10/asyncio/base_events.py", line 1103, in create_connection
    transport, protocol = await self._create_connection_transport(
  File "/usr/local/python3/lib/python3.10/asyncio/base_events.py", line 1133, in _create_connection_transport
    await waiter
  File "/usr/local/python3/lib/python3.10/asyncio/sslproto.py", line 534, in data_received
    ssldata, appdata = self._sslpipe.feed_ssldata(data)
  File "/usr/local/python3/lib/python3.10/asyncio/sslproto.py", line 188, in feed_ssldata
    self._sslobj.do_handshake()
  File "/usr/local/python3/lib/python3.10/ssl.py", line 975, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)

关于ttsAudioFormat

咨询下'ttsAudioFormat': 'audio-24khz-160kbitrate-mono-mp3'里的audio-24khz-160kbitrate-mono-mp3可以选择质量更高的比如wav格式的value吗?目前可以选择的有多少种哈,可以的话麻烦提供一个可供选择的列表,谢谢!

ssl问题

image
解决方法百度一堆,但是我还是提交一下吧
image
image

接口有次数限制,我看之前的API是可用的,如何替换?

wss://eastus.api.speech.microsoft.com/cognitiveservices/websocket/v1?TrafficType=AzureDemo&Authorization=bearer%20undefined&X-ConnectionId=577D1E595EEB45979BA26C056A519073

昨晚开始这个接口已经不能使用了,

https://www.null119.cn/index.php/archives/162/ 另外我看这款程序在用的接口,是之前本程序被淘汰的

wss://eastus.tts.speech.microsoft.com/cognitiveservices/websocket/v1

说明之前的这个接口是仍然可以使用的。

但是我没搞清楚如何替换为之前的接口。

C:\Users\dengz\Downloads\tts\tts.py:108: DeprecationWarning: There is no current event loop

I got the warning:

python tts.py --input SSML.xml
C:\Users\dengz\Downloads\tts\tts.py:108: DeprecationWarning: There is no current event loop
asyncio.get_event_loop().run_until_complete(mainSeq(SSML_text, output_path))
F9932303087047B88653BDAE462F4591
Traceback (most recent call last):
File "C:\Users\dengz\Downloads\tts\tts.py", line 108, in
asyncio.get_event_loop().run_until_complete(mainSeq(SSML_text, output_path))
File "C:\Python310\lib\asyncio\base_events.py", line 649, in run_until_complete
return future.result()
File "C:\Users\dengz\Downloads\tts\tts.py", line 98, in mainSeq
await transferMsTTSData(SSML_text, outputPath)
File "C:\Users\dengz\Downloads\tts\tts.py", line 57, in transferMsTTSData
async with websockets.connect(endpoint2,extra_headers={'Origin':'https://azure.microsoft.com'}) as websocket:
File "C:\Python310\lib\site-packages\websockets\legacy\client.py", line 642, in aenter
return await self
File "C:\Python310\lib\site-packages\websockets\legacy\client.py", line 659, in await_impl_timeout
return await asyncio.wait_for(self.await_impl(), self.open_timeout)
File "C:\Python310\lib\asyncio\tasks.py", line 445, in wait_for
return fut.result()
File "C:\Python310\lib\site-packages\websockets\legacy\client.py", line 666, in await_impl
await protocol.handshake(
File "C:\Python310\lib\site-packages\websockets\legacy\client.py", line 332, in handshake
raise InvalidStatusCode(status_code, response_headers)
websockets.exceptions.InvalidStatusCode: server rejected WebSocket connection: HTTP 429

websockets.exceptions.InvalidStatusCode: server rejected WebSocket connection: HTTP 429

035BE9F910F44BFC98F1115F40F3F881
Traceback (most recent call last):
File "tts.py", line 108, in
asyncio.get_event_loop().run_until_complete(mainSeq(SSML_text, output_path))
File "C:\Users\2019\Anaconda3\lib\asyncio\base_events.py", line 584, in run_until_complete
return future.result()
File "tts.py", line 98, in mainSeq
await transferMsTTSData(SSML_text, outputPath)
File "tts.py", line 57, in transferMsTTSData
async with websockets.connect(endpoint2,extra_headers={'Origin':'https://azure.microsoft.com'}) as websocket:
File "C:\Users\2019\Anaconda3\lib\site-packages\websockets\legacy\client.py", line 633, in aenter
return await self
File "C:\Users\2019\Anaconda3\lib\site-packages\websockets\legacy\client.py", line 650, in await_impl_timeout
return await asyncio.wait_for(self.await_impl(), self.open_timeout)
File "C:\Users\2019\Anaconda3\lib\asyncio\tasks.py", line 416, in wait_for
return fut.result()
File "C:\Users\2019\Anaconda3\lib\site-packages\websockets\legacy\client.py", line 663, in await_impl
extra_headers=protocol.extra_headers,
File "C:\Users\2019\Anaconda3\lib\site-packages\websockets\legacy\client.py", line 328, in handshake
raise InvalidStatusCode(status_code, response_headers)
websockets.exceptions.InvalidStatusCode: server rejected WebSocket connection: HTTP 429

Too Many Requests 问题:429

今天转化完,看了下才成功了一半,显示服务器拒绝连接。
websockets.exceptions.InvalidStatusCode: server rejected WebSocket connection: HTTP 429
不知道是不是有什么限制,求大神帮忙看下怎么处理,感激不尽~!

具体报错如下:
Traceback (most recent call last):
File "C:*\tts\python_cli_demo - sfb\tts.py", line 108, in
asyncio.get_event_loop().run_until_complete(mainSeq(SSML_text, output_path))
File "C:\ProgramData\Anaconda3\lib\asyncio\base_events.py", line 647, in run_until_complete
return future.result()
File "C:*\tts\python_cli_demo - sfb\tts.py", line 98, in mainSeq
await transferMsTTSData(SSML_text, outputPath)
File "C:*\tts\python_cli_demo - sfb\tts.py", line 57, in transferMsTTSData
async with websockets.connect(endpoint2) as websocket:
File "C:\Users*\AppData\Roaming\Python\Python39\site-packages\websockets\legacy\client.py", line 633, in aenter
return await self
File "C:\Users*\AppData\Roaming\Python\Python39\site-packages\websockets\legacy\client.py", line 650, in await_impl_timeout
return await asyncio.wait_for(self.await_impl(), self.open_timeout)
File "C:\ProgramData\Anaconda3\lib\asyncio\tasks.py", line 479, in wait_for
return fut.result()
File "C:\Users*\AppData\Roaming\Python\Python39\site-packages\websockets\legacy\client.py", line 658, in await_impl
await protocol.handshake(
File "C:\Users*\AppData\Roaming\Python\Python39\site-packages\websockets\legacy\client.py", line 328, in handshake
raise InvalidStatusCode(status_code, response_headers)
websockets.exceptions.InvalidStatusCode: server rejected WebSocket connection: HTTP 429

python程序报错


During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "D:\py\爬虫\tts.py", line 105, in <module>
    asyncio.get_event_loop().run_until_complete(mainSeq(SSML_text, output_path))
  File "C:\Users\ASUS\AppData\Local\Programs\Python\Python310\lib\asyncio\base_events.py", line 641, in run_until_complete
    return future.result()
  File "D:\py\爬虫\tts.py", line 95, in mainSeq
    await transferMsTTSData(SSML_text, outputPath)
  File "D:\py\爬虫\tts.py", line 43, in transferMsTTSData
    r = requests.get(endpoint1)
  File "C:\Users\ASUS\AppData\Local\Programs\Python\Python310\lib\site-packages\requests\api.py", line 75, in get
    return request('get', url, params=params, **kwargs)
  File "C:\Users\ASUS\AppData\Local\Programs\Python\Python310\lib\site-packages\requests\api.py", line 61, in request
    return session.request(method=method, url=url, **kwargs)
  File "C:\Users\ASUS\AppData\Local\Programs\Python\Python310\lib\site-packages\requests\sessions.py", line 529, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Users\ASUS\AppData\Local\Programs\Python\Python310\lib\site-packages\requests\sessions.py", line 645, in send
    r = adapter.send(request, **kwargs)
  File "C:\Users\ASUS\AppData\Local\Programs\Python\Python310\lib\site-packages\requests\adapters.py", line 517, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='azure.microsoft.com', port=443): Max retries exceeded with url: /en-gb/services/cognitive-services/text-to-speech/ (Caused by SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:997)')))

不支持情感

SSML.xml


<mstts:express-as style="poetry-reading">

晓晓的声音

</mstts:express-as>

报错
tts.py:119: DeprecationWarning: There is no current event loop
asyncio.get_event_loop().run_until_complete(mainSeq(SSML_text, output_path))
04CF12008D864E2CA1CD4B785066F6D4
receiving...
Traceback (most recent call last):
File "V:\tts-main\python_cli_demo\tts.py", line 119, in
asyncio.get_event_loop().run_until_complete(mainSeq(SSML_text, output_path))
File "C:\Users\888\AppData\Local\Programs\Python\Python310\lib\asyncio\base_events.py", line 641, in run_until_complete
return future.result()
File "V:\tts-main\python_cli_demo\tts.py", line 109, in mainSeq
await transferMsTTSData(SSML_text, outputPath)
File "V:\tts-main\python_cli_demo\tts.py", line 88, in transferMsTTSData
response = await websocket.recv()
File "C:\Users\888\AppData\Local\Programs\Python\Python310\lib\site-packages\websockets\legacy\protocol.py", line 552, in recv
await self.ensure_open()
File "C:\Users\888\AppData\Local\Programs\Python\Python310\lib\site-packages\websockets\legacy\protocol.py", line 929, in ensure_open
raise self.connection_closed_exc()
websockets.exceptions.ConnectionClosedError: received 1007 (invalid data) SSML is invalid; then sent 1007 (invalid data) SSML is invalid

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.