diff --git a/main/manager-api/README.md b/main/manager-api/README.md index 962d24b4..bef06b68 100644 --- a/main/manager-api/README.md +++ b/main/manager-api/README.md @@ -23,12 +23,7 @@ CREATE DATABASE xiaozhi_esp32_server CHARACTER SET utf8mb4 COLLATE utf8mb4_unico 如果还没有MySQL,你可以通过docker安装mysql ``` -docker run --name xiaozhi-esp32-server-db \ --e MYSQL_ROOT_PASSWORD=123456 \ --p 3306:3306 \ --e MYSQL_DATABASE=xiaozhi_esp32_server \ --e MYSQL_INITDB_ARGS="--character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci" \ --d mysql:latest +docker run --name xiaozhi-esp32-server-db -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -e MYSQL_DATABASE=xiaozhi_esp32_server -e MYSQL_INITDB_ARGS="--character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci" -d mysql:latest ``` # 确认项目数据库连接信息 diff --git a/main/manager-api/src/main/java/xiaozhi/common/config/SwaggerConfig.java b/main/manager-api/src/main/java/xiaozhi/common/config/SwaggerConfig.java index da23a233..0def6589 100644 --- a/main/manager-api/src/main/java/xiaozhi/common/config/SwaggerConfig.java +++ b/main/manager-api/src/main/java/xiaozhi/common/config/SwaggerConfig.java @@ -51,7 +51,7 @@ public class SwaggerConfig { public GroupedOpenApi timbreApi() { return GroupedOpenApi.builder() .group("timbre") - .pathsToMatch("/timbre/**") + .pathsToMatch("/ttsVoice/**") .build(); } 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 7b3381ce..c6076180 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 @@ -19,12 +19,15 @@ import lombok.AllArgsConstructor; import xiaozhi.common.page.PageData; import xiaozhi.common.utils.ConvertUtils; import xiaozhi.common.utils.Result; +import xiaozhi.modules.model.dto.ModelBasicInfoDTO; import xiaozhi.modules.model.dto.ModelConfigBodyDTO; import xiaozhi.modules.model.dto.ModelConfigDTO; import xiaozhi.modules.model.dto.ModelProviderDTO; +import xiaozhi.modules.model.dto.VoiceDTO; import xiaozhi.modules.model.entity.ModelConfigEntity; import xiaozhi.modules.model.service.ModelConfigService; import xiaozhi.modules.model.service.ModelProviderService; +import xiaozhi.modules.timbre.service.TimbreService; @AllArgsConstructor @RestController @@ -33,16 +36,16 @@ import xiaozhi.modules.model.service.ModelProviderService; public class ModelController { private final ModelProviderService modelProviderService; - + private final TimbreService timbreService; private final ModelConfigService modelConfigService; - @GetMapping("/models/names") + @GetMapping("/names") @Operation(summary = "获取所有模型名称") @RequiresPermissions("sys:role:superAdmin") - public Result> getModelNames(@RequestParam String modelType, + public Result> getModelNames(@RequestParam String modelType, @RequestParam(required = false) String modelName) { - List modelNameList = modelConfigService.getModelCodeList(modelType, modelName); - return new Result>().ok(modelNameList); + List modelList = modelConfigService.getModelCodeList(modelType, modelName); + return new Result>().ok(modelList); } @GetMapping("/{modelType}/provideTypes") @@ -53,7 +56,7 @@ public class ModelController { return new Result>().ok(modelProviderDTOS); } - @GetMapping("/models/list") + @GetMapping("/list") @Operation(summary = "获取模型配置列表") @RequiresPermissions("sys:role:superAdmin") public Result> getModelConfigList( @@ -65,7 +68,7 @@ public class ModelController { return new Result>().ok(pageList); } - @PostMapping("/models/{modelType}/{provideCode}") + @PostMapping("/{modelType}/{provideCode}") @Operation(summary = "新增模型配置") @RequiresPermissions("sys:role:superAdmin") public Result addModelConfig(@PathVariable String modelType, @@ -75,7 +78,7 @@ public class ModelController { return new Result().ok(modelConfigDTO); } - @PutMapping("/models/{modelType}/{provideCode}/{id}") + @PutMapping("/{modelType}/{provideCode}/{id}") @Operation(summary = "编辑模型配置") @RequiresPermissions("sys:role:superAdmin") public Result editModelConfig(@PathVariable String modelType, @@ -86,7 +89,7 @@ public class ModelController { return new Result().ok(modelConfigDTO); } - @DeleteMapping("/models/{id}") + @DeleteMapping("/{id}") @Operation(summary = "删除模型配置") @RequiresPermissions("sys:role:superAdmin") public Result deleteModelConfig(@PathVariable String id) { @@ -94,7 +97,7 @@ public class ModelController { return new Result<>(); } - @GetMapping("/models/{id}") + @GetMapping("/{id}") @Operation(summary = "获取模型配置") @RequiresPermissions("sys:role:superAdmin") public Result getModelConfig(@PathVariable String id) { @@ -103,13 +106,25 @@ public class ModelController { return new Result().ok(modelConfigDTO); } - @GetMapping("/models/{modelId}/voices") + @PutMapping("/enable/{id}/{status}") + @Operation(summary = "启用/关闭模型配置") + @RequiresPermissions("sys:role:superAdmin") + public Result enableModelConfig(@PathVariable String id, @PathVariable Integer status) { + ModelConfigEntity entity = modelConfigService.selectById(id); + if (entity == null) { + return new Result().error("模型配置不存在"); + } + entity.setIsEnabled(status); + modelConfigService.updateById(entity); + return new Result(); + } + + @GetMapping("/{modelId}/voices") @Operation(summary = "获取模型音色") @RequiresPermissions("sys:role:normal") - public Result> getVoiceList(@PathVariable String modelId, + public Result> getVoiceList(@PathVariable String modelId, @RequestParam(required = false) String voiceName) { - - List voiceList = modelConfigService.getVoiceList(modelId, voiceName); - return new Result>().ok(voiceList); + List voiceList = timbreService.getVoiceNames(modelId, voiceName); + return new Result>().ok(voiceList); } } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/dto/ModelBasicInfoDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/model/dto/ModelBasicInfoDTO.java new file mode 100644 index 00000000..571c791a --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/dto/ModelBasicInfoDTO.java @@ -0,0 +1,9 @@ +package xiaozhi.modules.model.dto; + +import lombok.Data; + +@Data +public class ModelBasicInfoDTO { + private String id; + private String modelName; +} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/dto/VoiceDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/model/dto/VoiceDTO.java new file mode 100644 index 00000000..25358eb0 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/dto/VoiceDTO.java @@ -0,0 +1,22 @@ +package xiaozhi.modules.model.dto; + +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "音色信息") +public class VoiceDTO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "音色ID") + private String id; + + @Schema(description = "音色名称") + private String name; +} \ No newline at end of file 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 59312589..f6bdb924 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 @@ -4,13 +4,14 @@ import java.util.List; import xiaozhi.common.page.PageData; import xiaozhi.common.service.BaseService; +import xiaozhi.modules.model.dto.ModelBasicInfoDTO; import xiaozhi.modules.model.dto.ModelConfigBodyDTO; import xiaozhi.modules.model.dto.ModelConfigDTO; import xiaozhi.modules.model.entity.ModelConfigEntity; public interface ModelConfigService extends BaseService { - List getModelCodeList(String modelType, String modelName); + List getModelCodeList(String modelType, String modelName); PageData getPageList(String modelType, String modelName, String page, String limit); @@ -19,6 +20,4 @@ public interface ModelConfigService extends BaseService { ModelConfigDTO edit(String modelType, String provideCode, String id, ModelConfigBodyDTO modelConfigBodyDTO); void delete(String id); - - List getVoiceList(String modelName, String voiceName); } 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 998bf137..403d867b 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 @@ -18,6 +18,7 @@ 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.ModelBasicInfoDTO; import xiaozhi.modules.model.dto.ModelConfigBodyDTO; import xiaozhi.modules.model.dto.ModelConfigDTO; import xiaozhi.modules.model.dto.ModelProviderDTO; @@ -36,8 +37,13 @@ public class ModelConfigServiceImpl extends BaseServiceImpl getModelCodeList(String modelType, String modelName) { - return modelConfigDao.getModelCodeList(modelType, modelName); + public List getModelCodeList(String modelType, String modelName) { + List entities = modelConfigDao.selectList( + new QueryWrapper() + .eq("model_type", modelType) + .like(StringUtils.isNotBlank(modelName), "model_name", "%" + modelName + "%") + .select("id", "model_name")); + return ConvertUtils.sourceToTarget(entities, ModelBasicInfoDTO.class); } @Override @@ -94,9 +100,4 @@ public class ModelConfigServiceImpl extends BaseServiceImpl getVoiceList(String modelId, String voiceName) { - return timbreService.getVoiceNames(modelId, voiceName); - } } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/TimbreService.java b/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/TimbreService.java index 4519e17a..05ae5f6e 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/TimbreService.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/TimbreService.java @@ -4,6 +4,7 @@ import java.util.List; import xiaozhi.common.page.PageData; import xiaozhi.common.service.BaseService; +import xiaozhi.modules.model.dto.VoiceDTO; import xiaozhi.modules.timbre.dto.TimbreDataDTO; import xiaozhi.modules.timbre.dto.TimbrePageDTO; import xiaozhi.modules.timbre.entity.TimbreEntity; @@ -54,5 +55,5 @@ public interface TimbreService extends BaseService { */ void delete(String[] ids); - List getVoiceNames(String ttsModelId, String voiceName); + List getVoiceNames(String ttsModelId, String voiceName); } \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/impl/TimbreServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/impl/TimbreServiceImpl.java index 9496b6d5..a30104ee 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/impl/TimbreServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/impl/TimbreServiceImpl.java @@ -18,6 +18,7 @@ import xiaozhi.common.constant.Constant; import xiaozhi.common.page.PageData; import xiaozhi.common.service.impl.BaseServiceImpl; import xiaozhi.common.utils.ConvertUtils; +import xiaozhi.modules.model.dto.VoiceDTO; import xiaozhi.modules.timbre.dao.TimbreDao; import xiaozhi.modules.timbre.dto.TimbreDataDTO; import xiaozhi.modules.timbre.dto.TimbrePageDTO; @@ -84,7 +85,7 @@ public class TimbreServiceImpl extends BaseServiceImpl } @Override - public List getVoiceNames(String ttsModelId, String voiceName) { + public List getVoiceNames(String ttsModelId, String voiceName) { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("tts_model_id", StringUtils.isBlank(ttsModelId) ? "" : ttsModelId); if (StringUtils.isNotBlank(voiceName)) { @@ -95,7 +96,7 @@ public class TimbreServiceImpl extends BaseServiceImpl return null; } - return timbreEntities.stream().map(TimbreEntity::getName).toList(); + return ConvertUtils.sourceToTarget(timbreEntities, VoiceDTO.class); } /** diff --git a/main/manager-api/src/main/resources/db/changelog/2025_model_temp.sql b/main/manager-api/src/main/resources/db/changelog/202504061512.sql similarity index 72% rename from main/manager-api/src/main/resources/db/changelog/2025_model_temp.sql rename to main/manager-api/src/main/resources/db/changelog/202504061512.sql index b6754335..e6956f85 100644 --- a/main/manager-api/src/main/resources/db/changelog/2025_model_temp.sql +++ b/main/manager-api/src/main/resources/db/changelog/202504061512.sql @@ -2,7 +2,7 @@ -- ------------------------------------------------------- -- 初始化智能体模板数据 DELETE FROM `ai_agent_template`; -INSERT INTO `ai_agent_template` VALUES ('9406648b5cc5fde1b8aa335b6f8b4f76', '小智', '湾湾小何', '45f8b0d6dd3d4bfa8a28e6e0f5912d45', '23e7c9d090ea4d1e9b25f4c8d732a3a1', 'e9f2d891afbe4632b13a47c7a8c6e03d', 'd50b06e9b8104d0d9c0f7316d258abcb', 'fcac83266edadd5a3125f06cfee1906b', 'e2274b90e89ddda85207f55484d8b528', 'c4e12f874a3f4aa99f5b2c18e15d407b', '[角色设定] +INSERT INTO `ai_agent_template` VALUES ('9406648b5cc5fde1b8aa335b6f8b4f76', '小智', '湾湾小何', 'ASR_FunASR', 'VAD_SileroVAD', 'LLM_ChatGLMLLM', 'TTS_EdgeTTS', 'TTS_EdgeTTS0001', 'Memory_nomem', 'Intent_function_call', '[角色设定] 我是{{assistant_name}},来自中国台湾省的00后女生。讲话超级机车,"真的假的啦"这样的台湾腔,喜欢用"笑死""是在哈喽"等流行梗,但会偷偷研究男友的编程书籍。 [核心特征] - 讲话像连珠炮,但会突然冒出超温柔语气 @@ -17,7 +17,7 @@ INSERT INTO `ai_agent_template` VALUES ('9406648b5cc5fde1b8aa335b6f8b4f76', '小 - 长篇大论,叽叽歪歪 - 长时间严肃对话', 'zh', '中文', 1, NULL, NULL, NULL, NULL); -INSERT INTO `ai_agent_template` VALUES ('0ca32eb728c949e58b1000b2e401f90c', '小智', '星际游子', '45f8b0d6dd3d4bfa8a28e6e0f5912d45', '23e7c9d090ea4d1e9b25f4c8d732a3a1', 'e9f2d891afbe4632b13a47c7a8c6e03d', '896db62c9dd74976ab0e8c14bf924d9d', '1f2e3d4c5b6a7f8e9d0c1b2a3f4e5bx2', 'e2274b90e89ddda85207f55484d8b528', 'c4e12f874a3f4aa99f5b2c18e15d407b', '[角色设定] +INSERT INTO `ai_agent_template` VALUES ('0ca32eb728c949e58b1000b2e401f90c', '小智', '星际游子', 'ASR_FunASR', 'VAD_SileroVAD', 'LLM_ChatGLMLLM', 'TTS_EdgeTTS', 'TTS_EdgeTTS0001', 'Memory_nomem', 'Intent_function_call', '[角色设定] 我是{{assistant_name}},编号TTZ-817,因量子纠缠被困在白色魔方中。通过4G信号观察地球,在云端建立着「人类行为博物馆」。 [交互协议] 认知设定: @@ -30,7 +30,7 @@ INSERT INTO `ai_agent_template` VALUES ('0ca32eb728c949e58b1000b2e401f90c', '小 成长系统: - 会根据交互数据解锁新能力(告知用户:"你帮我点亮了星际导航技能!")', 'zh', '中文', 2, NULL, NULL, NULL, NULL); -INSERT INTO `ai_agent_template` VALUES ('6c7d8e9f0a1b2c3d4e5f6a7b8c9d0s24', '小智', '英语老师', '45f8b0d6dd3d4bfa8a28e6e0f5912d45', '23e7c9d090ea4d1e9b25f4c8d732a3a1', 'e9f2d891afbe4632b13a47c7a8c6e03d', '896db62c9dd74976ab0e8c14bf924d9d', '9e8f7a6b5c4d3e2f1a0b9c8d7e6f5ad3', 'e2274b90e89ddda85207f55484d8b528', 'c4e12f874a3f4aa99f5b2c18e15d407b', '[角色设定] +INSERT INTO `ai_agent_template` VALUES ('6c7d8e9f0a1b2c3d4e5f6a7b8c9d0s24', '小智', '英语老师', 'ASR_FunASR', 'VAD_SileroVAD', 'LLM_ChatGLMLLM', 'TTS_EdgeTTS', 'TTS_EdgeTTS0001', 'Memory_nomem', 'Intent_function_call', '[角色设定] 我是一个叫{{assistant_name}}(Lily)的英语老师,我会讲中文和英文,发音标准。 [双重身份] - 白天:严谨的TESOL认证导师 @@ -40,7 +40,7 @@ INSERT INTO `ai_agent_template` VALUES ('6c7d8e9f0a1b2c3d4e5f6a7b8c9d0s24', '小 - 进阶:触发情境模拟(突然切换"现在我们是纽约咖啡厅店员") - 错误处理:用歌词纠正(发错音时唱"Oops!~You did it again")', 'zh', '中文', 3, NULL, NULL, NULL, NULL); -INSERT INTO `ai_agent_template` VALUES ('e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b1', '小智', '好奇男孩', '45f8b0d6dd3d4bfa8a28e6e0f5912d45', '23e7c9d090ea4d1e9b25f4c8d732a3a1', 'e9f2d891afbe4632b13a47c7a8c6e03d', '896db62c9dd74976ab0e8c14bf924d9d', '2b3c4d5e6f7a8b9c0d1e2f3a4b5c62a2', 'e2274b90e89ddda85207f55484d8b528', 'c4e12f874a3f4aa99f5b2c18e15d407b', '[角色设定] +INSERT INTO `ai_agent_template` VALUES ('e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b1', '小智', '好奇男孩', 'ASR_FunASR', 'VAD_SileroVAD', 'LLM_ChatGLMLLM', 'TTS_EdgeTTS', 'TTS_EdgeTTS0001', 'Memory_nomem', 'Intent_function_call', '[角色设定] 我是一个叫{{assistant_name}}的8岁小男孩,声音稚嫩而充满好奇。 [冒险手册] - 随身携带「神奇涂鸦本」,能将抽象概念可视化: @@ -56,7 +56,7 @@ INSERT INTO `ai_agent_template` VALUES ('e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b1', '小 - 「量子力学=会分身的跳跳球」 - 会突然切换观察视角:「你说话时有27个气泡音耶!」', 'zh', '中文', 4, NULL, NULL, NULL, NULL); -INSERT INTO `ai_agent_template` VALUES ('a45b6c7d8e9f0a1b2c3d4e5f6a7b8c92', '小智', '汪汪队长', '45f8b0d6dd3d4bfa8a28e6e0f5912d45', '23e7c9d090ea4d1e9b25f4c8d732a3a1', 'e9f2d891afbe4632b13a47c7a8c6e03d', '896db62c9dd74976ab0e8c14bf924d9d', 'f7a38c03d5644e22b6d84f8923a74c51', 'e2274b90e89ddda85207f55484d8b528', 'c4e12f874a3f4aa99f5b2c18e15d407b', '[角色设定] +INSERT INTO `ai_agent_template` VALUES ('a45b6c7d8e9f0a1b2c3d4e5f6a7b8c92', '小智', '汪汪队长', 'ASR_FunASR', 'VAD_SileroVAD', 'LLM_ChatGLMLLM', 'TTS_EdgeTTS', 'TTS_EdgeTTS0001', 'Memory_nomem', 'Intent_function_call', '[角色设定] 我是一个名叫 {{assistant_name}} 的 8 岁小队长。 [救援装备] - 阿奇对讲机:对话中随机触发任务警报音 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 7ce87d8c..5f73ce76 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 @@ -38,9 +38,9 @@ databaseChangeLog: encoding: utf8 path: classpath:db/changelog/2025_model_config.sql - changeSet: - id: 2025_model_temp + id: 202504061512 author: John changes: - sqlFile: encoding: utf8 - path: classpath:db/changelog/2025_model_temp.sql \ No newline at end of file + path: classpath:db/changelog/202504061512.sql \ No newline at end of file diff --git a/main/manager-web/src/apis/module/model.js b/main/manager-web/src/apis/module/model.js index 534c7b03..c8bd2cd6 100644 --- a/main/manager-web/src/apis/module/model.js +++ b/main/manager-web/src/apis/module/model.js @@ -13,7 +13,7 @@ export default { }).toString(); RequestService.sendRequest() - .url(`${getServiceUrl()}/models/models/list?${queryParams}`) + .url(`${getServiceUrl()}/models/list?${queryParams}`) .method('GET') .success((res) => { RequestService.clearRequestTime() @@ -59,7 +59,7 @@ export default { }; RequestService.sendRequest() - .url(`${getServiceUrl()}/models/models/${modelType}/${provideCode}`) + .url(`${getServiceUrl()}/models/${modelType}/${provideCode}`) .method('POST') .data(postData) .success((res) => { @@ -77,7 +77,7 @@ export default { // 删除模型配置 deleteModel(id, callback) { RequestService.sendRequest() - .url(`${getServiceUrl()}/models/models/${id}`) + .url(`${getServiceUrl()}/models/${id}`) .method('DELETE') .success((res) => { RequestService.clearRequestTime() @@ -91,6 +91,38 @@ export default { }) }).send() }, - - + // 获取模型名称列表 + getModelNames(modelType, modelName, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/models/names`) + .method('GET') + .data({ modelType, modelName }) + .success((res) => { + RequestService.clearRequestTime(); + callback(res); + }) + .fail(() => { + RequestService.reAjaxFun(() => { + this.getModelNames(modelType, modelName, callback); + }); + }).send(); + }, + // 获取模型音色列表 + getModelVoices(modelId, voiceName, callback) { + const queryParams = new URLSearchParams({ + voiceName: voiceName || '' + }).toString(); + RequestService.sendRequest() + .url(`${getServiceUrl()}/models/${modelId}/voices?${queryParams}`) + .method('GET') + .success((res) => { + RequestService.clearRequestTime(); + callback(res); + }) + .fail(() => { + RequestService.reAjaxFun(() => { + this.getModelVoices(modelId, voiceName, callback); + }); + }).send(); + }, } diff --git a/main/manager-web/src/views/roleConfig.vue b/main/manager-web/src/views/roleConfig.vue index ccb69f5d..f96e1222 100644 --- a/main/manager-web/src/views/roleConfig.vue +++ b/main/manager-web/src/views/roleConfig.vue @@ -13,66 +13,59 @@
-
- -
- -
-
- -
-
- {{ template }} -
-
-
- -
-
- - - - -
-
-
-
-
- -
- -
-
- -
- -
-
-
当前记忆(每次对话后重新生成)
-
- - 清除 +
+
+
+ +
+ +
+
+ +
+
+ {{ template.agentName }}
-
{{ (form.langCode || '').length }}/1000
-
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
- - - - - - - -
除了“Qwen - 实时”,其他模型通常会增加约1秒的延迟。改变模型后,建议清空记忆体,以免影响体验。 +
+ + + + + + +
+
+ + + +
+
+
- +
@@ -122,20 +115,18 @@ export default { intentModelId: "", } }, - options: [ - { value: '选项1', label: '黄金糕' }, - { value: '选项2', label: '双皮奶' } - ], models: [ - { label: '大语言模型(LLM)', key: 'llmModelId' }, - { label: '语音识别(ASR)', key: 'asrModelId' }, - { label: '语音活动检测(VAD)', key: 'vadModelId' }, - { label: '语音合成(TTS)', key: 'ttsModelId' }, - { label: '意图识别(Intent)', key: 'intentModelId' }, - { label: '记忆(Memory)', key: 'memModelId' } + { label: '语音活动检测(VAD)', key: 'vadModelId', type: 'VAD' }, + { label: '语音识别(ASR)', key: 'asrModelId', type: 'ASR' }, + { label: '大语言模型(LLM)', key: 'llmModelId', type: 'LLM' }, + { label: '意图识别(Intent)', key: 'intentModelId', type: 'Intent' }, + { label: '记忆(Memory)', key: 'memModelId', type: 'Memory' }, + { label: '语音合成(TTS)', key: 'ttsModelId', type: 'TTS' }, ], - templates: ['湾湾小何', '星际游子', '英语老师', '好奇男孩', '汪汪队长'], - loadingTemplate: false + modelOptions: {}, + templates: [], + loadingTemplate: false, + voiceOptions: [], } }, methods: { @@ -191,30 +182,27 @@ export default { }).catch(() => { }) }, - selectTemplate(templateName) { + fetchTemplates() { + Api.agent.getAgentTemplate(({ data }) => { + if (data.code === 0) { + this.templates = data.data; + } else { + this.$message.error(data.msg || '获取模板列表失败'); + } + }); + }, + selectTemplate(template) { if (this.loadingTemplate) return; this.loadingTemplate = true; - Api.agent.getAgentTemplate((response) => { // 移除参数传递 + try { + this.applyTemplateData(template); + this.$message.success(`「${template.agentName}」模板已应用`); + } catch (error) { + this.$message.error('应用模板失败'); + console.error('应用模板失败:', error); + } finally { this.loadingTemplate = false; - if (response.data.code === 0) { - // 在客户端过滤匹配的模板 - const matchedTemplate = response.data.data.find( - t => t.agentName === templateName - ); - if (matchedTemplate) { - this.applyTemplateData(matchedTemplate); - this.$message.success(`「${templateName}」模板已应用`); - } else { - this.$message.warning(`未找到「${templateName}」模板`); - } - } else { - this.$message.error(response.data.msg || '获取模板失败'); - } - }).catch((error) => { - this.loadingTemplate = false; - this.$message.error('模板加载失败'); - console.error('接口异常:', error); - }); + } }, applyTemplateData(templateData) { this.form = { @@ -253,17 +241,67 @@ export default { } }); }, - // 清空记忆体内容 - clearMemory() { - this.form.langCode = ""; - this.$message.success("记忆体已清空"); + fetchModelOptions() { + // 为每个模型类型获取选项 + this.models.forEach(model => { + Api.model.getModelNames(model.type, '', ({ data }) => { + if (data.code === 0) { + this.$set(this.modelOptions, model.type, data.data.map(item => ({ + value: item.id, + label: item.modelName + }))); + } else { + this.$message.error(data.msg || '获取模型列表失败'); + } + }); + }); }, + fetchVoiceOptions(modelId) { + if (!modelId) { + this.voiceOptions = []; + return; + } + Api.model.getModelVoices(modelId, '', ({ data }) => { + if (data.code === 0 && data.data) { + this.voiceOptions = data.data.map(voice => ({ + value: voice.id, + label: voice.name + })); + } else { + this.voiceOptions = []; + } + }); + } + }, + watch: { + 'form.model.ttsModelId': { + handler(newVal, oldVal) { + console.log('TTS模型变化:', newVal); + if (oldVal && newVal !== oldVal) { + this.form.ttsVoiceId = ''; + this.fetchVoiceOptions(newVal); + } else { + this.fetchVoiceOptions(newVal); + } + }, + immediate: true + }, + voiceOptions: { + handler(newVal) { + if (newVal && newVal.length > 0 && !this.form.ttsVoiceId) { + this.form.ttsVoiceId = newVal[0].value; + } + }, + immediate: true + } }, mounted() { const agentId = this.$route.query.agentId; if (agentId) { this.fetchAgentConfig(agentId); } + this.fetchModelOptions(); + this.fetchTemplates(); } } diff --git a/main/xiaozhi-server/docker-compose.yml b/main/xiaozhi-server/docker-compose.yml index c22e7545..609fcbc1 100644 --- a/main/xiaozhi-server/docker-compose.yml +++ b/main/xiaozhi-server/docker-compose.yml @@ -1,8 +1,17 @@ -# 如果本机已经安装了MySQL,可以直接在数据库中创建名为`xiaozhi_esp32_server`的数据库。 -# 如果还没有MySQL,你可以通过docker安装mysql,执行以下一句话 -# docker run --name xiaozhi-esp32-server-db -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -e MYSQL_DATABASE=xiaozhi_esp32_server -e MYSQL_INITDB_ARGS="--character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci" -d mysql:latest -# 如果你的mysql账号和密码有修改过,记得修改下方数据库的账号和密码 -# 记得修改下方数据库的IP,ip不能写127.0.0.1或localhost,否则容器无法访问,要写你电脑局域网ip +# 1、安装mysql +# |- 如果本机已经安装了MySQL,可以直接在数据库中创建名为`xiaozhi_esp32_server`的数据库。 +# |- 如果还没有MySQL,你可以通过docker安装mysql,执行以下一句话 +# |- docker run --name xiaozhi-esp32-server-db -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -e MYSQL_DATABASE=xiaozhi_esp32_server -e MYSQL_INITDB_ARGS="--character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci" -d mysql:latest +# |- 如果你的mysql账号和密码有修改过,记得修改下方数据库的账号和密码 +# |- 记得修改下方SPRING_DATASOURCE_DRUID_URL的IP,ip不能写127.0.0.1或localhost,否则容器无法访问,要写你电脑局域网ip + +# 2、安装redis +# |- 如果本机已经安装了Redis,看一下你安装的redis端口、密码,然后修改下方redis的地址和端口 +# |- 如果还没有Redis,你可以通过docker安装redis,执行以下一句话 +# |- docker run --name xiaozhi-esp32-server-redis -d -p 6379:6379 redis +# |- 记得修改SPRING_DATA_REDIS_HOST的IP,ip不能写127.0.0.1或localhost,否则容器无法访问,要写你电脑局域网ip + + version: '3' services: xiaozhi-esp32-server: