| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- package com.ruoyi.cc.controller;
- import java.io.File;
- import java.util.*;
- import com.alibaba.fastjson.JSONObject;
- import com.ruoyi.aicall.domain.CcCallTask;
- import com.ruoyi.aicall.tts.aliyun.AliyunTTSWebApi;
- import com.ruoyi.aicall.tts.doubao.DoubaoTTSWebApi;
- import com.ruoyi.cc.service.ICcParamsService;
- import com.ruoyi.common.core.domain.entity.SysMenu;
- import com.ruoyi.common.utils.DateUtils;
- import com.ruoyi.common.utils.ExceptionUtil;
- import com.ruoyi.common.utils.MessageUtils;
- import com.ruoyi.common.utils.StringUtils;
- import com.ruoyi.common.utils.file.FileUtils;
- import com.ruoyi.common.utils.uuid.UuidGenerator;
- import com.ruoyi.framework.shiro.util.AuthorizationUtils;
- import org.apache.commons.io.FilenameUtils;
- import org.apache.commons.lang3.RandomStringUtils;
- import org.apache.shiro.authz.annotation.RequiresPermissions;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.ModelMap;
- import org.springframework.web.bind.annotation.*;
- import com.ruoyi.common.annotation.Log;
- import com.ruoyi.common.enums.BusinessType;
- import com.ruoyi.cc.domain.CcIvr;
- import com.ruoyi.cc.service.ICcIvrService;
- import com.ruoyi.common.core.controller.BaseController;
- import com.ruoyi.common.core.domain.AjaxResult;
- import com.ruoyi.common.utils.poi.ExcelUtil;
- import com.ruoyi.common.core.page.TableDataInfo;
- import org.springframework.web.multipart.MultipartFile;
- /**
- * IVR配置Controller
- *
- * @author ruoyi
- * @date 2025-12-19
- */
- @Controller
- @RequestMapping("/cc/ivr")
- public class CcIvrController extends BaseController
- {
- private String prefix = "cc/ivr";
- @Autowired
- private ICcIvrService ccIvrService;
- @Autowired
- private ICcParamsService ccParamsService;
- @RequiresPermissions("cc:ivr:view")
- @GetMapping()
- public String ivr()
- {
- return prefix + "/ivr";
- }
- /**
- * 查询IVR配置列表
- */
- @RequiresPermissions("cc:ivr:list")
- @PostMapping("/list")
- @ResponseBody
- public List<CcIvr> list(CcIvr ccIvr)
- {
- List<CcIvr> list = ccIvrService.selectCcIvrList(ccIvr);
- return list;
- }
- /**
- * 新增IVR配置
- */
- @GetMapping("/add/{parentId}")
- public String add(@PathVariable("parentId") String parentId, ModelMap mmap)
- {
- CcIvr ccIvr = new CcIvr();
- ccIvr.setParentNodeId(parentId);
- ccIvr.setId(UuidGenerator.GetOneUuid());
- if ("0".equals(parentId)) {
- ccIvr.setRootId(ccIvr.getId());
- } else {
- ccIvr.setRootId(ccIvrService.selectCcIvrById(parentId).getRootId());
- }
- mmap.put("ccIvr", ccIvr);
- return prefix + "/add";
- }
- /**
- * 新增保存IVR配置
- */
- @RequiresPermissions("cc:ivr:add")
- @Log(title = "IVR配置", businessType = BusinessType.INSERT)
- @PostMapping("/add")
- @ResponseBody
- public AjaxResult addSave(CcIvr ccIvr)
- {
- if ("acd".equals(ccIvr.getAction())) {
- ccIvr.setAiTransferData(ccIvr.getAiTransferGroupId());
- } else if ("extension".equals(ccIvr.getAction())) {
- ccIvr.setAiTransferData(ccIvr.getAiTransferExtNumber());
- } else if ("gateway".equals(ccIvr.getAction())) {
- JSONObject aiTransferData = new JSONObject();
- aiTransferData.put("gatewayId", ccIvr.getAiTransferGatewayId());
- aiTransferData.put("destNumber", ccIvr.getAiTransferGatewayDestNumber());
- ccIvr.setAiTransferData(JSONObject.toJSONString(aiTransferData));
- } else if ("ai".equals(ccIvr.getAction())) {
- ccIvr.setAiTransferData(ccIvr.getAiInboundId());
- }
- if ("0".equals(ccIvr.getParentNodeId()) || StringUtils.isBlank(ccIvr.getDigit())) {
- ccIvr.setDigit("-1");
- }
- return toAjax(ccIvrService.insertCcIvr(ccIvr));
- }
- /**
- * 修改IVR配置
- */
- @RequiresPermissions("cc:ivr:edit")
- @GetMapping("/edit/{id}")
- public String edit(@PathVariable("id") String id, ModelMap mmap)
- {
- CcIvr ccIvr = ccIvrService.selectCcIvrById(id);
- if ("acd".equals(ccIvr.getAction())) {
- ccIvr.setAiTransferGroupId(ccIvr.getAiTransferData());
- } else if ("extension".equals(ccIvr.getAction())) {
- ccIvr.setAiTransferExtNumber(ccIvr.getAiTransferData());
- } else if ("gateway".equals(ccIvr.getAction())) {
- if (StringUtils.isNotEmpty(ccIvr.getAiTransferData())) {
- JSONObject aiTransferData = JSONObject.parseObject(ccIvr.getAiTransferData());
- ccIvr.setAiTransferGatewayId(aiTransferData.getString("gatewayId"));
- ccIvr.setAiTransferGatewayDestNumber(aiTransferData.getString("destNumber"));
- }
- } else if ("ai".equals(ccIvr.getAction())) {
- ccIvr.setAiInboundId(ccIvr.getAiTransferData());
- }
- String recordingPath = ccParamsService.getParamValueByCode("recording_path", "/home/Records/");
- if (StringUtils.isNotEmpty(ccIvr.getTtsTextWav()) && ccIvr.getTtsTextWav().endsWith(".wav")) {
- ccIvr.setTtsTextfileUrl("recordings/files?filename=" + ccIvr.getTtsTextWav().replace(recordingPath, ""));
- }
- if (StringUtils.isNotEmpty(ccIvr.getPressKeyInvalidTipsWav()) && ccIvr.getPressKeyInvalidTipsWav().endsWith(".wav")) {
- ccIvr.setInvalidTipsfileUrl("recordings/files?filename=" + ccIvr.getPressKeyInvalidTipsWav().replace(recordingPath, ""));
- }
- if (StringUtils.isNotEmpty(ccIvr.getHangupTipsWav()) && ccIvr.getHangupTipsWav().endsWith(".wav")) {
- ccIvr.setHangupTipsfileUrl("recordings/files?filename=" + ccIvr.getHangupTipsWav().replace(recordingPath, ""));
- }
- mmap.put("ccIvr", ccIvr);
- return prefix + "/edit";
- }
- /**
- * 修改保存IVR配置
- */
- @RequiresPermissions("cc:ivr:edit")
- @Log(title = "IVR配置", businessType = BusinessType.UPDATE)
- @PostMapping("/edit")
- @ResponseBody
- public AjaxResult editSave(CcIvr ccIvr)
- {
- if ("acd".equals(ccIvr.getAction())) {
- ccIvr.setAiTransferData(ccIvr.getAiTransferGroupId());
- } else if ("extension".equals(ccIvr.getAction())) {
- ccIvr.setAiTransferData(ccIvr.getAiTransferExtNumber());
- } else if ("gateway".equals(ccIvr.getAction())) {
- JSONObject aiTransferData = new JSONObject();
- aiTransferData.put("gatewayId", ccIvr.getAiTransferGatewayId());
- aiTransferData.put("destNumber", ccIvr.getAiTransferGatewayDestNumber());
- ccIvr.setAiTransferData(JSONObject.toJSONString(aiTransferData));
- } else if ("ai".equals(ccIvr.getAction())) {
- ccIvr.setAiTransferData(ccIvr.getAiInboundId());
- }
- if ("0".equals(ccIvr.getParentNodeId())) {
- ccIvr.setDigit("-1");
- }
- return toAjax(ccIvrService.updateCcIvr(ccIvr));
- }
- /**
- * 删除
- */
- @RequiresPermissions("cc:ivr:remove")
- @Log(title = "IVR配置", businessType = BusinessType.DELETE)
- @GetMapping("/remove/{id}")
- @ResponseBody
- public AjaxResult remove(@PathVariable("id") String id)
- {
- List<CcIvr> list = ccIvrService.selectCcIvrList(new CcIvr().setParentNodeId(id));
- if (list.size() > 0) {
- return AjaxResult.error("请先删除下层节点");
- }
- return toAjax(ccIvrService.deleteCcIvrById(id));
- }
- @PostMapping("/uploadVoice")
- @ResponseBody
- public AjaxResult uploadVoice(@RequestParam("file") MultipartFile file,
- @RequestParam("rootId") String rootId) {
- try {
- if (file.isEmpty()) {
- return AjaxResult.error("文件不能为空");
- }
- String suffix = FilenameUtils.getExtension(file.getOriginalFilename()).toLowerCase();
- if (!"wav".equals(suffix)) {
- return AjaxResult.error("仅支持WAV格式文件");
- }
- long maxSize = 50 * 1024 * 1024;
- if (file.getSize() > maxSize) {
- return AjaxResult.error("文件大小不能超过50MB");
- }
- String fileName = DateUtils.format(new Date(), "yyyyMMddHHmmssSSS") + RandomStringUtils.random(3, false, true) + ".wav";
- String absolutePath = ccParamsService.getParamValueByCode("recording_path", "/home/Records/") + rootId + "/";
- File destPath = new File(absolutePath);
- destPath.mkdirs();
- File destFile = new File(absolutePath + fileName);
- file.transferTo(destFile);
- Map<String, String> result = new HashMap<>();
- result.put("fileUrl", "recordings/files?filename=" + rootId + "/" + fileName);
- result.put("filePath", absolutePath + fileName);
- result.put("originalName", file.getOriginalFilename());
- result.put("fileSize", String.valueOf(file.getSize()));
- return AjaxResult.success(result);
- } catch (Exception e) {
- logger.error("文件上传失败", e);
- return AjaxResult.error("文件上传失败:" + e.getMessage());
- }
- }
- /**
- * 校验同一层级下digit是否重复
- * @param digit 按键值
- * @param parentNodeId 父节点ID
- * @param id 当前记录ID(编辑时用于排除自身)
- * @return
- */
- @PostMapping("/checkDigit")
- @ResponseBody
- public AjaxResult checkDigit(@RequestParam String digit,
- @RequestParam String parentNodeId,
- @RequestParam(required = false) Long id) {
- // 根节点不校验
- if ("0".equals(parentNodeId)) {
- return AjaxResult.success();
- }
- boolean exists = ccIvrService.checkDigitExists(digit, parentNodeId, id);
- return exists ? AjaxResult.error("该按键值已存在") : AjaxResult.success();
- }
- @GetMapping("/all")
- @ResponseBody
- public AjaxResult all()
- {
- List<CcIvr> list = ccIvrService.selectCcIvrList(new CcIvr().setParentNodeId("0"));
- return AjaxResult.success(list);
- }
- @GetMapping("/reload")
- @ResponseBody
- public AjaxResult reload()
- {
- try {
- JSONObject reloadRsp = ccIvrService.reloadIvr();;
- if (null != reloadRsp) {
- if (reloadRsp.getBoolean("success")) {
- return AjaxResult.success(MessageUtils.message("ivr.reload.success"));
- } else {
- return AjaxResult.error(MessageUtils.message("ivr.reload.fail"));
- }
- }
- } catch (Exception e) {
- logger.error("IVR configuration reloaded failed." + ExceptionUtil.getExceptionMessage(e));
- }
- return AjaxResult.error(MessageUtils.message("ivr.reload.fail"));
- }
- @GetMapping("/tts")
- @ResponseBody
- public AjaxResult tts(@RequestParam("rootId") String rootId,
- @RequestParam(value = "voiceSource", required = false) String voiceSource,
- @RequestParam(value = "voiceCode", required = false) String voiceCode,
- @RequestParam(value = "ttsText", required = false) String ttsText)
- {
- if (StringUtils.isBlank(ttsText)) {
- return AjaxResult.error("请输入要合成的内容!");
- }
- CcIvr ccIvr = ccIvrService.selectCcIvrByRootId(rootId);
- if (null != ccIvr) {
- if (StringUtils.isBlank(voiceSource)) {
- voiceSource = ccIvr.getTtsProvider();
- }
- if (StringUtils.isBlank(voiceCode)) {
- voiceCode = ccIvr.getVoiceCode();
- }
- }
- if (null == ccIvr
- && StringUtils.isBlank(voiceSource)
- && StringUtils.isBlank(voiceCode)) {
- return AjaxResult.error("请选择音色!");
- }
- String fileName = DateUtils.format(new Date(), "yyyyMMddHHmmssSSS") + RandomStringUtils.random(3, false, true) + ".wav";
- String fileDirName = ccParamsService.getParamValueByCode("recording_path", "/home/Records/") + rootId + "/";
- File fileDir = new File(fileDirName);
- if (!fileDir.exists()) {
- fileDir.mkdirs();
- }
- String ttsPath = fileDirName + fileName;
- if ("aliyun_tts".equals(voiceSource)) {
- String aliyunTtsAccountJson = ccParamsService.getParamValueByCode("aliyun-tts-account-json", "{}");
- String appKey = JSONObject.parseObject(aliyunTtsAccountJson).getString("app_key");
- if (StringUtils.isBlank(appKey) || appKey.contains("******")) {
- return AjaxResult.error("请先配置阿里云TTS配置!");
- }
- if (AliyunTTSWebApi.shortTextTTSWebAPI(voiceCode, ttsText, ttsPath, aliyunTtsAccountJson)) {
- Map<String, String> result = new HashMap<>();
- result.put("fileUrl", "recordings/files?filename=" + rootId + "/" + fileName);
- result.put("filePath", ttsPath);
- result.put("originalName", fileName);
- return AjaxResult.success(result);
- } else {
- return AjaxResult.error("合成失败,请检查tts配置!");
- }
- } else if ("doubao_vcl_tts".equals(voiceSource)) {
- String doubaoTtsAccountJson = ccParamsService.getParamValueByCode("doubao-tts-account-json", "{}");
- String accessToken = JSONObject.parseObject(doubaoTtsAccountJson).getString("access_token");
- if (StringUtils.isBlank(accessToken) || accessToken.contains("******")) {
- return AjaxResult.error("请先配置豆包TTS配置!");
- }
- if (DoubaoTTSWebApi.shortTextTTSWebAPI(voiceCode, ttsText, ttsPath, doubaoTtsAccountJson)) {
- Map<String, String> result = new HashMap<>();
- result.put("fileUrl", "recordings/files?filename=" + rootId + "/" + fileName);
- result.put("filePath", ttsPath);
- result.put("originalName", fileName);
- return AjaxResult.success(result);
- } else {
- return AjaxResult.error("合成失败,请检查tts配置!");
- }
- } else {
- return AjaxResult.error("暂不支持该tts厂商的IVR语音在线合成!");
- }
- }
- }
|