├── .vercelignore
├── .dockerignore
├── Dockerfile
├── vercel.json
├── package.json
├── LICENSE
├── .github
└── workflows
│ └── docker.yml
├── api
└── tts.js
├── downloadvoicesjson.js
├── README.md
├── .gitignore
├── index.js
├── cf_worker.js
└── public
└── index.html
/.vercelignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.log
3 | .cache/
4 | temp/
5 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | *node_modules
2 | npm-debug.log
3 | .git
4 | README.md
5 | .idea
6 | *card.json
7 | *.idea
8 | *.vscode
9 | *.iml
10 | *.DS_Store
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:18-alpine
2 |
3 | WORKDIR /usr/src/app
4 |
5 | COPY package*.json ./
6 |
7 | RUN npm ci --only=production
8 |
9 | COPY . .
10 |
11 | EXPOSE 3035
12 |
13 | CMD [ "npm", "start" ]
14 |
--------------------------------------------------------------------------------
/vercel.json:
--------------------------------------------------------------------------------
1 | {
2 | "builds": [
3 | {
4 | "src": "index.js",
5 | "use": "@vercel/node"
6 | }
7 | ],
8 | "routes": [
9 | {
10 | "src": "/(.*)",
11 | "dest": "index.js"
12 | }
13 | ]
14 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tts",
3 | "version": "1.0.0",
4 | "description": "微软azure文本转语音 音频下载",
5 | "main": "index.js",
6 | "type": "module",
7 | "scripts": {
8 | "dev": "nodemon index.js",
9 | "start": "node index.js"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/x-dr/tts.git"
14 | },
15 | "keywords": [
16 | "tts"
17 | ],
18 | "author": "x-dr",
19 | "license": "MIT",
20 | "bugs": {
21 | "url": "https://github.com/x-dr/tts/issues"
22 | },
23 | "homepage": "https://github.com/x-dr/tts#readme",
24 | "devDependencies": {
25 | "nodemon": "^3.0.1"
26 | },
27 | "dependencies": {
28 | "axios": "^1.4.0",
29 | "express": "^4.18.2"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 x-dr
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.github/workflows/docker.yml:
--------------------------------------------------------------------------------
1 | name: "docker build release"
2 |
3 |
4 | on:
5 | push:
6 | branches:
7 | - 'main'
8 | # on:
9 | # workflow_dispatch:
10 | # inputs:
11 | # project:
12 | # description: 'Project:VERSION'
13 | # required: true
14 | # default:
15 |
16 | jobs:
17 | build:
18 | runs-on: ubuntu-latest
19 | steps:
20 | - name: Checkout
21 | uses: actions/checkout@v3
22 |
23 | - name: Set tag
24 | id: tag
25 | run: |
26 | echo "tag=$(date +%Y)-$(date +%m)-$(date +%d)" >> $GITHUB_ENV
27 | - name: Set up QEMU
28 | uses: docker/setup-qemu-action@v2
29 |
30 | - name: Set up Docker Buildx
31 | uses: docker/setup-buildx-action@v2
32 |
33 | - name: Login Docker Hub
34 | uses: docker/login-action@v2
35 | with:
36 | username: ${{ secrets.DOCKER_USERNAME }}
37 | password: ${{ secrets.DOCKERHUB_TOKEN }}
38 |
39 | - name: Build and push to docker hub
40 | uses: docker/build-push-action@v3
41 | with:
42 | context: .
43 | platforms: linux/amd64,linux/arm64
44 | push: true
45 | build-args: VERSION=${{ env.tag }}
46 | tags: |
47 | ${{ secrets.DOCKER_USERNAME }}/tts-azure:latest
48 | ${{ secrets.DOCKER_USERNAME }}/tts-azure:${{ env.tag }}
--------------------------------------------------------------------------------
/api/tts.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | function generateUUID() {
4 | let uuid = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'.replace(/[x]/g, function(c) {
5 | let r = Math.random() * 16 | 0,
6 | v = c === 'x' ? r : (r & 0x3 | 0x8);
7 | return v.toString(16);
8 | });
9 | return uuid;
10 | }
11 |
12 | const speechApi = (ssml) => {
13 | var data = JSON.stringify({
14 | ssml,
15 | ttsAudioFormat: "audio-24khz-160kbitrate-mono-mp3",
16 | offsetInPlainText: 0,
17 | properties: {
18 | SpeakTriggerSource: "AccTuningPagePlayButton",
19 | },
20 | });
21 |
22 | var config = {
23 | method: "post",
24 | url: "https://southeastasia.api.speech.microsoft.com/accfreetrial/texttospeech/acc/v3.0-beta1/vcg/speak",
25 | responseType: "arraybuffer",
26 | headers: {
27 | authority: "southeastasia.api.speech.microsoft.com",
28 | accept: "*/*",
29 | "accept-language": "zh-CN,zh;q=0.9",
30 | customvoiceconnectionid: generateUUID(),
31 | origin: "https://speech.microsoft.com",
32 | "sec-ch-ua":
33 | '"Google Chrome";v="111", "Not(A:Brand";v="8", "Chromium";v="111"',
34 | "sec-ch-ua-mobile": "?0",
35 | "sec-ch-ua-platform": '"Windows"',
36 | "sec-fetch-dest": "empty",
37 | "sec-fetch-mode": "cors",
38 | "sec-fetch-site": "same-site",
39 | "user-agent":
40 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36",
41 | "content-type": "application/json",
42 | },
43 |
44 | data: data,
45 | };
46 | return new Promise((resolve, reject) => {
47 | axios(config)
48 | .then(function (response) {
49 | resolve(response.data);
50 | })
51 | .catch(function (error) {
52 | reject(error);
53 | });
54 | });
55 | };
56 |
57 |
58 |
59 | export default speechApi;
60 |
61 |
--------------------------------------------------------------------------------
/downloadvoicesjson.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import fs from "fs";
3 | const speechApi = () => {
4 | const data = JSON.stringify({
5 | "queryCondition": {
6 | "items": [
7 | {
8 | "name": "VoiceTypeList",
9 | "value": "StandardVoice",
10 | "operatorKind": "Contains"
11 | }
12 | ]
13 | }
14 | });
15 | // https://southeastasia.api.speech.microsoft.com/accfreetrial/texttospeech/acc/v3.0-beta1/vcg/voices
16 | const config = {
17 | method: 'post',
18 | url: 'https://southeastasia.api.speech.microsoft.com/accfreetrial/texttospeech/acc/v3.0-beta1/vcg/voices',
19 | headers: {
20 | 'authority': 'southeastasia.api.speech.microsoft.com',
21 | 'accept': 'application/json, text/plain, */*',
22 | 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
23 | 'customvoiceconnectionid': '97130be0-f304-11ed-b81e-274ad6e5de17',
24 | 'origin': 'https://speech.microsoft.com',
25 | 'sec-ch-ua': '"Microsoft Edge";v="113", "Chromium";v="113", "Not-A.Brand";v="24"',
26 | 'sec-ch-ua-mobile': '?0',
27 | 'sec-ch-ua-platform': '"Windows"',
28 | 'sec-fetch-dest': 'empty',
29 | 'sec-fetch-mode': 'cors',
30 | 'sec-fetch-site': 'same-site',
31 | 'speechstudio-session-id': '951910a0-f304-11ed-b81e-274ad6e5de17',
32 | 'speechstudio-subscriptionsession-id': 'undefined',
33 | 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.42',
34 | 'x-ms-useragent': 'SpeechStudio/2021.05.001',
35 | 'content-type': 'application/json'
36 | },
37 | data: data,
38 | // timeout: 1500,
39 | };
40 |
41 | return new Promise((resolve, reject) => {
42 | axios(config)
43 | .then(function (response) {
44 | fs.writeFileSync("voices.json", JSON.stringify(response.data));
45 | resolve(response.data);
46 | })
47 | .catch(function (error) {
48 | reject(error);
49 | });
50 | });
51 | };
52 |
53 |
54 | speechApi()
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # 已失效
3 |
4 |
5 | ### 微软azure文本转语音 音频下载
6 | *Demo* : [https://tts.131213.xyz/](https://tts.131213.xyz/)
7 |
8 |
9 | > *本文由GitHub Copilot 生成*
10 |
11 | ### 1. 介绍
12 |
13 | 本项目是基于微软azure的文本转语音服务,通过调用微软azure的api接口,将文本转换为语音,然后下载到本地。
14 |
15 | ### 2. 安装说明
16 |
17 | #### 利用Cloudflare Workers部署
18 |
19 | 1. 新建一个 Cloudflare Worker
20 |
21 | 2. 将 [cf_worker.js](https://github.com/x-dr/tts/blob/main/cf_worker.js) 中的代码复制到 Cloudflare Worker 中并部署即可
22 |
23 |
24 |
25 | > 修改前端
26 |
27 | `https://raw.githubusercontent.com/x-dr/cf_pages/main/tts.html` 是前端代码 ,想修改的自己修改cf_worker.js中的下面行就行
28 |
29 | ```javascript
30 | const html = await fetch("https://raw.githubusercontent.com/x-dr/cf_pages/main/tts.html")
31 | ```
32 |
33 | ***
34 |
35 | #### 利用docker部署
36 |
37 | 1. 下载docker镜像
38 |
39 | ```bash
40 | docker pull gindex/tts-azure:latest
41 | ```
42 |
43 | 2. 运行容器
44 |
45 | ```bash
46 | docker run -itd \
47 | --name tts \
48 | -p 3035:3035 \
49 | --restart=always \
50 | gindex/tts-azure:latest
51 | ```
52 |
53 | 3. 访问地址
54 |
55 | ```bash
56 | http://ip:3035/
57 | ```
58 |
59 |
60 | ***
61 |
62 | #### 利用Vercel部署
63 |
64 |
65 | [](https://vercel.com/new/clone?utm_source=busiyi&utm_campaign=oss&repository-url=https://github.com/x-dr/tts)
66 |
67 | #### 利用Linux服务器部署
68 |
69 | 1. 安装nodejs (如果已经安装过nodejs则跳过此步骤)
70 |
71 | ```bash
72 | curl -sL https://deb.nodesource.com/setup_18.x | sudo -E bash -
73 | sudo apt-get install -y nodejs
74 | ```
75 |
76 | 2. 安装git (如果已经安装过git则跳过此步骤)
77 |
78 | ```bash
79 | sudo apt-get install git
80 | ```
81 |
82 | 3. 下载项目
83 |
84 | ```bash
85 | git clone https://github.com/x-dr/tts.git
86 | ```
87 |
88 | 4. 安装依赖
89 |
90 | ```bash
91 | cd tts
92 | npm install
93 | ```
94 |
95 | 5. 运行项目
96 |
97 | ```bash
98 | node index.js
99 | ```
100 |
101 | 6. 访问地址
102 |
103 | ```bash
104 | http://ip:3035/
105 | ```
106 |
107 | ### 3. 使用说明
108 |
109 | > iOS源阅读tts复制链接网络导入即可
110 |
111 |
112 |
113 | ### 4. 更新日志
114 |
115 | + 2023-11-27 : 添加阅读3.0和iOS源阅读 tts
116 |
117 | ### Star History
118 |
119 | [](https://star-history.com/#x-dr/tts&Timeline)
120 |
121 |
122 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 | .pnpm-debug.log*
9 |
10 | # Diagnostic reports (https://nodejs.org/api/report.html)
11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
12 |
13 | # Runtime data
14 | pids
15 | *.pid
16 | *.seed
17 | *.pid.lock
18 |
19 | # Directory for instrumented libs generated by jscoverage/JSCover
20 | lib-cov
21 |
22 | # Coverage directory used by tools like istanbul
23 | coverage
24 | *.lcov
25 |
26 | # nyc test coverage
27 | .nyc_output
28 |
29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
30 | .grunt
31 |
32 | # Bower dependency directory (https://bower.io/)
33 | bower_components
34 |
35 | # node-waf configuration
36 | .lock-wscript
37 |
38 | # Compiled binary addons (https://nodejs.org/api/addons.html)
39 | build/Release
40 |
41 | # Dependency directories
42 | node_modules/
43 | jspm_packages/
44 |
45 | # Snowpack dependency directory (https://snowpack.dev/)
46 | web_modules/
47 |
48 | # TypeScript cache
49 | *.tsbuildinfo
50 |
51 | # Optional npm cache directory
52 | .npm
53 |
54 | # Optional eslint cache
55 | .eslintcache
56 |
57 | # Optional stylelint cache
58 | .stylelintcache
59 |
60 | # Microbundle cache
61 | .rpt2_cache/
62 | .rts2_cache_cjs/
63 | .rts2_cache_es/
64 | .rts2_cache_umd/
65 |
66 | # Optional REPL history
67 | .node_repl_history
68 |
69 | # Output of 'npm pack'
70 | *.tgz
71 |
72 | # Yarn Integrity file
73 | .yarn-integrity
74 |
75 | # dotenv environment variable files
76 | .env
77 | .env.development.local
78 | .env.test.local
79 | .env.production.local
80 | .env.local
81 |
82 | # parcel-bundler cache (https://parceljs.org/)
83 | .cache
84 | .parcel-cache
85 |
86 | # Next.js build output
87 | .next
88 | out
89 |
90 | # Nuxt.js build / generate output
91 | .nuxt
92 | dist
93 |
94 | # Gatsby files
95 | .cache/
96 | # Comment in the public line in if your project uses Gatsby and not Next.js
97 | # https://nextjs.org/blog/next-9-1#public-directory-support
98 | # public
99 |
100 | # vuepress build output
101 | .vuepress/dist
102 |
103 | # vuepress v2.x temp and cache directory
104 | .temp
105 | .cache
106 |
107 | # Docusaurus cache and generated files
108 | .docusaurus
109 |
110 | # Serverless directories
111 | .serverless/
112 |
113 | # FuseBox cache
114 | .fusebox/
115 |
116 | # DynamoDB Local files
117 | .dynamodb/
118 |
119 | # TernJS port file
120 | .tern-port
121 |
122 | # Stores VSCode versions used for testing VSCode extensions
123 | .vscode-test
124 |
125 | # yarn v2
126 | .yarn/cache
127 | .yarn/unplugged
128 | .yarn/build-state.yml
129 | .yarn/install-state.gz
130 | .pnp.*
131 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | // const express = require("express");
2 | import Express from "express";
3 | const app = Express();
4 |
5 | import speechApi from "./api/tts.js" // 导入 speechApi 函数
6 | import path from 'path';
7 | const __dirname = path.resolve();
8 |
9 | app.set('x-powered-by', false)
10 | app.use(Express.json())
11 | app.use(Express.urlencoded({ extended: false }))
12 | app.use(Express.static(__dirname+'/public'));
13 |
14 |
15 |
16 |
17 | app.get("/audio", async (req, res) => {
18 | try {
19 |
20 | const { voice, rate, pitch, text,voiceStyle } = req.query;
21 | const ssml = `