mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-22 07:03:53 +08:00
Merge pull request #2794 from xinnan-tech/20260104SSL
拓展首页的搜索栏-支持同时搜索设备mac和智能体名字
This commit is contained in:
+8
-2
@@ -73,9 +73,13 @@ public class AgentController {
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获取用户智能体列表")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
public Result<List<AgentDTO>> getUserAgents() {
|
||||
public Result<List<AgentDTO>> getUserAgents(
|
||||
@RequestParam(value = "keyword", required = false) String keyword,
|
||||
@RequestParam(value = "searchType", defaultValue = "name") String searchType) {
|
||||
UserDetail user = SecurityUser.getUser();
|
||||
List<AgentDTO> agents = agentService.getUserAgents(user.getId());
|
||||
|
||||
// 直接调用整合后的getUserAgents方法,无需再区分搜索和普通查询
|
||||
List<AgentDTO> agents = agentService.getUserAgents(user.getId(), keyword, searchType);
|
||||
return new Result<List<AgentDTO>>().ok(agents);
|
||||
}
|
||||
|
||||
@@ -271,4 +275,6 @@ public class AgentController {
|
||||
.body(audioData);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package xiaozhi.modules.agent.dto;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@@ -54,9 +54,11 @@ public interface AgentService extends BaseService<AgentEntity> {
|
||||
* 获取用户智能体列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param keyword 搜索关键词
|
||||
* @param searchType 搜索类型(name - 按名称搜索,mac - 按MAC地址搜索)
|
||||
* @return 智能体列表
|
||||
*/
|
||||
List<AgentDTO> getUserAgents(Long userId);
|
||||
List<AgentDTO> getUserAgents(Long userId, String keyword, String searchType);
|
||||
|
||||
/**
|
||||
* 根据智能体ID获取设备数量
|
||||
@@ -98,4 +100,6 @@ public interface AgentService extends BaseService<AgentEntity> {
|
||||
* @return 创建的智能体ID
|
||||
*/
|
||||
String createAgent(AgentCreateDTO dto);
|
||||
|
||||
|
||||
}
|
||||
|
||||
+67
-28
@@ -42,6 +42,7 @@ import xiaozhi.modules.agent.service.AgentPluginMappingService;
|
||||
import xiaozhi.modules.agent.service.AgentService;
|
||||
import xiaozhi.modules.agent.service.AgentTemplateService;
|
||||
import xiaozhi.modules.agent.vo.AgentInfoVO;
|
||||
import xiaozhi.modules.device.entity.DeviceEntity;
|
||||
import xiaozhi.modules.device.service.DeviceService;
|
||||
import xiaozhi.modules.model.dto.ModelProviderDTO;
|
||||
import xiaozhi.modules.model.dto.VoiceDTO;
|
||||
@@ -88,13 +89,13 @@ public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> imp
|
||||
agent.setChatHistoryConf(Constant.ChatHistoryConfEnum.RECORD_TEXT_AUDIO.getCode());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 查询上下文源配置
|
||||
AgentContextProviderEntity contextProviderEntity = agentContextProviderService.getByAgentId(id);
|
||||
if (contextProviderEntity != null) {
|
||||
agent.setContextProviders(contextProviderEntity.getContextProviders());
|
||||
}
|
||||
|
||||
|
||||
// 无需额外查询插件列表,已通过SQL查询出来
|
||||
return agent;
|
||||
}
|
||||
@@ -127,38 +128,75 @@ public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> imp
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AgentDTO> getUserAgents(Long userId) {
|
||||
QueryWrapper<AgentEntity> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq("user_id", userId);
|
||||
List<AgentEntity> agents = agentDao.selectList(wrapper);
|
||||
return agents.stream().map(agent -> {
|
||||
AgentDTO dto = new AgentDTO();
|
||||
dto.setId(agent.getId());
|
||||
dto.setAgentName(agent.getAgentName());
|
||||
dto.setSystemPrompt(agent.getSystemPrompt());
|
||||
public List<AgentDTO> getUserAgents(Long userId, String keyword, String searchType) {
|
||||
QueryWrapper<AgentEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("user_id", userId);
|
||||
|
||||
// 获取 TTS 模型名称
|
||||
dto.setTtsModelName(modelConfigService.getModelNameById(agent.getTtsModelId()));
|
||||
// 如果有搜索关键词,根据搜索类型添加相应的查询条件
|
||||
if (StringUtils.isNotBlank(keyword)) {
|
||||
if ("mac".equals(searchType)) {
|
||||
// 按MAC地址搜索:先搜索设备,再获取对应的智能体
|
||||
List<DeviceEntity> devices = deviceService.searchDevicesByMacAddress(keyword, userId);
|
||||
|
||||
// 获取 LLM 模型名称
|
||||
dto.setLlmModelName(modelConfigService.getModelNameById(agent.getLlmModelId()));
|
||||
if (!devices.isEmpty()) {
|
||||
// 获取设备对应的智能体ID列表
|
||||
List<String> agentIds = devices.stream()
|
||||
.map(DeviceEntity::getAgentId)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 获取 VLLM 模型名称
|
||||
dto.setVllmModelName(modelConfigService.getModelNameById(agent.getVllmModelId()));
|
||||
if (!agentIds.isEmpty()) {
|
||||
queryWrapper.in("id", agentIds);
|
||||
} else {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
} else {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
} else {
|
||||
// 按名称搜索
|
||||
queryWrapper.like("agent_name", keyword);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取记忆模型名称
|
||||
dto.setMemModelId(agent.getMemModelId());
|
||||
// 执行查询
|
||||
List<AgentEntity> agentEntities = baseDao.selectList(queryWrapper);
|
||||
|
||||
// 获取 TTS 音色名称
|
||||
dto.setTtsVoiceName(timbreModelService.getTimbreNameById(agent.getTtsVoiceId()));
|
||||
// 转换为DTO并设置所有必要字段
|
||||
return agentEntities.stream().map(this::buildAgentDTO).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// 获取智能体最近的最后连接时长
|
||||
dto.setLastConnectedAt(deviceService.getLatestLastConnectionTime(agent.getId()));
|
||||
/**
|
||||
* 将AgentEntity转换为AgentDTO
|
||||
*/
|
||||
private AgentDTO buildAgentDTO(AgentEntity agent) {
|
||||
AgentDTO dto = new AgentDTO();
|
||||
dto.setId(agent.getId());
|
||||
dto.setAgentName(agent.getAgentName());
|
||||
dto.setSystemPrompt(agent.getSystemPrompt());
|
||||
|
||||
// 获取设备数量
|
||||
dto.setDeviceCount(getDeviceCountByAgentId(agent.getId()));
|
||||
return dto;
|
||||
}).collect(Collectors.toList());
|
||||
// 获取 TTS 模型名称
|
||||
dto.setTtsModelName(modelConfigService.getModelNameById(agent.getTtsModelId()));
|
||||
|
||||
// 获取 LLM 模型名称
|
||||
dto.setLlmModelName(modelConfigService.getModelNameById(agent.getLlmModelId()));
|
||||
|
||||
// 获取 VLLM 模型名称
|
||||
dto.setVllmModelName(modelConfigService.getModelNameById(agent.getVllmModelId()));
|
||||
|
||||
// 获取记忆模型名称
|
||||
dto.setMemModelId(agent.getMemModelId());
|
||||
|
||||
// 获取 TTS 音色名称
|
||||
dto.setTtsVoiceName(timbreModelService.getTimbreNameById(agent.getTtsVoiceId()));
|
||||
|
||||
// 获取智能体最近的最后连接时长
|
||||
dto.setLastConnectedAt(deviceService.getLatestLastConnectionTime(agent.getId()));
|
||||
|
||||
// 获取设备数量
|
||||
dto.setDeviceCount(getDeviceCountByAgentId(agent.getId()));
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -468,4 +506,5 @@ public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> imp
|
||||
agentPluginMappingService.saveBatch(toInsert);
|
||||
return entity.getId();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -108,4 +108,13 @@ public interface DeviceService extends BaseService<DeviceEntity> {
|
||||
*/
|
||||
String generateWebSocketToken(String clientId, String username) throws Exception;
|
||||
|
||||
/**
|
||||
* 根据MAC地址搜索设备
|
||||
*
|
||||
* @param macAddress MAC地址关键词
|
||||
* @param userId 用户ID
|
||||
* @return 设备列表
|
||||
*/
|
||||
List<DeviceEntity> searchDevicesByMacAddress(String macAddress, Long userId);
|
||||
|
||||
}
|
||||
+8
@@ -496,6 +496,14 @@ public class DeviceServiceImpl extends BaseServiceImpl<DeviceDao, DeviceEntity>
|
||||
redisUtils.delete(RedisKeys.getAgentDeviceCountById(dto.getAgentId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DeviceEntity> searchDevicesByMacAddress(String macAddress, Long userId) {
|
||||
QueryWrapper<DeviceEntity> wrapper = new QueryWrapper<>();
|
||||
wrapper.like("mac_address", macAddress);
|
||||
wrapper.eq("user_id", userId);
|
||||
return deviceDao.selectList(wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成MQTT密码签名
|
||||
*
|
||||
|
||||
@@ -382,4 +382,20 @@ export default {
|
||||
});
|
||||
}).send();
|
||||
},
|
||||
|
||||
// 搜索智能体
|
||||
searchAgent(keyword, searchType, callback) {
|
||||
RequestService.sendRequest()
|
||||
.url(`${getServiceUrl()}/agent/list?keyword=${encodeURIComponent(keyword)}&searchType=${searchType}`)
|
||||
.method('GET')
|
||||
.success((res) => {
|
||||
RequestService.clearRequestTime();
|
||||
callback(res);
|
||||
})
|
||||
.networkFail(() => {
|
||||
RequestService.reAjaxFun(() => {
|
||||
this.searchAgent(keyword, searchType, callback);
|
||||
});
|
||||
}).send();
|
||||
},
|
||||
}
|
||||
|
||||
@@ -408,18 +408,8 @@ export default {
|
||||
// 保存搜索历史
|
||||
this.saveSearchHistory(searchValue);
|
||||
|
||||
try {
|
||||
// 创建不区分大小写的正则表达式
|
||||
const regex = new RegExp(searchValue, "i");
|
||||
// 触发搜索事件,将正则表达式传递给父组件
|
||||
this.$emit("search", regex);
|
||||
} catch (error) {
|
||||
console.error("正则表达式创建失败:", error);
|
||||
this.$message.error({
|
||||
message: this.$t("message.error"),
|
||||
showClose: true,
|
||||
});
|
||||
}
|
||||
// 触发搜索事件,将搜索关键词传递给父组件
|
||||
this.$emit("search", searchValue);
|
||||
|
||||
// 搜索完成后让输入框失去焦点,从而触发blur事件隐藏搜索历史
|
||||
if (this.$refs.searchInput) {
|
||||
|
||||
@@ -25,7 +25,7 @@ export default {
|
||||
'header.featureManagement': 'Systemfunktionsverwaltung',
|
||||
'header.changePassword': 'Passwort ändern',
|
||||
'header.logout': 'Abmelden',
|
||||
'header.searchPlaceholder': 'Nach Namen suchen..',
|
||||
'header.searchPlaceholder': 'Namen oder MAC suchen',
|
||||
|
||||
// McpToolCallDialog component text
|
||||
'mcpToolCall.title': 'Werkzeugaufruf',
|
||||
|
||||
@@ -25,7 +25,7 @@ export default {
|
||||
'header.featureManagement': 'System Feature Management',
|
||||
'header.changePassword': 'Change Password',
|
||||
'header.logout': 'Logout',
|
||||
'header.searchPlaceholder': 'Search by name..',
|
||||
'header.searchPlaceholder': 'Search name or mac',
|
||||
|
||||
// McpToolCallDialog component text
|
||||
'mcpToolCall.title': 'Tool Call',
|
||||
|
||||
@@ -25,7 +25,7 @@ export default {
|
||||
'header.featureManagement': 'Cấu hình chức năng hệ thống',
|
||||
'header.changePassword': 'Đổi mật khẩu',
|
||||
'header.logout': 'Đăng xuất',
|
||||
'header.searchPlaceholder': 'Tìm kiếm theo tên..',
|
||||
'header.searchPlaceholder': 'Tìm tên hoặc MAC',
|
||||
|
||||
// McpToolCallDialog component text
|
||||
'mcpToolCall.title': 'Gọi công cụ',
|
||||
|
||||
@@ -25,7 +25,7 @@ export default {
|
||||
'header.featureManagement': '系统功能配置',
|
||||
'header.changePassword': '修改密码',
|
||||
'header.logout': '退出登录',
|
||||
'header.searchPlaceholder': '输入名称搜索..',
|
||||
'header.searchPlaceholder': '输入名称或mac搜索',
|
||||
|
||||
// McpToolCallDialog组件文本
|
||||
'mcpToolCall.title': '工具调用',
|
||||
|
||||
@@ -25,7 +25,7 @@ export default {
|
||||
'header.featureManagement': '系統功能配置',
|
||||
'header.changePassword': '修改密碼',
|
||||
'header.logout': '退出登錄',
|
||||
'header.searchPlaceholder': '輸入名稱搜索..',
|
||||
'header.searchPlaceholder': '輸入名稱或mac搜索',
|
||||
|
||||
// McpToolCallDialog组件文本
|
||||
'mcpToolCall.title': '工具調用',
|
||||
|
||||
@@ -119,26 +119,32 @@ export default {
|
||||
handleDeviceManage() {
|
||||
this.$router.push('/device-management');
|
||||
},
|
||||
handleSearch(regex) {
|
||||
handleSearch(keyword) {
|
||||
this.isSearching = true;
|
||||
this.searchRegex = regex;
|
||||
this.applySearchFilter();
|
||||
this.isLoading = true;
|
||||
// 检测MAC地址格式:包含4个冒号
|
||||
const isMac = /^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$/.test(keyword)
|
||||
const searchType = isMac ? 'mac' : 'name';
|
||||
Api.agent.searchAgent(keyword, searchType, ({ data }) => {
|
||||
if (data?.data) {
|
||||
this.devices = data.data.map(item => ({
|
||||
...item,
|
||||
agentId: item.id
|
||||
}));
|
||||
}
|
||||
this.isLoading = false;
|
||||
}, (error) => {
|
||||
console.error('搜索智能体失败:', error);
|
||||
this.isLoading = false;
|
||||
this.$message.error(this.$t('message.searchFailed'));
|
||||
});
|
||||
},
|
||||
handleSearchReset() {
|
||||
this.isSearching = false;
|
||||
this.searchRegex = null;
|
||||
// 直接将原始设备列表赋值给显示设备列表,避免重新加载数据
|
||||
this.devices = [...this.originalDevices];
|
||||
},
|
||||
applySearchFilter() {
|
||||
if (!this.isSearching || !this.searchRegex) {
|
||||
this.devices = [...this.originalDevices];
|
||||
return;
|
||||
}
|
||||
|
||||
this.devices = this.originalDevices.filter(device => {
|
||||
return this.searchRegex.test(device.agentName);
|
||||
});
|
||||
},
|
||||
// 搜索更新智能体列表
|
||||
handleSearchResult(filteredList) {
|
||||
this.devices = filteredList; // 更新设备列表
|
||||
|
||||
Reference in New Issue
Block a user