فهرست منبع

今正-豆包语音复刻计数,自动任务

lk 1 روز پیش
والد
کامیت
47bdc97071

+ 50 - 0
fs-service/src/main/java/com/fs/aiSoundReplication/mapper/VoiceCloneMapper.java

@@ -0,0 +1,50 @@
+package com.fs.aiSoundReplication.mapper;
+
+
+import com.fs.aiSoundReplication.param.TtsChargeParam;
+import org.apache.ibatis.annotations.*;
+
+import java.util.List;
+
+public interface VoiceCloneMapper {
+    // 插入
+    @Insert("INSERT INTO vc_tts_charge_count (company_id,company_user_id,qw_user_id, text, text_length, voice_url, create_time, version_id, duration,fastgpt_role_id) VALUES (#{param.companyId},#{param.companyUserId},#{param.qwUserId} ,#{param.text}, #{param.textLength}, #{param.voiceUrl}, #{param.createTime}, #{param.versionId}, #{param.duration},#{param.fastgptRoleId})")
+    int insert(@Param("param") TtsChargeParam param);
+
+    // 根据ID删除
+    @Delete("DELETE FROM vc_tts_charge_count WHERE id = #{id}")
+    int deleteById(@Param("id") Long id);
+
+    // 更新
+    @Update("UPDATE vc_tts_charge_count SET company_user_id=#{companyUserId}, text=#{text}, text_length=#{textLength}, voice_url=#{voiceUrl}, create_time=#{createTime}, version_id=#{versionId}, unit_price=#{unitPrice}, total_price=#{totalPrice}, duration=#{duration} WHERE id = #{id}")
+    int updateById(@Param("param") TtsChargeParam param);
+
+    // 根据ID查询
+    @Select("SELECT * FROM vc_tts_charge_count WHERE id = #{id}")
+    TtsChargeParam selectById(@Param("id") Long id);
+
+    // 查询所有
+    @Select("SELECT * FROM vc_tts_charge_count")
+    List<TtsChargeParam> selectAll();
+
+    // 条件查询
+    @Select("<script>" +
+            "SELECT * FROM vc_tts_charge_count WHERE 1=1" +
+            "<if test='companyUserId != null'> AND company_user_id = #{companyUserId}</if>" +
+            "<if test='versionId != null'> AND version_id = #{versionId}</if>" +
+            "</script>")
+    List<TtsChargeParam> selectByCondition(@Param("companyUserId") Long companyUserId, @Param("versionId") Integer versionId);
+
+    @Select("SELECT \n" +
+            "company_id as companyId,\n" +
+            "company_user_id as companyUserId," +
+            "qw_user_id as qwUserId," +
+            "fastgpt_role_id as fastgptRoleId," +
+            "create_time as createTime," +
+            "SUM(text_length) AS total_text_length\n" +
+            "FROM vc_tts_charge_count\n" +
+            "WHERE create_time  >= DATE_SUB(CURDATE(), INTERVAL 1 DAY)\n" +
+            "  AND create_time < CURDATE()\n" +
+            "GROUP BY company_id,company_user_id,qw_user_id,fastgpt_role_id ")
+    List<TtsChargeParam> countDailyTtsWords();
+}

+ 83 - 0
fs-service/src/main/java/com/fs/aiSoundReplication/param/TtsChargeParam.java

@@ -0,0 +1,83 @@
+package com.fs.aiSoundReplication.param;
+
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 语音合成计费参数
+ */
+@Data
+@Accessors(chain = true)
+public class TtsChargeParam {
+    /**
+     * 主键
+     */
+    private Long id;
+
+    /**
+     * 公司id
+     */
+    private Long companyId;
+    /**
+     * 销售用户id
+     */
+    private Long companyUserId;
+
+    /**
+     * 企微用户id
+     */
+    private Long qwUserId;
+
+    /**
+     * fastgpt表的roleid
+     */
+    private Long fastgptRoleId;
+    /**
+     * tts的文本
+     */
+    private String text;
+
+    /**
+     * 文本字数
+     */
+    private Integer textLength;
+
+    /**
+     * tts的音频url
+     */
+    private String voiceUrl;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 豆包版本
+     */
+    private Integer versionId;
+
+    /**
+     * 单字价格
+     */
+    private BigDecimal unitPrice;
+
+    /**
+     * 总价
+     */
+    private BigDecimal totalPrice;
+
+    /**
+     * 音频时长
+     */
+    private Integer duration;
+
+    /**
+     * 总字数
+     */
+    private Long totalTextLength;
+}

+ 7 - 1
fs-service/src/main/java/com/fs/aiSoundReplication/service/TtsService.java

@@ -2,7 +2,9 @@ package com.fs.aiSoundReplication.service;
 
 import com.fs.aiSoundReplication.param.TtsRequest;
 import com.fs.aiSoundReplication.param.TtsResponse;
+import com.fs.company.param.VcCompanyUser;
 import com.fs.fastgptApi.vo.AudioVO;
+import com.fs.qw.domain.QwUser;
 import org.springframework.core.io.Resource;
 
 import java.io.File;
@@ -50,8 +52,12 @@ public interface TtsService {
     /**
      * 批量文本转语音
      * @param texts 文本列表
-     * @param voiceType 音色ID
+//     * @param voiceType 音色ID
      * @return 音频文件列表
      */
 //    java.util.List<File> batchTextToSpeech(java.util.List<String> texts, String voiceType);
+
+    void ttsChargeByCount(VcCompanyUser vcCompanyUser, AudioVO audioVO, QwUser user);
+
+    void countDailyTtsWords();
 }

+ 66 - 4
fs-service/src/main/java/com/fs/aiSoundReplication/service/impl/TtsServiceImpl.java

@@ -1,40 +1,52 @@
 package com.fs.aiSoundReplication.service.impl;
 
 
+import cn.hutool.core.bean.BeanUtil;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fs.aiSoundReplication.config.TtsConfig;
 import com.fs.aiSoundReplication.config.VoiceCloneConfig;
 import com.fs.aiSoundReplication.exception.VoiceCloneException;
+import com.fs.aiSoundReplication.mapper.VoiceCloneMapper;
+import com.fs.aiSoundReplication.param.TtsChargeParam;
 import com.fs.aiSoundReplication.param.TtsRequest;
 import com.fs.aiSoundReplication.param.TtsResponse;
 import com.fs.aiSoundReplication.service.TtsService;
-import com.fs.fastgptApi.util.AudioUtils;
+import com.fs.company.param.VcCompanyUser;
+import com.fs.fastGpt.domain.FastgptEventLogTotal;
+import com.fs.fastGpt.mapper.FastGptRoleMapper;
+import com.fs.fastGpt.service.impl.FastgptEventLogTotalServiceImpl;
 import com.fs.fastgptApi.vo.AudioVO;
+import com.fs.qw.domain.QwUser;
+import com.fs.qw.mapper.QwUserMapper;
 import com.fs.system.oss.CloudStorageService;
 import com.fs.system.oss.OSSFactory;
 import lombok.extern.slf4j.Slf4j;
 import okhttp3.*;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.math.BigDecimal;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
-import java.util.Base64;
 
 import static com.fs.fastgptApi.util.AudioUtils.getDurations;
 import static com.fs.fastgptApi.util.AudioUtils.transferAudioSilk;
 
-@Service
+@Service("ttsService")
 @Slf4j
-public class TtsServiceImpl implements TtsService {
+public class TtsServiceImpl implements TtsService  {
 
     @Autowired
     private TtsConfig ttsConfig;
@@ -52,6 +64,12 @@ public class TtsServiceImpl implements TtsService {
 
     private static final String AUTHORIZATION_HEADER = "Authorization";
     private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
+    @Autowired
+    private VoiceCloneMapper voiceCloneMapper;
+    @Autowired
+    private FastGptRoleMapper fastGptRoleMapper;
+    @Autowired
+    private FastgptEventLogTotalServiceImpl fastgptEventLogTotalServiceImpl;
 
     @Override
     public AudioVO textToSpeech(TtsRequest request) {
@@ -95,6 +113,7 @@ public class TtsServiceImpl implements TtsService {
                 audioVO.setDuration(durations);
                 audioVO.setUrl(silkUrl);
                 audioVO.setWavUrl(wavUrl);
+                audioVO.setVoiceTxt(request.getText());
                 log.info("音频文件上传OSS成功: {}", audioVO.getUrl());
                 return audioVO;
             } finally {
@@ -111,6 +130,49 @@ public class TtsServiceImpl implements TtsService {
         }
     }
 
+    @Override
+    public void ttsChargeByCount(VcCompanyUser vcCompanyUser, AudioVO audioVO, QwUser user) {
+        try {
+            //        BigDecimal ttsCharge = getTtsCharge(texts,unitPrice); // 算钱 暂时没有确认价格,只是统计字数
+            TtsChargeParam ttsChargeParam = new TtsChargeParam();
+            ttsChargeParam.setText(audioVO.getVoiceTxt()).setTextLength(audioVO.getVoiceTxt().length()).setCreateTime(LocalDateTime.now())
+//                .setTotalPrice(ttsCharge).setUnitPrice(unitPrice)
+                    .setCompanyUserId(Long.valueOf(vcCompanyUser.getId())).setVoiceUrl(audioVO.getUrl()).setDuration(audioVO.getDuration())
+                    .setVersionId(vcCompanyUser.getVersionId());
+            if (user.getCompanyId()!=null){
+                ttsChargeParam.setCompanyId(user.getCompanyId()).setQwUserId(user.getId());
+                if (user.getFastGptRoleId()!=null){
+                    ttsChargeParam.setFastgptRoleId(user.getFastGptRoleId());
+                }
+            }
+            voiceCloneMapper.insert(ttsChargeParam);
+        }catch (Exception e){
+            log.error("豆包声音复刻计数异常",e);
+        }
+
+
+    }
+
+    @Override
+    public void countDailyTtsWords() {
+        List<TtsChargeParam> ttsChargeParams = voiceCloneMapper.countDailyTtsWords();
+        if (ttsChargeParams.isEmpty()){
+            log.info("每日统计声音复刻昨日无数据");
+            return;
+        }
+        log.info("每日统计声音复刻:"+ttsChargeParams);
+
+        ArrayList<FastgptEventLogTotal> Totals = new ArrayList<>();
+        ttsChargeParams.forEach(o->{
+            FastgptEventLogTotal bean = BeanUtil.toBean(o, FastgptEventLogTotal.class);
+            bean.setRoleId(o.getFastgptRoleId());
+            bean.setType(14);
+            bean.setCount(o.getTotalTextLength() * 450);
+            bean.setStatTime(o.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+            Totals.add(bean);
+        });
+        fastgptEventLogTotalServiceImpl.getBaseMapper().insertFastgptEventLogTotalBatch(Totals);
+    }
 //    @Override
 //    public String textToSpeech(String text, String voiceType) {
 //        // 创建简化版请求

+ 12 - 0
fs-service/src/main/java/com/fs/company/param/VcCompanyUser.java

@@ -9,6 +9,7 @@ import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
 
 import java.io.Serializable;
+import java.math.BigDecimal;
 
 /**
  * 公司用户音色表实体类
@@ -66,6 +67,17 @@ public class VcCompanyUser implements Serializable {
     @TableField("latest_text_to_speech_url")
     private String latestTextToSpeechUrl;
 
+    /**
+     * 豆包版本
+     */
+    @TableField("version_id")
+    private Integer versionId;
+
+    /**
+     * 单价
+     */
+    @TableField("unit_price")
+    private BigDecimal unitPrice;
     // 下面是可选添加的方法和字段
 
     /**

+ 1 - 2
fs-service/src/main/java/com/fs/fastGpt/service/impl/AiHookServiceImpl.java

@@ -1022,9 +1022,8 @@ public class AiHookServiceImpl implements AiHookService {
         /*判断是否走豆包语音*/
         com.alibaba.fastjson.JSONObject vcConfig = configUtil.generateConfigByKey(SysConfigEnum.VS_CONFIG.getKey());
         if (vcConfig != null && !vcConfig.isEmpty() &&
-//                !vcConfig.equals(new com.alibaba.fastjson.JSONObject()) &&
                 "2".equals(vcConfig.getString("type"))){
-            silkVoice = wxWorkService.getSilkVoiceDoubao(content, user.getCompanyUserId());
+            silkVoice = wxWorkService.getSilkVoiceDoubao(content, user.getCompanyUserId(),user);
         }else {
             silkVoice= wxWorkService.getSilkVoice(content, user.getCompanyUserId());
         }

+ 2 - 1
fs-service/src/main/java/com/fs/wxwork/service/WxWorkService.java

@@ -1,5 +1,6 @@
 package com.fs.wxwork.service;
 
+import com.fs.qw.domain.QwUser;
 import com.fs.wxwork.dto.*;
 
 import java.util.List;
@@ -239,5 +240,5 @@ public interface WxWorkService {
      */
     WxWorkResponseDTO<WxCdnUploadImgLinkResp> cdnUploadImgLink(WxCdnUploadImgLinkDTO param, Long serverId);
 
-    WxwSilkVoceDTO getSilkVoiceDoubao(String content, Long companyUserId);
+    WxwSilkVoceDTO getSilkVoiceDoubao(String content, Long companyUserId, QwUser user);
 }

+ 3 - 1
fs-service/src/main/java/com/fs/wxwork/service/WxWorkServiceImpl.java

@@ -12,6 +12,7 @@ import com.fs.company.param.VcCompanyUser;
 import com.fs.config.ai.AiHostProper;
 import com.fs.fastgptApi.vo.AudioVO;
 import com.fs.qw.domain.QwIpadServer;
+import com.fs.qw.domain.QwUser;
 import com.fs.qw.service.IQwIpadServerService;
 import com.fs.wxwork.dto.*;
 import com.fs.wxwork.utils.WxWorkHttpUtil;
@@ -368,7 +369,7 @@ public class WxWorkServiceImpl implements WxWorkService {
     }
 
     @Override
-    public WxwSilkVoceDTO getSilkVoiceDoubao(String content, Long companyUserId) {
+    public WxwSilkVoceDTO getSilkVoiceDoubao(String content, Long companyUserId, QwUser user) {
         VcCompanyUser vcCompanyUser = companyUserMapper.selectVcCompanyUserByCompanyUserId(companyUserId);
         try {
             if (vcCompanyUser == null)throw new RuntimeException("用户不存在");
@@ -386,6 +387,7 @@ public class WxWorkServiceImpl implements WxWorkService {
         data.setDuration(audioVO.getDuration());
         wxwSilkVoceDTO.setData(data);
         wxwSilkVoceDTO.setCode(200);
+        ttsServiceImpl.ttsChargeByCount(vcCompanyUser,audioVO,user);
         log.info("豆包语音生成成功,url: {}", (audioVO.getUrl()));
         return wxwSilkVoceDTO;
     }

+ 28 - 6
fs-user-app/src/main/java/com/fs/app/controller/CompanyUserController.java

@@ -49,6 +49,8 @@ import com.fs.his.service.*;
 import com.fs.his.utils.ConfigUtil;
 import com.fs.his.vo.*;
 import com.fs.hisStore.enums.SysConfigEnum;
+import com.fs.qw.domain.QwUser;
+import com.fs.qw.mapper.QwUserMapper;
 import com.fs.sop.domain.QwSopTempVoice;
 import com.fs.sop.service.IQwSopTempVoiceService;
 import com.fs.system.oss.CloudStorageService;
@@ -68,6 +70,7 @@ import org.apache.http.impl.client.HttpClients;
 import org.apache.http.util.EntityUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.mock.web.MockMultipartFile;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
@@ -82,9 +85,7 @@ import javax.sound.sampled.AudioSystem;
 import java.io.*;
 import java.net.HttpURLConnection;
 import java.net.URL;
-import java.util.List;
-import java.util.Optional;
-import java.util.UUID;
+import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
@@ -123,6 +124,9 @@ public class CompanyUserController extends AppBaseController {
     private VoiceCloneController voiceCloneController;
     @Autowired
     private TtsServiceImpl ttsServiceImpl;
+    @Qualifier("qwUserMapper")
+    @Autowired
+    private QwUserMapper qwUserMapper;
 
     @PostMapping("/login")
     public R Login(@RequestBody CompanyUserLoginParam param, HttpServletRequest request) {
@@ -318,11 +322,20 @@ public class CompanyUserController extends AppBaseController {
         if (qwSopTempVoice != null && qwSopTempVoice.getCompanyUserId() != null) {
             JSONObject vcConfig = configUtil.generateConfigByKey(SysConfigEnum.VS_CONFIG.getKey());
             if (vcConfig != null && !vcConfig.isEmpty() &&
-//                    !vcConfig.equals(new JSONObject()) &&
                     "2".equals(vcConfig.getString("type"))) {
                 VcCompanyUser vcCompanyUser = companyUserMapper.selectVcCompanyUserByCompanyUserId(companyUserId);
                 if (vcCompanyUser == null) throw new RuntimeException("用户不存在");
                 audioVO = ttsServiceImpl.textToSpeech(new TtsRequest(null, null, vcCompanyUser.getSpeakerId(), qwSopTempVoice.getVoiceTxt().replace(" ", "")));
+                QwUser qwUser = new QwUser();
+                qwUser.setCompanyUserId(companyUserId);
+                List<QwUser> qwUsers = qwUserMapper.selectQwUserList(qwUser);
+                if (qwUsers != null && !qwUsers.isEmpty()){
+                    List<QwUser> collect = qwUsers.stream().filter(o -> o.getFastGptRoleId() != null).collect(Collectors.toList());
+                    if (!collect.isEmpty()){
+                        qwUsers = collect;
+                    }
+                }else qwUsers= Collections.singletonList(new QwUser());
+                ttsServiceImpl.ttsChargeByCount(vcCompanyUser, audioVO, qwUsers.get(0));
             } else {
                 List<FastgptChatVoiceHomo> homos = fastgptChatVoiceHomoMapper.selectFastgptChatVoiceHomoList(new FastgptChatVoiceHomo());
                 audioVO = AudioUtils.createUserUrlAndUrl(homos, qwSopTempVoice.getCompanyUserId(), qwSopTempVoice.getVoiceTxt().replace(" ", ""));
@@ -363,11 +376,20 @@ public class CompanyUserController extends AppBaseController {
         if (qwSopTempVoice != null && qwSopTempVoice.getId() != null) {
             JSONObject vcConfig = configUtil.generateConfigByKey(SysConfigEnum.VS_CONFIG.getKey());
             if (vcConfig != null && !vcConfig.isEmpty() &&
-//                    !vcConfig.equals(new JSONObject()) &&
                     "2".equals(vcConfig.getString("type"))) {
                 VcCompanyUser vcCompanyUser = companyUserMapper.selectVcCompanyUserByCompanyUserId(companyUserId);
                 if (vcCompanyUser == null) throw new RuntimeException("用户不存在");
                 audioVO = ttsServiceImpl.textToSpeech(new TtsRequest(null, null, vcCompanyUser.getSpeakerId(), qwSopTempVoice.getVoiceTxt().replace(" ", "")));
+                QwUser qwUser = new QwUser();
+                qwUser.setCompanyUserId(companyUserId);
+                List<QwUser> qwUsers = qwUserMapper.selectQwUserList(qwUser);
+                if (qwUsers != null && !qwUsers.isEmpty()){
+                    List<QwUser> collect = qwUsers.stream().filter(o -> o.getFastGptRoleId() != null).collect(Collectors.toList());
+                    if (!collect.isEmpty()){
+                        qwUsers = collect;
+                    }
+                }else qwUsers= Collections.singletonList(new QwUser());
+                ttsServiceImpl.ttsChargeByCount(vcCompanyUser, audioVO, qwUsers.get(0));
             } else {
                 audioVO = AudioUtils.createVoiceUrl(qwSopTempVoice.getCompanyUserId(), userVoiceUrl);
             }
@@ -565,7 +587,7 @@ public class CompanyUserController extends AppBaseController {
         Double duration = (double) frames / format.getFrameRate();
         audioInputStream.close();
         MultipartFile convert = FileToMultipartConverterUtil.convert(file);
-        R r = voiceCloneController.uploadVoice(vcCompanyUser.getSpeakerId(), convert, 1, 0);
+        R r = voiceCloneController.uploadVoice(vcCompanyUser.getSpeakerId(), convert, vcCompanyUser.getVersionId(), 0);
         if (r.get("code") != "200")
             return AjaxResult.error("上传声纹失败", r.get("msg"));
         vcCompanyUser.incrementTimes();