From 5d69ba079655c59fc22c86041d932e18a688f2c8 Mon Sep 17 00:00:00 2001 From: hrz <1710360675@qq.com> Date: Sat, 12 Apr 2025 17:36:04 +0800 Subject: [PATCH] =?UTF-8?q?update:server=E8=BF=9E=E6=8E=A5api=20(#747)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update:server连接manager-api * update:读取智能体模型配置 * update:添加默认模型的按钮 * update:优化配置读取方式 * update:server兼容manager接口改造 * update:优化私有配置加载 * update:加载私有模型配置 --- .../xiaozhi/common/config/SwaggerConfig.java | 8 + .../xiaozhi/common/exception/ErrorCode.java | 1 + .../java/xiaozhi/common/redis/RedisKeys.java | 23 +- .../agent/controller/AgentController.java | 1 + .../agent/service/AgentTemplateService.java | 8 + .../impl/AgentTemplateServiceImpl.java | 35 +++ .../config/controller/ConfigController.java | 61 ++++ .../modules/config/dto/AgentModelsDTO.java | 28 ++ .../init}/SystemInitConfig.java | 7 +- .../modules/config/service/ConfigService.java | 22 ++ .../service/impl/ConfigServiceImpl.java | 253 +++++++++++++++ .../modules/device/service/DeviceService.java | 8 + .../service/impl/DeviceServiceImpl.java | 10 + .../model/controller/ModelController.java | 26 ++ .../model/service/ModelConfigService.java | 17 ++ .../service/impl/ModelConfigServiceImpl.java | 28 ++ .../modules/security/config/ShiroConfig.java | 3 +- .../modules/sys/dto/ConfigSecretDTO.java | 13 + .../service/impl/SysParamsServiceImpl.java | 7 + .../modules/timbre/service/TimbreService.java | 2 +- .../service/impl/TimbreServiceImpl.java | 30 +- .../{202504082210.sql => 202504112044.sql} | 76 ++--- .../{202504092313.sql => 202504112057.sql} | 24 +- .../db/changelog/db.changelog-master.yaml | 30 +- .../main/resources/i18n/messages.properties | 1 + .../resources/i18n/messages_en_US.properties | 3 +- .../resources/i18n/messages_zh_CN.properties | 3 +- .../resources/i18n/messages_zh_TW.properties | 3 +- main/manager-web/src/apis/module/model.js | 85 +++--- main/manager-web/src/views/ModelConfig.vue | 48 ++- main/manager-web/src/views/UserManagement.vue | 1 + main/xiaozhi-server/app.py | 4 + main/xiaozhi-server/config.yaml | 3 +- main/xiaozhi-server/config/config_loader.py | 178 +++++++++++ main/xiaozhi-server/config/logger.py | 27 +- main/xiaozhi-server/config/private_config.py | 241 --------------- main/xiaozhi-server/config/settings.py | 93 +----- main/xiaozhi-server/config_from_api.yaml | 12 + main/xiaozhi-server/core/connection.py | 174 ++++++----- .../xiaozhi-server/core/handle/helloHandle.py | 9 + main/xiaozhi-server/core/mcp/manager.py | 59 ++-- .../core/providers/llm/gemini/gemini.py | 38 +-- .../core/providers/llm/openai/openai.py | 25 +- .../core/providers/memory/mem0ai/mem0ai.py | 38 +-- .../memory/mem_local_short/mem_local_short.py | 54 ++-- .../core/providers/tts/doubao.py | 27 +- .../core/providers/tts/fishspeech.py | 17 +- .../core/providers/tts/openai.py | 18 +- .../xiaozhi-server/core/providers/vad/base.py | 9 + .../core/providers/vad/silero.py | 63 ++++ .../core/utils/auth_code_gen.py | 97 ------ .../xiaozhi-server/core/utils/lock_manager.py | 39 --- main/xiaozhi-server/core/utils/memory.py | 11 +- main/xiaozhi-server/core/utils/util.py | 131 ++++++-- main/xiaozhi-server/core/utils/vad.py | 82 +---- main/xiaozhi-server/core/websocket_server.py | 81 +---- main/xiaozhi-server/performance_tester.py | 289 +++++++++++------- 57 files changed, 1618 insertions(+), 1066 deletions(-) create mode 100644 main/manager-api/src/main/java/xiaozhi/modules/config/controller/ConfigController.java create mode 100644 main/manager-api/src/main/java/xiaozhi/modules/config/dto/AgentModelsDTO.java rename main/manager-api/src/main/java/xiaozhi/modules/{sys/config => config/init}/SystemInitConfig.java (73%) create mode 100644 main/manager-api/src/main/java/xiaozhi/modules/config/service/ConfigService.java create mode 100644 main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java create mode 100644 main/manager-api/src/main/java/xiaozhi/modules/sys/dto/ConfigSecretDTO.java rename main/manager-api/src/main/resources/db/changelog/{202504082210.sql => 202504112044.sql} (54%) rename main/manager-api/src/main/resources/db/changelog/{202504092313.sql => 202504112057.sql} (73%) create mode 100644 main/xiaozhi-server/config/config_loader.py delete mode 100644 main/xiaozhi-server/config/private_config.py create mode 100644 main/xiaozhi-server/config_from_api.yaml create mode 100644 main/xiaozhi-server/core/providers/vad/base.py create mode 100644 main/xiaozhi-server/core/providers/vad/silero.py delete mode 100644 main/xiaozhi-server/core/utils/auth_code_gen.py delete mode 100644 main/xiaozhi-server/core/utils/lock_manager.py 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 0def6589..8fb31641 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 @@ -71,6 +71,14 @@ public class SwaggerConfig { .build(); } + @Bean + public GroupedOpenApi configApi() { + return GroupedOpenApi.builder() + .group("config") + .pathsToMatch("/config/**") + .build(); + } + @Bean public OpenAPI customOpenAPI() { return new OpenAPI().info(new Info() diff --git a/main/manager-api/src/main/java/xiaozhi/common/exception/ErrorCode.java b/main/manager-api/src/main/java/xiaozhi/common/exception/ErrorCode.java index 4497a095..d9217013 100644 --- a/main/manager-api/src/main/java/xiaozhi/common/exception/ErrorCode.java +++ b/main/manager-api/src/main/java/xiaozhi/common/exception/ErrorCode.java @@ -51,4 +51,5 @@ public interface ErrorCode { int PARAM_NUMBER_INVALID = 10037; int PARAM_BOOLEAN_INVALID = 10038; int PARAM_ARRAY_INVALID = 10039; + int PARAM_JSON_INVALID = 10040; } diff --git a/main/manager-api/src/main/java/xiaozhi/common/redis/RedisKeys.java b/main/manager-api/src/main/java/xiaozhi/common/redis/RedisKeys.java index 53aa08dc..7bc0c48d 100644 --- a/main/manager-api/src/main/java/xiaozhi/common/redis/RedisKeys.java +++ b/main/manager-api/src/main/java/xiaozhi/common/redis/RedisKeys.java @@ -38,7 +38,14 @@ public class RedisKeys { * 模型名称的Key */ public static String getModelNameById(String id) { - return "sys:model:name:" + id; + return "model:name:" + id; + } + + /** + * 模型配置的Key + */ + public static String getModelConfigById(String id) { + return "model:data:" + id; } /** @@ -54,4 +61,18 @@ public class RedisKeys { public static String getAgentDeviceCountById(String id) { return "agent:device:count:" + id; } + + /** + * 获取系统配置缓存key + */ + public static String getServerConfigKey() { + return "server:config"; + } + + /** + * 获取音色详情缓存key + */ + public static String getTimbreDetailsKey(String id) { + return "timbre:details:" + id; + } } 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 eea2d7fe..123e10ba 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 @@ -191,4 +191,5 @@ public class AgentController { .list(new QueryWrapper().orderByAsc("sort")); return new Result>().ok(list); } + } \ No newline at end of file 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 index 197c860e..4e279c40 100644 --- 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 @@ -17,4 +17,12 @@ public interface AgentTemplateService extends IService { * @return 默认模板实体 */ AgentTemplateEntity getDefaultTemplate(); + + /** + * 更新默认模板中的模型ID + * + * @param modelType 模型类型 + * @param modelId 模型ID + */ + void updateDefaultTemplateModelId(String modelType, String modelId); } 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 index 949a2f2d..08702d10 100644 --- 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 @@ -29,4 +29,39 @@ public class AgentTemplateServiceImpl extends ServiceImpl getConfig(@RequestBody ConfigSecretDTO dto) { + // 效验数据 + ValidatorUtils.validateEntity(dto); + checkSecret(dto.getSecret()); + Object config = configService.getConfig(true); + return new Result().ok(config); + } + + @PostMapping("agent-models") + @Operation(summary = "获取智能体模型") + public Result getAgentModels(@RequestBody AgentModelsDTO dto) { + // 效验数据 + ValidatorUtils.validateEntity(dto); + checkSecret(dto.getSecret()); + Object models = configService.getAgentModels(dto.getMacAddress(), dto.getSelectedModule()); + return new Result().ok(models); + } + + private void checkSecret(String secret) { + String secretParam = sysParamsService.getValue(Constant.SERVER_SECRET, true); + // 验证密钥 + if (StringUtils.isBlank(secret) || !secret.equals(secretParam)) { + throw new RenException("密钥错误"); + } + } +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/config/dto/AgentModelsDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/config/dto/AgentModelsDTO.java new file mode 100644 index 00000000..4a07a743 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/config/dto/AgentModelsDTO.java @@ -0,0 +1,28 @@ +package xiaozhi.modules.config.dto; + +import java.util.Map; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +@Schema(description = "获取智能体模型配置DTO") +public class AgentModelsDTO { + @NotBlank(message = "密钥不能为空") + @Schema(description = "密钥") + private String secret; + + @NotBlank(message = "设备MAC地址不能为空") + @Schema(description = "设备MAC地址") + private String macAddress; + + @NotBlank(message = "客户端ID不能为空") + @Schema(description = "客户端ID") + private String clientId; + + @NotNull(message = "客户端已实例化的模型不能为空") + @Schema(description = "客户端已实例化的模型") + private Map selectedModule; +} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/config/SystemInitConfig.java b/main/manager-api/src/main/java/xiaozhi/modules/config/init/SystemInitConfig.java similarity index 73% rename from main/manager-api/src/main/java/xiaozhi/modules/sys/config/SystemInitConfig.java rename to main/manager-api/src/main/java/xiaozhi/modules/config/init/SystemInitConfig.java index 5122367d..a8e3794e 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/sys/config/SystemInitConfig.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/config/init/SystemInitConfig.java @@ -1,10 +1,11 @@ -package xiaozhi.modules.sys.config; +package xiaozhi.modules.config.init; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import jakarta.annotation.PostConstruct; +import xiaozhi.modules.config.service.ConfigService; import xiaozhi.modules.sys.service.SysParamsService; @Configuration @@ -14,8 +15,12 @@ public class SystemInitConfig { @Autowired private SysParamsService sysParamsService; + @Autowired + private ConfigService configService; + @PostConstruct public void init() { sysParamsService.initServerSecret(); + configService.getConfig(false); } } \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/config/service/ConfigService.java b/main/manager-api/src/main/java/xiaozhi/modules/config/service/ConfigService.java new file mode 100644 index 00000000..93845e8e --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/config/service/ConfigService.java @@ -0,0 +1,22 @@ +package xiaozhi.modules.config.service; + +import java.util.Map; + +public interface ConfigService { + /** + * 获取服务器配置 + * + * @param isCache 是否缓存 + * @return 配置信息 + */ + Object getConfig(Boolean isCache); + + /** + * 获取智能体模型配置 + * + * @param macAddress MAC地址 + * @param selectedModule 客户端已实例化的模型 + * @return 模型配置信息 + */ + Map getAgentModels(String macAddress, Map selectedModule); +} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java new file mode 100644 index 00000000..8c5b9138 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java @@ -0,0 +1,253 @@ +package xiaozhi.modules.config.service.impl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import lombok.AllArgsConstructor; +import xiaozhi.common.exception.RenException; +import xiaozhi.common.redis.RedisKeys; +import xiaozhi.common.redis.RedisUtils; +import xiaozhi.common.utils.JsonUtils; +import xiaozhi.modules.agent.entity.AgentEntity; +import xiaozhi.modules.agent.entity.AgentTemplateEntity; +import xiaozhi.modules.agent.service.AgentService; +import xiaozhi.modules.agent.service.AgentTemplateService; +import xiaozhi.modules.config.service.ConfigService; +import xiaozhi.modules.device.entity.DeviceEntity; +import xiaozhi.modules.device.service.DeviceService; +import xiaozhi.modules.model.entity.ModelConfigEntity; +import xiaozhi.modules.model.service.ModelConfigService; +import xiaozhi.modules.sys.dto.SysParamsDTO; +import xiaozhi.modules.sys.service.SysParamsService; +import xiaozhi.modules.timbre.service.TimbreService; +import xiaozhi.modules.timbre.vo.TimbreDetailsVO; + +@Service +@AllArgsConstructor +public class ConfigServiceImpl implements ConfigService { + private final SysParamsService sysParamsService; + private final DeviceService deviceService; + private final ModelConfigService modelConfigService; + private final AgentService agentService; + private final AgentTemplateService agentTemplateService; + private final RedisUtils redisUtils; + private final TimbreService timbreService; + + @Override + public Object getConfig(Boolean isCache) { + if (isCache) { + // 先从Redis获取配置 + Object cachedConfig = redisUtils.get(RedisKeys.getServerConfigKey()); + if (cachedConfig != null) { + return cachedConfig; + } + } + + // 构建配置信息 + Map result = new HashMap<>(); + buildConfig(result); + + // 查询默认智能体 + AgentTemplateEntity agent = agentTemplateService.getDefaultTemplate(); + if (agent == null) { + throw new RenException("默认智能体未找到"); + } + + // 构建模块配置 + buildModuleConfig( + agent.getSystemPrompt(), + null, + agent.getVadModelId(), + agent.getAsrModelId(), + agent.getLlmModelId(), + agent.getTtsModelId(), + agent.getMemModelId(), + agent.getIntentModelId(), + result, + isCache); + + // 将配置存入Redis + redisUtils.set(RedisKeys.getServerConfigKey(), result); + + return result; + } + + @Override + public Map getAgentModels(String macAddress, Map selectedModule) { + // 根据MAC地址查找设备 + DeviceEntity device = deviceService.getDeviceByMacAddress(macAddress); + if (device == null) { + throw new RenException("设备未找到"); + } + // 获取智能体信息 + AgentEntity agent = agentService.getAgentById(device.getAgentId()); + if (agent == null) { + throw new RenException("智能体未找到"); + } + // 获取音色信息 + String voice = null; + TimbreDetailsVO timbre = timbreService.get(agent.getTtsVoiceId()); + if (timbre != null) { + voice = timbre.getTtsVoice(); + } + // 构建返回数据 + Map result = new HashMap<>(); + + // 如果客户端已实例化模型,则不返回 + String alreadySelectedVadModelId = (String) selectedModule.get("VAD"); + if (alreadySelectedVadModelId != null && alreadySelectedVadModelId.equals(agent.getVadModelId())) { + agent.setVadModelId(null); + } + String alreadySelectedAsrModelId = (String) selectedModule.get("ASR"); + if (alreadySelectedAsrModelId != null && alreadySelectedAsrModelId.equals(agent.getAsrModelId())) { + agent.setAsrModelId(null); + } + String alreadySelectedLlmModelId = (String) selectedModule.get("LLM"); + if (alreadySelectedLlmModelId != null && alreadySelectedLlmModelId.equals(agent.getLlmModelId())) { + agent.setLlmModelId(null); + } + String alreadySelectedMemModelId = (String) selectedModule.get("Memory"); + if (alreadySelectedMemModelId != null && alreadySelectedMemModelId.equals(agent.getMemModelId())) { + agent.setMemModelId(null); + } + String alreadySelectedIntentModelId = (String) selectedModule.get("Intent"); + if (alreadySelectedIntentModelId != null && alreadySelectedIntentModelId.equals(agent.getIntentModelId())) { + agent.setIntentModelId(null); + } + + // 构建模块配置 + buildModuleConfig( + agent.getSystemPrompt(), + voice, + agent.getVadModelId(), + agent.getAsrModelId(), + agent.getLlmModelId(), + agent.getTtsModelId(), + agent.getMemModelId(), + agent.getIntentModelId(), + result, + true); + + return result; + } + + /** + * 构建配置信息 + * + * @param paramsList 系统参数列表 + * @return 配置信息 + */ + @SuppressWarnings("unchecked") + private Object buildConfig(Map config) { + + // 查询所有系统参数 + List paramsList = sysParamsService.list(new HashMap<>()); + + for (SysParamsDTO param : paramsList) { + String[] keys = param.getParamCode().split("\\."); + Map current = config; + + // 遍历除最后一个key之外的所有key + for (int i = 0; i < keys.length - 1; i++) { + String key = keys[i]; + if (!current.containsKey(key)) { + current.put(key, new HashMap()); + } + current = (Map) current.get(key); + } + + // 处理最后一个key + String lastKey = keys[keys.length - 1]; + String value = param.getParamValue(); + + // 根据valueType转换值 + switch (param.getValueType().toLowerCase()) { + case "number": + try { + current.put(lastKey, Double.parseDouble(value)); + } catch (NumberFormatException e) { + current.put(lastKey, value); + } + break; + case "boolean": + current.put(lastKey, Boolean.parseBoolean(value)); + break; + case "array": + // 将分号分隔的字符串转换为数字数组 + List list = new ArrayList<>(); + for (String num : value.split(";")) { + if (StringUtils.isNotBlank(num)) { + list.add(num.trim()); + } + } + current.put(lastKey, list); + break; + case "json": + try { + current.put(lastKey, JsonUtils.parseObject(value, Object.class)); + } catch (Exception e) { + current.put(lastKey, value); + } + break; + default: + current.put(lastKey, value); + } + } + + return config; + } + + /** + * 构建模块配置 + * + * @param prompt 提示词 + * @param voice 音色 + * @param vadModelId VAD模型ID + * @param asrModelId ASR模型ID + * @param llmModelId LLM模型ID + * @param ttsModelId TTS模型ID + * @param memModelId 记忆模型ID + * @param intentModelId 意图模型ID + * @param result 结果Map + */ + private void buildModuleConfig( + String prompt, + String voice, + String vadModelId, + String asrModelId, + String llmModelId, + String ttsModelId, + String memModelId, + String intentModelId, + Map result, + boolean isCache) { + Map selectedModule = new HashMap<>(); + + String[] modelTypes = { "VAD", "ASR", "LLM", "TTS", "Memory", "Intent" }; + String[] modelIds = { vadModelId, asrModelId, llmModelId, ttsModelId, memModelId, intentModelId }; + + for (int i = 0; i < modelIds.length; i++) { + if (modelIds[i] == null) { + continue; + } + ModelConfigEntity model = modelConfigService.getModelById(modelIds[i], isCache); + Map typeConfig = new HashMap<>(); + if (model.getConfigJson() != null) { + typeConfig.put(model.getId(), model.getConfigJson()); + // 如果是TTS类型,添加private_voice属性 + if ("TTS".equals(modelTypes[i]) && voice != null) { + ((Map) model.getConfigJson()).put("private_voice", voice); + } + } + result.put(modelTypes[i], typeConfig); + selectedModule.put(modelTypes[i], model.getId()); + } + result.put("selected_module", selectedModule); + result.put("prompt", prompt); + } +} 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 37ff8d49..983cb6ee 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 @@ -66,4 +66,12 @@ public interface DeviceService { * @return 用户列表分页数据 */ PageData page(DevicePageUserDTO dto); + + /** + * 根据MAC地址获取设备信息 + * + * @param macAddress MAC地址 + * @return 设备信息 + */ + DeviceEntity getDeviceByMacAddress(String macAddress); } \ No newline at end of file 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 a9797f42..f2821053 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 @@ -240,6 +240,16 @@ public class DeviceServiceImpl extends BaseServiceImpl return new PageData<>(list, page.getTotal()); } + @Override + public DeviceEntity getDeviceByMacAddress(String macAddress) { + if (StringUtils.isBlank(macAddress)) { + return null; + } + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("mac_address", macAddress); + return baseDao.selectOne(wrapper); + } + private DeviceReportRespDTO.ServerTime buildServerTime() { DeviceReportRespDTO.ServerTime serverTime = new DeviceReportRespDTO.ServerTime(); TimeZone tz = TimeZone.getDefault(); 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 0ce42157..c2ec0122 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,6 +19,8 @@ import lombok.AllArgsConstructor; import xiaozhi.common.page.PageData; import xiaozhi.common.utils.ConvertUtils; import xiaozhi.common.utils.Result; +import xiaozhi.modules.agent.service.AgentTemplateService; +import xiaozhi.modules.config.service.ConfigService; import xiaozhi.modules.model.dto.ModelBasicInfoDTO; import xiaozhi.modules.model.dto.ModelConfigBodyDTO; import xiaozhi.modules.model.dto.ModelConfigDTO; @@ -38,6 +40,8 @@ public class ModelController { private final ModelProviderService modelProviderService; private final TimbreService timbreService; private final ModelConfigService modelConfigService; + private final ConfigService configService; + private final AgentTemplateService agentTemplateService; @GetMapping("/names") @Operation(summary = "获取所有模型名称") @@ -75,6 +79,7 @@ public class ModelController { @PathVariable String provideCode, @RequestBody ModelConfigBodyDTO modelConfigBodyDTO) { ModelConfigDTO modelConfigDTO = modelConfigService.add(modelType, provideCode, modelConfigBodyDTO); + configService.getConfig(false); return new Result().ok(modelConfigDTO); } @@ -86,6 +91,7 @@ public class ModelController { @PathVariable String id, @RequestBody ModelConfigBodyDTO modelConfigBodyDTO) { ModelConfigDTO modelConfigDTO = modelConfigService.edit(modelType, provideCode, id, modelConfigBodyDTO); + configService.getConfig(false); return new Result().ok(modelConfigDTO); } @@ -119,6 +125,26 @@ public class ModelController { return new Result(); } + @PutMapping("/default/{id}") + @Operation(summary = "设置默认模型") + @RequiresPermissions("sys:role:superAdmin") + public Result setDefaultModel(@PathVariable String id) { + ModelConfigEntity entity = modelConfigService.selectById(id); + if (entity == null) { + return new Result().error("模型配置不存在"); + } + // 将其他模型设置为非默认 + modelConfigService.setDefaultModel(entity.getModelType(), 0); + entity.setIsDefault(1); + modelConfigService.updateById(entity); + + // 更新模板表中对应的模型ID + agentTemplateService.updateDefaultTemplateModelId(entity.getModelType(), entity.getId()); + + configService.getConfig(false); + return new Result(); + } + @GetMapping("/{modelId}/voices") @Operation(summary = "获取模型音色") @RequiresPermissions("sys:role:normal") 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 b8cc38b1..9d15ac6d 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 @@ -28,4 +28,21 @@ public interface ModelConfigService extends BaseService { * @return 模型名称 */ String getModelNameById(String id); + + /** + * 根据ID获取模型配置 + * + * @param id 模型ID + * @param isCache 是否缓存 + * @return 模型配置实体 + */ + ModelConfigEntity getModelById(String id, boolean isCache); + + /** + * 设置默认模型 + * + * @param modelType 模型类型 + * @param isDefault 是否默认 + */ + void setDefaultModel(String modelType, int isDefault); } 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 de8cbd4f..b33b13b4 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 @@ -94,6 +94,8 @@ public class ModelConfigServiceImpl extends BaseServiceImpl() + .eq("model_type", modelType)); + } } 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 e5b89c99..7bd356fc 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 @@ -77,7 +77,8 @@ public class ShiroConfig { filterMap.put("/user/captcha", "anon"); filterMap.put("/user/login", "anon"); filterMap.put("/user/register", "anon"); - filterMap.put("/device/register", "anon"); + filterMap.put("/config/server-base", "anon"); + filterMap.put("/config/agent-models", "anon"); filterMap.put("/**", "oauth2"); shiroFilter.setFilterChainDefinitionMap(filterMap); diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/dto/ConfigSecretDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/dto/ConfigSecretDTO.java new file mode 100644 index 00000000..8e4978f9 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/dto/ConfigSecretDTO.java @@ -0,0 +1,13 @@ +package xiaozhi.modules.sys.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +@Data +@Schema(description = "配置密钥DTO") +public class ConfigSecretDTO { + @Schema(description = "密钥") + @NotBlank(message = "密钥不能为空") + private String secret; +} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysParamsServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysParamsServiceImpl.java index 85814975..5ca59f6b 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysParamsServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysParamsServiceImpl.java @@ -125,6 +125,13 @@ public class SysParamsServiceImpl extends BaseServiceImpl { * @param timbreId 音色表id * @return 音色信息 */ - TimbreDetailsVO get(Long timbreId); + TimbreDetailsVO get(String timbreId); /** * 保存音色信息 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 54e5ec04..fe5cb555 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 @@ -59,9 +59,33 @@ public class TimbreServiceImpl extends BaseServiceImpl } @Override - public TimbreDetailsVO get(Long timbreId) { + public TimbreDetailsVO get(String timbreId) { + if (StringUtils.isBlank(timbreId)) { + return null; + } + + // 先从Redis获取缓存 + String key = RedisKeys.getTimbreDetailsKey(timbreId); + TimbreDetailsVO cachedDetails = (TimbreDetailsVO) redisUtils.get(key); + if (cachedDetails != null) { + return cachedDetails; + } + + // 如果缓存中没有,则从数据库获取 TimbreEntity entity = baseDao.selectById(timbreId); - return ConvertUtils.sourceToTarget(entity, TimbreDetailsVO.class); + if (entity == null) { + return null; + } + + // 转换为VO对象 + TimbreDetailsVO details = ConvertUtils.sourceToTarget(entity, TimbreDetailsVO.class); + + // 存入Redis缓存 + if (details != null) { + redisUtils.set(key, details); + } + + return details; } @Override @@ -79,6 +103,8 @@ public class TimbreServiceImpl extends BaseServiceImpl TimbreEntity timbreEntity = ConvertUtils.sourceToTarget(dto, TimbreEntity.class); timbreEntity.setId(timbreId); baseDao.updateById(timbreEntity); + // 删除缓存 + redisUtils.delete(RedisKeys.getTimbreDetailsKey(timbreId)); } @Override diff --git a/main/manager-api/src/main/resources/db/changelog/202504082210.sql b/main/manager-api/src/main/resources/db/changelog/202504112044.sql similarity index 54% rename from main/manager-api/src/main/resources/db/changelog/202504082210.sql rename to main/manager-api/src/main/resources/db/changelog/202504112044.sql index 65858527..9fd2257d 100644 --- a/main/manager-api/src/main/resources/db/changelog/202504082210.sql +++ b/main/manager-api/src/main/resources/db/changelog/202504112044.sql @@ -4,50 +4,52 @@ DELETE FROM `ai_model_config`; -- VAD模型配置 -INSERT INTO `ai_model_config` VALUES ('VAD_SileroVAD', 'VAD', 'SileroVAD', '语音活动检测', 1, 1, '{\"type\": \"silero\", \"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 ('VAD_SileroVAD', 'VAD', 'SileroVAD', '语音活动检测', 1, 1, '{\"type\": \"silero\", \"model_dir\": \"models/snakers4_silero-vad\", \"threshold\": 0.5, \"min_silence_duration_ms\": 700}', NULL, NULL, 1, NULL, NULL, NULL, NULL); -- ASR模型配置 -INSERT INTO `ai_model_config` VALUES ('ASR_FunASR', 'ASR', 'FunASR', 'FunASR语音识别', 1, 1, '{\"type\": \"fun_local\", \"model_dir\": \"models/SenseVoiceSmall\", \"output_dir\": \"tmp/\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('ASR_SherpaASR', 'ASR', 'SherpaASR', 'Sherpa语音识别', 1, 0, '{\"type\": \"sherpa_onnx_local\", \"model_dir\": \"models/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17\", \"output_dir\": \"tmp/\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('ASR_DoubaoASR', 'ASR', 'DoubaoASR', '豆包语音识别', 1, 0, '{\"type\": \"doubao\", \"appid\": \"\", \"access_token\": \"\", \"cluster\": \"volcengine_input_common\", \"output_dir\": \"tmp/\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('ASR_FunASR', 'ASR', 'FunASR', 'FunASR语音识别', 1, 1, '{\"type\": \"fun_local\", \"model_dir\": \"models/SenseVoiceSmall\", \"output_dir\": \"tmp/\"}', NULL, NULL, 1, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('ASR_SherpaASR', 'ASR', 'SherpaASR', 'Sherpa语音识别', 0, 1, '{\"type\": \"sherpa_onnx_local\", \"model_dir\": \"models/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17\", \"output_dir\": \"tmp/\"}', NULL, NULL, 2, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('ASR_DoubaoASR', 'ASR', 'DoubaoASR', '豆包语音识别', 0, 1, '{\"type\": \"doubao\", \"appid\": \"\", \"access_token\": \"\", \"cluster\": \"volcengine_input_common\", \"output_dir\": \"tmp/\"}', NULL, NULL, 3, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('ASR_TencentASR', 'ASR', 'TencentASR', '腾讯语音识别', 0, 1, '{\"type\": \"tencent\", \"appid\": \"\", \"secret_id\": \"\", \"secret_key\": \"你的secret_key\", \"output_dir\": \"tmp/\"}', NULL, NULL, 4, NULL, NULL, NULL, NULL); -- LLM模型配置 -INSERT INTO `ai_model_config` VALUES ('LLM_AliLLM', 'LLM', 'AliLLM', '通义千问', 1, 0, '{\"type\": \"openai\", \"base_url\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\", \"model_name\": \"qwen-turbo\", \"api_key\": \"\", \"temperature\": 0.7, \"max_tokens\": 500, \"top_p\": 1, \"top_k\": 50, \"frequency_penalty\": 0}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('LLM_AliAppLLM', 'LLM', 'AliAppLLM', '通义百炼', 1, 0, '{\"type\": \"AliBL\", \"base_url\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\", \"app_id\": \"\", \"api_key\": \"\", \"is_no_prompt\": true, \"ali_memory_id\": false}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('LLM_DoubaoLLM', 'LLM', 'DoubaoLLM', '豆包大模型', 1, 0, '{\"type\": \"openai\", \"base_url\": \"https://ark.cn-beijing.volces.com/api/v3\", \"model_name\": \"doubao-pro-32k-functioncall-241028\", \"api_key\": \"\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('LLM_DeepSeekLLM', 'LLM', 'DeepSeekLLM', 'DeepSeek', 1, 0, '{\"type\": \"openai\", \"model_name\": \"deepseek-chat\", \"url\": \"https://api.deepseek.com\", \"api_key\": \"\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('LLM_ChatGLMLLM', 'LLM', 'ChatGLMLLM', '智谱AI', 1, 1, '{\"type\": \"openai\", \"model_name\": \"glm-4-flash\", \"url\": \"https://open.bigmodel.cn/api/paas/v4/\", \"api_key\": \"\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('LLM_OllamaLLM', 'LLM', 'OllamaLLM', 'Ollama本地模型', 1, 0, '{\"type\": \"ollama\", \"model_name\": \"qwen2.5\", \"base_url\": \"http://localhost:11434\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('LLM_DifyLLM', 'LLM', 'DifyLLM', 'Dify', 1, 0, '{\"type\": \"dify\", \"base_url\": \"https://api.dify.ai/v1\", \"api_key\": \"\", \"mode\": \"chat-messages\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('LLM_GeminiLLM', 'LLM', 'GeminiLLM', '谷歌Gemini', 1, 0, '{\"type\": \"gemini\", \"api_key\": \"\", \"model_name\": \"gemini-2.0-flash\", \"http_proxy\": \"\", \"https_proxy\": \"\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('LLM_CozeLLM', 'LLM', 'CozeLLM', 'Coze', 1, 0, '{\"type\": \"coze\", \"bot_id\": \"\", \"user_id\": \"\", \"personal_access_token\": \"\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('LLM_LMStudioLLM', 'LLM', 'LMStudioLLM', 'LM Studio', 1, 0, '{\"type\": \"openai\", \"model_name\": \"deepseek-r1-distill-llama-8b@q4_k_m\", \"url\": \"http://localhost:1234/v1\", \"api_key\": \"lm-studio\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('LLM_FastgptLLM', 'LLM', 'FastgptLLM', 'FastGPT', 1, 0, '{\"type\": \"fastgpt\", \"base_url\": \"https://host/api/v1\", \"api_key\": \"fastgpt-xxx\", \"variables\": {\"k\": \"v\", \"k2\": \"v2\"}}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('LLM_XinferenceLLM', 'LLM', 'XinferenceLLM', 'Xinference大模型', 1, 0, '{\"type\": \"xinference\", \"model_name\": \"qwen2.5:72b-AWQ\", \"base_url\": \"http://localhost:9997\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('LLM_XinferenceSmallLLM', 'LLM', 'XinferenceSmallLLM', 'Xinference小模型', 1, 0, '{\"type\": \"xinference\", \"model_name\": \"qwen2.5:3b-AWQ\", \"base_url\": \"http://localhost:9997\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('LLM_ChatGLMLLM', 'LLM', 'ChatGLMLLM', '智谱AI', 1, 1, '{\"type\": \"openai\", \"model_name\": \"glm-4-flash\", \"base_url\": \"https://open.bigmodel.cn/api/paas/v4/\", \"api_key\": \"你的api_key\"}', NULL, NULL, 1, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('LLM_OllamaLLM', 'LLM', 'OllamaLLM', 'Ollama本地模型', 0, 1, '{\"type\": \"ollama\", \"model_name\": \"qwen2.5\", \"base_url\": \"http://localhost:11434\"}', NULL, NULL, 2, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('LLM_AliLLM', 'LLM', 'AliLLM', '通义千问', 0, 1, '{\"type\": \"openai\", \"base_url\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\", \"model_name\": \"qwen-turbo\", \"api_key\": \"你的api_key\", \"temperature\": 0.7, \"max_tokens\": 500, \"top_p\": 1, \"top_k\": 50, \"frequency_penalty\": 0}', NULL, NULL, 3, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('LLM_AliAppLLM', 'LLM', 'AliAppLLM', '通义百炼', 0, 1, '{\"type\": \"AliBL\", \"base_url\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\", \"app_id\": \"你的app_id\", \"api_key\": \"你的api_key\", \"is_no_prompt\": true, \"ali_memory_id\": false}', NULL, NULL, 4, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('LLM_DoubaoLLM', 'LLM', 'DoubaoLLM', '豆包大模型', 0, 1, '{\"type\": \"openai\", \"base_url\": \"https://ark.cn-beijing.volces.com/api/v3\", \"model_name\": \"doubao-pro-32k-functioncall-241028\", \"api_key\": \"你的api_key\"}', NULL, NULL, 5, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('LLM_DeepSeekLLM', 'LLM', 'DeepSeekLLM', 'DeepSeek', 0, 1, '{\"type\": \"openai\", \"model_name\": \"deepseek-chat\", \"base_url\": \"https://api.deepseek.com\", \"api_key\": \"你的api_key\"}', NULL, NULL, 6, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('LLM_DifyLLM', 'LLM', 'DifyLLM', 'Dify', 0, 1, '{\"type\": \"dify\", \"base_url\": \"https://api.dify.ai/v1\", \"api_key\": \"你的api_key\", \"mode\": \"chat-messages\"}', NULL, NULL, 7, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('LLM_GeminiLLM', 'LLM', 'GeminiLLM', '谷歌Gemini', 0, 1, '{\"type\": \"gemini\", \"api_key\": \"你的api_key\", \"model_name\": \"gemini-2.0-flash\", \"http_proxy\": \"\", \"https_proxy\": \"\"}', NULL, NULL, 8, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('LLM_CozeLLM', 'LLM', 'CozeLLM', 'Coze', 0, 1, '{\"type\": \"coze\", \"bot_id\": \"你的bot_id\", \"user_id\": \"你的user_id\", \"personal_access_token\": \"你的personal_access_token\"}', NULL, NULL, 9, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('LLM_LMStudioLLM', 'LLM', 'LMStudioLLM', 'LM Studio', 0, 1, '{\"type\": \"openai\", \"model_name\": \"deepseek-r1-distill-llama-8b@q4_k_m\", \"base_url\": \"http://localhost:1234/v1\", \"api_key\": \"lm-studio\"}', NULL, NULL, 10, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('LLM_FastgptLLM', 'LLM', 'FastgptLLM', 'FastGPT', 0, 1, '{\"type\": \"fastgpt\", \"base_url\": \"https://host/api/v1\", \"api_key\": \"fastgpt-xxx\", \"variables\": {\"k\": \"v\", \"k2\": \"v2\"}}', NULL, NULL, 11, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('LLM_XinferenceLLM', 'LLM', 'XinferenceLLM', 'Xinference大模型', 0, 1, '{\"type\": \"xinference\", \"model_name\": \"qwen2.5:72b-AWQ\", \"base_url\": \"http://localhost:9997\"}', NULL, NULL, 12, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('LLM_XinferenceSmallLLM', 'LLM', 'XinferenceSmallLLM', 'Xinference小模型', 0, 1, '{\"type\": \"xinference\", \"model_name\": \"qwen2.5:3b-AWQ\", \"base_url\": \"http://localhost:9997\"}', NULL, NULL, 13, NULL, NULL, NULL, NULL); -- TTS模型配置 -INSERT INTO `ai_model_config` VALUES ('TTS_EdgeTTS', 'TTS', 'EdgeTTS', 'Edge语音合成', 1, 1, '{\"type\": \"edge\", \"voice\": \"zh-CN-XiaoxiaoNeural\", \"output_dir\": \"tmp/\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('TTS_DoubaoTTS', 'TTS', 'DoubaoTTS', '豆包语音合成', 1, 0, '{\"type\": \"doubao\", \"api_url\": \"https://openspeech.bytedance.com/api/v1/tts\", \"voice\": \"BV001_streaming\", \"output_dir\": \"tmp/\", \"authorization\": \"Bearer;\", \"appid\": \"\", \"access_token\": \"\", \"cluster\": \"volcano_tts\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('TTS_CosyVoiceSiliconflow', 'TTS', 'CosyVoiceSiliconflow', '硅基流动语音合成', 1, 0, '{\"type\": \"siliconflow\", \"model\": \"FunAudioLLM/CosyVoice2-0.5B\", \"voice\": \"FunAudioLLM/CosyVoice2-0.5B:alex\", \"output_dir\": \"tmp/\", \"access_token\": \"\", \"response_format\": \"wav\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('TTS_CozeCnTTS', 'TTS', 'CozeCnTTS', 'Coze中文语音合成', 1, 0, '{\"type\": \"cozecn\", \"voice\": \"7426720361733046281\", \"output_dir\": \"tmp/\", \"access_token\": \"\", \"response_format\": \"wav\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('TTS_FishSpeech', 'TTS', 'FishSpeech', 'FishSpeech语音合成', 1, 0, '{\"type\": \"fishspeech\", \"output_dir\": \"tmp/\", \"response_format\": \"wav\", \"reference_id\": null, \"reference_audio\": [\"/tmp/test.wav\"], \"reference_text\": [\"你弄来这些吟词宴曲来看,还是这些混话来欺负我。\"], \"normalize\": true, \"max_new_tokens\": 1024, \"chunk_length\": 200, \"top_p\": 0.7, \"repetition_penalty\": 1.2, \"temperature\": 0.7, \"streaming\": false, \"use_memory_cache\": \"on\", \"seed\": null, \"channels\": 1, \"rate\": 44100, \"api_key\": \"\", \"api_url\": \"http://127.0.0.1:8080/v1/tts\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('TTS_GPT_SOVITS_V2', 'TTS', 'GPT_SOVITS_V2', 'GPT-SoVITS V2', 1, 0, '{\"type\": \"gpt_sovits_v2\", \"url\": \"http://127.0.0.1:9880/tts\", \"output_dir\": \"tmp/\", \"text_lang\": \"auto\", \"ref_audio_path\": \"caixukun.wav\", \"prompt_text\": \"\", \"prompt_lang\": \"zh\", \"top_k\": 5, \"top_p\": 1, \"temperature\": 1, \"text_split_method\": \"cut0\", \"batch_size\": 1, \"batch_threshold\": 0.75, \"split_bucket\": true, \"return_fragment\": false, \"speed_factor\": 1.0, \"streaming_mode\": false, \"seed\": -1, \"parallel_infer\": true, \"repetition_penalty\": 1.35, \"aux_ref_audio_paths\": []}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('TTS_GPT_SOVITS_V3', 'TTS', 'GPT_SOVITS_V3', 'GPT-SoVITS V3', 1, 0, '{\"type\": \"gpt_sovits_v3\", \"url\": \"http://127.0.0.1:9880\", \"output_dir\": \"tmp/\", \"text_language\": \"auto\", \"refer_wav_path\": \"caixukun.wav\", \"prompt_language\": \"zh\", \"prompt_text\": \"\", \"top_k\": 15, \"top_p\": 1.0, \"temperature\": 1.0, \"cut_punc\": \"\", \"speed\": 1.0, \"inp_refs\": [], \"sample_steps\": 32, \"if_sr\": false}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('TTS_MinimaxTTS', 'TTS', 'MinimaxTTS', 'MiniMax语音合成', 1, 0, '{\"type\": \"minimax\", \"output_dir\": \"tmp/\", \"group_id\": \"\", \"api_key\": \"\", \"model\": \"speech-01-turbo\", \"voice_id\": \"female-shaonv\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('TTS_AliyunTTS', 'TTS', 'AliyunTTS', '阿里云语音合成', 1, 0, '{\"type\": \"aliyun\", \"output_dir\": \"tmp/\", \"appkey\": \"\", \"token\": \"\", \"voice\": \"xiaoyun\", \"access_key_id\": \"\", \"access_key_secret\": \"\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('TTS_TTS302AI', 'TTS', 'TTS302AI', '302AI语音合成', 1, 0, '{\"type\": \"doubao\", \"api_url\": \"https://api.302ai.cn/doubao/tts_hd\", \"authorization\": \"Bearer \", \"voice\": \"zh_female_wanwanxiaohe_moon_bigtts\", \"output_dir\": \"tmp/\", \"access_token\": \"\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('TTS_GizwitsTTS', 'TTS', 'GizwitsTTS', '机智云语音合成', 1, 0, '{\"type\": \"doubao\", \"api_url\": \"https://bytedance.gizwitsapi.com/api/v1/tts\", \"authorization\": \"Bearer \", \"voice\": \"zh_female_wanwanxiaohe_moon_bigtts\", \"output_dir\": \"tmp/\", \"access_token\": \"\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('TTS_ACGNTTS', 'TTS', 'ACGNTTS', 'ACGN语音合成', 1, 0, '{\"type\": \"ttson\", \"token\": \"\", \"voice_id\": 1695, \"speed_factor\": 1, \"pitch_factor\": 0, \"volume_change_dB\": 0, \"to_lang\": \"ZH\", \"url\": \"https://u95167-bd74-2aef8085.westx.seetacloud.com:8443/flashsummary/tts?token=\", \"format\": \"mp3\", \"output_dir\": \"tmp/\", \"emotion\": 1}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('TTS_OpenAITTS', 'TTS', 'OpenAITTS', 'OpenAI语音合成', 1, 0, '{\"type\": \"openai\", \"api_key\": \"\", \"api_url\": \"https://api.openai.com/v1/audio/speech\", \"model\": \"tts-1\", \"voice\": \"onyx\", \"speed\": 1, \"output_dir\": \"tmp/\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('TTS_CustomTTS', 'TTS', 'CustomTTS', '自定义语音合成', 1, 0, '{\"type\": \"custom\", \"url\": \"http://127.0.0.1:9880/tts\", \"params\": {}, \"headers\": {}, \"format\": \"wav\", \"output_dir\": \"tmp/\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('TTS_EdgeTTS', 'TTS', 'EdgeTTS', 'Edge语音合成', 1, 1, '{\"type\": \"edge\", \"voice\": \"zh-CN-XiaoxiaoNeural\", \"output_dir\": \"tmp/\"}', NULL, NULL, 1, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('TTS_DoubaoTTS', 'TTS', 'DoubaoTTS', '豆包语音合成', 0, 1, '{\"type\": \"doubao\", \"api_url\": \"https://openspeech.bytedance.com/api/v1/tts\", \"voice\": \"BV001_streaming\", \"output_dir\": \"tmp/\", \"authorization\": \"Bearer;\", \"appid\": \"\", \"access_token\": \"\", \"cluster\": \"volcano_tts\"}', NULL, NULL, 2, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('TTS_CosyVoiceSiliconflow', 'TTS', 'CosyVoiceSiliconflow', '硅基流动语音合成', 0, 1, '{\"type\": \"siliconflow\", \"model\": \"FunAudioLLM/CosyVoice2-0.5B\", \"voice\": \"FunAudioLLM/CosyVoice2-0.5B:alex\", \"output_dir\": \"tmp/\", \"access_token\": \"\", \"response_format\": \"wav\"}', NULL, NULL, 3, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('TTS_CozeCnTTS', 'TTS', 'CozeCnTTS', 'Coze中文语音合成', 0, 1, '{\"type\": \"cozecn\", \"voice\": \"7426720361733046281\", \"output_dir\": \"tmp/\", \"access_token\": \"\", \"response_format\": \"wav\"}', NULL, NULL, 4, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('TTS_FishSpeech', 'TTS', 'FishSpeech', 'FishSpeech语音合成', 0, 1, '{\"type\": \"fishspeech\", \"output_dir\": \"tmp/\", \"response_format\": \"wav\", \"reference_id\": null, \"reference_audio\": [\"/tmp/test.wav\"], \"reference_text\": [\"你弄来这些吟词宴曲来看,还是这些混话来欺负我。\"], \"normalize\": true, \"max_new_tokens\": 1024, \"chunk_length\": 200, \"top_p\": 0.7, \"repetition_penalty\": 1.2, \"temperature\": 0.7, \"streaming\": false, \"use_memory_cache\": \"on\", \"seed\": null, \"channels\": 1, \"rate\": 44100, \"api_key\": \"\", \"api_url\": \"http://127.0.0.1:8080/v1/tts\"}', NULL, NULL, 5, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('TTS_GPT_SOVITS_V2', 'TTS', 'GPT_SOVITS_V2', 'GPT-SoVITS V2', 0, 1, '{\"type\": \"gpt_sovits_v2\", \"url\": \"http://127.0.0.1:9880/tts\", \"output_dir\": \"tmp/\", \"text_lang\": \"auto\", \"ref_audio_path\": \"caixukun.wav\", \"prompt_text\": \"\", \"prompt_lang\": \"zh\", \"top_k\": 5, \"top_p\": 1, \"temperature\": 1, \"text_split_method\": \"cut0\", \"batch_size\": 1, \"batch_threshold\": 0.75, \"split_bucket\": true, \"return_fragment\": false, \"speed_factor\": 1.0, \"streaming_mode\": false, \"seed\": -1, \"parallel_infer\": true, \"repetition_penalty\": 1.35, \"aux_ref_audio_paths\": []}', NULL, NULL, 6, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('TTS_GPT_SOVITS_V3', 'TTS', 'GPT_SOVITS_V3', 'GPT-SoVITS V3', 0, 1, '{\"type\": \"gpt_sovits_v3\", \"url\": \"http://127.0.0.1:9880\", \"output_dir\": \"tmp/\", \"text_language\": \"auto\", \"refer_wav_path\": \"caixukun.wav\", \"prompt_language\": \"zh\", \"prompt_text\": \"\", \"top_k\": 15, \"top_p\": 1.0, \"temperature\": 1.0, \"cut_punc\": \"\", \"speed\": 1.0, \"inp_refs\": [], \"sample_steps\": 32, \"if_sr\": false}', NULL, NULL, 7, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('TTS_MinimaxTTS', 'TTS', 'MinimaxTTS', 'MiniMax语音合成', 0, 1, '{\"type\": \"minimax\", \"output_dir\": \"tmp/\", \"group_id\": \"\", \"api_key\": \"你的api_key\", \"model\": \"speech-01-turbo\", \"voice_id\": \"female-shaonv\"}', NULL, NULL, 8, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('TTS_AliyunTTS', 'TTS', 'AliyunTTS', '阿里云语音合成', 0, 1, '{\"type\": \"aliyun\", \"output_dir\": \"tmp/\", \"appkey\": \"\", \"token\": \"\", \"voice\": \"xiaoyun\", \"access_key_id\": \"\", \"access_key_secret\": \"\"}', NULL, NULL, 9, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('TTS_TTS302AI', 'TTS', 'TTS302AI', '302AI语音合成', 0, 1, '{\"type\": \"doubao\", \"api_url\": \"https://api.302ai.cn/doubao/tts_hd\", \"authorization\": \"Bearer \", \"voice\": \"zh_female_wanwanxiaohe_moon_bigtts\", \"output_dir\": \"tmp/\", \"access_token\": \"\"}', NULL, NULL, 10, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('TTS_GizwitsTTS', 'TTS', 'GizwitsTTS', '机智云语音合成', 0, 1, '{\"type\": \"doubao\", \"api_url\": \"https://bytedance.gizwitsapi.com/api/v1/tts\", \"authorization\": \"Bearer \", \"voice\": \"zh_female_wanwanxiaohe_moon_bigtts\", \"output_dir\": \"tmp/\", \"access_token\": \"\"}', NULL, NULL, 11, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('TTS_ACGNTTS', 'TTS', 'ACGNTTS', 'ACGN语音合成', 0, 1, '{\"type\": \"ttson\", \"token\": \"\", \"voice_id\": 1695, \"speed_factor\": 1, \"pitch_factor\": 0, \"volume_change_dB\": 0, \"to_lang\": \"ZH\", \"url\": \"https://u95167-bd74-2aef8085.westx.seetacloud.com:8443/flashsummary/tts?token=\", \"format\": \"mp3\", \"output_dir\": \"tmp/\", \"emotion\": 1}', NULL, NULL, 12, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('TTS_OpenAITTS', 'TTS', 'OpenAITTS', 'OpenAI语音合成', 0, 1, '{\"type\": \"openai\", \"api_key\": \"你的api_key\", \"api_url\": \"https://api.openai.com/v1/audio/speech\", \"model\": \"tts-1\", \"voice\": \"onyx\", \"speed\": 1, \"output_dir\": \"tmp/\"}', NULL, NULL, 13, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('TTS_CustomTTS', 'TTS', 'CustomTTS', '自定义语音合成', 0, 1, '{\"type\": \"custom\", \"url\": \"http://127.0.0.1:9880/tts\", \"params\": {}, \"headers\": {}, \"format\": \"wav\", \"output_dir\": \"tmp/\"}', NULL, NULL, 14, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('TTS_TencentTTS', 'TTS', 'TencentTTS', '腾讯语音合成', 0, 1, '{\"type\": \"tencent\", \"appid\": \"\", \"secret_id\": \"\", \"secret_key\": \"\", \"region\": \"ap-guangzhou\", \"voice\": \"101001\", \"output_dir\": \"tmp/\"}', NULL, NULL, 3, NULL, NULL, NULL, NULL); -- Memory模型配置 -INSERT INTO `ai_model_config` VALUES ('Memory_mem0ai', 'Memory', 'mem0ai', 'Mem0AI记忆', 1, 0, '{\"type\": \"mem0ai\", \"api_key\": \"\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('Memory_nomem', 'Memory', 'nomem', '无记忆', 1, 1, '{\"type\": \"nomem\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('Memory_mem_local_short', 'Memory', 'mem_local_short', '本地短期记忆', 1, 0, '{\"type\": \"mem_local_short\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('Memory_nomem', 'Memory', 'nomem', '无记忆', 1, 1, '{\"type\": \"nomem\"}', NULL, NULL, 1, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('Memory_mem_local_short', 'Memory', 'mem_local_short', '本地短期记忆', 0, 1, '{\"type\": \"mem_local_short\"}', NULL, NULL, 2, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('Memory_mem0ai', 'Memory', 'mem0ai', 'Mem0AI记忆', 0, 1, '{\"type\": \"mem0ai\", \"api_key\": \"你的api_key\"}', NULL, NULL, 3, NULL, NULL, NULL, NULL); -- Intent模型配置 -INSERT INTO `ai_model_config` VALUES ('Intent_nointent', 'Intent', 'nointent', '无意图识别', 1, 0, '{\"type\": \"nointent\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('Intent_intent_llm', 'Intent', 'intent_llm', 'LLM意图识别', 1, 0, '{\"type\": \"intent_llm\", \"llm\": \"ChatGLMLLM\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL); -INSERT INTO `ai_model_config` VALUES ('Intent_function_call', 'Intent', 'function_call', '函数调用意图识别', 1, 1, '{\"type\": \"function_call\", \"functions\": [\"change_role\", \"get_weather\", \"get_news\", \"play_music\"]}', NULL, NULL, 0, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('Intent_nointent', 'Intent', 'nointent', '无意图识别', 1, 0, '{\"type\": \"nointent\"}', NULL, NULL, 1, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('Intent_intent_llm', 'Intent', 'intent_llm', 'LLM意图识别', 0, 1, '{\"type\": \"intent_llm\", \"llm\": \"ChatGLMLLM\"}', NULL, NULL, 2, NULL, NULL, NULL, NULL); +INSERT INTO `ai_model_config` VALUES ('Intent_function_call', 'Intent', 'function_call', '函数调用意图识别', 0, 1, '{\"type\": \"function_call\", \"functions\": [\"change_role\", \"get_weather\", \"get_news\", \"play_music\"]}', NULL, NULL, 3, NULL, NULL, NULL, NULL); diff --git a/main/manager-api/src/main/resources/db/changelog/202504092313.sql b/main/manager-api/src/main/resources/db/changelog/202504112057.sql similarity index 73% rename from main/manager-api/src/main/resources/db/changelog/202504092313.sql rename to main/manager-api/src/main/resources/db/changelog/202504112057.sql index da924bda..8b87826f 100644 --- a/main/manager-api/src/main/resources/db/changelog/202504092313.sql +++ b/main/manager-api/src/main/resources/db/changelog/202504112057.sql @@ -23,7 +23,7 @@ create table sys_params INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (100, 'server.ip', '0.0.0.0', 'string', 1, '服务器监听IP地址'); INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (101, 'server.port', '8000', 'number', 1, '服务器监听端口'); INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (102, 'server.secret', 'null', 'string', 1, '服务器密钥'); -INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (201, 'log.log_format', '{time:YYMMDD HH:mm:ss}[{version}_{selected_module}][{extra[tag]}]-{level}-{message}', 'string', 1, '控制台日志格式'); +INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (201, 'log.log_format', '{time:YYMMDD HH:mm:ss}[{version}-{selected_module}][{extra[tag]}]-{level}-{message}', 'string', 1, '控制台日志格式'); INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (202, 'log.log_format_file', '{time:YYYY-MM-DD HH:mm:ss} - {version}_{selected_module} - {name} - {level} - {extra[tag]} - {message}', 'string', 1, '文件日志格式'); INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (203, 'log.log_level', 'INFO', 'string', 1, '日志级别'); INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (204, 'log.log_dir', 'tmp', 'string', 1, '日志目录'); @@ -47,15 +47,15 @@ INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, r "channels": 1, "frame_duration": 60 } -}', 'string', 1, '小智类型'); +}', 'json', 1, '小智类型'); INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (310, 'wakeup_words', '你好小智;你好小志;小爱同学;你好小鑫;你好小新;小美同学;小龙小龙;喵喵同学;小滨小滨;小冰小冰', 'array', 1, '唤醒词列表,用于识别唤醒词'); -INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (400, 'plugin.weather.api_key', 'a861d0d5e7bf4ee1a83d9a9e4f96d4da', 'string', 1, '天气插件API密钥'); -INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (401, 'plugin.weather.default_location', '广州', 'string', 1, '天气插件默认城市'); -INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (410, 'plugin.news.default_rss_url', 'https://www.chinanews.com.cn/rss/society.xml', 'string', 1, '新闻插件默认RSS地址'); -INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (411, 'plugin.news.category_urls', '{"society":"https://www.chinanews.com.cn/rss/society.xml","world":"https://www.chinanews.com.cn/rss/world.xml","finance":"https://www.chinanews.com.cn/rss/finance.xml"}', 'string', 1, '新闻插件分类RSS地址'); -INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (421, 'plugin.home_assistant.devices', '客厅,玩具灯,switch.cuco_cn_460494544_cp1_on_p_2_1;卧室,台灯,switch.iot_cn_831898993_socn1_on_p_2_1', 'array', 1, 'Home Assistant设备列表'); -INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (422, 'plugin.home_assistant.base_url', 'http://homeassistant.local:8123', 'string', 1, 'Home Assistant服务器地址'); -INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (423, 'plugin.home_assistant.api_key', '你的home assistant api访问令牌', 'string', 1, 'Home Assistant API密钥'); -INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (430, 'plugin.music.music_dir', './music', 'string', 1, '音乐文件存放路径'); -INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (431, 'plugin.music.music_ext', 'mp3;wav;p3', 'array', 1, '音乐文件类型'); -INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (432, 'plugin.music.refresh_time', '300', 'number', 1, '音乐列表刷新间隔(秒)'); +INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (400, 'plugins.get_weather.api_key', 'a861d0d5e7bf4ee1a83d9a9e4f96d4da', 'string', 1, '天气插件API密钥'); +INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (401, 'plugins.get_weather.default_location', '广州', 'string', 1, '天气插件默认城市'); +INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (410, 'plugins.get_news.default_rss_url', 'https://www.chinanews.com.cn/rss/society.xml', 'string', 1, '新闻插件默认RSS地址'); +INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (411, 'plugins.get_news.category_urls', '{"society":"https://www.chinanews.com.cn/rss/society.xml","world":"https://www.chinanews.com.cn/rss/world.xml","finance":"https://www.chinanews.com.cn/rss/finance.xml"}', 'json', 1, '新闻插件分类RSS地址'); +INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (421, 'plugins.home_assistant.devices', '客厅,玩具灯,switch.cuco_cn_460494544_cp1_on_p_2_1;卧室,台灯,switch.iot_cn_831898993_socn1_on_p_2_1', 'array', 1, 'Home Assistant设备列表'); +INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (422, 'plugins.home_assistant.base_url', 'http://homeassistant.local:8123', 'string', 1, 'Home Assistant服务器地址'); +INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (423, 'plugins.home_assistant.api_key', '你的home assistant api访问令牌', 'string', 1, 'Home Assistant API密钥'); +INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (430, 'plugins.play_music.music_dir', './music', 'string', 1, '音乐文件存放路径'); +INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (431, 'plugins.play_music.music_ext', 'mp3;wav;p3', 'array', 1, '音乐文件类型'); +INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (432, 'plugins.play_music.refresh_time', '300', 'number', 1, '音乐列表刷新间隔(秒)'); 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 f0ac310f..8ceb6ea5 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 @@ -23,13 +23,6 @@ databaseChangeLog: - sqlFile: encoding: utf8 path: classpath:db/changelog/2025_tts_voive.sql - - changeSet: - id: 202504082210 - author: John - changes: - - sqlFile: - encoding: utf8 - path: classpath:db/changelog/202504082210.sql - changeSet: id: 202504082211 author: John @@ -37,17 +30,24 @@ databaseChangeLog: - sqlFile: encoding: utf8 path: classpath:db/changelog/202504082211.sql - - changeSet: - id: 202504092313 - author: John - changes: - - sqlFile: - encoding: utf8 - path: classpath:db/changelog/202504092313.sql - changeSet: id: 202504092335 author: John changes: - sqlFile: encoding: utf8 - path: classpath:db/changelog/202504092335.sql \ No newline at end of file + path: classpath:db/changelog/202504092335.sql + - changeSet: + id: 202504112044 + author: John + changes: + - sqlFile: + encoding: utf8 + path: classpath:db/changelog/202504112044.sql + - changeSet: + id: 202504112057 + author: John + changes: + - sqlFile: + encoding: utf8 + path: classpath:db/changelog/202504112057.sql \ No newline at end of file diff --git a/main/manager-api/src/main/resources/i18n/messages.properties b/main/manager-api/src/main/resources/i18n/messages.properties index ce6cf61b..ace07209 100644 --- a/main/manager-api/src/main/resources/i18n/messages.properties +++ b/main/manager-api/src/main/resources/i18n/messages.properties @@ -40,3 +40,4 @@ 10037=\u53C2\u6570\u503C\u5FC5\u987B\u662F\u6709\u6548\u7684\u6570\u5B57 10038=\u53C2\u6570\u503C\u5FC5\u987B\u662Ftrue\u6216false 10039=\u53C2\u6570\u503C\u5FC5\u987B\u662F\u6709\u6548\u7684JSON\u6570\u7EC4\u683C\u5F0F +10040=\u53C2\u6570\u503C\u5FC5\u987B\u662F\u6709\u6548\u7684JSON\u683C\u5F0F diff --git a/main/manager-api/src/main/resources/i18n/messages_en_US.properties b/main/manager-api/src/main/resources/i18n/messages_en_US.properties index d6c1bc0c..9c3a3c12 100644 --- a/main/manager-api/src/main/resources/i18n/messages_en_US.properties +++ b/main/manager-api/src/main/resources/i18n/messages_en_US.properties @@ -39,4 +39,5 @@ 10036=Unsupported parameter type 10037=Parameter value must be a valid number 10038=Parameter value must be true or false -10039=Parameter value must be a valid JSON array format \ No newline at end of file +10039=Parameter value must be a valid JSON array format +10040=Parameter value must be a valid JSON format \ No newline at end of file diff --git a/main/manager-api/src/main/resources/i18n/messages_zh_CN.properties b/main/manager-api/src/main/resources/i18n/messages_zh_CN.properties index 566ca0c9..22c4842a 100644 --- a/main/manager-api/src/main/resources/i18n/messages_zh_CN.properties +++ b/main/manager-api/src/main/resources/i18n/messages_zh_CN.properties @@ -39,4 +39,5 @@ 10036=\u4E0D\u652F\u6301\u7684\u53C2\u6570\u7C7B\u578B 10037=\u53C2\u6570\u503C\u5FC5\u987B\u662F\u6709\u6548\u7684\u6570\u5B57 10038=\u53C2\u6570\u503C\u5FC5\u987B\u662Ftrue\u6216false -10039=\u53C2\u6570\u503C\u5FC5\u987B\u662F\u6709\u6548\u7684JSON\u6570\u7EC4\u683C\u5F0F \ No newline at end of file +10039=\u53C2\u6570\u503C\u5FC5\u987B\u662F\u6709\u6548\u7684JSON\u6570\u7EC4\u683C\u5F0F +10040=\u53C2\u6570\u503C\u5FC5\u987B\u662F\u6709\u6548\u7684JSON\u683C\u5F0F \ No newline at end of file diff --git a/main/manager-api/src/main/resources/i18n/messages_zh_TW.properties b/main/manager-api/src/main/resources/i18n/messages_zh_TW.properties index a5d81697..663a8e98 100644 --- a/main/manager-api/src/main/resources/i18n/messages_zh_TW.properties +++ b/main/manager-api/src/main/resources/i18n/messages_zh_TW.properties @@ -39,4 +39,5 @@ 10036=\u4E0D\u652F\u63F4\u7684\u53C3\u6578\u985E\u578B 10037=\u53C3\u6578\u503C\u5FC5\u9808\u662F\u6709\u6548\u7684\u6578\u5B57 10038=\u53C3\u6578\u503C\u5FC5\u9808\u662Ftrue\u6216false -10039=\u53C3\u6578\u503C\u5FC5\u9808\u662F\u6709\u6548\u7684JSON\u6578\u7D44\u683C\u5F0F \ No newline at end of file +10039=\u53C3\u6578\u503C\u5FC5\u9808\u662F\u6709\u6548\u7684JSON\u6578\u7D44\u683C\u5F0F +10040=\u53C3\u6578\u503C\u5FC5\u9808\u662F\u6709\u6548\u7684JSON\u683C\u5F0F \ 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 38cc946e..868d38dd 100644 --- a/main/manager-web/src/apis/module/model.js +++ b/main/manager-web/src/apis/module/model.js @@ -142,40 +142,57 @@ export default { }) }).send() }, - // 启用/禁用模型状态 - updateModelStatus(id, status, callback) { - RequestService.sendRequest() - .url(`${getServiceUrl()}/models/enable/${id}/${status}`) - .method('PUT') - .success((res) => { - RequestService.clearRequestTime() - callback(res) + // 启用/禁用模型状态 + updateModelStatus(id, status, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/models/enable/${id}/${status}`) + .method('PUT') + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .fail((err) => { + console.error('更新模型状态失败:', err) + this.$message.error(err.msg || '更新模型状态失败') + RequestService.reAjaxFun(() => { + this.updateModelStatus(id, status, callback) }) - .fail((err) => { - console.error('更新模型状态失败:', err) - this.$message.error(err.msg || '更新模型状态失败') - RequestService.reAjaxFun(() => { - this.updateModelStatus(id, status, callback) - }) - }).send() - }, - // 更新模型配置 - updateModel(params, callback) { - const { modelType, provideCode, id, formData } = params; - RequestService.sendRequest() - .url(`${getServiceUrl()}/models/${modelType}/${provideCode}/${id}`) - .method('PUT') - .data(formData) - .success((res) => { - RequestService.clearRequestTime(); - callback(res); + }).send() + }, + // 更新模型配置 + updateModel(params, callback) { + const { modelType, provideCode, id, formData } = params; + RequestService.sendRequest() + .url(`${getServiceUrl()}/models/${modelType}/${provideCode}/${id}`) + .method('PUT') + .data(formData) + .success((res) => { + RequestService.clearRequestTime(); + callback(res); + }) + .fail((err) => { + console.error('更新模型失败:', err); + this.$message.error(err.msg || '更新模型失败'); + RequestService.reAjaxFun(() => { + this.updateModel(params, callback); + }); + }).send(); + }, + // 设置默认模型 + setDefaultModel(id, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/models/default/${id}`) + .method('PUT') + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .fail((err) => { + console.error('设置默认模型失败:', err) + this.$message.error(err.msg || '设置默认模型失败') + RequestService.reAjaxFun(() => { + this.setDefaultModel(id, callback) }) - .fail((err) => { - console.error('更新模型失败:', err); - this.$message.error(err.msg || '更新模型失败'); - RequestService.reAjaxFun(() => { - this.updateModel(params, callback); - }); - }).send(); - }, + }).send() + } } diff --git a/main/manager-web/src/views/ModelConfig.vue b/main/manager-web/src/views/ModelConfig.vue index 1216c45f..343cb06f 100644 --- a/main/manager-web/src/views/ModelConfig.vue +++ b/main/manager-web/src/views/ModelConfig.vue @@ -4,16 +4,6 @@

{{ modelTypeText }}

- - - - - - - - - -
+ + + @@ -130,7 +122,7 @@ - +
@@ -304,14 +296,6 @@ export default { this.currentPage = page; this.$refs.modelTable.clearSelection(); }, - handleImport() { - // TODO: 导入配置 - console.log('导入配置'); - }, - handleExport() { - // TODO: 导出配置 - console.log('导出配置'); - }, handleModelSave({ provideCode, formData }) { const modelType = this.activeTab; const id = formData.id; @@ -412,11 +396,11 @@ export default { } }); }, - // 处理启用/禁用状态变更 + // 处理启用/禁用状态变更 handleStatusChange(model) { const newStatus = model.isEnabled ? 1 : 0 const originalStatus = model.isEnabled - + model.isEnabled = !model.isEnabled Api.model.updateModelStatus( @@ -434,12 +418,24 @@ export default { } } ) + }, + handleDefaultChange(model) { + Api.model.setDefaultModel(model.id, ({ data }) => { + if (data.code === 0) { + this.$message.success('设置默认模型成功') + this.loadData() + } + }) } }, };