IESM项目实训六——两种语音录入方式前后端具体实现和修改为弹窗输入成绩类型

IESM项目实训六

前一篇文章大概实现了基本的前后端交互方式,舍弃使用语音录入成绩类型,改为使用弹窗选择,该文章是具体两种方式代码。

单独成绩录入

后端相关URL:
找到当前第一个未曾录入学生的索引,不能为上一次期望录入同学,否则一个同学多次录入失败会不断重复该学生。无论上一位同学是否正常录入都不会影响录入下一位同学,它会在下一位同学的下一位录入,即失败会间隔一位同学再次录入。如果返回索引为-1,表示所有学生成绩已录入,前端停止音频录制等相关周期方法。

//找到未录入的第一个学生,返回该学生索引
    @ResponseBody
    @RequestMapping(value = "/inputStuIndex")
    public Result<Integer> inputStuIndex(@RequestParam(name = "lastIndex") int lastIndex, @RequestParam(name = "type") int type) {
        int index = -2;
        if (this.stuList != null) {
            for (int i = 0; i < this.stuList.size(); i++) {
                if (type == 2) {
                    if ((this.stuList.get(i).getExamScores() == null||this.stuList.get(i).getExamScores() == 0) && i != lastIndex) {
                        index = i;
                        break;
                    }
                } else if (type == 1) {
                    if ((this.stuList.get(i).getTestScores() == null||this.stuList.get(i).getTestScores() == 0) && i != lastIndex) {
                        index = i;
                        break;
                    }
                } else if (type == 3) {
                    if ((this.stuList.get(i).getUsualScores() == null||this.stuList.get(i).getUsualScores() == 0) && i != lastIndex) {
                        index = i;
                        break;
                    }
                } else {
                    System.out.println(type);
                }
            }
        } else {
            index=-1;
            System.out.println("这门课没有学生可以录入了");
        }
        System.out.println("下一个录入学生索引:" + index);
        return Result.OK(index);
    }

语音合成索引对应学生姓名,用以提示教师当前录入学生姓名和表示开始录制音频信号。

 //合成学生姓名语音
    @RequestMapping(value = "/stuNameVoice")
    public Result<Boolean> stuNameVoice(@RequestParam(name = "index") int index) {
        VoiceCompose voiceCompose = new VoiceCompose();
        Boolean result = false;
        String startVoice = this.stuList.get(index).getStuName();
        if (!voiceCompose.getMP3ByText(startVoice)) {
            System.out.println("转换失败");
        } else {
            result = true;
            voiceCompose.playMP3();
        }
        return Result.OK(result);
    }

识别音频文件,处理识别结果,判断是否为0-100。正确则按照索引更新学生对应类型成绩,错误则不更新学生成绩,学生成绩仍为空,间隔一位同学后,系统会再次播放该学生姓名。

 //识别成绩录入数据库
    @ResponseBody
    @RequestMapping(value = "/voiceInputScores")
    public Result<List<Scores>> voiceInputScores(@RequestParam(name = "type") int type,
                                                 @RequestParam(name = "index") int index,
                                                 @RequestParam(name = "voiceBlobFile") MultipartFile voiceBlobFile,
                                                 @RequestParam(name = "scoresType") String scoresType) {
        Scores stu = this.stuList.get(index);
        String scores = "";
        Integer score = 0;
        byte[] voiceData = new byte[1024];
        //将前端的参数转换为byte数组,进行识别处理
        try {
            voiceData = voiceBlobFile.getBytes();
        } catch (IOException e) {
            e.printStackTrace();
        }
        VoiceRecognition voiceRecognition = new VoiceRecognition();
        scores = voiceRecognition.recognizeNum(voiceData);
        if (!scores.equals("")) {
            System.out.println("语音识别初始结果" + VoiceRecognition.getResultText());
            score = Integer.parseInt(scores);
            System.out.println("语音识别转换结果" + score);
            if(score>100||score<0){
                System.out.println("成绩录入格式不正确,不在0-100内");
                return Result.error("成绩录入格式不正确,不在0-100内");
            }else {
                if (type == 1) {
                    this.stuList.get(index).setExamScores(score);
                    scoresService.updateExamScores(score, stu.getCsId(), stu.getLesOrd(), stu.getStuId());

                    System.out.println("更新了" + stuList.get(index).getStuName() + ":" + stuList.get(index).getExamScores());
                } else if (type == 2) {
                    this.stuList.get(index).setTestScores(score);
                    scoresService.updateTestScores(score, stu.getCsId(), stu.getLesOrd(), stu.getStuId());
                    System.out.println("更新了" + stuList.get(index).getStuName() + ":" + stuList.get(index).getTestScores());

                } else if (type == 3) {
                    this.stuList.get(index).setUsualScores(score);
                    scoresService.updateUsualScores(score, stu.getCsId(), stu.getLesOrd(), stu.getStuId());
                    System.out.println("更新了" + stuList.get(index).getStuName() + ":" + stuList.get(index).getUsualScores());
                }
                updateScores(this.stuList.get(index),scoresType);
            }
        } else {
            String remind = "语音识别失败,请您重说一次";
            return Result.error(remind);
            System.out.println(remind);
        }
        return Result.OK(this.stuList);
    }

总成绩通过任何方式录入,后台会根据各种类型成绩和所占比例得出总成绩。考虑学生课程存在两种总成绩类型,一种为百分制,一种为评级制,所以总成绩类型为String。数据库默认为百分制,如需修改则在前端进行修改。

public void updateScores(Scores scores,String scoresType){
        int usualScores=-1;
        int testScores=-1;
        int scoreNum=-1;
        if(scores.getUsualScores()==null){
            usualScores=0;
        }else{
            usualScores=scores.getUsualScores();
        }
        if(scores.getExamScores()==null){
            scoreNum=0;
        }else{
            scoreNum=scores.getExamScores();
        }
        if(scores.getTestScores()==null){
            testScores=0;
        }else{
            testScores=scores.getTestScores();
        }

        double score=this.temporaryScores.getTestPercent()*testScores*0.01
                +this.temporaryScores.getUsualPercent()*usualScores*0.01
                +(100-this.temporaryScores.getTestPercent()-this.temporaryScores.getUsualPercent())*scoreNum*0.01;
        String num;
        if(scoresType.equals("百分制")){
            num=(int)myround(score)+"";
            System.out.println("原成绩"+score+"    四舍五入后"+num);
            scores.setScores(num);

        }else {
            num=scoresToLevel((int)myround(score))+"";
            System.out.println("原成绩"+score+"    四舍五入后"+num);
            scores.setScores(num);
        }
            scoresService.updateScores(num,scores.getCsId(),scores.getLesOrd(),scores.getStuId());
    }

正常计算总成绩结果为double,需要四舍五入后,转换为String。

 //四舍五入double
    public static double myround(double num)
    {
        BigDecimal b=new BigDecimal(num);
        num=b.setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue();
        return num;
    }

//评级制,总成绩生成
    public static String scoresToLevel(int num){
        String temp="";
        if(num>=90&&num<=100){
            temp="优";
        }else if(num>=80&&num<=90){
            temp="良";
        }else if(num>=70&&num<=80){
            temp="中";
        }else if(num>=60&&num<=70){
            temp="及格";
        }else if(num<60){
            temp="不及格";
        }
        return temp;
    }

前端代码:

  url: {
	stuNameVoice: "ScoresInput/scores/stuNameVoice",
	inputStuIndex: "ScoresInput/scores/inputStuIndex",
	voiceInputScores: "ScoresInput/scores/voiceInputScores",
}
    //语音录入按钮只可点击一次,控制不能重复点击响应
    voiceController: true,
    startRecording: function () {
      if(this.inputState==="已提交"){
        alert("该课程成绩已提交不可进行修改");
      }else {
      if (this.voiceController === true) {
        let output = false;
        let startVoice = "现在开始语音录入成绩,请选择录入成绩类型";
        getAction(this.url.startInputScoresVoice, {startVoice: startVoice}).then((res) => {
          if (res.result===true) {
            output = res.result;
            let that = this;
            if (output === true) {
              console.log("开始提示语音播放成功");
              that.voiceController = false;
              //弹出选择输入成绩类型
              that.dialogVisible = true;
              //等待输入类型选择
              that.waitType = setInterval(function () {
                if (that.dialogVisible === false) {
                  console.log("要输入的类型是" + that.type);
                  clearInterval(that.waitType);
                  //初始化索引
                  let index = -3;
                  //获取学生列表
                  let voiceBlobFile;//录入成绩的音频文件
                  let lastIndex = index;//防止该同学录入失败无间隔重复该学生,所以保存上一个同学的索引,避免相邻两次录入学生相同
                  that.inputScores = setInterval(function () {
                    //获取索引
                    getAction(that.url.inputStuIndex, {lastIndex: lastIndex, type: that.type}).then((res) => {
                      //如果没有为空值的学生,就表示学生成绩已经全部录入
                      if (res.result === -1) {
                        //如果所有同学录入,停止该周期函数,弹出弹窗提醒,按钮控制为true
                        if (recorder !== null) {
                          recorder.stop();
                        }
                        that.voiceController = true;
                        clearInterval(that.inputScores);
                        alert("学生成绩已全部录入");
                      } else {
                        index = res.result;
                        console.log("录入学生成绩索引" + index)
                        if (index !== -2) {
                          getAction(that.url.stuNameVoice, {index: index}).then((res) => {
                            console.log("学生姓名播放");
                            if (res.result === true) {
                              console.log("学生姓名播放成功了");
                            } else {
                              console.log("学生姓名播放失败");
                            }
                            //开始音频录制
                            Recorder.get(function (rec) {
                              recorder = rec
                              recorder.start()
                            })
                          })
                        } else if (index === -2) {
                          if (recorder !== null) {
                            recorder.stop();
                          }
                          that.voiceController = true;
                          clearInterval(that.inputScores);
                          alert("该课程没有学生!");
                        }
                      //因为每隔5秒录入一名学生,所以开始的4.5秒后获取音频数据,确保为当前学生的成绩音频
                        that.getVoiceFile = setTimeout(function () {
                          voiceBlobFile = recorder.getBlob();
                          //录入学生成绩
                          if (index >= 0) {
                            that.recognitionScores(that.type, index, voiceBlobFile);
                          }
                          //防止相邻两次都是同一学生
                          lastIndex = index;
                        }, 4500)
                      }
                    })
                  }, 5000)
                }
              }, 10);
            } else {
              console.log("开始提示语音播放失败");
            }
          }
        })
      }
      }
    },
    
     //向后端传递录制成绩的音频,仅识别成绩
	recognitionScores: function (type, index, voiceBlobFile) {
      let formData = new FormData();
      console.log(voiceBlobFile)
      formData.append("voiceBlobFile", voiceBlobFile);
      formData.append("index", index);
      formData.append("type", type);
      formData.append("scoresType", this.scoresTypeValue);
      axios.post(this.url.voiceInputScores, formData).then((res) => {
        if(res.success){
        //将数据实时显示出来,不需要通过数据库查询
          this.superFieldList = res.result;
          this.dataSource=this.superFieldList;
          console.log("成绩音频数据传递成功");
        }else{
          console.log("成绩音频数据传递失败");
        }
      })
    },

语音姓名成绩录入

后端代码如下:

//识别成绩录入数据库
    @ResponseBody
    @RequestMapping(value = "/voiceInputAllScores")
     public Result<List<Scores>> voiceInputAllScores(@RequestParam(name = "type") int type,
                                                    @RequestParam(name = "voiceBlobFile") MultipartFile voiceBlobFile,
                                                    @RequestParam(name = "scoresType") String scoresType) {
        String scores = "";
        Integer score = 0;
        byte[] voiceData = new byte[1024];
        //将前端的参数转换为byte数组,进行识别处理
        try {
            voiceData = voiceBlobFile.getBytes();
        } catch (IOException e) {
            e.printStackTrace();
        }
        VoiceRecognition voiceRecognition = new VoiceRecognition();
        boolean judgement = voiceRecognition.recognizeDataVoice(voiceData);
        String result = VoiceRecognition.getResultText();
        String stuName = VoiceRecognition.stuNameRecognize(result);
        scores = VoiceRecognition.format(result);
        if (judgement && !stuName.equals("") && !scores.equals("")) {

            score = Integer.parseInt(scores);
            if (score > 100 || score < 0) {
                System.out.println("成绩录入格式不正确,不在0-100内");
                return Result.error("成绩录入格式不正确,不在0-100内");
            }else {
                Scores stu = new Scores();
                int index = -1;
                //找是否有名字对应的同学
                String[] nameArr = new String[this.stuList.size()];
                for (int i = 0; i < this.stuList.size(); i++) {
                    nameArr[i] = this.stuList.get(i).getStuName();
                }
                System.out.println(nameArr);
                String similarWord = Search.getSimilarWord(stuName, nameArr);
                System.out.println("找到的最相似姓名:" + similarWord);
                for (int i = 0; i < stuList.size(); i++) {
                    if (Objects.equals(similarWord, stuList.get(i).getStuName())) {
                        stu = stuList.get(i);
                        index = i;
                        break;
                    }
                }
                //找不到就返回false,找到就更新数据库
                if (index == -1) {
                    String remind = "没有找到该同学";
                    System.out.println(remind);
                    return Result.error(remind);

                } else {
                    if (type == 1) {
                        this.stuList.get(index).setExamScores(score);
                        scoresService.updateExamScores(score, stu.getCsId(), stu.getLesOrd(), stu.getStuId());
                        System.out.println("更新了" + stuList.get(index).getExamScores());

                    } else if (type == 2) {
                        this.stuList.get(index).setTestScores(score);
                        scoresService.updateTestScores(score, stu.getCsId(), stu.getLesOrd(), stu.getStuId());
                        System.out.println("更新了" + stuList.get(index).getTestScores());
                    } else if (type == 3) {
                        this.stuList.get(index).setUsualScores(score);
                        scoresService.updateUsualScores(score, stu.getCsId(), stu.getLesOrd(), stu.getStuId());
                        System.out.println("更新了" + stuList.get(index).getStuName() + ":" + stuList.get(index).getUsualScores());
                    }
                    updateScores(this.stuList.get(index), scoresType);
                }
            }
        } else {
            String remind = "语音识别失败,请您重说一次";
            System.out.println(remind);
            return Result.error(remind);

        }
        return Result.OK(this.stuList);
    }

与单独录入方式不同,该方法没有可以让过程暂停的条件,所以额外添加了一个方法获取当前需要录入学生数目。

//计算学生数目,可以获取学生列表
    @ResponseBody
    @RequestMapping(value = "/ScoresStuNum")
    public Result<Integer> ScoresStuNum(@RequestParam(name = "type") int type,
                                        @RequestParam(name = "cs_id") String cs_id,
                                        @RequestParam(name = "les_ord") String les_ord) {
        int stuNum = 0;
        this.stuList = scoresService.getStuList(cs_id, les_ord);
        List<Scores> stu = new ArrayList<>();
        System.out.println(stuList);
        System.out.println("输入类型"+type);
        double s = 0.0;
        if (stuList != null) {
            if (type == 2) {
                for (int i = 0; i < stuList.size(); i++) {
                    if (stuList.get(i).getExamScores() == null||this.stuList.get(i).getExamScores() == 0) {
                        stu.add(stuList.get(i));
                        stuNum = stuNum + 1;
                    }
                }
            } else if (type == 1) {
                for (int i = 0; i < stuList.size(); i++) {
                    if (stuList.get(i).getTestScores() == null||stuList.get(i).getTestScores() == 0) {
                        stu.add(stuList.get(i));
                        stuNum = stuNum + 1;
                    }
                }
            } else if (type == 3) {
                for (int i = 0; i < stuList.size(); i++) {
                    if (stuList.get(i).getUsualScores() == null||this.stuList.get(i).getUsualScores() == 0) {
                        stu.add(stuList.get(i));
                        stuNum = stuNum + 1;
                    }
                }
            }

        } else {
            System.out.println("这门课没有学生");
        }
        System.out.println(stuNum);
        return Result.OK(stuNum);
    }

后续考虑使用该方法更倾向于是教师不需要再查找对应学生,所以不需要设置自动暂停,需要教师操作手动暂停。
前端代码如下:

voiceInputAllScores: "ScoresInput/scores/voiceInputAllScores",
ScoresStuNum: "ScoresInput/scores/ScoresStuNum",
//语音名字都由教师语音录入
    stuNameRecording: function () {
      if(this.inputState==="已提交"){
        alert("该课程成绩已提交不可进行修改");
      }else {
        if (this.voiceControllerTwo === true) {
          this.voiceControllerTwo = false;
          let output = false;
          let startVoice = "现在开始语音录入姓名和成绩,请选择录入成绩类型";
          getAction(this.url.startInputScoresVoice, {startVoice: startVoice}).then((res) => {       
            if (res.success) {
              output = res.result;
              let that = this;
              if (output === true) {
                console.log("开始提示语音播放成功");
                //弹出选择输入成绩类型
                that.dialogVisible = true;
                //等待输入类型选择
                that.waitTypeTwo = setInterval(function () {
                  if (that.dialogVisible === false) {
                    console.log("要输入的类型是" + that.type);
                    clearInterval(that.waitTypeTwo);
                    let voiceBlobFile;//录入成绩的音频文件
                    let n = 1;
                    that.inputScoresTwo = setInterval(function () {
                      let startVoice;
                      //判断合成的语音,第一次为现在开始录入
                      if (n === 1) {
                        startVoice = "现在开始录入:";
                      } else {
                        startVoice = "下个同学";
                      }
                      getAction(that.url.startInputScoresVoice, {startVoice: startVoice}).then((res) => {
                        if (res.success) {
                          Recorder.get(function (rec) {
                            recorder = rec
                            recorder.start()
                          })
                          that.getVoiceFile = setTimeout(function () {
                            voiceBlobFile = recorder.getBlob();
                            that.allScoresVoiceInput(voiceBlobFile);
                            recorder.stop()
                          }, 5000)
                          n = 2;
                          console.log("下一次语音合成" + n);
                        } else {
                          console.log("下一次语音合成错误")
                        }
                      })
                    }, 7000)
                  }
                })
              }
            }
          })
        }
      }
    },
    //三种录入类型人数统计,包括成绩为空和0的同学,后期未使用
    ScoresStuList: function (cs_id, les_ord) {
      this.stuNum = -2;
      getAction(this.url.ScoresStuNum, {type: this.type, cs_id: cs_id, les_ord: les_ord}).then((res) => {
        this.stuNum = res.result;
        console.log("获取一次学生列表");

      })
    },
    
	//传递包含姓名和成绩的音频文件
    allScoresVoiceInput: function (voiceBlobFile) {
      let formData = new FormData();
      console.log(voiceBlobFile)
      //formData=Object.assign(na,voiceBlobFilea);
      formData.append("type", this.type);
      formData.append("voiceBlobFile", voiceBlobFile);
      formData.append("scoresType", this.scoresTypeValue);
      axios.post(this.url.voiceInputAllScores, formData).then((res) => {
        if (res.result!=null) {
        //实时显示到前端
          this.superFieldList = res.result;
          this.dataSource=this.superFieldList;
          console.log("数据传输成功");
        } else {
          console.log("数据传输失败");
        }

      })
    },

录入成绩类型选择弹窗

弹窗:
不同值代表不同的录入类型,type为全局变量

<j-modal :visible="dialogVisible" title="请选择要输入成绩类型">
      <a-button @click="usualTypeDialog">平时成绩</a-button>
      <a-button @click="examTypeDialog">实验成绩</a-button>
      <a-button @click="testTypeDialog">考试成绩</a-button>
    </j-modal>

响应事件,type值更改,语音录入时会将该参数传入后台:

      //各类成绩占比
      usualPercent:0,
      testPercent:0,
 //选择成绩类型,设置成绩类型,关闭弹窗
    usualTypeDialog: function () {
      this.type = 3;
      this.dialogVisible = false;
      console.log("平时成绩" + this.type);
    },
    testTypeDialog: function () {
      this.type = 2;
      this.dialogVisible = false;
      console.log("实验成绩" + this.type);
    },
    examTypeDialog: function () {
      this.type = 1;
      this.dialogVisible = false;
      console.log("考试成绩" + this.type);
    },

停止录制按钮响应事件

将所有周期函数和延迟执行的函数暂停,将按钮恢复可以点击的状态。

 stopRecording: function () {
      recorder.stop();
      clearInterval(this.inputScores);
      clearInterval(this.waitType);
      clearInterval(this.inputScoresTwo);
      clearInterval(this.waitTypeTwo);
      console.log('已暂停');
      this.voiceController = true;
      this.voiceControllerTwo = true;
    },
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值