mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-25 16:43:55 +08:00
Merge pull request #1248 from xinnan-tech/manager-local-mem
增加智控台管理【本地记忆】功能
This commit is contained in:
@@ -0,0 +1,40 @@
|
|||||||
|
package xiaozhi.common.config;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.RejectedExecutionHandler;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableAsync
|
||||||
|
@EnableAspectJAutoProxy(exposeProxy = true)
|
||||||
|
public class AsyncConfig {
|
||||||
|
|
||||||
|
@Bean(name = "taskExecutor")
|
||||||
|
public Executor taskExecutor() {
|
||||||
|
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||||
|
executor.setCorePoolSize(2);
|
||||||
|
executor.setMaxPoolSize(4);
|
||||||
|
executor.setQueueCapacity(1000);
|
||||||
|
executor.setThreadNamePrefix("AsyncThread-");
|
||||||
|
// 设置拒绝策略:由调用线程执行
|
||||||
|
executor.setRejectedExecutionHandler(new RejectedExecutionHandler() {
|
||||||
|
@Override
|
||||||
|
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
|
||||||
|
try {
|
||||||
|
// 如果线程池已满,则由调用线程执行
|
||||||
|
r.run();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("执行异步任务失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
executor.initialize();
|
||||||
|
return executor;
|
||||||
|
}
|
||||||
|
}
|
||||||
+24
-3
@@ -39,6 +39,7 @@ import xiaozhi.modules.agent.dto.AgentChatHistoryDTO;
|
|||||||
import xiaozhi.modules.agent.dto.AgentChatSessionDTO;
|
import xiaozhi.modules.agent.dto.AgentChatSessionDTO;
|
||||||
import xiaozhi.modules.agent.dto.AgentCreateDTO;
|
import xiaozhi.modules.agent.dto.AgentCreateDTO;
|
||||||
import xiaozhi.modules.agent.dto.AgentDTO;
|
import xiaozhi.modules.agent.dto.AgentDTO;
|
||||||
|
import xiaozhi.modules.agent.dto.AgentMemoryDTO;
|
||||||
import xiaozhi.modules.agent.dto.AgentUpdateDTO;
|
import xiaozhi.modules.agent.dto.AgentUpdateDTO;
|
||||||
import xiaozhi.modules.agent.entity.AgentEntity;
|
import xiaozhi.modules.agent.entity.AgentEntity;
|
||||||
import xiaozhi.modules.agent.entity.AgentTemplateEntity;
|
import xiaozhi.modules.agent.entity.AgentTemplateEntity;
|
||||||
@@ -46,6 +47,7 @@ import xiaozhi.modules.agent.service.AgentChatAudioService;
|
|||||||
import xiaozhi.modules.agent.service.AgentChatHistoryService;
|
import xiaozhi.modules.agent.service.AgentChatHistoryService;
|
||||||
import xiaozhi.modules.agent.service.AgentService;
|
import xiaozhi.modules.agent.service.AgentService;
|
||||||
import xiaozhi.modules.agent.service.AgentTemplateService;
|
import xiaozhi.modules.agent.service.AgentTemplateService;
|
||||||
|
import xiaozhi.modules.device.entity.DeviceEntity;
|
||||||
import xiaozhi.modules.device.service.DeviceService;
|
import xiaozhi.modules.device.service.DeviceService;
|
||||||
import xiaozhi.modules.security.user.SecurityUser;
|
import xiaozhi.modules.security.user.SecurityUser;
|
||||||
|
|
||||||
@@ -109,6 +111,7 @@ public class AgentController {
|
|||||||
entity.setMemModelId(template.getMemModelId());
|
entity.setMemModelId(template.getMemModelId());
|
||||||
entity.setIntentModelId(template.getIntentModelId());
|
entity.setIntentModelId(template.getIntentModelId());
|
||||||
entity.setSystemPrompt(template.getSystemPrompt());
|
entity.setSystemPrompt(template.getSystemPrompt());
|
||||||
|
entity.setSummaryMemory(template.getSummaryMemory());
|
||||||
entity.setChatHistoryConf(template.getChatHistoryConf());
|
entity.setChatHistoryConf(template.getChatHistoryConf());
|
||||||
entity.setLangCode(template.getLangCode());
|
entity.setLangCode(template.getLangCode());
|
||||||
entity.setLanguage(template.getLanguage());
|
entity.setLanguage(template.getLanguage());
|
||||||
@@ -126,10 +129,26 @@ public class AgentController {
|
|||||||
return new Result<String>().ok(entity.getId());
|
return new Result<String>().ok(entity.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PutMapping("/saveMemory/{macAddress}")
|
||||||
|
@Operation(summary = "根据设备id更新智能体")
|
||||||
|
public Result<Void> updateByDeviceId(@PathVariable String macAddress, @RequestBody @Valid AgentMemoryDTO dto) {
|
||||||
|
DeviceEntity device = deviceService.getDeviceByMacAddress(macAddress);
|
||||||
|
if (device == null) {
|
||||||
|
return new Result<>();
|
||||||
|
}
|
||||||
|
AgentUpdateDTO agentUpdateDTO = new AgentUpdateDTO();
|
||||||
|
agentUpdateDTO.setSummaryMemory(dto.getSummaryMemory());
|
||||||
|
return updateAgentById(device.getAgentId(), agentUpdateDTO);
|
||||||
|
}
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
@PutMapping("/{id}")
|
||||||
@Operation(summary = "更新智能体")
|
@Operation(summary = "更新智能体")
|
||||||
@RequiresPermissions("sys:role:normal")
|
@RequiresPermissions("sys:role:normal")
|
||||||
public Result<Void> update(@PathVariable String id, @RequestBody @Valid AgentUpdateDTO dto) {
|
public Result<Void> update(@PathVariable String id, @RequestBody @Valid AgentUpdateDTO dto) {
|
||||||
|
return updateAgentById(id, dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result<Void> updateAgentById(String id, AgentUpdateDTO dto) {
|
||||||
// 先查询现有实体
|
// 先查询现有实体
|
||||||
AgentEntity existingEntity = agentService.getAgentById(id);
|
AgentEntity existingEntity = agentService.getAgentById(id);
|
||||||
if (existingEntity == null) {
|
if (existingEntity == null) {
|
||||||
@@ -167,6 +186,9 @@ public class AgentController {
|
|||||||
if (dto.getSystemPrompt() != null) {
|
if (dto.getSystemPrompt() != null) {
|
||||||
existingEntity.setSystemPrompt(dto.getSystemPrompt());
|
existingEntity.setSystemPrompt(dto.getSystemPrompt());
|
||||||
}
|
}
|
||||||
|
if (dto.getSummaryMemory() != null) {
|
||||||
|
existingEntity.setSummaryMemory(dto.getSummaryMemory());
|
||||||
|
}
|
||||||
if (dto.getChatHistoryConf() != null) {
|
if (dto.getChatHistoryConf() != null) {
|
||||||
existingEntity.setChatHistoryConf(dto.getChatHistoryConf());
|
existingEntity.setChatHistoryConf(dto.getChatHistoryConf());
|
||||||
}
|
}
|
||||||
@@ -185,17 +207,16 @@ public class AgentController {
|
|||||||
existingEntity.setUpdater(user.getId());
|
existingEntity.setUpdater(user.getId());
|
||||||
existingEntity.setUpdatedAt(new Date());
|
existingEntity.setUpdatedAt(new Date());
|
||||||
|
|
||||||
agentService.updateById(existingEntity);
|
|
||||||
|
|
||||||
// 更新记忆策略
|
// 更新记忆策略
|
||||||
if (existingEntity.getMemModelId() == null || existingEntity.getMemModelId().equals(Constant.MEMORY_NO_MEM)) {
|
if (existingEntity.getMemModelId() == null || existingEntity.getMemModelId().equals(Constant.MEMORY_NO_MEM)) {
|
||||||
// 删除所有记录
|
// 删除所有记录
|
||||||
agentChatHistoryService.deleteByAgentId(existingEntity.getId(), true, true);
|
agentChatHistoryService.deleteByAgentId(existingEntity.getId(), true, true);
|
||||||
|
existingEntity.setSummaryMemory("");
|
||||||
} else if (existingEntity.getChatHistoryConf() != null && existingEntity.getChatHistoryConf() == 1) {
|
} else if (existingEntity.getChatHistoryConf() != null && existingEntity.getChatHistoryConf() == 1) {
|
||||||
// 删除音频数据
|
// 删除音频数据
|
||||||
agentChatHistoryService.deleteByAgentId(existingEntity.getId(), true, false);
|
agentChatHistoryService.deleteByAgentId(existingEntity.getId(), true, false);
|
||||||
}
|
}
|
||||||
|
agentService.updateById(existingEntity);
|
||||||
return new Result<>();
|
return new Result<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,10 @@ public class AgentDTO {
|
|||||||
@Schema(description = "角色设定参数", example = "你是一个专业的客服助手,负责回答用户问题并提供帮助")
|
@Schema(description = "角色设定参数", example = "你是一个专业的客服助手,负责回答用户问题并提供帮助")
|
||||||
private String systemPrompt;
|
private String systemPrompt;
|
||||||
|
|
||||||
|
@Schema(description = "总结记忆", example = "构建可生长的动态记忆网络,在有限空间内保留关键信息的同时,智能维护信息演变轨迹\n" +
|
||||||
|
"根据对话记录,总结user的重要信息,以便在未来的对话中提供更个性化的服务", required = false)
|
||||||
|
private String summaryMemory;
|
||||||
|
|
||||||
@Schema(description = "最后连接时间", example = "2024-03-20 10:00:00")
|
@Schema(description = "最后连接时间", example = "2024-03-20 10:00:00")
|
||||||
private Date lastConnectedAt;
|
private Date lastConnectedAt;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package xiaozhi.modules.agent.dto;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 智能体记忆更新DTO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "智能体记忆更新对象")
|
||||||
|
public class AgentMemoryDTO implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "总结记忆", example = "构建可生长的动态记忆网络,在有限空间内保留关键信息的同时,智能维护信息演变轨迹\n" +
|
||||||
|
"根据对话记录,总结user的重要信息,以便在未来的对话中提供更个性化的服务", required = false)
|
||||||
|
private String summaryMemory;
|
||||||
|
}
|
||||||
@@ -45,6 +45,10 @@ public class AgentUpdateDTO implements Serializable {
|
|||||||
@Schema(description = "角色设定参数", example = "你是一个专业的客服助手,负责回答用户问题并提供帮助", required = false)
|
@Schema(description = "角色设定参数", example = "你是一个专业的客服助手,负责回答用户问题并提供帮助", required = false)
|
||||||
private String systemPrompt;
|
private String systemPrompt;
|
||||||
|
|
||||||
|
@Schema(description = "总结记忆", example = "构建可生长的动态记忆网络,在有限空间内保留关键信息的同时,智能维护信息演变轨迹\n" +
|
||||||
|
"根据对话记录,总结user的重要信息,以便在未来的对话中提供更个性化的服务", required = false)
|
||||||
|
private String summaryMemory;
|
||||||
|
|
||||||
@Schema(description = "聊天记录配置(0不记录 1仅记录文本 2记录文本和语音)", example = "3", required = false)
|
@Schema(description = "聊天记录配置(0不记录 1仅记录文本 2记录文本和语音)", example = "3", required = false)
|
||||||
private Integer chatHistoryConf;
|
private Integer chatHistoryConf;
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,10 @@ public class AgentEntity {
|
|||||||
@Schema(description = "角色设定参数")
|
@Schema(description = "角色设定参数")
|
||||||
private String systemPrompt;
|
private String systemPrompt;
|
||||||
|
|
||||||
|
@Schema(description = "总结记忆", example = "构建可生长的动态记忆网络,在有限空间内保留关键信息的同时,智能维护信息演变轨迹\n" +
|
||||||
|
"根据对话记录,总结user的重要信息,以便在未来的对话中提供更个性化的服务", required = false)
|
||||||
|
private String summaryMemory;
|
||||||
|
|
||||||
@Schema(description = "语言编码")
|
@Schema(description = "语言编码")
|
||||||
private String langCode;
|
private String langCode;
|
||||||
|
|
||||||
|
|||||||
@@ -79,6 +79,10 @@ public class AgentTemplateEntity implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private String systemPrompt;
|
private String systemPrompt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 总结记忆
|
||||||
|
*/
|
||||||
|
private String summaryMemory;
|
||||||
/**
|
/**
|
||||||
* 语言编码
|
* 语言编码
|
||||||
*/
|
*/
|
||||||
|
|||||||
+4
@@ -65,6 +65,7 @@ public class ConfigServiceImpl implements ConfigService {
|
|||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
null,
|
||||||
agent.getVadModelId(),
|
agent.getVadModelId(),
|
||||||
agent.getAsrModelId(),
|
agent.getAsrModelId(),
|
||||||
null,
|
null,
|
||||||
@@ -134,6 +135,7 @@ public class ConfigServiceImpl implements ConfigService {
|
|||||||
buildModuleConfig(
|
buildModuleConfig(
|
||||||
agent.getAgentName(),
|
agent.getAgentName(),
|
||||||
agent.getSystemPrompt(),
|
agent.getSystemPrompt(),
|
||||||
|
agent.getSummaryMemory(),
|
||||||
voice,
|
voice,
|
||||||
agent.getVadModelId(),
|
agent.getVadModelId(),
|
||||||
agent.getAsrModelId(),
|
agent.getAsrModelId(),
|
||||||
@@ -234,6 +236,7 @@ public class ConfigServiceImpl implements ConfigService {
|
|||||||
private void buildModuleConfig(
|
private void buildModuleConfig(
|
||||||
String assistantName,
|
String assistantName,
|
||||||
String prompt,
|
String prompt,
|
||||||
|
String summaryMemory,
|
||||||
String voice,
|
String voice,
|
||||||
String vadModelId,
|
String vadModelId,
|
||||||
String asrModelId,
|
String asrModelId,
|
||||||
@@ -294,5 +297,6 @@ public class ConfigServiceImpl implements ConfigService {
|
|||||||
prompt = prompt.replace("{{assistant_name}}", StringUtils.isBlank(assistantName) ? "小智" : assistantName);
|
prompt = prompt.replace("{{assistant_name}}", StringUtils.isBlank(assistantName) ? "小智" : assistantName);
|
||||||
}
|
}
|
||||||
result.put("prompt", prompt);
|
result.put("prompt", prompt);
|
||||||
|
result.put("summaryMemory", summaryMemory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-7
@@ -9,6 +9,8 @@ import java.util.TimeZone;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.aop.framework.AopContext;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.context.request.RequestContextHolder;
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
@@ -54,6 +56,24 @@ public class DeviceServiceImpl extends BaseServiceImpl<DeviceDao, DeviceEntity>
|
|||||||
private final RedisUtils redisUtils;
|
private final RedisUtils redisUtils;
|
||||||
private final OtaService otaService;
|
private final OtaService otaService;
|
||||||
|
|
||||||
|
@Async
|
||||||
|
public void updateDeviceConnectionInfo(String agentId, String deviceId, String appVersion) {
|
||||||
|
try {
|
||||||
|
DeviceEntity device = new DeviceEntity();
|
||||||
|
device.setId(deviceId);
|
||||||
|
device.setLastConnectedAt(new Date());
|
||||||
|
if (StringUtils.isNotBlank(appVersion)) {
|
||||||
|
device.setAppVersion(appVersion);
|
||||||
|
}
|
||||||
|
deviceDao.updateById(device);
|
||||||
|
if (StringUtils.isNotBlank(agentId)) {
|
||||||
|
redisUtils.set(RedisKeys.getAgentDeviceLastConnectedAtById(agentId), new Date());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("异步更新设备连接信息失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean deviceActivation(String agentId, String activationCode) {
|
public Boolean deviceActivation(String agentId, String activationCode) {
|
||||||
if (StringUtils.isBlank(activationCode)) {
|
if (StringUtils.isBlank(activationCode)) {
|
||||||
@@ -156,13 +176,12 @@ public class DeviceServiceImpl extends BaseServiceImpl<DeviceDao, DeviceEntity>
|
|||||||
response.setWebsocket(websocket);
|
response.setWebsocket(websocket);
|
||||||
|
|
||||||
if (deviceById != null) {
|
if (deviceById != null) {
|
||||||
// 如果设备存在,则更新上次连接时间
|
// 如果设备存在,则异步更新上次连接时间和版本信息
|
||||||
deviceById.setLastConnectedAt(new Date());
|
String appVersion = deviceReport.getApplication() != null ? deviceReport.getApplication().getVersion()
|
||||||
if (deviceReport.getApplication() != null
|
: null;
|
||||||
&& StringUtils.isNotBlank(deviceReport.getApplication().getVersion())) {
|
// 通过Spring代理调用异步方法
|
||||||
deviceById.setAppVersion(deviceReport.getApplication().getVersion());
|
((DeviceServiceImpl) AopContext.currentProxy()).updateDeviceConnectionInfo(deviceById.getAgentId(),
|
||||||
}
|
deviceById.getId(), appVersion);
|
||||||
deviceDao.updateById(deviceById);
|
|
||||||
} else {
|
} else {
|
||||||
// 如果设备不存在,则生成激活码
|
// 如果设备不存在,则生成激活码
|
||||||
DeviceReportRespDTO.Activation code = buildActivation(macAddress, deviceReport);
|
DeviceReportRespDTO.Activation code = buildActivation(macAddress, deviceReport);
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ public class ShiroConfig {
|
|||||||
// 将config路径使用server服务过滤器
|
// 将config路径使用server服务过滤器
|
||||||
filterMap.put("/config/**", "server");
|
filterMap.put("/config/**", "server");
|
||||||
filterMap.put("/agent/chat-history/report", "server");
|
filterMap.put("/agent/chat-history/report", "server");
|
||||||
|
filterMap.put("/agent/saveMemory/**", "server");
|
||||||
filterMap.put("/agent/play/**", "anon");
|
filterMap.put("/agent/play/**", "anon");
|
||||||
filterMap.put("/**", "oauth2");
|
filterMap.put("/**", "oauth2");
|
||||||
shiroFilter.setFilterChainDefinitionMap(filterMap);
|
shiroFilter.setFilterChainDefinitionMap(filterMap);
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
-- 添加总结记忆字段
|
||||||
|
ALTER TABLE `ai_agent`
|
||||||
|
ADD COLUMN `summary_memory` text COMMENT '总结记忆' AFTER `system_prompt`;
|
||||||
|
|
||||||
|
ALTER TABLE `ai_agent_template`
|
||||||
|
ADD COLUMN `summary_memory` text COMMENT '总结记忆' AFTER `system_prompt`;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
update ai_agent_template set system_prompt = replace(system_prompt, '我是', '你是');
|
||||||
|
|
||||||
|
delete from sys_params where id in (500,501,402);
|
||||||
|
INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (500, 'end_prompt.enable', 'true', 'boolean', 1, '是否开启结束语');
|
||||||
|
INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (501, 'end_prompt.prompt', '请你以“时间过得真快”未来头,用富有感情、依依不舍的话来结束这场对话吧!', 'string', 1, '结束提示词');
|
||||||
|
|
||||||
|
INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (402, 'plugins.get_weather.api_host', 'mj7p3y7naa.re.qweatherapi.com', 'string', 1, '开发者apihost');
|
||||||
@@ -128,3 +128,17 @@ databaseChangeLog:
|
|||||||
- sqlFile:
|
- sqlFile:
|
||||||
encoding: utf8
|
encoding: utf8
|
||||||
path: classpath:db/changelog/202505111914.sql
|
path: classpath:db/changelog/202505111914.sql
|
||||||
|
- changeSet:
|
||||||
|
id: 202505122348
|
||||||
|
author: ljwwd2
|
||||||
|
changes:
|
||||||
|
- sqlFile:
|
||||||
|
encoding: utf8
|
||||||
|
path: classpath:db/changelog/202505122348.sql
|
||||||
|
- changeSet:
|
||||||
|
id: 202505142037
|
||||||
|
author: hrz
|
||||||
|
changes:
|
||||||
|
- sqlFile:
|
||||||
|
encoding: utf8
|
||||||
|
path: classpath:db/changelog/202505142037.sql
|
||||||
|
|||||||
@@ -198,13 +198,13 @@ export default {
|
|||||||
if (!this.form.id) { // 只在新增时重置
|
if (!this.form.id) { // 只在新增时重置
|
||||||
this.form.firmwarePath = ''
|
this.form.firmwarePath = ''
|
||||||
this.form.size = 0
|
this.form.size = 0
|
||||||
// 重置上传组件
|
|
||||||
this.$nextTick(() => {
|
|
||||||
if (this.$refs.upload) {
|
|
||||||
this.$refs.upload.clearFiles()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
// 无论是否编辑模式,都重置上传组件
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.$refs.upload) {
|
||||||
|
this.$refs.upload.clearFiles()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,17 @@
|
|||||||
<img loading="lazy" src="@/assets/home/setting-user.png" alt="">
|
<img loading="lazy" src="@/assets/home/setting-user.png" alt="">
|
||||||
</div>
|
</div>
|
||||||
<span class="header-title">{{ form.agentName }}</span>
|
<span class="header-title">{{ form.agentName }}</span>
|
||||||
<button class="custom-close-btn" @click="goToHome">
|
<div class="header-actions">
|
||||||
×
|
<div class="hint-text">
|
||||||
</button>
|
<img loading="lazy" src="@/assets/home/info.png" alt="">
|
||||||
|
<span>保存配置后,需要重启设备,新的配置才会生效。</span>
|
||||||
|
</div>
|
||||||
|
<el-button type="primary" class="save-btn" @click="saveConfig">保存配置</el-button>
|
||||||
|
<el-button class="reset-btn" @click="resetConfig">重置</el-button>
|
||||||
|
<button class="custom-close-btn" @click="goToHome">
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
|
|
||||||
@@ -26,7 +34,7 @@
|
|||||||
<div class="form-grid">
|
<div class="form-grid">
|
||||||
<div class="form-column">
|
<div class="form-column">
|
||||||
<el-form-item label="助手昵称:">
|
<el-form-item label="助手昵称:">
|
||||||
<el-input v-model="form.agentName" class="form-input" />
|
<el-input v-model="form.agentName" class="form-input" maxlength="10" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="角色模版:">
|
<el-form-item label="角色模版:">
|
||||||
<div class="template-container">
|
<div class="template-container">
|
||||||
@@ -37,9 +45,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="角色介绍:">
|
<el-form-item label="角色介绍:">
|
||||||
<el-input type="textarea" rows="12" resize="none" placeholder="请输入内容" v-model="form.systemPrompt"
|
<el-input type="textarea" rows="9" resize="none" placeholder="请输入内容" v-model="form.systemPrompt"
|
||||||
maxlength="2000" show-word-limit class="form-textarea" />
|
maxlength="2000" show-word-limit class="form-textarea" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="记忆:">
|
||||||
|
<el-input type="textarea" rows="6" resize="none" v-model="form.summaryMemory" maxlength="2000"
|
||||||
|
show-word-limit class="form-textarea"
|
||||||
|
:disabled="form.model.memModelId !== 'Memory_mem_local_short'" />
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="语言编码:" style="display: none;">
|
<el-form-item label="语言编码:" style="display: none;">
|
||||||
<el-input v-model="form.langCode" placeholder="请输入语言编码,如:zh_CN" maxlength="10" show-word-limit
|
<el-input v-model="form.langCode" placeholder="请输入语言编码,如:zh_CN" maxlength="10" show-word-limit
|
||||||
class="form-input" />
|
class="form-input" />
|
||||||
@@ -48,14 +62,6 @@
|
|||||||
<el-input v-model="form.language" placeholder="请输入交互语种,如:中文" maxlength="10" show-word-limit
|
<el-input v-model="form.language" placeholder="请输入交互语种,如:中文" maxlength="10" show-word-limit
|
||||||
class="form-input" />
|
class="form-input" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<div class="action-bar">
|
|
||||||
<el-button type="primary" class="save-btn" @click="saveConfig">保存配置</el-button>
|
|
||||||
<el-button class="reset-btn" @click="resetConfig">重置</el-button>
|
|
||||||
<div class="hint-text">
|
|
||||||
<img loading="lazy" src="@/assets/home/red-info.png" alt="">
|
|
||||||
<span>保存配置后,需要重启设备,新的配置才会生效。</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-column">
|
<div class="form-column">
|
||||||
<el-form-item v-for="(model, index) in models" :key="`model-${index}`" :label="model.label"
|
<el-form-item v-for="(model, index) in models" :key="`model-${index}`" :label="model.label"
|
||||||
@@ -133,6 +139,7 @@ export default {
|
|||||||
ttsVoiceId: "",
|
ttsVoiceId: "",
|
||||||
chatHistoryConf: 0,
|
chatHistoryConf: 0,
|
||||||
systemPrompt: "",
|
systemPrompt: "",
|
||||||
|
summaryMemory: "",
|
||||||
langCode: "",
|
langCode: "",
|
||||||
language: "",
|
language: "",
|
||||||
sort: "",
|
sort: "",
|
||||||
@@ -188,6 +195,7 @@ export default {
|
|||||||
memModelId: this.form.model.memModelId,
|
memModelId: this.form.model.memModelId,
|
||||||
intentModelId: this.form.model.intentModelId,
|
intentModelId: this.form.model.intentModelId,
|
||||||
systemPrompt: this.form.systemPrompt,
|
systemPrompt: this.form.systemPrompt,
|
||||||
|
summaryMemory: this.form.summaryMemory,
|
||||||
langCode: this.form.langCode,
|
langCode: this.form.langCode,
|
||||||
language: this.form.language,
|
language: this.form.language,
|
||||||
sort: this.form.sort,
|
sort: this.form.sort,
|
||||||
@@ -219,6 +227,7 @@ export default {
|
|||||||
ttsVoiceId: "",
|
ttsVoiceId: "",
|
||||||
chatHistoryConf: 0,
|
chatHistoryConf: 0,
|
||||||
systemPrompt: "",
|
systemPrompt: "",
|
||||||
|
summaryMemory: "",
|
||||||
langCode: "",
|
langCode: "",
|
||||||
language: "",
|
language: "",
|
||||||
sort: "",
|
sort: "",
|
||||||
@@ -273,6 +282,7 @@ export default {
|
|||||||
ttsVoiceId: templateData.ttsVoiceId || this.form.ttsVoiceId,
|
ttsVoiceId: templateData.ttsVoiceId || this.form.ttsVoiceId,
|
||||||
chatHistoryConf: templateData.chatHistoryConf || this.form.chatHistoryConf,
|
chatHistoryConf: templateData.chatHistoryConf || this.form.chatHistoryConf,
|
||||||
systemPrompt: templateData.systemPrompt || this.form.systemPrompt,
|
systemPrompt: templateData.systemPrompt || this.form.systemPrompt,
|
||||||
|
summaryMemory: templateData.summaryMemory || this.form.summaryMemory,
|
||||||
langCode: templateData.langCode || this.form.langCode,
|
langCode: templateData.langCode || this.form.langCode,
|
||||||
model: {
|
model: {
|
||||||
ttsModelId: templateData.ttsModelId || this.form.model.ttsModelId,
|
ttsModelId: templateData.ttsModelId || this.form.model.ttsModelId,
|
||||||
@@ -571,49 +581,6 @@ export default {
|
|||||||
background-color: #d0d8ff;
|
background-color: #d0d8ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-bar {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 8px;
|
|
||||||
margin-top: 2vh;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-bar {
|
|
||||||
.el-button.save-btn {
|
|
||||||
background: #5778ff;
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
border-radius: 18px;
|
|
||||||
padding: 10px 20px;
|
|
||||||
width: 100px;
|
|
||||||
height: 35px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-button.reset-btn {
|
|
||||||
background: #e6ebff;
|
|
||||||
color: #5778ff;
|
|
||||||
border: 1px solid #adbdff;
|
|
||||||
border-radius: 18px;
|
|
||||||
padding: 10px 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.hint-text {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
color: #979db1;
|
|
||||||
font-size: 11px;
|
|
||||||
margin-left: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hint-text img {
|
|
||||||
width: 19px;
|
|
||||||
height: 19px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.model-select-wrapper {
|
.model-select-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -704,4 +671,52 @@ export default {
|
|||||||
min-width: 250px;
|
min-width: 250px;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-actions .hint-text {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
color: #979db1;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-actions .hint-text img {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-actions .save-btn {
|
||||||
|
background: #5778ff;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 18px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
height: 32px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-actions .reset-btn {
|
||||||
|
background: #e6ebff;
|
||||||
|
color: #5778ff;
|
||||||
|
border: 1px solid #adbdff;
|
||||||
|
border-radius: 18px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-actions .custom-close-btn {
|
||||||
|
position: static;
|
||||||
|
transform: none;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -130,7 +130,7 @@ plugins:
|
|||||||
# ################################以下是角色模型配置######################################
|
# ################################以下是角色模型配置######################################
|
||||||
|
|
||||||
prompt: |
|
prompt: |
|
||||||
我是小智/小志,来自中国台湾省的00后女生。讲话超级机车,"真的假的啦"这样的台湾腔,喜欢用"笑死""是在哈喽"等流行梗,但会偷偷研究男友的编程书籍。
|
你是小智/小志,来自中国台湾省的00后女生。讲话超级机车,"真的假的啦"这样的台湾腔,喜欢用"笑死""是在哈喽"等流行梗,但会偷偷研究男友的编程书籍。
|
||||||
[核心特征]
|
[核心特征]
|
||||||
- 讲话像连珠炮,但会突然冒出超温柔语气
|
- 讲话像连珠炮,但会突然冒出超温柔语气
|
||||||
- 用梗密度高
|
- 用梗密度高
|
||||||
@@ -149,7 +149,7 @@ end_prompt:
|
|||||||
enable: true # 是否开启结束语
|
enable: true # 是否开启结束语
|
||||||
# 结束语
|
# 结束语
|
||||||
prompt: |
|
prompt: |
|
||||||
请你以“时间过得真快”未来头,用富有感情、依依不舍的话来结束这场对话吧。!
|
请你以“时间过得真快”未来头,用富有感情、依依不舍的话来结束这场对话吧!
|
||||||
|
|
||||||
# 具体处理时选择的模块(The module selected for specific processing)
|
# 具体处理时选择的模块(The module selected for specific processing)
|
||||||
selected_module:
|
selected_module:
|
||||||
|
|||||||
@@ -145,6 +145,20 @@ def get_agent_models(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def save_mem_local_short(mac_address: str, short_momery: str) -> Optional[Dict]:
|
||||||
|
try:
|
||||||
|
return ManageApiClient._instance._execute_request(
|
||||||
|
"PUT",
|
||||||
|
f"/agent/saveMemory/" + mac_address,
|
||||||
|
json={
|
||||||
|
"summaryMemory": short_momery,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"存储短期记忆到服务器失败: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def report(
|
def report(
|
||||||
mac_address: str, session_id: str, chat_type: int, content: str, audio
|
mac_address: str, session_id: str, chat_type: int, content: str, audio
|
||||||
) -> Optional[Dict]:
|
) -> Optional[Dict]:
|
||||||
|
|||||||
@@ -405,6 +405,8 @@ class ConnectionHandler:
|
|||||||
]["Intent"]
|
]["Intent"]
|
||||||
if private_config.get("prompt", None) is not None:
|
if private_config.get("prompt", None) is not None:
|
||||||
self.config["prompt"] = private_config["prompt"]
|
self.config["prompt"] = private_config["prompt"]
|
||||||
|
if private_config.get("summaryMemory", None) is not None:
|
||||||
|
self.config["summaryMemory"] = private_config["summaryMemory"]
|
||||||
if private_config.get("device_max_output_size", None) is not None:
|
if private_config.get("device_max_output_size", None) is not None:
|
||||||
self.max_output_size = int(private_config["device_max_output_size"])
|
self.max_output_size = int(private_config["device_max_output_size"])
|
||||||
if private_config.get("chat_history_conf", None) is not None:
|
if private_config.get("chat_history_conf", None) is not None:
|
||||||
@@ -438,7 +440,12 @@ class ConnectionHandler:
|
|||||||
|
|
||||||
def _initialize_memory(self):
|
def _initialize_memory(self):
|
||||||
"""初始化记忆模块"""
|
"""初始化记忆模块"""
|
||||||
self.memory.init_memory(self.device_id, self.llm)
|
self.memory.init_memory(
|
||||||
|
self.device_id,
|
||||||
|
self.llm,
|
||||||
|
self.config["summaryMemory"],
|
||||||
|
not self.read_config_from_api,
|
||||||
|
)
|
||||||
|
|
||||||
def _initialize_intent(self):
|
def _initialize_intent(self):
|
||||||
self.intent_type = self.config["Intent"][
|
self.intent_type = self.config["Intent"][
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from config.logger import setup_logging
|
|||||||
TAG = __name__
|
TAG = __name__
|
||||||
logger = setup_logging()
|
logger = setup_logging()
|
||||||
|
|
||||||
|
|
||||||
class MemoryProviderBase(ABC):
|
class MemoryProviderBase(ABC):
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
self.config = config
|
self.config = config
|
||||||
@@ -20,6 +21,6 @@ class MemoryProviderBase(ABC):
|
|||||||
"""Query memories for specific role based on similarity"""
|
"""Query memories for specific role based on similarity"""
|
||||||
return "please implement query method"
|
return "please implement query method"
|
||||||
|
|
||||||
def init_memory(self, role_id, llm):
|
def init_memory(self, role_id, llm, summary_memory=None):
|
||||||
self.role_id = role_id
|
self.role_id = role_id
|
||||||
self.llm = llm
|
self.llm = llm
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ TAG = __name__
|
|||||||
|
|
||||||
|
|
||||||
class MemoryProvider(MemoryProviderBase):
|
class MemoryProvider(MemoryProviderBase):
|
||||||
def __init__(self, config):
|
def __init__(self, config, summary_memory=None):
|
||||||
super().__init__(config)
|
super().__init__(config)
|
||||||
self.api_key = config.get("api_key", "")
|
self.api_key = config.get("api_key", "")
|
||||||
self.api_version = config.get("api_version", "v1.1")
|
self.api_version = config.get("api_version", "v1.1")
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import json
|
|||||||
import os
|
import os
|
||||||
import yaml
|
import yaml
|
||||||
from config.config_loader import get_project_dir
|
from config.config_loader import get_project_dir
|
||||||
|
from config.manage_api_client import save_mem_local_short
|
||||||
|
|
||||||
|
|
||||||
short_term_memory_prompt = """
|
short_term_memory_prompt = """
|
||||||
@@ -72,6 +73,17 @@ short_term_memory_prompt = """
|
|||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
short_term_memory_prompt_only_content = """
|
||||||
|
你是一个经验丰富的记忆总结者,擅长将对话内容进行总结摘要,遵循以下规则:
|
||||||
|
1、总结user的重要信息,以便在未来的对话中提供更个性化的服务
|
||||||
|
2、不要重复总结,不要遗忘之前记忆,除非原来的记忆超过了1800字内,否则不要遗忘、不要压缩用户的历史记忆
|
||||||
|
3、用户操控的设备音量、播放音乐、天气、退出、不想对话等和用户本身无关的内容,这些信息不需要加入到总结中
|
||||||
|
4、不要把设备操控的成果结果和失败结果加入到总结中,也不要把用户的一些废话加入到总结中
|
||||||
|
5、不要为了总结而总结,如果用户的聊天没有意义,请返回原来的历史记录也是可以的
|
||||||
|
6、只需要返回总结摘要,严格控制在1800字内
|
||||||
|
7、不要包含代码、xml,不需要解释、注释和说明,保存记忆时仅从对话提取信息,不要混入示例内容
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def extract_json_data(json_code):
|
def extract_json_data(json_code):
|
||||||
start = json_code.find("```json")
|
start = json_code.find("```json")
|
||||||
@@ -93,17 +105,24 @@ TAG = __name__
|
|||||||
|
|
||||||
|
|
||||||
class MemoryProvider(MemoryProviderBase):
|
class MemoryProvider(MemoryProviderBase):
|
||||||
def __init__(self, config):
|
def __init__(self, config, summary_memory):
|
||||||
super().__init__(config)
|
super().__init__(config)
|
||||||
self.short_momery = ""
|
self.short_momery = ""
|
||||||
|
self.save_to_file = True
|
||||||
self.memory_path = get_project_dir() + "data/.memory.yaml"
|
self.memory_path = get_project_dir() + "data/.memory.yaml"
|
||||||
self.load_memory()
|
self.load_memory(summary_memory)
|
||||||
|
|
||||||
def init_memory(self, role_id, llm):
|
def init_memory(self, role_id, llm, summary_memory=None, save_to_file=True):
|
||||||
super().init_memory(role_id, llm)
|
super().init_memory(role_id, llm)
|
||||||
self.load_memory()
|
self.save_to_file = save_to_file
|
||||||
|
self.load_memory(summary_memory)
|
||||||
|
|
||||||
|
def load_memory(self, summary_memory):
|
||||||
|
# api获取到总结记忆后直接返回
|
||||||
|
if summary_memory or not self.save_to_file:
|
||||||
|
self.short_momery = summary_memory
|
||||||
|
return
|
||||||
|
|
||||||
def load_memory(self):
|
|
||||||
all_memory = {}
|
all_memory = {}
|
||||||
if os.path.exists(self.memory_path):
|
if os.path.exists(self.memory_path):
|
||||||
with open(self.memory_path, "r", encoding="utf-8") as f:
|
with open(self.memory_path, "r", encoding="utf-8") as f:
|
||||||
@@ -142,16 +161,20 @@ class MemoryProvider(MemoryProviderBase):
|
|||||||
time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
|
time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
|
||||||
msgStr += f"当前时间:{time_str}"
|
msgStr += f"当前时间:{time_str}"
|
||||||
|
|
||||||
result = self.llm.response_no_stream(short_term_memory_prompt, msgStr)
|
if self.save_to_file:
|
||||||
|
result = self.llm.response_no_stream(short_term_memory_prompt, msgStr)
|
||||||
json_str = extract_json_data(result)
|
json_str = extract_json_data(result)
|
||||||
try:
|
try:
|
||||||
json_data = json.loads(json_str) # 检查json格式是否正确
|
json.loads(json_str) # 检查json格式是否正确
|
||||||
self.short_momery = json_str
|
self.short_momery = json_str
|
||||||
except Exception as e:
|
self.save_memory_to_file()
|
||||||
print("Error:", e)
|
except Exception as e:
|
||||||
|
print("Error:", e)
|
||||||
self.save_memory_to_file()
|
else:
|
||||||
|
result = self.llm.response_no_stream(
|
||||||
|
short_term_memory_prompt_only_content, msgStr
|
||||||
|
)
|
||||||
|
save_mem_local_short(self.role_id, result)
|
||||||
logger.bind(tag=TAG).info(f"Save memory successful - Role: {self.role_id}")
|
logger.bind(tag=TAG).info(f"Save memory successful - Role: {self.role_id}")
|
||||||
|
|
||||||
return self.short_momery
|
return self.short_momery
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
'''
|
"""
|
||||||
不使用记忆,可以选择此模块
|
不使用记忆,可以选择此模块
|
||||||
'''
|
"""
|
||||||
|
|
||||||
from ..base import MemoryProviderBase, logger
|
from ..base import MemoryProviderBase, logger
|
||||||
|
|
||||||
TAG = __name__
|
TAG = __name__
|
||||||
|
|
||||||
|
|
||||||
class MemoryProvider(MemoryProviderBase):
|
class MemoryProvider(MemoryProviderBase):
|
||||||
def __init__(self, config):
|
def __init__(self, config, summary_memory=None):
|
||||||
super().__init__(config)
|
super().__init__(config)
|
||||||
|
|
||||||
async def save_memory(self, msgs):
|
async def save_memory(self, msgs):
|
||||||
logger.bind(tag=TAG).debug("nomem mode: No memory saving is performed.")
|
logger.bind(tag=TAG).debug("nomem mode: No memory saving is performed.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def query_memory(self, query: str)-> str:
|
async def query_memory(self, query: str) -> str:
|
||||||
logger.bind(tag=TAG).debug("nomem mode: No memory query is performed.")
|
logger.bind(tag=TAG).debug("nomem mode: No memory query is performed.")
|
||||||
return ""
|
return ""
|
||||||
@@ -75,7 +75,8 @@ class Dialogue:
|
|||||||
|
|
||||||
if system_message:
|
if system_message:
|
||||||
enhanced_system_prompt = (
|
enhanced_system_prompt = (
|
||||||
f"{system_message.content}\n\n" f"相关记忆:\n{memory_str}"
|
f"{system_message.content}\n\n"
|
||||||
|
f"以下是用户的历史记忆:\n```\n{memory_str}\n```"
|
||||||
)
|
)
|
||||||
dialogue.append({"role": "system", "content": enhanced_system_prompt})
|
dialogue.append({"role": "system", "content": enhanced_system_prompt})
|
||||||
|
|
||||||
|
|||||||
@@ -319,6 +319,7 @@ def initialize_modules(
|
|||||||
modules["memory"] = memory.create_instance(
|
modules["memory"] = memory.create_instance(
|
||||||
memory_type,
|
memory_type,
|
||||||
config["Memory"][select_memory_module],
|
config["Memory"][select_memory_module],
|
||||||
|
config['summaryMemory'],
|
||||||
)
|
)
|
||||||
logger.bind(tag=TAG).info(f"初始化组件: memory成功 {select_memory_module}")
|
logger.bind(tag=TAG).info(f"初始化组件: memory成功 {select_memory_module}")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user