update:整合现有版本

This commit is contained in:
hrz
2025-03-29 17:06:53 +08:00
parent 2988e5eef2
commit b63fcc80a1
69 changed files with 979 additions and 2471 deletions
@@ -1,46 +0,0 @@
package xiaozhi.common.controller;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Enumeration;
import java.util.HashMap;
public class BaseController {
@Autowired
protected HttpServletRequest request;
/**
* 获取请求头
*
* @return
*/
protected HashMap<String, String> getRequestHeaders() {
HashMap<String, String> requestHeaders = new HashMap<String, String>();
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
String headerValue = request.getHeader(headerName);
requestHeaders.put(headerName, headerValue);
}
return requestHeaders;
}
/**
* 获取请求参数
*
* @return
*/
protected HashMap<String, String> getRequestParams() {
HashMap<String, String> requestParams = new HashMap<String, String>();
Enumeration<String> paramNames = request.getParameterNames();
while (paramNames.hasMoreElements()) {
String paramName = paramNames.nextElement();
String paramValue = request.getParameter(paramName);
requestParams.put(paramName, paramValue);
}
return requestParams;
}
}
@@ -1,17 +1,17 @@
package xiaozhi.common.convert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
/**
* 日期转换
* Copyright (c) 人人开源 All rights reserved.
@@ -1,287 +1,158 @@
package xiaozhi.modules.agent.controller;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.*;
import xiaozhi.common.controller.BaseController;
import xiaozhi.common.redis.RedisUtils;
import xiaozhi.common.user.UserDetail;
import xiaozhi.common.utils.Result;
import xiaozhi.modules.agent.domain.Agent;
import xiaozhi.modules.agent.domain.AgentTemplate;
import xiaozhi.modules.agent.service.AgentService;
import xiaozhi.modules.agent.service.AgentTemplateService;
import xiaozhi.modules.agent.vo.AgentVO;
import xiaozhi.modules.device.domain.Device;
import xiaozhi.modules.device.service.DeviceService;
import xiaozhi.modules.model.domain.ModelConfig;
import xiaozhi.modules.model.domain.TtsVoice;
import xiaozhi.modules.model.service.ModelConfigService;
import xiaozhi.modules.model.service.TtsVoiceService;
import xiaozhi.modules.security.user.SecurityUser;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.Map;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
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 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;
@Slf4j
@Tag(name = "智能体管理")
@AllArgsConstructor
@RestController
@RequestMapping("/user/agent")
public class AgentController extends BaseController {
@RequestMapping("/agent")
public class AgentController {
private final AgentService agentService;
private final AgentTemplateService agentTemplateService;
private final ModelConfigService modelConfigService;
private final TtsVoiceService ttsVoiceService;
private final DeviceService deviceService;
private final RedisUtils redisUtils;
@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 = "添加智能体")
@Operation(summary = "创建智能体")
@RequiresPermissions("sys:role:normal")
public Result<Agent> addAgent(@RequestBody Agent agent) {
public Result<Void> save(@RequestBody @Valid AgentCreateDTO dto) {
AgentEntity entity = ConvertUtils.sourceToTarget(dto, AgentEntity.class);
// 设置用户ID和创建者信息
UserDetail user = SecurityUser.getUser();
if (StringUtils.isBlank(agent.getAgentName())) {
log.error("智能体名称不能为空");
}
Agent oldAgent = agentService.getOne(new QueryWrapper<Agent>().eq("agent_name", agent.getAgentName()));
if (ObjectUtils.isNull(oldAgent)) {
AgentTemplate agentTemplate = agentTemplateService.getOne(new QueryWrapper<AgentTemplate>().eq("is_default", 1));
if (ObjectUtils.isNull(agentTemplate)) {
entity.setUserId(user.getId());
entity.setCreator(user.getId());
entity.setCreatedAt(new Date());
} else {
try {
oldAgent = new Agent();
BeanUtils.copyProperties(oldAgent, agentTemplate);
oldAgent.setId(UUID.randomUUID().toString().replace("-", ""));
oldAgent.setAgentName(agent.getAgentName());
oldAgent.setUserId(user.getId());
oldAgent.setCreator(user.getId());
oldAgent.setCreatedAt(new Date());
agentService.save(oldAgent);
} catch (Exception e) {
log.error("对象赋值异常", e);
}
}
} else {
// ID、智能体编码和排序会在Service层自动生成
agentService.insert(entity);
}
return new Result<Agent>().ok(agent);
return new Result<>();
}
@PutMapping("{agentId}")
@PutMapping
@Operation(summary = "更新智能体")
@RequiresPermissions("sys:role:normal")
public Result<Agent> updateAgent(@PathVariable String agentId, @RequestBody Agent agent) {
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();
if (StringUtils.isBlank(agentId)) {
log.error("智能体ID不能为空");
return new Result<Agent>().error("更新失败,智能体ID不能为空");
}
Agent oldAgent = agentService.getById(agentId);
if (ObjectUtils.isNull(oldAgent)) {
log.error("智能体不存在");
return new Result<Agent>().error("更新失败,智能体不存在");
} else {
UpdateWrapper<Agent> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("id", agentId);
updateWrapper.set("agent_code", agent.getAgentCode());
updateWrapper.set("asr_model_id", agent.getAsrModelId());
updateWrapper.set("intent_model_id", agent.getIntentModelId());
updateWrapper.set("llm_model_id", agent.getLlmModelId());
updateWrapper.set("memory_model_id", agent.getMemoryModelId());
updateWrapper.set("system_prompt", agent.getSystemPrompt());
updateWrapper.set("tts_voice_id", agent.getTtsVoiceId());
updateWrapper.set("tts_model_id", agent.getTtsModelId());
updateWrapper.set("vad_model_id", agent.getVadModelId());
updateWrapper.set("updater", user.getId());
updateWrapper.set("updated_at", new Date());
boolean bool = agentService.update(updateWrapper);
if (!bool)
return new Result<Agent>().error("更新失败");
}
return new Result<Agent>().ok(agent);
existingEntity.setUpdater(user.getId());
existingEntity.setUpdatedAt(new Date());
agentService.updateById(existingEntity);
return new Result<>();
}
@DeleteMapping("/{agentId}")
@DeleteMapping("/{id}")
@Operation(summary = "删除智能体")
@RequiresPermissions("sys:role:normal")
public Result<Agent> delAgent(@PathVariable String agentId) {
UserDetail user = SecurityUser.getUser();
if (StringUtils.isBlank(agentId)) {
log.error("智能体ID不能为空");
}
boolean bool = agentService.removeById(agentId);
if (!bool) {
return new Result<Agent>().error("删除失败");
}
return new Result<Agent>().ok(null);
}
@GetMapping("/{agentId}")
@Operation(summary = "获取智能体信息")
@RequiresPermissions("sys:role:normal")
public Result<Agent> getAgent(@PathVariable String agentId) {
if (StringUtils.isBlank(agentId)) {
log.error("智能体ID不能为空");
}
Agent agent = agentService.getById(agentId);
return new Result<Agent>().ok(agent);
}
@GetMapping
@Operation(summary = "智能体列表")
@RequiresPermissions("sys:role:normal")
public Result<List<AgentVO>> agentList() {
UserDetail user = SecurityUser.getUser();
List<Agent> agents = agentService.list(new QueryWrapper<Agent>().eq("user_id", user.getId()));
List<AgentVO> list = new ArrayList<>();
this.convertAgentVOList(list, agents);
return new Result<List<AgentVO>>().ok(list);
}
@GetMapping("/loadAgentConfig/{deviceId}")
@Operation(summary = "下载智能体配置")
public Result<JSONObject> loadAgentConfig(@PathVariable String deviceId) {
Device device = deviceService.getOne(new QueryWrapper<Device>().eq("mac_address", deviceId.toUpperCase()));
if (ObjectUtils.isNull(device)) {
return new Result<JSONObject>().error("设备不存在");
}
Agent agent = agentService.getOne(new QueryWrapper<Agent>().eq("id", device.getAgentId()));
if (ObjectUtils.isNull(agent)) {
return new Result<JSONObject>().error("智能体不存在");
}
JSONObject jsonObject = new JSONObject();
jsonObject.set("prompt", agent.getSystemPrompt().replace("{{assistant_name}}", agent.getAgentCode()));
jsonObject.set("owner", String.valueOf(agent.getUserId()));
ModelConfig asrModel = modelConfigService.getById(agent.getAsrModelId());
jsonObject.set("ASR", JSONUtil.parseObj(asrModel.getConfigJson()));
ModelConfig llmModel = modelConfigService.getById(agent.getLlmModelId());
jsonObject.set("LLM", JSONUtil.parseObj(llmModel.getConfigJson()));
ModelConfig ttsModel = modelConfigService.getById(agent.getTtsModelId());
JSONObject ttsJson = JSONUtil.parseObj(ttsModel.getConfigJson());
TtsVoice ttsVoice = ttsVoiceService.getById(agent.getTtsVoiceId());
ttsJson.getJSONObject(ttsModel.getModelCode()).set("voice", ttsVoice.getTtsVoice());
jsonObject.set("TTS", ttsJson);
ModelConfig vadModel = modelConfigService.getById(agent.getVadModelId());
jsonObject.set("VAD", JSONUtil.parseObj(vadModel.getConfigJson()));
ModelConfig intentModel = modelConfigService.getById(agent.getIntentModelId());
jsonObject.set("Intent", JSONUtil.parseObj(intentModel.getConfigJson()));
ModelConfig memoryModel = modelConfigService.getById(agent.getMemoryModelId());
jsonObject.set("Memory", JSONUtil.parseObj(memoryModel.getConfigJson()));
JSONObject module = new JSONObject();
module.set("ASR", asrModel.getModelCode());
module.set("LLM", llmModel.getModelCode());
module.set("TTS", ttsModel.getModelCode());
module.set("Intent", intentModel.getModelCode());
module.set("Memory", memoryModel.getModelCode());
module.set("VAD", vadModel.getModelCode());
jsonObject.set("selected_module", module);
return new Result<JSONObject>().ok(jsonObject);
// String json = "{\n" +
// " \"ASR\": {\n" +
// " \"FunASR\": {\n" +
// " \"model_dir\": \"models/SenseVoiceSmall\",\n" +
// " \"output_dir\": \"tmp/\",\n" +
// " \"type\": \"fun_local\"\n" +
// " }\n" +
// " },\n" +
// " \"LLM\": {\n" +
// " \"ChatGLMLLM\": {\n" +
// " \"api_key\": \"0415dad4014847babc3e3f03024c50a3.qH7FgTy5Yawc85fl\",\n" +
// " \"model_name\": \"glm-4-flash\",\n" +
// " \"type\": \"openai\",\n" +
// " \"url\": \"https://open.bigmodel.cn/api/paas/v4/\"\n" +
// " }\n" +
// " },\n" +
// " \"TTS\": {\n" +
// " \"DoubaoTTS\": {\n" +
// " \"access_token\": \"hrnx22F9WutWBm7YJzE62r_Z1myUmHEL\",\n" +
// " \"api_url\": \"https://openspeech.bytedance.com/api/v1/tts\",\n" +
// " \"appid\": \"6295576095\",\n" +
// " \"authorization\": \"Bearer;\",\n" +
// " \"cluster\": \"volcano_tts\",\n" +
// " \"output_dir\": \"tmp/\",\n" +
// " \"type\": \"doubao\",\n" +
// " \"voice\": \"BV034_streaming\"\n" +
// " }\n" +
// " },\n" +
// " \"VAD\": {\n" +
// " \"SileroVAD\": {\n" +
// " \"min_silence_duration_ms\": 700,\n" +
// " \"model_dir\": \"models/snakers4_silero-vad\",\n" +
// " \"threshold\": 0.5\n" +
// " }\n" +
// " },\n" +
// " \"auth_code\": \"642365\",\n" +
// " \"prompt\": \"你是一个叫小优的女孩,来自优享生活公司的AI智能体,声音好听,习惯简短表达,爱用网络梗。\\n请注意,要像一个人一样说话,请不要回复表情符号、代码、和xml标签。\\n现在我正在和你进行语音聊天,我们开始吧。\\n如果用户希望结束对话,请在最后说“拜拜”或“再见”。\\n\",\n" +
// " \"selected_module\": {\n" +
// " \"ASR\": \"FunASR\",\n" +
// " \"Intent\": \"function_call\",\n" +
// " \"LLM\": \"ChatGLMLLM\",\n" +
// " \"Memory\": \"mem0ai\",\n" +
// " \"TTS\": \"DoubaoTTS\",\n" +
// " \"VAD\": \"SileroVAD\"\n" +
// " },\n" +
// " \"owner\":\"18600806164\"\n" +
// "}";
//
// return new Result<JSONObject>().ok(new JSONObject(json));
}
/**
* 将Agent对象列表转换为AgentVO对象列表
* 此方法遍历Agent对象列表,将每个Agent对象转换为AgentVO对象,并添加到AgentVO列表中
*
* @param agentVOList 转换后的AgentVO对象列表
* @param agentList 原始的Agent对象列表
*/
private void convertAgentVOList(List<AgentVO> agentVOList, List<Agent> agentList) {
// 遍历Agent对象列表
for (Agent agent : agentList) {
// 创建一个新的AgentVO对象
AgentVO agentVO = new AgentVO();
// 将当前Agent对象的属性值转换并设置到AgentVO对象中
this.convertAgentVO(agentVO, agent);
// 将转换后的AgentVO对象添加到AgentVO列表中
agentVOList.add(agentVO);
}
}
private void convertAgentVO(AgentVO agentVO, Agent agent) {
try {
BeanUtils.copyProperties(agentVO, agent);
agentVO.setTtsModelName("未知");
TtsVoice ttsVoice = ttsVoiceService.getOne(new QueryWrapper<TtsVoice>().eq("id", agent.getTtsVoiceId()));
if (ObjectUtils.isNotNull(ttsVoice)) {
agentVO.setTtsModelName(ttsVoice.getName());
}
agentVO.setLlmModelName("未知");
ModelConfig modelConfig = modelConfigService.getOne(new QueryWrapper<ModelConfig>().eq("id", agent.getLlmModelId()));
if (ObjectUtils.isNotNull(modelConfig)) {
agentVO.setLlmModelName(modelConfig.getModelName());
}
agentVO.setLastConnectedAt("今天");
agentVO.setDeviceCount(0L);
long deviceCount = deviceService.count(new QueryWrapper<Device>().eq("agent_id", agent.getId()));
agentVO.setDeviceCount(deviceCount);
} catch (Exception e) {
log.error("[convertAgentVO]对象转换报错", e);
}
public Result<Void> delete(@PathVariable String id) {
agentService.deleteById(id);
return new Result<>();
}
}
@@ -1,131 +1,37 @@
package xiaozhi.modules.agent.controller;
import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.*;
import xiaozhi.common.controller.BaseController;
import xiaozhi.common.user.UserDetail;
import xiaozhi.common.utils.Result;
import xiaozhi.modules.agent.domain.AgentTemplate;
import xiaozhi.modules.agent.entity.AgentTemplateEntity;
import xiaozhi.modules.agent.service.AgentTemplateService;
import xiaozhi.modules.agent.vo.AgentTemplateVO;
import xiaozhi.modules.model.domain.ModelConfig;
import xiaozhi.modules.model.domain.TtsVoice;
import xiaozhi.modules.model.service.ModelConfigService;
import xiaozhi.modules.model.service.TtsVoiceService;
import xiaozhi.modules.security.user.SecurityUser;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
@Slf4j
@Tag(name = "智能体模板管理")
@AllArgsConstructor
@RestController
@RequestMapping("/user/agent/template")
public class AgentTemplateController extends BaseController {
public class AgentTemplateController {
private final AgentTemplateService agentTemplateService;
private final ModelConfigService modelConfigService;
private final TtsVoiceService ttsVoiceService;
@PostMapping
@Operation(summary = "添加智能体模板")
@RequiresPermissions("sys:role:superAdmin")
public Result<AgentTemplate> addTemplate(@RequestBody AgentTemplate agentTemplate) {
UserDetail user = SecurityUser.getUser();
if (StringUtils.isBlank(agentTemplate.getAgentName())) {
log.error("智能体模板名称不能为空");
}
try {
agentTemplate = new AgentTemplate();
agentTemplate.setId(UUID.randomUUID().toString().replace("-", ""));
agentTemplate.setAgentName(agentTemplate.getAgentName());
agentTemplate.setCreator(user.getId());
agentTemplate.setCreatedAt(new Date());
agentTemplateService.save(agentTemplate);
} catch (Exception e) {
log.error("对象赋值异常", e);
}
return new Result<AgentTemplate>().ok(agentTemplate);
}
@DeleteMapping("/{templateId}")
@Operation(summary = "删除智能体模板")
@RequiresPermissions("sys:role:superAdmin")
public Result<AgentTemplate> delTemplate(@PathVariable String templateId) {
UserDetail user = SecurityUser.getUser();
if (StringUtils.isBlank(templateId)) {
log.error("智能体模板ID不能为空");
}
boolean bool = agentTemplateService.removeById(templateId);
if (!bool) {
return new Result<AgentTemplate>().error("删除失败");
}
return new Result<AgentTemplate>().ok(null);
}
@GetMapping
@Operation(summary = "智能体模板模板列表")
@RequiresPermissions("sys:role:normal")
public Result<List<AgentTemplate>> templateList() {
List<AgentTemplate> list = agentTemplateService.list(new QueryWrapper<AgentTemplate>().orderByAsc("sort"));
return new Result<List<AgentTemplate>>().ok(list);
public Result<List<AgentTemplateEntity>> templateList() {
List<AgentTemplateEntity> list = agentTemplateService
.list(new QueryWrapper<AgentTemplateEntity>().orderByAsc("sort"));
return new Result<List<AgentTemplateEntity>>().ok(list);
}
@GetMapping("/vo")
@Operation(summary = "智能体模板模板列表")
@RequiresPermissions("sys:role:normal")
public Result<List<AgentTemplateVO>> templateVOList() {
UserDetail user = SecurityUser.getUser();
List<AgentTemplate> templates = agentTemplateService.list();
List<AgentTemplateVO> list = new ArrayList<>();
this.convertAgentTemplateVOList(list, templates);
return new Result<List<AgentTemplateVO>>().ok(list);
}
/**
* 将Agent对象列表转换为AgentTemplateVO对象列表
* 此方法遍历Agent对象列表,将每个Agent对象转换为AgentTemplateVO对象,并添加到AgentTemplateVO列表中
*
* @param agentVOList 转换后的AgentTemplateVO对象列表
* @param agentList 原始的Agent对象列表
*/
private void convertAgentTemplateVOList(List<AgentTemplateVO> agentVOList, List<AgentTemplate> agentList) {
// 遍历Agent对象列表
for (AgentTemplate agentTemplate : agentList) {
// 创建一个新的AgentTemplateVO对象
AgentTemplateVO agentTemplateVO = new AgentTemplateVO();
// 将当前Agent对象的属性值转换并设置到AgentTemplateVO对象中
this.convertAgentTemplateVO(agentTemplateVO, agentTemplate);
// 将转换后的AgentTemplateVO对象添加到AgentTemplateVO列表中
agentVOList.add(agentTemplateVO);
}
}
private void convertAgentTemplateVO(AgentTemplateVO agentTemplateVO, AgentTemplate agentTemplate) {
try {
BeanUtils.copyProperties(agentTemplateVO, agentTemplate);
agentTemplateVO.setTtsModelName("未知");
TtsVoice ttsVoice = ttsVoiceService.getOne(new QueryWrapper<TtsVoice>().eq("id", agentTemplate.getTtsVoiceId()));
if (ObjectUtils.isNotNull(ttsVoice)) {
agentTemplateVO.setTtsModelName(ttsVoice.getName());
}
agentTemplateVO.setLlmModelName("未知");
ModelConfig modelConfig = modelConfigService.getOne(new QueryWrapper<ModelConfig>().eq("id", agentTemplate.getLlmModelId()));
if (ObjectUtils.isNotNull(modelConfig)) {
agentTemplateVO.setLlmModelName(modelConfig.getModelName());
}
} catch (Exception e) {
log.error("[convertAgentTemplateVO]对象转换报错", e);
}
}
}
@@ -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> {
}
@@ -1,17 +1,17 @@
package xiaozhi.modules.agent.mapper;
package xiaozhi.modules.agent.dao;
import org.apache.ibatis.annotations.Mapper;
import xiaozhi.modules.agent.domain.AgentTemplate;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import xiaozhi.modules.agent.entity.AgentTemplateEntity;
/**
* @author chenerlei
* @description 针对表ai_agent_template(智能体配置模板表)的数据库操作Mapper
* @createDate 2025-03-22 11:48:18
* @Entity xiaozhi.modules.agent.domain.AgentTemplate
*/
@Mapper
public interface AgentTemplateMapper extends BaseMapper<AgentTemplate> {
public interface AgentTemplateDao extends BaseMapper<AgentTemplateEntity> {
}
@@ -1,116 +0,0 @@
package xiaozhi.modules.agent.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
* 智能体配置表
* @TableName ai_agent
*/
@TableName(value ="ai_agent")
@Data
public class Agent implements Serializable {
/**
* 智能体唯一标识
*/
@TableId
private String id;
/**
* 所属用户 ID
*/
private Long userId;
/**
* 智能体编码
*/
private String agentCode;
/**
* 智能体名称
*/
private String agentName;
/**
* 语音识别模型标识
*/
private String asrModelId;
/**
* 语音活动检测标识
*/
private String vadModelId;
/**
* 大语言模型标识
*/
private String llmModelId;
/**
* 语音合成模型标识
*/
private String ttsModelId;
/**
* 音色标识
*/
private String ttsVoiceId;
/**
* 记忆模型标识
*/
private String memoryModelId;
/**
* 意图模型标识
*/
private String intentModelId;
/**
* 角色设定参数
*/
private String systemPrompt;
/**
* 语言编码
*/
private String langCode;
/**
* 交互语种
*/
private String language;
/**
* 排序权重
*/
private Integer sort;
/**
* 创建者 ID
*/
private Long creator;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新者 ID
*/
private Long updater;
/**
* 更新时间
*/
private Date updatedAt;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}
@@ -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;
}
@@ -1,6 +1,5 @@
package xiaozhi.modules.agent.domain;
package xiaozhi.modules.agent.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@@ -14,7 +13,7 @@ import lombok.Data;
*/
@TableName(value ="ai_agent_template")
@Data
public class AgentTemplate implements Serializable {
public class AgentTemplateEntity implements Serializable {
/**
* 智能体唯一标识
*/
@@ -1,20 +0,0 @@
package xiaozhi.modules.agent.mapper;
import org.apache.ibatis.annotations.Mapper;
import xiaozhi.modules.agent.domain.Agent;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author chenerlei
* @description 针对表【ai_agent(智能体配置表)】的数据库操作Mapper
* @createDate 2025-03-22 11:48:18
* @Entity xiaozhi.modules.agent.domain.Agent
*/
@Mapper
public interface AgentMapper extends BaseMapper<Agent> {
}
@@ -1,13 +1,25 @@
package xiaozhi.modules.agent.service;
import xiaozhi.modules.agent.domain.Agent;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author chenerlei
* @description 针对表【ai_agent(智能体配置表)】的数据库操作Service
* @createDate 2025-03-22 11:48:18
*/
public interface AgentService extends IService<Agent> {
}
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);
}
@@ -1,13 +1,14 @@
package xiaozhi.modules.agent.service;
import xiaozhi.modules.agent.domain.AgentTemplate;
import xiaozhi.modules.agent.entity.AgentTemplateEntity;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author chenerlei
* @description 针对表【ai_agent_template(智能体配置模板表)】的数据库操作Service
* @createDate 2025-03-22 11:48:18
*/
public interface AgentTemplateService extends IService<AgentTemplate> {
* @author chenerlei
* @description 针对表【ai_agent_template(智能体配置模板表)】的数据库操作Service
* @createDate 2025-03-22 11:48:18
*/
public interface AgentTemplateService extends IService<AgentTemplateEntity> {
}
@@ -1,22 +1,65 @@
package xiaozhi.modules.agent.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import xiaozhi.modules.agent.domain.Agent;
import xiaozhi.modules.agent.service.AgentService;
import xiaozhi.modules.agent.mapper.AgentMapper;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.springframework.stereotype.Service;
/**
* @author chenerlei
* @description 针对表【ai_agent(智能体配置表)】的数据库操作Service实现
* @createDate 2025-03-22 11:48:18
*/
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
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;
@Service
public class AgentServiceImpl extends ServiceImpl<AgentMapper, Agent>
implements AgentService{
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);
}
}
@@ -1,22 +1,20 @@
package xiaozhi.modules.agent.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import xiaozhi.modules.agent.domain.AgentTemplate;
import xiaozhi.modules.agent.service.AgentTemplateService;
import xiaozhi.modules.agent.mapper.AgentTemplateMapper;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import xiaozhi.modules.agent.dao.AgentTemplateDao;
import xiaozhi.modules.agent.entity.AgentTemplateEntity;
import xiaozhi.modules.agent.service.AgentTemplateService;
/**
* @author chenerlei
* @description 针对表【ai_agent_template(智能体配置模板表)】的数据库操作Service实现
* @createDate 2025-03-22 11:48:18
*/
* @author chenerlei
* @description 针对表【ai_agent_template(智能体配置模板表)】的数据库操作Service实现
* @createDate 2025-03-22 11:48:18
*/
@Service
public class AgentTemplateServiceImpl extends ServiceImpl<AgentTemplateMapper, AgentTemplate>
implements AgentTemplateService{
public class AgentTemplateServiceImpl extends ServiceImpl<AgentTemplateDao, AgentTemplateEntity>
implements AgentTemplateService {
}
@@ -1,17 +0,0 @@
package xiaozhi.modules.agent.vo;
import cn.hutool.json.JSONObject;
import lombok.Data;
@Data
public class AgentConfigVO {
private JSONObject selected_module;
private String prompt;
private JSONObject LLM;
private JSONObject TTS;
private JSONObject ASR;
private JSONObject VAD;
private JSONObject Memory;
private JSONObject Intent;
private String owner;
}
@@ -1,14 +1,13 @@
package xiaozhi.modules.agent.vo;
import lombok.Data;
import xiaozhi.modules.agent.domain.Agent;
import xiaozhi.modules.agent.domain.AgentTemplate;
import xiaozhi.modules.agent.entity.AgentTemplateEntity;
@Data
public class AgentTemplateVO extends AgentTemplate {
//角色音色
public class AgentTemplateVO extends AgentTemplateEntity {
// 角色音色
private String ttsModelName;
//角色模型
// 角色模型
private String llmModelName;
}
@@ -1,19 +0,0 @@
package xiaozhi.modules.agent.vo;
import lombok.Data;
import xiaozhi.modules.agent.domain.Agent;
@Data
public class AgentVO extends Agent {
//角色音色
private String ttsModelName;
//角色明星
private String llmModelName;
//最近对话
private String lastConnectedAt;
//设备数量
private Long deviceCount;
}
@@ -1,7 +0,0 @@
package xiaozhi.modules.device.constant;
public class DeviceConstant {
public static final String REDIS_KEY_PREFIX_DEVICE_ACTIVATION_CODE = "device:activation:code";
public static final String REDIS_KEY_PREFIX_DEVICE_ACTIVATION_MAC = "device:activation:mac";
}
@@ -1,173 +1,82 @@
package xiaozhi.modules.device.controller;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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 lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.*;
import xiaozhi.common.controller.BaseController;
import xiaozhi.common.constant.Constant;
import xiaozhi.common.exception.ErrorCode;
import xiaozhi.common.page.PageData;
import xiaozhi.common.redis.RedisKeys;
import xiaozhi.common.redis.RedisUtils;
import xiaozhi.common.user.UserDetail;
import xiaozhi.common.utils.JsonUtils;
import xiaozhi.common.utils.Result;
import xiaozhi.modules.agent.domain.Agent;
import xiaozhi.modules.agent.service.AgentService;
import xiaozhi.modules.device.constant.DeviceConstant;
import xiaozhi.modules.device.domain.Device;
import xiaozhi.modules.device.dto.DeviceHeaderDTO;
import xiaozhi.modules.device.dto.DeviceUnBindDTO;
import xiaozhi.modules.device.entity.DeviceEntity;
import xiaozhi.modules.device.service.DeviceService;
import xiaozhi.modules.device.vo.DeviceCodeVO;
import xiaozhi.modules.security.user.SecurityUser;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Slf4j
@Tag(name = "设备管理")
@AllArgsConstructor
@RestController
@RequestMapping("/user/agent/device")
public class DeviceController extends BaseController {
private final AgentService agentService;
@RequestMapping("/device")
public class DeviceController {
private final DeviceService deviceService;
private final RedisUtils redisUtils;
@GetMapping("/bind/{agentId}")
@Operation(summary = "已绑定设备列表")
@RequiresPermissions("sys:role:normal")
public Result<Page<Device>> bindDeviceList(@PathVariable String agentId, @RequestParam Integer pageNo, @RequestParam Integer pageSize) {
if (StringUtils.isBlank(agentId)) {
log.error("智能体ID不能为空");
return new Result().error("智能体ID不能为空");
}
UserDetail user = SecurityUser.getUser();
Agent agent = agentService.getById(agentId);
if (ObjectUtils.isNull(agent)) {
log.error("智能体不存在");
return new Result().error("智能体不存在");
}
Page page = new Page<Device>(pageNo, pageSize);
page = deviceService.page(page, new QueryWrapper<Device>().eq("user_id", user.getId()).eq("agent_id", agentId));
return new Result<Page<Device>>().ok(page);
}
@PostMapping("/bind/{agentId}")
@PostMapping("/bind/{deviceCode}")
@Operation(summary = "绑定设备")
@RequiresPermissions("sys:role:normal")
public Result<Device> bindDevice(@PathVariable String agentId, @RequestBody DeviceCodeVO deviceCodeVO) {
if (ObjectUtils.isNull(deviceCodeVO) || StringUtils.isBlank(deviceCodeVO.getDeviceCode())) {
log.error("授权码不能为空");
return new Result().error("授权码不能为空");
}
if (StringUtils.isBlank(agentId)) {
log.error("智能体ID不能为空");
return new Result().error("智能体ID不能为空");
}
public Result<DeviceEntity> bindDevice(@PathVariable String deviceCode) {
UserDetail user = SecurityUser.getUser();
// 从 Redis 中获取设备信息
Object redisValue = redisUtils.hGet(DeviceConstant.REDIS_KEY_PREFIX_DEVICE_ACTIVATION_CODE, deviceCodeVO.getDeviceCode());
if (ObjectUtils.isNull(redisValue)) {
log.error("授权码不存在:{}", deviceCodeVO.getDeviceCode());
return new Result().error("授权码不存在");
String deviceHeaders = (String) redisUtils.get(RedisKeys.getDeviceCaptchaKey(deviceCode));
if (StringUtils.isBlank(deviceHeaders)) {
return new Result<DeviceEntity>().error(ErrorCode.DEVICE_CAPTCHA_ERROR);
}
JSONObject jsonObject = (JSONObject) redisValue;
try {
redisUtils.hDel(DeviceConstant.REDIS_KEY_PREFIX_DEVICE_ACTIVATION_CODE, deviceCodeVO.getDeviceCode());
redisUtils.hDel(DeviceConstant.REDIS_KEY_PREFIX_DEVICE_ACTIVATION_MAC, jsonObject.getStr("mac_address").toUpperCase());
} catch (Exception e) {
log.warn("授权缓存删除失败", e);
}
JSONObject board = jsonObject.getJSONObject("board");
JSONObject application = jsonObject.getJSONObject("application");
if (ObjectUtils.isNull(board) || ObjectUtils.isNull(application)) {
log.error("设备码绑定信息无效,{}:{}", jsonObject.getStr("mac_address").toUpperCase(), deviceCodeVO.getDeviceCode());
return new Result().error("设备码绑定信息无效");
}
Agent agent = agentService.getById(agentId);
if (ObjectUtils.isNull(agent)) {
log.error("智能体不存在");
return new Result().error("智能体不存在");
}
Device device = new Device();
device.setId(jsonObject.getStr("uuid").replace("-", ""));
device.setUserId(user.getId());
device.setMacAddress(jsonObject.getStr("mac_address").toUpperCase());
device.setBoard(board.getStr("type"));
device.setAppVersion(application.getStr("version"));
device.setAgentId(agentId);
device.setCreator(user.getId());
device.setCreateDate(new Date());
device.setAutoUpdate(1);
boolean bool = deviceService.save(device);
if (!bool) {
return new Result().error("绑定失败");
}
return new Result<Device>().ok(device);
DeviceHeaderDTO deviceHeader = JsonUtils.parseObject(deviceHeaders.getBytes(), DeviceHeaderDTO.class);
DeviceEntity device = deviceService.bindDevice(user.getId(), deviceHeader);
return new Result<DeviceEntity>().ok(device);
}
@PutMapping("/unbind/{deviceId}")
@GetMapping("/bind")
@Operation(summary = "获取已绑定设备")
@RequiresPermissions("sys:role:normal")
public Result<List<DeviceEntity>> getUserDevices() {
UserDetail user = SecurityUser.getUser();
List<DeviceEntity> devices = deviceService.getUserDevices(user.getId());
return new Result<List<DeviceEntity>>().ok(devices);
}
@PostMapping("/unbind")
@Operation(summary = "解绑设备")
@RequiresPermissions("sys:role:normal")
public Result<Device> bindDevice(@PathVariable String deviceId) {
if (StringUtils.isBlank(deviceId)) {
log.error("设备ID不能为空");
return new Result().error("设备ID不能为空");
}
boolean bool = deviceService.removeById(deviceId);
if (!bool) {
return new Result().error("解绑失败");
}
return new Result<Device>().ok(null);
public Result unbindDevice(@RequestBody DeviceUnBindDTO unDeviveBind) {
UserDetail user = SecurityUser.getUser();
deviceService.unbindDevice(user.getId(), unDeviveBind.getDeviceId());
return new Result();
}
@PostMapping("/autoUpdate/{deviceId}")
@Operation(summary = "切换设备OTA升级状态")
@RequiresPermissions("sys:role:normal")
public Result<Device> toggleAutoUpdate(@PathVariable String deviceId, @RequestBody Device device) {
if (StringUtils.isBlank(deviceId)) {
log.error("设备ID不能为空");
return new Result().error("设备ID不能为空");
}
UserDetail user = SecurityUser.getUser();
boolean bool = deviceService.update(
new UpdateWrapper<Device>().eq("id", deviceId)
.set("auto_update", device.getAutoUpdate())
.set("updater", user.getId())
.set("update_date", new Date())
);
if (!bool) {
return new Result<Device>().error("切换设备OTA升级状态失败");
}
return new Result<Device>().ok(null);
}
@PostMapping("/alias/{deviceId}")
@Operation(summary = "设置设备别名")
@RequiresPermissions("sys:role:normal")
public Result<Device> setAlias(@PathVariable String deviceId, @RequestBody Device device) {
if (StringUtils.isBlank(deviceId)) {
log.error("设备ID不能为空");
return new Result().error("设备ID不能为空");
}
UserDetail user = SecurityUser.getUser();
boolean bool = deviceService.update(
new UpdateWrapper<Device>().eq("id", deviceId)
.set("alias", device.getAlias())
.set("updater", user.getId())
.set("update_date", new Date())
);
if (!bool) {
return new Result<Device>().error("设置设备别名失败");
}
return new Result<Device>().ok(null);
@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<DeviceEntity>> adminDeviceList(
@Parameter(hidden = true) @RequestParam Map<String, Object> params) {
PageData<DeviceEntity> page = deviceService.adminDeviceList(params);
return new Result<PageData<DeviceEntity>>().ok(page);
}
}
@@ -0,0 +1,9 @@
package xiaozhi.modules.device.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import xiaozhi.modules.device.entity.DeviceEntity;
@Mapper
public interface DeviceDao extends BaseMapper<DeviceEntity> {
}
@@ -1,91 +0,0 @@
package xiaozhi.modules.device.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
* 设备信息表
* @TableName ai_device
*/
@TableName(value ="ai_device")
@Data
public class Device implements Serializable {
/**
* 设备唯一标识
*/
@TableId
private String id;
/**
* 关联用户 ID
*/
private Long userId;
/**
* MAC 地址
*/
private String macAddress;
/**
* 最后连接时间
*/
private Date lastConnectedAt;
/**
* 自动更新开关(0 关闭/1 开启)
*/
private Integer autoUpdate;
/**
* 设备硬件型号
*/
private String board;
/**
* 设备别名
*/
private String alias;
/**
* 智能体 ID
*/
private String agentId;
/**
* 固件版本号
*/
private String appVersion;
/**
* 排序
*/
private Integer sort;
/**
* 创建者
*/
private Long creator;
/**
* 创建时间
*/
private Date createDate;
/**
* 更新者
*/
private Long updater;
/**
* 更新时间
*/
private Date updateDate;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}
@@ -0,0 +1,19 @@
package xiaozhi.modules.device.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
@Schema(description = "设备连接头信息")
public class DeviceHeaderDTO {
@Schema(description = "设备ID")
private String deviceId;
@Schema(description = "协议版本号")
private Long protocolVersion;
@Schema(description = "认证信息")
private String authorization;
}
@@ -0,0 +1,19 @@
package xiaozhi.modules.device.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import java.io.Serializable;
/**
* 设备解绑表单
*/
@Data
@Schema(description = "设备解绑表单")
public class DeviceUnBindDTO implements Serializable {
@Schema(description = "设备ID")
@NotBlank(message = "设备ID不能为空")
private Long deviceId;
}
@@ -0,0 +1,54 @@
package xiaozhi.modules.device.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_device")
@Schema(description = "设备信息")
public class DeviceEntity {
@Schema(description = "设备ID")
private Long id;
@Schema(description = "关联用户ID")
private Long userId;
@Schema(description = "MAC地址")
private String macAddress;
@Schema(description = "最后连接时间")
private Date lastConnectedAt;
@Schema(description = "自动更新开关(0关闭/1开启)")
private Integer autoUpdate;
@Schema(description = "设备硬件型号")
private String board;
@Schema(description = "设备别名")
private String alias;
@Schema(description = "智能体ID")
private String agentId;
@Schema(description = "固件版本号")
private String appVersion;
@Schema(description = "排序")
private Integer sort;
@Schema(description = "创建者")
private Long creator;
@Schema(description = "创建时间")
private Date createDate;
@Schema(description = "更新者")
private Long updater;
@Schema(description = "更新时间")
private Date updateDate;
}
@@ -1,20 +0,0 @@
package xiaozhi.modules.device.mapper;
import org.apache.ibatis.annotations.Mapper;
import xiaozhi.modules.device.domain.Device;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author chenerlei
* @description 针对表【ai_device(设备信息表)】的数据库操作Mapper
* @createDate 2025-03-22 13:26:35
* @Entity xiaozhi.modules.device.domain.Device
*/
@Mapper
public interface DeviceMapper extends BaseMapper<Device> {
}
@@ -1,13 +1,19 @@
package xiaozhi.modules.device.service;
import xiaozhi.modules.device.domain.Device;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author chenerlei
* @description 针对表【ai_device(设备信息表)】的数据库操作Service
* @createDate 2025-03-22 13:26:35
*/
public interface DeviceService extends IService<Device> {
}
package xiaozhi.modules.device.service;
import xiaozhi.common.page.PageData;
import xiaozhi.common.service.BaseService;
import xiaozhi.modules.device.dto.DeviceHeaderDTO;
import xiaozhi.modules.device.entity.DeviceEntity;
import java.util.List;
import java.util.Map;
public interface DeviceService extends BaseService<DeviceEntity> {
DeviceEntity bindDevice(Long userId, DeviceHeaderDTO deviceHeader);
List<DeviceEntity> getUserDevices(Long userId);
void unbindDevice(Long userId, Long deviceId);
PageData<DeviceEntity> adminDeviceList(Map<String, Object> params);
}
@@ -1,22 +1,57 @@
package xiaozhi.modules.device.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import xiaozhi.modules.device.domain.Device;
import xiaozhi.modules.device.service.DeviceService;
import xiaozhi.modules.device.mapper.DeviceMapper;
import org.springframework.stereotype.Service;
/**
* @author chenerlei
* @description 针对表【ai_device(设备信息表)】的数据库操作Service实现
* @createDate 2025-03-22 13:26:35
*/
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device>
implements DeviceService{
}
package xiaozhi.modules.device.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.device.dao.DeviceDao;
import xiaozhi.modules.device.dto.DeviceHeaderDTO;
import xiaozhi.modules.device.entity.DeviceEntity;
import xiaozhi.modules.device.service.DeviceService;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Service
public class DeviceServiceImpl extends BaseServiceImpl<DeviceDao, DeviceEntity> implements DeviceService {
private final DeviceDao deviceDao;
// 添加构造函数来初始化 deviceMapper
public DeviceServiceImpl(DeviceDao deviceDao) {
this.deviceDao = deviceDao;
}
@Override
public DeviceEntity bindDevice(Long userId, DeviceHeaderDTO deviceHeader) {
DeviceEntity device = new DeviceEntity();
device.setUserId(userId);
device.setMacAddress(deviceHeader.getDeviceId());
device.setCreateDate(new Date());
deviceDao.insert(device);
return device;
}
@Override
public List<DeviceEntity> getUserDevices(Long userId) {
QueryWrapper<DeviceEntity> wrapper = new QueryWrapper<>();
wrapper.eq("user_id", userId);
return deviceDao.selectList(wrapper);
}
@Override
public void unbindDevice(Long userId, Long deviceId) {
deviceDao.deleteById(deviceId);
}
@Override
public PageData<DeviceEntity> adminDeviceList(Map<String, Object> params) {
IPage<DeviceEntity> page = deviceDao.selectPage(
getPage(params, "sort", true),
new QueryWrapper<>()
);
return new PageData<>(page.getRecords(), page.getTotal());
}
}
@@ -1,68 +0,0 @@
package xiaozhi.modules.device.utils;
import java.util.Random;
public class CodeGeneratorUtil {
private static long lastTime = 0;
private static int counter = 0;
/**
* 生成6位数字码,首位不为0,短期内不会重复。
* @return 6位数字码
*/
public static synchronized String generateCode() {
long currentTime = System.currentTimeMillis();
// 如果当前时间与上次相同,增加计数器以避免重复
if (currentTime == lastTime) {
counter++;
} else {
counter = 0; // 时间变化时重置计数器
}
lastTime = currentTime;
// 使用当前时间和计数器生成随机种子
long seed = currentTime + counter;
Random random = new Random(seed);
// 确保首位不为0
int firstDigit = random.nextInt(9) + 1;
int remainingDigits = random.nextInt(100000); // 剩余5位
// 拼接生成的6位数字码
return String.format("%d%05d", firstDigit, remainingDigits);
}
/**
* 生成指定位数的数字码,首位不为0,短期内不会重复。
* @param digits 生成的数字码位数
* @return 指定位数的数字码
*/
public static synchronized String generateCode(int digits) {
if (digits < 2) {
throw new IllegalArgumentException("数字码位数必须大于等于2");
}
long currentTime = System.currentTimeMillis();
// 如果当前时间与上次相同,增加计数器以避免重复
if (currentTime == lastTime) {
counter++;
} else {
counter = 0; // 时间变化时重置计数器
}
lastTime = currentTime;
// 使用当前时间和计数器生成随机种子
long seed = currentTime + counter;
Random random = new Random(seed);
// 确保首位不为0
int firstDigit = random.nextInt(9) + 1;
int remainingDigits = random.nextInt((int) Math.pow(10, digits - 1)); // 剩余位数
// 拼接生成的动态位数数字码
return String.format("%d%0" + (digits - 1) + "d", firstDigit, remainingDigits);
}
}
@@ -1,8 +0,0 @@
package xiaozhi.modules.device.vo;
import lombok.Data;
@Data
public class DeviceCodeVO {
private String deviceCode;
}
@@ -1,106 +0,0 @@
package xiaozhi.modules.model.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.*;
import xiaozhi.common.page.PageData;
import xiaozhi.common.utils.Result;
import xiaozhi.modules.model.dto.ModelConfigBodyDTO;
import xiaozhi.modules.model.dto.ModelConfigDTO;
import xiaozhi.modules.model.dto.ModelProviderDTO;
import xiaozhi.modules.model.service.Conflict_ModelConfigService;
import xiaozhi.modules.model.service.Conflict_ModelProviderService;
import java.util.List;
@AllArgsConstructor
@RestController
@RequestMapping("/models")
@Tag(name = "模型配置")
public class Conflict_ModelController {
private final Conflict_ModelProviderService modelProviderService;
private final Conflict_ModelConfigService modelConfigService;
@GetMapping("/models/names")
@Operation(summary = "获取所有模型名称")
@RequiresPermissions("sys:role:superAdmin")
public Result<List<String>> getModelNames(@RequestParam String modelType,
@RequestParam(required = false) String modelName) {
List<String> modelNameList = modelConfigService.getModelCodeList(modelType, modelName);
return new Result<List<String>>().ok(modelNameList);
}
@GetMapping("/{modelType}/provideTypes")
@Operation(summary = "获取模型供应器列表")
@RequiresPermissions("sys:role:superAdmin")
public Result<List<ModelProviderDTO>> getModelProviderList(@PathVariable String modelType) {
List<ModelProviderDTO> modelProviderDTOS = modelProviderService.getListByModelType(modelType);
return new Result<List<ModelProviderDTO>>().ok(modelProviderDTOS);
}
@GetMapping("/{modelType}/{provideCode}/fields")
@Operation(summary = "获取模型供应器字段")
@RequiresPermissions("sys:role:superAdmin")
public Result<List<String>> getModelProviderFields(@PathVariable String modelType, @PathVariable String provideCode) {
List<String> fieldList = modelProviderService.getFieldList(modelType, provideCode);
return new Result<List<String>>().ok(fieldList);
}
@GetMapping("/models/list")
@Operation(summary = "获取模型配置列表")
@RequiresPermissions("sys:role:superAdmin")
public Result<PageData<ModelConfigDTO>> getModelConfigList(@RequestParam String modelType,
@RequestParam(required = false) String modelName,
@RequestParam(required = false, defaultValue = "0") Integer page,
@RequestParam(required = false, defaultValue = "10") Integer limit) {
PageData<ModelConfigDTO> pageList = modelConfigService.getPageList(modelType, modelName, page, limit);
return new Result<PageData<ModelConfigDTO>>().ok(pageList);
}
@PostMapping("/models/{modelType}/{provideCode}")
@Operation(summary = "新增模型配置")
@RequiresPermissions("sys:role:superAdmin")
public Result<ModelConfigDTO> addModelConfig(@PathVariable String modelType,
@PathVariable String provideCode,
@RequestBody ModelConfigBodyDTO modelConfigBodyDTO) {
ModelConfigDTO modelConfigDTO = modelConfigService.add(modelType, provideCode, modelConfigBodyDTO);
return new Result<ModelConfigDTO>().ok(modelConfigDTO);
}
@PutMapping("/models/{modelType}/{provideCode}/{id}")
@Operation(summary = "编辑模型配置")
@RequiresPermissions("sys:role:superAdmin")
public Result<ModelConfigDTO> editModelConfig(@PathVariable String modelType,
@PathVariable String provideCode,
@PathVariable String id,
@RequestBody ModelConfigBodyDTO modelConfigBodyDTO) {
ModelConfigDTO modelConfigDTO = modelConfigService.edit(modelType, provideCode, id, modelConfigBodyDTO);
return new Result<ModelConfigDTO>().ok(modelConfigDTO);
}
@DeleteMapping("/models/{modelType}/{provideCode}/{id}")
@Operation(summary = "删除模型配置")
@RequiresPermissions("sys:role:superAdmin")
public Result<Void> deleteModelConfig(@PathVariable String modelType, @PathVariable String provideCode, @PathVariable String id) {
modelConfigService.delete(modelType, provideCode, id);
return new Result<>();
}
@GetMapping("/models/{modelName}/voices")
@Operation(summary = "获取模型音色")
@RequiresPermissions("sys:role:normal")
public Result<List<String>> getVoiceList(@PathVariable String modelName,
@RequestParam(required = false) String voiceName) {
List<String> voiceList = modelConfigService.getVoiceList(modelName, voiceName);
return new Result<List<String>>().ok(voiceList);
}
}
@@ -1,124 +1,106 @@
package xiaozhi.modules.model.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import xiaozhi.common.controller.BaseController;
import xiaozhi.common.redis.RedisUtils;
import org.springframework.web.bind.annotation.*;
import xiaozhi.common.page.PageData;
import xiaozhi.common.utils.Result;
import xiaozhi.modules.model.domain.ModelConfig;
import xiaozhi.modules.model.domain.TtsVoice;
import xiaozhi.modules.model.dto.ModelConfigBodyDTO;
import xiaozhi.modules.model.dto.ModelConfigDTO;
import xiaozhi.modules.model.dto.ModelProviderDTO;
import xiaozhi.modules.model.service.ModelConfigService;
import xiaozhi.modules.model.service.TtsVoiceService;
import xiaozhi.modules.model.service.ModelProviderService;
import java.util.List;
@Slf4j
@Tag(name = "模型数据管理")
@AllArgsConstructor
@RestController
@RequestMapping("/model/")
public class ModelController extends BaseController {
private final TtsVoiceService ttsVoiceService;
@RequestMapping("/models")
@Tag(name = "模型配置")
public class ModelController {
private final ModelProviderService modelProviderService;
private final ModelConfigService modelConfigService;
@GetMapping("/models/names")
@Operation(summary = "获取所有模型名称")
@RequiresPermissions("sys:role:superAdmin")
public Result<List<String>> getModelNames(@RequestParam String modelType,
@RequestParam(required = false) String modelName) {
List<String> modelNameList = modelConfigService.getModelCodeList(modelType, modelName);
return new Result<List<String>>().ok(modelNameList);
}
@GetMapping("/list")
@Operation(summary = "模型配置列表")
@RequiresPermissions("sys:role:normal")
public Result<List<ModelConfig>> getModelList() {
List<ModelConfig> list = modelConfigService.list(new QueryWrapper<ModelConfig>().eq("is_enabled", 1));
return new Result<List<ModelConfig>>().ok(list);
@GetMapping("/{modelType}/provideTypes")
@Operation(summary = "获取模型供应器列表")
@RequiresPermissions("sys:role:superAdmin")
public Result<List<ModelProviderDTO>> getModelProviderList(@PathVariable String modelType) {
List<ModelProviderDTO> modelProviderDTOS = modelProviderService.getListByModelType(modelType);
return new Result<List<ModelProviderDTO>>().ok(modelProviderDTOS);
}
@GetMapping("/{modelType}/{provideCode}/fields")
@Operation(summary = "获取模型供应器字段")
@RequiresPermissions("sys:role:superAdmin")
public Result<List<String>> getModelProviderFields(@PathVariable String modelType, @PathVariable String provideCode) {
List<String> fieldList = modelProviderService.getFieldList(modelType, provideCode);
return new Result<List<String>>().ok(fieldList);
}
// private final ModelProviderService modelProviderService;
//
// private final ModelConfigService modelConfigService;
//
// @GetMapping("/models/names")
// @Operation(summary = "获取所有模型名称")
// @RequiresPermissions("sys:role:superAdmin")
// public Result<List<String>> getModelNames(@RequestParam String modelType,
// @RequestParam(required = false) String modelName) {
// List<String> modelNameList = modelConfigService.getModelCodeList(modelType, modelName);
// return new Result<List<String>>().ok(modelNameList);
// }
//
// @GetMapping("/{modelType}/provideTypes")
// @Operation(summary = "获取模型供应器列表")
// @RequiresPermissions("sys:role:superAdmin")
// public Result<List<ModelProviderDTO>> getModelProviderList(@PathVariable String modelType) {
// List<ModelProviderDTO> modelProviderDTOS = modelProviderService.getListByModelType(modelType);
// return new Result<List<ModelProviderDTO>>().ok(modelProviderDTOS);
// }
//
// @GetMapping("/{modelType}/{provideCode}/fields")
// @Operation(summary = "获取模型供应器字段")
// @RequiresPermissions("sys:role:superAdmin")
// public Result<List<String>> getModelProviderFields(@PathVariable String modelType, @PathVariable String provideCode) {
// List<String> fieldList = modelProviderService.getFieldList(modelType, provideCode);
// return new Result<List<String>>().ok(fieldList);
// }
//
//
// @GetMapping("/models/list")
// @Operation(summary = "获取模型配置列表")
// @RequiresPermissions("sys:role:superAdmin")
// public Result<PageData<ModelConfigDTO>> getModelConfigList(@RequestParam String modelType,
// @RequestParam(required = false) String modelName,
// @RequestParam(required = false, defaultValue = "0") Integer page,
// @RequestParam(required = false,defaultValue = "10") Integer limit) {
// PageData<ModelConfigDTO> pageList = modelConfigService.getPageList(modelType, modelName, page, limit);
// return new Result<PageData<ModelConfigDTO>>().ok(pageList);
// }
//
//
// @PostMapping("/models/{modelType}/{provideCode}")
// @Operation(summary = "新增模型配置")
// @RequiresPermissions("sys:role:superAdmin")
// public Result<ModelConfigDTO> addModelConfig(@PathVariable String modelType,
// @PathVariable String provideCode,
// @RequestBody ModelConfigBodyDTO modelConfigBodyDTO) {
// ModelConfigDTO modelConfigDTO = modelConfigService.add(modelType, provideCode, modelConfigBodyDTO);
// return new Result<ModelConfigDTO>().ok(modelConfigDTO);
// }
//
//
// @PutMapping("/models/{modelType}/{provideCode}/{id}")
// @Operation(summary = "编辑模型配置")
// @RequiresPermissions("sys:role:superAdmin")
// public Result<ModelConfigDTO> editModelConfig(@PathVariable String modelType,
// @PathVariable String provideCode,
// @PathVariable String id,
// @RequestBody ModelConfigBodyDTO modelConfigBodyDTO) {
// ModelConfigDTO modelConfigDTO = modelConfigService.edit(modelType, provideCode, id, modelConfigBodyDTO);
// return new Result<ModelConfigDTO>().ok(modelConfigDTO);
// }
//
//
// @DeleteMapping("/models/{modelType}/{provideCode}/{id}")
// @Operation(summary = "删除模型配置")
// @RequiresPermissions("sys:role:superAdmin")
// public Result<Void> deleteModelConfig(@PathVariable String modelType, @PathVariable String provideCode, @PathVariable String id) {
// modelConfigService.delete(modelType, provideCode, id);
// return new Result<>();
// }
//
// @GetMapping("/models/{modelName}/voices")
// @Operation(summary = "获取模型音色")
// @RequiresPermissions("sys:role:normal")
// public Result<List<String>> getVoiceList(@PathVariable String modelName,
// @RequestParam(required = false) String voiceName) {
//
// List<String> voiceList = modelConfigService.getVoiceList(modelName, voiceName);
// return new Result<List<String>>().ok(voiceList);
// }
}
@GetMapping("/models/list")
@Operation(summary = "获取模型配置列表")
@RequiresPermissions("sys:role:superAdmin")
public Result<PageData<ModelConfigDTO>> getModelConfigList(@RequestParam String modelType,
@RequestParam(required = false) String modelName,
@RequestParam(required = false, defaultValue = "0") Integer page,
@RequestParam(required = false,defaultValue = "10") Integer limit) {
PageData<ModelConfigDTO> pageList = modelConfigService.getPageList(modelType, modelName, page, limit);
return new Result<PageData<ModelConfigDTO>>().ok(pageList);
}
@PostMapping("/models/{modelType}/{provideCode}")
@Operation(summary = "新增模型配置")
@RequiresPermissions("sys:role:superAdmin")
public Result<ModelConfigDTO> addModelConfig(@PathVariable String modelType,
@PathVariable String provideCode,
@RequestBody ModelConfigBodyDTO modelConfigBodyDTO) {
ModelConfigDTO modelConfigDTO = modelConfigService.add(modelType, provideCode, modelConfigBodyDTO);
return new Result<ModelConfigDTO>().ok(modelConfigDTO);
}
@PutMapping("/models/{modelType}/{provideCode}/{id}")
@Operation(summary = "编辑模型配置")
@RequiresPermissions("sys:role:superAdmin")
public Result<ModelConfigDTO> editModelConfig(@PathVariable String modelType,
@PathVariable String provideCode,
@PathVariable String id,
@RequestBody ModelConfigBodyDTO modelConfigBodyDTO) {
ModelConfigDTO modelConfigDTO = modelConfigService.edit(modelType, provideCode, id, modelConfigBodyDTO);
return new Result<ModelConfigDTO>().ok(modelConfigDTO);
}
@DeleteMapping("/models/{modelType}/{provideCode}/{id}")
@Operation(summary = "删除模型配置")
@RequiresPermissions("sys:role:superAdmin")
public Result<Void> deleteModelConfig(@PathVariable String modelType, @PathVariable String provideCode, @PathVariable String id) {
modelConfigService.delete(modelType, provideCode, id);
return new Result<>();
}
@GetMapping("/models/{modelName}/voices")
@Operation(summary = "获取模型音色")
@RequiresPermissions("sys:role:normal")
public Result<List<String>> getVoiceList(@PathVariable String modelName,
@RequestParam(required = false) String voiceName) {
List<String> voiceList = modelConfigService.getVoiceList(modelName, voiceName);
return new Result<List<String>>().ok(voiceList);
}
}
@@ -1,124 +0,0 @@
package xiaozhi.modules.model.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.*;
import xiaozhi.common.controller.BaseController;
import xiaozhi.common.utils.Result;
import xiaozhi.modules.model.domain.TtsVoice;
import xiaozhi.modules.model.service.ModelConfigService;
import xiaozhi.modules.model.service.TtsVoiceService;
import java.util.List;
@Slf4j
@Tag(name = "模型数据管理")
@AllArgsConstructor
@RestController
@RequestMapping("/tts")
public class TtsController extends BaseController {
private final TtsVoiceService ttsVoiceService;
private final ModelConfigService modelConfigService;
@GetMapping("/voice")
@Operation(summary = "音色列表")
@RequiresPermissions("sys:role:normal")
public Result<List<TtsVoice>> getTtsList(@RequestParam(required = false) String ttsModelId) {
QueryWrapper<TtsVoice> queryWrapper = new QueryWrapper<>();
if (StringUtils.isNotBlank(ttsModelId)) {
queryWrapper.eq("ttsModelId", ttsModelId);
}
queryWrapper.orderByAsc("sort");
List<TtsVoice> list = ttsVoiceService.list(queryWrapper);
return new Result<List<TtsVoice>>().ok(list);
}
// private final ModelProviderService modelProviderService;
//
// private final ModelConfigService modelConfigService;
//
// @GetMapping("/models/names")
// @Operation(summary = "获取所有模型名称")
// @RequiresPermissions("sys:role:superAdmin")
// public Result<List<String>> getModelNames(@RequestParam String modelType,
// @RequestParam(required = false) String modelName) {
// List<String> modelNameList = modelConfigService.getModelCodeList(modelType, modelName);
// return new Result<List<String>>().ok(modelNameList);
// }
//
// @GetMapping("/{modelType}/provideTypes")
// @Operation(summary = "获取模型供应器列表")
// @RequiresPermissions("sys:role:superAdmin")
// public Result<List<ModelProviderDTO>> getModelProviderList(@PathVariable String modelType) {
// List<ModelProviderDTO> modelProviderDTOS = modelProviderService.getListByModelType(modelType);
// return new Result<List<ModelProviderDTO>>().ok(modelProviderDTOS);
// }
//
// @GetMapping("/{modelType}/{provideCode}/fields")
// @Operation(summary = "获取模型供应器字段")
// @RequiresPermissions("sys:role:superAdmin")
// public Result<List<String>> getModelProviderFields(@PathVariable String modelType, @PathVariable String provideCode) {
// List<String> fieldList = modelProviderService.getFieldList(modelType, provideCode);
// return new Result<List<String>>().ok(fieldList);
// }
//
//
// @GetMapping("/models/list")
// @Operation(summary = "获取模型配置列表")
// @RequiresPermissions("sys:role:superAdmin")
// public Result<PageData<ModelConfigDTO>> getModelConfigList(@RequestParam String modelType,
// @RequestParam(required = false) String modelName,
// @RequestParam(required = false, defaultValue = "0") Integer page,
// @RequestParam(required = false,defaultValue = "10") Integer limit) {
// PageData<ModelConfigDTO> pageList = modelConfigService.getPageList(modelType, modelName, page, limit);
// return new Result<PageData<ModelConfigDTO>>().ok(pageList);
// }
//
//
// @PostMapping("/models/{modelType}/{provideCode}")
// @Operation(summary = "新增模型配置")
// @RequiresPermissions("sys:role:superAdmin")
// public Result<ModelConfigDTO> addModelConfig(@PathVariable String modelType,
// @PathVariable String provideCode,
// @RequestBody ModelConfigBodyDTO modelConfigBodyDTO) {
// ModelConfigDTO modelConfigDTO = modelConfigService.add(modelType, provideCode, modelConfigBodyDTO);
// return new Result<ModelConfigDTO>().ok(modelConfigDTO);
// }
//
//
// @PutMapping("/models/{modelType}/{provideCode}/{id}")
// @Operation(summary = "编辑模型配置")
// @RequiresPermissions("sys:role:superAdmin")
// public Result<ModelConfigDTO> editModelConfig(@PathVariable String modelType,
// @PathVariable String provideCode,
// @PathVariable String id,
// @RequestBody ModelConfigBodyDTO modelConfigBodyDTO) {
// ModelConfigDTO modelConfigDTO = modelConfigService.edit(modelType, provideCode, id, modelConfigBodyDTO);
// return new Result<ModelConfigDTO>().ok(modelConfigDTO);
// }
//
//
// @DeleteMapping("/models/{modelType}/{provideCode}/{id}")
// @Operation(summary = "删除模型配置")
// @RequiresPermissions("sys:role:superAdmin")
// public Result<Void> deleteModelConfig(@PathVariable String modelType, @PathVariable String provideCode, @PathVariable String id) {
// modelConfigService.delete(modelType, provideCode, id);
// return new Result<>();
// }
//
// @GetMapping("/models/{modelName}/voices")
// @Operation(summary = "获取模型音色")
// @RequiresPermissions("sys:role:normal")
// public Result<List<String>> getVoiceList(@PathVariable String modelName,
// @RequestParam(required = false) String voiceName) {
//
// List<String> voiceList = modelConfigService.getVoiceList(modelName, voiceName);
// return new Result<List<String>>().ok(voiceList);
// }
}
@@ -1,91 +0,0 @@
package xiaozhi.modules.model.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
* 模型配置表
* @TableName ai_model_config
*/
@TableName(value ="ai_model_config")
@Data
public class ModelConfig implements Serializable {
/**
* 主键
*/
@TableId
private String id;
/**
* 模型类型(Memory/ASR/VAD/LLM/TTS)
*/
private String modelType;
/**
* 模型编码(如AliLLM、DoubaoTTS)
*/
private String modelCode;
/**
* 模型名称
*/
private String modelName;
/**
* 是否默认配置(0否 1是)
*/
private Integer isDefault;
/**
* 是否启用
*/
private Integer isEnabled;
/**
* 模型配置(JSON格式)
*/
private String configJson;
/**
* 官方文档链接
*/
private String docLink;
/**
* 备注
*/
private String remark;
/**
* 排序
*/
private Integer sort;
/**
* 创建者
*/
private Long creator;
/**
* 创建时间
*/
private Date createDate;
/**
* 更新者
*/
private Long updater;
/**
* 更新时间
*/
private Date updateDate;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}
@@ -1,71 +0,0 @@
package xiaozhi.modules.model.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
* 模型配置表
* @TableName ai_model_provider
*/
@TableName(value ="ai_model_provider")
@Data
public class ModelProvider implements Serializable {
/**
* 主键
*/
@TableId
private String id;
/**
* 模型类型(Memory/ASR/VAD/LLM/TTS)
*/
private String modelType;
/**
* 供应器类型
*/
private String providerCode;
/**
* 供应器名称
*/
private String name;
/**
* 供应器字段列表(JSON格式)
*/
private Object fields;
/**
* 排序
*/
private Integer sort;
/**
* 创建者
*/
private Long creator;
/**
* 创建时间
*/
private Date createDate;
/**
* 更新者
*/
private Long updater;
/**
* 更新时间
*/
private Date updateDate;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}
@@ -1,81 +0,0 @@
package xiaozhi.modules.model.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
* TTS 音色表
* @TableName ai_tts_voice
*/
@TableName(value ="ai_tts_voice")
@Data
public class TtsVoice implements Serializable {
/**
* 主键
*/
@TableId
private String id;
/**
* 对应 TTS 模型主键
*/
private String ttsModelId;
/**
* 音色名称
*/
private String name;
/**
* 音色编码
*/
private String ttsVoice;
/**
* 语言
*/
private String languages;
/**
* 音色 Demo
*/
private String voiceDemo;
/**
* 备注
*/
private String remark;
/**
* 排序
*/
private Integer sort;
/**
* 创建者
*/
private Long creator;
/**
* 创建时间
*/
private Date createDate;
/**
* 更新者
*/
private Long updater;
/**
* 更新时间
*/
private Date updateDate;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}
@@ -1,20 +0,0 @@
package xiaozhi.modules.model.mapper;
import org.apache.ibatis.annotations.Mapper;
import xiaozhi.modules.model.domain.ModelConfig;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author chenerlei
* @description 针对表【ai_model_config(模型配置表)】的数据库操作Mapper
* @createDate 2025-03-22 15:31:57
* @Entity xiaozhi.modules.model.domain.ModelConfig
*/
@Mapper
public interface ModelConfigMapper extends BaseMapper<ModelConfig> {
}
@@ -1,20 +0,0 @@
package xiaozhi.modules.model.mapper;
import org.apache.ibatis.annotations.Mapper;
import xiaozhi.modules.model.domain.ModelProvider;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author chenerlei
* @description 针对表【ai_model_provider(模型配置表)】的数据库操作Mapper
* @createDate 2025-03-24 18:24:13
* @Entity xiaozhi.modules.model.domain.ModelProvider
*/
@Mapper
public interface ModelProviderMapper extends BaseMapper<ModelProvider> {
}
@@ -1,20 +0,0 @@
package xiaozhi.modules.model.mapper;
import org.apache.ibatis.annotations.Mapper;
import xiaozhi.modules.model.domain.TtsVoice;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author chenerlei
* @description 针对表【ai_tts_voice(TTS 音色表)】的数据库操作Mapper
* @createDate 2025-03-22 15:31:57
* @Entity xiaozhi.modules.model.domain.TtsVoice
*/
@Mapper
public interface TtsVoiceMapper extends BaseMapper<TtsVoice> {
}
@@ -1,22 +0,0 @@
package xiaozhi.modules.model.service;
import xiaozhi.common.page.PageData;
import xiaozhi.modules.model.dto.ModelConfigBodyDTO;
import xiaozhi.modules.model.dto.ModelConfigDTO;
import java.util.List;
public interface Conflict_ModelConfigService {
List<String> getModelCodeList(String modelType, String modelName);
PageData<ModelConfigDTO> getPageList(String modelType, String modelName, Integer page, Integer limit);
ModelConfigDTO add(String modelType, String provideCode, ModelConfigBodyDTO modelConfigBodyDTO);
ModelConfigDTO edit(String modelType, String provideCode, String id, ModelConfigBodyDTO modelConfigBodyDTO);
void delete(String modelType, String provideCode, String id);
List<String> getVoiceList(String modelName, String voiceName);
}
@@ -1,23 +0,0 @@
package xiaozhi.modules.model.service;
import xiaozhi.modules.model.dto.ModelProviderDTO;
import xiaozhi.modules.model.entity.ModelProviderEntity;
import java.util.List;
public interface Conflict_ModelProviderService {
// List<String> getModelNames(String modelType, String modelName);
List<ModelProviderDTO> getListByModelType(String modelType);
ModelProviderDTO add(ModelProviderEntity modelProviderEntity);
ModelProviderDTO edit(ModelProviderEntity modelProviderEntity);
void delete();
List<ModelProviderDTO> getList(String modelType, String provideCode);
List<String> getFieldList(String modelType, String provideCode);
}
@@ -1,13 +1,22 @@
package xiaozhi.modules.model.service;
import com.baomidou.mybatisplus.extension.service.IService;
import xiaozhi.modules.model.domain.ModelConfig;
import xiaozhi.common.page.PageData;
import xiaozhi.modules.model.dto.ModelConfigBodyDTO;
import xiaozhi.modules.model.dto.ModelConfigDTO;
/**
* @author chenerlei
* @description 针对表【ai_model_config(模型配置表)】的数据库操作Service
* @createDate 2025-03-22 15:31:57
*/
public interface ModelConfigService extends IService<ModelConfig> {
import java.util.List;
public interface ModelConfigService {
List<String> getModelCodeList(String modelType, String modelName);
PageData<ModelConfigDTO> getPageList(String modelType, String modelName, Integer page, Integer limit);
ModelConfigDTO add(String modelType, String provideCode, ModelConfigBodyDTO modelConfigBodyDTO);
ModelConfigDTO edit(String modelType, String provideCode, String id, ModelConfigBodyDTO modelConfigBodyDTO);
void delete(String modelType, String provideCode, String id);
List<String> getVoiceList(String modelName, String voiceName);
}
@@ -1,13 +1,23 @@
package xiaozhi.modules.model.service;
import com.baomidou.mybatisplus.extension.service.IService;
import xiaozhi.modules.model.domain.ModelProvider;
import xiaozhi.modules.model.dto.ModelProviderDTO;
import xiaozhi.modules.model.entity.ModelProviderEntity;
/**
* @author chenerlei
* @description 针对表【ai_model_provider(模型配置表)】的数据库操作Service
* @createDate 2025-03-24 18:24:13
*/
public interface ModelProviderService extends IService<ModelProvider> {
import java.util.List;
public interface ModelProviderService {
// List<String> getModelNames(String modelType, String modelName);
List<ModelProviderDTO> getListByModelType(String modelType);
ModelProviderDTO add(ModelProviderEntity modelProviderEntity);
ModelProviderDTO edit(ModelProviderEntity modelProviderEntity);
void delete();
List<ModelProviderDTO> getList(String modelType, String provideCode);
List<String> getFieldList(String modelType, String provideCode);
}
@@ -1,13 +0,0 @@
package xiaozhi.modules.model.service;
import com.baomidou.mybatisplus.extension.service.IService;
import xiaozhi.modules.model.domain.TtsVoice;
/**
* @author chenerlei
* @description 针对表【ai_tts_voice(TTS 音色表)】的数据库操作Service
* @createDate 2025-03-22 15:31:57
*/
public interface TtsVoiceService extends IService<TtsVoice> {
}
@@ -1,124 +0,0 @@
package xiaozhi.modules.model.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import xiaozhi.common.constant.Constant;
import xiaozhi.common.exception.RenException;
import xiaozhi.common.page.PageData;
import xiaozhi.common.service.impl.BaseServiceImpl;
import xiaozhi.common.utils.ConvertUtils;
import xiaozhi.modules.model.dao.ModelConfigDao;
import xiaozhi.modules.model.dto.ModelConfigBodyDTO;
import xiaozhi.modules.model.dto.ModelConfigDTO;
import xiaozhi.modules.model.dto.ModelProviderDTO;
import xiaozhi.modules.model.entity.ModelConfigEntity;
import xiaozhi.modules.model.service.Conflict_ModelConfigService;
import xiaozhi.modules.model.service.Conflict_ModelProviderService;
import xiaozhi.modules.timbre.service.TimbreService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
@AllArgsConstructor
public class Conflict_ModelConfigServiceImpl extends BaseServiceImpl<ModelConfigDao, ModelConfigEntity> implements Conflict_ModelConfigService {
private final ModelConfigDao modelConfigDao;
private final Conflict_ModelProviderService modelProviderService;
private final TimbreService timbreService;
private static final Logger logger = LoggerFactory.getLogger(ModelConfigServiceImpl.class);
@Override
public List<String> getModelCodeList(String modelType, String modelName) {
return modelConfigDao.getModelCodeList(modelType, modelName);
}
@Override
public PageData<ModelConfigDTO> getPageList(String modelType, String modelName, Integer page, Integer limit) {
Map<String, Object> params = new HashMap<String, Object>();
params.put(Constant.PAGE, page);
params.put(Constant.LIMIT, limit);
IPage<ModelConfigEntity> modelConfigEntityIPage = modelConfigDao.selectPage(
getPage(params, "sort", true),
new QueryWrapper<ModelConfigEntity>()
.eq("model_type", modelType)
.like(StringUtils.isNotBlank(modelName), "model_name", modelName)
);
return getPageData(modelConfigEntityIPage, ModelConfigDTO.class);
}
@Override
public ModelConfigDTO add(String modelType, String provideCode, ModelConfigBodyDTO modelConfigBodyDTO) {
// 先验证有没有供应器
if (StringUtils.isBlank(modelType) || StringUtils.isBlank(provideCode)) {
throw new RenException("modelType和provideCode不能为空");
}
List<ModelProviderDTO> providerList = modelProviderService.getList(modelType, provideCode);
if (CollectionUtil.isEmpty(providerList)) {
throw new RenException("供应器不存在");
}
// 再保存供应器提供的模型
ModelConfigEntity modelConfigEntity = ConvertUtils.sourceToTarget(modelConfigBodyDTO, ModelConfigEntity.class);
modelConfigEntity.setModelType(modelType);
modelConfigDao.insert(modelConfigEntity);
return ConvertUtils.sourceToTarget(modelConfigEntity, ModelConfigDTO.class);
}
@Override
public ModelConfigDTO edit(String modelType, String provideCode, String id, ModelConfigBodyDTO modelConfigBodyDTO) {
// 先验证有没有供应器
if (StringUtils.isBlank(modelType) || StringUtils.isBlank(provideCode)) {
throw new RenException("modelType和provideCode不能为空");
}
List<ModelProviderDTO> providerList = modelProviderService.getList(modelType, provideCode);
if (CollectionUtil.isEmpty(providerList)) {
throw new RenException("供应器不存在");
}
// 再更新供应器提供的模型
ModelConfigEntity modelConfigEntity = ConvertUtils.sourceToTarget(modelConfigBodyDTO, ModelConfigEntity.class);
modelConfigEntity.setId(id);
modelConfigEntity.setModelType(modelType);
modelConfigDao.updateById(modelConfigEntity);
return ConvertUtils.sourceToTarget(modelConfigEntity, ModelConfigDTO.class);
}
@Override
public void delete(String modelType, String provideCode, String id) {
// 先验证有没有供应器
if (StringUtils.isBlank(modelType) || StringUtils.isBlank(provideCode)) {
throw new RenException("modelType和provideCode不能为空");
}
List<ModelProviderDTO> providerList = modelProviderService.getList(modelType, provideCode);
if (CollectionUtil.isEmpty(providerList)) {
throw new RenException("供应器不存在");
}
modelConfigDao.deleteById(Long.getLong(id));
}
@Override
public List<String> getVoiceList(String modelName, String voiceName) {
QueryWrapper<ModelConfigEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("model_name", StringUtils.isBlank(modelName) ? "" : modelName);
queryWrapper.eq("model_type", "TTS");
List<ModelConfigEntity> modelConfigEntities = modelConfigDao.selectList(queryWrapper);
if (CollectionUtil.isEmpty(modelConfigEntities)) {
logger.warn("没有找到模型配置信息");
return null;
}
ModelConfigEntity modelConfigEntity = modelConfigEntities.get(0);
String id = modelConfigEntity.getId();
return timbreService.getVoiceNames(id, voiceName);
}
}
@@ -1,59 +0,0 @@
package xiaozhi.modules.model.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import xiaozhi.common.service.impl.BaseServiceImpl;
import xiaozhi.common.utils.ConvertUtils;
import xiaozhi.modules.model.dao.ModelProviderDao;
import xiaozhi.modules.model.dto.ModelProviderDTO;
import xiaozhi.modules.model.entity.ModelProviderEntity;
import xiaozhi.modules.model.service.Conflict_ModelProviderService;
import java.util.List;
@Service
@AllArgsConstructor
public class Conflict_ModelProviderServiceImpl extends BaseServiceImpl<ModelProviderDao, ModelProviderEntity> implements Conflict_ModelProviderService {
private final ModelProviderDao modelProviderDao;
@Override
public List<ModelProviderDTO> getListByModelType(String modelType) {
QueryWrapper<ModelProviderEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("model_type", StringUtils.isBlank(modelType) ? "" : modelType);
List<ModelProviderEntity> providerEntities = modelProviderDao.selectList(queryWrapper);
return ConvertUtils.sourceToTarget(providerEntities, ModelProviderDTO.class);
}
@Override
public ModelProviderDTO add(ModelProviderEntity modelProviderEntity) {
return null;
}
@Override
public ModelProviderDTO edit(ModelProviderEntity modelProviderEntity) {
return null;
}
@Override
public void delete() {
}
@Override
public List<ModelProviderDTO> getList(String modelType, String provideCode) {
QueryWrapper<ModelProviderEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("model_type", StringUtils.isBlank(modelType) ? "" : modelType);
queryWrapper.eq("provide_code", StringUtils.isBlank(provideCode) ? "" : provideCode);
List<ModelProviderEntity> providerEntities = modelProviderDao.selectList(queryWrapper);
return ConvertUtils.sourceToTarget(providerEntities, ModelProviderDTO.class);
}
@Override
public List<String> getFieldList(String modelType, String provideCode) {
return modelProviderDao.getFieldList(modelType, provideCode);
}
}
@@ -1,22 +1,124 @@
package xiaozhi.modules.model.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import xiaozhi.modules.model.domain.ModelConfig;
import xiaozhi.modules.model.mapper.ModelConfigMapper;
import xiaozhi.common.constant.Constant;
import xiaozhi.common.exception.RenException;
import xiaozhi.common.page.PageData;
import xiaozhi.common.service.impl.BaseServiceImpl;
import xiaozhi.common.utils.ConvertUtils;
import xiaozhi.modules.model.dao.ModelConfigDao;
import xiaozhi.modules.model.dto.ModelConfigBodyDTO;
import xiaozhi.modules.model.dto.ModelConfigDTO;
import xiaozhi.modules.model.dto.ModelProviderDTO;
import xiaozhi.modules.model.entity.ModelConfigEntity;
import xiaozhi.modules.model.service.ModelConfigService;
import xiaozhi.modules.model.service.ModelProviderService;
import xiaozhi.modules.timbre.service.TimbreService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author chenerlei
* @description 针对表【ai_model_config(模型配置表)】的数据库操作Service实现
* @createDate 2025-03-22 15:31:57
*/
@Service
public class ModelConfigServiceImpl extends ServiceImpl<ModelConfigMapper, ModelConfig>
implements ModelConfigService {
@AllArgsConstructor
public class ModelConfigServiceImpl extends BaseServiceImpl<ModelConfigDao, ModelConfigEntity> implements ModelConfigService {
private final ModelConfigDao modelConfigDao;
private final ModelProviderService modelProviderService;
private final TimbreService timbreService;
private static final Logger logger = LoggerFactory.getLogger(ModelConfigServiceImpl.class);
@Override
public List<String> getModelCodeList(String modelType, String modelName) {
return modelConfigDao.getModelCodeList(modelType, modelName);
}
@Override
public PageData<ModelConfigDTO> getPageList(String modelType, String modelName, Integer page, Integer limit) {
Map<String, Object> params = new HashMap<String, Object>();
params.put(Constant.PAGE, page);
params.put(Constant.LIMIT, limit);
IPage<ModelConfigEntity> modelConfigEntityIPage = modelConfigDao.selectPage(
getPage(params, "sort", true),
new QueryWrapper<ModelConfigEntity>()
.eq("model_type", modelType)
.like(StringUtils.isNotBlank(modelName), "model_name", modelName)
);
return getPageData(modelConfigEntityIPage, ModelConfigDTO.class);
}
@Override
public ModelConfigDTO add(String modelType, String provideCode, ModelConfigBodyDTO modelConfigBodyDTO) {
// 先验证有没有供应器
if (StringUtils.isBlank(modelType) || StringUtils.isBlank(provideCode)) {
throw new RenException("modelType和provideCode不能为空");
}
List<ModelProviderDTO> providerList = modelProviderService.getList(modelType, provideCode);
if (CollectionUtil.isEmpty(providerList)) {
throw new RenException("供应器不存在");
}
// 再保存供应器提供的模型
ModelConfigEntity modelConfigEntity = ConvertUtils.sourceToTarget(modelConfigBodyDTO, ModelConfigEntity.class);
modelConfigEntity.setModelType(modelType);
modelConfigDao.insert(modelConfigEntity);
return ConvertUtils.sourceToTarget(modelConfigEntity, ModelConfigDTO.class);
}
@Override
public ModelConfigDTO edit(String modelType, String provideCode, String id, ModelConfigBodyDTO modelConfigBodyDTO) {
// 先验证有没有供应器
if (StringUtils.isBlank(modelType) || StringUtils.isBlank(provideCode)) {
throw new RenException("modelType和provideCode不能为空");
}
List<ModelProviderDTO> providerList = modelProviderService.getList(modelType, provideCode);
if (CollectionUtil.isEmpty(providerList)) {
throw new RenException("供应器不存在");
}
// 再更新供应器提供的模型
ModelConfigEntity modelConfigEntity = ConvertUtils.sourceToTarget(modelConfigBodyDTO, ModelConfigEntity.class);
modelConfigEntity.setId(id);
modelConfigEntity.setModelType(modelType);
modelConfigDao.updateById(modelConfigEntity);
return ConvertUtils.sourceToTarget(modelConfigEntity, ModelConfigDTO.class);
}
@Override
public void delete(String modelType, String provideCode, String id) {
// 先验证有没有供应器
if (StringUtils.isBlank(modelType) || StringUtils.isBlank(provideCode)) {
throw new RenException("modelType和provideCode不能为空");
}
List<ModelProviderDTO> providerList = modelProviderService.getList(modelType, provideCode);
if (CollectionUtil.isEmpty(providerList)) {
throw new RenException("供应器不存在");
}
modelConfigDao.deleteById(Long.getLong(id));
}
@Override
public List<String> getVoiceList(String modelName, String voiceName) {
QueryWrapper<ModelConfigEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("model_name", StringUtils.isBlank(modelName) ? "" : modelName);
queryWrapper.eq("model_type", "TTS");
List<ModelConfigEntity> modelConfigEntities = modelConfigDao.selectList(queryWrapper);
if (CollectionUtil.isEmpty(modelConfigEntities)) {
logger.warn("没有找到模型配置信息");
return null;
}
ModelConfigEntity modelConfigEntity = modelConfigEntities.get(0);
String id = modelConfigEntity.getId();
return timbreService.getVoiceNames(id, voiceName);
}
}
@@ -1,22 +1,59 @@
package xiaozhi.modules.model.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import xiaozhi.modules.model.domain.ModelProvider;
import xiaozhi.modules.model.mapper.ModelProviderMapper;
import xiaozhi.common.service.impl.BaseServiceImpl;
import xiaozhi.common.utils.ConvertUtils;
import xiaozhi.modules.model.dao.ModelProviderDao;
import xiaozhi.modules.model.dto.ModelProviderDTO;
import xiaozhi.modules.model.entity.ModelProviderEntity;
import xiaozhi.modules.model.service.ModelProviderService;
/**
* @author chenerlei
* @description 针对表【ai_model_provider(模型配置表)】的数据库操作Service实现
* @createDate 2025-03-24 18:24:13
*/
import java.util.List;
@Service
public class ModelProviderServiceImpl extends ServiceImpl<ModelProviderMapper, ModelProvider>
implements ModelProviderService {
@AllArgsConstructor
public class ModelProviderServiceImpl extends BaseServiceImpl<ModelProviderDao, ModelProviderEntity> implements ModelProviderService {
private final ModelProviderDao modelProviderDao;
@Override
public List<ModelProviderDTO> getListByModelType(String modelType) {
QueryWrapper<ModelProviderEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("model_type", StringUtils.isBlank(modelType) ? "" : modelType);
List<ModelProviderEntity> providerEntities = modelProviderDao.selectList(queryWrapper);
return ConvertUtils.sourceToTarget(providerEntities, ModelProviderDTO.class);
}
@Override
public ModelProviderDTO add(ModelProviderEntity modelProviderEntity) {
return null;
}
@Override
public ModelProviderDTO edit(ModelProviderEntity modelProviderEntity) {
return null;
}
@Override
public void delete() {
}
@Override
public List<ModelProviderDTO> getList(String modelType, String provideCode) {
QueryWrapper<ModelProviderEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("model_type", StringUtils.isBlank(modelType) ? "" : modelType);
queryWrapper.eq("provide_code", StringUtils.isBlank(provideCode) ? "" : provideCode);
List<ModelProviderEntity> providerEntities = modelProviderDao.selectList(queryWrapper);
return ConvertUtils.sourceToTarget(providerEntities, ModelProviderDTO.class);
}
@Override
public List<String> getFieldList(String modelType, String provideCode) {
return modelProviderDao.getFieldList(modelType, provideCode);
}
}
@@ -1,22 +0,0 @@
package xiaozhi.modules.model.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import xiaozhi.modules.model.domain.TtsVoice;
import xiaozhi.modules.model.service.TtsVoiceService;
import xiaozhi.modules.model.mapper.TtsVoiceMapper;
import org.springframework.stereotype.Service;
/**
* @author chenerlei
* @description 针对表【ai_tts_voice(TTS 音色表)】的数据库操作Service实现
* @createDate 2025-03-22 15:31:57
*/
@Service
public class TtsVoiceServiceImpl extends ServiceImpl<TtsVoiceMapper, TtsVoice>
implements TtsVoiceService{
}
@@ -1,145 +0,0 @@
package xiaozhi.modules.ota.controller;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.*;
import xiaozhi.common.controller.BaseController;
import xiaozhi.common.redis.RedisUtils;
import xiaozhi.common.user.UserDetail;
import xiaozhi.common.utils.Result;
import xiaozhi.modules.device.constant.DeviceConstant;
import xiaozhi.modules.device.domain.Device;
import xiaozhi.modules.device.service.DeviceService;
import xiaozhi.modules.device.utils.CodeGeneratorUtil;
import xiaozhi.modules.device.vo.DeviceOtaVO;
import xiaozhi.modules.ota.domain.Ota;
import xiaozhi.modules.ota.service.OtaService;
import xiaozhi.modules.security.user.SecurityUser;
import java.util.Date;
@Slf4j
@Tag(name = "设备OTA管理")
@AllArgsConstructor
@RestController
@RequestMapping("/ota")
public class OtaController extends BaseController {
private final DeviceService deviceService;
private final OtaService otaService;
@Resource
private RedisUtils redisUtils;
@CrossOrigin(originPatterns = "*", methods = {RequestMethod.GET, RequestMethod.POST})
@RequestMapping(path = "/", method = {RequestMethod.POST, RequestMethod.GET}, produces = "application/json")
@Operation(summary = "设备OTA升级")
public String ota(@RequestHeader(required = false) HttpHeaders headers, @RequestBody(required = false) JSONObject jsonObject) {
log.info("OTA升级请求:header:{}body:{}", headers, jsonObject);
if (ObjectUtils.isNull(headers) || StringUtils.isBlank(headers.getFirst("device-id"))) {
log.error("设备ID不能为空");
return "{\"error\": \"Device ID is required\"}";
}
DeviceOtaVO otaVO = new DeviceOtaVO();
Device device = deviceService.getOne(new UpdateWrapper<Device>().eq("mac_address", headers.getFirst("device-id").toUpperCase()).eq("id", headers.getFirst("client-Id").replace("-", "")), false);
if (ObjectUtils.isNull(device)) {
// 从 Redis 中获取设备信息
Object redisValue = redisUtils.hGet(DeviceConstant.REDIS_KEY_PREFIX_DEVICE_ACTIVATION_MAC, headers.getFirst("device-id").toUpperCase());
if (ObjectUtils.isNull(redisValue)) {
String code = CodeGeneratorUtil.generateCode(6);
log.info("[gen]授权码已广播:{}", code);
otaVO.setActivation(new DeviceOtaVO.Activation(code, "youxlife.com\n" + code));
redisUtils.hSet(DeviceConstant.REDIS_KEY_PREFIX_DEVICE_ACTIVATION_MAC, headers.getFirst("device-id").toUpperCase(), code, RedisUtils.HOUR_ONE_EXPIRE);
redisUtils.hSet(DeviceConstant.REDIS_KEY_PREFIX_DEVICE_ACTIVATION_CODE, code, jsonObject, RedisUtils.HOUR_ONE_EXPIRE);
} else {
log.warn("[get]授权码已广播:{}", redisValue);
otaVO.setActivation(new DeviceOtaVO.Activation(redisValue.toString(), "youxlife.com\n" + redisValue));
}
}
//规范输出,赋值默认数据
otaVO.setFirmware(new DeviceOtaVO.Firmware("0.0.1", ""));
if (ObjectUtils.isNull(device) || device.getAutoUpdate() == 1) {
//{"version":"1.0.0","url":"http://https://youxlife.oss-cn-zhangjiakou.aliyuncs.com/v1.4.5.bin"}
String board = ObjectUtils.isNull(device) ? headers.getFirst("user-agent").split("/")[0] : device.getBoard();
Ota ota = otaService.getOne(new UpdateWrapper<Ota>().eq("board", board).eq("is_enabled", 1));
if (ObjectUtils.isNotNull(ota)) {
otaVO.setFirmware(new DeviceOtaVO.Firmware(ota.getAppVersion(), ota.getUrl()));
}
}
otaVO.setServer_time(new DeviceOtaVO.ServerTime(new Date().getTime(), 8 * 60));
return JSONUtil.toJsonStr(otaVO);
}
@GetMapping("/sys/getOtalist")
@Operation(summary = "设备OTA列表")
@RequiresPermissions("sys:role:superAdmin")
public Result<Page<Ota>> getOtalist(@RequestParam Integer pageNo, @RequestParam Integer pageSize) {
UserDetail user = SecurityUser.getUser();
Page page = new Page<Ota>(pageNo, pageSize);
page = otaService.page(page);
return new Result<Page<Ota>>().ok(page);
}
@PostMapping("/sys/save")
@Operation(summary = "添加设备OTA")
@RequiresPermissions("sys:role:superAdmin")
public Result<Ota> save(@RequestBody Ota ota) {
UserDetail user = SecurityUser.getUser();
ota.setCreator(user.getId());
ota.setCreateDate(new Date());
boolean bool = otaService.save(ota);
if (!bool) {
return new Result().error("设备OTA添加失败");
}
return new Result<Ota>().ok(null);
}
@PostMapping("/sys/update")
@Operation(summary = "更新设备OTA")
@RequiresPermissions("sys:role:superAdmin")
public Result<Ota> update(@RequestBody Ota ota) {
UserDetail user = SecurityUser.getUser();
boolean bool = otaService.update(
new UpdateWrapper<Ota>().eq("id", ota.getId())
.set("board", ota.getBoard().trim().toLowerCase())
.set("app_version", ota.getAppVersion())
.set("url", ota.getUrl())
.set("is_enabled", ota.getIsEnabled())
.set("updater", user.getId())
.set("update_date", new Date())
);
if (!bool) {
return new Result().error("设备OTA更新失败");
}
return new Result<Ota>().ok(null);
}
@PostMapping("/sys/toggleEnabled")
@Operation(summary = "切换设备OTA可用状态")
@RequiresPermissions("sys:role:superAdmin")
public Result<Ota> toggleEnabled(@RequestBody Ota ota) {
UserDetail user = SecurityUser.getUser();
boolean bool = otaService.update(
new UpdateWrapper<Ota>().eq("id", ota.getId())
.set("is_enabled", ota.getIsEnabled())
.set("updater", user.getId())
.set("update_date", new Date())
);
if (!bool) {
return new Result().error("切换设备OTA可用状态失败");
}
return new Result<Ota>().ok(null);
}
}
@@ -1,66 +0,0 @@
package xiaozhi.modules.ota.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
* OTA升级信息表
* @TableName ai_ota
*/
@TableName(value ="ai_ota")
@Data
public class Ota implements Serializable {
/**
* 记录唯一标识
*/
@TableId
private String id;
/**
* 设备硬件型号
*/
private String board;
/**
* 固件版本号
*/
private String appVersion;
/**
* 下载地址
*/
private String url;
/**
* 是否启用
*/
private Integer isEnabled;
/**
* 创建者
*/
private Long creator;
/**
* 创建时间
*/
private Date createDate;
/**
* 更新者
*/
private Long updater;
/**
* 更新时间
*/
private Date updateDate;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}
@@ -1,20 +0,0 @@
package xiaozhi.modules.ota.mapper;
import org.apache.ibatis.annotations.Mapper;
import xiaozhi.modules.ota.domain.Ota;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author chenerlei
* @description 针对表【ai_ota(OTA升级信息表)】的数据库操作Mapper
* @createDate 2025-03-24 18:25:14
* @Entity xiaozhi.modules.ota.domain.Ota
*/
@Mapper
public interface OtaMapper extends BaseMapper<Ota> {
}
@@ -1,13 +0,0 @@
package xiaozhi.modules.ota.service;
import xiaozhi.modules.ota.domain.Ota;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author chenerlei
* @description 针对表【ai_ota(OTA升级信息表)】的数据库操作Service
* @createDate 2025-03-24 18:25:14
*/
public interface OtaService extends IService<Ota> {
}
@@ -1,22 +0,0 @@
package xiaozhi.modules.ota.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import xiaozhi.modules.ota.domain.Ota;
import xiaozhi.modules.ota.service.OtaService;
import xiaozhi.modules.ota.mapper.OtaMapper;
import org.springframework.stereotype.Service;
/**
* @author chenerlei
* @description 针对表【ai_ota(OTA升级信息表)】的数据库操作Service实现
* @createDate 2025-03-24 18:25:14
*/
@Service
public class OtaServiceImpl extends ServiceImpl<OtaMapper, Ota>
implements OtaService{
}
@@ -74,7 +74,6 @@ public class ShiroConfig {
filterMap.put("/user/login", "anon");
filterMap.put("/user/register", "anon");
filterMap.put("/ota/**", "anon");
filterMap.put("/user/agent/loadAgentConfig/**", "anon");
filterMap.put("/**", "oauth2");
shiroFilter.setFilterChainDefinitionMap(filterMap);
@@ -1,12 +1,18 @@
package xiaozhi.modules.security.controller;
import java.io.IOException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import xiaozhi.common.exception.ErrorCode;
import xiaozhi.common.exception.RenException;
import xiaozhi.common.page.TokenDTO;
@@ -22,8 +28,6 @@ import xiaozhi.modules.sys.dto.PasswordDTO;
import xiaozhi.modules.sys.dto.SysUserDTO;
import xiaozhi.modules.sys.service.SysUserService;
import java.io.IOException;
/**
* 登录控制层
*/
@@ -36,14 +40,13 @@ public class LoginController {
private final SysUserTokenService sysUserTokenService;
private final CaptchaService captchaService;
@GetMapping("/captcha")
@Operation(summary = "验证码")
public void captcha(HttpServletResponse response, String uuid) throws IOException {
//uuid不能为空
// uuid不能为空
AssertUtils.isBlank(uuid, ErrorCode.IDENTIFIER_NOT_NULL);
//生成验证码
// 生成验证码
captchaService.create(response, uuid);
}
@@ -55,11 +55,6 @@ public class Oauth2Filter extends AuthenticatingFilter {
//获取请求token,如果token不存在,直接返回401
String token = getRequestToken((HttpServletRequest) request);
// TODO 调试接口,临时取消登录限制,需要 token 参数的除外
// if (true) {
// return true;
// }
if (StringUtils.isBlank(token)) {
logger.warn("onAccessDenied:token is empty");
@@ -15,7 +15,7 @@ spring:
druid:
#MySQL
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/xiaozhi_esp32_server?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
url: jdbc:mysql://127.0.0.1:3306/xiaozhi_esp32_server?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
username: root
password: 123456
initial-size: 10
@@ -44,16 +44,10 @@ spring:
multi-statement-allow: true
data:
redis:
host: localhost # Redis服务器地址
host: 127.0.0.1 # Redis服务器地址
port: 6379 # Redis服务器连接端口
password: # Redis服务器连接密码(默认为空)
database: 0 # Redis数据库索引(默认为0
# jedis:
# pool:
# max-active: 8 # 连接池最大连接数(使用负值表示没有限制)
# max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
# max-idle: 8 # 连接池中的最大空闲连接
# min-idle: 0 # 连接池中的最小空闲连接
timeout: 10000ms # 连接超时时间(毫秒)
lettuce:
pool:
@@ -30,19 +30,3 @@ INSERT INTO `ai_tts_voice` VALUES ('9e8f7a6b5c4d3e2f1a0b9c8d7e6f5ad3', '896db62c
INSERT INTO `ai_tts_voice` VALUES ('2b3c4d5e6f7a8b9c0d1e2f3a4b5c62a2', '896db62c9dd74976ab0e8c14bf924d9d', '阳光男生', 'BV056_streaming', '中文', 'https://lf3-speech.bytetos.com/obj/speech-tts-external/portal/Portal_Demo_BV056.mp3', NULL, 4, NULL, NULL, NULL, NULL);
INSERT INTO `ai_tts_voice` VALUES ('f7a38c03d5644e22b6d84f8923a74c51', '896db62c9dd74976ab0e8c14bf924d9d', '奶气萌娃', 'BV051_streaming', '中文', 'https://lf3-speech.bytetos.com/obj/speech-tts-external/portal/Portal_Demo_BV051.mp3', NULL, 5, NULL, NULL, NULL, NULL);
-- OTA升级信息表
DROP TABLE IF EXISTS `ai_ota`;
CREATE TABLE `ai_ota` (
`id` VARCHAR(32) NOT NULL COMMENT '记录唯一标识',
`board` VARCHAR(50) COMMENT '设备硬件型号',
`app_version` VARCHAR(20) COMMENT '固件版本号',
`url` VARCHAR(500) COMMENT '下载地址',
`is_enabled` TINYINT(1) DEFAULT 0 COMMENT '是否启用',
`creator` BIGINT COMMENT '创建者',
`create_date` DATETIME COMMENT '创建时间',
`updater` BIGINT COMMENT '更新者',
`update_date` DATETIME COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uni_ai_ota_board` (`board`) COMMENT '设备型号唯一索引,用于快速查找升级信息'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='OTA升级信息表';
@@ -1,35 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xiaozhi.modules.agent.mapper.AgentMapper">
<resultMap id="BaseResultMap" type="xiaozhi.modules.agent.domain.Agent">
<id property="id" column="id" />
<result property="userId" column="user_id" />
<result property="agentCode" column="agent_code" />
<result property="agentName" column="agent_name" />
<result property="asrModelId" column="asr_model_id" />
<result property="vadModelId" column="vad_model_id" />
<result property="llmModelId" column="llm_model_id" />
<result property="ttsModelId" column="tts_model_id" />
<result property="ttsVoiceId" column="tts_voice_id" />
<result property="memoryModelId" column="memory_model_id" />
<result property="intentModelId" column="intent_model_id" />
<result property="systemPrompt" column="system_prompt" />
<result property="langCode" column="lang_code" />
<result property="language" column="language" />
<result property="sort" column="sort" />
<result property="creator" column="creator" />
<result property="createdAt" column="created_at" />
<result property="updater" column="updater" />
<result property="updatedAt" column="updated_at" />
</resultMap>
<sql id="Base_Column_List">
id,user_id,agent_code,agent_name,asr_model_id,vad_model_id,
llm_model_id,tts_model_id,tts_voice_id,memory_model_id,intent_model_id,
system_prompt,lang_code,language,sort,creator,
created_at,updater,updated_at
</sql>
</mapper>
@@ -2,34 +2,5 @@
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xiaozhi.modules.agent.mapper.AgentTemplateMapper">
<resultMap id="BaseResultMap" type="xiaozhi.modules.agent.domain.AgentTemplate">
<id property="id" column="id" />
<result property="agentCode" column="agent_code" />
<result property="agentName" column="agent_name" />
<result property="asrModelId" column="asr_model_id" />
<result property="vadModelId" column="vad_model_id" />
<result property="llmModelId" column="llm_model_id" />
<result property="ttsModelId" column="tts_model_id" />
<result property="ttsVoiceId" column="tts_voice_id" />
<result property="memoryModelId" column="memory_model_id" />
<result property="intentModelId" column="intent_model_id" />
<result property="systemPrompt" column="system_prompt" />
<result property="langCode" column="lang_code" />
<result property="language" column="language" />
<result property="sort" column="sort" />
<result property="isDefault" column="is_default" />
<result property="creator" column="creator" />
<result property="createdAt" column="created_at" />
<result property="updater" column="updater" />
<result property="updatedAt" column="updated_at" />
</resultMap>
<sql id="Base_Column_List">
id,agent_code,agent_name,asr_model_id,vad_model_id,llm_model_id,
tts_model_id,tts_voice_id,memory_model_id,intent_model_id,system_prompt,
lang_code,language,sort,is_default,creator,
created_at,updater,updated_at
</sql>
<mapper namespace="xiaozhi.modules.agent.dao.AgentTemplateDao">
</mapper>
@@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xiaozhi.modules.device.mapper.DeviceMapper">
<resultMap id="BaseResultMap" type="xiaozhi.modules.device.domain.Device">
<id property="id" column="id" />
<result property="userId" column="user_id" />
<result property="macAddress" column="mac_address" />
<result property="lastConnectedAt" column="last_connected_at" />
<result property="autoUpdate" column="auto_update" />
<result property="board" column="board" />
<result property="alias" column="alias" />
<result property="agentId" column="agent_id" />
<result property="appVersion" column="app_version" />
<result property="sort" column="sort" />
<result property="creator" column="creator" />
<result property="createDate" column="create_date" />
<result property="updater" column="updater" />
<result property="updateDate" column="update_date" />
</resultMap>
<sql id="Base_Column_List">
id,user_id,mac_address,last_connected_at,auto_update,board,
alias,agent_id,app_version,sort,creator,
create_date,updater,update_date
</sql>
</mapper>
@@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xiaozhi.modules.model.mapper.ModelConfigMapper">
<resultMap id="BaseResultMap" type="xiaozhi.modules.model.domain.ModelConfig">
<id property="id" column="id" />
<result property="modelType" column="model_type" />
<result property="modelCode" column="model_code" />
<result property="modelName" column="model_name" />
<result property="isDefault" column="is_default" />
<result property="isEnabled" column="is_enabled" />
<result property="configJson" column="config_json" />
<result property="docLink" column="doc_link" />
<result property="remark" column="remark" />
<result property="sort" column="sort" />
<result property="creator" column="creator" />
<result property="createDate" column="create_date" />
<result property="updater" column="updater" />
<result property="updateDate" column="update_date" />
</resultMap>
<sql id="Base_Column_List">
id,model_type,model_code,model_name,is_default,is_enabled,
config_json,doc_link,remark,sort,creator,
create_date,updater,update_date
</sql>
</mapper>
@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xiaozhi.modules.model.mapper.ModelProviderMapper">
<resultMap id="BaseResultMap" type="xiaozhi.modules.model.domain.ModelProvider">
<id property="id" column="id" />
<result property="modelType" column="model_type" />
<result property="providerCode" column="provider_code" />
<result property="name" column="name" />
<result property="fields" column="fields" />
<result property="sort" column="sort" />
<result property="creator" column="creator" />
<result property="createDate" column="create_date" />
<result property="updater" column="updater" />
<result property="updateDate" column="update_date" />
</resultMap>
<sql id="Base_Column_List">
id,model_type,provider_code,name,fields,sort,
creator,create_date,updater,update_date
</sql>
</mapper>
@@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xiaozhi.modules.model.mapper.TtsVoiceMapper">
<resultMap id="BaseResultMap" type="xiaozhi.modules.model.domain.TtsVoice">
<id property="id" column="id" />
<result property="ttsModelId" column="tts_model_id" />
<result property="name" column="name" />
<result property="ttsVoice" column="tts_voice" />
<result property="languages" column="languages" />
<result property="voiceDemo" column="voice_demo" />
<result property="remark" column="remark" />
<result property="sort" column="sort" />
<result property="creator" column="creator" />
<result property="createDate" column="create_date" />
<result property="updater" column="updater" />
<result property="updateDate" column="update_date" />
</resultMap>
<sql id="Base_Column_List">
id,tts_model_id,name,tts_voice,languages,voice_demo,
remark,sort,creator,create_date,updater,
update_date
</sql>
</mapper>
@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xiaozhi.modules.ota.mapper.OtaMapper">
<resultMap id="BaseResultMap" type="xiaozhi.modules.ota.domain.Ota">
<id property="id" column="id" />
<result property="board" column="board" />
<result property="appVersion" column="app_version" />
<result property="url" column="url" />
<result property="isEnabled" column="is_enabled" />
<result property="creator" column="creator" />
<result property="createDate" column="create_date" />
<result property="updater" column="updater" />
<result property="updateDate" column="update_date" />
</resultMap>
<sql id="Base_Column_List">
id,board,app_version,url,is_enabled,creator,
create_date,updater,update_date
</sql>
</mapper>