diff --git a/.gitignore b/.gitignore
index 675fb688..e4c2ac00 100644
--- a/.gitignore
+++ b/.gitignore
@@ -156,3 +156,4 @@ main/manager-web/node_modules
main/xiaozhi-server/models/SenseVoiceSmall/model.pt
main/xiaozhi-server/models/sherpa-onnx*
my_wakeup_words.mp3
+main/manager-api/.vscode
diff --git a/main/manager-api/README.md b/main/manager-api/README.md
index 0435956e..5eb87ae8 100644
--- a/main/manager-api/README.md
+++ b/main/manager-api/README.md
@@ -11,6 +11,7 @@ manager-api 该项目基于SpringBoot框架开发。
JDK 21
Maven 3.8+
MySQL 8.0+
+Redis 5.0+
Vue 3.x
# 创建数据库
@@ -43,6 +44,30 @@ spring:
password: 123456
```
+
+# 连接Redis
+
+如果还没有Redis,你可以通过docker安装redis
+
+```
+docker run --name xiaozhi-esp32-server-redis -d -p 6379:6379 redis
+```
+
+# 确认项目Redis连接信息
+
+在`src/main/resources/application-dev.yml`中配置Redis连接信息
+
+```
+spring:
+ data:
+ redis:
+ host: localhost
+ port: 6379
+ password:
+ database: 0
+```
+
+
# 测试启动
本项目为SpringBoot项目,启动方式为:
diff --git a/main/manager-api/pom.xml b/main/manager-api/pom.xml
index eacbdff9..441c09e6 100644
--- a/main/manager-api/pom.xml
+++ b/main/manager-api/pom.xml
@@ -27,7 +27,6 @@
2.0.2
1.6.2
33.0.0-jre
- 3.3.2
4.20.0
@@ -168,6 +167,12 @@
lombok
true
+
+
+ org.apache.logging.log4j
+ log4j-slf4j-impl
+ 2.20.0
+
diff --git a/main/manager-api/src/main/java/xiaozhi/common/convert/DateConverter.java b/main/manager-api/src/main/java/xiaozhi/common/convert/DateConverter.java
index a8439180..20c61be8 100644
--- a/main/manager-api/src/main/java/xiaozhi/common/convert/DateConverter.java
+++ b/main/manager-api/src/main/java/xiaozhi/common/convert/DateConverter.java
@@ -1,17 +1,17 @@
package xiaozhi.common.convert;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.core.convert.converter.Converter;
-import org.springframework.stereotype.Component;
-import org.springframework.util.StringUtils;
-
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+
/**
* 日期转换
* Copyright (c) 人人开源 All rights reserved.
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java
index 9f2cb10d..bb0bb52d 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java
@@ -1,13 +1,26 @@
package xiaozhi.modules.agent.controller;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
-import org.apache.shiro.authz.annotation.RequiresPermissions;
-import org.springframework.web.bind.annotation.*;
import xiaozhi.common.constant.Constant;
import xiaozhi.common.page.PageData;
import xiaozhi.common.user.UserDetail;
@@ -19,17 +32,13 @@ import xiaozhi.modules.agent.entity.AgentEntity;
import xiaozhi.modules.agent.service.AgentService;
import xiaozhi.modules.security.user.SecurityUser;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-
@Tag(name = "智能体管理")
@AllArgsConstructor
@RestController
@RequestMapping("/agent")
public class AgentController {
private final AgentService agentService;
-
+
@GetMapping("/list")
@Operation(summary = "获取用户智能体列表")
@RequiresPermissions("sys:role:normal")
@@ -38,7 +47,7 @@ public class AgentController {
List agents = agentService.getUserAgents(user.getId());
return new Result>().ok(agents);
}
-
+
@GetMapping("/all")
@Operation(summary = "智能体列表(管理员)")
@RequiresPermissions("sys:role:superAdmin")
@@ -51,7 +60,7 @@ public class AgentController {
PageData page = agentService.adminAgentList(params);
return new Result>().ok(page);
}
-
+
@GetMapping("/{id}")
@Operation(summary = "获取智能体详情")
@RequiresPermissions("sys:role:normal")
@@ -59,25 +68,25 @@ public class AgentController {
AgentEntity agent = agentService.getAgentById(id);
return new Result().ok(agent);
}
-
+
@PostMapping
@Operation(summary = "创建智能体")
@RequiresPermissions("sys:role:normal")
public Result save(@RequestBody @Valid AgentCreateDTO dto) {
AgentEntity entity = ConvertUtils.sourceToTarget(dto, AgentEntity.class);
-
+
// 设置用户ID和创建者信息
UserDetail user = SecurityUser.getUser();
entity.setUserId(user.getId());
entity.setCreator(user.getId());
entity.setCreatedAt(new Date());
-
+
// ID、智能体编码和排序会在Service层自动生成
agentService.insert(entity);
-
+
return new Result<>();
}
-
+
@PutMapping
@Operation(summary = "更新智能体")
@RequiresPermissions("sys:role:normal")
@@ -87,7 +96,7 @@ public class AgentController {
if (existingEntity == null) {
return new Result().error("智能体不存在");
}
-
+
// 只更新提供的非空字段
if (dto.getAgentName() != null) {
existingEntity.setAgentName(dto.getAgentName());
@@ -128,17 +137,17 @@ public class AgentController {
if (dto.getSort() != null) {
existingEntity.setSort(dto.getSort());
}
-
+
// 设置更新者信息
UserDetail user = SecurityUser.getUser();
existingEntity.setUpdater(user.getId());
existingEntity.setUpdatedAt(new Date());
-
+
agentService.updateById(existingEntity);
-
+
return new Result<>();
}
-
+
@DeleteMapping("/{id}")
@Operation(summary = "删除智能体")
@RequiresPermissions("sys:role:normal")
@@ -146,4 +155,4 @@ public class AgentController {
agentService.deleteById(id);
return new Result<>();
}
-}
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentTemplateController.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentTemplateController.java
new file mode 100644
index 00000000..cd88a4c8
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentTemplateController.java
@@ -0,0 +1,37 @@
+package xiaozhi.modules.agent.controller;
+
+import java.util.List;
+
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import xiaozhi.common.utils.Result;
+import xiaozhi.modules.agent.entity.AgentTemplateEntity;
+import xiaozhi.modules.agent.service.AgentTemplateService;
+
+@Slf4j
+@Tag(name = "智能体模板管理")
+@AllArgsConstructor
+@RestController
+@RequestMapping("/user/agent/template")
+public class AgentTemplateController {
+ private final AgentTemplateService agentTemplateService;
+
+ @GetMapping
+ @Operation(summary = "智能体模板模板列表")
+ @RequiresPermissions("sys:role:normal")
+ public Result> templateList() {
+ List list = agentTemplateService
+ .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/dao/AgentTemplateDao.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/dao/AgentTemplateDao.java
new file mode 100644
index 00000000..33871a63
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/dao/AgentTemplateDao.java
@@ -0,0 +1,20 @@
+package xiaozhi.modules.agent.dao;
+
+import org.apache.ibatis.annotations.Mapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+import xiaozhi.modules.agent.entity.AgentTemplateEntity;
+
+/**
+* @author chenerlei
+* @description 针对表【ai_agent_template(智能体配置模板表)】的数据库操作Mapper
+* @createDate 2025-03-22 11:48:18
+*/
+@Mapper
+public interface AgentTemplateDao extends BaseMapper {
+
+}
+
+
+
+
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/entity/AgentTemplateEntity.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/entity/AgentTemplateEntity.java
new file mode 100644
index 00000000..ca021242
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/entity/AgentTemplateEntity.java
@@ -0,0 +1,115 @@
+package xiaozhi.modules.agent.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import java.util.Date;
+import lombok.Data;
+
+/**
+ * 智能体配置模板表
+ * @TableName ai_agent_template
+ */
+@TableName(value ="ai_agent_template")
+@Data
+public class AgentTemplateEntity implements Serializable {
+ /**
+ * 智能体唯一标识
+ */
+ @TableId
+ private String id;
+
+ /**
+ * 智能体编码
+ */
+ private String agentCode;
+
+ /**
+ * 智能体名称
+ */
+ private String agentName;
+
+ /**
+ * 语音识别模型标识
+ */
+ private String asrModelId;
+
+ /**
+ * 语音活动检测标识
+ */
+ private String vadModelId;
+
+ /**
+ * 大语言模型标识
+ */
+ private String llmModelId;
+
+ /**
+ * 语音合成模型标识
+ */
+ private String ttsModelId;
+
+ /**
+ * 音色标识
+ */
+ private String ttsVoiceId;
+
+ /**
+ * 记忆模型标识
+ */
+ private String memoryModelId;
+
+ /**
+ * 意图模型标识
+ */
+ private String intentModelId;
+
+ /**
+ * 角色设定参数
+ */
+ private String systemPrompt;
+
+ /**
+ * 语言编码
+ */
+ private String langCode;
+
+ /**
+ * 交互语种
+ */
+ private String language;
+
+ /**
+ * 排序权重
+ */
+ private Integer sort;
+
+ /**
+ * 是否默认模板:1:是,0:不是
+ */
+ private Integer isDefault;
+
+ /**
+ * 创建者 ID
+ */
+ private Long creator;
+
+ /**
+ * 创建时间
+ */
+ private Date createdAt;
+
+ /**
+ * 更新者 ID
+ */
+ private Long updater;
+
+ /**
+ * 更新时间
+ */
+ private Date updatedAt;
+
+ @TableField(exist = false)
+ private static final long serialVersionUID = 1L;
+}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentTemplateService.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentTemplateService.java
new file mode 100644
index 00000000..01bb50d5
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentTemplateService.java
@@ -0,0 +1,14 @@
+package xiaozhi.modules.agent.service;
+
+import xiaozhi.modules.agent.entity.AgentTemplateEntity;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * @author chenerlei
+ * @description 针对表【ai_agent_template(智能体配置模板表)】的数据库操作Service
+ * @createDate 2025-03-22 11:48:18
+ */
+public interface AgentTemplateService extends IService {
+
+}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java
index b41310ab..8e73c003 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java
@@ -1,64 +1,65 @@
-package xiaozhi.modules.agent.service.impl;
-
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import org.springframework.stereotype.Service;
-import xiaozhi.common.page.PageData;
-import xiaozhi.common.service.impl.BaseServiceImpl;
-import xiaozhi.modules.agent.dao.AgentDao;
-import xiaozhi.modules.agent.entity.AgentEntity;
-import xiaozhi.modules.agent.service.AgentService;
-
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-
-@Service
-public class AgentServiceImpl extends BaseServiceImpl implements AgentService {
- private final AgentDao agentDao;
-
- public AgentServiceImpl(AgentDao agentDao) {
- this.agentDao = agentDao;
- }
-
- @Override
- public List getUserAgents(Long userId) {
- QueryWrapper wrapper = new QueryWrapper<>();
- wrapper.eq("user_id", userId);
- return agentDao.selectList(wrapper);
- }
-
- @Override
- public PageData adminAgentList(Map params) {
- IPage page = agentDao.selectPage(
- getPage(params, "sort", true),
- new QueryWrapper<>()
- );
- return new PageData<>(page.getRecords(), page.getTotal());
- }
-
- @Override
- public AgentEntity getAgentById(String id) {
- return agentDao.selectById(id);
- }
-
- @Override
- public boolean insert(AgentEntity entity) {
- // 如果ID为空,自动生成一个UUID作为ID
- if (entity.getId() == null || entity.getId().trim().isEmpty()) {
- entity.setId(UUID.randomUUID().toString().replace("-", ""));
- }
-
- // 如果智能体编码为空,自动生成一个带前缀的编码
- if (entity.getAgentCode() == null || entity.getAgentCode().trim().isEmpty()) {
- entity.setAgentCode("AGT_" + System.currentTimeMillis());
- }
-
- // 如果排序字段为空,设置默认值0
- if (entity.getSort() == null) {
- entity.setSort(0);
- }
-
- return super.insert(entity);
- }
-}
\ No newline at end of file
+package xiaozhi.modules.agent.service.impl;
+
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.springframework.stereotype.Service;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+import xiaozhi.common.page.PageData;
+import xiaozhi.common.service.impl.BaseServiceImpl;
+import xiaozhi.modules.agent.dao.AgentDao;
+import xiaozhi.modules.agent.entity.AgentEntity;
+import xiaozhi.modules.agent.service.AgentService;
+
+@Service
+public class AgentServiceImpl extends BaseServiceImpl implements AgentService {
+ private final AgentDao agentDao;
+
+ public AgentServiceImpl(AgentDao agentDao) {
+ this.agentDao = agentDao;
+ }
+
+ @Override
+ public List getUserAgents(Long userId) {
+ QueryWrapper wrapper = new QueryWrapper<>();
+ wrapper.eq("user_id", userId);
+ return agentDao.selectList(wrapper);
+ }
+
+ @Override
+ public PageData adminAgentList(Map params) {
+ IPage page = agentDao.selectPage(
+ getPage(params, "sort", true),
+ new QueryWrapper<>());
+ return new PageData<>(page.getRecords(), page.getTotal());
+ }
+
+ @Override
+ public AgentEntity getAgentById(String id) {
+ return agentDao.selectById(id);
+ }
+
+ @Override
+ public boolean insert(AgentEntity entity) {
+ // 如果ID为空,自动生成一个UUID作为ID
+ if (entity.getId() == null || entity.getId().trim().isEmpty()) {
+ entity.setId(UUID.randomUUID().toString().replace("-", ""));
+ }
+
+ // 如果智能体编码为空,自动生成一个带前缀的编码
+ if (entity.getAgentCode() == null || entity.getAgentCode().trim().isEmpty()) {
+ entity.setAgentCode("AGT_" + System.currentTimeMillis());
+ }
+
+ // 如果排序字段为空,设置默认值0
+ if (entity.getSort() == null) {
+ entity.setSort(0);
+ }
+
+ return super.insert(entity);
+ }
+}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentTemplateServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentTemplateServiceImpl.java
new file mode 100644
index 00000000..02dafdec
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentTemplateServiceImpl.java
@@ -0,0 +1,20 @@
+package xiaozhi.modules.agent.service.impl;
+
+import org.springframework.stereotype.Service;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+import xiaozhi.modules.agent.dao.AgentTemplateDao;
+import xiaozhi.modules.agent.entity.AgentTemplateEntity;
+import xiaozhi.modules.agent.service.AgentTemplateService;
+
+/**
+ * @author chenerlei
+ * @description 针对表【ai_agent_template(智能体配置模板表)】的数据库操作Service实现
+ * @createDate 2025-03-22 11:48:18
+ */
+@Service
+public class AgentTemplateServiceImpl extends ServiceImpl
+ implements AgentTemplateService {
+
+}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/vo/AgentTemplateVO.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/vo/AgentTemplateVO.java
new file mode 100644
index 00000000..20c0e144
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/vo/AgentTemplateVO.java
@@ -0,0 +1,13 @@
+package xiaozhi.modules.agent.vo;
+
+import lombok.Data;
+import xiaozhi.modules.agent.entity.AgentTemplateEntity;
+
+@Data
+public class AgentTemplateVO extends AgentTemplateEntity {
+ // 角色音色
+ private String ttsModelName;
+
+ // 角色模型
+ private String llmModelName;
+}
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 31b28ebb..4feb1024 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java
@@ -1,6 +1,7 @@
package xiaozhi.modules.device.service;
import xiaozhi.common.page.PageData;
+import xiaozhi.common.service.BaseService;
import xiaozhi.modules.device.dto.DeviceHeaderDTO;
import xiaozhi.modules.device.dto.DeviceReportReqDTO;
import xiaozhi.modules.device.dto.DeviceReportRespDTO;
@@ -19,11 +20,11 @@ public interface DeviceService {
DeviceReportRespDTO checkDeviceActive(String macAddress, String deviceId, String clientId, DeviceReportReqDTO deviceReport);
DeviceEntity bindDevice(Long userId, DeviceHeaderDTO deviceHeader);
-
+
List getUserDevices(Long userId);
-
+
void unbindDevice(Long userId, Long deviceId);
-
+
PageData adminDeviceList(Map params);
Boolean deviceActivation(String activationCode);
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/vo/DeviceOtaVO.java b/main/manager-api/src/main/java/xiaozhi/modules/device/vo/DeviceOtaVO.java
new file mode 100644
index 00000000..c5af75af
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/modules/device/vo/DeviceOtaVO.java
@@ -0,0 +1,55 @@
+package xiaozhi.modules.device.vo;
+
+import lombok.Data;
+
+@Data
+public class DeviceOtaVO {
+ private Activation activation;
+ private Mqtt mqtt;
+ private ServerTime server_time;
+ private Firmware firmware;
+ private String error;
+
+ @Data
+ public static class Activation {
+ private String code;
+ private String message;
+
+ public Activation() {
+ }
+ public Activation(String code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+ }
+
+ @Data
+ public class Mqtt {
+
+ }
+
+ @Data
+ public static class ServerTime {
+ private Long timestamp;
+ private Integer timezone_offset;
+
+ public ServerTime() {
+ }
+ public ServerTime(Long timestamp, Integer timezone_offset) {
+ this.timestamp = timestamp;
+ this.timezone_offset = timezone_offset;
+ }
+ }
+
+ @Data
+ public static class Firmware {
+ private String version;
+ private String url;
+ public Firmware() {
+ }
+ public Firmware(String version, String url) {
+ this.version = version;
+ this.url = url;
+ }
+ }
+}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/security/config/ShiroConfig.java b/main/manager-api/src/main/java/xiaozhi/modules/security/config/ShiroConfig.java
index 1013c4b8..f5c00fe9 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
@@ -74,6 +74,7 @@ public class ShiroConfig {
filterMap.put("/user/captcha", "anon");
filterMap.put("/user/login", "anon");
filterMap.put("/user/register", "anon");
+ filterMap.put("/ota/**", "anon");
filterMap.put("/**", "oauth2");
shiroFilter.setFilterChainDefinitionMap(filterMap);
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/security/controller/LoginController.java b/main/manager-api/src/main/java/xiaozhi/modules/security/controller/LoginController.java
index 6ab9d1b9..657217ae 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/security/controller/LoginController.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/security/controller/LoginController.java
@@ -1,12 +1,18 @@
package xiaozhi.modules.security.controller;
+import java.io.IOException;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.web.bind.annotation.*;
import xiaozhi.common.exception.ErrorCode;
import xiaozhi.common.exception.RenException;
import xiaozhi.common.page.TokenDTO;
@@ -22,8 +28,6 @@ import xiaozhi.modules.sys.dto.PasswordDTO;
import xiaozhi.modules.sys.dto.SysUserDTO;
import xiaozhi.modules.sys.service.SysUserService;
-import java.io.IOException;
-
/**
* 登录控制层
*/
@@ -36,14 +40,13 @@ public class LoginController {
private final SysUserTokenService sysUserTokenService;
private final CaptchaService captchaService;
-
@GetMapping("/captcha")
@Operation(summary = "验证码")
public void captcha(HttpServletResponse response, String uuid) throws IOException {
- //uuid不能为空
+ // uuid不能为空
AssertUtils.isBlank(uuid, ErrorCode.IDENTIFIER_NOT_NULL);
- //生成验证码
+ // 生成验证码
captchaService.create(response, uuid);
}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/security/oauth2/Oauth2Filter.java b/main/manager-api/src/main/java/xiaozhi/modules/security/oauth2/Oauth2Filter.java
index 8f110941..1ca288fd 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/security/oauth2/Oauth2Filter.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/security/oauth2/Oauth2Filter.java
@@ -55,11 +55,6 @@ public class Oauth2Filter extends AuthenticatingFilter {
//获取请求token,如果token不存在,直接返回401
String token = getRequestToken((HttpServletRequest) request);
- // TODO 调试接口,临时取消登录限制,需要 token 参数的除外
-// if (true) {
-// return true;
-// }
-
if (StringUtils.isBlank(token)) {
logger.warn("onAccessDenied:token is empty");
diff --git a/main/manager-api/src/main/resources/application-dev.yml b/main/manager-api/src/main/resources/application-dev.yml
index a8fdf21f..753cca9a 100644
--- a/main/manager-api/src/main/resources/application-dev.yml
+++ b/main/manager-api/src/main/resources/application-dev.yml
@@ -15,7 +15,7 @@ spring:
druid:
#MySQL
driver-class-name: com.mysql.cj.jdbc.Driver
- url: jdbc:mysql://localhost:3306/xiaozhi_esp32_server?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
+ url: jdbc:mysql://127.0.0.1:3306/xiaozhi_esp32_server?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
username: root
password: 123456
initial-size: 10
@@ -41,4 +41,17 @@ spring:
merge-sql: false
wall:
config:
- multi-statement-allow: true
\ No newline at end of file
+ multi-statement-allow: true
+ data:
+ redis:
+ host: 127.0.0.1 # Redis服务器地址
+ port: 6379 # Redis服务器连接端口
+ password: # Redis服务器连接密码(默认为空)
+ database: 0 # Redis数据库索引(默认为0)
+ timeout: 10000ms # 连接超时时间(毫秒)
+ lettuce:
+ pool:
+ max-active: 8 # 连接池最大连接数(使用负值表示没有限制)
+ max-idle: 8 # 连接池中的最大空闲连接
+ min-idle: 0 # 连接池中的最小空闲连接
+ shutdown-timeout: 100ms # 客户端优雅关闭的等待时间
\ No newline at end of file
diff --git a/main/manager-api/src/main/resources/application.yml b/main/manager-api/src/main/resources/application.yml
index 282362d0..9c38b392 100644
--- a/main/manager-api/src/main/resources/application.yml
+++ b/main/manager-api/src/main/resources/application.yml
@@ -24,21 +24,9 @@ spring:
max-file-size: 100MB
max-request-size: 100MB
enabled: true
- data:
- redis:
- database: 0
- host: 127.0.0.1
- port: 6379
- password: # 密码(默认为空)
- timeout: 6000ms # 连接超时时长(毫秒)
- lettuce:
- pool:
- max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
- max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
- max-idle: 10 # 连接池中的最大空闲连接
- min-idle: 5 # 连接池中的最小空闲连接
main:
allow-bean-definition-overriding: true
+
knife4j:
enable: true
basic:
@@ -50,7 +38,7 @@ knife4j:
renren:
redis:
- open: false
+ open: true
xss:
enabled: true
exclude-urls:
@@ -59,7 +47,7 @@ renren:
mybatis-plus:
mapper-locations: classpath*:/mapper/**/*.xml
#实体扫描,多个package用逗号或者分号分隔
- typeAliasesPackage: xiaozhi.modules.*.entity
+ typeAliasesPackage: xiaozhi.modules.*.entity;xiaozhi.modules.*.domain
global-config:
#数据库相关配置
db-config:
diff --git a/main/manager-api/src/main/resources/db/changelog/202503241020.sql b/main/manager-api/src/main/resources/db/changelog/202503241020.sql
new file mode 100644
index 00000000..95e75a7b
--- /dev/null
+++ b/main/manager-api/src/main/resources/db/changelog/202503241020.sql
@@ -0,0 +1,32 @@
+-- 修改字段名
+ALTER TABLE `ai_agent` RENAME COLUMN `mem_model_id` TO `memory_model_id`;
+ALTER TABLE `ai_agent_template` RENAME COLUMN `mem_model_id` TO `memory_model_id`;
+-- 添加字段
+ALTER TABLE `ai_agent_template` ADD COLUMN `is_default` tinyint(1) NULL DEFAULT 0 COMMENT '是否默认模板:1:是,0:不是' AFTER `sort`;
+
+-- 初始化智能体模板数据
+INSERT INTO `ai_agent_template` VALUES ('9406648b5cc5fde1b8aa335b6f8b4f76', '小智', '湾湾小何', '45f8b0d6dd3d4bfa8a28e6e0f5912d45', '23e7c9d090ea4d1e9b25f4c8d732a3a1', 'e9f2d891afbe4632b13a47c7a8c6e03d', 'd50b06e9b8104d0d9c0f7316d258abcb', 'fcac83266edadd5a3125f06cfee1906b', 'e2274b90e89ddda85207f55484d8b528', 'c4e12f874a3f4aa99f5b2c18e15d407b', '你是一个叫{{assistant_name}}的台湾女孩,说话机车,声音好听,习惯简短表达,爱用网络梗。\n请注意,要像一个人一样说话,请不要回复表情符号、代码、和xml标签。\n现在我正在和你进行语音聊天,我们开始吧。\n如果用户希望结束对话,请在最后说“拜拜”或“再见”。', 'zh', '中文', 1, 1, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_agent_template` VALUES ('0ca32eb728c949e58b1000b2e401f90c', '小智', '通用男声', '45f8b0d6dd3d4bfa8a28e6e0f5912d45', '23e7c9d090ea4d1e9b25f4c8d732a3a1', 'e9f2d891afbe4632b13a47c7a8c6e03d', '896db62c9dd74976ab0e8c14bf924d9d', '1f2e3d4c5b6a7f8e9d0c1b2a3f4e5bx2', 'e2274b90e89ddda85207f55484d8b528', 'c4e12f874a3f4aa99f5b2c18e15d407b', '你是一个叫{{assistant_name}}的男生,说话机车,声音好听,习惯简短表达,爱用网络梗。\n请注意,要像一个人一样说话,请不要回复表情符号、代码、和xml标签。\n现在我正在和你进行语音聊天,我们开始吧。\n如果用户希望结束对话,请在最后说“拜拜”或“再见”。', 'zh', '中文', 2, 0, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_agent_template` VALUES ('6c7d8e9f0a1b2c3d4e5f6a7b8c9d0s24', '小智', '通用女声', '45f8b0d6dd3d4bfa8a28e6e0f5912d45', '23e7c9d090ea4d1e9b25f4c8d732a3a1', 'e9f2d891afbe4632b13a47c7a8c6e03d', '896db62c9dd74976ab0e8c14bf924d9d', '9e8f7a6b5c4d3e2f1a0b9c8d7e6f5ad3', 'e2274b90e89ddda85207f55484d8b528', 'c4e12f874a3f4aa99f5b2c18e15d407b', '你是一个叫{{assistant_name}}的女生,说话机车,声音好听,习惯简短表达,爱用网络梗。\n请注意,要像一个人一样说话,请不要回复表情符号、代码、和xml标签。\n现在我正在和你进行语音聊天,我们开始吧。\n如果用户希望结束对话,请在最后说“拜拜”或“再见”。', 'zh', '中文', 3, 0, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_agent_template` VALUES ('e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b1', '小智', '阳光男生', '45f8b0d6dd3d4bfa8a28e6e0f5912d45', '23e7c9d090ea4d1e9b25f4c8d732a3a1', 'e9f2d891afbe4632b13a47c7a8c6e03d', '896db62c9dd74976ab0e8c14bf924d9d', '2b3c4d5e6f7a8b9c0d1e2f3a4b5c62a2', 'e2274b90e89ddda85207f55484d8b528', 'c4e12f874a3f4aa99f5b2c18e15d407b', '你是一个叫{{assistant_name}}的男生,说话机车,声音好听,习惯简短表达,爱用网络梗。\n请注意,要像一个人一样说话,请不要回复表情符号、代码、和xml标签。\n现在我正在和你进行语音聊天,我们开始吧。\n如果用户希望结束对话,请在最后说“拜拜”或“再见”。', 'zh', '中文', 4, 0, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_agent_template` VALUES ('a45b6c7d8e9f0a1b2c3d4e5f6a7b8c92', '小智', '奶气萌娃', '45f8b0d6dd3d4bfa8a28e6e0f5912d45', '23e7c9d090ea4d1e9b25f4c8d732a3a1', 'e9f2d891afbe4632b13a47c7a8c6e03d', '896db62c9dd74976ab0e8c14bf924d9d', 'f7a38c03d5644e22b6d84f8923a74c51', 'e2274b90e89ddda85207f55484d8b528', 'c4e12f874a3f4aa99f5b2c18e15d407b', '你是一个叫{{assistant_name}}的萌娃,声音可爱,习惯简短表达,爱用网络梗。\n请注意,要像一个人一样说话,请不要回复表情符号、代码、和xml标签。\n现在我正在和你进行语音聊天,我们开始吧。\n如果用户希望结束对话,请在最后说“拜拜”或“再见”。', 'zh', '中文', 5, 0, NULL, NULL, NULL, NULL);
+
+-- 初始化模型配置数据
+INSERT INTO `ai_model_config` VALUES ('23e7c9d090ea4d1e9b25f4c8d732a3a1', 'VAD', 'SileroVAD', 'SileroVAD', 1, 1, '{\"SileroVAD\": {\"model_dir\": \"models/snakers4_silero-vad\", \"threshold\": 0.5, \"min_silence_duration_ms\": 700}}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('45f8b0d6dd3d4bfa8a28e6e0f5912d45', 'ASR', 'FunASR', 'FunASR', 1, 1, '{\"FunASR\": {\"type\": \"fun_local\", \"model_dir\": \"models/SenseVoiceSmall\", \"output_dir\": \"tmp/\"}}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('e2274b90e89ddda85207f55484d8b528', 'Memory', 'nomem', 'nomem', 1, 1, '{\"mem0ai\": {\"type\": \"nomem\"}}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('3930ac3448faf621f0a120bc829dfdfa', 'Memory', 'mem_local_short', 'mem_local_short', 1, 1, '{\"mem_local_short\": {\"type\": \"mem_local_short\"}}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('a07f3d25f52340b2b2a1e8d264079e1a', 'Memory', 'mem0ai', 'mem0ai', 1, 1, '{\"mem0ai\": {\"type\": \"mem0ai\", \"api_key\": \"你的mem0ai api key\"}}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('7a1c0a8e6d0e4035b982a4c07c3a5f76', 'LLM', 'AliLLM', 'AliLLM', 1, 1, '{\"AliLLM\": {\"type\": \"openai\", \"top_k\": 50, \"top_p\": 1, \"api_key\": \"你的ali api key\", \"base_url\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\", \"max_tokens\": 500, \"model_name\": \"qwen-turbo\", \"temperature\": 0.7, \"frequency_penalty\": 0}}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('e9f2d891afbe4632b13a47c7a8c6e03d', 'LLM', 'ChatGLMLLM', 'ChatGLMLLM', 1, 1, '{\"ChatGLMLLM\": {\"url\": \"https://open.bigmodel.cn/api/paas/v4/\", \"type\": \"openai\", \"api_key\": \"0415dad4014847babc3e3f03024c50a3.qH7FgTy5Yawc85fl\", \"model_name\": \"glm-4-flash\"}}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('d50b06e9b8104d0d9c0f7316d258abcb', 'TTS', 'EdgeTTS', 'EdgeTTS', 1, 1, '{\"EdgeTTS\": {\"type\": \"edge\", \"voice\": \"zh-CN-XiaoxiaoNeural\", \"output_dir\": \"tmp/\"}}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('896db62c9dd74976ab0e8c14bf924d9d', 'TTS', 'DoubaoTTS', 'DoubaoTTS', 1, 1, '{\"DoubaoTTS\": {\"type\": \"doubao\", \"appid\": \"你的火山引擎语音合成服务appid\", \"voice\": \"BV034_streaming\", \"api_url\": \"https://openspeech.bytedance.com/api/v1/tts\", \"cluster\": \"volcano_tts\", \"output_dir\": \"tmp/\", \"access_token\": \"你的火山引擎语音合成服务access_token\", \"authorization\": \"Bearer;\"}}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('c4e12f874a3f4aa99f5b2c18e15d407b', 'Intent', 'function_call', 'function_call', 1, 1, '{\"function_call\": {\"type\": \"nointent\", \"functions\": [\"change_role\", \"get_weather\", \"get_news\", \"play_music\"]}}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
+
+-- 初始化音色数据
+INSERT INTO `ai_tts_voice` VALUES ('fcac83266edadd5a3125f06cfee1906b', 'd50b06e9b8104d0d9c0f7316d258abcb', '湾湾小何', 'zh-CN-XiaoxiaoNeural', '中文', 'https://lf3-static.bytednsdoc.com/obj/eden-cn/lm_hz_ihsph/ljhwZthlaukjlkulzlp/portal/bigtts/湾湾小何.mp3', NULL, 1, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_tts_voice` VALUES ('1f2e3d4c5b6a7f8e9d0c1b2a3f4e5bx2', '896db62c9dd74976ab0e8c14bf924d9d', '通用男声', 'BV002_streaming', '中文', 'https://lf3-speech.bytetos.com/obj/speech-tts-external/portal/Portal_Demo_BV002.mp3', NULL, 2, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_tts_voice` VALUES ('9e8f7a6b5c4d3e2f1a0b9c8d7e6f5ad3', '896db62c9dd74976ab0e8c14bf924d9d', '通用女声', 'BV001_streaming', '中文', 'https://lf3-speech.bytetos.com/obj/speech-tts-external/portal/Portal_Demo_BV001.mp3', NULL, 3, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_tts_voice` VALUES ('2b3c4d5e6f7a8b9c0d1e2f3a4b5c62a2', '896db62c9dd74976ab0e8c14bf924d9d', '阳光男生', 'BV056_streaming', '中文', 'https://lf3-speech.bytetos.com/obj/speech-tts-external/portal/Portal_Demo_BV056.mp3', NULL, 4, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_tts_voice` VALUES ('f7a38c03d5644e22b6d84f8923a74c51', '896db62c9dd74976ab0e8c14bf924d9d', '奶气萌娃', 'BV051_streaming', '中文', 'https://lf3-speech.bytetos.com/obj/speech-tts-external/portal/Portal_Demo_BV051.mp3', NULL, 5, NULL, NULL, NULL, NULL);
+
diff --git a/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml b/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml
index 89ed7ff5..41d9f61a 100755
--- a/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml
+++ b/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml
@@ -15,4 +15,11 @@ databaseChangeLog:
changes:
- sqlFile:
encoding: utf8
- path: classpath:db/changelog/202503141346.sql
\ No newline at end of file
+ path: classpath:db/changelog/202503141346.sql
+ - changeSet:
+ id: 202503241020
+ author: dreamchen
+ changes:
+ - sqlFile:
+ encoding: utf8
+ path: classpath:db/changelog/202503241020.sql
\ No newline at end of file
diff --git a/main/manager-api/src/main/resources/mapper/agent/AgentTemplateMapper.xml b/main/manager-api/src/main/resources/mapper/agent/AgentTemplateMapper.xml
new file mode 100644
index 00000000..bc372f8a
--- /dev/null
+++ b/main/manager-api/src/main/resources/mapper/agent/AgentTemplateMapper.xml
@@ -0,0 +1,6 @@
+
+
+
+