mirror of
https://github.com/slhaf/Partner.git
synced 2026-05-12 08:43:02 +08:00
- 新建模块Partner-Api,推进Partner适配核心服务注册机制。
- 将原有的模块体系进一步区分,分离模型持有能力与调用能力,Model将有Module自身持有,可通过ActivateModel开启相应能力
This commit is contained in:
10
.idea/encodings.xml
generated
10
.idea/encodings.xml
generated
@@ -1,12 +1,14 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="Encoding">
|
<component name="Encoding">
|
||||||
|
<file url="file://$PROJECT_DIR$/Partner-Api/src/main/java" charset="UTF-8" />
|
||||||
|
<file url="file://$PROJECT_DIR$/Partner-Api/src/main/resources" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/Partner-Capability-Demo/src/main/java" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/Partner-Capability-Demo/src/main/java" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/Partner-Capability-Demo/src/main/resources" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/Partner-Capability-Demo/src/main/resources" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/Partner-Core/src/main/java" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/Partner-Main/src/main/java" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/Partner-Core/src/main/java/src/main/java" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/Partner-Main/src/main/java/src/main/java" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/Partner-Core/src/main/java/src/main/resources" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/Partner-Main/src/main/java/src/main/resources" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/Partner-Core/src/main/resources" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/Partner-Main/src/main/resources" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||||
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
5
.idea/misc.xml
generated
5
.idea/misc.xml
generated
@@ -1,5 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
|
<component name="EntryPointsManager">
|
||||||
|
<list size="1">
|
||||||
|
<item index="0" class="java.lang.String" itemvalue="work.slhaf.partner.api.capability.annotation.CapabilityMethod" />
|
||||||
|
</list>
|
||||||
|
</component>
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
<component name="MavenProjectsManager">
|
<component name="MavenProjectsManager">
|
||||||
<option name="originalFiles">
|
<option name="originalFiles">
|
||||||
|
|||||||
@@ -1,20 +1,30 @@
|
|||||||
autoDetectedPackages:
|
autoDetectedPackages:
|
||||||
- work.slhaf
|
- work.slhaf
|
||||||
enableAutoDetect: true
|
enableAutoDetect: true
|
||||||
entryDisplayConfig: null
|
entryDisplayConfig:
|
||||||
funcDisplayConfig: null
|
excludedPathPatterns: []
|
||||||
|
skipJsCss: true
|
||||||
|
funcDisplayConfig:
|
||||||
|
skipConstructors: false
|
||||||
|
skipFieldAccess: true
|
||||||
|
skipFieldChange: true
|
||||||
|
skipGetters: false
|
||||||
|
skipNonProjectPackages: false
|
||||||
|
skipPrivateMethods: false
|
||||||
|
skipSetters: false
|
||||||
ignoreSameClassCall: null
|
ignoreSameClassCall: null
|
||||||
ignoreSamePackageCall: null
|
ignoreSamePackageCall: null
|
||||||
includedPackagePrefixes: null
|
includedPackagePrefixes: null
|
||||||
includedParentClasses: null
|
includedParentClasses: null
|
||||||
maxColSize: null
|
maxColSize: 32
|
||||||
maxNumFirst: null
|
maxNumFirst: 12
|
||||||
maxNumFirstImportant: null
|
maxNumFirstImportant: 1024
|
||||||
maxNumHash: null
|
maxNumHash: 3
|
||||||
maxNumHashImportant: null
|
maxNumHashImportant: 256
|
||||||
maxObjectDepth: null
|
maxObjectDepth: 4
|
||||||
maxStrSize: null
|
maxStrSize: 4096
|
||||||
name: xcodemap-filter
|
name: xcodemap-filter
|
||||||
recordMode: null
|
recordMode: manual
|
||||||
sourceDisplayConfig: null
|
sourceDisplayConfig:
|
||||||
startOnDebug: null
|
color: blue
|
||||||
|
startOnDebug: false
|
||||||
|
|||||||
@@ -9,7 +9,15 @@
|
|||||||
<version>0.5.0</version>
|
<version>0.5.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>Partner-Core</artifactId>
|
<artifactId>Partner-Api</artifactId>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.reflections</groupId>
|
||||||
|
<artifactId>reflections</artifactId>
|
||||||
|
<version>0.10.2</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package work.slhaf.partner.api.capability;
|
||||||
|
|
||||||
|
|
||||||
|
public class BaseCoordinateManager {
|
||||||
|
}
|
||||||
@@ -0,0 +1,374 @@
|
|||||||
|
package work.slhaf.partner.api.capability;
|
||||||
|
|
||||||
|
import org.reflections.Reflections;
|
||||||
|
import org.reflections.scanners.Scanners;
|
||||||
|
import org.reflections.util.ClasspathHelper;
|
||||||
|
import org.reflections.util.ConfigurationBuilder;
|
||||||
|
import work.slhaf.partner.api.capability.annotation.*;
|
||||||
|
import work.slhaf.partner.api.capability.exception.*;
|
||||||
|
import work.slhaf.partner.api.capability.module.CapabilityHolder;
|
||||||
|
import work.slhaf.partner.api.capability.util.CapabilityUtil;
|
||||||
|
|
||||||
|
import java.lang.reflect.*;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static work.slhaf.partner.api.capability.util.CapabilityUtil.methodSignature;
|
||||||
|
|
||||||
|
|
||||||
|
public final class CapabilityRegisterFactory {
|
||||||
|
|
||||||
|
public static volatile CapabilityRegisterFactory capabilityRegisterFactory;
|
||||||
|
|
||||||
|
private Reflections reflections;
|
||||||
|
private final HashMap<String, Function<Object[], Object>> methodsRouterTable = new HashMap<>();
|
||||||
|
private final HashMap<String, Function<Object[], Object>> coordinatedMethodsRouterTable = new HashMap<>();
|
||||||
|
private final HashMap<Class<?>, Object> capabilityCoreInstances = new HashMap<>();
|
||||||
|
private final HashMap<Class<?>, Object> capabilityHolderInstances = new HashMap<>();
|
||||||
|
private Set<Class<?>> cores;
|
||||||
|
private Set<Class<?>> capabilities;
|
||||||
|
|
||||||
|
private CapabilityRegisterFactory() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CapabilityRegisterFactory getInstance() {
|
||||||
|
if (capabilityRegisterFactory == null) {
|
||||||
|
synchronized (CapabilityRegisterFactory.class) {
|
||||||
|
if (capabilityRegisterFactory == null) {
|
||||||
|
capabilityRegisterFactory = new CapabilityRegisterFactory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return capabilityRegisterFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void registerCapabilities(String scannerPath) {
|
||||||
|
setBasicVariable(scannerPath);
|
||||||
|
//检查可注册能力是否正常
|
||||||
|
statusCheck();
|
||||||
|
generateMethodsRouterTable();
|
||||||
|
generateCoordinatedMethodsRouterTable();
|
||||||
|
//扫描现有Capability, value为键,返回函数路由表, 函数路由表内部通过反射调用对应core的方法
|
||||||
|
injectCapability();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateCoordinatedMethodsRouterTable() {
|
||||||
|
Set<Method> methodsAnnotatedWith = reflections.getMethodsAnnotatedWith(Coordinated.class);
|
||||||
|
if (methodsAnnotatedWith.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
//获取所有CM实例
|
||||||
|
HashMap<String, Object> cognationManagerInstances = getCognationManagerInstances();
|
||||||
|
methodsAnnotatedWith.forEach(method -> {
|
||||||
|
String key = method.getAnnotation(Coordinated.class).capability() + "." + methodSignature(method);
|
||||||
|
Function<Object[], Object> function = args -> {
|
||||||
|
try {
|
||||||
|
return method.invoke(cognationManagerInstances.get(key), args);
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
coordinatedMethodsRouterTable.put(key, function);
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new FactoryExecuteFailedException("创建协调方法路由表出错", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private HashMap<String, Object> getCognationManagerInstances() throws InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
|
||||||
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
|
for (Class<? extends BaseCoordinateManager> c : reflections.getSubTypesOf(BaseCoordinateManager.class)) {
|
||||||
|
Constructor<? extends BaseCoordinateManager> constructor = c.getDeclaredConstructor();
|
||||||
|
BaseCoordinateManager instance = constructor.newInstance();
|
||||||
|
|
||||||
|
Arrays.stream(c.getMethods())
|
||||||
|
.filter(method -> method.isAnnotationPresent(Coordinated.class))
|
||||||
|
.forEach(method -> {
|
||||||
|
String key = method.getAnnotation(Coordinated.class).capability() + "." + methodSignature(method);
|
||||||
|
map.put(key, instance);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setBasicVariable(String scannerPath) {
|
||||||
|
setReflections(scannerPath);
|
||||||
|
setAnnotatedClasses();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setAnnotatedClasses() {
|
||||||
|
cores = reflections.getTypesAnnotatedWith(CapabilityCore.class);
|
||||||
|
capabilities = reflections.getTypesAnnotatedWith(Capability.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setReflections(String scannerPath) {
|
||||||
|
//后续可替换为根据传入的启动类获取路径
|
||||||
|
Collection<URL> urls = ClasspathHelper.forPackage(scannerPath);
|
||||||
|
reflections = new Reflections(
|
||||||
|
new ConfigurationBuilder()
|
||||||
|
.setUrls(urls)
|
||||||
|
.setScanners(
|
||||||
|
Scanners.TypesAnnotated,
|
||||||
|
Scanners.MethodsAnnotated,
|
||||||
|
Scanners.SubTypes,
|
||||||
|
Scanners.FieldsAnnotated
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateMethodsRouterTable() {
|
||||||
|
//扫描`@Capability`与`@CapabilityMethod`注解的类与方法
|
||||||
|
//将`capabilityValue.methodSignature`作为key,函数对象为通过反射拿到的core实例对应的方法
|
||||||
|
cores.forEach(core -> Arrays.stream(core.getMethods())
|
||||||
|
.filter(method -> method.isAnnotationPresent(CapabilityMethod.class))
|
||||||
|
.forEach(method -> {
|
||||||
|
Function<Object[], Object> function = args -> {
|
||||||
|
try {
|
||||||
|
return method.invoke(capabilityCoreInstances.get(core), args);
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
String key = core.getAnnotation(CapabilityCore.class).value() + "." + methodSignature(method);
|
||||||
|
if (methodsRouterTable.containsKey(key)) {
|
||||||
|
throw new DuplicateMethodException("重复注册能力方法: " + core.getPackage().getName() + "." + core.getSimpleName() + "#" + method.getName());
|
||||||
|
}
|
||||||
|
methodsRouterTable.put(key, function);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void injectCapability() {
|
||||||
|
//获取现有的`@InjectCapability`注解所在字段,并获取对应的类,通过动态代理注入对象
|
||||||
|
Set<Field> fields = reflections.getFieldsAnnotatedWith(InjectCapability.class);
|
||||||
|
//在动态代理内部,通过函数路由表调用对应的方法
|
||||||
|
createProxy(fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createProxy(Set<Field> fields) {
|
||||||
|
try {
|
||||||
|
for (Field field : fields) {
|
||||||
|
field.setAccessible(true);
|
||||||
|
Class<?> fieldType = field.getType();
|
||||||
|
Object instance = Proxy.newProxyInstance(
|
||||||
|
fieldType.getClassLoader(),
|
||||||
|
new Class[]{fieldType},
|
||||||
|
(proxy, method, objects) -> {
|
||||||
|
if (method.isAnnotationPresent(ToCoordinated.class)) {
|
||||||
|
String key = method.getDeclaringClass().getAnnotation(Capability.class).value() + "." + methodSignature(method);
|
||||||
|
return coordinatedMethodsRouterTable.get(key).apply(objects);
|
||||||
|
}
|
||||||
|
String key = fieldType.getAnnotation(Capability.class).value() + "." + methodSignature(method);
|
||||||
|
return methodsRouterTable.get(key).apply(objects);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
field.set(capabilityHolderInstances.get(field.getDeclaringClass()), instance);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ProxySetFailedException("代理设置失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void statusCheck() {
|
||||||
|
capabilityHolderCheck();
|
||||||
|
checkCountAndCapabilities();
|
||||||
|
checkCapabilityMethods();
|
||||||
|
checkCoordinatedMethods();
|
||||||
|
checkInjectCapability();
|
||||||
|
//检查完毕,设置core的实例类
|
||||||
|
setCapabilityCoreInstances();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkInjectCapability() {
|
||||||
|
reflections.getFieldsAnnotatedWith(InjectCapability.class).forEach(field -> {
|
||||||
|
if (!CapabilityHolder.class.isAssignableFrom(field.getDeclaringClass())) {
|
||||||
|
throw new UnMatchedCapabilityException("InjectCapability 注解只能用于CapabilityHolder的子类");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void capabilityHolderCheck() {
|
||||||
|
if (capabilityHolderInstances.isEmpty()) {
|
||||||
|
throw new EmptyCapabilityHolderException("Capability 持有者实例为空");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setCapabilityCoreInstances() {
|
||||||
|
try {
|
||||||
|
for (Class<?> core : cores) {
|
||||||
|
Constructor<?> constructor = core.getDeclaredConstructor();
|
||||||
|
constructor.setAccessible(true);
|
||||||
|
capabilityCoreInstances.put(core, constructor.newInstance());
|
||||||
|
}
|
||||||
|
} catch (InvocationTargetException | NoSuchMethodException | InstantiationException |
|
||||||
|
IllegalAccessException e) {
|
||||||
|
throw new CoreInstancesCreateFailedException("core实例创建失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkCoordinatedMethods() {
|
||||||
|
//检查各个capability中是否含有ToCoordinated注解
|
||||||
|
//如果含有,则需要查找AbstractCognationManager的子类,看这里是否有对应的Coordinated注解所在方法
|
||||||
|
Set<String> methodsToCoordinated = capabilities.stream()
|
||||||
|
.flatMap(capability -> Arrays.stream(capability.getDeclaredMethods()))
|
||||||
|
.filter(method -> method.isAnnotationPresent(ToCoordinated.class))
|
||||||
|
.map(method -> {
|
||||||
|
String capabilityValue = method.getDeclaringClass().getAnnotation(Capability.class).value();
|
||||||
|
return capabilityValue + "." + methodSignature(method);
|
||||||
|
})
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
if (!methodsToCoordinated.isEmpty()) {
|
||||||
|
Set<Class<? extends BaseCoordinateManager>> subTypesOfAbsCM = reflections.getSubTypesOf(BaseCoordinateManager.class);
|
||||||
|
Set<String> methodsCoordinated = getMethodsCoordinated(subTypesOfAbsCM);
|
||||||
|
if (!methodsCoordinated.equals(methodsToCoordinated)) {
|
||||||
|
// 找出缺少的协调方法
|
||||||
|
Set<String> missingMethods = new HashSet<>(methodsToCoordinated);
|
||||||
|
missingMethods.removeAll(methodsCoordinated);
|
||||||
|
|
||||||
|
// 找出多余的协调方法
|
||||||
|
Set<String> extraMethods = new HashSet<>(methodsCoordinated);
|
||||||
|
extraMethods.removeAll(methodsToCoordinated);
|
||||||
|
|
||||||
|
// 抛出异常或记录错误
|
||||||
|
if (!missingMethods.isEmpty()) {
|
||||||
|
throw new UnMatchedCoordinatedMethodException("缺少协调方法: " + String.join(", ", missingMethods));
|
||||||
|
}
|
||||||
|
if (!extraMethods.isEmpty()) {
|
||||||
|
throw new UnMatchedCoordinatedMethodException("发现多余的协调方法: " + String.join(", ", extraMethods));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> getMethodsCoordinated(Set<Class<? extends BaseCoordinateManager>> subTypesOfAbsCM) {
|
||||||
|
Set<String> methodsCoordinated = new HashSet<>();
|
||||||
|
for (Class<? extends BaseCoordinateManager> cm : subTypesOfAbsCM) {
|
||||||
|
Method[] methods = cm.getMethods();
|
||||||
|
for (Method method : methods) {
|
||||||
|
if (method.isAnnotationPresent(Coordinated.class)) {
|
||||||
|
methodsCoordinated.add(method.getAnnotation(Coordinated.class).capability() + "." + methodSignature(method));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return methodsCoordinated;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void checkCapabilityMethods() {
|
||||||
|
HashMap<String, List<Method>> capabilitiesMethods = getCapabilityMethods(capabilities);
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (Class<?> core : cores) {
|
||||||
|
List<Method> methodsWithAnnotation = Arrays.stream(core.getMethods())
|
||||||
|
.filter(method -> method.isAnnotationPresent(CapabilityMethod.class))
|
||||||
|
.toList();
|
||||||
|
List<Method> capabilityMethods = capabilitiesMethods.get(core.getAnnotation(CapabilityCore.class).value());
|
||||||
|
LackRecord lackRecord = checkMethodsMatched(methodsWithAnnotation, capabilityMethods);
|
||||||
|
if (lackRecord.hasNotEmptyRecord()) {
|
||||||
|
sb.append(lackRecord.toLackErrorMsg(core.getAnnotation(CapabilityCore.class).value()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!sb.isEmpty()) {
|
||||||
|
throw new UnMatchedCapabilityMethodException(sb.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private LackRecord checkMethodsMatched(List<Method> methodsWithAnnotation, List<Method> capabilityMethods) {
|
||||||
|
Set<String> collectedMethodsWithAnnotation = methodsWithAnnotation.stream()
|
||||||
|
.filter(method -> !method.isAnnotationPresent(ToCoordinated.class))
|
||||||
|
.map(CapabilityUtil::methodSignature)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
Set<String> collectedCapabilityMethods = capabilityMethods.stream()
|
||||||
|
.filter(method -> !method.isAnnotationPresent(ToCoordinated.class))
|
||||||
|
.map(CapabilityUtil::methodSignature)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
return checkMethodsMatched(collectedMethodsWithAnnotation, collectedCapabilityMethods);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LackRecord checkMethodsMatched(Set<String> collectedMethodsWithAnnotation, Set<String> collectedCapabilityMethods) {
|
||||||
|
List<String> coreLack = new ArrayList<>();
|
||||||
|
List<String> capLack = new ArrayList<>();
|
||||||
|
// 找出 core 中多余的方法
|
||||||
|
for (String coreSig : collectedMethodsWithAnnotation) {
|
||||||
|
if (!collectedCapabilityMethods.contains(coreSig)) {
|
||||||
|
capLack.add(coreSig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 找出 capability 中多余的方法
|
||||||
|
for (String capSig : collectedCapabilityMethods) {
|
||||||
|
if (!collectedMethodsWithAnnotation.contains(capSig)) {
|
||||||
|
coreLack.add(capSig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new LackRecord(coreLack, capLack);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private HashMap<String, List<Method>> getCapabilityMethods(Set<Class<?>> capabilities) {
|
||||||
|
HashMap<String, List<Method>> capabilityMethods = new HashMap<>();
|
||||||
|
capabilities.forEach(capability -> {
|
||||||
|
capabilityMethods.put(capability.getAnnotation(Capability.class).value(), Arrays.stream(capability.getMethods()).toList());
|
||||||
|
});
|
||||||
|
return capabilityMethods;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkCountAndCapabilities() {
|
||||||
|
if (cores.size() != capabilities.size()) {
|
||||||
|
throw new UnMatchedCapabilityException("Capability 注册异常: 已存在的CapabilityCore与Capability数量不匹配!");
|
||||||
|
}
|
||||||
|
if (!checkValuesMatched(cores, capabilities)) {
|
||||||
|
throw new UnMatchedCapabilityException("Capability 注册异常: 已存在的CapabilityCore与Capability不匹配!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean checkValuesMatched(Set<Class<?>> cores, Set<Class<?>> capabilities) {
|
||||||
|
Set<String> coresValues = new HashSet<>();
|
||||||
|
Set<String> capabilitiesValues = new HashSet<>();
|
||||||
|
for (Class<?> core : cores) {
|
||||||
|
CapabilityCore annotation = core.getAnnotation(CapabilityCore.class);
|
||||||
|
if (annotation != null) {
|
||||||
|
if (coresValues.contains(annotation.value())) {
|
||||||
|
throw new DuplicateCapabilityException(String.format("Capability 注册异常: 重复的Capability核心: %s", annotation.value()));
|
||||||
|
}
|
||||||
|
coresValues.add(annotation.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Class<?> capability : capabilities) {
|
||||||
|
Capability annotation = capability.getAnnotation(Capability.class);
|
||||||
|
if (annotation != null) {
|
||||||
|
if (capabilitiesValues.contains(annotation.value())) {
|
||||||
|
throw new DuplicateCapabilityException(String.format("Capability 注册异常: 重复的Capability接口: %s", annotation.value()));
|
||||||
|
}
|
||||||
|
capabilitiesValues.add(annotation.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return coresValues.equals(capabilitiesValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerModule(CapabilityHolder capabilityHolder) {
|
||||||
|
capabilityHolderInstances.put(capabilityHolder.getClass(), capabilityHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
record LackRecord(List<String> coreLack, List<String> capLack) {
|
||||||
|
public boolean hasNotEmptyRecord() {
|
||||||
|
return !coreLack.isEmpty() || !capLack.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toLackErrorMsg(String capabilityName) {
|
||||||
|
StringBuilder sb = new StringBuilder("\n").append(capabilityName).append("\n");
|
||||||
|
if (!coreLack.isEmpty()) {
|
||||||
|
sb.append("缺少Core方法:").append("\n").append(coreLack).append("\n");
|
||||||
|
}
|
||||||
|
if (!capLack.isEmpty()) {
|
||||||
|
sb.append("缺少Capability方法:").append("\n").append(capLack).append("\n");
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package work.slhaf.partner.core.cognation.capability.interfaces;
|
package work.slhaf.partner.api.capability.annotation;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package work.slhaf.partner.core.cognation.capability.interfaces;
|
package work.slhaf.partner.api.capability.annotation;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package work.slhaf.partner.api.capability.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
public @interface CapabilityMethod {
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package work.slhaf.partner.core.cognation.capability.interfaces;
|
package work.slhaf.partner.api.capability.annotation;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
@@ -11,5 +11,5 @@ import java.lang.annotation.Target;
|
|||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
public @interface Coordinated {
|
public @interface Coordinated {
|
||||||
String value();
|
String capability();
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package work.slhaf.partner.core.cognation.capability.interfaces;
|
package work.slhaf.partner.api.capability.annotation;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package work.slhaf.partner.core.cognation.capability.interfaces;
|
package work.slhaf.partner.api.capability.annotation;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
@@ -12,5 +12,4 @@ import java.lang.annotation.Target;
|
|||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface ToCoordinated {
|
public @interface ToCoordinated {
|
||||||
String value();
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package work.slhaf.partner.api.capability.exception;
|
||||||
|
|
||||||
|
public class CapabilityCheckFailedException extends RuntimeException {
|
||||||
|
public CapabilityCheckFailedException(String message) {
|
||||||
|
super("Capability注册失败: " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CapabilityCheckFailedException(String message, Throwable cause) {
|
||||||
|
super("Capability注册失败: " + message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package work.slhaf.partner.api.capability.exception;
|
||||||
|
|
||||||
|
public class CoreInstancesCreateFailedException extends FactoryExecuteFailedException {
|
||||||
|
public CoreInstancesCreateFailedException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CoreInstancesCreateFailedException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package work.slhaf.partner.api.capability.exception;
|
||||||
|
|
||||||
|
public class DuplicateCapabilityException extends CapabilityCheckFailedException {
|
||||||
|
public DuplicateCapabilityException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DuplicateCapabilityException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package work.slhaf.partner.api.capability.exception;
|
||||||
|
|
||||||
|
public class DuplicateMethodException extends CapabilityCheckFailedException{
|
||||||
|
public DuplicateMethodException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DuplicateMethodException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package work.slhaf.partner.api.capability.exception;
|
||||||
|
|
||||||
|
public class EmptyCapabilityHolderException extends CapabilityCheckFailedException{
|
||||||
|
public EmptyCapabilityHolderException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EmptyCapabilityHolderException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package work.slhaf.partner.api.capability.exception;
|
||||||
|
|
||||||
|
public class FactoryExecuteFailedException extends RuntimeException {
|
||||||
|
public FactoryExecuteFailedException(String message) {
|
||||||
|
super("CapabilityRegisterFactory 执行失败: " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FactoryExecuteFailedException(String message, Throwable cause) {
|
||||||
|
super("CapabilityRegisterFactory 执行失败: " + message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package work.slhaf.partner.api.capability.exception;
|
||||||
|
|
||||||
|
public class ProxySetFailedException extends FactoryExecuteFailedException{
|
||||||
|
public ProxySetFailedException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProxySetFailedException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package work.slhaf.partner.api.capability.exception;
|
||||||
|
|
||||||
|
public class UnMatchedCapabilityException extends CapabilityCheckFailedException{
|
||||||
|
public UnMatchedCapabilityException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnMatchedCapabilityException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package work.slhaf.partner.api.capability.exception;
|
||||||
|
|
||||||
|
public class UnMatchedCapabilityMethodException extends CapabilityCheckFailedException {
|
||||||
|
public UnMatchedCapabilityMethodException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnMatchedCapabilityMethodException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package work.slhaf.partner.api.capability.exception;
|
||||||
|
|
||||||
|
public class UnMatchedCoordinatedMethodException extends CapabilityCheckFailedException {
|
||||||
|
public UnMatchedCoordinatedMethodException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnMatchedCoordinatedMethodException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package work.slhaf.partner.api.capability.module;
|
||||||
|
|
||||||
|
import work.slhaf.partner.api.capability.CapabilityRegisterFactory;
|
||||||
|
|
||||||
|
public abstract class CapabilityHolder {
|
||||||
|
protected CapabilityHolder() {
|
||||||
|
CapabilityRegisterFactory.getInstance().registerModule(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package work.slhaf.partner.api.capability.util;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
public final class CapabilityUtil {
|
||||||
|
public static String methodSignature(Method method) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("(");
|
||||||
|
sb.append(method.getReturnType().getName()).append(" ");
|
||||||
|
sb.append(method.getName()).append("(");
|
||||||
|
Class<?>[] paramTypes = method.getParameterTypes();
|
||||||
|
for (int i = 0; i < paramTypes.length; i++) {
|
||||||
|
sb.append(paramTypes[i].getName());
|
||||||
|
if (i < paramTypes.length - 1) sb.append(",");
|
||||||
|
}
|
||||||
|
sb.append(")").append(")");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,14 @@
|
|||||||
|
|
||||||
<artifactId>Partner-Capability-Demo</artifactId>
|
<artifactId>Partner-Capability-Demo</artifactId>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.reflections</groupId>
|
||||||
|
<artifactId>reflections</artifactId>
|
||||||
|
<version>0.10.2</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
<maven.compiler.target>21</maven.compiler.target>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package work.slhaf.demo;
|
package work.slhaf.demo;
|
||||||
|
|
||||||
import work.slhaf.demo.ability.CacheCapability;
|
|
||||||
import work.slhaf.demo.ability.MemoryCapability;
|
import work.slhaf.demo.ability.MemoryCapability;
|
||||||
import work.slhaf.demo.capability.annotation.InjectCapability;
|
import work.slhaf.demo.capability.annotation.InjectCapability;
|
||||||
import work.slhaf.demo.capability.module.CapabilityHolder;
|
import work.slhaf.demo.capability.module.CapabilityHolder;
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import org.reflections.Reflections;
|
|||||||
import org.reflections.scanners.Scanners;
|
import org.reflections.scanners.Scanners;
|
||||||
import org.reflections.util.ClasspathHelper;
|
import org.reflections.util.ClasspathHelper;
|
||||||
import org.reflections.util.ConfigurationBuilder;
|
import org.reflections.util.ConfigurationBuilder;
|
||||||
import work.slhaf.demo.capability.exception.*;
|
|
||||||
import work.slhaf.demo.capability.annotation.*;
|
import work.slhaf.demo.capability.annotation.*;
|
||||||
|
import work.slhaf.demo.capability.exception.*;
|
||||||
import work.slhaf.demo.capability.module.CapabilityHolder;
|
import work.slhaf.demo.capability.module.CapabilityHolder;
|
||||||
import work.slhaf.demo.capability.util.CapabilityUtil;
|
import work.slhaf.demo.capability.util.CapabilityUtil;
|
||||||
|
|
||||||
|
|||||||
5
Partner-Capability-Demo/src/test/java/InterfaceTest.java
Normal file
5
Partner-Capability-Demo/src/test/java/InterfaceTest.java
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
public interface InterfaceTest {
|
||||||
|
default String getName(){
|
||||||
|
return "111";
|
||||||
|
}
|
||||||
|
}
|
||||||
9
Partner-Capability-Demo/src/test/java/TestImpl.java
Normal file
9
Partner-Capability-Demo/src/test/java/TestImpl.java
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class TestImpl implements InterfaceTest{
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test(){
|
||||||
|
System.out.println(getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package work.slhaf.partner.core.cognation.capability;
|
|
||||||
|
|
||||||
import org.reflections.Reflections;
|
|
||||||
import work.slhaf.partner.core.cognation.capability.exception.CapabilityRegisterFailedException;
|
|
||||||
import work.slhaf.partner.core.cognation.capability.interfaces.Capability;
|
|
||||||
import work.slhaf.partner.core.cognation.capability.interfaces.CapabilityCore;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class CapabilityRegisterFactory {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
package work.slhaf.partner.core.cognation.capability.ability;
|
|
||||||
|
|
||||||
public interface DispatchCapability {
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package work.slhaf.partner.core.cognation.capability.exception;
|
|
||||||
|
|
||||||
public class CapabilityRegisterFailedException extends RuntimeException {
|
|
||||||
public CapabilityRegisterFailedException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
package work.slhaf.partner.core.cognation.cognation;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
import work.slhaf.partner.common.chat.pojo.Message;
|
|
||||||
import work.slhaf.partner.common.serialize.PersistableObject;
|
|
||||||
import work.slhaf.partner.core.cognation.submodule.cache.CacheCore;
|
|
||||||
import work.slhaf.partner.core.cognation.submodule.memory.MemoryCore;
|
|
||||||
import work.slhaf.partner.core.cognation.submodule.perceive.PerceiveCore;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.nio.file.StandardCopyOption;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@Data
|
|
||||||
@Slf4j
|
|
||||||
public class CognationCore extends PersistableObject {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String STORAGE_DIR = "./data/memory/";
|
|
||||||
private static volatile CognationCore cognationCore;
|
|
||||||
|
|
||||||
private String id;
|
|
||||||
private MemoryCore memoryCore = new MemoryCore();
|
|
||||||
private CacheCore cacheCore = new CacheCore();
|
|
||||||
private PerceiveCore perceiveCore = new PerceiveCore();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 主模型的聊天记录
|
|
||||||
*/
|
|
||||||
private List<Message> chatMessages = new ArrayList<>();
|
|
||||||
|
|
||||||
public CognationCore(String id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CognationCore getInstance(String id) throws IOException, ClassNotFoundException {
|
|
||||||
if (cognationCore == null) {
|
|
||||||
synchronized (CognationCore.class) {
|
|
||||||
// 检查存储目录是否存在,不存在则创建
|
|
||||||
if (cognationCore == null) {
|
|
||||||
createStorageDirectory();
|
|
||||||
Path filePath = getFilePath(id);
|
|
||||||
if (Files.exists(filePath)) {
|
|
||||||
cognationCore = deserialize(id);
|
|
||||||
} else {
|
|
||||||
FileUtils.createParentDirectories(filePath.toFile().getParentFile());
|
|
||||||
cognationCore = new CognationCore(id);
|
|
||||||
cognationCore.serialize();
|
|
||||||
}
|
|
||||||
log.info("CognationCore注册完毕...");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cognationCore;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void serialize() throws IOException {
|
|
||||||
//先写入到临时文件,如果正常写入则覆盖原文件
|
|
||||||
Path filePath = getFilePath(this.id + "-temp");
|
|
||||||
Files.createDirectories(Path.of(STORAGE_DIR));
|
|
||||||
try {
|
|
||||||
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath.toFile()));
|
|
||||||
oos.writeObject(this);
|
|
||||||
oos.close();
|
|
||||||
Path path = getFilePath(this.id);
|
|
||||||
Files.move(filePath, path, StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
log.info("CognationCore 已保存到: {}", path);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Files.delete(filePath);
|
|
||||||
log.error("序列化保存失败: {}", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static CognationCore deserialize(String id) throws IOException, ClassNotFoundException {
|
|
||||||
Path filePath = getFilePath(id);
|
|
||||||
try (ObjectInputStream ois = new ObjectInputStream(
|
|
||||||
new FileInputStream(filePath.toFile()))) {
|
|
||||||
CognationCore graph = (CognationCore) ois.readObject();
|
|
||||||
log.info("CognationCore 已从文件加载: {}", filePath);
|
|
||||||
return graph;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Path getFilePath(String id) {
|
|
||||||
return Paths.get(STORAGE_DIR, id + ".memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void createStorageDirectory() {
|
|
||||||
try {
|
|
||||||
Files.createDirectories(Paths.get(STORAGE_DIR));
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.err.println("创建存储目录失败: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
package work.slhaf.partner.module.common;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import work.slhaf.partner.common.chat.ChatClient;
|
|
||||||
import work.slhaf.partner.common.chat.constant.ChatConstant;
|
|
||||||
import work.slhaf.partner.common.chat.pojo.ChatResponse;
|
|
||||||
import work.slhaf.partner.common.chat.pojo.Message;
|
|
||||||
import work.slhaf.partner.common.config.ModelConfig;
|
|
||||||
import work.slhaf.partner.common.util.ResourcesUtil;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public abstract class Model {
|
|
||||||
protected ChatClient chatClient;
|
|
||||||
protected List<Message> chatMessages;
|
|
||||||
protected List<Message> baseMessages;
|
|
||||||
|
|
||||||
protected static void setModel(Model model, String promptModule, boolean withAwareness) {
|
|
||||||
String model_key = model.modelKey();
|
|
||||||
ModelConfig modelConfig = ModelConfig.load(model_key);
|
|
||||||
|
|
||||||
model.setBaseMessages(withAwareness ? ResourcesUtil.Prompt.loadPromptWithSelfAwareness(model_key, promptModule) : ResourcesUtil.Prompt.loadPrompt(model_key, promptModule));
|
|
||||||
model.setChatClient(new ChatClient(modelConfig.getBaseUrl(), modelConfig.getApikey(), modelConfig.getModel()));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ChatResponse chat() {
|
|
||||||
List<Message> temp = new ArrayList<>();
|
|
||||||
temp.addAll(this.baseMessages);
|
|
||||||
temp.addAll(this.chatMessages);
|
|
||||||
return this.chatClient.runChat(temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ChatResponse singleChat(String input) {
|
|
||||||
List<Message> temp = new ArrayList<>(baseMessages);
|
|
||||||
temp.add( new Message(ChatConstant.Character.USER, input));
|
|
||||||
return this.chatClient.runChat(temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void updateChatClientSettings() {
|
|
||||||
this.chatClient.setTemperature(0.4);
|
|
||||||
this.chatClient.setTop_p(0.8);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract String modelKey();
|
|
||||||
}
|
|
||||||
48
Partner-Main/pom.xml
Normal file
48
Partner-Main/pom.xml
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>work.slhaf</groupId>
|
||||||
|
<artifactId>Partner</artifactId>
|
||||||
|
<version>0.5.0</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>Partner-Main</artifactId>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>fastjson</artifactId>
|
||||||
|
<version>2.0.56</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-io</groupId>
|
||||||
|
<artifactId>commons-io</artifactId>
|
||||||
|
<version>2.18.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-all</artifactId>
|
||||||
|
<version>5.8.36</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.java-websocket</groupId>
|
||||||
|
<artifactId>Java-WebSocket</artifactId>
|
||||||
|
<version>1.6.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>work.slhaf</groupId>
|
||||||
|
<artifactId>Partner-Api</artifactId>
|
||||||
|
<version>0.5.0</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
|
<maven.compiler.target>21</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -3,12 +3,13 @@ package work.slhaf.partner.core;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import work.slhaf.partner.api.capability.CapabilityRegisterFactory;
|
||||||
import work.slhaf.partner.common.exception_handler.GlobalExceptionHandler;
|
import work.slhaf.partner.common.exception_handler.GlobalExceptionHandler;
|
||||||
import work.slhaf.partner.common.exception_handler.pojo.GlobalException;
|
import work.slhaf.partner.common.exception_handler.pojo.GlobalException;
|
||||||
import work.slhaf.partner.core.interaction.agent_interface.TaskCallback;
|
import work.slhaf.partner.core.interaction.agent_interface.TaskCallback;
|
||||||
import work.slhaf.partner.core.interaction.data.InteractionInputData;
|
import work.slhaf.partner.core.interaction.data.InteractionInputData;
|
||||||
import work.slhaf.partner.core.interaction.data.context.InteractionContext;
|
import work.slhaf.partner.core.interaction.data.context.InteractionContext;
|
||||||
import work.slhaf.partner.core.interaction.module.InteractionModule;
|
import work.slhaf.partner.core.interaction.module.InteractionFlow;
|
||||||
import work.slhaf.partner.core.interaction.module.InteractionModulesLoader;
|
import work.slhaf.partner.core.interaction.module.InteractionModulesLoader;
|
||||||
import work.slhaf.partner.module.modules.process.PreprocessExecutor;
|
import work.slhaf.partner.module.modules.process.PreprocessExecutor;
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@ public class InteractionHub {
|
|||||||
|
|
||||||
@ToString.Exclude
|
@ToString.Exclude
|
||||||
private TaskCallback callback;
|
private TaskCallback callback;
|
||||||
private List<InteractionModule> interactionModules;
|
private List<InteractionFlow> interactionModules;
|
||||||
|
|
||||||
public static InteractionHub initialize() throws IOException {
|
public static InteractionHub initialize() throws IOException {
|
||||||
if (interactionHub == null) {
|
if (interactionHub == null) {
|
||||||
@@ -32,6 +33,7 @@ public class InteractionHub {
|
|||||||
interactionHub = new InteractionHub();
|
interactionHub = new InteractionHub();
|
||||||
//加载模块
|
//加载模块
|
||||||
interactionHub.setInteractionModules(InteractionModulesLoader.getInstance().registerInteractionModules());
|
interactionHub.setInteractionModules(InteractionModulesLoader.getInstance().registerInteractionModules());
|
||||||
|
CapabilityRegisterFactory.getInstance().registerCapabilities("work.slhaf.partner");
|
||||||
log.info("InteractionHub注册完毕...");
|
log.info("InteractionHub注册完毕...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,7 +44,7 @@ public class InteractionHub {
|
|||||||
public void call(InteractionInputData inputData) throws IOException, ClassNotFoundException {
|
public void call(InteractionInputData inputData) throws IOException, ClassNotFoundException {
|
||||||
InteractionContext interactionContext = PreprocessExecutor.getInstance().execute(inputData);
|
InteractionContext interactionContext = PreprocessExecutor.getInstance().execute(inputData);
|
||||||
try {
|
try {
|
||||||
for (InteractionModule interactionModule : interactionModules) {
|
for (InteractionFlow interactionModule : interactionModules) {
|
||||||
interactionModule.execute(interactionContext);
|
interactionModule.execute(interactionContext);
|
||||||
}
|
}
|
||||||
} catch (GlobalException e) {
|
} catch (GlobalException e) {
|
||||||
@@ -2,55 +2,42 @@ package work.slhaf.partner.core.cognation;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import work.slhaf.partner.api.capability.BaseCoordinateManager;
|
||||||
|
import work.slhaf.partner.api.capability.annotation.Coordinated;
|
||||||
import work.slhaf.partner.common.chat.constant.ChatConstant;
|
import work.slhaf.partner.common.chat.constant.ChatConstant;
|
||||||
import work.slhaf.partner.common.chat.pojo.Message;
|
|
||||||
import work.slhaf.partner.common.config.Config;
|
|
||||||
import work.slhaf.partner.common.exception_handler.GlobalExceptionHandler;
|
import work.slhaf.partner.common.exception_handler.GlobalExceptionHandler;
|
||||||
import work.slhaf.partner.common.exception_handler.pojo.GlobalException;
|
import work.slhaf.partner.common.exception_handler.pojo.GlobalException;
|
||||||
import work.slhaf.partner.common.serialize.PersistableObject;
|
|
||||||
import work.slhaf.partner.core.cognation.capability.ability.CacheCapability;
|
|
||||||
import work.slhaf.partner.core.cognation.capability.ability.CognationCapability;
|
|
||||||
import work.slhaf.partner.core.cognation.capability.ability.MemoryCapability;
|
|
||||||
import work.slhaf.partner.core.cognation.capability.ability.PerceiveCapability;
|
|
||||||
import work.slhaf.partner.core.cognation.cognation.CognationCore;
|
import work.slhaf.partner.core.cognation.cognation.CognationCore;
|
||||||
import work.slhaf.partner.core.cognation.cognation.exception.UserNotExistsException;
|
|
||||||
import work.slhaf.partner.core.cognation.cognation.pojo.ActiveData;
|
|
||||||
import work.slhaf.partner.core.cognation.common.pojo.MemoryResult;
|
import work.slhaf.partner.core.cognation.common.pojo.MemoryResult;
|
||||||
import work.slhaf.partner.core.cognation.common.pojo.MemorySliceResult;
|
import work.slhaf.partner.core.cognation.common.pojo.MemorySliceResult;
|
||||||
import work.slhaf.partner.core.cognation.submodule.cache.CacheCore;
|
import work.slhaf.partner.core.cognation.submodule.cache.CacheCore;
|
||||||
import work.slhaf.partner.core.cognation.submodule.dispatch.DispatchCore;
|
import work.slhaf.partner.core.cognation.submodule.dispatch.DispatchCore;
|
||||||
import work.slhaf.partner.core.cognation.submodule.memory.MemoryCore;
|
import work.slhaf.partner.core.cognation.submodule.memory.MemoryCore;
|
||||||
import work.slhaf.partner.core.cognation.submodule.memory.pojo.EvaluatedSlice;
|
|
||||||
import work.slhaf.partner.core.cognation.submodule.memory.pojo.MemorySlice;
|
import work.slhaf.partner.core.cognation.submodule.memory.pojo.MemorySlice;
|
||||||
import work.slhaf.partner.core.cognation.submodule.perceive.PerceiveCore;
|
import work.slhaf.partner.core.cognation.submodule.perceive.PerceiveCore;
|
||||||
import work.slhaf.partner.core.cognation.submodule.perceive.pojo.User;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
import static work.slhaf.partner.common.util.ExtractUtil.extractUserId;
|
import static work.slhaf.partner.common.util.ExtractUtil.extractUserId;
|
||||||
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Data
|
@Data
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class CognationManager extends PersistableObject implements CacheCapability, MemoryCapability, PerceiveCapability, CognationCapability {
|
public class CognationManager extends BaseCoordinateManager implements Serializable {
|
||||||
|
|
||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private static volatile CognationManager cognationManager;
|
private static volatile CognationManager cognationManager;
|
||||||
private final Lock sliceInsertLock = new ReentrantLock();
|
private final Lock sliceInsertLock = new ReentrantLock();
|
||||||
@Getter
|
|
||||||
public final Lock messageLock = new ReentrantLock();
|
|
||||||
|
|
||||||
|
|
||||||
private CognationCore cognationCore;
|
private CognationCore cognationCore;
|
||||||
private CacheCore cacheCore;
|
private CacheCore cacheCore;
|
||||||
@@ -58,8 +45,6 @@ public class CognationManager extends PersistableObject implements CacheCapabili
|
|||||||
private PerceiveCore perceiveCore;
|
private PerceiveCore perceiveCore;
|
||||||
private DispatchCore dispatchCore;
|
private DispatchCore dispatchCore;
|
||||||
|
|
||||||
private ActiveData activeData;
|
|
||||||
|
|
||||||
private CognationManager() {
|
private CognationManager() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,12 +53,9 @@ public class CognationManager extends PersistableObject implements CacheCapabili
|
|||||||
if (cognationManager == null) {
|
if (cognationManager == null) {
|
||||||
synchronized (CognationManager.class) {
|
synchronized (CognationManager.class) {
|
||||||
if (cognationManager == null) {
|
if (cognationManager == null) {
|
||||||
Config config = Config.getConfig();
|
|
||||||
cognationManager = new CognationManager();
|
cognationManager = new CognationManager();
|
||||||
cognationManager.setCognationCore(CognationCore.getInstance(config.getAgentId()));
|
cognationManager.setCognationCore(CognationCore.getInstance());
|
||||||
cognationManager.setCores();
|
cognationManager.setCores();
|
||||||
cognationManager.setActiveData(new ActiveData());
|
|
||||||
cognationManager.setShutdownHook();
|
|
||||||
log.info("[CognationManager] MemoryManager注册完毕...");
|
log.info("[CognationManager] MemoryManager注册完毕...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,18 +69,8 @@ public class CognationManager extends PersistableObject implements CacheCapabili
|
|||||||
this.setPerceiveCore(this.getCognationCore().getPerceiveCore());
|
this.setPerceiveCore(this.getCognationCore().getPerceiveCore());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setShutdownHook() {
|
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
|
||||||
try {
|
|
||||||
cognationManager.save();
|
|
||||||
log.info("[CognationManager] MemoryGraph已保存");
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("[CognationManager] 保存MemoryGraph失败: ", e);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Coordinated(capability = "memory")
|
||||||
public MemoryResult selectMemory(String topicPathStr) {
|
public MemoryResult selectMemory(String topicPathStr) {
|
||||||
MemoryResult memoryResult;
|
MemoryResult memoryResult;
|
||||||
List<String> topicPath = List.of(topicPathStr.split("->"));
|
List<String> topicPath = List.of(topicPathStr.split("->"));
|
||||||
@@ -118,7 +90,7 @@ public class CognationManager extends PersistableObject implements CacheCapabili
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("[CognationManager] selectMemory error: ", e);
|
log.error("[CognationManager] selectMemory error: ", e);
|
||||||
log.error("[CognationManager] 路径: {}", topicPathStr);
|
log.error("[CognationManager] 路径: {}", topicPathStr);
|
||||||
log.error("[CognationManager] 主题树: {}", getTopicTree());
|
log.error("[CognationManager] 主题树: {}", memoryCore.getTopicTree());
|
||||||
memoryResult = new MemoryResult();
|
memoryResult = new MemoryResult();
|
||||||
memoryResult.setRelatedMemorySliceResult(new ArrayList<>());
|
memoryResult.setRelatedMemorySliceResult(new ArrayList<>());
|
||||||
memoryResult.setMemorySliceResult(new CopyOnWriteArrayList<>());
|
memoryResult.setMemorySliceResult(new CopyOnWriteArrayList<>());
|
||||||
@@ -127,7 +99,7 @@ public class CognationManager extends PersistableObject implements CacheCapabili
|
|||||||
return cacheFilter(memoryResult);
|
return cacheFilter(memoryResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Coordinated(capability = "memory")
|
||||||
public MemoryResult selectMemory(LocalDate date) throws IOException, ClassNotFoundException {
|
public MemoryResult selectMemory(LocalDate date) throws IOException, ClassNotFoundException {
|
||||||
return cacheFilter(memoryCore.selectMemory(date));
|
return cacheFilter(memoryCore.selectMemory(date));
|
||||||
}
|
}
|
||||||
@@ -136,49 +108,15 @@ public class CognationManager extends PersistableObject implements CacheCapabili
|
|||||||
//过滤掉与缓存重复的切片
|
//过滤掉与缓存重复的切片
|
||||||
CopyOnWriteArrayList<MemorySliceResult> memorySliceResult = memoryResult.getMemorySliceResult();
|
CopyOnWriteArrayList<MemorySliceResult> memorySliceResult = memoryResult.getMemorySliceResult();
|
||||||
List<MemorySlice> relatedMemorySliceResult = memoryResult.getRelatedMemorySliceResult();
|
List<MemorySlice> relatedMemorySliceResult = memoryResult.getRelatedMemorySliceResult();
|
||||||
getDialogMap().forEach((k, v) -> {
|
cacheCore.getDialogMap().forEach((k, v) -> {
|
||||||
memorySliceResult.removeIf(m -> m.getMemorySlice().getSummary().equals(v));
|
memorySliceResult.removeIf(m -> m.getMemorySlice().getSummary().equals(v));
|
||||||
relatedMemorySliceResult.removeIf(m -> m.getSummary().equals(v));
|
relatedMemorySliceResult.removeIf(m -> m.getSummary().equals(v));
|
||||||
});
|
});
|
||||||
return memoryResult;
|
return memoryResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cleanSelectedSliceFilter() {
|
|
||||||
memoryCore.getSelectedSlices().clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Coordinated(capability = "memory")
|
||||||
public User getUser(String userInfo, String client) {
|
|
||||||
return perceiveCore.selectUser(userInfo, client);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Message> getChatMessages() {
|
|
||||||
return cognationCore.getChatMessages();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setChatMessages(List<Message> chatMessages) {
|
|
||||||
cognationCore.setChatMessages(chatMessages);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getTopicTree() {
|
|
||||||
return memoryCore.getTopicTree();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HashMap<LocalDateTime, String> getDialogMap() {
|
|
||||||
return cacheCore.getDialogMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ConcurrentHashMap<LocalDateTime, String> getUserDialogMap(String userId) {
|
|
||||||
return cacheCore.getUserDialogMap().get(userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void insertSlice(MemorySlice memorySlice, String topicPath) {
|
public void insertSlice(MemorySlice memorySlice, String topicPath) {
|
||||||
sliceInsertLock.lock();
|
sliceInsertLock.lock();
|
||||||
List<String> topicPathList = Arrays.stream(topicPath.split("->")).toList();
|
List<String> topicPathList = Arrays.stream(topicPath.split("->")).toList();
|
||||||
@@ -200,80 +138,19 @@ public class CognationManager extends PersistableObject implements CacheCapabili
|
|||||||
sliceInsertLock.unlock();
|
sliceInsertLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cleanMessage(List<Message> messages) {
|
|
||||||
messageLock.lock();
|
|
||||||
cognationCore.getChatMessages().removeAll(messages);
|
|
||||||
messageLock.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateDialogMap(LocalDateTime dateTime, String newDialogCache) {
|
|
||||||
cacheCore.updateDialogMap(dateTime, newDialogCache);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void save() throws IOException {
|
|
||||||
cognationCore.serialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateActivatedSlices(String userId, List<EvaluatedSlice> memorySlices) {
|
|
||||||
activeData.updateActivatedSlices(userId, memorySlices);
|
|
||||||
log.debug("[CognationManager] 已更新激活切片, userId: {}", userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public User getUser(String id) {
|
|
||||||
User user = perceiveCore.selectUser(id);
|
|
||||||
if (user == null) {
|
|
||||||
throw new UserNotExistsException("[CognationManager] 用户不存在: " + id);
|
|
||||||
}
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getActivatedSlicesStr(String userId) {
|
|
||||||
return activeData.getActivatedSlicesStr(userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDialogMapStr() {
|
|
||||||
StringBuilder str = new StringBuilder();
|
|
||||||
cacheCore.getDialogMap().forEach((dateTime, dialog) -> str.append("\n\n").append("[").append(dateTime).append("]\n")
|
|
||||||
.append(dialog));
|
|
||||||
return str.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUserDialogMapStr(String userId) {
|
|
||||||
if (cacheCore.getUserDialogMap().containsKey(userId)) {
|
|
||||||
StringBuilder str = new StringBuilder();
|
|
||||||
Collection<String> dialogMapValues = cacheCore.getDialogMap().values();
|
|
||||||
cacheCore.getUserDialogMap().get(userId).forEach((dateTime, dialog) -> {
|
|
||||||
if (dialogMapValues.contains(dialog)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
str.append("\n\n").append("[").append(dateTime).append("]\n")
|
|
||||||
.append(dialog);
|
|
||||||
});
|
|
||||||
return str.toString();
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isCacheSingleUser() {
|
private boolean isCacheSingleUser() {
|
||||||
return cacheCore.getUserDialogMap().size() <= 1;
|
return cacheCore.getUserDialogMap().size() <= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Coordinated(capability = "cognation")
|
||||||
public boolean isSingleUser() {
|
public boolean isSingleUser() {
|
||||||
return isCacheSingleUser() && isChatMessagesSingleUser();
|
return isCacheSingleUser() && isChatMessagesSingleUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isChatMessagesSingleUser() {
|
private boolean isChatMessagesSingleUser() {
|
||||||
Set<String> userIdSet = new HashSet<>();
|
Set<String> userIdSet = new HashSet<>();
|
||||||
cognationManager.getChatMessages().forEach(m -> {
|
cognationCore.getChatMessages().forEach(m -> {
|
||||||
if (m.getRole().equals(ChatConstant.Character.ASSISTANT)) {
|
if (m.getRole().equals(ChatConstant.Character.ASSISTANT)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -286,38 +163,5 @@ public class CognationManager extends PersistableObject implements CacheCapabili
|
|||||||
return userIdSet.size() <= 1;
|
return userIdSet.size() <= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public User addUser(String userInfo, String platform, String userNickName) {
|
|
||||||
return perceiveCore.addUser(userInfo, platform, userNickName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateUser(User tempUser) {
|
|
||||||
perceiveCore.updateUser(tempUser);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HashMap<String, List<EvaluatedSlice>> getActivatedSlices() {
|
|
||||||
return activeData.getActivatedSlices();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearActivatedSlices(String userId) {
|
|
||||||
activeData.clearActivatedSlices(userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasActivatedSlices(String userId) {
|
|
||||||
return activeData.hasActivatedSlices(userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getActivatedSlicesSize(String userId) {
|
|
||||||
return activeData.getActivatedSlices().get(userId).size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<EvaluatedSlice> getActivatedSlices(String userId) {
|
|
||||||
return activeData.getActivatedSlices().get(userId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
package work.slhaf.partner.core.cognation.capability.ability;
|
package work.slhaf.partner.core.cognation.cognation;
|
||||||
|
|
||||||
|
import work.slhaf.partner.api.capability.annotation.Capability;
|
||||||
|
import work.slhaf.partner.api.capability.annotation.CapabilityMethod;
|
||||||
|
import work.slhaf.partner.api.capability.annotation.ToCoordinated;
|
||||||
import work.slhaf.partner.common.chat.pojo.Message;
|
import work.slhaf.partner.common.chat.pojo.Message;
|
||||||
import work.slhaf.partner.core.cognation.submodule.memory.pojo.EvaluatedSlice;
|
import work.slhaf.partner.core.cognation.submodule.memory.pojo.EvaluatedSlice;
|
||||||
|
|
||||||
@@ -7,17 +10,42 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
|
|
||||||
|
@Capability("cognation")
|
||||||
public interface CognationCapability {
|
public interface CognationCapability {
|
||||||
|
|
||||||
|
@CapabilityMethod
|
||||||
List<Message> getChatMessages();
|
List<Message> getChatMessages();
|
||||||
|
|
||||||
|
@CapabilityMethod
|
||||||
void setChatMessages(List<Message> chatMessages);
|
void setChatMessages(List<Message> chatMessages);
|
||||||
|
|
||||||
|
@CapabilityMethod
|
||||||
void cleanMessage(List<Message> messages);
|
void cleanMessage(List<Message> messages);
|
||||||
|
|
||||||
|
@CapabilityMethod
|
||||||
void updateActivatedSlices(String userId, List<EvaluatedSlice> memorySlices);
|
void updateActivatedSlices(String userId, List<EvaluatedSlice> memorySlices);
|
||||||
|
|
||||||
|
@CapabilityMethod
|
||||||
String getActivatedSlicesStr(String userId);
|
String getActivatedSlicesStr(String userId);
|
||||||
|
|
||||||
|
@CapabilityMethod
|
||||||
HashMap<String, List<EvaluatedSlice>> getActivatedSlices();
|
HashMap<String, List<EvaluatedSlice>> getActivatedSlices();
|
||||||
|
|
||||||
|
@CapabilityMethod
|
||||||
void clearActivatedSlices(String userId);
|
void clearActivatedSlices(String userId);
|
||||||
|
|
||||||
|
@CapabilityMethod
|
||||||
boolean hasActivatedSlices(String userId);
|
boolean hasActivatedSlices(String userId);
|
||||||
|
|
||||||
|
@CapabilityMethod
|
||||||
int getActivatedSlicesSize(String userId);
|
int getActivatedSlicesSize(String userId);
|
||||||
|
|
||||||
|
@CapabilityMethod
|
||||||
List<EvaluatedSlice> getActivatedSlices(String userId);
|
List<EvaluatedSlice> getActivatedSlices(String userId);
|
||||||
boolean isSingleUser();
|
|
||||||
|
@CapabilityMethod
|
||||||
Lock getMessageLock();
|
Lock getMessageLock();
|
||||||
|
|
||||||
|
@ToCoordinated
|
||||||
|
boolean isSingleUser();
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
package work.slhaf.partner.core.cognation.cognation;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import work.slhaf.partner.api.capability.annotation.CapabilityCore;
|
||||||
|
import work.slhaf.partner.common.chat.pojo.Message;
|
||||||
|
import work.slhaf.partner.common.serialize.PersistableObject;
|
||||||
|
import work.slhaf.partner.core.cognation.cognation.pojo.ActiveData;
|
||||||
|
import work.slhaf.partner.core.cognation.submodule.cache.CacheCore;
|
||||||
|
import work.slhaf.partner.core.cognation.submodule.memory.MemoryCore;
|
||||||
|
import work.slhaf.partner.core.cognation.submodule.memory.pojo.EvaluatedSlice;
|
||||||
|
import work.slhaf.partner.core.cognation.submodule.perceive.PerceiveCore;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
@Slf4j
|
||||||
|
@CapabilityCore(value = "cognation")
|
||||||
|
public class CognationCore extends PersistableObject {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private static final String STORAGE_DIR = "./data/memory/";
|
||||||
|
private static volatile CognationCore cognationCore;
|
||||||
|
|
||||||
|
private MemoryCore memoryCore = new MemoryCore();
|
||||||
|
private CacheCore cacheCore = new CacheCore();
|
||||||
|
private PerceiveCore perceiveCore = new PerceiveCore();
|
||||||
|
private ReentrantLock messageLock = new ReentrantLock();
|
||||||
|
private ActiveData activeData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主模型的聊天记录
|
||||||
|
*/
|
||||||
|
private List<Message> chatMessages = new ArrayList<>();
|
||||||
|
|
||||||
|
public CognationCore() throws IOException, ClassNotFoundException {
|
||||||
|
createStorageDirectory();
|
||||||
|
Path filePath = getFilePath("partner");
|
||||||
|
if (Files.exists(filePath)) {
|
||||||
|
setupData(this);
|
||||||
|
} else {
|
||||||
|
FileUtils.createParentDirectories(filePath.toFile().getParentFile());
|
||||||
|
connectCores(this);
|
||||||
|
this.serialize();
|
||||||
|
}
|
||||||
|
setupHook(this);
|
||||||
|
log.info("CognationCore注册完毕...");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connectCores(CognationCore temp) {
|
||||||
|
temp.setCacheCore(CacheCore.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupHook(CognationCore temp) {
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||||
|
try {
|
||||||
|
temp.serialize();
|
||||||
|
log.info("[CognationCore] CognationCore已保存");
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("[CognationCore] CognationCore保存失败: ", e);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupData(CognationCore temp) throws IOException, ClassNotFoundException {
|
||||||
|
CognationCore deserialize = deserialize();
|
||||||
|
temp.activeData = deserialize.activeData;
|
||||||
|
temp.memoryCore = deserialize.memoryCore;
|
||||||
|
temp.cacheCore = deserialize.cacheCore;
|
||||||
|
temp.perceiveCore = deserialize.perceiveCore;
|
||||||
|
temp.chatMessages = deserialize.chatMessages;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static CognationCore getInstance() {
|
||||||
|
return cognationCore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serialize() throws IOException {
|
||||||
|
//先写入到临时文件,如果正常写入则覆盖原文件
|
||||||
|
Path filePath = getFilePath("partner-temp");
|
||||||
|
Files.createDirectories(Path.of(STORAGE_DIR));
|
||||||
|
try {
|
||||||
|
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath.toFile()));
|
||||||
|
oos.writeObject(this);
|
||||||
|
oos.close();
|
||||||
|
Path path = getFilePath("partner");
|
||||||
|
Files.move(filePath, path, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
log.info("CognationCore 已保存到: {}", path);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Files.delete(filePath);
|
||||||
|
log.error("序列化保存失败: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CognationCore deserialize() throws IOException, ClassNotFoundException {
|
||||||
|
Path filePath = getFilePath("partner");
|
||||||
|
try (ObjectInputStream ois = new ObjectInputStream(
|
||||||
|
new FileInputStream(filePath.toFile()))) {
|
||||||
|
CognationCore graph = (CognationCore) ois.readObject();
|
||||||
|
log.info("CognationCore 已从文件加载: {}", filePath);
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Path getFilePath(String s) {
|
||||||
|
return Paths.get(STORAGE_DIR, s + ".memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void createStorageDirectory() {
|
||||||
|
try {
|
||||||
|
Files.createDirectories(Paths.get(STORAGE_DIR));
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("创建存储目录失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanMessage(List<Message> messages) {
|
||||||
|
messageLock.lock();
|
||||||
|
this.getChatMessages().removeAll(messages);
|
||||||
|
messageLock.unlock();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateActivatedSlices(String userId, List<EvaluatedSlice> memorySlices) {
|
||||||
|
activeData.updateActivatedSlices(userId, memorySlices);
|
||||||
|
log.debug("[CognationManager] 已更新激活切片, userId: {}", userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getActivatedSlicesStr(String userId) {
|
||||||
|
return activeData.getActivatedSlicesStr(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMap<String, List<EvaluatedSlice>> getActivatedSlices() {
|
||||||
|
return activeData.getActivatedSlices();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearActivatedSlices(String userId) {
|
||||||
|
activeData.clearActivatedSlices(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasActivatedSlices(String userId) {
|
||||||
|
return activeData.hasActivatedSlices(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getActivatedSlicesSize(String userId) {
|
||||||
|
return activeData.getActivatedSlices().get(userId).size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<EvaluatedSlice> getActivatedSlices(String userId) {
|
||||||
|
return activeData.getActivatedSlices().get(userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
package work.slhaf.partner.core.cognation.capability.ability;
|
package work.slhaf.partner.core.cognation.submodule.cache;
|
||||||
|
|
||||||
|
import work.slhaf.partner.api.capability.annotation.Capability;
|
||||||
|
import work.slhaf.partner.api.capability.annotation.CapabilityMethod;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@Capability(value = "cache")
|
||||||
public interface CacheCapability {
|
public interface CacheCapability {
|
||||||
HashMap<LocalDateTime, String> getDialogMap();
|
HashMap<LocalDateTime, String> getDialogMap();
|
||||||
ConcurrentHashMap<LocalDateTime, String> getUserDialogMap(String userId);
|
ConcurrentHashMap<LocalDateTime, String> getUserDialogMap(String userId);
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
package work.slhaf.partner.core.cognation.submodule.cache;
|
package work.slhaf.partner.core.cognation.submodule.cache;
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import work.slhaf.partner.api.capability.annotation.CapabilityCore;
|
||||||
|
import work.slhaf.partner.api.capability.annotation.CapabilityMethod;
|
||||||
import work.slhaf.partner.common.serialize.PersistableObject;
|
import work.slhaf.partner.common.serialize.PersistableObject;
|
||||||
import work.slhaf.partner.core.cognation.common.pojo.MemoryResult;
|
import work.slhaf.partner.core.cognation.common.pojo.MemoryResult;
|
||||||
import work.slhaf.partner.core.cognation.submodule.memory.pojo.MemorySlice;
|
import work.slhaf.partner.core.cognation.submodule.memory.pojo.MemorySlice;
|
||||||
@@ -14,12 +16,14 @@ import java.util.*;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Data
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@CapabilityCore(value = "cache")
|
||||||
|
@Getter
|
||||||
public class CacheCore extends PersistableObject {
|
public class CacheCore extends PersistableObject {
|
||||||
|
|
||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
public static volatile CacheCore cacheCore;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 近两日的对话总结缓存, 用于为大模型提供必要的记忆补充, hashmap以切片的存储时间为键,总结为值
|
* 近两日的对话总结缓存, 用于为大模型提供必要的记忆补充, hashmap以切片的存储时间为键,总结为值
|
||||||
@@ -54,6 +58,66 @@ public class CacheCore extends PersistableObject {
|
|||||||
*/
|
*/
|
||||||
private Set<Long> selectedSlices = new HashSet<>();
|
private Set<Long> selectedSlices = new HashSet<>();
|
||||||
|
|
||||||
|
public CacheCore() {
|
||||||
|
cacheCore = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CacheCore getInstance(){
|
||||||
|
return cacheCore;
|
||||||
|
}
|
||||||
|
|
||||||
|
@CapabilityMethod
|
||||||
|
public void updateDialogMap(LocalDateTime dateTime, String newDialogCache) {
|
||||||
|
List<LocalDateTime> keysToRemove = new ArrayList<>();
|
||||||
|
dialogMap.forEach((k, v) -> {
|
||||||
|
if (dateTime.minusDays(2).isAfter(k)) {
|
||||||
|
keysToRemove.add(k);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for (LocalDateTime temp : keysToRemove) {
|
||||||
|
dialogMap.remove(temp);
|
||||||
|
}
|
||||||
|
keysToRemove.clear();
|
||||||
|
//放入新缓存
|
||||||
|
dialogMap.put(dateTime, newDialogCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
@CapabilityMethod
|
||||||
|
public HashMap<LocalDateTime, String> getDialogMap(){
|
||||||
|
return dialogMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@CapabilityMethod
|
||||||
|
public ConcurrentHashMap<LocalDateTime, String> getUserDialogMap(String userId) {
|
||||||
|
return this.getUserDialogMap().get(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@CapabilityMethod
|
||||||
|
public String getDialogMapStr() {
|
||||||
|
StringBuilder str = new StringBuilder();
|
||||||
|
this.getDialogMap().forEach((dateTime, dialog) -> str.append("\n\n").append("[").append(dateTime).append("]\n")
|
||||||
|
.append(dialog));
|
||||||
|
return str.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@CapabilityMethod
|
||||||
|
public String getUserDialogMapStr(String userId) {
|
||||||
|
if (this.getUserDialogMap().containsKey(userId)) {
|
||||||
|
StringBuilder str = new StringBuilder();
|
||||||
|
Collection<String> dialogMapValues = this.getDialogMap().values();
|
||||||
|
this.getUserDialogMap().get(userId).forEach((dateTime, dialog) -> {
|
||||||
|
if (dialogMapValues.contains(dialog)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
str.append("\n\n").append("[").append(dateTime).append("]\n")
|
||||||
|
.append(dialog);
|
||||||
|
});
|
||||||
|
return str.toString();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void updateCacheCounter(List<String> topicPath) {
|
public void updateCacheCounter(List<String> topicPath) {
|
||||||
if (memoryNodeCacheCounter.containsKey(topicPath)) {
|
if (memoryNodeCacheCounter.containsKey(topicPath)) {
|
||||||
Integer tempCount = memoryNodeCacheCounter.get(topicPath);
|
Integer tempCount = memoryNodeCacheCounter.get(topicPath);
|
||||||
@@ -71,21 +135,6 @@ public class CacheCore extends PersistableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateDialogMap(LocalDateTime dateTime, String newDialogCache) {
|
|
||||||
List<LocalDateTime> keysToRemove = new ArrayList<>();
|
|
||||||
dialogMap.forEach((k, v) -> {
|
|
||||||
if (dateTime.minusDays(2).isAfter(k)) {
|
|
||||||
keysToRemove.add(k);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
for (LocalDateTime temp : keysToRemove) {
|
|
||||||
dialogMap.remove(temp);
|
|
||||||
}
|
|
||||||
keysToRemove.clear();
|
|
||||||
//放入新缓存
|
|
||||||
dialogMap.put(dateTime, newDialogCache);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateCache(List<String> topicPath, MemoryResult memoryResult) {
|
public void updateCache(List<String> topicPath, MemoryResult memoryResult) {
|
||||||
Integer tempCount = memoryNodeCacheCounter.get(topicPath);
|
Integer tempCount = memoryNodeCacheCounter.get(topicPath);
|
||||||
if (tempCount == null) {
|
if (tempCount == null) {
|
||||||
@@ -129,4 +178,5 @@ public class CacheCore extends PersistableObject {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package work.slhaf.partner.core.cognation.submodule.dispatch;
|
||||||
|
|
||||||
|
public interface DispatchCapability {
|
||||||
|
}
|
||||||
@@ -1,15 +1,26 @@
|
|||||||
package work.slhaf.partner.core.cognation.capability.ability;
|
package work.slhaf.partner.core.cognation.submodule.memory;
|
||||||
|
|
||||||
|
import work.slhaf.partner.api.capability.annotation.Capability;
|
||||||
|
import work.slhaf.partner.api.capability.annotation.CapabilityMethod;
|
||||||
|
import work.slhaf.partner.api.capability.annotation.ToCoordinated;
|
||||||
import work.slhaf.partner.core.cognation.common.pojo.MemoryResult;
|
import work.slhaf.partner.core.cognation.common.pojo.MemoryResult;
|
||||||
import work.slhaf.partner.core.cognation.submodule.memory.pojo.MemorySlice;
|
import work.slhaf.partner.core.cognation.submodule.memory.pojo.MemorySlice;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
@Capability(value = "memory")
|
||||||
public interface MemoryCapability {
|
public interface MemoryCapability {
|
||||||
MemoryResult selectMemory(String topicPathStr);
|
|
||||||
MemoryResult selectMemory(LocalDate date) throws IOException, ClassNotFoundException;
|
|
||||||
void insertSlice(MemorySlice memorySlice, String topicPath);
|
|
||||||
void cleanSelectedSliceFilter();
|
void cleanSelectedSliceFilter();
|
||||||
String getTopicTree();
|
String getTopicTree();
|
||||||
|
|
||||||
|
@ToCoordinated
|
||||||
|
MemoryResult selectMemory(String topicPathStr);
|
||||||
|
|
||||||
|
@ToCoordinated
|
||||||
|
MemoryResult selectMemory(LocalDate date) throws IOException, ClassNotFoundException;
|
||||||
|
|
||||||
|
@ToCoordinated
|
||||||
|
void insertSlice(MemorySlice memorySlice, String topicPath);
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,8 @@ package work.slhaf.partner.core.cognation.submodule.memory;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import work.slhaf.partner.api.capability.annotation.CapabilityCore;
|
||||||
|
import work.slhaf.partner.api.capability.annotation.CapabilityMethod;
|
||||||
import work.slhaf.partner.common.serialize.PersistableObject;
|
import work.slhaf.partner.common.serialize.PersistableObject;
|
||||||
import work.slhaf.partner.core.cognation.common.pojo.MemoryResult;
|
import work.slhaf.partner.core.cognation.common.pojo.MemoryResult;
|
||||||
import work.slhaf.partner.core.cognation.common.pojo.MemorySliceResult;
|
import work.slhaf.partner.core.cognation.common.pojo.MemorySliceResult;
|
||||||
@@ -20,10 +22,12 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
|||||||
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Data
|
@Data
|
||||||
|
@CapabilityCore(value = "memory")
|
||||||
public class MemoryCore extends PersistableObject {
|
public class MemoryCore extends PersistableObject {
|
||||||
|
|
||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
public static MemoryCore memoryCore;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* key: 根主题名称 value: 根主题节点
|
* key: 根主题名称 value: 根主题节点
|
||||||
@@ -53,6 +57,13 @@ public class MemoryCore extends PersistableObject {
|
|||||||
|
|
||||||
private HashMap<String,List<String>> userIndex = new HashMap<>();
|
private HashMap<String,List<String>> userIndex = new HashMap<>();
|
||||||
|
|
||||||
|
public MemoryCore(){
|
||||||
|
memoryCore = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MemoryCore getInstance() {
|
||||||
|
return memoryCore;
|
||||||
|
}
|
||||||
|
|
||||||
public MemoryResult selectMemory(LocalDate date) throws IOException, ClassNotFoundException {
|
public MemoryResult selectMemory(LocalDate date) throws IOException, ClassNotFoundException {
|
||||||
MemoryResult memoryResult = new MemoryResult();
|
MemoryResult memoryResult = new MemoryResult();
|
||||||
@@ -87,6 +98,7 @@ public class MemoryCore extends PersistableObject {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CapabilityMethod
|
||||||
public String getTopicTree() {
|
public String getTopicTree() {
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
for (Map.Entry<String, TopicNode> entry : topicNodes.entrySet()) {
|
for (Map.Entry<String, TopicNode> entry : topicNodes.entrySet()) {
|
||||||
@@ -314,4 +326,8 @@ public class MemoryCore extends PersistableObject {
|
|||||||
return targetParentNode;
|
return targetParentNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CapabilityMethod
|
||||||
|
public void cleanSelectedSliceFilter() {
|
||||||
|
this.getSelectedSlices().clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
package work.slhaf.partner.core.cognation.capability.ability;
|
package work.slhaf.partner.core.cognation.submodule.perceive;
|
||||||
|
|
||||||
|
import work.slhaf.partner.api.capability.annotation.Capability;
|
||||||
|
import work.slhaf.partner.api.capability.annotation.CapabilityMethod;
|
||||||
import work.slhaf.partner.core.cognation.submodule.perceive.pojo.User;
|
import work.slhaf.partner.core.cognation.submodule.perceive.pojo.User;
|
||||||
|
|
||||||
|
@Capability(value = "perceive")
|
||||||
public interface PerceiveCapability {
|
public interface PerceiveCapability {
|
||||||
User getUser(String userInfo, String client);
|
User getUser(String userInfo, String client);
|
||||||
User getUser(String id);
|
User getUser(String id);
|
||||||
@@ -2,7 +2,10 @@ package work.slhaf.partner.core.cognation.submodule.perceive;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import work.slhaf.partner.api.capability.annotation.CapabilityCore;
|
||||||
|
import work.slhaf.partner.api.capability.annotation.CapabilityMethod;
|
||||||
import work.slhaf.partner.common.serialize.PersistableObject;
|
import work.slhaf.partner.common.serialize.PersistableObject;
|
||||||
|
import work.slhaf.partner.core.cognation.cognation.exception.UserNotExistsException;
|
||||||
import work.slhaf.partner.core.cognation.submodule.perceive.pojo.User;
|
import work.slhaf.partner.core.cognation.submodule.perceive.pojo.User;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
@@ -14,11 +17,12 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||||||
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Data
|
@Data
|
||||||
|
@CapabilityCore(value = "perceive")
|
||||||
public class PerceiveCore extends PersistableObject {
|
public class PerceiveCore extends PersistableObject {
|
||||||
|
|
||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private static volatile PerceiveCore perceiveCore = new PerceiveCore();
|
private static volatile PerceiveCore perceiveCore;
|
||||||
private static final ReentrantLock usersLock = new ReentrantLock();
|
private static final ReentrantLock usersLock = new ReentrantLock();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,18 +30,16 @@ public class PerceiveCore extends PersistableObject {
|
|||||||
*/
|
*/
|
||||||
private List<User> users = new ArrayList<>();
|
private List<User> users = new ArrayList<>();
|
||||||
|
|
||||||
|
public PerceiveCore() {
|
||||||
|
perceiveCore = this;
|
||||||
|
}
|
||||||
|
|
||||||
public static PerceiveCore getInstance() {
|
public static PerceiveCore getInstance() {
|
||||||
if (perceiveCore == null) {
|
|
||||||
synchronized (PerceiveCore.class) {
|
|
||||||
if (perceiveCore == null) {
|
|
||||||
perceiveCore = new PerceiveCore();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return perceiveCore;
|
return perceiveCore;
|
||||||
}
|
}
|
||||||
|
|
||||||
public User selectUser(String userInfo, String platform) {
|
@CapabilityMethod
|
||||||
|
public User getUser(String userInfo, String platform) {
|
||||||
User resultUser = null;
|
User resultUser = null;
|
||||||
usersLock.lock();
|
usersLock.lock();
|
||||||
for (User user : users) {
|
for (User user : users) {
|
||||||
@@ -52,6 +54,7 @@ public class PerceiveCore extends PersistableObject {
|
|||||||
return resultUser;
|
return resultUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CapabilityMethod
|
||||||
public User addUser(String userInfo, String platform, String userNickName) {
|
public User addUser(String userInfo, String platform, String userNickName) {
|
||||||
User user = new User();
|
User user = new User();
|
||||||
user.addInfo(platform, userInfo);
|
user.addInfo(platform, userInfo);
|
||||||
@@ -64,20 +67,26 @@ public class PerceiveCore extends PersistableObject {
|
|||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
public User selectUser(String id) {
|
@CapabilityMethod
|
||||||
|
public User getUser(String id) {
|
||||||
usersLock.lock();
|
usersLock.lock();
|
||||||
|
User resultUser = null;
|
||||||
for (User user : users) {
|
for (User user : users) {
|
||||||
if (user.getUuid().equals(id)) {
|
if (user.getUuid().equals(id)) {
|
||||||
return user;
|
resultUser = user;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
usersLock.unlock();
|
usersLock.unlock();
|
||||||
return null;
|
if (resultUser == null) {
|
||||||
|
throw new UserNotExistsException("[PerceiveCore] 用户不存在: " + id);
|
||||||
|
}
|
||||||
|
return resultUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CapabilityMethod
|
||||||
public void updateUser(User temp) {
|
public void updateUser(User temp) {
|
||||||
usersLock.lock();
|
usersLock.lock();
|
||||||
User user = selectUser(temp.getUuid());
|
User user = getUser(temp.getUuid());
|
||||||
user.setRelation(temp.getRelation());
|
user.setRelation(temp.getRelation());
|
||||||
user.setImpressions(temp.getImpressions());
|
user.setImpressions(temp.getImpressions());
|
||||||
user.setAttitude(temp.getAttitude());
|
user.setAttitude(temp.getAttitude());
|
||||||
@@ -6,7 +6,7 @@ import lombok.EqualsAndHashCode;
|
|||||||
import work.slhaf.partner.common.serialize.PersistableObject;
|
import work.slhaf.partner.common.serialize.PersistableObject;
|
||||||
import work.slhaf.partner.core.interaction.data.context.subcontext.CoreContext;
|
import work.slhaf.partner.core.interaction.data.context.subcontext.CoreContext;
|
||||||
import work.slhaf.partner.core.interaction.data.context.subcontext.ModuleContext;
|
import work.slhaf.partner.core.interaction.data.context.subcontext.ModuleContext;
|
||||||
import work.slhaf.partner.module.common.AppendPromptData;
|
import work.slhaf.partner.module.common.entity.AppendPromptData;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@@ -4,7 +4,7 @@ import com.alibaba.fastjson2.JSONObject;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import work.slhaf.partner.common.serialize.PersistableObject;
|
import work.slhaf.partner.common.serialize.PersistableObject;
|
||||||
import work.slhaf.partner.module.common.AppendPromptData;
|
import work.slhaf.partner.module.common.entity.AppendPromptData;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -4,6 +4,6 @@ import work.slhaf.partner.core.interaction.data.context.InteractionContext;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public interface InteractionModule {
|
public interface InteractionFlow {
|
||||||
void execute(InteractionContext context) throws IOException, ClassNotFoundException;
|
void execute(InteractionContext context) throws IOException, ClassNotFoundException;
|
||||||
}
|
}
|
||||||
@@ -22,8 +22,8 @@ public class InteractionModulesLoader {
|
|||||||
return interactionModulesLoader;
|
return interactionModulesLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<InteractionModule> registerInteractionModules() throws IOException {
|
public List<InteractionFlow> registerInteractionModules() throws IOException {
|
||||||
List<InteractionModule> moduleList = new ArrayList<>();
|
List<InteractionFlow> moduleList = new ArrayList<>();
|
||||||
List<ModuleConfig> moduleConfigList = Config.getConfig().getModuleConfigList();
|
List<ModuleConfig> moduleConfigList = Config.getConfig().getModuleConfigList();
|
||||||
for (ModuleConfig moduleConfig : moduleConfigList) {
|
for (ModuleConfig moduleConfig : moduleConfigList) {
|
||||||
if (ModuleConfig.Constant.INTERNAL.equals(moduleConfig.getType())) {
|
if (ModuleConfig.Constant.INTERNAL.equals(moduleConfig.getType())) {
|
||||||
@@ -35,24 +35,24 @@ public class InteractionModulesLoader {
|
|||||||
return moduleList;
|
return moduleList;
|
||||||
}
|
}
|
||||||
|
|
||||||
private InteractionModule loadExternalModule(String className, String path) {
|
private InteractionFlow loadExternalModule(String className, String path) {
|
||||||
try {
|
try {
|
||||||
URL jarUrl = new File(path).toURI().toURL();
|
URL jarUrl = new File(path).toURI().toURL();
|
||||||
URLClassLoader loader = new URLClassLoader(new URL[]{jarUrl}, this.getClass().getClassLoader());
|
URLClassLoader loader = new URLClassLoader(new URL[]{jarUrl}, this.getClass().getClassLoader());
|
||||||
|
|
||||||
Class<?> clazz = loader.loadClass(className);
|
Class<?> clazz = loader.loadClass(className);
|
||||||
loader.close();
|
loader.close();
|
||||||
return (InteractionModule) clazz.getMethod("getInstance").invoke(null);
|
return (InteractionFlow) clazz.getMethod("getInstance").invoke(null);
|
||||||
} catch (ClassNotFoundException | InvocationTargetException | IllegalAccessException |
|
} catch (ClassNotFoundException | InvocationTargetException | IllegalAccessException |
|
||||||
NoSuchMethodException | IOException e) {
|
NoSuchMethodException | IOException e) {
|
||||||
throw new RuntimeException("Fail to load internal module: " + className ,e);
|
throw new RuntimeException("Fail to load internal module: " + className ,e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InteractionModule loadInternalModule(String className) {
|
private static InteractionFlow loadInternalModule(String className) {
|
||||||
try {
|
try {
|
||||||
Class<?> clazz = Class.forName(className);
|
Class<?> clazz = Class.forName(className);
|
||||||
return (InteractionModule) clazz.getMethod("getInstance").invoke(null);
|
return (InteractionFlow) clazz.getMethod("getInstance").invoke(null);
|
||||||
} catch (ClassNotFoundException | InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
|
} catch (ClassNotFoundException | InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
|
||||||
throw new RuntimeException("Fail to load internal module: " + className,e);
|
throw new RuntimeException("Fail to load internal module: " + className,e);
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package work.slhaf.partner.module.common;
|
package work.slhaf.partner.module.common.entity;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package work.slhaf.partner.module.common.model;
|
||||||
|
|
||||||
|
import work.slhaf.partner.common.chat.ChatClient;
|
||||||
|
import work.slhaf.partner.common.chat.constant.ChatConstant;
|
||||||
|
import work.slhaf.partner.common.chat.pojo.ChatResponse;
|
||||||
|
import work.slhaf.partner.common.chat.pojo.Message;
|
||||||
|
import work.slhaf.partner.common.config.ModelConfig;
|
||||||
|
import work.slhaf.partner.common.util.ResourcesUtil;
|
||||||
|
import work.slhaf.partner.module.common.module.Module;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface ActivateModel {
|
||||||
|
|
||||||
|
default void modelSettings() {
|
||||||
|
Model model = getModel();
|
||||||
|
ModelConfig modelConfig = ModelConfig.load(modelKey());
|
||||||
|
model.setBaseMessages(withAwareness() ? ResourcesUtil.Prompt.loadPromptWithSelfAwareness(modelKey(), promptModule()) : ResourcesUtil.Prompt.loadPrompt(modelKey(), promptModule()));
|
||||||
|
model.setChatClient(new ChatClient(modelConfig.getBaseUrl(), modelConfig.getApikey(), modelConfig.getModel()));
|
||||||
|
}
|
||||||
|
|
||||||
|
default ChatResponse chat() {
|
||||||
|
Model model = getModel();
|
||||||
|
List<Message> temp = new ArrayList<>();
|
||||||
|
temp.addAll(model.baseMessages);
|
||||||
|
temp.addAll(model.chatMessages);
|
||||||
|
return model.chatClient.runChat(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
default ChatResponse singleChat(String input) {
|
||||||
|
Model model = getModel();
|
||||||
|
List<Message> temp = new ArrayList<>(model.baseMessages);
|
||||||
|
temp.add(new Message(ChatConstant.Character.USER, input));
|
||||||
|
return model.chatClient.runChat(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
default void updateChatClientSettings() {
|
||||||
|
Model model = getModel();
|
||||||
|
model.chatClient.setTemperature(0.4);
|
||||||
|
model.chatClient.setTop_p(0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
default List<Message> chatMessages() {
|
||||||
|
return getModel().getChatMessages();
|
||||||
|
}
|
||||||
|
|
||||||
|
default List<Message> baseMessages() {
|
||||||
|
return getModel().getBaseMessages();
|
||||||
|
}
|
||||||
|
|
||||||
|
default ChatClient chatClient() {
|
||||||
|
return getModel().getChatClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仅适用Module子类,否则需要重写
|
||||||
|
*
|
||||||
|
* @return 持有的model实例
|
||||||
|
*/
|
||||||
|
default Model getModel() {
|
||||||
|
return ((Module) this).getModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
default void setModel(Model model) {
|
||||||
|
((Module) this).setModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
String modelKey();
|
||||||
|
|
||||||
|
boolean withAwareness();
|
||||||
|
|
||||||
|
String promptModule();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package work.slhaf.partner.module.common.model;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import work.slhaf.partner.common.chat.ChatClient;
|
||||||
|
import work.slhaf.partner.common.chat.constant.ChatConstant;
|
||||||
|
import work.slhaf.partner.common.chat.pojo.ChatResponse;
|
||||||
|
import work.slhaf.partner.common.chat.pojo.Message;
|
||||||
|
import work.slhaf.partner.common.config.ModelConfig;
|
||||||
|
import work.slhaf.partner.common.util.ResourcesUtil;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public abstract class Model {
|
||||||
|
|
||||||
|
protected ChatClient chatClient;
|
||||||
|
protected List<Message> chatMessages;
|
||||||
|
protected List<Message> baseMessages;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package work.slhaf.partner.module.common;
|
package work.slhaf.partner.module.common.model;
|
||||||
|
|
||||||
public class ModelConstant {
|
public class ModelConstant {
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package work.slhaf.partner.module.common.module;
|
||||||
|
|
||||||
|
import work.slhaf.partner.core.interaction.module.InteractionFlow;
|
||||||
|
|
||||||
|
public abstract class CoreModule extends InteractionModule {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package work.slhaf.partner.module.common.module;
|
||||||
|
|
||||||
|
import work.slhaf.partner.core.interaction.module.InteractionFlow;
|
||||||
|
|
||||||
|
public abstract class InteractionModule extends Module implements InteractionFlow {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package work.slhaf.partner.module.common.module;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import work.slhaf.partner.api.capability.module.CapabilityHolder;
|
||||||
|
import work.slhaf.partner.module.common.model.Model;
|
||||||
|
|
||||||
|
public abstract class Module extends CapabilityHolder {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
protected Model model;
|
||||||
|
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user