mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-27 17:43:55 +08:00
feature:实现角色配置
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 279 KiB After Width: | Height: | Size: 298 KiB |
@@ -0,0 +1,84 @@
|
|||||||
|
package xiaozhi.modules.admin.contrloler;
|
||||||
|
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameters;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import 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.utils.Result;
|
||||||
|
import xiaozhi.common.validator.ValidatorUtils;
|
||||||
|
import xiaozhi.modules.sys.dto.AdminPageUserDTO;
|
||||||
|
import xiaozhi.modules.sys.service.SysUserService;
|
||||||
|
import xiaozhi.modules.sys.vo.AdminPageUserVO;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理员控制层
|
||||||
|
*
|
||||||
|
* @author zjy
|
||||||
|
* @since 2025-3-25
|
||||||
|
*/
|
||||||
|
@AllArgsConstructor
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/admin")
|
||||||
|
@Tag(name = "管理员管理")
|
||||||
|
public class AdminController {
|
||||||
|
private final SysUserService sysUserService;
|
||||||
|
|
||||||
|
@GetMapping("/users")
|
||||||
|
@Operation(summary = "分页查找用户")
|
||||||
|
@RequiresPermissions("sys:role:superAdmin")
|
||||||
|
@Parameters({
|
||||||
|
@Parameter(name = "mobile", description = "用户手机号码", required = true),
|
||||||
|
@Parameter(name = Constant.PAGE, description = "当前页码,从1开始", required = true),
|
||||||
|
@Parameter(name = Constant.LIMIT, description = "每页显示记录数", required = true),
|
||||||
|
})
|
||||||
|
public Result<PageData<AdminPageUserVO>> pageUser(
|
||||||
|
@Parameter(hidden = true) @RequestParam Map<String, Object> params) {
|
||||||
|
AdminPageUserDTO dto = new AdminPageUserDTO();
|
||||||
|
dto.setMobile((String) params.get("mobile"));
|
||||||
|
dto.setLimit((String) params.get(Constant.LIMIT));
|
||||||
|
dto.setPage((String) params.get("pages"));
|
||||||
|
|
||||||
|
ValidatorUtils.validateEntity(dto);
|
||||||
|
PageData<AdminPageUserVO> page = sysUserService.page(dto);
|
||||||
|
return new Result<PageData<AdminPageUserVO>>().ok(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/users/{id}")
|
||||||
|
@Operation(summary = "重置密码")
|
||||||
|
@RequiresPermissions("sys:role:superAdmin")
|
||||||
|
public Result<String> update(
|
||||||
|
@PathVariable Long id) {
|
||||||
|
String password = sysUserService.resetPassword(id);
|
||||||
|
return new Result<String>().ok(password);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/users/{id}")
|
||||||
|
@Operation(summary = "用户删除")
|
||||||
|
@RequiresPermissions("sys:role:superAdmin")
|
||||||
|
public Result<Void> delete(@PathVariable Long id) {
|
||||||
|
sysUserService.delete(new Long[]{id});
|
||||||
|
return new Result<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/device/all")
|
||||||
|
@Operation(summary = "分页查找设备")
|
||||||
|
@RequiresPermissions("sys:role:superAdmin")
|
||||||
|
@Parameters({
|
||||||
|
@Parameter(name = "keywords", description = "用户手机号码", required = true),
|
||||||
|
@Parameter(name = Constant.PAGE, description = "当前页码,从1开始", required = true),
|
||||||
|
@Parameter(name = Constant.LIMIT, description = "每页显示记录数", required = true),
|
||||||
|
})
|
||||||
|
public Result<Void> pageDevice(
|
||||||
|
@Parameter(hidden = true) @RequestParam Map<String, Object> params) {
|
||||||
|
//TODO 等设备功能模块写好
|
||||||
|
return new Result<Void>().error(600,"等设备功能模块写好");
|
||||||
|
}
|
||||||
|
}
|
||||||
+38
-2
@@ -2,6 +2,7 @@ package xiaozhi.modules.agent.controller;
|
|||||||
|
|
||||||
import cn.hutool.json.JSONObject;
|
import cn.hutool.json.JSONObject;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
|
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
@@ -80,6 +81,40 @@ public class UserAgentController extends BaseController {
|
|||||||
return new Result<Agent>().ok(agent);
|
return new Result<Agent>().ok(agent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PutMapping("{agentId}")
|
||||||
|
@Operation(summary = "更新智能体")
|
||||||
|
@RequiresPermissions("sys:role:normal")
|
||||||
|
public Result<Agent> updateAgent(@PathVariable String agentId, @RequestBody Agent agent) {
|
||||||
|
UserDetail user = SecurityUser.getUser();
|
||||||
|
if (StringUtils.isBlank(agentId)) {
|
||||||
|
log.error("智能体ID不能为空");
|
||||||
|
return new Result<Agent>().error("更新失败,智能体ID不能为空");
|
||||||
|
}
|
||||||
|
Agent oldAgent = agentService.getById(agentId);
|
||||||
|
if (ObjectUtils.isNull(oldAgent)) {
|
||||||
|
log.error("智能体不存在");
|
||||||
|
return new Result<Agent>().error("更新失败,智能体不存在");
|
||||||
|
} else {
|
||||||
|
UpdateWrapper<Agent> updateWrapper = new UpdateWrapper<>();
|
||||||
|
updateWrapper.eq("id", agentId);
|
||||||
|
updateWrapper.set("agent_code", agent.getAgentCode());
|
||||||
|
updateWrapper.set("asr_model_id", agent.getAsrModelId());
|
||||||
|
updateWrapper.set("intent_model_id", agent.getIntentModelId());
|
||||||
|
updateWrapper.set("llm_model_id", agent.getLlmModelId());
|
||||||
|
updateWrapper.set("memory_model_id", agent.getMemoryModelId());
|
||||||
|
updateWrapper.set("system_prompt", agent.getSystemPrompt());
|
||||||
|
updateWrapper.set("tts_voice_id", agent.getTtsVoiceId());
|
||||||
|
updateWrapper.set("tts_model_id", agent.getTtsModelId());
|
||||||
|
updateWrapper.set("vad_model_id", agent.getVadModelId());
|
||||||
|
updateWrapper.set("updater", user.getId());
|
||||||
|
updateWrapper.set("updated_at", new Date());
|
||||||
|
boolean bool = agentService.update(updateWrapper);
|
||||||
|
if (!bool)
|
||||||
|
return new Result<Agent>().error("更新失败");
|
||||||
|
}
|
||||||
|
return new Result<Agent>().ok(agent);
|
||||||
|
}
|
||||||
|
|
||||||
@DeleteMapping("/{agentId}")
|
@DeleteMapping("/{agentId}")
|
||||||
@Operation(summary = "删除智能体")
|
@Operation(summary = "删除智能体")
|
||||||
@RequiresPermissions("sys:role:normal")
|
@RequiresPermissions("sys:role:normal")
|
||||||
@@ -113,7 +148,7 @@ public class UserAgentController extends BaseController {
|
|||||||
UserDetail user = SecurityUser.getUser();
|
UserDetail user = SecurityUser.getUser();
|
||||||
List<Agent> agents = agentService.list(new QueryWrapper<Agent>().eq("user_id", user.getId()));
|
List<Agent> agents = agentService.list(new QueryWrapper<Agent>().eq("user_id", user.getId()));
|
||||||
List<AgentVO> list = new ArrayList<>();
|
List<AgentVO> list = new ArrayList<>();
|
||||||
this.convertAgetVOList(list, agents);
|
this.convertAgentVOList(list, agents);
|
||||||
return new Result<List<AgentVO>>().ok(list);
|
return new Result<List<AgentVO>>().ok(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,6 +164,7 @@ public class UserAgentController extends BaseController {
|
|||||||
return new Result<JSONObject>().error("智能体不存在");
|
return new Result<JSONObject>().error("智能体不存在");
|
||||||
}
|
}
|
||||||
AgentConfigVO agentConfigVO = new AgentConfigVO();
|
AgentConfigVO agentConfigVO = new AgentConfigVO();
|
||||||
|
agentConfigVO.setPrompt(agent.getSystemPrompt());
|
||||||
// return new Result<AgentConfigVO>().ok(agentConfigVO);
|
// return new Result<AgentConfigVO>().ok(agentConfigVO);
|
||||||
String json = "{\n" +
|
String json = "{\n" +
|
||||||
" \"ASR\": {\n" +
|
" \"ASR\": {\n" +
|
||||||
@@ -188,7 +224,7 @@ public class UserAgentController extends BaseController {
|
|||||||
* @param agentVOList 转换后的AgentVO对象列表
|
* @param agentVOList 转换后的AgentVO对象列表
|
||||||
* @param agentList 原始的Agent对象列表
|
* @param agentList 原始的Agent对象列表
|
||||||
*/
|
*/
|
||||||
private void convertAgetVOList(List<AgentVO> agentVOList, List<Agent> agentList) {
|
private void convertAgentVOList(List<AgentVO> agentVOList, List<Agent> agentList) {
|
||||||
// 遍历Agent对象列表
|
// 遍历Agent对象列表
|
||||||
for (Agent agent : agentList) {
|
for (Agent agent : agentList) {
|
||||||
// 创建一个新的AgentVO对象
|
// 创建一个新的AgentVO对象
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ public class Agent implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* 记忆模型标识
|
* 记忆模型标识
|
||||||
*/
|
*/
|
||||||
private String memModelId;
|
private String memoryModelId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 意图模型标识
|
* 意图模型标识
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ public class AgentTemplate implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* 记忆模型标识
|
* 记忆模型标识
|
||||||
*/
|
*/
|
||||||
private String memModelId;
|
private String memoryModelId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 意图模型标识
|
* 意图模型标识
|
||||||
|
|||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
package xiaozhi.modules.model.controller;public class ModelConfigController {
|
||||||
|
}
|
||||||
+99
-121
@@ -1,33 +1,24 @@
|
|||||||
package xiaozhi.modules.model.controller;
|
package xiaozhi.modules.model.controller;
|
||||||
|
|
||||||
import cn.hutool.json.JSONObject;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import cn.hutool.json.JSONUtil;
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
|
||||||
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import xiaozhi.common.controller.BaseController;
|
import xiaozhi.common.controller.BaseController;
|
||||||
import xiaozhi.common.redis.RedisUtils;
|
import xiaozhi.common.redis.RedisUtils;
|
||||||
import xiaozhi.common.user.UserDetail;
|
|
||||||
import xiaozhi.common.utils.Result;
|
import xiaozhi.common.utils.Result;
|
||||||
import xiaozhi.modules.device.constant.DeviceConstant;
|
import xiaozhi.modules.model.domain.ModelConfig;
|
||||||
import xiaozhi.modules.device.domain.Device;
|
import xiaozhi.modules.model.domain.TtsVoice;
|
||||||
import xiaozhi.modules.device.service.DeviceService;
|
import xiaozhi.modules.model.service.ModelConfigService;
|
||||||
import xiaozhi.modules.device.utils.CodeGeneratorUtil;
|
import xiaozhi.modules.model.service.TtsVoiceService;
|
||||||
import xiaozhi.modules.device.vo.DeviceOtaVO;
|
|
||||||
import xiaozhi.modules.ota.domain.Ota;
|
|
||||||
import xiaozhi.modules.ota.service.OtaService;
|
|
||||||
import xiaozhi.modules.security.user.SecurityUser;
|
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.List;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Tag(name = "模型数据管理")
|
@Tag(name = "模型数据管理")
|
||||||
@@ -35,112 +26,99 @@ import java.util.Date;
|
|||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/model/")
|
@RequestMapping("/model/")
|
||||||
public class ModelController extends BaseController {
|
public class ModelController extends BaseController {
|
||||||
private final DeviceService deviceService;
|
private final TtsVoiceService ttsVoiceService;
|
||||||
private final OtaService otaService;
|
private final ModelConfigService modelConfigService;
|
||||||
@Resource
|
|
||||||
private RedisUtils redisUtils;
|
|
||||||
|
|
||||||
@CrossOrigin(originPatterns = "*", methods = {RequestMethod.GET, RequestMethod.POST})
|
|
||||||
@RequestMapping(path = "/", method = {RequestMethod.POST, RequestMethod.GET}, produces = "application/json")
|
|
||||||
@Operation(summary = "设备OTA升级")
|
|
||||||
public String ota(@RequestHeader(required = false) HttpHeaders headers, @RequestBody(required = false) JSONObject jsonObject) {
|
|
||||||
log.info("OTA升级请求:header:{},body:{}", headers, jsonObject);
|
|
||||||
if (ObjectUtils.isNull(headers) || StringUtils.isBlank(headers.getFirst("device-id"))) {
|
|
||||||
log.error("设备ID不能为空");
|
|
||||||
return "{\"error\": \"Device ID is required\"}";
|
|
||||||
}
|
|
||||||
|
|
||||||
DeviceOtaVO otaVO = new DeviceOtaVO();
|
|
||||||
Device device = deviceService.getOne(new UpdateWrapper<Device>().eq("mac_address", headers.getFirst("device-id").toUpperCase()).eq("id", headers.getFirst("client-Id").replace("-", "")));
|
|
||||||
if (ObjectUtils.isNull(device)) {
|
|
||||||
// 从 Redis 中获取设备信息
|
|
||||||
Object redisValue = redisUtils.hGet(DeviceConstant.REDIS_KEY_PREFIX_DEVICE_ACTIVATION_MAC, headers.getFirst("device-id").toUpperCase());
|
|
||||||
if (ObjectUtils.isNull(redisValue)) {
|
|
||||||
String code = CodeGeneratorUtil.generateCode(6);
|
|
||||||
log.info("[gen]授权码已广播:{}", code);
|
|
||||||
otaVO.setActivation(new DeviceOtaVO.Activation(code, "youxlife.com\n" + code));
|
|
||||||
redisUtils.hSet(DeviceConstant.REDIS_KEY_PREFIX_DEVICE_ACTIVATION_MAC, headers.getFirst("device-id").toUpperCase(), code, RedisUtils.HOUR_ONE_EXPIRE);
|
|
||||||
redisUtils.hSet(DeviceConstant.REDIS_KEY_PREFIX_DEVICE_ACTIVATION_CODE, code, jsonObject, RedisUtils.HOUR_ONE_EXPIRE);
|
|
||||||
} else {
|
|
||||||
log.warn("[get]授权码已广播:{}", redisValue);
|
|
||||||
otaVO.setActivation(new DeviceOtaVO.Activation(redisValue.toString(), "youxlife.com\n" + redisValue));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (ObjectUtils.isNull(device) || device.getAutoUpdate() == 1) {
|
@GetMapping("/list")
|
||||||
//{"version":"1.0.0","url":"http://https://youxlife.oss-cn-zhangjiakou.aliyuncs.com/v1.4.5.bin"}
|
@Operation(summary = "模型配置列表")
|
||||||
String board = ObjectUtils.isNull(device)?headers.getFirst("user-agent").split("/")[0]:device.getBoard();
|
@RequiresPermissions("sys:role:normal")
|
||||||
Ota ota = otaService.getOne(new UpdateWrapper<Ota>().eq("board", board).eq("is_enabled", 1));
|
public Result<List<ModelConfig>> getModelList() {
|
||||||
if (ObjectUtils.isNull(ota)) {
|
List<ModelConfig> list = modelConfigService.list(new QueryWrapper<ModelConfig>().eq("is_enabled", 1));
|
||||||
log.warn("OTA升级信息未配置");
|
return new Result<List<ModelConfig>>().ok(list);
|
||||||
} else {
|
|
||||||
otaVO.setFirmware(new DeviceOtaVO.Firmware(ota.getAppVersion(), ota.getUrl()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
otaVO.setServer_time(new DeviceOtaVO.ServerTime(new Date().getTime(), 8 * 60));
|
|
||||||
return JSONUtil.toJsonStr(otaVO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/sys/getOtalist")
|
|
||||||
@Operation(summary = "设备OTA列表")
|
|
||||||
@RequiresPermissions("sys:role:superAdmin")
|
|
||||||
public Result<Page<Ota>> getOtalist(@RequestParam Integer pageNo, @RequestParam Integer pageSize) {
|
|
||||||
UserDetail user = SecurityUser.getUser();
|
|
||||||
Page page = new Page<Ota>(pageNo, pageSize);
|
|
||||||
page = otaService.page(page);
|
|
||||||
return new Result<Page<Ota>>().ok(page);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/sys/save")
|
// private final ModelProviderService modelProviderService;
|
||||||
@Operation(summary = "添加设备OTA")
|
//
|
||||||
@RequiresPermissions("sys:role:superAdmin")
|
// private final ModelConfigService modelConfigService;
|
||||||
public Result<Ota> save(@RequestBody Ota ota) {
|
//
|
||||||
UserDetail user = SecurityUser.getUser();
|
// @GetMapping("/models/names")
|
||||||
ota.setCreator(user.getId());
|
// @Operation(summary = "获取所有模型名称")
|
||||||
ota.setCreateDate(new Date());
|
// @RequiresPermissions("sys:role:superAdmin")
|
||||||
boolean bool = otaService.save(ota);
|
// public Result<List<String>> getModelNames(@RequestParam String modelType,
|
||||||
if (!bool) {
|
// @RequestParam(required = false) String modelName) {
|
||||||
return new Result().error("设备OTA添加失败");
|
// List<String> modelNameList = modelConfigService.getModelCodeList(modelType, modelName);
|
||||||
}
|
// return new Result<List<String>>().ok(modelNameList);
|
||||||
return new Result<Ota>().ok(null);
|
// }
|
||||||
}
|
//
|
||||||
|
// @GetMapping("/{modelType}/provideTypes")
|
||||||
@PostMapping("/sys/update")
|
// @Operation(summary = "获取模型供应器列表")
|
||||||
@Operation(summary = "更新设备OTA")
|
// @RequiresPermissions("sys:role:superAdmin")
|
||||||
@RequiresPermissions("sys:role:superAdmin")
|
// public Result<List<ModelProviderDTO>> getModelProviderList(@PathVariable String modelType) {
|
||||||
public Result<Ota> update(@RequestBody Ota ota) {
|
// List<ModelProviderDTO> modelProviderDTOS = modelProviderService.getListByModelType(modelType);
|
||||||
UserDetail user = SecurityUser.getUser();
|
// return new Result<List<ModelProviderDTO>>().ok(modelProviderDTOS);
|
||||||
boolean bool = otaService.update(
|
// }
|
||||||
new UpdateWrapper<Ota>().eq("id", ota.getId())
|
//
|
||||||
.set("board", ota.getBoard().trim().toLowerCase())
|
// @GetMapping("/{modelType}/{provideCode}/fields")
|
||||||
.set("app_version", ota.getAppVersion())
|
// @Operation(summary = "获取模型供应器字段")
|
||||||
.set("url", ota.getUrl())
|
// @RequiresPermissions("sys:role:superAdmin")
|
||||||
.set("is_enabled", ota.getIsEnabled())
|
// public Result<List<String>> getModelProviderFields(@PathVariable String modelType, @PathVariable String provideCode) {
|
||||||
.set("updater", user.getId())
|
// List<String> fieldList = modelProviderService.getFieldList(modelType, provideCode);
|
||||||
.set("update_date", new Date())
|
// return new Result<List<String>>().ok(fieldList);
|
||||||
);
|
// }
|
||||||
if (!bool) {
|
//
|
||||||
return new Result().error("设备OTA更新失败");
|
//
|
||||||
}
|
// @GetMapping("/models/list")
|
||||||
return new Result<Ota>().ok(null);
|
// @Operation(summary = "获取模型配置列表")
|
||||||
}
|
// @RequiresPermissions("sys:role:superAdmin")
|
||||||
|
// public Result<PageData<ModelConfigDTO>> getModelConfigList(@RequestParam String modelType,
|
||||||
@PostMapping("/sys/toggleEnabled")
|
// @RequestParam(required = false) String modelName,
|
||||||
@Operation(summary = "切换设备OTA可用状态")
|
// @RequestParam(required = false, defaultValue = "0") Integer page,
|
||||||
@RequiresPermissions("sys:role:superAdmin")
|
// @RequestParam(required = false,defaultValue = "10") Integer limit) {
|
||||||
public Result<Ota> toggleEnabled(@RequestBody Ota ota) {
|
// PageData<ModelConfigDTO> pageList = modelConfigService.getPageList(modelType, modelName, page, limit);
|
||||||
UserDetail user = SecurityUser.getUser();
|
// return new Result<PageData<ModelConfigDTO>>().ok(pageList);
|
||||||
boolean bool = otaService.update(
|
// }
|
||||||
new UpdateWrapper<Ota>().eq("id", ota.getId())
|
//
|
||||||
.set("is_enabled", ota.getIsEnabled())
|
//
|
||||||
.set("updater", user.getId())
|
// @PostMapping("/models/{modelType}/{provideCode}")
|
||||||
.set("update_date", new Date())
|
// @Operation(summary = "新增模型配置")
|
||||||
);
|
// @RequiresPermissions("sys:role:superAdmin")
|
||||||
if (!bool) {
|
// public Result<ModelConfigDTO> addModelConfig(@PathVariable String modelType,
|
||||||
return new Result().error("切换设备OTA可用状态失败");
|
// @PathVariable String provideCode,
|
||||||
}
|
// @RequestBody ModelConfigBodyDTO modelConfigBodyDTO) {
|
||||||
return new Result<Ota>().ok(null);
|
// ModelConfigDTO modelConfigDTO = modelConfigService.add(modelType, provideCode, modelConfigBodyDTO);
|
||||||
}
|
// return new Result<ModelConfigDTO>().ok(modelConfigDTO);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// @PutMapping("/models/{modelType}/{provideCode}/{id}")
|
||||||
|
// @Operation(summary = "编辑模型配置")
|
||||||
|
// @RequiresPermissions("sys:role:superAdmin")
|
||||||
|
// public Result<ModelConfigDTO> editModelConfig(@PathVariable String modelType,
|
||||||
|
// @PathVariable String provideCode,
|
||||||
|
// @PathVariable String id,
|
||||||
|
// @RequestBody ModelConfigBodyDTO modelConfigBodyDTO) {
|
||||||
|
// ModelConfigDTO modelConfigDTO = modelConfigService.edit(modelType, provideCode, id, modelConfigBodyDTO);
|
||||||
|
// return new Result<ModelConfigDTO>().ok(modelConfigDTO);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// @DeleteMapping("/models/{modelType}/{provideCode}/{id}")
|
||||||
|
// @Operation(summary = "删除模型配置")
|
||||||
|
// @RequiresPermissions("sys:role:superAdmin")
|
||||||
|
// public Result<Void> deleteModelConfig(@PathVariable String modelType, @PathVariable String provideCode, @PathVariable String id) {
|
||||||
|
// modelConfigService.delete(modelType, provideCode, id);
|
||||||
|
// return new Result<>();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @GetMapping("/models/{modelName}/voices")
|
||||||
|
// @Operation(summary = "获取模型音色")
|
||||||
|
// @RequiresPermissions("sys:role:normal")
|
||||||
|
// public Result<List<String>> getVoiceList(@PathVariable String modelName,
|
||||||
|
// @RequestParam(required = false) String voiceName) {
|
||||||
|
//
|
||||||
|
// List<String> voiceList = modelConfigService.getVoiceList(modelName, voiceName);
|
||||||
|
// return new Result<List<String>>().ok(voiceList);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
package xiaozhi.modules.model.controller;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import xiaozhi.common.controller.BaseController;
|
||||||
|
import xiaozhi.common.utils.Result;
|
||||||
|
import xiaozhi.modules.model.domain.TtsVoice;
|
||||||
|
import xiaozhi.modules.model.service.ModelConfigService;
|
||||||
|
import xiaozhi.modules.model.service.TtsVoiceService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Tag(name = "模型数据管理")
|
||||||
|
@AllArgsConstructor
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/tts")
|
||||||
|
public class TtsController extends BaseController {
|
||||||
|
private final TtsVoiceService ttsVoiceService;
|
||||||
|
private final ModelConfigService modelConfigService;
|
||||||
|
|
||||||
|
@GetMapping("/voice")
|
||||||
|
@Operation(summary = "音色列表")
|
||||||
|
@RequiresPermissions("sys:role:normal")
|
||||||
|
public Result<List<TtsVoice>> getTtsList(@RequestParam(required = false) String ttsModelId) {
|
||||||
|
QueryWrapper<TtsVoice> queryWrapper = new QueryWrapper<>();
|
||||||
|
if (StringUtils.isNotBlank(ttsModelId)) {
|
||||||
|
queryWrapper.eq("ttsModelId", ttsModelId);
|
||||||
|
}
|
||||||
|
List<TtsVoice> list = ttsVoiceService.list(queryWrapper);
|
||||||
|
return new Result<List<TtsVoice>>().ok(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// private final ModelProviderService modelProviderService;
|
||||||
|
//
|
||||||
|
// private final ModelConfigService modelConfigService;
|
||||||
|
//
|
||||||
|
// @GetMapping("/models/names")
|
||||||
|
// @Operation(summary = "获取所有模型名称")
|
||||||
|
// @RequiresPermissions("sys:role:superAdmin")
|
||||||
|
// public Result<List<String>> getModelNames(@RequestParam String modelType,
|
||||||
|
// @RequestParam(required = false) String modelName) {
|
||||||
|
// List<String> modelNameList = modelConfigService.getModelCodeList(modelType, modelName);
|
||||||
|
// return new Result<List<String>>().ok(modelNameList);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @GetMapping("/{modelType}/provideTypes")
|
||||||
|
// @Operation(summary = "获取模型供应器列表")
|
||||||
|
// @RequiresPermissions("sys:role:superAdmin")
|
||||||
|
// public Result<List<ModelProviderDTO>> getModelProviderList(@PathVariable String modelType) {
|
||||||
|
// List<ModelProviderDTO> modelProviderDTOS = modelProviderService.getListByModelType(modelType);
|
||||||
|
// return new Result<List<ModelProviderDTO>>().ok(modelProviderDTOS);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @GetMapping("/{modelType}/{provideCode}/fields")
|
||||||
|
// @Operation(summary = "获取模型供应器字段")
|
||||||
|
// @RequiresPermissions("sys:role:superAdmin")
|
||||||
|
// public Result<List<String>> getModelProviderFields(@PathVariable String modelType, @PathVariable String provideCode) {
|
||||||
|
// List<String> fieldList = modelProviderService.getFieldList(modelType, provideCode);
|
||||||
|
// return new Result<List<String>>().ok(fieldList);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// @GetMapping("/models/list")
|
||||||
|
// @Operation(summary = "获取模型配置列表")
|
||||||
|
// @RequiresPermissions("sys:role:superAdmin")
|
||||||
|
// public Result<PageData<ModelConfigDTO>> getModelConfigList(@RequestParam String modelType,
|
||||||
|
// @RequestParam(required = false) String modelName,
|
||||||
|
// @RequestParam(required = false, defaultValue = "0") Integer page,
|
||||||
|
// @RequestParam(required = false,defaultValue = "10") Integer limit) {
|
||||||
|
// PageData<ModelConfigDTO> pageList = modelConfigService.getPageList(modelType, modelName, page, limit);
|
||||||
|
// return new Result<PageData<ModelConfigDTO>>().ok(pageList);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// @PostMapping("/models/{modelType}/{provideCode}")
|
||||||
|
// @Operation(summary = "新增模型配置")
|
||||||
|
// @RequiresPermissions("sys:role:superAdmin")
|
||||||
|
// public Result<ModelConfigDTO> addModelConfig(@PathVariable String modelType,
|
||||||
|
// @PathVariable String provideCode,
|
||||||
|
// @RequestBody ModelConfigBodyDTO modelConfigBodyDTO) {
|
||||||
|
// ModelConfigDTO modelConfigDTO = modelConfigService.add(modelType, provideCode, modelConfigBodyDTO);
|
||||||
|
// return new Result<ModelConfigDTO>().ok(modelConfigDTO);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// @PutMapping("/models/{modelType}/{provideCode}/{id}")
|
||||||
|
// @Operation(summary = "编辑模型配置")
|
||||||
|
// @RequiresPermissions("sys:role:superAdmin")
|
||||||
|
// public Result<ModelConfigDTO> editModelConfig(@PathVariable String modelType,
|
||||||
|
// @PathVariable String provideCode,
|
||||||
|
// @PathVariable String id,
|
||||||
|
// @RequestBody ModelConfigBodyDTO modelConfigBodyDTO) {
|
||||||
|
// ModelConfigDTO modelConfigDTO = modelConfigService.edit(modelType, provideCode, id, modelConfigBodyDTO);
|
||||||
|
// return new Result<ModelConfigDTO>().ok(modelConfigDTO);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// @DeleteMapping("/models/{modelType}/{provideCode}/{id}")
|
||||||
|
// @Operation(summary = "删除模型配置")
|
||||||
|
// @RequiresPermissions("sys:role:superAdmin")
|
||||||
|
// public Result<Void> deleteModelConfig(@PathVariable String modelType, @PathVariable String provideCode, @PathVariable String id) {
|
||||||
|
// modelConfigService.delete(modelType, provideCode, id);
|
||||||
|
// return new Result<>();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @GetMapping("/models/{modelName}/voices")
|
||||||
|
// @Operation(summary = "获取模型音色")
|
||||||
|
// @RequiresPermissions("sys:role:normal")
|
||||||
|
// public Result<List<String>> getVoiceList(@PathVariable String modelName,
|
||||||
|
// @RequestParam(required = false) String voiceName) {
|
||||||
|
//
|
||||||
|
// List<String> voiceList = modelConfigService.getVoiceList(modelName, voiceName);
|
||||||
|
// return new Result<List<String>>().ok(voiceList);
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package xiaozhi.modules.model.dao;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import xiaozhi.common.dao.BaseDao;
|
||||||
|
import xiaozhi.modules.model.entity.ModelConfigEntity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface ModelConfigDao extends BaseDao<ModelConfigEntity> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get model_code list
|
||||||
|
*/
|
||||||
|
List<String> getModelCodeList(@Param("modelType") String modelType, @Param("modelName") String modelName);
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package xiaozhi.modules.model.dao;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import xiaozhi.common.dao.BaseDao;
|
||||||
|
import xiaozhi.modules.model.entity.ModelProviderEntity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface ModelProviderDao extends BaseDao<ModelProviderEntity> {
|
||||||
|
|
||||||
|
List<String> getFieldList(@Param("modelType") String modelType, @Param("provideCode") String provideCode);
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package xiaozhi.modules.model.dto;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Schema(description = "模型供应器/商")
|
||||||
|
public class ModelConfigBodyDTO {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
// @Schema(description = "模型类型(Memory/ASR/VAD/LLM/TTS)")
|
||||||
|
// private String modelType;
|
||||||
|
//
|
||||||
|
@Schema(description = "模型编码(如AliLLM、DoubaoTTS)")
|
||||||
|
private String modelCode;
|
||||||
|
|
||||||
|
@Schema(description = "模型名称")
|
||||||
|
private String modelName;
|
||||||
|
|
||||||
|
@Schema(description = "是否默认配置(0否 1是)")
|
||||||
|
private Integer isDefault;
|
||||||
|
|
||||||
|
@Schema(description = "是否启用")
|
||||||
|
private Integer isEnabled;
|
||||||
|
|
||||||
|
@Schema(description = "模型配置(JSON格式)")
|
||||||
|
private String configJson;
|
||||||
|
|
||||||
|
@Schema(description = "官方文档链接")
|
||||||
|
private String docLink;
|
||||||
|
|
||||||
|
@Schema(description = "备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
@Schema(description = "排序")
|
||||||
|
private Integer sort;
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package xiaozhi.modules.model.dto;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Schema(description = "模型供应器/商")
|
||||||
|
public class ModelConfigDTO implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "主键")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "模型类型(Memory/ASR/VAD/LLM/TTS)")
|
||||||
|
private String modelType;
|
||||||
|
|
||||||
|
@Schema(description = "模型编码(如AliLLM、DoubaoTTS)")
|
||||||
|
private String modelCode;
|
||||||
|
|
||||||
|
@Schema(description = "模型名称")
|
||||||
|
private String modelName;
|
||||||
|
|
||||||
|
@Schema(description = "是否默认配置(0否 1是)")
|
||||||
|
private Integer isDefault;
|
||||||
|
|
||||||
|
@Schema(description = "是否启用")
|
||||||
|
private Integer isEnabled;
|
||||||
|
|
||||||
|
@Schema(description = "模型配置(JSON格式)")
|
||||||
|
private String configJson;
|
||||||
|
|
||||||
|
@Schema(description = "官方文档链接")
|
||||||
|
private String docLink;
|
||||||
|
|
||||||
|
@Schema(description = "备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
@Schema(description = "排序")
|
||||||
|
private Integer sort;
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package xiaozhi.modules.model.dto;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Schema(description = "模型供应器/商")
|
||||||
|
public class ModelProviderDTO implements Serializable {
|
||||||
|
//
|
||||||
|
// @Schema(description = "主键")
|
||||||
|
// private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "模型类型(Memory/ASR/VAD/LLM/TTS)")
|
||||||
|
private String modelType;
|
||||||
|
|
||||||
|
@Schema(description = "供应器类型")
|
||||||
|
private String providerCode;
|
||||||
|
|
||||||
|
@Schema(description = "供应器名称")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "供应器字段列表(JSON格式)")
|
||||||
|
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||||
|
private String fields;
|
||||||
|
|
||||||
|
@Schema(description = "排序")
|
||||||
|
private Integer sort;
|
||||||
|
|
||||||
|
@Schema(description = "创建者")
|
||||||
|
private Long creator;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间")
|
||||||
|
private Date createDate;
|
||||||
|
|
||||||
|
@Schema(description = "更新者")
|
||||||
|
private Long updater;
|
||||||
|
|
||||||
|
@Schema(description = "更新时间")
|
||||||
|
private Date updateDate;
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package xiaozhi.modules.model.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@TableName("ai_model_config")
|
||||||
|
@Schema(description = "模型配置表")
|
||||||
|
public class ModelConfigEntity {
|
||||||
|
|
||||||
|
@TableId(type = IdType.ASSIGN_UUID)
|
||||||
|
@Schema(description = "主键")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Schema(description = "模型类型(Memory/ASR/VAD/LLM/TTS)")
|
||||||
|
private String modelType;
|
||||||
|
|
||||||
|
@Schema(description = "模型编码(如AliLLM、DoubaoTTS)")
|
||||||
|
private String modelCode;
|
||||||
|
|
||||||
|
@Schema(description = "模型名称")
|
||||||
|
private String modelName;
|
||||||
|
|
||||||
|
@Schema(description = "是否默认配置(0否 1是)")
|
||||||
|
private Integer isDefault;
|
||||||
|
|
||||||
|
@Schema(description = "是否启用")
|
||||||
|
private Integer isEnabled;
|
||||||
|
|
||||||
|
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||||
|
@Schema(description = "模型配置(JSON格式)")
|
||||||
|
private String configJson;
|
||||||
|
|
||||||
|
@Schema(description = "官方文档链接")
|
||||||
|
private String docLink;
|
||||||
|
|
||||||
|
@Schema(description = "备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
@Schema(description = "排序")
|
||||||
|
private Integer sort;
|
||||||
|
|
||||||
|
@Schema(description = "创建者")
|
||||||
|
private Long creator;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间")
|
||||||
|
private Date createDate;
|
||||||
|
|
||||||
|
@Schema(description = "更新者")
|
||||||
|
private Long updater;
|
||||||
|
|
||||||
|
@Schema(description = "更新时间")
|
||||||
|
private Date updateDate;
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package xiaozhi.modules.model.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@TableName("ai_model_provider")
|
||||||
|
@Schema(description = "模型供应器表")
|
||||||
|
public class ModelProviderEntity {
|
||||||
|
|
||||||
|
@TableId(type = IdType.ASSIGN_UUID)
|
||||||
|
@Schema(description = "主键")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Schema(description = "模型类型(Memory/ASR/VAD/LLM/TTS)")
|
||||||
|
private String modelType;
|
||||||
|
|
||||||
|
@Schema(description = "供应器类型,如 openai、")
|
||||||
|
private String providerCode;
|
||||||
|
|
||||||
|
@Schema(description = "供应器名称")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "供应器字段列表(JSON格式)")
|
||||||
|
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||||
|
private String fields;
|
||||||
|
|
||||||
|
@Schema(description = "排序")
|
||||||
|
private Integer sort;
|
||||||
|
|
||||||
|
@Schema(description = "创建者")
|
||||||
|
private Long creator;
|
||||||
|
|
||||||
|
@Schema(description = "创建时间")
|
||||||
|
private Date createDate;
|
||||||
|
|
||||||
|
@Schema(description = "更新者")
|
||||||
|
private Long updater;
|
||||||
|
|
||||||
|
@Schema(description = "更新时间")
|
||||||
|
private Date updateDate;
|
||||||
|
}
|
||||||
@@ -10,4 +10,15 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
|||||||
*/
|
*/
|
||||||
public interface ModelConfigService extends IService<ModelConfig> {
|
public interface ModelConfigService extends IService<ModelConfig> {
|
||||||
|
|
||||||
|
// List<String> getModelCodeList(String modelType, String modelName);
|
||||||
|
//
|
||||||
|
// PageData<ModelConfigDTO> getPageList(String modelType, String modelName, Integer page, Integer limit);
|
||||||
|
//
|
||||||
|
// ModelConfigDTO add(String modelType, String provideCode, ModelConfigBodyDTO modelConfigBodyDTO);
|
||||||
|
//
|
||||||
|
// ModelConfigDTO edit(String modelType, String provideCode, String id, ModelConfigBodyDTO modelConfigBodyDTO);
|
||||||
|
//
|
||||||
|
// void delete(String modelType, String provideCode, String id);
|
||||||
|
//
|
||||||
|
// List<String> getVoiceList(String modelName, String voiceName);
|
||||||
}
|
}
|
||||||
|
|||||||
+13
@@ -10,4 +10,17 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
|||||||
*/
|
*/
|
||||||
public interface ModelProviderService extends IService<ModelProvider> {
|
public interface ModelProviderService extends IService<ModelProvider> {
|
||||||
|
|
||||||
|
//// List<String> getModelNames(String modelType, String modelName);
|
||||||
|
//
|
||||||
|
// List<ModelProviderDTO> getListByModelType(String modelType);
|
||||||
|
//
|
||||||
|
// ModelProviderDTO add(ModelProviderEntity modelProviderEntity);
|
||||||
|
//
|
||||||
|
// ModelProviderDTO edit(ModelProviderEntity modelProviderEntity);
|
||||||
|
//
|
||||||
|
// void delete();
|
||||||
|
//
|
||||||
|
// List<ModelProviderDTO> getList(String modelType, String provideCode);
|
||||||
|
//
|
||||||
|
// List<String> getFieldList(String modelType, String provideCode);
|
||||||
}
|
}
|
||||||
|
|||||||
+91
@@ -15,6 +15,97 @@ import org.springframework.stereotype.Service;
|
|||||||
public class ModelConfigServiceImpl extends ServiceImpl<ModelConfigMapper, ModelConfig>
|
public class ModelConfigServiceImpl extends ServiceImpl<ModelConfigMapper, ModelConfig>
|
||||||
implements ModelConfigService{
|
implements ModelConfigService{
|
||||||
|
|
||||||
|
// private final ModelConfigDao modelConfigDao;
|
||||||
|
// private final ModelProviderService modelProviderService;
|
||||||
|
// private final TimbreService timbreService;
|
||||||
|
//
|
||||||
|
// private static final Logger logger = LoggerFactory.getLogger(ModelConfigServiceImpl.class);
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public List<String> getModelCodeList(String modelType, String modelName) {
|
||||||
|
// return modelConfigDao.getModelCodeList(modelType, modelName);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public PageData<ModelConfigDTO> getPageList(String modelType, String modelName, Integer page, Integer limit) {
|
||||||
|
// Map<String, Object> params = new HashMap<String, Object>();
|
||||||
|
// params.put(Constant.PAGE, page);
|
||||||
|
// params.put(Constant.LIMIT, limit);
|
||||||
|
// IPage<ModelConfigEntity> modelConfigEntityIPage = modelConfigDao.selectPage(
|
||||||
|
// getPage(params, "sort", true),
|
||||||
|
// new QueryWrapper<ModelConfigEntity>()
|
||||||
|
// .eq("model_type", modelType)
|
||||||
|
// .like(StringUtils.isNotBlank(modelName), "model_name", modelName)
|
||||||
|
// );
|
||||||
|
// return getPageData(modelConfigEntityIPage, ModelConfigDTO.class);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public ModelConfigDTO add(String modelType, String provideCode, ModelConfigBodyDTO modelConfigBodyDTO) {
|
||||||
|
// // 先验证有没有供应器
|
||||||
|
// if (StringUtils.isBlank(modelType) || StringUtils.isBlank(provideCode)) {
|
||||||
|
// throw new RenException("modelType和provideCode不能为空");
|
||||||
|
// }
|
||||||
|
// List<ModelProviderDTO> providerList = modelProviderService.getList(modelType, provideCode);
|
||||||
|
// if (CollectionUtil.isEmpty(providerList)) {
|
||||||
|
// throw new RenException("供应器不存在");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 再保存供应器提供的模型
|
||||||
|
// ModelConfigEntity modelConfigEntity = ConvertUtils.sourceToTarget(modelConfigBodyDTO, ModelConfigEntity.class);
|
||||||
|
// modelConfigEntity.setModelType(modelType);
|
||||||
|
// modelConfigDao.insert(modelConfigEntity);
|
||||||
|
// return ConvertUtils.sourceToTarget(modelConfigEntity, ModelConfigDTO.class);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public ModelConfigDTO edit(String modelType, String provideCode, String id, ModelConfigBodyDTO modelConfigBodyDTO) {
|
||||||
|
// // 先验证有没有供应器
|
||||||
|
// if (StringUtils.isBlank(modelType) || StringUtils.isBlank(provideCode)) {
|
||||||
|
// throw new RenException("modelType和provideCode不能为空");
|
||||||
|
// }
|
||||||
|
// List<ModelProviderDTO> providerList = modelProviderService.getList(modelType, provideCode);
|
||||||
|
// if (CollectionUtil.isEmpty(providerList)) {
|
||||||
|
// throw new RenException("供应器不存在");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 再更新供应器提供的模型
|
||||||
|
// ModelConfigEntity modelConfigEntity = ConvertUtils.sourceToTarget(modelConfigBodyDTO, ModelConfigEntity.class);
|
||||||
|
// modelConfigEntity.setId(id);
|
||||||
|
// modelConfigEntity.setModelType(modelType);
|
||||||
|
// modelConfigDao.updateById(modelConfigEntity);
|
||||||
|
// return ConvertUtils.sourceToTarget(modelConfigEntity, ModelConfigDTO.class);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public void delete(String modelType, String provideCode, String id) {
|
||||||
|
// // 先验证有没有供应器
|
||||||
|
// if (StringUtils.isBlank(modelType) || StringUtils.isBlank(provideCode)) {
|
||||||
|
// throw new RenException("modelType和provideCode不能为空");
|
||||||
|
// }
|
||||||
|
// List<ModelProviderDTO> providerList = modelProviderService.getList(modelType, provideCode);
|
||||||
|
// if (CollectionUtil.isEmpty(providerList)) {
|
||||||
|
// throw new RenException("供应器不存在");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// modelConfigDao.deleteById(Long.getLong(id));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public List<String> getVoiceList(String modelName, String voiceName) {
|
||||||
|
// QueryWrapper<ModelConfigEntity> queryWrapper = new QueryWrapper<>();
|
||||||
|
// queryWrapper.eq("model_name", StringUtils.isBlank(modelName) ? "" : modelName);
|
||||||
|
// queryWrapper.eq("model_type", "TTS");
|
||||||
|
// List<ModelConfigEntity> modelConfigEntities = modelConfigDao.selectList(queryWrapper);
|
||||||
|
// if (CollectionUtil.isEmpty(modelConfigEntities)) {
|
||||||
|
// logger.warn("没有找到模型配置信息");
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// ModelConfigEntity modelConfigEntity = modelConfigEntities.get(0);
|
||||||
|
// String id = modelConfigEntity.getId();
|
||||||
|
//
|
||||||
|
// return timbreService.getVoiceNames(id, voiceName);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+39
@@ -15,6 +15,45 @@ import org.springframework.stereotype.Service;
|
|||||||
public class ModelProviderServiceImpl extends ServiceImpl<ModelProviderMapper, ModelProvider>
|
public class ModelProviderServiceImpl extends ServiceImpl<ModelProviderMapper, ModelProvider>
|
||||||
implements ModelProviderService{
|
implements ModelProviderService{
|
||||||
|
|
||||||
|
// private final ModelProviderDao modelProviderDao;
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public List<ModelProviderDTO> getListByModelType(String modelType) {
|
||||||
|
//
|
||||||
|
// QueryWrapper<ModelProviderEntity> queryWrapper = new QueryWrapper<>();
|
||||||
|
// queryWrapper.eq("model_type", StringUtils.isBlank(modelType) ? "" : modelType);
|
||||||
|
// List<ModelProviderEntity> providerEntities = modelProviderDao.selectList(queryWrapper);
|
||||||
|
// return ConvertUtils.sourceToTarget(providerEntities, ModelProviderDTO.class);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public ModelProviderDTO add(ModelProviderEntity modelProviderEntity) {
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public ModelProviderDTO edit(ModelProviderEntity modelProviderEntity) {
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public void delete() {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public List<ModelProviderDTO> getList(String modelType, String provideCode) {
|
||||||
|
// QueryWrapper<ModelProviderEntity> queryWrapper = new QueryWrapper<>();
|
||||||
|
// queryWrapper.eq("model_type", StringUtils.isBlank(modelType) ? "" : modelType);
|
||||||
|
// queryWrapper.eq("provide_code", StringUtils.isBlank(provideCode) ? "" : provideCode);
|
||||||
|
// List<ModelProviderEntity> providerEntities = modelProviderDao.selectList(queryWrapper);
|
||||||
|
// return ConvertUtils.sourceToTarget(providerEntities, ModelProviderDTO.class);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public List<String> getFieldList(String modelType, String provideCode) {
|
||||||
|
// return modelProviderDao.getFieldList(modelType, provideCode);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
import org.apache.shiro.authc.AuthenticationException;
|
import org.apache.shiro.authc.AuthenticationException;
|
||||||
import org.apache.shiro.authc.AuthenticationToken;
|
import org.apache.shiro.authc.AuthenticationToken;
|
||||||
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
|
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
import xiaozhi.common.constant.Constant;
|
import xiaozhi.common.constant.Constant;
|
||||||
import xiaozhi.common.exception.ErrorCode;
|
import xiaozhi.common.exception.ErrorCode;
|
||||||
@@ -24,12 +26,15 @@ import java.io.IOException;
|
|||||||
*/
|
*/
|
||||||
public class Oauth2Filter extends AuthenticatingFilter {
|
public class Oauth2Filter extends AuthenticatingFilter {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(Oauth2Filter.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
|
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
|
||||||
//获取请求token
|
//获取请求token
|
||||||
String token = getRequestToken((HttpServletRequest) request);
|
String token = getRequestToken((HttpServletRequest) request);
|
||||||
|
|
||||||
if (StringUtils.isBlank(token)) {
|
if (StringUtils.isBlank(token)) {
|
||||||
|
logger.warn("createToken:token is empty");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +54,15 @@ public class Oauth2Filter extends AuthenticatingFilter {
|
|||||||
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
|
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
|
||||||
//获取请求token,如果token不存在,直接返回401
|
//获取请求token,如果token不存在,直接返回401
|
||||||
String token = getRequestToken((HttpServletRequest) request);
|
String token = getRequestToken((HttpServletRequest) request);
|
||||||
|
|
||||||
|
// TODO 调试接口,临时取消登录限制,需要 token 参数的除外
|
||||||
|
// if (true) {
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
if (StringUtils.isBlank(token)) {
|
if (StringUtils.isBlank(token)) {
|
||||||
|
logger.warn("onAccessDenied:token is empty");
|
||||||
|
|
||||||
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||||
httpResponse.setContentType("application/json;charset=utf-8");
|
httpResponse.setContentType("application/json;charset=utf-8");
|
||||||
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
|
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
|
||||||
@@ -73,13 +86,14 @@ public class Oauth2Filter extends AuthenticatingFilter {
|
|||||||
httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());
|
httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());
|
||||||
try {
|
try {
|
||||||
//处理登录失败的异常
|
//处理登录失败的异常
|
||||||
|
logger.error("onLoginFailure:登录失败!", e);
|
||||||
Throwable throwable = e.getCause() == null ? e : e.getCause();
|
Throwable throwable = e.getCause() == null ? e : e.getCause();
|
||||||
Result r = new Result().error(ErrorCode.UNAUTHORIZED, throwable.getMessage());
|
Result r = new Result().error(ErrorCode.UNAUTHORIZED, throwable.getMessage());
|
||||||
|
|
||||||
String json = JsonUtils.toJsonString(r);
|
String json = JsonUtils.toJsonString(r);
|
||||||
httpResponse.getWriter().print(json);
|
httpResponse.getWriter().print(json);
|
||||||
} catch (IOException e1) {
|
} catch (IOException e1) {
|
||||||
|
logger.error("onLoginFailure:登录失败! msg:{}", e1.getMessage(), e1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
+4
@@ -4,8 +4,11 @@ import com.google.common.cache.Cache;
|
|||||||
import com.google.common.cache.CacheBuilder;
|
import com.google.common.cache.CacheBuilder;
|
||||||
import com.wf.captcha.SpecCaptcha;
|
import com.wf.captcha.SpecCaptcha;
|
||||||
import com.wf.captcha.base.Captcha;
|
import com.wf.captcha.base.Captcha;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import xiaozhi.common.redis.RedisKeys;
|
import xiaozhi.common.redis.RedisKeys;
|
||||||
import xiaozhi.common.redis.RedisUtils;
|
import xiaozhi.common.redis.RedisUtils;
|
||||||
|
import xiaozhi.modules.security.oauth2.Oauth2Realm;
|
||||||
import xiaozhi.modules.security.service.CaptchaService;
|
import xiaozhi.modules.security.service.CaptchaService;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
@@ -29,6 +32,7 @@ public class CaptchaServiceImpl implements CaptchaService {
|
|||||||
* Local Cache 5分钟过期
|
* Local Cache 5分钟过期
|
||||||
*/
|
*/
|
||||||
Cache<String, String> localCache = CacheBuilder.newBuilder().maximumSize(1000).expireAfterAccess(5, TimeUnit.MINUTES).build();
|
Cache<String, String> localCache = CacheBuilder.newBuilder().maximumSize(1000).expireAfterAccess(5, TimeUnit.MINUTES).build();
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(Oauth2Realm.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void create(HttpServletResponse response, String uuid) throws IOException {
|
public void create(HttpServletResponse response, String uuid) throws IOException {
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package xiaozhi.modules.sys.dto;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理员分页用户的参数DTO
|
||||||
|
* @author zjy
|
||||||
|
* @since 2025-3-21
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "音色分页参数")
|
||||||
|
public class AdminPageUserDTO {
|
||||||
|
|
||||||
|
|
||||||
|
@Schema(description = "手机号码")
|
||||||
|
private String mobile;
|
||||||
|
|
||||||
|
@Schema(description = "页数")
|
||||||
|
private String page;
|
||||||
|
|
||||||
|
@Schema(description = "显示列数")
|
||||||
|
private String limit;
|
||||||
|
}
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
package xiaozhi.modules.sys.service;
|
package xiaozhi.modules.sys.service;
|
||||||
|
|
||||||
|
import xiaozhi.common.page.PageData;
|
||||||
import xiaozhi.common.service.BaseService;
|
import xiaozhi.common.service.BaseService;
|
||||||
|
import xiaozhi.modules.sys.dto.AdminPageUserDTO;
|
||||||
import xiaozhi.modules.sys.dto.PasswordDTO;
|
import xiaozhi.modules.sys.dto.PasswordDTO;
|
||||||
import xiaozhi.modules.sys.dto.SysUserDTO;
|
import xiaozhi.modules.sys.dto.SysUserDTO;
|
||||||
import xiaozhi.modules.sys.entity.SysUserEntity;
|
import xiaozhi.modules.sys.entity.SysUserEntity;
|
||||||
|
import xiaozhi.modules.sys.vo.AdminPageUserVO;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -19,5 +22,30 @@ public interface SysUserService extends BaseService<SysUserEntity> {
|
|||||||
|
|
||||||
void delete(Long[] ids);
|
void delete(Long[] ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证是否允许修改密码更改
|
||||||
|
* @param userId 用户id
|
||||||
|
* @param passwordDTO 验证密码的参数
|
||||||
|
*/
|
||||||
void changePassword(Long userId, PasswordDTO passwordDTO);
|
void changePassword(Long userId, PasswordDTO passwordDTO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 直接修改密码,不需要验证
|
||||||
|
* @param userId 用户id
|
||||||
|
* @param password 密码
|
||||||
|
*/
|
||||||
|
void changePasswordDirectly(Long userId, String password);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置密码
|
||||||
|
* @param userId 用户id
|
||||||
|
* @return 随机生成符合规范的密码
|
||||||
|
*/
|
||||||
|
String resetPassword(Long userId);
|
||||||
|
/**
|
||||||
|
* 管理员分页用户信息
|
||||||
|
* @param dto 分页查找参数
|
||||||
|
* @return 用户列表分页数据
|
||||||
|
*/
|
||||||
|
PageData<AdminPageUserVO> page(AdminPageUserDTO dto);
|
||||||
}
|
}
|
||||||
|
|||||||
+63
-2
@@ -1,23 +1,28 @@
|
|||||||
package xiaozhi.modules.sys.service.impl;
|
package xiaozhi.modules.sys.service.impl;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import xiaozhi.common.constant.Constant;
|
||||||
import xiaozhi.common.exception.ErrorCode;
|
import xiaozhi.common.exception.ErrorCode;
|
||||||
import xiaozhi.common.exception.RenException;
|
import xiaozhi.common.exception.RenException;
|
||||||
|
import xiaozhi.common.page.PageData;
|
||||||
import xiaozhi.common.service.impl.BaseServiceImpl;
|
import xiaozhi.common.service.impl.BaseServiceImpl;
|
||||||
import xiaozhi.common.utils.ConvertUtils;
|
import xiaozhi.common.utils.ConvertUtils;
|
||||||
import xiaozhi.modules.security.password.PasswordUtils;
|
import xiaozhi.modules.security.password.PasswordUtils;
|
||||||
import xiaozhi.modules.sys.dao.SysUserDao;
|
import xiaozhi.modules.sys.dao.SysUserDao;
|
||||||
|
import xiaozhi.modules.sys.dto.AdminPageUserDTO;
|
||||||
import xiaozhi.modules.sys.dto.PasswordDTO;
|
import xiaozhi.modules.sys.dto.PasswordDTO;
|
||||||
import xiaozhi.modules.sys.dto.SysUserDTO;
|
import xiaozhi.modules.sys.dto.SysUserDTO;
|
||||||
import xiaozhi.modules.sys.entity.SysUserEntity;
|
import xiaozhi.modules.sys.entity.SysUserEntity;
|
||||||
import xiaozhi.modules.sys.enums.SuperAdminEnum;
|
import xiaozhi.modules.sys.enums.SuperAdminEnum;
|
||||||
import xiaozhi.modules.sys.service.SysUserService;
|
import xiaozhi.modules.sys.service.SysUserService;
|
||||||
|
import xiaozhi.modules.sys.vo.AdminPageUserVO;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@@ -80,9 +85,11 @@ public class SysUserServiceImpl extends BaseServiceImpl<SysUserDao, SysUserEntit
|
|||||||
public void delete(Long[] ids) {
|
public void delete(Long[] ids) {
|
||||||
//删除用户
|
//删除用户
|
||||||
baseDao.deleteBatchIds(Arrays.asList(ids));
|
baseDao.deleteBatchIds(Arrays.asList(ids));
|
||||||
|
//TODO 除了要删除用户还要删除用户关联的设备,对话,智能体。等此3个功能完善在添加
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void changePassword(Long userId, PasswordDTO passwordDTO) {
|
public void changePassword(Long userId, PasswordDTO passwordDTO) {
|
||||||
SysUserEntity sysUserEntity = sysUserDao.selectById(userId);
|
SysUserEntity sysUserEntity = sysUserDao.selectById(userId);
|
||||||
|
|
||||||
@@ -107,11 +114,50 @@ public class SysUserServiceImpl extends BaseServiceImpl<SysUserDao, SysUserEntit
|
|||||||
updateById(sysUserEntity);
|
updateById(sysUserEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void changePasswordDirectly(Long userId, String password) {
|
||||||
|
SysUserEntity sysUserEntity = new SysUserEntity();
|
||||||
|
sysUserEntity.setId(userId);
|
||||||
|
sysUserEntity.setPassword(PasswordUtils.encode(password));
|
||||||
|
updateById(sysUserEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public String resetPassword(Long userId) {
|
||||||
|
String password = generatePassword();
|
||||||
|
changePasswordDirectly(userId,password);
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
private Long getUserCount() {
|
private Long getUserCount() {
|
||||||
QueryWrapper<SysUserEntity> queryWrapper = new QueryWrapper<>();
|
QueryWrapper<SysUserEntity> queryWrapper = new QueryWrapper<>();
|
||||||
return baseDao.selectCount(queryWrapper);
|
return baseDao.selectCount(queryWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageData<AdminPageUserVO> page(AdminPageUserDTO dto) {
|
||||||
|
Map<String, Object> params = new HashMap<String, Object>();
|
||||||
|
params.put(Constant.PAGE, dto.getPage());
|
||||||
|
params.put(Constant.LIMIT,dto.getLimit());
|
||||||
|
IPage<SysUserEntity> page = baseDao.selectPage(
|
||||||
|
getPage(params, "id", true),
|
||||||
|
//定义查询条件
|
||||||
|
new QueryWrapper<SysUserEntity>()
|
||||||
|
//必须按照手机号码查找
|
||||||
|
.eq(StringUtils.isNotBlank(dto.getMobile()),"username",dto.getMobile()));
|
||||||
|
List<AdminPageUserVO> list = page.getRecords().stream().map(user -> {
|
||||||
|
AdminPageUserVO adminPageUserVO = new AdminPageUserVO();
|
||||||
|
adminPageUserVO.setUserid(user.getId().toString());
|
||||||
|
adminPageUserVO.setMobile(user.getUsername());
|
||||||
|
//TODO 2. 等设备功能写好,获取对应数据
|
||||||
|
adminPageUserVO.setDeviceCount("0");
|
||||||
|
return adminPageUserVO;
|
||||||
|
}).toList();
|
||||||
|
return new PageData<>(list, page.getTotal());
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isStrongPassword(String password) {
|
private boolean isStrongPassword(String password) {
|
||||||
// 弱密码的正则表达式
|
// 弱密码的正则表达式
|
||||||
@@ -120,4 +166,19 @@ public class SysUserServiceImpl extends BaseServiceImpl<SysUserDao, SysUserEntit
|
|||||||
Matcher matcher = pattern.matcher(password);
|
Matcher matcher = pattern.matcher(password);
|
||||||
return matcher.matches();
|
return matcher.matches();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()";
|
||||||
|
private static final Random random = new Random();
|
||||||
|
/**
|
||||||
|
* 生成随机密码
|
||||||
|
* @return 随机生成的密码
|
||||||
|
*/
|
||||||
|
private String generatePassword(){
|
||||||
|
StringBuilder password = new StringBuilder();
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
int randomIndex = random.nextInt(CHARACTERS.length());
|
||||||
|
password.append(CHARACTERS.charAt(randomIndex));
|
||||||
|
}
|
||||||
|
return password.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package xiaozhi.modules.sys.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理员分页展示用户的VO
|
||||||
|
* @ zjy
|
||||||
|
* @since 2025-3-25
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class AdminPageUserVO {
|
||||||
|
|
||||||
|
@Schema(description = "设备数量")
|
||||||
|
private String deviceCount;
|
||||||
|
|
||||||
|
@Schema(description = "手机号码")
|
||||||
|
private String mobile;
|
||||||
|
|
||||||
|
@Schema(description = "用户id")
|
||||||
|
private String userid;
|
||||||
|
}
|
||||||
@@ -7,6 +7,8 @@ import xiaozhi.modules.timbre.dto.TimbrePageDTO;
|
|||||||
import xiaozhi.modules.timbre.entity.TimbreEntity;
|
import xiaozhi.modules.timbre.entity.TimbreEntity;
|
||||||
import xiaozhi.modules.timbre.vo.TimbreDetailsVO;
|
import xiaozhi.modules.timbre.vo.TimbreDetailsVO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 音色的业务层的定义
|
* 音色的业务层的定义
|
||||||
@@ -46,4 +48,6 @@ public interface TimbreService extends BaseService<TimbreEntity> {
|
|||||||
* @param ids 需要被删除的音色id列表
|
* @param ids 需要被删除的音色id列表
|
||||||
*/
|
*/
|
||||||
void delete(Long[] ids);
|
void delete(Long[] ids);
|
||||||
|
|
||||||
|
List<String> getVoiceNames(String ttsModelId, String voiceName);
|
||||||
}
|
}
|
||||||
+21
-1
@@ -1,7 +1,9 @@
|
|||||||
package xiaozhi.modules.timbre.service.impl;
|
package xiaozhi.modules.timbre.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@@ -12,12 +14,13 @@ import xiaozhi.common.utils.ConvertUtils;
|
|||||||
import xiaozhi.modules.timbre.dao.TimbreDao;
|
import xiaozhi.modules.timbre.dao.TimbreDao;
|
||||||
import xiaozhi.modules.timbre.dto.TimbreDataDTO;
|
import xiaozhi.modules.timbre.dto.TimbreDataDTO;
|
||||||
import xiaozhi.modules.timbre.dto.TimbrePageDTO;
|
import xiaozhi.modules.timbre.dto.TimbrePageDTO;
|
||||||
import xiaozhi.modules.timbre.service.TimbreService;
|
|
||||||
import xiaozhi.modules.timbre.entity.TimbreEntity;
|
import xiaozhi.modules.timbre.entity.TimbreEntity;
|
||||||
|
import xiaozhi.modules.timbre.service.TimbreService;
|
||||||
import xiaozhi.modules.timbre.vo.TimbreDetailsVO;
|
import xiaozhi.modules.timbre.vo.TimbreDetailsVO;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,9 +28,11 @@ import java.util.Map;
|
|||||||
* @author zjy
|
* @author zjy
|
||||||
* @since 2025-3-21
|
* @since 2025-3-21
|
||||||
*/
|
*/
|
||||||
|
@AllArgsConstructor
|
||||||
@Service
|
@Service
|
||||||
public class TimbreServiceImpl extends BaseServiceImpl<TimbreDao, TimbreEntity> implements TimbreService {
|
public class TimbreServiceImpl extends BaseServiceImpl<TimbreDao, TimbreEntity> implements TimbreService {
|
||||||
|
|
||||||
|
private final TimbreDao timbreDao;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageData<TimbreDetailsVO> page(TimbrePageDTO dto) {
|
public PageData<TimbreDetailsVO> page(TimbrePageDTO dto) {
|
||||||
@@ -76,6 +81,21 @@ public class TimbreServiceImpl extends BaseServiceImpl<TimbreDao, TimbreEntity>
|
|||||||
baseDao.deleteBatchIds(Arrays.asList(ids));
|
baseDao.deleteBatchIds(Arrays.asList(ids));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getVoiceNames(String ttsModelId, String voiceName) {
|
||||||
|
QueryWrapper<TimbreEntity> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("ttsModelId", StringUtils.isBlank(ttsModelId) ? "" : ttsModelId);
|
||||||
|
if (StringUtils.isNotBlank(voiceName)) {
|
||||||
|
queryWrapper.like("name", voiceName);
|
||||||
|
}
|
||||||
|
List<TimbreEntity> timbreEntities = timbreDao.selectList(queryWrapper);
|
||||||
|
if (CollectionUtil.isEmpty(timbreEntities)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return timbreEntities.stream().map(TimbreEntity::getName).toList();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理是不是tts模型的id
|
* 处理是不是tts模型的id
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<result property="llmModelId" column="llm_model_id" />
|
<result property="llmModelId" column="llm_model_id" />
|
||||||
<result property="ttsModelId" column="tts_model_id" />
|
<result property="ttsModelId" column="tts_model_id" />
|
||||||
<result property="ttsVoiceId" column="tts_voice_id" />
|
<result property="ttsVoiceId" column="tts_voice_id" />
|
||||||
<result property="memModelId" column="mem_model_id" />
|
<result property="memoryModelId" column="memory_model_id" />
|
||||||
<result property="intentModelId" column="intent_model_id" />
|
<result property="intentModelId" column="intent_model_id" />
|
||||||
<result property="systemPrompt" column="system_prompt" />
|
<result property="systemPrompt" column="system_prompt" />
|
||||||
<result property="langCode" column="lang_code" />
|
<result property="langCode" column="lang_code" />
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id,user_id,agent_code,agent_name,asr_model_id,vad_model_id,
|
id,user_id,agent_code,agent_name,asr_model_id,vad_model_id,
|
||||||
llm_model_id,tts_model_id,tts_voice_id,mem_model_id,intent_model_id,
|
llm_model_id,tts_model_id,tts_voice_id,memory_model_id,intent_model_id,
|
||||||
system_prompt,lang_code,language,sort,creator,
|
system_prompt,lang_code,language,sort,creator,
|
||||||
created_at,updater,updated_at
|
created_at,updater,updated_at
|
||||||
</sql>
|
</sql>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<result property="llmModelId" column="llm_model_id" />
|
<result property="llmModelId" column="llm_model_id" />
|
||||||
<result property="ttsModelId" column="tts_model_id" />
|
<result property="ttsModelId" column="tts_model_id" />
|
||||||
<result property="ttsVoiceId" column="tts_voice_id" />
|
<result property="ttsVoiceId" column="tts_voice_id" />
|
||||||
<result property="memModelId" column="mem_model_id" />
|
<result property="memoryModelId" column="memory_model_id" />
|
||||||
<result property="intentModelId" column="intent_model_id" />
|
<result property="intentModelId" column="intent_model_id" />
|
||||||
<result property="systemPrompt" column="system_prompt" />
|
<result property="systemPrompt" column="system_prompt" />
|
||||||
<result property="langCode" column="lang_code" />
|
<result property="langCode" column="lang_code" />
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id,agent_code,agent_name,asr_model_id,vad_model_id,llm_model_id,
|
id,agent_code,agent_name,asr_model_id,vad_model_id,llm_model_id,
|
||||||
tts_model_id,tts_voice_id,mem_model_id,intent_model_id,system_prompt,
|
tts_model_id,tts_voice_id,memory_model_id,intent_model_id,system_prompt,
|
||||||
lang_code,language,sort,is_default,creator,
|
lang_code,language,sort,is_default,creator,
|
||||||
created_at,updater,updated_at
|
created_at,updater,updated_at
|
||||||
</sql>
|
</sql>
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?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.model.dao.ModelConfigDao">
|
||||||
|
<!-- 获取模型供应器字段 -->
|
||||||
|
<select id="getModelCodeList" resultType="String">
|
||||||
|
select model_name from ai_model_config where model_type = #{modelType}
|
||||||
|
<if test="modelName != null">and model_name = #{modelName}</if>
|
||||||
|
</select>
|
||||||
|
</mapper>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?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.model.dao.ModelProviderDao">
|
||||||
|
<!-- 获取模型供应器字段 -->
|
||||||
|
<select id="getFieldList" resultType="string">
|
||||||
|
select fields from ai_model_provider where model_type = #{modelType} and provider_code = #{providerCode};
|
||||||
|
</select>
|
||||||
|
</mapper>
|
||||||
@@ -3,6 +3,7 @@ import agent from './module/agent.js'
|
|||||||
import device from './module/device.js'
|
import device from './module/device.js'
|
||||||
import user from './module/user.js'
|
import user from './module/user.js'
|
||||||
import ota from './module/ota.js'
|
import ota from './module/ota.js'
|
||||||
|
import model from './module/model.js'
|
||||||
import admin from './module/admin.js'
|
import admin from './module/admin.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,5 +32,6 @@ export default {
|
|||||||
agent,
|
agent,
|
||||||
device,
|
device,
|
||||||
ota,
|
ota,
|
||||||
|
model,
|
||||||
admin
|
admin
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ import {getServiceUrl} from '../api'
|
|||||||
export default {
|
export default {
|
||||||
// 用户列表
|
// 用户列表
|
||||||
getUserList(callback) {
|
getUserList(callback) {
|
||||||
RequestService.sendRequest().url(`${getServiceUrl()}/api/v1/admin/users`)
|
RequestService.sendRequest().url(`${getServiceUrl()}/admin/users`)
|
||||||
.method('GET')
|
.method('GET')
|
||||||
.success((res) => {
|
.success((res) => {
|
||||||
RequestService.clearRequestTime()
|
RequestService.clearRequestTime()
|
||||||
callback(res)
|
callback(res)
|
||||||
})
|
})
|
||||||
.fail(() => {
|
.fail(() => {
|
||||||
RequestService.reAjaxFun(() => {
|
// RequestService.reAjaxFun(() => {
|
||||||
this.getList()
|
// this.getUserList()
|
||||||
})
|
// })
|
||||||
}).send()
|
}).send()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
Executable
+32
@@ -0,0 +1,32 @@
|
|||||||
|
import RequestService from '../httpRequest'
|
||||||
|
import {getServiceUrl} from '../api'
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
//模型配置列表
|
||||||
|
getModelList(callback) {
|
||||||
|
RequestService.sendRequest().url(`${getServiceUrl()}/model/list`)
|
||||||
|
.method('GET')
|
||||||
|
.success((res) => {
|
||||||
|
RequestService.clearRequestTime()
|
||||||
|
callback(res)
|
||||||
|
})
|
||||||
|
.fail((err) => {
|
||||||
|
console.error('获取模型配置列表失败:', err);
|
||||||
|
}).send()
|
||||||
|
},
|
||||||
|
|
||||||
|
//音色列表
|
||||||
|
getTtsVoiceList(ttsModelId, callback) {
|
||||||
|
RequestService.sendRequest().url(`${getServiceUrl()}/tts/voice`)
|
||||||
|
.method('GET')
|
||||||
|
.data({ttsModelId})
|
||||||
|
.success((res) => {
|
||||||
|
RequestService.clearRequestTime()
|
||||||
|
callback(res)
|
||||||
|
})
|
||||||
|
.fail((err) => {
|
||||||
|
console.error('获取音色列表失败:', err);
|
||||||
|
}).send()
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -18,7 +18,8 @@ export default {
|
|||||||
// this.login(loginForm, callback)
|
// this.login(loginForm, callback)
|
||||||
// })
|
// })
|
||||||
}).send()
|
}).send()
|
||||||
}, // 获取验证码
|
},
|
||||||
|
// 获取验证码
|
||||||
getCaptcha(uuid, callback) {
|
getCaptcha(uuid, callback) {
|
||||||
|
|
||||||
RequestService.sendRequest()
|
RequestService.sendRequest()
|
||||||
@@ -98,4 +99,24 @@ export default {
|
|||||||
// })
|
// })
|
||||||
}).send()
|
}).send()
|
||||||
},
|
},
|
||||||
|
// 修改用户密码
|
||||||
|
changePassword(oldPassword, newPassword, successCallback, errorCallback) {
|
||||||
|
RequestService.sendRequest()
|
||||||
|
.url(`${getServiceUrl()}/user/change-password`) // 修改URL
|
||||||
|
.method('PUT') // 修改方法为PUT
|
||||||
|
.data({
|
||||||
|
old_password: oldPassword, // 修改参数名
|
||||||
|
new_password: newPassword // 修改参数名
|
||||||
|
})
|
||||||
|
.success((res) => {
|
||||||
|
RequestService.clearRequestTime();
|
||||||
|
successCallback(res);
|
||||||
|
})
|
||||||
|
.fail((error) => {
|
||||||
|
// RequestService.reAjaxFun(() => {
|
||||||
|
// this.changePassword(oldPassword, newPassword, successCallback, errorCallback);
|
||||||
|
// });
|
||||||
|
})
|
||||||
|
.send();
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
@@ -1,16 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog
|
<el-dialog
|
||||||
:visible.sync="visible"
|
:visible.sync="visible"
|
||||||
width="1000px"
|
width="975px"
|
||||||
center
|
center
|
||||||
custom-class="custom-dialog"
|
custom-class="custom-dialog"
|
||||||
:show-close="false"
|
:show-close="false"
|
||||||
|
class="center-dialog"
|
||||||
|
|
||||||
>
|
>
|
||||||
<div style="margin: 0 30px 20px; text-align: left; padding: 20px; border-radius: 10px;">
|
<div style="margin: 0 18px; text-align: left; padding: 10px; border-radius: 10px;">
|
||||||
<div style="font-size: 27px; color: #3d4566; margin-bottom: 15px; text-align: center;">添加模型</div>
|
<div style="font-size: 30px; color: #3d4566; margin-top: -10px; margin-bottom: 10px; text-align: center;">
|
||||||
|
添加模型
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 关闭按钮 -->
|
||||||
|
<button class="custom-close-btn" @click="handleClose">
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
|
||||||
<!-- 模型信息部分 -->
|
<!-- 模型信息部分 -->
|
||||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
|
||||||
<div style="font-size: 20px; font-weight: bold; color: #3d4566;">模型信息</div>
|
<div style="font-size: 20px; font-weight: bold; color: #3d4566;">模型信息</div>
|
||||||
<div style="display: flex; align-items: center; gap: 20px;">
|
<div style="display: flex; align-items: center; gap: 20px;">
|
||||||
<div style="display: flex; align-items: center;">
|
<div style="display: flex; align-items: center;">
|
||||||
@@ -24,35 +33,35 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="height: 2px; background: #e9e9e9; margin-bottom: 20px;"></div>
|
<div style="height: 2px; background: #e9e9e9; margin-bottom: 22px;"></div>
|
||||||
|
|
||||||
<el-form :model="formData" label-width="100px" label-position="left" class="custom-form">
|
<el-form :model="formData" label-width="100px" label-position="left" class="custom-form">
|
||||||
<!-- 第一行:模型名称和模型编码 -->
|
<!-- 第一行:模型名称和模型编码 -->
|
||||||
<div style="display: flex; gap: 20px; margin-bottom: 15px;">
|
<div style="display: flex; gap: 20px; margin-bottom: 0;">
|
||||||
<el-form-item label="模型名称" prop="modelName" style="flex: 1; margin-bottom: 0;">
|
<el-form-item label="模型名称" prop="modelName" style="flex: 1;">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="formData.modelName"
|
v-model="formData.modelName"
|
||||||
placeholder="请输入模型名称"
|
placeholder="请输入模型名称"
|
||||||
class="custom-input-bg"
|
class="custom-input-bg"
|
||||||
></el-input>
|
></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="模型编码" prop="modelCode" style="flex: 1; margin-bottom: 0;">
|
<el-form-item label="模型编码" prop="modelCode" style="flex: 1;">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="formData.modelCode"
|
v-model="formData.modelCode"
|
||||||
placeholder="请输入模型编码"
|
placeholder="请输入模型编码"
|
||||||
class="custom-input-bg"
|
class="custom-input-bg"
|
||||||
></el-input>
|
></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 第二行:供应器和排序号 -->
|
<!-- 第二行:供应器和排序号 -->
|
||||||
<div style="display: flex; gap: 20px; margin-bottom: 15px;">
|
<div style="display: flex; gap: 20px; margin-bottom: 0;">
|
||||||
<el-form-item label="供应器" prop="supplier" style="flex: 1; margin-bottom: 0;">
|
<el-form-item label="供应器" prop="supplier" style="flex: 1;">
|
||||||
<el-select
|
<el-select
|
||||||
v-model="formData.supplier"
|
v-model="formData.supplier"
|
||||||
placeholder="请选择"
|
placeholder="请选择"
|
||||||
class="custom-select custom-input-bg"
|
class="custom-select custom-input-bg"
|
||||||
style="width: 100%;"
|
style="width: 100%;"
|
||||||
>
|
>
|
||||||
<el-option label="硅基流动" value="硅基流动"></el-option>
|
<el-option label="硅基流动" value="硅基流动"></el-option>
|
||||||
<el-option label="智脑科技" value="智脑科技"></el-option>
|
<el-option label="智脑科技" value="智脑科技"></el-option>
|
||||||
@@ -60,26 +69,26 @@
|
|||||||
<el-option label="其他" value="其他"></el-option>
|
<el-option label="其他" value="其他"></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="排序号" prop="sortOrder" style="flex: 1; margin-bottom: 0;">
|
<el-form-item label="排序号" prop="sortOrder" style="flex: 1;">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="formData.sort"
|
v-model="formData.sort"
|
||||||
placeholder="请输入排序号"
|
placeholder="请输入排序号"
|
||||||
class="custom-input-bg"
|
class="custom-input-bg"
|
||||||
></el-input>
|
></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 文档地址 -->
|
<!-- 文档地址 -->
|
||||||
<el-form-item label="文档地址" prop="docLink" style="margin-bottom: 15px;">
|
<el-form-item label="文档地址" prop="docLink" style="margin-bottom: 27px;">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="formData.docLink"
|
v-model="formData.docLink"
|
||||||
placeholder="请输入文档地址"
|
placeholder="请输入文档地址"
|
||||||
class="custom-input-bg"
|
class="custom-input-bg"
|
||||||
></el-input>
|
></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<!-- 备注 -->
|
<!-- 备注 -->
|
||||||
<el-form-item label="备注" prop="remark" style="margin-bottom: 15px;">
|
<el-form-item label="备注" prop="remark" class="prop-remark">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="formData.remark"
|
v-model="formData.remark"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
@@ -92,29 +101,29 @@
|
|||||||
|
|
||||||
<!-- 调用信息部分 -->
|
<!-- 调用信息部分 -->
|
||||||
<div style="font-size: 20px; font-weight: bold; color: #3d4566; margin-bottom: 15px;">调用信息</div>
|
<div style="font-size: 20px; font-weight: bold; color: #3d4566; margin-bottom: 15px;">调用信息</div>
|
||||||
<div style="height: 2px; background: #e9e9e9; margin-bottom: 20px;"></div>
|
<div style="height: 2px; background: #e9e9e9; margin-bottom: 15px;"></div>
|
||||||
|
|
||||||
<el-form :model="formData" label-width="100px" label-position="left" class="custom-form">
|
<el-form :model="formData" label-width="100px" label-position="left" class="custom-form">
|
||||||
<!-- 第一行:模型名称和接口地址 -->
|
<!-- 第一行:模型名称和接口地址 -->
|
||||||
<div style="display: flex; gap: 20px; margin-bottom: 15px;">
|
<div style="display: flex; gap: 10px; margin-bottom: 15px;">
|
||||||
<el-form-item label="模型名称" prop="param1" style="flex: 0.5; margin-bottom: 0;">
|
<el-form-item label="模型名称" prop="param1" style="flex: 0.5; margin-bottom: 0;">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="formData.configJson.param1"
|
v-model="formData.configJson.param1"
|
||||||
placeholder="请输入model_name"
|
placeholder="请输入model_name"
|
||||||
class="custom-input-bg"
|
class="custom-input-bg"
|
||||||
></el-input>
|
></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="接口地址" prop="param2" style="flex: 1; margin-bottom: 0;">
|
<el-form-item label="接口地址" prop="param2" style="flex: 1; margin-bottom: 0;">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="formData.configJson.param2"
|
v-model="formData.configJson.param2"
|
||||||
placeholder="请输入base_url"
|
placeholder="请输入base_url"
|
||||||
class="custom-input-bg"
|
class="custom-input-bg"
|
||||||
></el-input>
|
></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 秘钥信息 -->
|
<!-- 秘钥信息 -->
|
||||||
<el-form-item label="秘钥信息" prop="apiKey" style="margin-bottom: 15px;">
|
<el-form-item label="秘钥信息" prop="apiKey">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="formData.configJson.apiKey"
|
v-model="formData.configJson.apiKey"
|
||||||
placeholder="请输入api_key"
|
placeholder="请输入api_key"
|
||||||
@@ -126,7 +135,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 保存按钮 -->
|
<!-- 保存按钮 -->
|
||||||
<div style="display: flex; margin: 20px 0; justify-content: center;">
|
<div style="display: flex;justify-content: center;">
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
@click="confirm"
|
@click="confirm"
|
||||||
@@ -135,12 +144,6 @@
|
|||||||
保存
|
保存
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 关闭按钮 -->
|
|
||||||
<!-- 修改关闭按钮 -->
|
|
||||||
<button class="custom-close-btn" @click="handleClose">
|
|
||||||
×
|
|
||||||
</button>
|
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -216,6 +219,7 @@ export default {
|
|||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: white;
|
background: white;
|
||||||
|
padding-bottom: 17px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-dialog .el-dialog__header {
|
.custom-dialog .el-dialog__header {
|
||||||
@@ -223,6 +227,18 @@ export default {
|
|||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.center-dialog {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center-dialog .el-dialog {
|
||||||
|
margin: 4% 0 auto !important;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
.custom-close-btn {
|
.custom-close-btn {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 20px;
|
top: 20px;
|
||||||
@@ -249,19 +265,15 @@ export default {
|
|||||||
border-color: #409EFF;
|
border-color: #409EFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-select .el-input__inner {
|
|
||||||
padding-right: 30px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-select .el-input__suffix {
|
.custom-select .el-input__suffix {
|
||||||
background: #e6e8ea;
|
background: #e6e8ea;
|
||||||
right: 7px;
|
right: 6px;
|
||||||
width: 24px;
|
width: 20px;
|
||||||
height: 24px;
|
height: 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
top: 7px;
|
top: 9px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-select .el-input__suffix-inner {
|
.custom-select .el-input__suffix-inner {
|
||||||
@@ -276,42 +288,34 @@ export default {
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
border-left: 6px solid transparent;
|
border-left: 5px solid transparent;
|
||||||
border-right: 6px solid transparent;
|
border-right: 5px solid transparent;
|
||||||
border-top: 8px solid #c0c4cc;
|
border-top: 7px solid #c0c4cc;
|
||||||
position: relative;
|
position: relative;
|
||||||
top: -1px;
|
top: -2px;
|
||||||
transform: rotate(180deg);
|
transform: rotate(180deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-select .el-select .el-input .el-select__caret {
|
|
||||||
color: #c0c4cc;
|
|
||||||
font-size: 14px;
|
|
||||||
transition: transform .3s;
|
|
||||||
transform: rotateZ(0deg);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-select .el-select .el-input.is-focus .el-icon-arrow-up:before {
|
|
||||||
transform: rotateZ(180deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 表单样式调整 */
|
|
||||||
.custom-form .el-form-item {
|
.custom-form .el-form-item {
|
||||||
margin-bottom: 0;
|
margin-bottom: 20px; /* 统一设置所有表单项的间距 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-form .el-form-item__label {
|
.custom-form .el-form-item__label {
|
||||||
color: #3d4566;
|
color: #3d4566;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
padding-right: 15px;
|
padding-right: 20px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-form .el-form-item.prop-remark .el-form-item__label {
|
||||||
|
margin-top: -4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 修改placeholder颜色 */
|
/* 修改placeholder颜色 */
|
||||||
.custom-input-bg .el-input__inner::-webkit-input-placeholder,
|
.custom-input-bg .el-input__inner::-webkit-input-placeholder,
|
||||||
.custom-input-bg .el-textarea__inner::-webkit-input-placeholder {
|
.custom-input-bg .el-textarea__inner::-webkit-input-placeholder {
|
||||||
color: #9c9f9e ;
|
color: #9c9f9e;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 输入框背景色 */
|
/* 输入框背景色 */
|
||||||
@@ -320,16 +324,6 @@ export default {
|
|||||||
background-color: #f6f8fc;
|
background-color: #f6f8fc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-form .el-input__inner,
|
|
||||||
.custom-form .el-textarea__inner {
|
|
||||||
border-radius: 4px;
|
|
||||||
border: 1px solid #DCDFE6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-form .el-input__inner:focus,
|
|
||||||
.custom-form .el-textarea__inner:focus {
|
|
||||||
border-color: #409EFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
.save-btn {
|
.save-btn {
|
||||||
background: #e6f0fd;
|
background: #e6f0fd;
|
||||||
@@ -347,10 +341,6 @@ export default {
|
|||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 修复select宽度问题 */
|
|
||||||
.el-select {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 修改开关样式 */
|
/* 修改开关样式 */
|
||||||
.custom-switch .el-switch__core {
|
.custom-switch .el-switch__core {
|
||||||
@@ -381,4 +371,17 @@ export default {
|
|||||||
margin-left: -18px;
|
margin-left: -18px;
|
||||||
background-color: #1b47ee;
|
background-color: #1b47ee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 调整flex布局的gap */
|
||||||
|
[style*="display: flex"] {
|
||||||
|
gap: 20px; /* 扩大flex项间距 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 调整输入框高度 */
|
||||||
|
.custom-input-bg .el-input__inner {
|
||||||
|
height: 32px; /* 固定输入框高度 */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
@@ -23,8 +23,7 @@ export default {
|
|||||||
.message {
|
.message {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
margin-top: auto;
|
padding: 20px;
|
||||||
padding-top: 30px;
|
|
||||||
color: #979db1;
|
color: #979db1;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -14,9 +14,11 @@
|
|||||||
控制台
|
控制台
|
||||||
</div>
|
</div>
|
||||||
<div ref="menu-code_user" class="menu-btn" @click="goToPage('/user-management')">
|
<div ref="menu-code_user" class="menu-btn" @click="goToPage('/user-management')">
|
||||||
|
<i class="el-icon-user"></i>
|
||||||
用户管理
|
用户管理
|
||||||
</div>
|
</div>
|
||||||
<div ref="menu-code_model" class="menu-btn" @click="goToPage('/model-config')">
|
<div ref="menu-code_model" class="menu-btn" @click="goToPage('/model-config')">
|
||||||
|
<i class="el-icon-news"></i>
|
||||||
模型配置
|
模型配置
|
||||||
</div>
|
</div>
|
||||||
<div ref="menu-code_ota" class="menu-btn" @click="goToPage('/ota')">
|
<div ref="menu-code_ota" class="menu-btn" @click="goToPage('/ota')">
|
||||||
@@ -34,7 +36,7 @@
|
|||||||
<img alt="" src="@/assets/home/avatar.png" style="width: 21px;height: 21px;"/>
|
<img alt="" src="@/assets/home/avatar.png" style="width: 21px;height: 21px;"/>
|
||||||
<el-dropdown trigger="click">
|
<el-dropdown trigger="click">
|
||||||
<span class="el-dropdown-link">
|
<span class="el-dropdown-link">
|
||||||
{{ userInfo.mobile || '加载中...' }}<i class="el-icon-arrow-down el-icon--right"></i>
|
{{ userInfo.username || '加载中...' }}<i class="el-icon-arrow-down el-icon--right"></i>
|
||||||
</span>
|
</span>
|
||||||
<el-dropdown-menu slot="dropdown">
|
<el-dropdown-menu slot="dropdown">
|
||||||
<el-dropdown-item icon="el-icon-user" @click.native="">个人中心</el-dropdown-item>
|
<el-dropdown-item icon="el-icon-user" @click.native="">个人中心</el-dropdown-item>
|
||||||
|
|||||||
@@ -122,9 +122,10 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.model-menu {
|
.model-menu {
|
||||||
border-right: 1px solid #ebeef5;
|
border: 1px solid #ebeef5;
|
||||||
height: calc(100vh - 300px);
|
height: calc(100vh - 300px);
|
||||||
background-color: #fafafa;
|
background-color: #fafafa;
|
||||||
|
margin-right: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-operate {
|
.search-operate {
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ const routes = [
|
|||||||
menuCode: 'user',
|
menuCode: 'user',
|
||||||
},
|
},
|
||||||
component: function () {
|
component: function () {
|
||||||
return import('../views/UserManagement.vue')
|
return import('../views/userManagement.vue')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -83,7 +83,7 @@ const routes = [
|
|||||||
menuCode: 'model',
|
menuCode: 'model',
|
||||||
},
|
},
|
||||||
component: function () {
|
component: function () {
|
||||||
return import('../views/ModelConfig.vue')
|
return import('../views/modelConfig.vue')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,285 +1,407 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="welcome">
|
<div class="welcome">
|
||||||
<HeaderBar />
|
<HeaderBar />
|
||||||
<div class="model-container">
|
<!-- 首页内容 -->
|
||||||
<el-menu :default-active="activeTab" class="el-menu-vertical-demo" @select="handleMenuSelect">
|
<el-main style="padding: 20px; display: flex; flex-direction: column;">
|
||||||
<el-menu-item index="vad">语音活动检测</el-menu-item>
|
<div class="operation-bar">
|
||||||
<el-menu-item index="asr">语音识别</el-menu-item>
|
<!-- 面包屑-->
|
||||||
<el-menu-item index="llm">大语言模型</el-menu-item>
|
<div class="breadcrumbs">
|
||||||
<el-menu-item index="intent">意图识别</el-menu-item>
|
<el-breadcrumb separator="/">
|
||||||
<el-menu-item index="tts">语音合成</el-menu-item>
|
<el-breadcrumb-item>控制台</el-breadcrumb-item>
|
||||||
<el-menu-item index="memory">记忆</el-menu-item>
|
<el-breadcrumb-item>模型配置</el-breadcrumb-item>
|
||||||
</el-menu>
|
</el-breadcrumb>
|
||||||
<div class="content-container">
|
</div>
|
||||||
<div class="import-export-btn">
|
<div class="right-operations">
|
||||||
<el-button v-if="activeTab === 'tts'" type="primary" @click="ttsDialogVisible = true" style="margin-right: 10px;">
|
<el-button v-if="activeTab === 'tts'" type="primary" plain size="small" @click="ttsDialogVisible = true">
|
||||||
模型设置
|
语音设置
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button size="small" @click="handleImportExport">导入导出配置</el-button>
|
<el-button type="primary" plain size="small" @click="handleImport">
|
||||||
</div>
|
导入配置
|
||||||
<el-main style="padding: 20px; display: flex; flex-direction: column;">
|
</el-button>
|
||||||
<el-card class="model-card" shadow="always">
|
<el-button type="success" plain size="small" @click="handleExport">
|
||||||
<div class="model-header">
|
导出配置
|
||||||
<h2>大语言模型 (LLM)</h2>
|
</el-button>
|
||||||
<el-button type="primary" @click="addModel" class="add-btn">添加</el-button>
|
|
||||||
</div>
|
|
||||||
<div class="model-search-operate" style="margin-bottom: 20px;">
|
|
||||||
<el-input
|
|
||||||
placeholder="请输入模型名称查询"
|
|
||||||
v-model="search"
|
|
||||||
style="width: 300px; margin-right: 10px"
|
|
||||||
/>
|
|
||||||
<el-button @click="handleSearch">查询</el-button>
|
|
||||||
</div>
|
|
||||||
<el-table
|
|
||||||
:data="modelList"
|
|
||||||
style="width: 100%;"
|
|
||||||
border
|
|
||||||
stripe
|
|
||||||
header-cell-class-name="header-cell"
|
|
||||||
>
|
|
||||||
<el-table-column type="selection" width="55"></el-table-column>
|
|
||||||
<el-table-column label="模型名称" prop="candidateName"></el-table-column>
|
|
||||||
<el-table-column label="模型编码" prop="code"></el-table-column>
|
|
||||||
<el-table-column label="提供商" prop="supplier"></el-table-column>
|
|
||||||
<el-table-column label="是否启用">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<el-switch v-model="scope.row.isApplied" active-color="#409EFF" inactive-color="#C0CCDA"></el-switch>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="操作">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<el-button
|
|
||||||
size="mini"
|
|
||||||
@click="editModel(scope.row)"
|
|
||||||
style="margin-right: 5px;"
|
|
||||||
type="text"
|
|
||||||
class="action-btn"
|
|
||||||
>修改</el-button>
|
|
||||||
<el-button
|
|
||||||
size="mini"
|
|
||||||
type="danger"
|
|
||||||
@click="deleteModel(scope.row)"
|
|
||||||
class="action-btn"
|
|
||||||
>删除</el-button>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
<div class="table-footer">
|
|
||||||
<el-button @click="selectAll" class="footer-btn">全选</el-button>
|
|
||||||
<el-button type="danger" @click="batchDelete" class="footer-btn">删除</el-button>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
<div class="pagination-container">
|
|
||||||
<el-pagination
|
|
||||||
@current-change="handleCurrentChange"
|
|
||||||
:current-page="currentPage"
|
|
||||||
:page-sizes="[5, 10, 15]"
|
|
||||||
:page-size="pageSize"
|
|
||||||
layout="prev, pager, next"
|
|
||||||
:total="total"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="copyright">
|
|
||||||
©2025 xiaozhi-esp32-server
|
|
||||||
</div>
|
|
||||||
<ModelEditDialog :visible.sync="editDialogVisible" :modelData="editModelData" @save="handleModelSave"/>
|
|
||||||
<TtsModel :visible.sync="ttsDialogVisible" />
|
|
||||||
<AddModelDialog :visible.sync="addDialogVisible" :modelType="activeTab" @confirm="handleAddConfirm"/>
|
|
||||||
</el-main>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<!-- 主体内容 -->
|
||||||
</template>
|
<div class="main-wrapper">
|
||||||
|
<div class="content-panel">
|
||||||
|
<!-- 左侧导航 -->
|
||||||
|
<el-menu :default-active="activeTab" class="nav-panel" @select="handleMenuSelect"
|
||||||
|
style="background-size: cover; background-position: center;">
|
||||||
|
<el-menu-item index="vad">
|
||||||
|
语言活动检测
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item index="asr">
|
||||||
|
语音识别
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item index="llm">
|
||||||
|
大语言模型
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item index="intent">
|
||||||
|
意图识别
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item index="tts">
|
||||||
|
语音合成
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item index="memory">
|
||||||
|
记忆
|
||||||
|
</el-menu-item>
|
||||||
|
</el-menu>
|
||||||
|
|
||||||
<script>
|
<!-- 右侧内容 -->
|
||||||
import HeaderBar from "@/components/HeaderBar.vue";
|
<div class="content-area">
|
||||||
import ModelEditDialog from "@/components/ModelEditDialog.vue";
|
<div class="title-bar">
|
||||||
import TtsModel from "@/components/TtsModel.vue";
|
<div class="title-wrapper">
|
||||||
import AddModelDialog from "@/components/AddModelDialog.vue";
|
<h2 class="model-title">大语言模型(LLM)</h2>
|
||||||
|
<el-button type="primary" size="small" @click="addModel" class="add-btn">
|
||||||
|
添加
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="action-group">
|
||||||
|
<div class="search-group">
|
||||||
|
<el-input placeholder="请输入模型名称查询" v-model="search" size="small" class="search-input" clearable/>
|
||||||
|
<el-button type="primary" size="small" class="search-btn" @click="handleSearch">
|
||||||
|
查询
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
export default {
|
<el-table :header-cell-style="{background: 'transparent'}" :data="modelList" border class="data-table" header-row-class-name="table-header" >
|
||||||
components: { HeaderBar, ModelEditDialog, TtsModel, AddModelDialog},
|
<el-table-column type="selection" width="55" align="center"></el-table-column>
|
||||||
data() {
|
<el-table-column label="模型名称" prop="candidateName" align="center"></el-table-column>
|
||||||
return {
|
<el-table-column label="模型编码" prop="code" align="center"></el-table-column>
|
||||||
activeTab: 'llm',
|
<el-table-column label="提供商" prop="supplier" align="center"></el-table-column>
|
||||||
search: '',
|
<el-table-column label="是否启用" align="center" width="120">
|
||||||
editDialogVisible: false,
|
<template slot-scope="scope">
|
||||||
editModelData: {},
|
<el-switch v-model="scope.row.isApplied" class="custom-switch" :active-color="null" :inactive-color="null"/>
|
||||||
ttsDialogVisible: false,
|
</template>
|
||||||
addDialogVisible: false, // 新增弹窗显示状态
|
</el-table-column>
|
||||||
modelList: [
|
<el-table-column label="操作" align="center" width="180">
|
||||||
{ code: 'DeepSeek', candidateName: '深度求索', isApplied: true, supplier: '硅基流动' },
|
<template slot-scope="scope">
|
||||||
{ code: 'SmartAssist', candidateName: '智能助手', isApplied: false, supplier: '智脑科技' },
|
<el-button type="text" size="mini" @click="editModel(scope.row)" class="edit-btn">
|
||||||
{ code: 'CogEngine', candidateName: '认知引擎', isApplied: true, supplier: '云智科技' },
|
修改
|
||||||
],
|
</el-button>
|
||||||
currentPage: 1,
|
<el-button type="text" size="mini" @click="deleteModel(scope.row)" class="delete-btn">
|
||||||
pageSize: 4,
|
删除
|
||||||
total: 20
|
</el-button>
|
||||||
};
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<div class="table-footer">
|
||||||
|
<div class="batch-actions">
|
||||||
|
<el-button size="mini" @click="selectAll">全选</el-button>
|
||||||
|
<el-button size="mini" type="danger" icon="el-icon-delete" @click="batchDelete">
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="pagination-container">
|
||||||
|
<el-pagination @current-change="handleCurrentChange" background :current-page="currentPage" :page-size="pageSize" layout="prev, pager, next" :total="total"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ModelEditDialog :visible.sync="editDialogVisible" :modelData="editModelData" @save="handleModelSave"/>
|
||||||
|
<TtsModel :visible.sync="ttsDialogVisible" />
|
||||||
|
<AddModelDialog :visible.sync="addDialogVisible" :modelType="activeTab" @confirm="handleAddConfirm"/>
|
||||||
|
</div>
|
||||||
|
</el-main>
|
||||||
|
<!-- 底部 -->
|
||||||
|
<Footer :visible="true" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import HeaderBar from "@/components/HeaderBar.vue";
|
||||||
|
import ModelEditDialog from "@/components/ModelEditDialog.vue";
|
||||||
|
import TtsModel from "@/components/TtsModel.vue";
|
||||||
|
import AddModelDialog from "@/components/AddModelDialog.vue";
|
||||||
|
import Footer from '@/components/Footer.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { HeaderBar, ModelEditDialog, TtsModel, AddModelDialog,Footer },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
addDialogVisible: false,
|
||||||
|
activeTab: 'llm',
|
||||||
|
search: '',
|
||||||
|
editDialogVisible: false,
|
||||||
|
editModelData: {},
|
||||||
|
ttsDialogVisible: false,
|
||||||
|
modelList: [
|
||||||
|
{ code: 'DeepSeek', candidateName: '深度求索', isApplied: true, supplier: '硅基流动' },
|
||||||
|
{ code: 'SmartAssist', candidateName: '智能助手', isApplied: false, supplier: '智脑科技' },
|
||||||
|
{ code: 'CogEngine', candidateName: '认知引擎', isApplied: true, supplier: '云智科技' },
|
||||||
|
],
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 4,
|
||||||
|
total: 20
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleMenuSelect(index) {
|
||||||
|
this.activeTab = index;
|
||||||
},
|
},
|
||||||
methods: {
|
handleSearch() {
|
||||||
handleMenuSelect(index) {
|
console.log('查询:', this.search);
|
||||||
this.activeTab = index;
|
},
|
||||||
},
|
batchDelete() {
|
||||||
handleSearch() {
|
console.log('批量删除');
|
||||||
console.log('查询:', this.search);
|
},
|
||||||
},
|
addModel() {
|
||||||
batchDelete() {
|
this.addDialogVisible = true;
|
||||||
console.log('批量删除');
|
},
|
||||||
},
|
editModel(model) {
|
||||||
// 修改addModel方法
|
this.editModelData = {
|
||||||
addModel() {
|
code: model.code,
|
||||||
this.addDialogVisible = true;
|
name: model.candidateName,
|
||||||
},
|
supplier: model.supplier,
|
||||||
// 新增处理方法
|
};
|
||||||
handleAddConfirm(formData) {
|
this.editDialogVisible = true;
|
||||||
// 这里处理添加模型的逻辑
|
},
|
||||||
console.log('新增模型数据:', formData);
|
deleteModel(model) {
|
||||||
// 模拟添加到列表
|
console.log('删除:', model);
|
||||||
this.modelList.unshift({
|
},
|
||||||
code: formData.modelCode,
|
handleCurrentChange(page) {
|
||||||
candidateName: formData.modelName,
|
this.currentPage = page;
|
||||||
supplier: formData.supplier,
|
console.log('当前页码:', page);
|
||||||
isApplied: formData.isEnabled
|
},
|
||||||
});
|
handleImport() {
|
||||||
this.$message.success('模型添加成功');
|
console.log('导入配置');
|
||||||
},
|
},
|
||||||
editModel(model) {
|
handleExport() {
|
||||||
this.editModelData = {
|
console.log('导出配置');
|
||||||
code: model.code,
|
},
|
||||||
name: model.candidateName,
|
handleModelSave(formData) {
|
||||||
supplier: model.supplier,
|
console.log('保存的模型数据:', formData);
|
||||||
};
|
},
|
||||||
this.editDialogVisible = true;
|
selectAll() {
|
||||||
},
|
console.log('全选');
|
||||||
deleteModel(model) {
|
},
|
||||||
console.log('删除:', model);
|
handleAddConfirm(newModel) {
|
||||||
},
|
console.log('新增模型数据:', newModel);
|
||||||
handleCurrentChange(page) {
|
|
||||||
this.currentPage = page;
|
|
||||||
console.log('当前页码:', page);
|
|
||||||
},
|
|
||||||
handleImportExport() {
|
|
||||||
console.log('导入导出');
|
|
||||||
},
|
|
||||||
handleModelSave(formData) {
|
|
||||||
console.log('保存的模型数据:', formData);
|
|
||||||
},
|
|
||||||
selectAll() {
|
|
||||||
console.log('全选');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
</script>
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.welcome {
|
.breadcrumbs{
|
||||||
min-width: 900px;
|
/* padding: 10px 0 0 5px; */
|
||||||
min-height: 506px;
|
}
|
||||||
height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
background-image: url("@/assets/home/background.png");
|
|
||||||
background-size: cover;
|
|
||||||
background-position: center;
|
|
||||||
-webkit-background-size: cover;
|
|
||||||
-o-background-size: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
.model-container {
|
::v-deep .el-table tr{
|
||||||
display: flex;
|
background: transparent;
|
||||||
margin-top: 25px;
|
}
|
||||||
}
|
.welcome {
|
||||||
|
min-width: 900px;
|
||||||
|
min-height: 506px;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
flex-direction: column;
|
||||||
|
background-size: cover;
|
||||||
|
background: linear-gradient(to bottom right, #dce8ff, #e4eeff, #e6cbfd) center;
|
||||||
|
-webkit-background-size: cover;
|
||||||
|
-o-background-size: cover;
|
||||||
|
}
|
||||||
|
|
||||||
.el-menu-vertical-demo {
|
.main-wrapper {
|
||||||
width: 250px;
|
/* margin: 5px 24px; */
|
||||||
margin-right: 20px;
|
background-image: url("@/assets/home/background.png");
|
||||||
background-color: #f8f9fa;
|
border-radius: 15px;
|
||||||
}
|
min-height: 600px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
.content-container {
|
.operation-bar {
|
||||||
flex: 1;
|
display: flex;
|
||||||
display: flex;
|
justify-content: space-between;
|
||||||
flex-direction: column;
|
align-items: center;
|
||||||
}
|
/* padding: 16px 24px; */
|
||||||
|
}
|
||||||
|
|
||||||
.model-header {
|
.content-panel {
|
||||||
display: flex;
|
flex: 1;
|
||||||
justify-content: space-between;
|
display: flex;
|
||||||
align-items: center;
|
overflow: hidden;
|
||||||
margin-bottom: 20px;
|
height: 100%;
|
||||||
}
|
border-radius: 15px;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
.model-search-operate {
|
.nav-panel {
|
||||||
display: flex;
|
width: 18%;
|
||||||
align-items: center;
|
min-width: 200px;
|
||||||
}
|
height: 100%;
|
||||||
|
border-right: 1px solid #ebeef5;
|
||||||
|
background-size: cover;
|
||||||
|
background: url("../assets/model/model.png") no-repeat center;
|
||||||
|
padding: 16px 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
.model-search-operate > * {
|
.nav-panel .el-menu-item {
|
||||||
margin-right: 10px;
|
height: 48px;
|
||||||
}
|
line-height: 48px;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
display: flex !important;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding-right: 12px !important;
|
||||||
|
width: fit-content;
|
||||||
|
margin: 8px 12px 8px auto;
|
||||||
|
min-width: unset;
|
||||||
|
}
|
||||||
|
|
||||||
.el-table__header th {
|
.nav-panel .el-menu-item.is-active {
|
||||||
background-color: #f5f7fa;
|
background-image:linear-gradient(-45deg,#ecf5ff,#cfe4f9);
|
||||||
color: #606266;
|
/* background: #ecf5ff; */
|
||||||
font-weight: 500;
|
color: #409EFF;
|
||||||
}
|
border-right: 3px solid #409EFF;
|
||||||
|
}
|
||||||
|
|
||||||
.model-card {
|
.nav-panel .el-menu-item:hover {
|
||||||
background: #fff;
|
background-image:linear-gradient(-45deg,#ecf5ff,#cfe4f9);
|
||||||
border-radius: 12px;
|
}
|
||||||
padding: 20px;
|
|
||||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.import-export-btn {
|
.content-area {
|
||||||
margin-bottom: 20px;
|
flex: 1;
|
||||||
display: flex;
|
padding: 24px;
|
||||||
justify-content: flex-end;
|
height: 100%;
|
||||||
margin-right: 40px;
|
min-width: 600px;
|
||||||
}
|
overflow-x: auto;
|
||||||
|
|
||||||
.pagination-container {
|
}
|
||||||
margin-top: 20px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-footer {
|
.title-bar {
|
||||||
margin-top: 20px;
|
display: flex;
|
||||||
display: flex;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
margin-bottom: 24px;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
.footer-btn {
|
.model-title {
|
||||||
margin-right: 10px;
|
font-size: 18px;
|
||||||
}
|
color: #303133;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.copyright {
|
.action-group {
|
||||||
font-size: 12px;
|
display: flex;
|
||||||
font-weight: 400;
|
align-items: center;
|
||||||
color: #979db1;
|
gap: 16px;
|
||||||
margin-top: auto;
|
}
|
||||||
padding-top: 30px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-btn {
|
.search-group {
|
||||||
padding: 0 8px;
|
display: flex;
|
||||||
}
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.header-cell {
|
.search-input {
|
||||||
font-weight: 500;
|
width: 240px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-btn {
|
||||||
|
background: linear-gradient(135deg, #6B8CFF, #A966FF);
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table {
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: transparent !important;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table /deep/ .el-table__row {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-header th {
|
||||||
|
background-color: transparent !important;
|
||||||
|
color: #606266;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-footer {
|
||||||
|
margin-top: 24px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16px 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copyright {
|
||||||
|
text-align: center;
|
||||||
|
color: #979db1;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
margin-top: auto;
|
||||||
|
padding: 30px 0 20px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-btn {
|
||||||
|
color: #409EFF !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-btn {
|
||||||
|
color: #F56C6C !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-btn {
|
||||||
|
background: #87CEFA;
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
padding: 8px 16px;
|
||||||
|
}
|
||||||
|
.title-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.batch-actions .el-button:first-child {
|
||||||
|
background: linear-gradient(135deg, #409EFF, #6B8CFF);
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-actions .el-button:first-child:hover {
|
||||||
|
background: linear-gradient(135deg, #3A8EE6, #5A7CFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-table th /deep/ .el-table__cell {
|
||||||
|
overflow: hidden;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
.add-btn {
|
|
||||||
margin-right: 830px;
|
|
||||||
padding: 8px 16px;
|
|
||||||
border-radius: 4px;
|
|
||||||
background-color: #409eff;
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -24,9 +24,9 @@
|
|||||||
type="selection"
|
type="selection"
|
||||||
width="55">
|
width="55">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="用户Id" prop="user_id"></el-table-column>
|
<el-table-column label="用户Id" prop="userid"></el-table-column>
|
||||||
<el-table-column label="手机号码" prop="mobile"></el-table-column>
|
<el-table-column label="手机号码" prop="mobile"></el-table-column>
|
||||||
<el-table-column label="设备数量" prop="device_count"></el-table-column>
|
<el-table-column label="设备数量" prop="deviceCount"></el-table-column>
|
||||||
<el-table-column label="状态" prop="status"></el-table-column>
|
<el-table-column label="状态" prop="status"></el-table-column>
|
||||||
<el-table-column label="操作">
|
<el-table-column label="操作">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
@@ -77,6 +77,7 @@ import adminApi from '@/apis/module/admin';
|
|||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
name: 'UserManagement',
|
||||||
components: { HeaderBar },
|
components: { HeaderBar },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -95,7 +96,7 @@ export default {
|
|||||||
created() {
|
created() {
|
||||||
adminApi.getUserList(({data}) => {
|
adminApi.getUserList(({data}) => {
|
||||||
//mock偶尔会返回-1导致出错,又会返回两个list,所以这里只取第一个
|
//mock偶尔会返回-1导致出错,又会返回两个list,所以这里只取第一个
|
||||||
this.userList = data.data[0].list;
|
this.userList = data.data.list;
|
||||||
console.log('用户列表:', this.userList);
|
console.log('用户列表:', this.userList);
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -198,6 +198,7 @@ export default {
|
|||||||
margin-left: 75px;
|
margin-left: 75px;
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
width: fit-content;
|
||||||
|
|
||||||
.left-add {
|
.left-add {
|
||||||
width: 105px;
|
width: 105px;
|
||||||
|
|||||||
@@ -36,11 +36,11 @@
|
|||||||
<!-- 分页 -->
|
<!-- 分页 -->
|
||||||
<el-pagination background :current-page="page.pageNo" :page-size="page.pageSize" :pager-count="5" layout="prev, pager, next" :total="page.total" style="margin-top: 4px;text-align: right;"></el-pagination>
|
<el-pagination background :current-page="page.pageNo" :page-size="page.pageSize" :pager-count="5" layout="prev, pager, next" :total="page.total" style="margin-top: 4px;text-align: right;"></el-pagination>
|
||||||
</div>
|
</div>
|
||||||
<!-- 底部 -->
|
|
||||||
<Footer :visible="true" />
|
|
||||||
<!-- 添加设备OTA对话框 -->
|
|
||||||
<AddDeviceOtaDialog :visible.sync="addDeviceOtaDialogVisible" :data="otaData" @confirmSave="handleSaveDeviceOta" @confirmUpdate="handleUpdateDeviceOta" />
|
|
||||||
</el-main>
|
</el-main>
|
||||||
|
<!-- 底部 -->
|
||||||
|
<Footer :visible="true" />
|
||||||
|
<!-- 添加设备OTA对话框 -->
|
||||||
|
<AddDeviceOtaDialog :visible.sync="addDeviceOtaDialogVisible" :data="otaData" @confirmSave="handleSaveDeviceOta" @confirmUpdate="handleUpdateDeviceOta" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -37,8 +37,8 @@
|
|||||||
<div style="display: flex;gap: 8px;align-items: center;">
|
<div style="display: flex;gap: 8px;align-items: center;">
|
||||||
<div style="flex:1;">
|
<div style="flex:1;">
|
||||||
<el-select v-model="form.ttsVoiceId" placeholder="请选择" style="width: 100%;">
|
<el-select v-model="form.ttsVoiceId" placeholder="请选择" style="width: 100%;">
|
||||||
<el-option v-for="item in options" :key="item.value" :label="item.label"
|
<el-option v-for="item in ttsVoices" :key="item.id" :label="item.name"
|
||||||
:value="item.value">
|
:value="item.id">
|
||||||
</el-option>
|
</el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
@@ -65,8 +65,8 @@
|
|||||||
<template slot="label">
|
<template slot="label">
|
||||||
<div style="line-height: 20px;">{{model.label}}</div>
|
<div style="line-height: 20px;">{{model.label}}</div>
|
||||||
</template>
|
</template>
|
||||||
<el-select v-model="form.model[model.key]" filterable placeholder="请选择" style="width: 100%;">
|
<el-select v-model="form[model.key+'ModelId']" filterable placeholder="请选择" style="width: 100%;" disabled>
|
||||||
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"/>
|
<el-option v-for="item in model.list" :key="item.id" :label="item.modelName" :value="item.id"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="" class="lh-form-item" style="margin-top: -25px;">
|
<el-form-item label="" class="lh-form-item" style="margin-top: -25px;">
|
||||||
@@ -98,6 +98,7 @@
|
|||||||
import Api from '@/apis/api';
|
import Api from '@/apis/api';
|
||||||
import HeaderBar from "@/components/HeaderBar.vue";
|
import HeaderBar from "@/components/HeaderBar.vue";
|
||||||
import Footer from "@/components/Footer.vue";
|
import Footer from "@/components/Footer.vue";
|
||||||
|
import {getUUID, goToPage, showDanger, showSuccess} from '@/utils'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'RoleConfigPage',
|
name: 'RoleConfigPage',
|
||||||
@@ -105,41 +106,37 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
agentId: this.$route.query.agentId,
|
agentId: this.$route.query.agentId,
|
||||||
agentName: this.$route.query.agentName,
|
|
||||||
form: {
|
form: {
|
||||||
agentCode:"",
|
agentCode:"",
|
||||||
agentName:"",
|
agentName:"",
|
||||||
asrModelId:"",
|
asrModelId:"",
|
||||||
intentModelId:"",
|
intentModelId:"",
|
||||||
llmModelId:"",
|
llmModelId:"",
|
||||||
memModelId:"",
|
memoryModelId:"",
|
||||||
systemPrompt:"",
|
systemPrompt:"",
|
||||||
ttsModelId:"",
|
ttsModelId:"",
|
||||||
ttsVoiceId:"",
|
ttsVoiceId:"",
|
||||||
vadModelId:"",
|
vadModelId:"",
|
||||||
model:{}
|
model:{}
|
||||||
},
|
},
|
||||||
options: [
|
ttsVoices: [],
|
||||||
{ value: '选项1', label: '黄金糕' },
|
models: [
|
||||||
{ value: '选项2', label: '双皮奶' }
|
{ label: '大语言模型(LLM)', key: 'llm', list: [] },
|
||||||
|
{ label: '语音转文本模型(ASR)', key: 'asr', list: [] },
|
||||||
|
{ label: '语音活动检测模型(VAD)', key: 'vad', list: [] },
|
||||||
|
{ label: '语音生成模型(TTS)', key: 'tts', list: [] },
|
||||||
|
{ label: '意图分类模型(Intent)', key: 'intent', list: [] },
|
||||||
|
{ label: '记忆增强模型(Memory)', key: 'memory', list: [] }
|
||||||
],
|
],
|
||||||
models: [],
|
templates: []
|
||||||
//[
|
|
||||||
// { label: '大语言模型(LLM)', key: 'llm' },
|
|
||||||
// { label: '语音转文本模型(ASR)', key: 'asr' },
|
|
||||||
// { label: '语音活动检测模型(VAD)', key: 'vad' },
|
|
||||||
// { label: '语音生成模型(TTS)', key: 'tts' },
|
|
||||||
// { label: '意图分类模型(Intent)', key: 'intent' },
|
|
||||||
// { label: '记忆增强模型(Memory)', key: 'memory' }
|
|
||||||
// ],
|
|
||||||
templates: ['通用男声','通用女声','阳光男生','奶气萌娃']
|
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
// 获取智能体列表
|
// 获取智能体列表
|
||||||
this.fetchAgentTemplateList();
|
this.fetchAgentTemplateList();
|
||||||
this.handleGetConfig();
|
this.handleGetConfig();
|
||||||
|
this.fetchModelList();
|
||||||
|
this.getTtsVoicelList();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
fetchAgentTemplateList() {
|
fetchAgentTemplateList() {
|
||||||
@@ -152,6 +149,30 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
fetchModelList() {
|
||||||
|
// 获取模型配置列表
|
||||||
|
Api.model.getModelList(({data}) => {
|
||||||
|
if (data.code === 0) {
|
||||||
|
let models = data.data;
|
||||||
|
this.models.map(model => {
|
||||||
|
model.list = models.filter(item => item.modelType.toLowerCase() === model.key)
|
||||||
|
})
|
||||||
|
console.log("models", this.models)
|
||||||
|
} else {
|
||||||
|
showDanger(data.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getTtsVoicelList(ttsModelId) {
|
||||||
|
// 获取智能体列表
|
||||||
|
Api.model.getTtsVoiceList(ttsModelId || '',({data}) => {
|
||||||
|
if (data.code === 0) {
|
||||||
|
this.ttsVoices = data.data
|
||||||
|
} else {
|
||||||
|
showDanger(data.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
handleGetConfig(){
|
handleGetConfig(){
|
||||||
Api.agent.getAgentConfig(this.agentId, ({data}) => {
|
Api.agent.getAgentConfig(this.agentId, ({data}) => {
|
||||||
if (data.code === 0) {
|
if (data.code === 0) {
|
||||||
@@ -163,7 +184,13 @@ export default {
|
|||||||
},
|
},
|
||||||
saveConfig() {
|
saveConfig() {
|
||||||
// 此处写保存配置逻辑
|
// 此处写保存配置逻辑
|
||||||
this.$message.success('配置已保存')
|
Api.agent.saveAgentConfig(this.agentId, this.form, ({data}) => {
|
||||||
|
if (data.code === 0) {
|
||||||
|
showSuccess('保存成功')
|
||||||
|
} else {
|
||||||
|
showDanger(data.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
resetConfig() {
|
resetConfig() {
|
||||||
this.$confirm('确定要重置配置吗?', '提示', {
|
this.$confirm('确定要重置配置吗?', '提示', {
|
||||||
@@ -185,8 +212,18 @@ export default {
|
|||||||
},
|
},
|
||||||
// 处理选择模板的逻辑
|
// 处理选择模板的逻辑
|
||||||
selectTemplate(template) {
|
selectTemplate(template) {
|
||||||
this.form.name = template;
|
Object.assign(this.form,{
|
||||||
this.$message.success(`已选择模板:${template}`);
|
agentCode: template.agentCode,
|
||||||
|
llmModelId: template.llmModelId,
|
||||||
|
asrModelId: template.asrModelId,
|
||||||
|
vadModelId: template.vadModelId,
|
||||||
|
ttsModelId: template.ttsModelId,
|
||||||
|
ttsVoiceId: template.ttsVoiceId,
|
||||||
|
intentModelId: template.intentModelId,
|
||||||
|
memoryModelId: template.memoryModelId,
|
||||||
|
systemPrompt: template.systemPrompt
|
||||||
|
})
|
||||||
|
this.$message.success(`已选择模板:${template.agentName}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,22 +39,22 @@ class AccessToken:
|
|||||||
'Version': '2019-02-28'}
|
'Version': '2019-02-28'}
|
||||||
# 构造规范化的请求字符串
|
# 构造规范化的请求字符串
|
||||||
query_string = AccessToken._encode_dict(parameters)
|
query_string = AccessToken._encode_dict(parameters)
|
||||||
print('规范化的请求字符串: %s' % query_string)
|
# print('规范化的请求字符串: %s' % query_string)
|
||||||
# 构造待签名字符串
|
# 构造待签名字符串
|
||||||
string_to_sign = 'GET' + '&' + AccessToken._encode_text('/') + '&' + AccessToken._encode_text(query_string)
|
string_to_sign = 'GET' + '&' + AccessToken._encode_text('/') + '&' + AccessToken._encode_text(query_string)
|
||||||
print('待签名的字符串: %s' % string_to_sign)
|
# print('待签名的字符串: %s' % string_to_sign)
|
||||||
# 计算签名
|
# 计算签名
|
||||||
secreted_string = hmac.new(bytes(access_key_secret + '&', encoding='utf-8'),
|
secreted_string = hmac.new(bytes(access_key_secret + '&', encoding='utf-8'),
|
||||||
bytes(string_to_sign, encoding='utf-8'),
|
bytes(string_to_sign, encoding='utf-8'),
|
||||||
hashlib.sha1).digest()
|
hashlib.sha1).digest()
|
||||||
signature = base64.b64encode(secreted_string)
|
signature = base64.b64encode(secreted_string)
|
||||||
print('签名: %s' % signature)
|
# print('签名: %s' % signature)
|
||||||
# 进行URL编码
|
# 进行URL编码
|
||||||
signature = AccessToken._encode_text(signature)
|
signature = AccessToken._encode_text(signature)
|
||||||
print('URL编码后的签名: %s' % signature)
|
# print('URL编码后的签名: %s' % signature)
|
||||||
# 调用服务
|
# 调用服务
|
||||||
full_url = 'http://nls-meta.cn-shanghai.aliyuncs.com/?Signature=%s&%s' % (signature, query_string)
|
full_url = 'http://nls-meta.cn-shanghai.aliyuncs.com/?Signature=%s&%s' % (signature, query_string)
|
||||||
print('url: %s' % full_url)
|
# print('url: %s' % full_url)
|
||||||
# 提交HTTP GET请求
|
# 提交HTTP GET请求
|
||||||
response = requests.get(full_url)
|
response = requests.get(full_url)
|
||||||
if response.ok:
|
if response.ok:
|
||||||
@@ -64,7 +64,7 @@ class AccessToken:
|
|||||||
token = root_obj[key]['Id']
|
token = root_obj[key]['Id']
|
||||||
expire_time = root_obj[key]['ExpireTime']
|
expire_time = root_obj[key]['ExpireTime']
|
||||||
return token, expire_time
|
return token, expire_time
|
||||||
print(response.text)
|
# print(response.text)
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
|
|
||||||
@@ -75,37 +75,80 @@ class TTSProvider(TTSProviderBase):
|
|||||||
super().__init__(config, delete_audio_file)
|
super().__init__(config, delete_audio_file)
|
||||||
|
|
||||||
# 新增空值判断逻辑
|
# 新增空值判断逻辑
|
||||||
access_key_id = config.get("access_key_id")
|
self.access_key_id = config.get("access_key_id")
|
||||||
access_key_secret = config.get("access_key_secret")
|
self.access_key_secret = config.get("access_key_secret")
|
||||||
if access_key_id and access_key_secret:
|
|
||||||
# 使用密钥对生成临时token
|
|
||||||
token, expire_time = AccessToken.create_token(access_key_id, access_key_secret)
|
|
||||||
else:
|
|
||||||
# 直接使用预生成的长期token
|
|
||||||
token = config.get("token")
|
|
||||||
expire_time = None
|
|
||||||
|
|
||||||
print('token: %s, expire time(s): %s' % (token, expire_time))
|
|
||||||
|
|
||||||
self.appkey = config.get("appkey")
|
self.appkey = config.get("appkey")
|
||||||
self.token = token
|
|
||||||
self.format = config.get("format", "wav")
|
self.format = config.get("format", "wav")
|
||||||
self.sample_rate = config.get("sample_rate", 16000)
|
self.sample_rate = config.get("sample_rate", 16000)
|
||||||
self.voice = config.get("voice", "xiaoyun")
|
self.voice = config.get("voice", "xiaoyun")
|
||||||
self.volume = config.get("volume", 50)
|
self.volume = config.get("volume", 50)
|
||||||
self.speech_rate = config.get("speech_rate", 0)
|
self.speech_rate = config.get("speech_rate", 0)
|
||||||
self.pitch_rate = config.get("pitch_rate", 0)
|
self.pitch_rate = config.get("pitch_rate", 0)
|
||||||
|
|
||||||
self.host = config.get("host", "nls-gateway-cn-shanghai.aliyuncs.com")
|
self.host = config.get("host", "nls-gateway-cn-shanghai.aliyuncs.com")
|
||||||
self.api_url = f"https://{self.host}/stream/v1/tts"
|
self.api_url = f"https://{self.host}/stream/v1/tts"
|
||||||
self.header = {
|
self.header = {
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.access_key_id and self.access_key_secret:
|
||||||
|
# 使用密钥对生成临时token
|
||||||
|
self._refresh_token()
|
||||||
|
else:
|
||||||
|
# 直接使用预生成的长期token
|
||||||
|
self.token = config.get("token")
|
||||||
|
self.expire_time = None
|
||||||
|
|
||||||
|
|
||||||
|
def _refresh_token(self):
|
||||||
|
"""刷新Token并记录过期时间"""
|
||||||
|
if self.access_key_id and self.access_key_secret:
|
||||||
|
self.token, expire_time_str = AccessToken.create_token(
|
||||||
|
self.access_key_id,
|
||||||
|
self.access_key_secret
|
||||||
|
)
|
||||||
|
if not expire_time_str:
|
||||||
|
raise ValueError("无法获取有效的Token过期时间")
|
||||||
|
|
||||||
|
try:
|
||||||
|
#统一转换为字符串处理
|
||||||
|
expire_str = str(expire_time_str).strip()
|
||||||
|
|
||||||
|
if expire_str.isdigit():
|
||||||
|
expire_time = datetime.fromtimestamp(int(expire_str))
|
||||||
|
else:
|
||||||
|
expire_time = datetime.strptime(
|
||||||
|
expire_str,
|
||||||
|
"%Y-%m-%dT%H:%M:%SZ"
|
||||||
|
)
|
||||||
|
self.expire_time = expire_time.timestamp() - 60
|
||||||
|
except Exception as e:
|
||||||
|
raise ValueError(f"无效的过期时间格式: {expire_str}") from e
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.expire_time = None
|
||||||
|
|
||||||
|
if not self.token:
|
||||||
|
raise ValueError("无法获取有效的访问Token")
|
||||||
|
|
||||||
|
def _is_token_expired(self):
|
||||||
|
"""检查Token是否过期"""
|
||||||
|
if not self.expire_time:
|
||||||
|
return False # 长期Token不过期
|
||||||
|
# 新增调试日志
|
||||||
|
# current_time = time.time()
|
||||||
|
# remaining = self.expire_time - current_time
|
||||||
|
# print(f"Token过期检查: 当前时间 {datetime.fromtimestamp(current_time)} | "
|
||||||
|
# f"过期时间 {datetime.fromtimestamp(self.expire_time)} | "
|
||||||
|
# f"剩余 {remaining:.2f}秒")
|
||||||
|
return time.time() > self.expire_time
|
||||||
def generate_filename(self, extension=".wav"):
|
def generate_filename(self, extension=".wav"):
|
||||||
return os.path.join(self.output_file, f"tts-{__name__}{datetime.now().date()}@{uuid.uuid4().hex}{extension}")
|
return os.path.join(self.output_file, f"tts-{__name__}{datetime.now().date()}@{uuid.uuid4().hex}{extension}")
|
||||||
|
|
||||||
async def text_to_speak(self, text, output_file):
|
async def text_to_speak(self, text, output_file):
|
||||||
|
if self._is_token_expired():
|
||||||
|
logger.warning("Token已过期,正在自动刷新...")
|
||||||
|
self._refresh_token()
|
||||||
request_json = {
|
request_json = {
|
||||||
"appkey": self.appkey,
|
"appkey": self.appkey,
|
||||||
"token": self.token,
|
"token": self.token,
|
||||||
@@ -118,9 +161,12 @@ class TTSProvider(TTSProviderBase):
|
|||||||
"pitch_rate": self.pitch_rate
|
"pitch_rate": self.pitch_rate
|
||||||
}
|
}
|
||||||
|
|
||||||
print(self.api_url, json.dumps(request_json, ensure_ascii=False))
|
# print(self.api_url, json.dumps(request_json, ensure_ascii=False))
|
||||||
try:
|
try:
|
||||||
resp = requests.post(self.api_url, json.dumps(request_json), headers=self.header)
|
resp = requests.post(self.api_url, json.dumps(request_json), headers=self.header)
|
||||||
|
if resp.status_code == 401: # Token过期特殊处理
|
||||||
|
self._refresh_token()
|
||||||
|
resp = requests.post(self.api_url, json.dumps(request_json), headers=self.header)
|
||||||
# 检查返回请求数据的mime类型是否是audio/***,是则保存到指定路径下;返回的是binary格式的
|
# 检查返回请求数据的mime类型是否是audio/***,是则保存到指定路径下;返回的是binary格式的
|
||||||
if resp.headers['Content-Type'].startswith('audio/'):
|
if resp.headers['Content-Type'].startswith('audio/'):
|
||||||
with open(output_file, 'wb') as f:
|
with open(output_file, 'wb') as f:
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ get_lunar_function_desc = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
@register_function('get_lunar', get_lunar_function_desc, ToolType.WAIT)
|
@register_function('get_lunar', get_lunar_function_desc, ToolType.WAIT)
|
||||||
def get_lunar(query):
|
def get_lunar(query=None):
|
||||||
"""
|
"""
|
||||||
用于获取当前的阴历/农历,和天干地支、节气、生肖、星座、八字、宜忌等黄历信息
|
用于获取当前的阴历/农历,和天干地支、节气、生肖、星座、八字、宜忌等黄历信息
|
||||||
"""
|
"""
|
||||||
@@ -54,6 +54,10 @@ def get_lunar(query):
|
|||||||
current_time = now.strftime("%H:%M:%S")
|
current_time = now.strftime("%H:%M:%S")
|
||||||
current_date = now.strftime("%Y-%m-%d")
|
current_date = now.strftime("%Y-%m-%d")
|
||||||
current_weekday = now.strftime("%A")
|
current_weekday = now.strftime("%A")
|
||||||
|
|
||||||
|
# 如果 query 为 None,则使用默认文本
|
||||||
|
if query is None:
|
||||||
|
query = "默认查询干支年和农历日期"
|
||||||
response_text = f"根据以下信息回应用户的查询请求,并提供与{query}相关的信息:\n"
|
response_text = f"根据以下信息回应用户的查询请求,并提供与{query}相关的信息:\n"
|
||||||
|
|
||||||
lunar = cnlunar.Lunar(now, godType='8char')
|
lunar = cnlunar.Lunar(now, godType='8char')
|
||||||
|
|||||||
Reference in New Issue
Block a user