diff --git a/main/manager-api/README.md b/main/manager-api/README.md index 0435956e..69aa5375 100644 --- a/main/manager-api/README.md +++ b/main/manager-api/README.md @@ -11,6 +11,7 @@ manager-api 该项目基于SpringBoot框架开发。 JDK 21 Maven 3.8+ MySQL 8.0+ +Redis 5.0+ Vue 3.x # 创建数据库 @@ -43,6 +44,37 @@ spring: password: 123456 ``` + +# 连接Redis + +如果还没有Redis,你可以通过docker安装redis + +``` +docker run --name xiaozhi-esp32-server-redis -d -p 6379:6379 redis +``` + +# 确认项目Redis连接信息 + +在`src/main/resources/application-dev.yml`中配置Redis连接信息 + +``` +spring: + data: + redis: + host: localhost + port: 6379 + password: + database: 0 +``` + +在`src/main/resources/application.yml`中配置Redis启用状态 + +``` +renren: + redis: + open: true +``` + # 测试启动 本项目为SpringBoot项目,启动方式为: diff --git a/main/manager-api/pom.xml b/main/manager-api/pom.xml index eacbdff9..0857ec3c 100644 --- a/main/manager-api/pom.xml +++ b/main/manager-api/pom.xml @@ -168,6 +168,12 @@ lombok true + + + org.apache.logging.log4j + log4j-slf4j-impl + 2.20.0 + diff --git a/main/manager-api/src/main/java/xiaozhi/common/controller/BaseController.java b/main/manager-api/src/main/java/xiaozhi/common/controller/BaseController.java new file mode 100644 index 00000000..8cda64c0 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/common/controller/BaseController.java @@ -0,0 +1,46 @@ +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 getRequestHeaders() { + HashMap requestHeaders = new HashMap(); + Enumeration headerNames = request.getHeaderNames(); + while (headerNames.hasMoreElements()) { + String headerName = headerNames.nextElement(); + String headerValue = request.getHeader(headerName); + requestHeaders.put(headerName, headerValue); + } + return requestHeaders; + } + + /** + * 获取请求参数 + * + * @return + */ + protected HashMap getRequestParams() { + HashMap requestParams = new HashMap(); + Enumeration paramNames = request.getParameterNames(); + while (paramNames.hasMoreElements()) { + String paramName = paramNames.nextElement(); + String paramValue = request.getParameter(paramName); + requestParams.put(paramName, paramValue); + } + return requestParams; + } + +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java index 9f2cb10d..f1d496ec 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java @@ -1,149 +1,287 @@ 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.Parameter; -import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.validation.Valid; 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.constant.Constant; -import xiaozhi.common.page.PageData; +import xiaozhi.common.controller.BaseController; +import xiaozhi.common.redis.RedisUtils; 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.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.Map; +import java.util.UUID; +@Slf4j @Tag(name = "智能体管理") @AllArgsConstructor @RestController -@RequestMapping("/agent") -public class AgentController { +@RequestMapping("/user/agent") +public class AgentController extends BaseController { private final AgentService agentService; - - @GetMapping("/list") - @Operation(summary = "获取用户智能体列表") - @RequiresPermissions("sys:role:normal") - public Result> getUserAgents() { - UserDetail user = SecurityUser.getUser(); - List agents = agentService.getUserAgents(user.getId()); - return new Result>().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> adminAgentList( - @Parameter(hidden = true) @RequestParam Map params) { - PageData page = agentService.adminAgentList(params); - return new Result>().ok(page); - } - - @GetMapping("/{id}") - @Operation(summary = "获取智能体详情") - @RequiresPermissions("sys:role:normal") - public Result getAgentById(@PathVariable("id") String id) { - AgentEntity agent = agentService.getAgentById(id); - return new Result().ok(agent); - } - + private final AgentTemplateService agentTemplateService; + private final ModelConfigService modelConfigService; + private final TtsVoiceService ttsVoiceService; + private final DeviceService deviceService; + private final RedisUtils redisUtils; + @PostMapping - @Operation(summary = "创建智能体") + @Operation(summary = "添加智能体") @RequiresPermissions("sys:role:normal") - public Result save(@RequestBody @Valid AgentCreateDTO dto) { - AgentEntity entity = ConvertUtils.sourceToTarget(dto, AgentEntity.class); - - // 设置用户ID和创建者信息 + public Result addAgent(@RequestBody Agent agent) { UserDetail user = SecurityUser.getUser(); - entity.setUserId(user.getId()); - entity.setCreator(user.getId()); - entity.setCreatedAt(new Date()); - - // ID、智能体编码和排序会在Service层自动生成 - agentService.insert(entity); - - return new Result<>(); + if (StringUtils.isBlank(agent.getAgentName())) { + log.error("智能体名称不能为空"); + } + Agent oldAgent = agentService.getOne(new QueryWrapper().eq("agent_name", agent.getAgentName())); + if (ObjectUtils.isNull(oldAgent)) { + AgentTemplate agentTemplate = agentTemplateService.getOne(new QueryWrapper().eq("is_default", 1)); + if (ObjectUtils.isNull(agentTemplate)) { + + } 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 { + + } + return new Result().ok(agent); } - - @PutMapping + + @PutMapping("{agentId}") @Operation(summary = "更新智能体") @RequiresPermissions("sys:role:normal") - public Result update(@RequestBody @Valid AgentUpdateDTO dto) { - // 先查询现有实体 - AgentEntity existingEntity = agentService.getAgentById(dto.getId()); - if (existingEntity == null) { - return new Result().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()); - } - - // 设置更新者信息 + public Result updateAgent(@PathVariable String agentId, @RequestBody Agent agent) { UserDetail user = SecurityUser.getUser(); - existingEntity.setUpdater(user.getId()); - existingEntity.setUpdatedAt(new Date()); - - agentService.updateById(existingEntity); - - return new Result<>(); + if (StringUtils.isBlank(agentId)) { + log.error("智能体ID不能为空"); + return new Result().error("更新失败,智能体ID不能为空"); + } + Agent oldAgent = agentService.getById(agentId); + if (ObjectUtils.isNull(oldAgent)) { + log.error("智能体不存在"); + return new Result().error("更新失败,智能体不存在"); + } else { + UpdateWrapper 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().error("更新失败"); + } + return new Result().ok(agent); } - - @DeleteMapping("/{id}") + + @DeleteMapping("/{agentId}") @Operation(summary = "删除智能体") @RequiresPermissions("sys:role:normal") - public Result delete(@PathVariable String id) { - agentService.deleteById(id); - return new Result<>(); + public Result 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().error("删除失败"); + } + return new Result().ok(null); } -} \ No newline at end of file + + @GetMapping("/{agentId}") + @Operation(summary = "获取智能体信息") + @RequiresPermissions("sys:role:normal") + public Result getAgent(@PathVariable String agentId) { + if (StringUtils.isBlank(agentId)) { + log.error("智能体ID不能为空"); + } + Agent agent = agentService.getById(agentId); + return new Result().ok(agent); + } + + @GetMapping + @Operation(summary = "智能体列表") + @RequiresPermissions("sys:role:normal") + public Result> agentList() { + UserDetail user = SecurityUser.getUser(); + List agents = agentService.list(new QueryWrapper().eq("user_id", user.getId())); + List list = new ArrayList<>(); + this.convertAgentVOList(list, agents); + return new Result>().ok(list); + } + + @GetMapping("/loadAgentConfig/{deviceId}") + @Operation(summary = "下载智能体配置") + public Result loadAgentConfig(@PathVariable String deviceId) { + Device device = deviceService.getOne(new QueryWrapper().eq("mac_address", deviceId.toUpperCase())); + if (ObjectUtils.isNull(device)) { + return new Result().error("设备不存在"); + } + Agent agent = agentService.getOne(new QueryWrapper().eq("id", device.getAgentId())); + if (ObjectUtils.isNull(agent)) { + return new Result().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().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().ok(new JSONObject(json)); + } + + /** + * 将Agent对象列表转换为AgentVO对象列表 + * 此方法遍历Agent对象列表,将每个Agent对象转换为AgentVO对象,并添加到AgentVO列表中 + * + * @param agentVOList 转换后的AgentVO对象列表 + * @param agentList 原始的Agent对象列表 + */ + private void convertAgentVOList(List agentVOList, List 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().eq("id", agent.getTtsVoiceId())); + if (ObjectUtils.isNotNull(ttsVoice)) { + agentVO.setTtsModelName(ttsVoice.getName()); + } + agentVO.setLlmModelName("未知"); + ModelConfig modelConfig = modelConfigService.getOne(new QueryWrapper().eq("id", agent.getLlmModelId())); + if (ObjectUtils.isNotNull(modelConfig)) { + agentVO.setLlmModelName(modelConfig.getModelName()); + } + agentVO.setLastConnectedAt("今天"); + agentVO.setDeviceCount(0L); + long deviceCount = deviceService.count(new QueryWrapper().eq("agent_id", agent.getId())); + agentVO.setDeviceCount(deviceCount); + } catch (Exception e) { + log.error("[convertAgentVO]对象转换报错", e); + } + } +} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentTemplateController.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentTemplateController.java new file mode 100644 index 00000000..08405cac --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentTemplateController.java @@ -0,0 +1,131 @@ +package xiaozhi.modules.agent.controller; + +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.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 { + private final AgentTemplateService agentTemplateService; + private final ModelConfigService modelConfigService; + private final TtsVoiceService ttsVoiceService; + + @PostMapping + @Operation(summary = "添加智能体模板") + @RequiresPermissions("sys:role:superAdmin") + public Result 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().ok(agentTemplate); + } + + @DeleteMapping("/{templateId}") + @Operation(summary = "删除智能体模板") + @RequiresPermissions("sys:role:superAdmin") + public Result 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().error("删除失败"); + } + return new Result().ok(null); + } + + @GetMapping + @Operation(summary = "智能体模板模板列表") + @RequiresPermissions("sys:role:normal") + public Result> templateList() { + List list = agentTemplateService.list(new QueryWrapper().orderByAsc("sort")); + return new Result>().ok(list); + } + + @GetMapping("/vo") + @Operation(summary = "智能体模板模板列表") + @RequiresPermissions("sys:role:normal") + public Result> templateVOList() { + UserDetail user = SecurityUser.getUser(); + List templates = agentTemplateService.list(); + List list = new ArrayList<>(); + this.convertAgentTemplateVOList(list, templates); + return new Result>().ok(list); + } + + /** + * 将Agent对象列表转换为AgentTemplateVO对象列表 + * 此方法遍历Agent对象列表,将每个Agent对象转换为AgentTemplateVO对象,并添加到AgentTemplateVO列表中 + * + * @param agentVOList 转换后的AgentTemplateVO对象列表 + * @param agentList 原始的Agent对象列表 + */ + private void convertAgentTemplateVOList(List agentVOList, List 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().eq("id", agentTemplate.getTtsVoiceId())); + if (ObjectUtils.isNotNull(ttsVoice)) { + agentTemplateVO.setTtsModelName(ttsVoice.getName()); + } + agentTemplateVO.setLlmModelName("未知"); + ModelConfig modelConfig = modelConfigService.getOne(new QueryWrapper().eq("id", agentTemplate.getLlmModelId())); + if (ObjectUtils.isNotNull(modelConfig)) { + agentTemplateVO.setLlmModelName(modelConfig.getModelName()); + } + } catch (Exception e) { + log.error("[convertAgentTemplateVO]对象转换报错", e); + } + } +} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/dao/AgentDao.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/dao/AgentDao.java deleted file mode 100644 index 169346bf..00000000 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/dao/AgentDao.java +++ /dev/null @@ -1,10 +0,0 @@ -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 { - -} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/domain/Agent.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/domain/Agent.java new file mode 100644 index 00000000..8ae48dec --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/domain/Agent.java @@ -0,0 +1,116 @@ +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; +} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/domain/AgentTemplate.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/domain/AgentTemplate.java new file mode 100644 index 00000000..594fc219 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/domain/AgentTemplate.java @@ -0,0 +1,116 @@ +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_template + */ +@TableName(value ="ai_agent_template") +@Data +public class AgentTemplate implements Serializable { + /** + * 智能体唯一标识 + */ + @TableId + private String id; + + /** + * 智能体编码 + */ + 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; + + /** + * 是否默认模板:1:是,0:不是 + */ + private Integer isDefault; + + /** + * 创建者 ID + */ + private Long creator; + + /** + * 创建时间 + */ + private Date createdAt; + + /** + * 更新者 ID + */ + private Long updater; + + /** + * 更新时间 + */ + private Date updatedAt; + + @TableField(exist = false) + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentCreateDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentCreateDTO.java deleted file mode 100644 index 302a55fb..00000000 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentCreateDTO.java +++ /dev/null @@ -1,51 +0,0 @@ -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; -} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentUpdateDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentUpdateDTO.java deleted file mode 100644 index 6445bdda..00000000 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentUpdateDTO.java +++ /dev/null @@ -1,61 +0,0 @@ -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; -} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/entity/AgentEntity.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/entity/AgentEntity.java deleted file mode 100644 index 6800aefb..00000000 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/entity/AgentEntity.java +++ /dev/null @@ -1,69 +0,0 @@ -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; -} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/mapper/AgentMapper.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/mapper/AgentMapper.java new file mode 100644 index 00000000..7c849280 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/mapper/AgentMapper.java @@ -0,0 +1,20 @@ +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 { + +} + + + + diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/mapper/AgentTemplateMapper.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/mapper/AgentTemplateMapper.java new file mode 100644 index 00000000..c3222cc4 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/mapper/AgentTemplateMapper.java @@ -0,0 +1,20 @@ +package xiaozhi.modules.agent.mapper; + +import org.apache.ibatis.annotations.Mapper; +import xiaozhi.modules.agent.domain.AgentTemplate; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** +* @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 { + +} + + + + diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentService.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentService.java index 76439ede..b7a7705b 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentService.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentService.java @@ -1,25 +1,13 @@ -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 { - /** - * 根据用户ID获取智能体列表 - */ - List getUserAgents(Long userId); - - /** - * 管理员获取所有智能体列表(分页) - */ - PageData adminAgentList(Map params); - - /** - * 获取智能体详情 - */ - AgentEntity getAgentById(String id); -} \ No newline at end of file +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 { + +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentTemplateService.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentTemplateService.java new file mode 100644 index 00000000..18849526 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentTemplateService.java @@ -0,0 +1,13 @@ +package xiaozhi.modules.agent.service; + +import xiaozhi.modules.agent.domain.AgentTemplate; +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 { + +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java index b41310ab..dfa3400d 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java @@ -1,64 +1,22 @@ -package xiaozhi.modules.agent.service.impl; - -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import org.springframework.stereotype.Service; -import xiaozhi.common.page.PageData; -import xiaozhi.common.service.impl.BaseServiceImpl; -import xiaozhi.modules.agent.dao.AgentDao; -import xiaozhi.modules.agent.entity.AgentEntity; -import xiaozhi.modules.agent.service.AgentService; - -import java.util.List; -import java.util.Map; -import java.util.UUID; - -@Service -public class AgentServiceImpl extends BaseServiceImpl implements AgentService { - private final AgentDao agentDao; - - public AgentServiceImpl(AgentDao agentDao) { - this.agentDao = agentDao; - } - - @Override - public List getUserAgents(Long userId) { - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.eq("user_id", userId); - return agentDao.selectList(wrapper); - } - - @Override - public PageData adminAgentList(Map params) { - IPage 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); - } -} \ No newline at end of file +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 org.springframework.stereotype.Service; + +/** +* @author chenerlei +* @description 针对表【ai_agent(智能体配置表)】的数据库操作Service实现 +* @createDate 2025-03-22 11:48:18 +*/ +@Service +public class AgentServiceImpl extends ServiceImpl + implements AgentService{ + +} + + + + diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentTemplateServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentTemplateServiceImpl.java new file mode 100644 index 00000000..112b65c0 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentTemplateServiceImpl.java @@ -0,0 +1,22 @@ +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; + +/** +* @author chenerlei +* @description 针对表【ai_agent_template(智能体配置模板表)】的数据库操作Service实现 +* @createDate 2025-03-22 11:48:18 +*/ +@Service +public class AgentTemplateServiceImpl extends ServiceImpl + implements AgentTemplateService{ + +} + + + + diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/vo/AgentConfigVO.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/vo/AgentConfigVO.java new file mode 100644 index 00000000..ba1ececc --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/vo/AgentConfigVO.java @@ -0,0 +1,17 @@ +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; +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/vo/AgentTemplateVO.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/vo/AgentTemplateVO.java new file mode 100644 index 00000000..9cd7d79d --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/vo/AgentTemplateVO.java @@ -0,0 +1,14 @@ +package xiaozhi.modules.agent.vo; + +import lombok.Data; +import xiaozhi.modules.agent.domain.Agent; +import xiaozhi.modules.agent.domain.AgentTemplate; + +@Data +public class AgentTemplateVO extends AgentTemplate { + //角色音色 + private String ttsModelName; + + //角色模型 + private String llmModelName; +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/vo/AgentVO.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/vo/AgentVO.java new file mode 100644 index 00000000..3ffddbd7 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/vo/AgentVO.java @@ -0,0 +1,19 @@ +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; +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/constant/DeviceConstant.java b/main/manager-api/src/main/java/xiaozhi/modules/device/constant/DeviceConstant.java new file mode 100644 index 00000000..5d6fb39e --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/constant/DeviceConstant.java @@ -0,0 +1,7 @@ +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"; +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java index d458e9f9..cfb51de3 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java @@ -1,82 +1,173 @@ 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.constant.Constant; -import xiaozhi.common.exception.ErrorCode; -import xiaozhi.common.page.PageData; -import xiaozhi.common.redis.RedisKeys; +import xiaozhi.common.controller.BaseController; import xiaozhi.common.redis.RedisUtils; import xiaozhi.common.user.UserDetail; -import xiaozhi.common.utils.JsonUtils; import xiaozhi.common.utils.Result; -import xiaozhi.modules.device.dto.DeviceHeaderDTO; -import xiaozhi.modules.device.dto.DeviceUnBindDTO; -import xiaozhi.modules.device.entity.DeviceEntity; +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.service.DeviceService; +import xiaozhi.modules.device.vo.DeviceCodeVO; import xiaozhi.modules.security.user.SecurityUser; -import java.util.List; -import java.util.Map; +import java.util.Date; +@Slf4j @Tag(name = "设备管理") @AllArgsConstructor @RestController -@RequestMapping("/device") -public class DeviceController { +@RequestMapping("/user/agent/device") +public class DeviceController extends BaseController { + private final AgentService agentService; private final DeviceService deviceService; private final RedisUtils redisUtils; + @GetMapping("/bind/{agentId}") + @Operation(summary = "已绑定设备列表") + @RequiresPermissions("sys:role:normal") + public Result> bindDeviceList(@PathVariable String agentId, @RequestParam Integer pageNo, @RequestParam Integer pageSize) { + if (StringUtils.isBlank(agentId)) { + log.error("智能体ID不能为空"); + return new Result().error("智能体ID不能为空"); + } - @PostMapping("/bind/{deviceCode}") + UserDetail user = SecurityUser.getUser(); + Agent agent = agentService.getById(agentId); + if (ObjectUtils.isNull(agent)) { + log.error("智能体不存在"); + return new Result().error("智能体不存在"); + } + Page page = new Page(pageNo, pageSize); + page = deviceService.page(page, new QueryWrapper().eq("user_id", user.getId()).eq("agent_id", agentId)); + return new Result>().ok(page); + } + + + @PostMapping("/bind/{agentId}") @Operation(summary = "绑定设备") @RequiresPermissions("sys:role:normal") - public Result bindDevice(@PathVariable String deviceCode) { - UserDetail user = SecurityUser.getUser(); - - String deviceHeaders = (String) redisUtils.get(RedisKeys.getDeviceCaptchaKey(deviceCode)); - if (StringUtils.isBlank(deviceHeaders)) { - return new Result().error(ErrorCode.DEVICE_CAPTCHA_ERROR); + public Result 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不能为空"); } - DeviceHeaderDTO deviceHeader = JsonUtils.parseObject(deviceHeaders.getBytes(), DeviceHeaderDTO.class); - DeviceEntity device = deviceService.bindDevice(user.getId(), deviceHeader); - return new Result().ok(device); - } - @GetMapping("/bind") - @Operation(summary = "获取已绑定设备") - @RequiresPermissions("sys:role:normal") - public Result> getUserDevices() { UserDetail user = SecurityUser.getUser(); - List devices = deviceService.getUserDevices(user.getId()); - return new Result>().ok(devices); + + // 从 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("授权码不存在"); + } + 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().ok(device); } - @PostMapping("/unbind") + @PutMapping("/unbind/{deviceId}") @Operation(summary = "解绑设备") @RequiresPermissions("sys:role:normal") - public Result unbindDevice(@RequestBody DeviceUnBindDTO unDeviveBind) { - UserDetail user = SecurityUser.getUser(); - deviceService.unbindDevice(user.getId(), unDeviveBind.getDeviceId()); - return new Result(); + public Result 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().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> adminDeviceList( - @Parameter(hidden = true) @RequestParam Map params) { - PageData page = deviceService.adminDeviceList(params); - return new Result>().ok(page); + @PostMapping("/autoUpdate/{deviceId}") + @Operation(summary = "切换设备OTA升级状态") + @RequiresPermissions("sys:role:normal") + public Result 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().eq("id", deviceId) + .set("auto_update", device.getAutoUpdate()) + .set("updater", user.getId()) + .set("update_date", new Date()) + ); + if (!bool) { + return new Result().error("切换设备OTA升级状态失败"); + } + return new Result().ok(null); + } + + @PostMapping("/alias/{deviceId}") + @Operation(summary = "设置设备别名") + @RequiresPermissions("sys:role:normal") + public Result 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().eq("id", deviceId) + .set("alias", device.getAlias()) + .set("updater", user.getId()) + .set("update_date", new Date()) + ); + if (!bool) { + return new Result().error("设置设备别名失败"); + } + return new Result().ok(null); } } \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/dao/DeviceDao.java b/main/manager-api/src/main/java/xiaozhi/modules/device/dao/DeviceDao.java deleted file mode 100644 index 9e4a8cd4..00000000 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/dao/DeviceDao.java +++ /dev/null @@ -1,9 +0,0 @@ -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 { -} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/domain/Device.java b/main/manager-api/src/main/java/xiaozhi/modules/device/domain/Device.java new file mode 100644 index 00000000..ae662dde --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/domain/Device.java @@ -0,0 +1,91 @@ +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; +} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/dto/DeviceHeaderDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/device/dto/DeviceHeaderDTO.java deleted file mode 100644 index 83327fef..00000000 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/dto/DeviceHeaderDTO.java +++ /dev/null @@ -1,19 +0,0 @@ -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; - -} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/dto/DeviceUnBindDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/device/dto/DeviceUnBindDTO.java deleted file mode 100644 index 830a51ae..00000000 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/dto/DeviceUnBindDTO.java +++ /dev/null @@ -1,19 +0,0 @@ -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; - -} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/entity/DeviceEntity.java b/main/manager-api/src/main/java/xiaozhi/modules/device/entity/DeviceEntity.java deleted file mode 100644 index ccbe4683..00000000 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/entity/DeviceEntity.java +++ /dev/null @@ -1,54 +0,0 @@ -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; -} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/mapper/DeviceMapper.java b/main/manager-api/src/main/java/xiaozhi/modules/device/mapper/DeviceMapper.java new file mode 100644 index 00000000..b43847a5 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/mapper/DeviceMapper.java @@ -0,0 +1,20 @@ +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 { + +} + + + + diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java b/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java index 16ad44fe..ec3efe56 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java @@ -1,18 +1,13 @@ -package xiaozhi.modules.device.service; - -import xiaozhi.common.page.PageData; -import xiaozhi.modules.device.dto.DeviceHeaderDTO; -import xiaozhi.modules.device.entity.DeviceEntity; - -import java.util.List; -import java.util.Map; - -public interface DeviceService { - DeviceEntity bindDevice(Long userId, DeviceHeaderDTO deviceHeader); - - List getUserDevices(Long userId); - - void unbindDevice(Long userId, Long deviceId); - - PageData adminDeviceList(Map params); -} \ No newline at end of file +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 { + +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java index 279a9f2e..4c317a64 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java @@ -1,57 +1,22 @@ -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 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 getUserDevices(Long userId) { - QueryWrapper 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 adminDeviceList(Map params) { - IPage page = deviceDao.selectPage( - getPage(params, "sort", true), - new QueryWrapper<>() - ); - return new PageData<>(page.getRecords(), page.getTotal()); - } - -} \ No newline at end of file +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 + implements DeviceService{ + +} + + + + diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/utils/CodeGeneratorUtil.java b/main/manager-api/src/main/java/xiaozhi/modules/device/utils/CodeGeneratorUtil.java new file mode 100644 index 00000000..3a9ca2e6 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/utils/CodeGeneratorUtil.java @@ -0,0 +1,68 @@ +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); + } +} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/vo/DeviceCodeVO.java b/main/manager-api/src/main/java/xiaozhi/modules/device/vo/DeviceCodeVO.java new file mode 100644 index 00000000..a27568cc --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/vo/DeviceCodeVO.java @@ -0,0 +1,8 @@ +package xiaozhi.modules.device.vo; + +import lombok.Data; + +@Data +public class DeviceCodeVO { + private String deviceCode; +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/vo/DeviceOtaVO.java b/main/manager-api/src/main/java/xiaozhi/modules/device/vo/DeviceOtaVO.java new file mode 100644 index 00000000..c5af75af --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/vo/DeviceOtaVO.java @@ -0,0 +1,55 @@ +package xiaozhi.modules.device.vo; + +import lombok.Data; + +@Data +public class DeviceOtaVO { + private Activation activation; + private Mqtt mqtt; + private ServerTime server_time; + private Firmware firmware; + private String error; + + @Data + public static class Activation { + private String code; + private String message; + + public Activation() { + } + public Activation(String code, String message) { + this.code = code; + this.message = message; + } + } + + @Data + public class Mqtt { + + } + + @Data + public static class ServerTime { + private Long timestamp; + private Integer timezone_offset; + + public ServerTime() { + } + public ServerTime(Long timestamp, Integer timezone_offset) { + this.timestamp = timestamp; + this.timezone_offset = timezone_offset; + } + } + + @Data + public static class Firmware { + private String version; + private String url; + public Firmware() { + } + public Firmware(String version, String url) { + this.version = version; + this.url = url; + } + } +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/controller/Conflict_ModelController.java b/main/manager-api/src/main/java/xiaozhi/modules/model/controller/Conflict_ModelController.java new file mode 100644 index 00000000..1524d8bc --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/controller/Conflict_ModelController.java @@ -0,0 +1,106 @@ +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> getModelNames(@RequestParam String modelType, + @RequestParam(required = false) String modelName) { + List modelNameList = modelConfigService.getModelCodeList(modelType, modelName); + return new Result>().ok(modelNameList); + } + + @GetMapping("/{modelType}/provideTypes") + @Operation(summary = "获取模型供应器列表") + @RequiresPermissions("sys:role:superAdmin") + public Result> getModelProviderList(@PathVariable String modelType) { + List modelProviderDTOS = modelProviderService.getListByModelType(modelType); + return new Result>().ok(modelProviderDTOS); + } + + @GetMapping("/{modelType}/{provideCode}/fields") + @Operation(summary = "获取模型供应器字段") + @RequiresPermissions("sys:role:superAdmin") + public Result> getModelProviderFields(@PathVariable String modelType, @PathVariable String provideCode) { + List fieldList = modelProviderService.getFieldList(modelType, provideCode); + return new Result>().ok(fieldList); + } + + + @GetMapping("/models/list") + @Operation(summary = "获取模型配置列表") + @RequiresPermissions("sys:role:superAdmin") + public Result> getModelConfigList(@RequestParam String modelType, + @RequestParam(required = false) String modelName, + @RequestParam(required = false, defaultValue = "0") Integer page, + @RequestParam(required = false, defaultValue = "10") Integer limit) { + PageData pageList = modelConfigService.getPageList(modelType, modelName, page, limit); + return new Result>().ok(pageList); + } + + + @PostMapping("/models/{modelType}/{provideCode}") + @Operation(summary = "新增模型配置") + @RequiresPermissions("sys:role:superAdmin") + public Result addModelConfig(@PathVariable String modelType, + @PathVariable String provideCode, + @RequestBody ModelConfigBodyDTO modelConfigBodyDTO) { + ModelConfigDTO modelConfigDTO = modelConfigService.add(modelType, provideCode, modelConfigBodyDTO); + return new Result().ok(modelConfigDTO); + } + + + @PutMapping("/models/{modelType}/{provideCode}/{id}") + @Operation(summary = "编辑模型配置") + @RequiresPermissions("sys:role:superAdmin") + public Result editModelConfig(@PathVariable String modelType, + @PathVariable String provideCode, + @PathVariable String id, + @RequestBody ModelConfigBodyDTO modelConfigBodyDTO) { + ModelConfigDTO modelConfigDTO = modelConfigService.edit(modelType, provideCode, id, modelConfigBodyDTO); + return new Result().ok(modelConfigDTO); + } + + + @DeleteMapping("/models/{modelType}/{provideCode}/{id}") + @Operation(summary = "删除模型配置") + @RequiresPermissions("sys:role:superAdmin") + public Result 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> getVoiceList(@PathVariable String modelName, + @RequestParam(required = false) String voiceName) { + + List voiceList = modelConfigService.getVoiceList(modelName, voiceName); + return new Result>().ok(voiceList); + } +} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/controller/ModelController.java b/main/manager-api/src/main/java/xiaozhi/modules/model/controller/ModelController.java index f743a795..f38586dc 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/model/controller/ModelController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/controller/ModelController.java @@ -1,106 +1,124 @@ 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.*; -import xiaozhi.common.page.PageData; +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 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.domain.ModelConfig; +import xiaozhi.modules.model.domain.TtsVoice; import xiaozhi.modules.model.service.ModelConfigService; -import xiaozhi.modules.model.service.ModelProviderService; +import xiaozhi.modules.model.service.TtsVoiceService; import java.util.List; +@Slf4j +@Tag(name = "模型数据管理") @AllArgsConstructor @RestController -@RequestMapping("/models") -@Tag(name = "模型配置") -public class ModelController { - - private final ModelProviderService modelProviderService; - +@RequestMapping("/model/") +public class ModelController extends BaseController { + private final TtsVoiceService ttsVoiceService; private final ModelConfigService modelConfigService; - @GetMapping("/models/names") - @Operation(summary = "获取所有模型名称") - @RequiresPermissions("sys:role:superAdmin") - public Result> getModelNames(@RequestParam String modelType, - @RequestParam(required = false) String modelName) { - List modelNameList = modelConfigService.getModelCodeList(modelType, modelName); - return new Result>().ok(modelNameList); - } - @GetMapping("/{modelType}/provideTypes") - @Operation(summary = "获取模型供应器列表") - @RequiresPermissions("sys:role:superAdmin") - public Result> getModelProviderList(@PathVariable String modelType) { - List modelProviderDTOS = modelProviderService.getListByModelType(modelType); - return new Result>().ok(modelProviderDTOS); - } - - @GetMapping("/{modelType}/{provideCode}/fields") - @Operation(summary = "获取模型供应器字段") - @RequiresPermissions("sys:role:superAdmin") - public Result> getModelProviderFields(@PathVariable String modelType, @PathVariable String provideCode) { - List fieldList = modelProviderService.getFieldList(modelType, provideCode); - return new Result>().ok(fieldList); - } - - - @GetMapping("/models/list") - @Operation(summary = "获取模型配置列表") - @RequiresPermissions("sys:role:superAdmin") - public Result> getModelConfigList(@RequestParam String modelType, - @RequestParam(required = false) String modelName, - @RequestParam(required = false, defaultValue = "0") Integer page, - @RequestParam(required = false,defaultValue = "10") Integer limit) { - PageData pageList = modelConfigService.getPageList(modelType, modelName, page, limit); - return new Result>().ok(pageList); - } - - - @PostMapping("/models/{modelType}/{provideCode}") - @Operation(summary = "新增模型配置") - @RequiresPermissions("sys:role:superAdmin") - public Result addModelConfig(@PathVariable String modelType, - @PathVariable String provideCode, - @RequestBody ModelConfigBodyDTO modelConfigBodyDTO) { - ModelConfigDTO modelConfigDTO = modelConfigService.add(modelType, provideCode, modelConfigBodyDTO); - return new Result().ok(modelConfigDTO); - } - - - @PutMapping("/models/{modelType}/{provideCode}/{id}") - @Operation(summary = "编辑模型配置") - @RequiresPermissions("sys:role:superAdmin") - public Result editModelConfig(@PathVariable String modelType, - @PathVariable String provideCode, - @PathVariable String id, - @RequestBody ModelConfigBodyDTO modelConfigBodyDTO) { - ModelConfigDTO modelConfigDTO = modelConfigService.edit(modelType, provideCode, id, modelConfigBodyDTO); - return new Result().ok(modelConfigDTO); - } - - - @DeleteMapping("/models/{modelType}/{provideCode}/{id}") - @Operation(summary = "删除模型配置") - @RequiresPermissions("sys:role:superAdmin") - public Result deleteModelConfig(@PathVariable String modelType, @PathVariable String provideCode, @PathVariable String id) { - modelConfigService.delete(modelType, provideCode, id); - return new Result<>(); - } - - @GetMapping("/models/{modelName}/voices") - @Operation(summary = "获取模型音色") + @GetMapping("/list") + @Operation(summary = "模型配置列表") @RequiresPermissions("sys:role:normal") - public Result> getVoiceList(@PathVariable String modelName, - @RequestParam(required = false) String voiceName) { - - List voiceList = modelConfigService.getVoiceList(modelName, voiceName); - return new Result>().ok(voiceList); + public Result> getModelList() { + List list = modelConfigService.list(new QueryWrapper().eq("is_enabled", 1)); + return new Result>().ok(list); } -} + + +// private final ModelProviderService modelProviderService; +// +// private final ModelConfigService modelConfigService; +// +// @GetMapping("/models/names") +// @Operation(summary = "获取所有模型名称") +// @RequiresPermissions("sys:role:superAdmin") +// public Result> getModelNames(@RequestParam String modelType, +// @RequestParam(required = false) String modelName) { +// List modelNameList = modelConfigService.getModelCodeList(modelType, modelName); +// return new Result>().ok(modelNameList); +// } +// +// @GetMapping("/{modelType}/provideTypes") +// @Operation(summary = "获取模型供应器列表") +// @RequiresPermissions("sys:role:superAdmin") +// public Result> getModelProviderList(@PathVariable String modelType) { +// List modelProviderDTOS = modelProviderService.getListByModelType(modelType); +// return new Result>().ok(modelProviderDTOS); +// } +// +// @GetMapping("/{modelType}/{provideCode}/fields") +// @Operation(summary = "获取模型供应器字段") +// @RequiresPermissions("sys:role:superAdmin") +// public Result> getModelProviderFields(@PathVariable String modelType, @PathVariable String provideCode) { +// List fieldList = modelProviderService.getFieldList(modelType, provideCode); +// return new Result>().ok(fieldList); +// } +// +// +// @GetMapping("/models/list") +// @Operation(summary = "获取模型配置列表") +// @RequiresPermissions("sys:role:superAdmin") +// public Result> getModelConfigList(@RequestParam String modelType, +// @RequestParam(required = false) String modelName, +// @RequestParam(required = false, defaultValue = "0") Integer page, +// @RequestParam(required = false,defaultValue = "10") Integer limit) { +// PageData pageList = modelConfigService.getPageList(modelType, modelName, page, limit); +// return new Result>().ok(pageList); +// } +// +// +// @PostMapping("/models/{modelType}/{provideCode}") +// @Operation(summary = "新增模型配置") +// @RequiresPermissions("sys:role:superAdmin") +// public Result addModelConfig(@PathVariable String modelType, +// @PathVariable String provideCode, +// @RequestBody ModelConfigBodyDTO modelConfigBodyDTO) { +// ModelConfigDTO modelConfigDTO = modelConfigService.add(modelType, provideCode, modelConfigBodyDTO); +// return new Result().ok(modelConfigDTO); +// } +// +// +// @PutMapping("/models/{modelType}/{provideCode}/{id}") +// @Operation(summary = "编辑模型配置") +// @RequiresPermissions("sys:role:superAdmin") +// public Result editModelConfig(@PathVariable String modelType, +// @PathVariable String provideCode, +// @PathVariable String id, +// @RequestBody ModelConfigBodyDTO modelConfigBodyDTO) { +// ModelConfigDTO modelConfigDTO = modelConfigService.edit(modelType, provideCode, id, modelConfigBodyDTO); +// return new Result().ok(modelConfigDTO); +// } +// +// +// @DeleteMapping("/models/{modelType}/{provideCode}/{id}") +// @Operation(summary = "删除模型配置") +// @RequiresPermissions("sys:role:superAdmin") +// public Result 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> getVoiceList(@PathVariable String modelName, +// @RequestParam(required = false) String voiceName) { +// +// List voiceList = modelConfigService.getVoiceList(modelName, voiceName); +// return new Result>().ok(voiceList); +// } +} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/controller/TtsController.java b/main/manager-api/src/main/java/xiaozhi/modules/model/controller/TtsController.java new file mode 100644 index 00000000..0e00ce0a --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/controller/TtsController.java @@ -0,0 +1,124 @@ +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> getTtsList(@RequestParam(required = false) String ttsModelId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (StringUtils.isNotBlank(ttsModelId)) { + queryWrapper.eq("ttsModelId", ttsModelId); + } + queryWrapper.orderByAsc("sort"); + List list = ttsVoiceService.list(queryWrapper); + return new Result>().ok(list); + } + + +// private final ModelProviderService modelProviderService; +// +// private final ModelConfigService modelConfigService; +// +// @GetMapping("/models/names") +// @Operation(summary = "获取所有模型名称") +// @RequiresPermissions("sys:role:superAdmin") +// public Result> getModelNames(@RequestParam String modelType, +// @RequestParam(required = false) String modelName) { +// List modelNameList = modelConfigService.getModelCodeList(modelType, modelName); +// return new Result>().ok(modelNameList); +// } +// +// @GetMapping("/{modelType}/provideTypes") +// @Operation(summary = "获取模型供应器列表") +// @RequiresPermissions("sys:role:superAdmin") +// public Result> getModelProviderList(@PathVariable String modelType) { +// List modelProviderDTOS = modelProviderService.getListByModelType(modelType); +// return new Result>().ok(modelProviderDTOS); +// } +// +// @GetMapping("/{modelType}/{provideCode}/fields") +// @Operation(summary = "获取模型供应器字段") +// @RequiresPermissions("sys:role:superAdmin") +// public Result> getModelProviderFields(@PathVariable String modelType, @PathVariable String provideCode) { +// List fieldList = modelProviderService.getFieldList(modelType, provideCode); +// return new Result>().ok(fieldList); +// } +// +// +// @GetMapping("/models/list") +// @Operation(summary = "获取模型配置列表") +// @RequiresPermissions("sys:role:superAdmin") +// public Result> getModelConfigList(@RequestParam String modelType, +// @RequestParam(required = false) String modelName, +// @RequestParam(required = false, defaultValue = "0") Integer page, +// @RequestParam(required = false,defaultValue = "10") Integer limit) { +// PageData pageList = modelConfigService.getPageList(modelType, modelName, page, limit); +// return new Result>().ok(pageList); +// } +// +// +// @PostMapping("/models/{modelType}/{provideCode}") +// @Operation(summary = "新增模型配置") +// @RequiresPermissions("sys:role:superAdmin") +// public Result addModelConfig(@PathVariable String modelType, +// @PathVariable String provideCode, +// @RequestBody ModelConfigBodyDTO modelConfigBodyDTO) { +// ModelConfigDTO modelConfigDTO = modelConfigService.add(modelType, provideCode, modelConfigBodyDTO); +// return new Result().ok(modelConfigDTO); +// } +// +// +// @PutMapping("/models/{modelType}/{provideCode}/{id}") +// @Operation(summary = "编辑模型配置") +// @RequiresPermissions("sys:role:superAdmin") +// public Result editModelConfig(@PathVariable String modelType, +// @PathVariable String provideCode, +// @PathVariable String id, +// @RequestBody ModelConfigBodyDTO modelConfigBodyDTO) { +// ModelConfigDTO modelConfigDTO = modelConfigService.edit(modelType, provideCode, id, modelConfigBodyDTO); +// return new Result().ok(modelConfigDTO); +// } +// +// +// @DeleteMapping("/models/{modelType}/{provideCode}/{id}") +// @Operation(summary = "删除模型配置") +// @RequiresPermissions("sys:role:superAdmin") +// public Result 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> getVoiceList(@PathVariable String modelName, +// @RequestParam(required = false) String voiceName) { +// +// List voiceList = modelConfigService.getVoiceList(modelName, voiceName); +// return new Result>().ok(voiceList); +// } +} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/domain/ModelConfig.java b/main/manager-api/src/main/java/xiaozhi/modules/model/domain/ModelConfig.java new file mode 100644 index 00000000..938565f9 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/domain/ModelConfig.java @@ -0,0 +1,91 @@ +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; +} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/domain/ModelProvider.java b/main/manager-api/src/main/java/xiaozhi/modules/model/domain/ModelProvider.java new file mode 100644 index 00000000..af21ffac --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/domain/ModelProvider.java @@ -0,0 +1,71 @@ +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; +} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/domain/TtsVoice.java b/main/manager-api/src/main/java/xiaozhi/modules/model/domain/TtsVoice.java new file mode 100644 index 00000000..744bd6e8 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/domain/TtsVoice.java @@ -0,0 +1,81 @@ +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; +} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/mapper/ModelConfigMapper.java b/main/manager-api/src/main/java/xiaozhi/modules/model/mapper/ModelConfigMapper.java new file mode 100644 index 00000000..0bbf4ca8 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/mapper/ModelConfigMapper.java @@ -0,0 +1,20 @@ +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 { + +} + + + + diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/mapper/ModelProviderMapper.java b/main/manager-api/src/main/java/xiaozhi/modules/model/mapper/ModelProviderMapper.java new file mode 100644 index 00000000..f3fa01ce --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/mapper/ModelProviderMapper.java @@ -0,0 +1,20 @@ +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 { + +} + + + + diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/mapper/TtsVoiceMapper.java b/main/manager-api/src/main/java/xiaozhi/modules/model/mapper/TtsVoiceMapper.java new file mode 100644 index 00000000..c4ec5089 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/mapper/TtsVoiceMapper.java @@ -0,0 +1,20 @@ +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 { + +} + + + + diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/service/Conflict_ModelConfigService.java b/main/manager-api/src/main/java/xiaozhi/modules/model/service/Conflict_ModelConfigService.java new file mode 100644 index 00000000..8ce94539 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/service/Conflict_ModelConfigService.java @@ -0,0 +1,22 @@ +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 getModelCodeList(String modelType, String modelName); + + PageData 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 getVoiceList(String modelName, String voiceName); +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/service/Conflict_ModelProviderService.java b/main/manager-api/src/main/java/xiaozhi/modules/model/service/Conflict_ModelProviderService.java new file mode 100644 index 00000000..47b70cbf --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/service/Conflict_ModelProviderService.java @@ -0,0 +1,23 @@ +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 getModelNames(String modelType, String modelName); + + List getListByModelType(String modelType); + + ModelProviderDTO add(ModelProviderEntity modelProviderEntity); + + ModelProviderDTO edit(ModelProviderEntity modelProviderEntity); + + void delete(); + + List getList(String modelType, String provideCode); + + List getFieldList(String modelType, String provideCode); +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/service/ModelConfigService.java b/main/manager-api/src/main/java/xiaozhi/modules/model/service/ModelConfigService.java index 1911be78..25a7be88 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/model/service/ModelConfigService.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/service/ModelConfigService.java @@ -1,22 +1,13 @@ package xiaozhi.modules.model.service; -import xiaozhi.common.page.PageData; -import xiaozhi.modules.model.dto.ModelConfigBodyDTO; -import xiaozhi.modules.model.dto.ModelConfigDTO; +import com.baomidou.mybatisplus.extension.service.IService; +import xiaozhi.modules.model.domain.ModelConfig; -import java.util.List; +/** + * @author chenerlei + * @description 针对表【ai_model_config(模型配置表)】的数据库操作Service + * @createDate 2025-03-22 15:31:57 + */ +public interface ModelConfigService extends IService { -public interface ModelConfigService { - - List getModelCodeList(String modelType, String modelName); - - PageData 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 getVoiceList(String modelName, String voiceName); } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/service/ModelProviderService.java b/main/manager-api/src/main/java/xiaozhi/modules/model/service/ModelProviderService.java index d0d221cf..d5a76615 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/model/service/ModelProviderService.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/service/ModelProviderService.java @@ -1,23 +1,13 @@ package xiaozhi.modules.model.service; -import xiaozhi.modules.model.dto.ModelProviderDTO; -import xiaozhi.modules.model.entity.ModelProviderEntity; +import com.baomidou.mybatisplus.extension.service.IService; +import xiaozhi.modules.model.domain.ModelProvider; -import java.util.List; +/** + * @author chenerlei + * @description 针对表【ai_model_provider(模型配置表)】的数据库操作Service + * @createDate 2025-03-24 18:24:13 + */ +public interface ModelProviderService extends IService { -public interface ModelProviderService { - -// List getModelNames(String modelType, String modelName); - - List getListByModelType(String modelType); - - ModelProviderDTO add(ModelProviderEntity modelProviderEntity); - - ModelProviderDTO edit(ModelProviderEntity modelProviderEntity); - - void delete(); - - List getList(String modelType, String provideCode); - - List getFieldList(String modelType, String provideCode); } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/service/TtsVoiceService.java b/main/manager-api/src/main/java/xiaozhi/modules/model/service/TtsVoiceService.java new file mode 100644 index 00000000..b5a6ecb3 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/service/TtsVoiceService.java @@ -0,0 +1,13 @@ +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 { + +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/Conflict_ModelConfigServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/Conflict_ModelConfigServiceImpl.java new file mode 100644 index 00000000..696df42a --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/Conflict_ModelConfigServiceImpl.java @@ -0,0 +1,124 @@ +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 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 getModelCodeList(String modelType, String modelName) { + return modelConfigDao.getModelCodeList(modelType, modelName); + } + + @Override + public PageData getPageList(String modelType, String modelName, Integer page, Integer limit) { + Map params = new HashMap(); + params.put(Constant.PAGE, page); + params.put(Constant.LIMIT, limit); + IPage modelConfigEntityIPage = modelConfigDao.selectPage( + getPage(params, "sort", true), + new QueryWrapper() + .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 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 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 providerList = modelProviderService.getList(modelType, provideCode); + if (CollectionUtil.isEmpty(providerList)) { + throw new RenException("供应器不存在"); + } + + modelConfigDao.deleteById(Long.getLong(id)); + } + + @Override + public List getVoiceList(String modelName, String voiceName) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("model_name", StringUtils.isBlank(modelName) ? "" : modelName); + queryWrapper.eq("model_type", "TTS"); + List 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); + } +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/Conflict_ModelProviderServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/Conflict_ModelProviderServiceImpl.java new file mode 100644 index 00000000..36c63d5e --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/Conflict_ModelProviderServiceImpl.java @@ -0,0 +1,59 @@ +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 implements Conflict_ModelProviderService { + + private final ModelProviderDao modelProviderDao; + + @Override + public List getListByModelType(String modelType) { + + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("model_type", StringUtils.isBlank(modelType) ? "" : modelType); + List 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 getList(String modelType, String provideCode) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("model_type", StringUtils.isBlank(modelType) ? "" : modelType); + queryWrapper.eq("provide_code", StringUtils.isBlank(provideCode) ? "" : provideCode); + List providerEntities = modelProviderDao.selectList(queryWrapper); + return ConvertUtils.sourceToTarget(providerEntities, ModelProviderDTO.class); + } + + @Override + public List getFieldList(String modelType, String provideCode) { + return modelProviderDao.getFieldList(modelType, provideCode); + } +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelConfigServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelConfigServiceImpl.java index a7ba9b10..41af10c3 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelConfigServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelConfigServiceImpl.java @@ -1,124 +1,22 @@ 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 com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 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.domain.ModelConfig; +import xiaozhi.modules.model.mapper.ModelConfigMapper; 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 -@AllArgsConstructor -public class ModelConfigServiceImpl extends BaseServiceImpl implements ModelConfigService { +public class ModelConfigServiceImpl extends ServiceImpl + 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 getModelCodeList(String modelType, String modelName) { - return modelConfigDao.getModelCodeList(modelType, modelName); - } - - @Override - public PageData getPageList(String modelType, String modelName, Integer page, Integer limit) { - Map params = new HashMap(); - params.put(Constant.PAGE, page); - params.put(Constant.LIMIT, limit); - IPage modelConfigEntityIPage = modelConfigDao.selectPage( - getPage(params, "sort", true), - new QueryWrapper() - .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 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 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 providerList = modelProviderService.getList(modelType, provideCode); - if (CollectionUtil.isEmpty(providerList)) { - throw new RenException("供应器不存在"); - } - - modelConfigDao.deleteById(Long.getLong(id)); - } - - @Override - public List getVoiceList(String modelName, String voiceName) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("model_name", StringUtils.isBlank(modelName) ? "" : modelName); - queryWrapper.eq("model_type", "TTS"); - List 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); - } } + + + + diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelProviderServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelProviderServiceImpl.java index 042749d9..53e6ae70 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelProviderServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelProviderServiceImpl.java @@ -1,59 +1,22 @@ package xiaozhi.modules.model.service.impl; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import lombok.AllArgsConstructor; -import org.apache.commons.lang3.StringUtils; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 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.domain.ModelProvider; +import xiaozhi.modules.model.mapper.ModelProviderMapper; import xiaozhi.modules.model.service.ModelProviderService; -import java.util.List; - +/** + * @author chenerlei + * @description 针对表【ai_model_provider(模型配置表)】的数据库操作Service实现 + * @createDate 2025-03-24 18:24:13 + */ @Service -@AllArgsConstructor -public class ModelProviderServiceImpl extends BaseServiceImpl implements ModelProviderService { +public class ModelProviderServiceImpl extends ServiceImpl + implements ModelProviderService { - private final ModelProviderDao modelProviderDao; - - @Override - public List getListByModelType(String modelType) { - - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("model_type", StringUtils.isBlank(modelType) ? "" : modelType); - List 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 getList(String modelType, String provideCode) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("model_type", StringUtils.isBlank(modelType) ? "" : modelType); - queryWrapper.eq("provide_code", StringUtils.isBlank(provideCode) ? "" : provideCode); - List providerEntities = modelProviderDao.selectList(queryWrapper); - return ConvertUtils.sourceToTarget(providerEntities, ModelProviderDTO.class); - } - - @Override - public List getFieldList(String modelType, String provideCode) { - return modelProviderDao.getFieldList(modelType, provideCode); - } } + + + + diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/TtsVoiceServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/TtsVoiceServiceImpl.java new file mode 100644 index 00000000..cb27eaa4 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/TtsVoiceServiceImpl.java @@ -0,0 +1,22 @@ +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 + implements TtsVoiceService{ + +} + + + + diff --git a/main/manager-api/src/main/java/xiaozhi/modules/ota/controller/OtaController.java b/main/manager-api/src/main/java/xiaozhi/modules/ota/controller/OtaController.java new file mode 100644 index 00000000..de3c1195 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/ota/controller/OtaController.java @@ -0,0 +1,145 @@ +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().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().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> getOtalist(@RequestParam Integer pageNo, @RequestParam Integer pageSize) { + UserDetail user = SecurityUser.getUser(); + Page page = new Page(pageNo, pageSize); + page = otaService.page(page); + return new Result>().ok(page); + } + + @PostMapping("/sys/save") + @Operation(summary = "添加设备OTA") + @RequiresPermissions("sys:role:superAdmin") + public Result 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().ok(null); + } + + @PostMapping("/sys/update") + @Operation(summary = "更新设备OTA") + @RequiresPermissions("sys:role:superAdmin") + public Result update(@RequestBody Ota ota) { + UserDetail user = SecurityUser.getUser(); + boolean bool = otaService.update( + new UpdateWrapper().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().ok(null); + } + + @PostMapping("/sys/toggleEnabled") + @Operation(summary = "切换设备OTA可用状态") + @RequiresPermissions("sys:role:superAdmin") + public Result toggleEnabled(@RequestBody Ota ota) { + UserDetail user = SecurityUser.getUser(); + boolean bool = otaService.update( + new UpdateWrapper().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().ok(null); + } +} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/ota/domain/Ota.java b/main/manager-api/src/main/java/xiaozhi/modules/ota/domain/Ota.java new file mode 100644 index 00000000..e07fc4e0 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/ota/domain/Ota.java @@ -0,0 +1,66 @@ +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; +} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/ota/mapper/OtaMapper.java b/main/manager-api/src/main/java/xiaozhi/modules/ota/mapper/OtaMapper.java new file mode 100644 index 00000000..e083316f --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/ota/mapper/OtaMapper.java @@ -0,0 +1,20 @@ +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 { + +} + + + + diff --git a/main/manager-api/src/main/java/xiaozhi/modules/ota/service/OtaService.java b/main/manager-api/src/main/java/xiaozhi/modules/ota/service/OtaService.java new file mode 100644 index 00000000..cad7e830 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/ota/service/OtaService.java @@ -0,0 +1,13 @@ +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 { + +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/ota/service/impl/OtaServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/ota/service/impl/OtaServiceImpl.java new file mode 100644 index 00000000..1956a95d --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/ota/service/impl/OtaServiceImpl.java @@ -0,0 +1,22 @@ +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 + implements OtaService{ + +} + + + + diff --git a/main/manager-api/src/main/java/xiaozhi/modules/security/config/ShiroConfig.java b/main/manager-api/src/main/java/xiaozhi/modules/security/config/ShiroConfig.java index de25d80e..74b85933 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/security/config/ShiroConfig.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/security/config/ShiroConfig.java @@ -73,6 +73,8 @@ public class ShiroConfig { filterMap.put("/user/captcha", "anon"); 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); diff --git a/main/manager-api/src/main/java/xiaozhi/modules/security/oauth2/Oauth2Filter.java b/main/manager-api/src/main/java/xiaozhi/modules/security/oauth2/Oauth2Filter.java index 55e3fa03..8f110941 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/security/oauth2/Oauth2Filter.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/security/oauth2/Oauth2Filter.java @@ -56,9 +56,9 @@ public class Oauth2Filter extends AuthenticatingFilter { String token = getRequestToken((HttpServletRequest) request); // TODO 调试接口,临时取消登录限制,需要 token 参数的除外 - if (true) { - return true; - } +// if (true) { +// return true; +// } if (StringUtils.isBlank(token)) { logger.warn("onAccessDenied:token is empty"); diff --git a/main/manager-api/src/main/resources/application-dev.yml b/main/manager-api/src/main/resources/application-dev.yml index a8fdf21f..f149133e 100644 --- a/main/manager-api/src/main/resources/application-dev.yml +++ b/main/manager-api/src/main/resources/application-dev.yml @@ -41,4 +41,23 @@ spring: merge-sql: false wall: config: - multi-statement-allow: true \ No newline at end of file + multi-statement-allow: true + data: + redis: + host: localhost # 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: + max-active: 8 # 连接池最大连接数(使用负值表示没有限制) + max-idle: 8 # 连接池中的最大空闲连接 + min-idle: 0 # 连接池中的最小空闲连接 + shutdown-timeout: 100ms # 客户端优雅关闭的等待时间 \ No newline at end of file diff --git a/main/manager-api/src/main/resources/application.yml b/main/manager-api/src/main/resources/application.yml index 03f6a044..74dfb0e6 100644 --- a/main/manager-api/src/main/resources/application.yml +++ b/main/manager-api/src/main/resources/application.yml @@ -24,21 +24,9 @@ spring: max-file-size: 100MB max-request-size: 100MB enabled: true - data: - redis: - database: 0 - host: 127.0.0.1 - port: 6379 - password: # 密码(默认为空) - timeout: 6000ms # 连接超时时长(毫秒) - lettuce: - pool: - max-active: 1000 # 连接池最大连接数(使用负值表示没有限制) - max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制) - max-idle: 10 # 连接池中的最大空闲连接 - min-idle: 5 # 连接池中的最小空闲连接 main: allow-bean-definition-overriding: true + knife4j: enable: true basic: @@ -50,7 +38,7 @@ knife4j: renren: redis: - open: false + open: true xss: enabled: true exclude-urls: @@ -59,7 +47,7 @@ renren: mybatis-plus: mapper-locations: classpath*:/mapper/**/*.xml #实体扫描,多个package用逗号或者分号分隔 - typeAliasesPackage: xiaozhi.modules.*.entity + typeAliasesPackage: xiaozhi.modules.*.entity;xiaozhi.modules.*.domain global-config: #数据库相关配置 db-config: diff --git a/main/manager-api/src/main/resources/db/changelog/202503241020.sql b/main/manager-api/src/main/resources/db/changelog/202503241020.sql new file mode 100644 index 00000000..094640fa --- /dev/null +++ b/main/manager-api/src/main/resources/db/changelog/202503241020.sql @@ -0,0 +1,48 @@ +-- 修改字段名 +ALTER TABLE `ai_agent` RENAME COLUMN `mem_model_id` TO `memory_model_id`; +ALTER TABLE `ai_agent_template` RENAME COLUMN `mem_model_id` TO `memory_model_id`; +-- 添加字段 +ALTER TABLE `ai_agent_template` ADD COLUMN `is_default` tinyint(1) NULL DEFAULT 0 COMMENT '是否默认模板:1:是,0:不是' AFTER `sort`; + +-- 初始化智能体模板数据 +INSERT INTO `ai_agent_template` VALUES ('9406648b5cc5fde1b8aa335b6f8b4f76', '小智', '湾湾小何', '45f8b0d6dd3d4bfa8a28e6e0f5912d45', '23e7c9d090ea4d1e9b25f4c8d732a3a1', 'e9f2d891afbe4632b13a47c7a8c6e03d', 'd50b06e9b8104d0d9c0f7316d258abcb', 'fcac83266edadd5a3125f06cfee1906b', 'e2274b90e89ddda85207f55484d8b528', 'c4e12f874a3f4aa99f5b2c18e15d407b', '你是一个叫{{assistant_name}}的台湾女孩,说话机车,声音好听,习惯简短表达,爱用网络梗。\n请注意,要像一个人一样说话,请不要回复表情符号、代码、和xml标签。\n现在我正在和你进行语音聊天,我们开始吧。\n如果用户希望结束对话,请在最后说“拜拜”或“再见”。', 'zh', '中文', 1, 1, NULL, NULL, NULL, NULL); +INSERT INTO `ai_agent_template` VALUES ('0ca32eb728c949e58b1000b2e401f90c', '小智', '通用男声', '45f8b0d6dd3d4bfa8a28e6e0f5912d45', '23e7c9d090ea4d1e9b25f4c8d732a3a1', 'e9f2d891afbe4632b13a47c7a8c6e03d', '896db62c9dd74976ab0e8c14bf924d9d', '1f2e3d4c5b6a7f8e9d0c1b2a3f4e5bx2', 'e2274b90e89ddda85207f55484d8b528', 'c4e12f874a3f4aa99f5b2c18e15d407b', '你是一个叫{{assistant_name}}的男生,说话机车,声音好听,习惯简短表达,爱用网络梗。\n请注意,要像一个人一样说话,请不要回复表情符号、代码、和xml标签。\n现在我正在和你进行语音聊天,我们开始吧。\n如果用户希望结束对话,请在最后说“拜拜”或“再见”。', 'zh', '中文', 2, 0, NULL, NULL, NULL, NULL); +INSERT INTO `ai_agent_template` VALUES ('6c7d8e9f0a1b2c3d4e5f6a7b8c9d0s24', '小智', '通用女声', '45f8b0d6dd3d4bfa8a28e6e0f5912d45', '23e7c9d090ea4d1e9b25f4c8d732a3a1', 'e9f2d891afbe4632b13a47c7a8c6e03d', '896db62c9dd74976ab0e8c14bf924d9d', '9e8f7a6b5c4d3e2f1a0b9c8d7e6f5ad3', 'e2274b90e89ddda85207f55484d8b528', 'c4e12f874a3f4aa99f5b2c18e15d407b', '你是一个叫{{assistant_name}}的女生,说话机车,声音好听,习惯简短表达,爱用网络梗。\n请注意,要像一个人一样说话,请不要回复表情符号、代码、和xml标签。\n现在我正在和你进行语音聊天,我们开始吧。\n如果用户希望结束对话,请在最后说“拜拜”或“再见”。', 'zh', '中文', 3, 0, NULL, NULL, NULL, NULL); +INSERT INTO `ai_agent_template` VALUES ('e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b1', '小智', '阳光男生', '45f8b0d6dd3d4bfa8a28e6e0f5912d45', '23e7c9d090ea4d1e9b25f4c8d732a3a1', 'e9f2d891afbe4632b13a47c7a8c6e03d', '896db62c9dd74976ab0e8c14bf924d9d', '2b3c4d5e6f7a8b9c0d1e2f3a4b5c62a2', 'e2274b90e89ddda85207f55484d8b528', 'c4e12f874a3f4aa99f5b2c18e15d407b', '你是一个叫{{assistant_name}}的男生,说话机车,声音好听,习惯简短表达,爱用网络梗。\n请注意,要像一个人一样说话,请不要回复表情符号、代码、和xml标签。\n现在我正在和你进行语音聊天,我们开始吧。\n如果用户希望结束对话,请在最后说“拜拜”或“再见”。', 'zh', '中文', 4, 0, NULL, NULL, NULL, NULL); +INSERT INTO `ai_agent_template` VALUES ('a45b6c7d8e9f0a1b2c3d4e5f6a7b8c92', '小智', '奶气萌娃', '45f8b0d6dd3d4bfa8a28e6e0f5912d45', '23e7c9d090ea4d1e9b25f4c8d732a3a1', 'e9f2d891afbe4632b13a47c7a8c6e03d', '896db62c9dd74976ab0e8c14bf924d9d', 'f7a38c03d5644e22b6d84f8923a74c51', 'e2274b90e89ddda85207f55484d8b528', 'c4e12f874a3f4aa99f5b2c18e15d407b', '你是一个叫{{assistant_name}}的萌娃,声音可爱,习惯简短表达,爱用网络梗。\n请注意,要像一个人一样说话,请不要回复表情符号、代码、和xml标签。\n现在我正在和你进行语音聊天,我们开始吧。\n如果用户希望结束对话,请在最后说“拜拜”或“再见”。', 'zh', '中文', 5, 0, NULL, NULL, NULL, NULL); + +-- 初始化模型配置数据 +INSERT INTO `ai_model_config` VALUES ('23e7c9d090ea4d1e9b25f4c8d732a3a1', 'VAD', 'SileroVAD', 'SileroVAD', 1, 1, '{\"SileroVAD\": {\"model_dir\": \"models/snakers4_silero-vad\", \"threshold\": 0.5, \"min_silence_duration_ms\": 700}}', NULL, NULL, 0, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('45f8b0d6dd3d4bfa8a28e6e0f5912d45', 'ASR', 'FunASR', 'FunASR', 1, 1, '{\"FunASR\": {\"type\": \"fun_local\", \"model_dir\": \"models/SenseVoiceSmall\", \"output_dir\": \"tmp/\"}}', NULL, NULL, 0, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('e2274b90e89ddda85207f55484d8b528', 'Memory', 'nomem', 'nomem', 1, 1, '{\"mem0ai\": {\"type\": \"nomem\"}}', NULL, NULL, 0, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('3930ac3448faf621f0a120bc829dfdfa', 'Memory', 'mem_local_short', 'mem_local_short', 1, 1, '{\"mem_local_short\": {\"type\": \"mem_local_short\"}}', NULL, NULL, 0, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('a07f3d25f52340b2b2a1e8d264079e1a', 'Memory', 'mem0ai', 'mem0ai', 1, 1, '{\"mem0ai\": {\"type\": \"mem0ai\", \"api_key\": \"你的mem0ai api key\"}}', NULL, NULL, 0, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('7a1c0a8e6d0e4035b982a4c07c3a5f76', 'LLM', 'AliLLM', 'AliLLM', 1, 1, '{\"AliLLM\": {\"type\": \"openai\", \"top_k\": 50, \"top_p\": 1, \"api_key\": \"你的ali api key\", \"base_url\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\", \"max_tokens\": 500, \"model_name\": \"qwen-turbo\", \"temperature\": 0.7, \"frequency_penalty\": 0}}', NULL, NULL, 0, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('e9f2d891afbe4632b13a47c7a8c6e03d', 'LLM', 'ChatGLMLLM', 'ChatGLMLLM', 1, 1, '{\"ChatGLMLLM\": {\"url\": \"https://open.bigmodel.cn/api/paas/v4/\", \"type\": \"openai\", \"api_key\": \"0415dad4014847babc3e3f03024c50a3.qH7FgTy5Yawc85fl\", \"model_name\": \"glm-4-flash\"}}', NULL, NULL, 0, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('d50b06e9b8104d0d9c0f7316d258abcb', 'TTS', 'EdgeTTS', 'EdgeTTS', 1, 1, '{\"EdgeTTS\": {\"type\": \"edge\", \"voice\": \"zh-CN-XiaoxiaoNeural\", \"output_dir\": \"tmp/\"}}', NULL, NULL, 0, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('896db62c9dd74976ab0e8c14bf924d9d', 'TTS', 'DoubaoTTS', 'DoubaoTTS', 1, 1, '{\"DoubaoTTS\": {\"type\": \"doubao\", \"appid\": \"你的火山引擎语音合成服务appid\", \"voice\": \"BV034_streaming\", \"api_url\": \"https://openspeech.bytedance.com/api/v1/tts\", \"cluster\": \"volcano_tts\", \"output_dir\": \"tmp/\", \"access_token\": \"你的火山引擎语音合成服务access_token\", \"authorization\": \"Bearer;\"}}', NULL, NULL, 0, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('c4e12f874a3f4aa99f5b2c18e15d407b', 'Intent', 'function_call', 'function_call', 1, 1, '{\"function_call\": {\"type\": \"nointent\", \"functions\": [\"change_role\", \"get_weather\", \"get_news\", \"play_music\"]}}', NULL, NULL, 0, NULL, NULL, NULL, NULL); + +-- 初始化音色数据 +INSERT INTO `ai_tts_voice` VALUES ('fcac83266edadd5a3125f06cfee1906b', 'd50b06e9b8104d0d9c0f7316d258abcb', '湾湾小何', 'zh-CN-XiaoxiaoNeural', '中文', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/湾湾小何.mp3', NULL, 1, NULL, NULL, NULL, NULL); +INSERT INTO `ai_tts_voice` VALUES ('1f2e3d4c5b6a7f8e9d0c1b2a3f4e5bx2', '896db62c9dd74976ab0e8c14bf924d9d', '通用男声', 'BV002_streaming', '中文', 'https://lf3-speech.bytetos.com/obj/speech-tts-external/portal/Portal_Demo_BV002.mp3', NULL, 2, NULL, NULL, NULL, NULL); +INSERT INTO `ai_tts_voice` VALUES ('9e8f7a6b5c4d3e2f1a0b9c8d7e6f5ad3', '896db62c9dd74976ab0e8c14bf924d9d', '通用女声', 'BV001_streaming', '中文', 'https://lf3-speech.bytetos.com/obj/speech-tts-external/portal/Portal_Demo_BV001.mp3', NULL, 3, NULL, NULL, NULL, NULL); +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升级信息表'; diff --git a/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml b/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml index 89ed7ff5..41d9f61a 100755 --- a/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml @@ -15,4 +15,11 @@ databaseChangeLog: changes: - sqlFile: encoding: utf8 - path: classpath:db/changelog/202503141346.sql \ No newline at end of file + path: classpath:db/changelog/202503141346.sql + - changeSet: + id: 202503241020 + author: dreamchen + changes: + - sqlFile: + encoding: utf8 + path: classpath:db/changelog/202503241020.sql \ No newline at end of file diff --git a/main/manager-api/src/main/resources/mapper/agent/AgentMapper.xml b/main/manager-api/src/main/resources/mapper/agent/AgentMapper.xml new file mode 100644 index 00000000..c618401e --- /dev/null +++ b/main/manager-api/src/main/resources/mapper/agent/AgentMapper.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + diff --git a/main/manager-api/src/main/resources/mapper/agent/AgentTemplateMapper.xml b/main/manager-api/src/main/resources/mapper/agent/AgentTemplateMapper.xml new file mode 100644 index 00000000..d099171a --- /dev/null +++ b/main/manager-api/src/main/resources/mapper/agent/AgentTemplateMapper.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + diff --git a/main/manager-api/src/main/resources/mapper/device/DeviceMapper.xml b/main/manager-api/src/main/resources/mapper/device/DeviceMapper.xml new file mode 100644 index 00000000..743003f7 --- /dev/null +++ b/main/manager-api/src/main/resources/mapper/device/DeviceMapper.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + id,user_id,mac_address,last_connected_at,auto_update,board, + alias,agent_id,app_version,sort,creator, + create_date,updater,update_date + + diff --git a/main/manager-api/src/main/resources/mapper/model/ModelConfigMapper.xml b/main/manager-api/src/main/resources/mapper/model/ModelConfigMapper.xml new file mode 100644 index 00000000..90cf097b --- /dev/null +++ b/main/manager-api/src/main/resources/mapper/model/ModelConfigMapper.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + id,model_type,model_code,model_name,is_default,is_enabled, + config_json,doc_link,remark,sort,creator, + create_date,updater,update_date + + diff --git a/main/manager-api/src/main/resources/mapper/model/ModelProviderMapper.xml b/main/manager-api/src/main/resources/mapper/model/ModelProviderMapper.xml new file mode 100644 index 00000000..c4d2ae8f --- /dev/null +++ b/main/manager-api/src/main/resources/mapper/model/ModelProviderMapper.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + id,model_type,provider_code,name,fields,sort, + creator,create_date,updater,update_date + + diff --git a/main/manager-api/src/main/resources/mapper/model/TtsVoiceMapper.xml b/main/manager-api/src/main/resources/mapper/model/TtsVoiceMapper.xml new file mode 100644 index 00000000..008cc4ed --- /dev/null +++ b/main/manager-api/src/main/resources/mapper/model/TtsVoiceMapper.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + id,tts_model_id,name,tts_voice,languages,voice_demo, + remark,sort,creator,create_date,updater, + update_date + + diff --git a/main/manager-api/src/main/resources/mapper/ota/OtaMapper.xml b/main/manager-api/src/main/resources/mapper/ota/OtaMapper.xml new file mode 100644 index 00000000..a3ab550c --- /dev/null +++ b/main/manager-api/src/main/resources/mapper/ota/OtaMapper.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + id,board,app_version,url,is_enabled,creator, + create_date,updater,update_date + + diff --git a/main/manager-web/src/apis/api.js b/main/manager-web/src/apis/api.js index 2f789925..178b2bfc 100755 --- a/main/manager-web/src/apis/api.js +++ b/main/manager-web/src/apis/api.js @@ -1,15 +1,20 @@ // 引入各个模块的请求 +import agent from './module/agent.js' +import device from './module/device.js' import user from './module/user.js' +import ota from './module/ota.js' +import model from './module/model.js' import admin from './module/admin.js' + /** * 接口地址 * 当前8002端口接口还没开发完成,暂时用 apifoxmock 接口代替 * 如果你想调用8002端口,就用'/xiaozhi-esp32-api/api/v1',请与vue.config.js的devServer配置相结合,方便跨域请求 * */ -const DEV_API_SERVICE = 'https://apifoxmock.com/m1/5931378-5618560-default' +// const DEV_API_SERVICE = 'https://m1.apifoxmock.com/m1/5931378-5618560-default' // 8002开发完成完成后使用这个 -// const DEV_API_SERVICE = '/xiaozhi-esp32-api' +const DEV_API_SERVICE = '/xiaozhi-esp32-api/api/v1' /** * 根据开发环境返回接口url @@ -24,4 +29,9 @@ export function getServiceUrl() { export default { getServiceUrl, user, + agent, + device, + ota, + model, + admin } diff --git a/main/manager-web/src/apis/httpRequest.js b/main/manager-web/src/apis/httpRequest.js index 98f47bf7..ec7c922b 100755 --- a/main/manager-web/src/apis/httpRequest.js +++ b/main/manager-web/src/apis/httpRequest.js @@ -109,6 +109,7 @@ function httpHandlerError(info, callBack) { if (info.data.code === 'success' || info.data.code === 0 || info.data.code === undefined) { return networkError }else if (info.data.code === 401) { + store.commit('setToken','') goToPage(Constant.PAGE.LOGIN, true) return true } else { diff --git a/main/manager-web/src/apis/module/admin.js b/main/manager-web/src/apis/module/admin.js index 52468d6b..231443c3 100644 --- a/main/manager-web/src/apis/module/admin.js +++ b/main/manager-web/src/apis/module/admin.js @@ -5,16 +5,16 @@ import {getServiceUrl} from '../api' export default { // 用户列表 getUserList(callback) { - RequestService.sendRequest().url(`${getServiceUrl()}/api/v1/admin/users`) + RequestService.sendRequest().url(`${getServiceUrl()}/admin/users`) .method('GET') .success((res) => { RequestService.clearRequestTime() callback(res) }) .fail(() => { - RequestService.reAjaxFun(() => { - this.getList() - }) + // RequestService.reAjaxFun(() => { + // this.getUserList() + // }) }).send() }, } diff --git a/main/manager-web/src/apis/module/agent.js b/main/manager-web/src/apis/module/agent.js new file mode 100755 index 00000000..2cac9840 --- /dev/null +++ b/main/manager-web/src/apis/module/agent.js @@ -0,0 +1,93 @@ +import RequestService from '../httpRequest' +import {getServiceUrl} from '../api' + + +export default { + //智能体列表 + getAgentList(callback) { + RequestService.sendRequest().url(`${getServiceUrl()}/user/agent`) + .method('GET') + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .fail((err) => { + console.error('获取智能体列表失败:', err); + }).send() + }, + //添加智能体 + addAgent(agentName, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/user/agent`) + .method('POST') + .data({agentName}) + .success((res) => { + RequestService.clearRequestTime(); + callback(res); + }) + .fail((err) => { + console.error('添加智能体失败:', err); + }).send(); + }, + //获取智能体配置 + getAgentConfig(agentId, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/user/agent/${agentId}`) + .method('GET') + .success((res) => { + RequestService.clearRequestTime(); + callback(res); + }) + .fail((err) => { + console.error('获取智能体配置失败:', err); + // RequestService.reAjaxFun(() => { + // this.getAgentConfig(agent_id, callback); + // }); + }).send(); + }, + //配置智能体 + saveAgentConfig(agentId, configData, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/user/agent/${agentId}`) + .method('PUT') + .data(configData) + .success((res) => { + RequestService.clearRequestTime(); + callback(res); + }) + .fail((err) => { + console.error('保存智能体配置失败:', err); + // RequestService.reAjaxFun(() => { + // this.saveAgentConfig(device_id, configData, callback); + // }); + }).send(); + }, + //删除智能体 + delAgent(agentId, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/user/agent/${agentId}`) + .method('DELETE') + .success((res) => { + RequestService.clearRequestTime(); + callback(res); + }) + .fail((err) => { + console.error('删除智能体失败:', err); + // RequestService.reAjaxFun(() => { + // this.deleteAgent(agent_id, callback); + // }); + }).send(); + }, + //智能体模板列表 + getAgentTemplateList(callback) { + RequestService.sendRequest().url(`${getServiceUrl()}/user/agent/template`) + .method('GET') + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .fail((err) => { + console.error('获取智能体模板列表失败:', err); + }).send() + }, +} diff --git a/main/manager-web/src/apis/module/device.js b/main/manager-web/src/apis/module/device.js new file mode 100755 index 00000000..fdf74bbc --- /dev/null +++ b/main/manager-web/src/apis/module/device.js @@ -0,0 +1,81 @@ +import RequestService from '../httpRequest' +import {getServiceUrl} from '../api' + + +export default { + //设备列表 + getDeviceList(agent_id, page, callback) { + RequestService.sendRequest().url(`${getServiceUrl()}/user/agent/device/bind/${agent_id}`) + .method('GET') + .data(page) + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .fail((err) => { + console.error('获取设备列表失败:', err); + }).send() + }, + //绑定设备 + bindDevice(agentId, deviceCode, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/user/agent/device/bind/${agentId}`) + .method('POST') + .data({deviceCode}) + .success((res) => { + RequestService.clearRequestTime(); + callback(res); + }) + .fail((err) => { + console.error('绑定设备失败:', err); + // RequestService.reAjaxFun(() => { + // this.addDevice(agentId, deviceCode, callback); + // }); + }).send(); + }, + // 解绑设备 + unbindDevice(deviceId, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/user/agent/device/unbind/${deviceId}`) + .method('PUT') + .success((res) => { + RequestService.clearRequestTime(); + callback(res); + }) + .fail((err) => { + console.error('解绑设备失败:', err); + // RequestService.reAjaxFun(() => { + // this.unbindDevice(deviceId, callback); + // }); + }).send() + }, + // 切换设备OTA升级状态 + toggleAutoUpdate(deviceId, autoUpdate, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/user/agent/device/autoUpdate/${deviceId}`) + .method('POST') + .data({autoUpdate}) + .success((res) => { + RequestService.clearRequestTime(); + callback(res); + }) + .fail((err) => { + console.error('切换设备OTA升级状态失败:', err); + }).send() + }, + // 设置设备别名 + setAlias(deviceId, alias, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/user/agent/device/alias/${deviceId}`) + .method('POST') + .data({alias}) + .success((res) => { + RequestService.clearRequestTime(); + callback(res); + }) + .fail((err) => { + console.error('设置设备别名失败:', err); + }).send() + }, + +} diff --git a/main/manager-web/src/apis/module/model.js b/main/manager-web/src/apis/module/model.js new file mode 100755 index 00000000..c5ee9087 --- /dev/null +++ b/main/manager-web/src/apis/module/model.js @@ -0,0 +1,32 @@ +import RequestService from '../httpRequest' +import {getServiceUrl} from '../api' + + +export default { + //模型配置列表 + getModelList(callback) { + RequestService.sendRequest().url(`${getServiceUrl()}/model/list`) + .method('GET') + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .fail((err) => { + console.error('获取模型配置列表失败:', err); + }).send() + }, + + //音色列表 + getTtsVoiceList(ttsModelId, callback) { + RequestService.sendRequest().url(`${getServiceUrl()}/tts/voice`) + .method('GET') + .data({ttsModelId}) + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .fail((err) => { + console.error('获取音色列表失败:', err); + }).send() + }, +} diff --git a/main/manager-web/src/apis/module/ota.js b/main/manager-web/src/apis/module/ota.js new file mode 100755 index 00000000..23344b9c --- /dev/null +++ b/main/manager-web/src/apis/module/ota.js @@ -0,0 +1,67 @@ +import RequestService from '../httpRequest' +import {getServiceUrl} from '../api' + + +export default { + //设备OTA列表 + getOtaList(page, callback) { + RequestService.sendRequest().url(`${getServiceUrl()}/ota/sys/getOtalist`) + .method('GET') + .data(page) + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .fail((err) => { + console.error('获取设备OTA列表失败:', err); + }).send() + }, + //添加设备OTA + saveOta(ota, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/ota/sys/save`) + .method('POST') + .data(ota) + .success((res) => { + RequestService.clearRequestTime(); + callback(res); + }) + .fail((err) => { + console.error('添加设备OTA失败:', err); + }).send(); + }, + //配置设备OTA + updateOta(ota, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/ota/sys/update`) + .method('POST') + .data(ota) + .success((res) => { + RequestService.clearRequestTime(); + callback(res); + }) + .fail((err) => { + console.error('保存设备OTA配置失败:', err); + // RequestService.reAjaxFun(() => { + // this.saveAgentConfig(device_id, configData, callback); + // }); + }).send(); + }, + //切换设备OTA可用状态失败 + toggleEnabled(ota, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/ota/sys/toggleEnabled`) + .method('POST') + .data(ota) + .success((res) => { + RequestService.clearRequestTime(); + callback(res); + }) + .fail((err) => { + console.error('切换设备OTA可用状态失败:', err); + // RequestService.reAjaxFun(() => { + // this.deleteAgent(agent_id, callback); + // }); + }).send(); + }, +} diff --git a/main/manager-web/src/apis/module/user.js b/main/manager-web/src/apis/module/user.js index 1fb3503d..6aee61bc 100755 --- a/main/manager-web/src/apis/module/user.js +++ b/main/manager-web/src/apis/module/user.js @@ -5,25 +5,25 @@ import {getServiceUrl} from '../api' export default { // 登录 login(loginForm, callback) { - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/user/login`) + RequestService.sendRequest().url(`${getServiceUrl()}/user/login`) .method('POST') .data(loginForm) .success((res) => { RequestService.clearRequestTime() callback(res) }) - .fail(() => { - RequestService.reAjaxFun(() => { - this.login(loginForm, callback) - }) + .fail((err) => { + console.error('登录失败:', err); + // RequestService.reAjaxFun(() => { + // this.login(loginForm, callback) + // }) }).send() - }, + }, // 获取验证码 getCaptcha(uuid, callback) { RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/user/captcha?uuid=${uuid}`) + .url(`${getServiceUrl()}/user/captcha?uuid=${uuid}`) .method('GET') .type('blob') .header({ @@ -36,59 +36,57 @@ export default { callback(res); }) .fail((err) => { // 添加错误参数 - + console.error('获取验证码失败:', err); }).send() }, // 注册账号 register(registerForm, callback) { - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/user/register`) - .method('POST') + RequestService.sendRequest().url(`${getServiceUrl()}/user/register`).method('POST') .data(registerForm) .success((res) => { RequestService.clearRequestTime() callback(res) }) - .fail(() => { + .fail((err) => { + console.error('注册账号失败:', err); }).send() }, - // 保存设备配置 - saveDeviceConfig(device_id, configData, callback) { + // 获取所有模型名称 + getModelNames(callback) { RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/user/configDevice/${device_id}`) - .method('PUT') - .data(configData) - .success((res) => { - RequestService.clearRequestTime(); - callback(res); - }) - .fail((err) => { - console.error('保存配置失败:', err); - RequestService.reAjaxFun(() => { - this.saveDeviceConfig(device_id, configData, callback); - }); - }).send(); - }, - // 获取智能体列表 - getAgentList(callback) { - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/user/agent`) + .url(`${getServiceUrl()}/models/names`) .method('GET') .success((res) => { RequestService.clearRequestTime(); callback(res); }) .fail(() => { - RequestService.reAjaxFun(() => { - this.getAgentList(callback); - }); + // RequestService.reAjaxFun(() => { + // this.getModelNames(callback); + // }); }).send(); }, - // 用户信息获取 + + // 获取模型音色 + getModelVoices(modelName, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/models/${modelName}/voices`) + .method('GET') + .success((res) => { + RequestService.clearRequestTime(); + callback(res); + }) + .fail(() => { + // RequestService.reAjaxFun(() => { + // this.getModelVoices(modelName, callback); + // }); + }).send(); + }, + // 获取用户信息 getUserInfo(callback) { RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/user/info`) + .url(`${getServiceUrl()}/user/info`) .method('GET') .success((res) => { RequestService.clearRequestTime() @@ -96,157 +94,29 @@ export default { }) .fail((err) => { console.error('接口请求失败:', err) - RequestService.reAjaxFun(() => { - this.getUserInfo(callback) - }) + // RequestService.reAjaxFun(() => { + // this.getUserInfo(callback) + // }) }).send() }, - // 添加智能体 - addAgent(agentName, callback) { - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/user/agent`) - .method('POST') - .data({name: agentName}) - .success((res) => { - RequestService.clearRequestTime(); - callback(res); - }) - .fail(() => { - RequestService.reAjaxFun(() => { - this.addAgent(agentName, callback); - }); - }).send(); - }, - // 删除智能体 - deleteAgent(agentId, callback) { - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/user/agent/${agentId}`) - .method('DELETE') - .success((res) => { - RequestService.clearRequestTime(); - callback(res); - }) - .fail(() => { - RequestService.reAjaxFun(() => { - this.deleteAgent(agentId, callback); - }); - }).send(); - }, // 修改用户密码 changePassword(oldPassword, newPassword, successCallback, errorCallback) { RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/user/change-password`) - .method('PUT') + .url(`${getServiceUrl()}/user/change-password`) // 修改URL + .method('PUT') // 修改方法为PUT .data({ - old_password: oldPassword, - new_password: newPassword, + old_password: oldPassword, // 修改参数名 + new_password: newPassword // 修改参数名 }) .success((res) => { RequestService.clearRequestTime(); successCallback(res); }) .fail((error) => { - RequestService.reAjaxFun(() => { - this.changePassword(oldPassword, newPassword, successCallback, errorCallback); - }); + // RequestService.reAjaxFun(() => { + // this.changePassword(oldPassword, newPassword, successCallback, errorCallback); + // }); }) .send(); }, - // 获取智能体配置 - getDeviceConfig(deviceId, callback) { - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/user/agent/${deviceId}`) - .method('GET') - .success((res) => { - RequestService.clearRequestTime(); - callback(res); - }) - .fail((err) => { - console.error('获取配置失败:', err); - RequestService.reAjaxFun(() => { - this.getDeviceConfig(deviceId, callback); - }); - }).send(); - }, - // 配置智能体 - updateAgentConfig(agentId, configData, callback) { - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/user/agent/${agentId}`) - .method('PUT') - .data(configData) - .success((res) => { - RequestService.clearRequestTime(); - callback(res); - }) - .fail(() => { - RequestService.reAjaxFun(() => { - this.updateAgentConfig(agentId, configData, callback); - }); - }).send(); - }, - // 已绑设备 - getAgentBindDevices(agentId, callback) { - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/user/agent/device/bind/${agentId}`) - .method('GET') - .success((res) => { - RequestService.clearRequestTime(); - callback(res); - }) - .fail((err) => { - console.error('获取设备列表失败:', err); - RequestService.reAjaxFun(() => { - this.getAgentBindDevices(agentId, callback); - }); - }).send(); - }, - // 解绑设备 - unbindDevice(device_id, callback) { - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/user/device/unbind/${device_id}`) - .method('PUT') - .success((res) => { - RequestService.clearRequestTime(); - callback(res); - }) - .fail((err) => { - console.error('解绑设备失败:', err); - RequestService.reAjaxFun(() => { - this.unbindDevice(device_id, callback); - }); - }).send(); - }, - // 绑定设备 - bindDevice(agentId, code, callback) { - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/user/agent/device/bind/${agentId}`) - .method('POST') - .data({ code }) - .success((res) => { - RequestService.clearRequestTime(); - callback(res); - }) - .fail((err) => { - console.error('绑定设备失败:', err); - RequestService.reAjaxFun(() => { - this.bindDevice(agentId, code, callback); - }); - }).send(); - }, - // 新增方法:获取智能体模板 - getAgentTemplate(templateName, callback) { - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/user/agent/templateId`) - .method('GET') - .success((res) => { - RequestService.clearRequestTime(); - callback(res); - }) - .fail((err) => { - console.error('获取模板失败:', err); - RequestService.reAjaxFun(() => { - this.getAgentTemplate(templateName, callback); - }); - }).send(); - }, } diff --git a/main/manager-web/src/components/AddWisdomBodyDialog.vue b/main/manager-web/src/components/AddAgentDialog.vue similarity index 66% rename from main/manager-web/src/components/AddWisdomBodyDialog.vue rename to main/manager-web/src/components/AddAgentDialog.vue index cca026ef..af3b0214 100644 --- a/main/manager-web/src/components/AddWisdomBodyDialog.vue +++ b/main/manager-web/src/components/AddAgentDialog.vue @@ -1,18 +1,18 @@