看看效果叭

解压的文件

上传的文件格式

测试1|||测试1的文字测试2|||测试2的文字测试3|||测试3的文字测试4|||测试4的文字测试5|||测试5的文字

实现的逻辑如下

  • 上传文件
  • 解析txt
  • 发送内容至百度语音合成
  • 生成文件夹放置本次合成的mp3文件,并压缩成zip
  • 发送zip的地址给前端

上传文件

使用了 element-ui 的 el-upload 组件
<el-upload      v-loading="loading"      class="upload-demo"      drag      ref="upload"      action="#"      accept=".txt"      :before-upload="onBeforeUploadImage"      :http-request="UploadImage"      :on-change="fileChange"      :file-list="fileList"    >    <i class="el-icon-upload"></i>    <div class="el-upload__text">        将文件拖到此处,或        <em>点击上传</em>    </div>    <div class="el-upload__tip" slot="tip">只能上传txt文件,且不超过1M</div></el-upload>
在上传之前判断上传的文件是否符合要求
onBeforeUploadImage(file) {    const isTxt = file.type === "text/plain";    const isLt1M = file.size / 1024 / 1024 < 1;    if (!isTxt) {        this.$message.error("上传文件只能是txt格式!");    }    if (!isLt1M) {        this.$message.error("上传文件大小不能超过 1MB!");    }    return isTxt && isLt1M;}
一次只上传一个文件,在文件列表更新时先清除之前的文件
fileChange(file) {    let obj = this.onBeforeUploadImage(file.raw);    if (obj) {        this.$refs.upload.clearFiles();         this.fileList = [{ name: file.name, url: file.url }];    }}
上传的主要函数
UploadImage(param) {    this.loading = true;    const formData = new FormData();    formData.append("file", param.file);    this.$axios({        url: process.env.VUE_APP_BASE_API + "api/txtToMp3",        method: "post",        data: formData    })    .then(response => {        if (response.data.code == 0) {            this.loading = false;            this.dialogVisible = true;            this.url = response.data.data.url;        }    })    .catch(error => {        console.log(error);    });}

node代码

用到的依赖项
const formidable = require("formidable"); //获取上传的txt,并保存const path = require("path"); const AipSpeech = require("baidu-aip-sdk").speech; //百度语音合成sdkconst fs = require("fs"); const compressing = require("compressing"); //压缩文件夹用
接口代码
router.post("/txtToMp3", async function (req, res, next) {  let form = new formidable.IncomingForm();  form.encoding = "utf-8"; //编码  form.uploadDir = path.join(__dirname + "/../txt"); //保存上传文件地址  form.keepExtensions = true; //保留后缀  form.parse(req, function (err, fields, files) {    let filename;    filename = files.file.name;    let nameArray = filename.split("."); //分割    let type = nameArray[nameArray.length - 1];    let name = "";    for (let i = 0; i < nameArray.length - 1; i++) {      name = name + nameArray[i];    }    let date = new Date();    let time = "_" + date.getTime();    let avatarName = name + time + "." + type;    let newPath = form.uploadDir + "/" + avatarName;    fs.renameSync(files.file.path, newPath); //移动文件    fs.readFile(newPath, "utf-8", function (err, data) {      if (err) {        console.log(err);        new Result(null, "读取失败").fail(res);      } else {        let client = new AipSpeech(          0,          "百度语音合成key",          "百度语音合成secret"        );        let resultData = data.split("\n");        let number = resultData.length;        let formTime = new Date().getTime();        let mp3FileDir = path.join(__dirname + "/../mp3_" + formTime);        fs.mkdirSync(mp3FileDir);        for (let i in resultData) {            setTimeout(function(){                if (resultData[i].indexOf("|||") != -1) {                let text = resultData[i].split("|||")[1];                // 语音合成,保存到本地文件                client.text2audio(text, { spd: 4, per: 4 }).then(                  function (result) {                    if (result.data) {                      let time = resultData[i].split("|||")[0] + "_voice";                      let avatarName_mp3 = mp3FileDir + "/" + time + ".mp3";                      fs.writeFileSync(avatarName_mp3, result.data);                      number--;                      if (number == 0) {                        let zipFileName = "zip/mp3_" + formTime + ".zip";                        compressing.zip                          .compressDir(mp3FileDir, zipFileName)                          .then(() => {                            let item = {                              url: zipFileName,                            };                            new Result(item, "压缩成功").success(res);                          })                          .catch((err) => {                            new Result(null, "压缩失败").fail(res);                          });                      }                    } else {                      // 合成服务发生错误                      new Result(null, "合成失败").fail(res);                    }                  },                  function (err) {                    console.log(err);                  }                );              } else {                new Result(null, "文件格式错误").fail(res);              }               },i * 20)        }      }    });  });});

PS:

在node部分,在判断需要合成的文件是否全部完成时,我是通过number的值等于0判断完成,不知道大佬们有啥好方法不?