feat(speech): 为语音转文字接口增加VIP每日调用限制
This commit is contained in:
@@ -1,16 +1,31 @@
|
||||
package com.yolo.keyborad.controller;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import com.yolo.keyborad.common.BaseResponse;
|
||||
import com.yolo.keyborad.common.ErrorCode;
|
||||
import com.yolo.keyborad.common.ResultUtils;
|
||||
import com.yolo.keyborad.config.AppConfig;
|
||||
import com.yolo.keyborad.config.NacosAppConfigCenter;
|
||||
import com.yolo.keyborad.exception.BusinessException;
|
||||
import com.yolo.keyborad.model.entity.KeyboardUser;
|
||||
import com.yolo.keyborad.model.vo.SpeechToTextVO;
|
||||
import com.yolo.keyborad.service.DeepgramService;
|
||||
import com.yolo.keyborad.service.UserService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 语音服务控制器
|
||||
*
|
||||
@@ -22,13 +37,71 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
@Tag(name = "语音服务", description = "语音相关功能接口")
|
||||
public class SpeechController {
|
||||
|
||||
private static final String SPEECH_DAILY_LIMIT_PREFIX = "speech:daily:limit:";
|
||||
|
||||
@Resource
|
||||
private DeepgramService deepgramService;
|
||||
|
||||
@Resource
|
||||
private UserService userService;
|
||||
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
private final NacosAppConfigCenter.DynamicAppConfig cfgHolder;
|
||||
|
||||
public SpeechController(NacosAppConfigCenter.DynamicAppConfig cfgHolder) {
|
||||
this.cfgHolder = cfgHolder;
|
||||
}
|
||||
|
||||
@PostMapping("/transcribe")
|
||||
@Operation(summary = "语音转文字", description = "上传音频文件并转换为文本")
|
||||
public BaseResponse<SpeechToTextVO> transcribe(@RequestPart("file") MultipartFile file) {
|
||||
// 获取当前登录用户ID
|
||||
Long userId = StpUtil.getLoginIdAsLong();
|
||||
|
||||
// 查询用户信息
|
||||
KeyboardUser user = userService.getById(userId);
|
||||
// 获取VIP等级(null视为0)
|
||||
int vipLevel = user != null && user.getVipLevel() != null ? user.getVipLevel() : 0;
|
||||
|
||||
// vipLevel >= 2 不做限制,直接放行
|
||||
if (vipLevel < 2) {
|
||||
AppConfig appConfig = cfgHolder.getRef().get();
|
||||
String redisKey = SPEECH_DAILY_LIMIT_PREFIX + userId;
|
||||
Integer dailyLimit = appConfig.getUserRegisterProperties().getVipFreeTrialTalk();
|
||||
|
||||
// 获取当前使用次数
|
||||
String countStr = stringRedisTemplate.opsForValue().get(redisKey);
|
||||
int currentCount = countStr != null ? Integer.parseInt(countStr) : 0;
|
||||
|
||||
// 检查是否超出限制
|
||||
if (currentCount >= dailyLimit) {
|
||||
log.warn("用户 {} VIP等级 {} 已达到每日语音转文字次数限制 {}", userId, vipLevel, dailyLimit);
|
||||
throw new BusinessException(ErrorCode.VIP_TRIAL_LIMIT_REACHED);
|
||||
}
|
||||
}
|
||||
|
||||
// 调用语音转文字服务
|
||||
SpeechToTextVO result = deepgramService.transcribe(file);
|
||||
|
||||
// 成功后扣减次数(仅 vipLevel < 2 的用户)
|
||||
if (vipLevel < 2) {
|
||||
String redisKey = SPEECH_DAILY_LIMIT_PREFIX + userId;
|
||||
Long newCount = stringRedisTemplate.opsForValue().increment(redisKey);
|
||||
|
||||
// 设置到午夜过期(只有第一次设置时需要设置过期时间)
|
||||
if (newCount != null && newCount == 1) {
|
||||
LocalDateTime now = LocalDateTime.now(ZoneId.of("America/New_York"));
|
||||
LocalDateTime midnight = LocalDateTime.of(LocalDate.now(ZoneId.of("America/New_York")).plusDays(1), LocalTime.MIDNIGHT);
|
||||
long secondsUntilMidnight = ChronoUnit.SECONDS.between(now, midnight);
|
||||
stringRedisTemplate.expire(redisKey, secondsUntilMidnight, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
log.info("用户 {} VIP等级 {} 今日已使用语音转文字 {}/{} 次", userId, vipLevel, newCount,
|
||||
cfgHolder.getRef().get().getUserRegisterProperties().getVipFreeTrialTalk());
|
||||
}
|
||||
|
||||
return ResultUtils.success(result);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user