mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-22 07:03:53 +08:00
Merge branch 'test-manager-api' into main
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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项目,启动方式为:
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
<shiro.version>2.0.2</shiro.version>
|
||||
<captcha.version>1.6.2</captcha.version>
|
||||
<guava.version>33.0.0-jre</guava.version>
|
||||
<easyexcel.version>3.3.2</easyexcel.version>
|
||||
<liquibase-core.version>4.20.0</liquibase-core.version>
|
||||
</properties>
|
||||
|
||||
@@ -168,6 +167,12 @@
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- SLF4J + Log4j2 实现(可选) -->
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j-impl</artifactId>
|
||||
<version>2.20.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<!-- 阿里云maven仓库 -->
|
||||
|
||||
@@ -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.
|
||||
|
||||
+29
-20
@@ -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<AgentEntity> agents = agentService.getUserAgents(user.getId());
|
||||
return new Result<List<AgentEntity>>().ok(agents);
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/all")
|
||||
@Operation(summary = "智能体列表(管理员)")
|
||||
@RequiresPermissions("sys:role:superAdmin")
|
||||
@@ -51,7 +60,7 @@ public class AgentController {
|
||||
PageData<AgentEntity> page = agentService.adminAgentList(params);
|
||||
return new Result<PageData<AgentEntity>>().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<AgentEntity>().ok(agent);
|
||||
}
|
||||
|
||||
|
||||
@PostMapping
|
||||
@Operation(summary = "创建智能体")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
public Result<Void> 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<Void>().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<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -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<List<AgentTemplateEntity>> templateList() {
|
||||
List<AgentTemplateEntity> list = agentTemplateService
|
||||
.list(new QueryWrapper<AgentTemplateEntity>().orderByAsc("sort"));
|
||||
return new Result<List<AgentTemplateEntity>>().ok(list);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<AgentTemplateEntity> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
+14
@@ -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<AgentTemplateEntity> {
|
||||
|
||||
}
|
||||
+65
-64
@@ -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<AgentDao, AgentEntity> implements AgentService {
|
||||
private final AgentDao agentDao;
|
||||
|
||||
public AgentServiceImpl(AgentDao agentDao) {
|
||||
this.agentDao = agentDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AgentEntity> getUserAgents(Long userId) {
|
||||
QueryWrapper<AgentEntity> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq("user_id", userId);
|
||||
return agentDao.selectList(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageData<AgentEntity> adminAgentList(Map<String, Object> params) {
|
||||
IPage<AgentEntity> page = agentDao.selectPage(
|
||||
getPage(params, "sort", true),
|
||||
new QueryWrapper<>()
|
||||
);
|
||||
return new PageData<>(page.getRecords(), page.getTotal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AgentEntity getAgentById(String id) {
|
||||
return agentDao.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(AgentEntity entity) {
|
||||
// 如果ID为空,自动生成一个UUID作为ID
|
||||
if (entity.getId() == null || entity.getId().trim().isEmpty()) {
|
||||
entity.setId(UUID.randomUUID().toString().replace("-", ""));
|
||||
}
|
||||
|
||||
// 如果智能体编码为空,自动生成一个带前缀的编码
|
||||
if (entity.getAgentCode() == null || entity.getAgentCode().trim().isEmpty()) {
|
||||
entity.setAgentCode("AGT_" + System.currentTimeMillis());
|
||||
}
|
||||
|
||||
// 如果排序字段为空,设置默认值0
|
||||
if (entity.getSort() == null) {
|
||||
entity.setSort(0);
|
||||
}
|
||||
|
||||
return super.insert(entity);
|
||||
}
|
||||
}
|
||||
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<AgentDao, AgentEntity> implements AgentService {
|
||||
private final AgentDao agentDao;
|
||||
|
||||
public AgentServiceImpl(AgentDao agentDao) {
|
||||
this.agentDao = agentDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AgentEntity> getUserAgents(Long userId) {
|
||||
QueryWrapper<AgentEntity> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq("user_id", userId);
|
||||
return agentDao.selectList(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageData<AgentEntity> adminAgentList(Map<String, Object> params) {
|
||||
IPage<AgentEntity> page = agentDao.selectPage(
|
||||
getPage(params, "sort", true),
|
||||
new QueryWrapper<>());
|
||||
return new PageData<>(page.getRecords(), page.getTotal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AgentEntity getAgentById(String id) {
|
||||
return agentDao.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(AgentEntity entity) {
|
||||
// 如果ID为空,自动生成一个UUID作为ID
|
||||
if (entity.getId() == null || entity.getId().trim().isEmpty()) {
|
||||
entity.setId(UUID.randomUUID().toString().replace("-", ""));
|
||||
}
|
||||
|
||||
// 如果智能体编码为空,自动生成一个带前缀的编码
|
||||
if (entity.getAgentCode() == null || entity.getAgentCode().trim().isEmpty()) {
|
||||
entity.setAgentCode("AGT_" + System.currentTimeMillis());
|
||||
}
|
||||
|
||||
// 如果排序字段为空,设置默认值0
|
||||
if (entity.getSort() == null) {
|
||||
entity.setSort(0);
|
||||
}
|
||||
|
||||
return super.insert(entity);
|
||||
}
|
||||
}
|
||||
+20
@@ -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<AgentTemplateDao, AgentTemplateEntity>
|
||||
implements AgentTemplateService {
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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<DeviceEntity> getUserDevices(Long userId);
|
||||
|
||||
|
||||
void unbindDevice(Long userId, Long deviceId);
|
||||
|
||||
|
||||
PageData<DeviceEntity> adminDeviceList(Map<String, Object> params);
|
||||
|
||||
Boolean deviceActivation(String activationCode);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
+11
-8
@@ -1,12 +1,18 @@
|
||||
package xiaozhi.modules.security.controller;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import xiaozhi.common.exception.ErrorCode;
|
||||
import xiaozhi.common.exception.RenException;
|
||||
import xiaozhi.common.page.TokenDTO;
|
||||
@@ -22,8 +28,6 @@ import xiaozhi.modules.sys.dto.PasswordDTO;
|
||||
import xiaozhi.modules.sys.dto.SysUserDTO;
|
||||
import xiaozhi.modules.sys.service.SysUserService;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 登录控制层
|
||||
*/
|
||||
@@ -36,14 +40,13 @@ public class LoginController {
|
||||
private final SysUserTokenService sysUserTokenService;
|
||||
private final CaptchaService captchaService;
|
||||
|
||||
|
||||
@GetMapping("/captcha")
|
||||
@Operation(summary = "验证码")
|
||||
public void captcha(HttpServletResponse response, String uuid) throws IOException {
|
||||
//uuid不能为空
|
||||
// uuid不能为空
|
||||
AssertUtils.isBlank(uuid, ErrorCode.IDENTIFIER_NOT_NULL);
|
||||
|
||||
//生成验证码
|
||||
// 生成验证码
|
||||
captchaService.create(response, uuid);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,11 +55,6 @@ public class Oauth2Filter extends AuthenticatingFilter {
|
||||
//获取请求token,如果token不存在,直接返回401
|
||||
String token = getRequestToken((HttpServletRequest) request);
|
||||
|
||||
// TODO 调试接口,临时取消登录限制,需要 token 参数的除外
|
||||
// if (true) {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
if (StringUtils.isBlank(token)) {
|
||||
logger.warn("onAccessDenied:token is empty");
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ spring:
|
||||
druid:
|
||||
#MySQL
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://localhost:3306/xiaozhi_esp32_server?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
|
||||
url: jdbc:mysql://127.0.0.1:3306/xiaozhi_esp32_server?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
|
||||
username: root
|
||||
password: 123456
|
||||
initial-size: 10
|
||||
@@ -41,4 +41,17 @@ spring:
|
||||
merge-sql: false
|
||||
wall:
|
||||
config:
|
||||
multi-statement-allow: true
|
||||
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 # 客户端优雅关闭的等待时间
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -15,4 +15,11 @@ databaseChangeLog:
|
||||
changes:
|
||||
- sqlFile:
|
||||
encoding: utf8
|
||||
path: classpath:db/changelog/202503141346.sql
|
||||
path: classpath:db/changelog/202503141346.sql
|
||||
- changeSet:
|
||||
id: 202503241020
|
||||
author: dreamchen
|
||||
changes:
|
||||
- sqlFile:
|
||||
encoding: utf8
|
||||
path: classpath:db/changelog/202503241020.sql
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="xiaozhi.modules.agent.dao.AgentTemplateDao">
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user