- 新建模块Partner-Api,推进Partner适配核心服务注册机制。

- 将原有的模块体系进一步区分,分离模型持有能力与调用能力,Model将有Module自身持有,可通过ActivateModel开启相应能力
This commit is contained in:
2025-07-21 23:47:52 +08:00
parent c9c9b05f18
commit 954095aa55
154 changed files with 1426 additions and 595 deletions

10
.idea/encodings.xml generated
View File

@@ -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
View File

@@ -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">

View File

@@ -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

View File

@@ -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>

View File

@@ -0,0 +1,5 @@
package work.slhaf.partner.api.capability;
public class BaseCoordinateManager {
}

View File

@@ -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();
}
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 {
}

View File

@@ -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();
} }

View File

@@ -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;

View File

@@ -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();
} }

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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>

View File

@@ -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;

View File

@@ -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;

View File

@@ -0,0 +1,5 @@
public interface InterfaceTest {
default String getName(){
return "111";
}
}

View File

@@ -0,0 +1,9 @@
import org.junit.jupiter.api.Test;
public class TestImpl implements InterfaceTest{
@Test
public void test(){
System.out.println(getName());
}
}

View File

@@ -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 {
}

View File

@@ -1,4 +0,0 @@
package work.slhaf.partner.core.cognation.capability.ability;
public interface DispatchCapability {
}

View File

@@ -1,7 +0,0 @@
package work.slhaf.partner.core.cognation.capability.exception;
public class CapabilityRegisterFailedException extends RuntimeException {
public CapabilityRegisterFailedException(String message) {
super(message);
}
}

View File

@@ -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());
}
}
}

View File

@@ -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
View 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>

View File

@@ -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) {

View File

@@ -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);
}
} }

View File

@@ -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();
} }

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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;
} }
} }

View File

@@ -0,0 +1,4 @@
package work.slhaf.partner.core.cognation.submodule.dispatch;
public interface DispatchCapability {
}

View File

@@ -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);
} }

View File

@@ -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();
}
} }

View File

@@ -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);

View File

@@ -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());

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
} }

View File

@@ -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);
} }

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -1,4 +1,4 @@
package work.slhaf.partner.module.common; package work.slhaf.partner.module.common.model;
public class ModelConstant { public class ModelConstant {

View File

@@ -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 {
}

View File

@@ -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 {
}

View File

@@ -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