吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4404|回复: 3
收起左侧

[其他转载] nodejs版讯飞文字合成语音

[复制链接]
alwaysol 发表于 2021-3-31 15:22
本帖最后由 alwaysol 于 2021-6-30 14:51 编辑

最近想听一部小说但是没语音版,看到讯飞有文字转语音的接口所有就玩玩,官方原版例子一次只能生成3000个字左右,所以我修改了下把整个小说分片段生成语音,如有不足的地方望大佬们指正
步骤:
1.去nodejs官网下载win版的nodejs.exe,直接安装就行,不需要任何设置
2.去讯飞开放平台注册账号,开通语音合成业务,可以免费用50000次,复制APPID等信息到以下代码config对应的位置
3.把下载的小说txt文件放到当前目录下,txt要utf-8编码的,如果不是另存txt为utf-8编码
4.修改代码里的txt文件名和你想保存的音频文件名
5.双击start.bat文件就会出现dos窗口,音频文件生成在当前目录下MP3文件夹里
源代码下载地址:https://wwa.lanzouj.com/iPLAJniey6f

[JavaScript] 纯文本查看 复制代码
/* Created by iflytek on 2020/03/01.
 *
 * 运行前:请先填写 appid、apiSecret、apiKey
 * 
 * 在线语音合成调用demo
 * 此demo只是一个简单的调用示例,不适合用到实际生产环境中
 *
 * 在线语音合成 WebAPI 接口调用示例 接口文档(必看):https://www.xfyun.cn/doc/tts/online_tts/API.html
 * 错误码链接:
 * https://www.xfyun.cn/document/error-code (code返回错误码时必看)
 * 
 */
const CryptoJS = require('crypto-js');
const WebSocket = require('ws');
const log = require('log4node');
const fs = require('fs');


//在控制台-我的应用-在线语音合成(流式版)获取
let appid = "";
//在控制台-我的应用-在线语音合成(流式版)获取
let apiSecret = "";
//在控制台-我的应用-在线语音合成(流式版)获取
let apiKey = "";

let vcn = "xiaoyan";//声音

var txt = fs.readFileSync('新建文本文档.txt', 'utf8');//读取的文件名
var flie = "newtxt";//保存的文件名
var min = 10;//每个音频时长,分钟

var array = (txt.length % 3000) > 0 ? parseInt(txt.length / 3000 + 1) : parseInt(txt.length / 3000);
min = min % 10 > 0 ? parseInt(min / 10) + 1 : parseInt(min / 10);

(async () => {

    var page = (array % 100) > 0 ? parseInt(array / 100 + 1) : parseInt(array / 100);
    for (let i = 0; i < page; i++) {
        for (let index = i * 100; index < (i * 100) + 100; index++) {
            main(index);
        }
        await wait(1000 * 20);
    }
})();

function main(index) {

    // 系统配置 
    var config = {
        // 请求地址
        hostUrl: "wss://tts-api.xfyun.cn/v2/tts",
        host: "tts-api.xfyun.cn",
        appid: appid,
        apiSecret: apiSecret,
        apiKey: apiKey,
        text: txt.substr(3000 * index, 3000),
        uri: "/v2/tts",
    }

    // 获取当前时间 RFC1123格式
    let date = (new Date().toUTCString());

    // 设置当前临时状态为初始化
    let wssUrl = config.hostUrl + "?authorization=" + getAuthStr(date) + "&date=" + date + "&host=" + config.host;
    let ws = new WebSocket(wssUrl);

    if (!fs.existsSync('./mp3/' + flie)) fs.mkdirSync('./mp3/' + flie);

    // 连接建立完毕,读取数据进行识别
    ws.on('open', () => {
        log.info("websocket connect!");
        send();

        // 如果之前保存过音频文件,删除之
        var ss = (index + 1);
        ss = ss % min > 0 ? parseInt(ss / min) + 1 : ss / min;
        if (fs.existsSync('./mp3/' + flie + '/' + flie + ss + '.mp3')) {
            fs.unlink('./mp3/' + flie + '/' + flie + ss + '.mp3', (err) => {
                if (err) {
                    log.error('remove error: ' + err);
                }
            })
        }
    })

    // 得到结果后进行处理,仅供参考,具体业务具体对待
    ws.on('message', async (data, err) => {
        if (err) {
            log.error('message error: ' + err);
            return;
        }

        let res = JSON.parse(data);

        if (res.code != 0) {
            log.error(`${res.code}: ${res.message}`);
            ws.close();
            return;
        }

        let audio = res.data.audio;
        let audioBuf = Buffer.from(audio, 'base64');

        await save(audioBuf);

        if (res.code == 0 && res.data.status == 2) {
            await wait(1000);
            var ss = (index + 1);
            ss = ss % min > 0 ? parseInt(ss / min) + 1 : ss / min;
            log.info('第' + ss + '个文件合并完成,共' + (array % min > 0 ? parseInt(array / min) + 1 : parseInt(array / min)) + '个文件*********************!');
            ws.close();
        }
    })

    // 资源释放
    ws.on('close', () => {
        log.info('connect close!');
    });

    // 连接错误
    ws.on('error', (err) => {
        log.error("websocket connect err: " + err);
    })

    // 鉴权签名
    function getAuthStr(date) {
        let signatureOrigin = `host: ${config.host}\ndate: ${date}\nGET ${config.uri} HTTP/1.1`;
        let signatureSha = CryptoJS.HmacSHA256(signatureOrigin, config.apiSecret);
        let signature = CryptoJS.enc.Base64.stringify(signatureSha);
        let authorizationOrigin = `api_key="${config.apiKey}", algorithm="hmac-sha256", headers="host date request-line", signature="${signature}"`;
        let authStr = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(authorizationOrigin));
        return authStr;
    }

    // 传输数据
    function send() {
        let frame = {
            // 填充common
            "common": {
                "app_id": config.appid
            },
            // 填充business
            "business": {
                "aue": "lame",
                "sfl": 1,
                "auf": "audio/L16;rate=16000",
                "vcn": vcn,
                "tte": "UTF8"
            },
            // 填充data
            "data": {
                "text": Buffer.from(config.text).toString('base64'),
                "status": 2
            }
        }

        ws.send(JSON.stringify(frame));

    }

    // 保存文件
    async function save(data) {
        return new Promise(async resolve => {
            var ss = (index + 1);
            ss = ss % min > 0 ? parseInt(ss / min) + 1 : ss / min;
            fs.writeFile('./mp3/' + flie + '/' + flie + ss + '.mp3', data, { flag: 'a' }, (err) => {
                if (err) {
                    log.error('save error: ' + err);
                    resolve();
                    return;
                }
                log.info('正下载第' + ss + '个文件碎片!');
                resolve();
            })
        })
    }

}

async function wait(time) {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve();
        }, time);
    })
}




免费评分

参与人数 2吾爱币 +6 热心值 +2 收起 理由
leo4242 + 1 + 1 牛B
苏紫方璇 + 5 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

fj198602 发表于 2021-6-9 23:33
感谢楼主分享,软件非常好用,使用后,发现一个小问题,因为合成的音频,是由很多小片段合并而来,合并处(小片段的拼接处)会出现破音或者撕裂的声音,一部小说转下来,很多都会有这个问题,不知道有没有优化的可能?
 楼主| alwaysol 发表于 2021-6-11 09:51
fj198602 发表于 2021-6-9 23:33
感谢楼主分享,软件非常好用,使用后,发现一个小问题,因为合成的音频,是由很多小片段合并而来,合并处( ...

好的,有时间我看看
fj198602 发表于 2021-6-29 01:37
大神,什么时候有时间,能优化一下。查了好多资料,看到一个答案:说是JS数据格式的问题。     本人小白,不太懂,不知道能不能给大神一点帮助。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 16:22

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表