mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-22 07:03:53 +08:00
Merge branch 'main' into manger-api-flashily
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
package xiaozhi.modules.agent.controller;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import xiaozhi.common.constant.Constant;
|
||||
import xiaozhi.common.page.PageData;
|
||||
import xiaozhi.common.user.UserDetail;
|
||||
import xiaozhi.common.utils.ConvertUtils;
|
||||
import xiaozhi.common.utils.Result;
|
||||
import xiaozhi.modules.agent.dto.AgentCreateDTO;
|
||||
import xiaozhi.modules.agent.dto.AgentUpdateDTO;
|
||||
import xiaozhi.modules.agent.entity.AgentEntity;
|
||||
import xiaozhi.modules.agent.service.AgentService;
|
||||
import xiaozhi.modules.security.user.SecurityUser;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Tag(name = "智能体管理")
|
||||
@AllArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/agent")
|
||||
public class AgentController {
|
||||
private final AgentService agentService;
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获取用户智能体列表")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
public Result<List<AgentEntity>> getUserAgents() {
|
||||
UserDetail user = SecurityUser.getUser();
|
||||
List<AgentEntity> agents = agentService.getUserAgents(user.getId());
|
||||
return new Result<List<AgentEntity>>().ok(agents);
|
||||
}
|
||||
|
||||
@GetMapping("/all")
|
||||
@Operation(summary = "智能体列表(管理员)")
|
||||
@RequiresPermissions("sys:role:superAdmin")
|
||||
@Parameters({
|
||||
@Parameter(name = Constant.PAGE, description = "当前页码,从1开始", required = true),
|
||||
@Parameter(name = Constant.LIMIT, description = "每页显示记录数", required = true),
|
||||
})
|
||||
public Result<PageData<AgentEntity>> adminAgentList(
|
||||
@Parameter(hidden = true) @RequestParam Map<String, Object> params) {
|
||||
PageData<AgentEntity> page = agentService.adminAgentList(params);
|
||||
return new Result<PageData<AgentEntity>>().ok(page);
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
@Operation(summary = "获取智能体详情")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
public Result<AgentEntity> getAgentById(@PathVariable("id") String id) {
|
||||
AgentEntity agent = agentService.getAgentById(id);
|
||||
return new Result<AgentEntity>().ok(agent);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@Operation(summary = "创建智能体")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
public Result<Void> save(@RequestBody @Valid AgentCreateDTO dto) {
|
||||
AgentEntity entity = ConvertUtils.sourceToTarget(dto, AgentEntity.class);
|
||||
|
||||
// 设置用户ID和创建者信息
|
||||
UserDetail user = SecurityUser.getUser();
|
||||
entity.setUserId(user.getId());
|
||||
entity.setCreator(user.getId());
|
||||
entity.setCreatedAt(new Date());
|
||||
|
||||
// ID、智能体编码和排序会在Service层自动生成
|
||||
agentService.insert(entity);
|
||||
|
||||
return new Result<>();
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
@Operation(summary = "更新智能体")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
public Result<Void> update(@RequestBody @Valid AgentUpdateDTO dto) {
|
||||
// 先查询现有实体
|
||||
AgentEntity existingEntity = agentService.getAgentById(dto.getId());
|
||||
if (existingEntity == null) {
|
||||
return new Result<Void>().error("智能体不存在");
|
||||
}
|
||||
|
||||
// 只更新提供的非空字段
|
||||
if (dto.getAgentName() != null) {
|
||||
existingEntity.setAgentName(dto.getAgentName());
|
||||
}
|
||||
if (dto.getAgentCode() != null) {
|
||||
existingEntity.setAgentCode(dto.getAgentCode());
|
||||
}
|
||||
if (dto.getAsrModelId() != null) {
|
||||
existingEntity.setAsrModelId(dto.getAsrModelId());
|
||||
}
|
||||
if (dto.getVadModelId() != null) {
|
||||
existingEntity.setVadModelId(dto.getVadModelId());
|
||||
}
|
||||
if (dto.getLlmModelId() != null) {
|
||||
existingEntity.setLlmModelId(dto.getLlmModelId());
|
||||
}
|
||||
if (dto.getTtsModelId() != null) {
|
||||
existingEntity.setTtsModelId(dto.getTtsModelId());
|
||||
}
|
||||
if (dto.getTtsVoiceId() != null) {
|
||||
existingEntity.setTtsVoiceId(dto.getTtsVoiceId());
|
||||
}
|
||||
if (dto.getMemModelId() != null) {
|
||||
existingEntity.setMemModelId(dto.getMemModelId());
|
||||
}
|
||||
if (dto.getIntentModelId() != null) {
|
||||
existingEntity.setIntentModelId(dto.getIntentModelId());
|
||||
}
|
||||
if (dto.getSystemPrompt() != null) {
|
||||
existingEntity.setSystemPrompt(dto.getSystemPrompt());
|
||||
}
|
||||
if (dto.getLangCode() != null) {
|
||||
existingEntity.setLangCode(dto.getLangCode());
|
||||
}
|
||||
if (dto.getLanguage() != null) {
|
||||
existingEntity.setLanguage(dto.getLanguage());
|
||||
}
|
||||
if (dto.getSort() != null) {
|
||||
existingEntity.setSort(dto.getSort());
|
||||
}
|
||||
|
||||
// 设置更新者信息
|
||||
UserDetail user = SecurityUser.getUser();
|
||||
existingEntity.setUpdater(user.getId());
|
||||
existingEntity.setUpdatedAt(new Date());
|
||||
|
||||
agentService.updateById(existingEntity);
|
||||
|
||||
return new Result<>();
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
@Operation(summary = "删除智能体")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
public Result<Void> delete(@PathVariable String id) {
|
||||
agentService.deleteById(id);
|
||||
return new Result<>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package xiaozhi.modules.agent.dao;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import xiaozhi.common.dao.BaseDao;
|
||||
import xiaozhi.modules.agent.entity.AgentEntity;
|
||||
|
||||
@Mapper
|
||||
public interface AgentDao extends BaseDao<AgentEntity> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package xiaozhi.modules.agent.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 智能体创建DTO
|
||||
* 专用于新增智能体,不包含id、agentCode和sort字段,这些字段由系统自动生成/设置默认值
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "智能体创建对象")
|
||||
public class AgentCreateDTO implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "智能体名称", example = "客服助手")
|
||||
@NotBlank(message = "智能体名称不能为空")
|
||||
private String agentName;
|
||||
|
||||
@Schema(description = "语音识别模型标识", example = "asr_model_01")
|
||||
private String asrModelId;
|
||||
|
||||
@Schema(description = "语音活动检测标识", example = "vad_model_01")
|
||||
private String vadModelId;
|
||||
|
||||
@Schema(description = "大语言模型标识", example = "llm_model_01")
|
||||
private String llmModelId;
|
||||
|
||||
@Schema(description = "语音合成模型标识", example = "tts_model_01")
|
||||
private String ttsModelId;
|
||||
|
||||
@Schema(description = "音色标识", example = "voice_01")
|
||||
private String ttsVoiceId;
|
||||
|
||||
@Schema(description = "记忆模型标识", example = "mem_model_01")
|
||||
private String memModelId;
|
||||
|
||||
@Schema(description = "意图模型标识", example = "intent_model_01")
|
||||
private String intentModelId;
|
||||
|
||||
@Schema(description = "角色设定参数", example = "你是一个专业的客服助手,负责回答用户问题")
|
||||
private String systemPrompt;
|
||||
|
||||
@Schema(description = "语言编码", example = "zh_CN")
|
||||
private String langCode;
|
||||
|
||||
@Schema(description = "交互语种", example = "中文")
|
||||
private String language;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package xiaozhi.modules.agent.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 智能体更新DTO
|
||||
* 专用于更新智能体,id字段是必需的,用于标识要更新的智能体
|
||||
* 其他字段均为非必填,只更新提供的字段
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "智能体更新对象")
|
||||
public class AgentUpdateDTO implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "智能体唯一标识", example = "a1b2c3d4e5f6", required = true)
|
||||
@NotBlank(message = "智能体ID不能为空")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "智能体编码", example = "AGT_1234567890", required = false)
|
||||
private String agentCode;
|
||||
|
||||
@Schema(description = "智能体名称", example = "客服助手", required = false)
|
||||
private String agentName;
|
||||
|
||||
@Schema(description = "语音识别模型标识", example = "asr_model_02", required = false)
|
||||
private String asrModelId;
|
||||
|
||||
@Schema(description = "语音活动检测标识", example = "vad_model_02", required = false)
|
||||
private String vadModelId;
|
||||
|
||||
@Schema(description = "大语言模型标识", example = "llm_model_02", required = false)
|
||||
private String llmModelId;
|
||||
|
||||
@Schema(description = "语音合成模型标识", example = "tts_model_02", required = false)
|
||||
private String ttsModelId;
|
||||
|
||||
@Schema(description = "音色标识", example = "voice_02", required = false)
|
||||
private String ttsVoiceId;
|
||||
|
||||
@Schema(description = "记忆模型标识", example = "mem_model_02", required = false)
|
||||
private String memModelId;
|
||||
|
||||
@Schema(description = "意图模型标识", example = "intent_model_02", required = false)
|
||||
private String intentModelId;
|
||||
|
||||
@Schema(description = "角色设定参数", example = "你是一个专业的客服助手,负责回答用户问题并提供帮助", required = false)
|
||||
private String systemPrompt;
|
||||
|
||||
@Schema(description = "语言编码", example = "zh_CN", required = false)
|
||||
private String langCode;
|
||||
|
||||
@Schema(description = "交互语种", example = "中文", required = false)
|
||||
private String language;
|
||||
|
||||
@Schema(description = "排序", example = "1", required = false)
|
||||
private Integer sort;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package xiaozhi.modules.agent.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@TableName("ai_agent")
|
||||
@Schema(description = "智能体信息")
|
||||
public class AgentEntity {
|
||||
@Schema(description = "智能体唯一标识")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "所属用户ID")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "智能体编码")
|
||||
private String agentCode;
|
||||
|
||||
@Schema(description = "智能体名称")
|
||||
private String agentName;
|
||||
|
||||
@Schema(description = "语音识别模型标识")
|
||||
private String asrModelId;
|
||||
|
||||
@Schema(description = "语音活动检测标识")
|
||||
private String vadModelId;
|
||||
|
||||
@Schema(description = "大语言模型标识")
|
||||
private String llmModelId;
|
||||
|
||||
@Schema(description = "语音合成模型标识")
|
||||
private String ttsModelId;
|
||||
|
||||
@Schema(description = "音色标识")
|
||||
private String ttsVoiceId;
|
||||
|
||||
@Schema(description = "记忆模型标识")
|
||||
private String memModelId;
|
||||
|
||||
@Schema(description = "意图模型标识")
|
||||
private String intentModelId;
|
||||
|
||||
@Schema(description = "角色设定参数")
|
||||
private String systemPrompt;
|
||||
|
||||
@Schema(description = "语言编码")
|
||||
private String langCode;
|
||||
|
||||
@Schema(description = "交互语种")
|
||||
private String language;
|
||||
|
||||
@Schema(description = "排序")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "创建者")
|
||||
private Long creator;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private Date createdAt;
|
||||
|
||||
@Schema(description = "更新者")
|
||||
private Long updater;
|
||||
|
||||
@Schema(description = "更新时间")
|
||||
private Date updatedAt;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package xiaozhi.modules.agent.service;
|
||||
|
||||
import xiaozhi.common.page.PageData;
|
||||
import xiaozhi.common.service.BaseService;
|
||||
import xiaozhi.modules.agent.entity.AgentEntity;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface AgentService extends BaseService<AgentEntity> {
|
||||
/**
|
||||
* 根据用户ID获取智能体列表
|
||||
*/
|
||||
List<AgentEntity> getUserAgents(Long userId);
|
||||
|
||||
/**
|
||||
* 管理员获取所有智能体列表(分页)
|
||||
*/
|
||||
PageData<AgentEntity> adminAgentList(Map<String, Object> params);
|
||||
|
||||
/**
|
||||
* 获取智能体详情
|
||||
*/
|
||||
AgentEntity getAgentById(String id);
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package xiaozhi.modules.agent.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.springframework.stereotype.Service;
|
||||
import xiaozhi.common.page.PageData;
|
||||
import xiaozhi.common.service.impl.BaseServiceImpl;
|
||||
import xiaozhi.modules.agent.dao.AgentDao;
|
||||
import xiaozhi.modules.agent.entity.AgentEntity;
|
||||
import xiaozhi.modules.agent.service.AgentService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> implements AgentService {
|
||||
private final AgentDao agentDao;
|
||||
|
||||
public AgentServiceImpl(AgentDao agentDao) {
|
||||
this.agentDao = agentDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AgentEntity> getUserAgents(Long userId) {
|
||||
QueryWrapper<AgentEntity> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq("user_id", userId);
|
||||
return agentDao.selectList(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageData<AgentEntity> adminAgentList(Map<String, Object> params) {
|
||||
IPage<AgentEntity> page = agentDao.selectPage(
|
||||
getPage(params, "sort", true),
|
||||
new QueryWrapper<>()
|
||||
);
|
||||
return new PageData<>(page.getRecords(), page.getTotal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AgentEntity getAgentById(String id) {
|
||||
return agentDao.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(AgentEntity entity) {
|
||||
// 如果ID为空,自动生成一个UUID作为ID
|
||||
if (entity.getId() == null || entity.getId().trim().isEmpty()) {
|
||||
entity.setId(UUID.randomUUID().toString().replace("-", ""));
|
||||
}
|
||||
|
||||
// 如果智能体编码为空,自动生成一个带前缀的编码
|
||||
if (entity.getAgentCode() == null || entity.getAgentCode().trim().isEmpty()) {
|
||||
entity.setAgentCode("AGT_" + System.currentTimeMillis());
|
||||
}
|
||||
|
||||
// 如果排序字段为空,设置默认值0
|
||||
if (entity.getSort() == null) {
|
||||
entity.setSort(0);
|
||||
}
|
||||
|
||||
return super.insert(entity);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -117,8 +117,8 @@ public class ModelConfigServiceImpl extends BaseServiceImpl<ModelConfigDao, Mode
|
||||
return null;
|
||||
}
|
||||
ModelConfigEntity modelConfigEntity = modelConfigEntities.get(0);
|
||||
Long id = Long.valueOf(modelConfigEntity.getId());
|
||||
String id = modelConfigEntity.getId();
|
||||
|
||||
return timbreService.getVoiceNames(String.valueOf(id), voiceName);
|
||||
return timbreService.getVoiceNames(id, voiceName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,22 +39,22 @@ class AccessToken:
|
||||
'Version': '2019-02-28'}
|
||||
# 构造规范化的请求字符串
|
||||
query_string = AccessToken._encode_dict(parameters)
|
||||
print('规范化的请求字符串: %s' % query_string)
|
||||
# print('规范化的请求字符串: %s' % query_string)
|
||||
# 构造待签名字符串
|
||||
string_to_sign = 'GET' + '&' + AccessToken._encode_text('/') + '&' + AccessToken._encode_text(query_string)
|
||||
print('待签名的字符串: %s' % string_to_sign)
|
||||
# print('待签名的字符串: %s' % string_to_sign)
|
||||
# 计算签名
|
||||
secreted_string = hmac.new(bytes(access_key_secret + '&', encoding='utf-8'),
|
||||
bytes(string_to_sign, encoding='utf-8'),
|
||||
hashlib.sha1).digest()
|
||||
signature = base64.b64encode(secreted_string)
|
||||
print('签名: %s' % signature)
|
||||
# print('签名: %s' % signature)
|
||||
# 进行URL编码
|
||||
signature = AccessToken._encode_text(signature)
|
||||
print('URL编码后的签名: %s' % signature)
|
||||
# print('URL编码后的签名: %s' % signature)
|
||||
# 调用服务
|
||||
full_url = 'http://nls-meta.cn-shanghai.aliyuncs.com/?Signature=%s&%s' % (signature, query_string)
|
||||
print('url: %s' % full_url)
|
||||
# print('url: %s' % full_url)
|
||||
# 提交HTTP GET请求
|
||||
response = requests.get(full_url)
|
||||
if response.ok:
|
||||
@@ -64,7 +64,7 @@ class AccessToken:
|
||||
token = root_obj[key]['Id']
|
||||
expire_time = root_obj[key]['ExpireTime']
|
||||
return token, expire_time
|
||||
print(response.text)
|
||||
# print(response.text)
|
||||
return None, None
|
||||
|
||||
|
||||
@@ -75,37 +75,80 @@ class TTSProvider(TTSProviderBase):
|
||||
super().__init__(config, delete_audio_file)
|
||||
|
||||
# 新增空值判断逻辑
|
||||
access_key_id = config.get("access_key_id")
|
||||
access_key_secret = config.get("access_key_secret")
|
||||
if access_key_id and access_key_secret:
|
||||
# 使用密钥对生成临时token
|
||||
token, expire_time = AccessToken.create_token(access_key_id, access_key_secret)
|
||||
else:
|
||||
# 直接使用预生成的长期token
|
||||
token = config.get("token")
|
||||
expire_time = None
|
||||
|
||||
print('token: %s, expire time(s): %s' % (token, expire_time))
|
||||
self.access_key_id = config.get("access_key_id")
|
||||
self.access_key_secret = config.get("access_key_secret")
|
||||
|
||||
self.appkey = config.get("appkey")
|
||||
self.token = token
|
||||
self.format = config.get("format", "wav")
|
||||
self.sample_rate = config.get("sample_rate", 16000)
|
||||
self.voice = config.get("voice", "xiaoyun")
|
||||
self.volume = config.get("volume", 50)
|
||||
self.speech_rate = config.get("speech_rate", 0)
|
||||
self.pitch_rate = config.get("pitch_rate", 0)
|
||||
|
||||
self.host = config.get("host", "nls-gateway-cn-shanghai.aliyuncs.com")
|
||||
self.api_url = f"https://{self.host}/stream/v1/tts"
|
||||
self.header = {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
if self.access_key_id and self.access_key_secret:
|
||||
# 使用密钥对生成临时token
|
||||
self._refresh_token()
|
||||
else:
|
||||
# 直接使用预生成的长期token
|
||||
self.token = config.get("token")
|
||||
self.expire_time = None
|
||||
|
||||
|
||||
def _refresh_token(self):
|
||||
"""刷新Token并记录过期时间"""
|
||||
if self.access_key_id and self.access_key_secret:
|
||||
self.token, expire_time_str = AccessToken.create_token(
|
||||
self.access_key_id,
|
||||
self.access_key_secret
|
||||
)
|
||||
if not expire_time_str:
|
||||
raise ValueError("无法获取有效的Token过期时间")
|
||||
|
||||
try:
|
||||
#统一转换为字符串处理
|
||||
expire_str = str(expire_time_str).strip()
|
||||
|
||||
if expire_str.isdigit():
|
||||
expire_time = datetime.fromtimestamp(int(expire_str))
|
||||
else:
|
||||
expire_time = datetime.strptime(
|
||||
expire_str,
|
||||
"%Y-%m-%dT%H:%M:%SZ"
|
||||
)
|
||||
self.expire_time = expire_time.timestamp() - 60
|
||||
except Exception as e:
|
||||
raise ValueError(f"无效的过期时间格式: {expire_str}") from e
|
||||
|
||||
else:
|
||||
self.expire_time = None
|
||||
|
||||
if not self.token:
|
||||
raise ValueError("无法获取有效的访问Token")
|
||||
|
||||
def _is_token_expired(self):
|
||||
"""检查Token是否过期"""
|
||||
if not self.expire_time:
|
||||
return False # 长期Token不过期
|
||||
# 新增调试日志
|
||||
# current_time = time.time()
|
||||
# remaining = self.expire_time - current_time
|
||||
# print(f"Token过期检查: 当前时间 {datetime.fromtimestamp(current_time)} | "
|
||||
# f"过期时间 {datetime.fromtimestamp(self.expire_time)} | "
|
||||
# f"剩余 {remaining:.2f}秒")
|
||||
return time.time() > self.expire_time
|
||||
def generate_filename(self, extension=".wav"):
|
||||
return os.path.join(self.output_file, f"tts-{__name__}{datetime.now().date()}@{uuid.uuid4().hex}{extension}")
|
||||
|
||||
async def text_to_speak(self, text, output_file):
|
||||
if self._is_token_expired():
|
||||
logger.warning("Token已过期,正在自动刷新...")
|
||||
self._refresh_token()
|
||||
request_json = {
|
||||
"appkey": self.appkey,
|
||||
"token": self.token,
|
||||
@@ -118,9 +161,12 @@ class TTSProvider(TTSProviderBase):
|
||||
"pitch_rate": self.pitch_rate
|
||||
}
|
||||
|
||||
print(self.api_url, json.dumps(request_json, ensure_ascii=False))
|
||||
# print(self.api_url, json.dumps(request_json, ensure_ascii=False))
|
||||
try:
|
||||
resp = requests.post(self.api_url, json.dumps(request_json), headers=self.header)
|
||||
if resp.status_code == 401: # Token过期特殊处理
|
||||
self._refresh_token()
|
||||
resp = requests.post(self.api_url, json.dumps(request_json), headers=self.header)
|
||||
# 检查返回请求数据的mime类型是否是audio/***,是则保存到指定路径下;返回的是binary格式的
|
||||
if resp.headers['Content-Type'].startswith('audio/'):
|
||||
with open(output_file, 'wb') as f:
|
||||
|
||||
Reference in New Issue
Block a user