mirror of
https://github.com/slhaf/Partner.git
synced 2026-10-25 02:43:49 +00:00
Compare commits
4
Commits
a929b3e0e6
...
23a1b7093e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23a1b7093e | ||
|
|
9de46f3589 | ||
|
|
fd8a0642b3 | ||
|
|
cffb369aef |
@@ -12,6 +12,7 @@ public abstract class VectorClient {
|
|||||||
|
|
||||||
public static boolean status = false;
|
public static boolean status = false;
|
||||||
public static VectorClient INSTANCE;
|
public static VectorClient INSTANCE;
|
||||||
|
public static String VECTOR_MODEL_ID;
|
||||||
|
|
||||||
public static void startClient(VectorConfig config) {
|
public static void startClient(VectorConfig config) {
|
||||||
try {
|
try {
|
||||||
@@ -23,6 +24,7 @@ public abstract class VectorClient {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
status = true;
|
status = true;
|
||||||
|
VECTOR_MODEL_ID = config.modelId;
|
||||||
} catch (VectorClientStartupException e) {
|
} catch (VectorClientStartupException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (VectorClientExecutionException e) {
|
} catch (VectorClientExecutionException e) {
|
||||||
|
|||||||
+1
-1
@@ -39,7 +39,7 @@ public class VectorClientRegistry implements Configurable, ConfigRegistration<Ve
|
|||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public VectorConfig defaultConfig() {
|
public VectorConfig defaultConfig() {
|
||||||
return new VectorConfig(false, null);
|
return new VectorConfig(false, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -5,10 +5,16 @@ import work.slhaf.partner.framework.agent.config.Config;
|
|||||||
public sealed class VectorConfig extends Config permits VectorConfig.Ollama, VectorConfig.Onnx {
|
public sealed class VectorConfig extends Config permits VectorConfig.Ollama, VectorConfig.Onnx {
|
||||||
final boolean enabled;
|
final boolean enabled;
|
||||||
final Type type;
|
final Type type;
|
||||||
|
final String modelId;
|
||||||
|
|
||||||
public VectorConfig(boolean enabled, Type type) {
|
public VectorConfig(boolean enabled, Type type, String modelId) {
|
||||||
this.enabled = enabled;
|
this.enabled = enabled;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.modelId = modelId;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static String fallbackModelId(String modelId, String fallback) {
|
||||||
|
return modelId == null || modelId.isBlank() ? fallback : modelId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Type {
|
public enum Type {
|
||||||
@@ -21,8 +27,8 @@ public sealed class VectorConfig extends Config permits VectorConfig.Ollama, Vec
|
|||||||
final String tokenizerPath;
|
final String tokenizerPath;
|
||||||
final String embeddingModelPath;
|
final String embeddingModelPath;
|
||||||
|
|
||||||
public Onnx(boolean enabled, Type type, String tokenizerPath, String embeddingModelPath) {
|
public Onnx(boolean enabled, Type type, String tokenizerPath, String embeddingModelPath, String modelId) {
|
||||||
super(enabled, type);
|
super(enabled, type, fallbackModelId(modelId, embeddingModelPath));
|
||||||
this.tokenizerPath = tokenizerPath;
|
this.tokenizerPath = tokenizerPath;
|
||||||
this.embeddingModelPath = embeddingModelPath;
|
this.embeddingModelPath = embeddingModelPath;
|
||||||
}
|
}
|
||||||
@@ -33,12 +39,10 @@ public sealed class VectorConfig extends Config permits VectorConfig.Ollama, Vec
|
|||||||
final String ollamaEmbeddingUrl;
|
final String ollamaEmbeddingUrl;
|
||||||
final String ollamaEmbeddingModel;
|
final String ollamaEmbeddingModel;
|
||||||
|
|
||||||
public Ollama(boolean enabled, Type type, String ollamaEmbeddingUrl, String ollamaEmbeddingModel) {
|
public Ollama(boolean enabled, Type type, String ollamaEmbeddingUrl, String ollamaEmbeddingModel, String modelId) {
|
||||||
super(enabled, type);
|
super(enabled, type, fallbackModelId(modelId, ollamaEmbeddingModel));
|
||||||
this.ollamaEmbeddingUrl = ollamaEmbeddingUrl;
|
this.ollamaEmbeddingUrl = ollamaEmbeddingUrl;
|
||||||
this.ollamaEmbeddingModel = ollamaEmbeddingModel;
|
this.ollamaEmbeddingModel = ollamaEmbeddingModel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package work.slhaf.partner.core.cognition.impression
|
package work.slhaf.partner.core.cognition.impression
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONArray
|
||||||
import com.alibaba.fastjson2.JSONObject
|
import com.alibaba.fastjson2.JSONObject
|
||||||
import work.slhaf.partner.framework.agent.state.State
|
import work.slhaf.partner.framework.agent.state.State
|
||||||
import work.slhaf.partner.framework.agent.state.StateSerializable
|
import work.slhaf.partner.framework.agent.state.StateSerializable
|
||||||
@@ -110,7 +111,6 @@ class Entity @JvmOverloads constructor(
|
|||||||
}.toSet()
|
}.toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun showFeatures(): Set<FeatureView> = featureLock.withLock {
|
fun showFeatures(): Set<FeatureView> = featureLock.withLock {
|
||||||
features.map {
|
features.map {
|
||||||
FeatureView(
|
FeatureView(
|
||||||
@@ -120,6 +120,14 @@ class Entity @JvmOverloads constructor(
|
|||||||
}.toSet()
|
}.toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun snapshotImpressions(): Map<String, IndexableData> = impressionLock.withLock {
|
||||||
|
impressions.toMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun snapshotFeatures(): Map<String, IndexableData> = featureLock.withLock {
|
||||||
|
features.toMap()
|
||||||
|
}
|
||||||
|
|
||||||
override fun statePath(): Path = Path.of("core", "impression", "entity-$uuid.json")
|
override fun statePath(): Path = Path.of("core", "impression", "entity-$uuid.json")
|
||||||
|
|
||||||
override fun load(state: JSONObject) {
|
override fun load(state: JSONObject) {
|
||||||
@@ -130,7 +138,7 @@ class Entity @JvmOverloads constructor(
|
|||||||
val relationObject = relationValue as? JSONObject ?: return@forEach
|
val relationObject = relationValue as? JSONObject ?: return@forEach
|
||||||
val relationMap = mutableMapOf<String, Double>()
|
val relationMap = mutableMapOf<String, Double>()
|
||||||
relationObject.forEach { (relation, strengthValue) ->
|
relationObject.forEach { (relation, strengthValue) ->
|
||||||
numberValue(strengthValue)?.let { relationMap[relation] = it }
|
doubleValue(strengthValue)?.let { relationMap[relation] = it }
|
||||||
}
|
}
|
||||||
if (relationMap.isNotEmpty()) {
|
if (relationMap.isNotEmpty()) {
|
||||||
relations[target] = relationMap
|
relations[target] = relationMap
|
||||||
@@ -182,39 +190,67 @@ class Entity @JvmOverloads constructor(
|
|||||||
private fun loadIndexableDataMap(state: JSONObject): Map<String, IndexableData> {
|
private fun loadIndexableDataMap(state: JSONObject): Map<String, IndexableData> {
|
||||||
val loaded = mutableMapOf<String, IndexableData>()
|
val loaded = mutableMapOf<String, IndexableData>()
|
||||||
state.forEach { (key, value) ->
|
state.forEach { (key, value) ->
|
||||||
val confidence = when (value) {
|
val data = when (value) {
|
||||||
is JSONObject -> value.getDouble("confidence")?.toDouble() ?: 1.0
|
is JSONObject -> loadIndexableData(value)
|
||||||
else -> numberValue(value) ?: return@forEach
|
else -> IndexableData(doubleValue(value) ?: return@forEach)
|
||||||
}
|
}
|
||||||
loaded[key] = IndexableData(confidence)
|
loaded[key] = data
|
||||||
}
|
}
|
||||||
return loaded
|
return loaded
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun indexableDataState(source: Map<String, IndexableData>): Map<String, Map<String, Double>> =
|
private fun loadIndexableData(state: JSONObject): IndexableData {
|
||||||
source.mapValues { (_, data) -> mapOf("confidence" to data.confidence) }
|
val data = IndexableData(state.getDouble("confidence") ?: 1.0)
|
||||||
|
state.getJSONObject("vectors")?.forEach { (embeddingModel, vectorValue) ->
|
||||||
|
val vectorArray = vectorValue as? JSONArray ?: return@forEach
|
||||||
|
val vector = FloatArray(vectorArray.size)
|
||||||
|
for (index in vectorArray.indices) {
|
||||||
|
vector[index] = floatValue(vectorArray[index]) ?: return@forEach
|
||||||
|
}
|
||||||
|
data.updateVector(embeddingModel, vector)
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
private fun numberValue(value: Any?): Double? = when (value) {
|
private fun indexableDataState(source: Map<String, IndexableData>): Map<String, Map<String, Any>> =
|
||||||
|
source.mapValues { (_, data) ->
|
||||||
|
mapOf(
|
||||||
|
"confidence" to data.confidence,
|
||||||
|
"vectors" to data.snapshotVectors().mapValues { (_, vector) -> vector.toList() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun doubleValue(value: Any?): Double? = when (value) {
|
||||||
is Number -> value.toDouble()
|
is Number -> value.toDouble()
|
||||||
is String -> value.toDoubleOrNull()
|
is String -> value.toDoubleOrNull()
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun floatValue(value: Any?): Float? = when (value) {
|
||||||
|
is Number -> value.toFloat()
|
||||||
|
is String -> value.toFloatOrNull()
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
data class IndexableData(
|
data class IndexableData(
|
||||||
var confidence: Double
|
var confidence: Double
|
||||||
) {
|
) {
|
||||||
private val vectors: ConcurrentHashMap<String, DoubleArray> = ConcurrentHashMap()
|
private val vectors: ConcurrentHashMap<String, FloatArray> = ConcurrentHashMap()
|
||||||
|
|
||||||
fun updateVector(
|
fun updateVector(
|
||||||
embeddingModel: String,
|
embeddingModel: String,
|
||||||
vector: DoubleArray
|
vector: FloatArray
|
||||||
) {
|
) {
|
||||||
vectors[embeddingModel] = vector
|
vectors[embeddingModel] = vector.copyOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getVector(embeddingModel: String): DoubleArray? {
|
fun getVector(embeddingModel: String): FloatArray? {
|
||||||
return vectors[embeddingModel]?.copyOf()
|
return vectors[embeddingModel]?.copyOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun snapshotVectors(): Map<String, FloatArray> {
|
||||||
|
return vectors.mapValues { (_, vector) -> vector.copyOf() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class RelationView(
|
data class RelationView(
|
||||||
@@ -231,6 +267,6 @@ class Entity @JvmOverloads constructor(
|
|||||||
data class ImpressionView(
|
data class ImpressionView(
|
||||||
val impression: String,
|
val impression: String,
|
||||||
val confidence: Double,
|
val confidence: Double,
|
||||||
val vector: DoubleArray?
|
val vector: FloatArray?
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-4
@@ -1,13 +1,38 @@
|
|||||||
package work.slhaf.partner.core.cognition.impression;
|
package work.slhaf.partner.core.cognition.impression;
|
||||||
|
|
||||||
|
import work.slhaf.partner.common.vector.VectorClient;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
public class ImpressionVectorIndex {
|
public class ImpressionVectorIndex {
|
||||||
|
|
||||||
public void sync(Entity entity){
|
private final Executor executor = Executors.newFixedThreadPool(2, r -> {
|
||||||
// TODO sync entity impressions/features with vector index.
|
Thread thread = new Thread(r, "impression-vector-index");
|
||||||
|
thread.setDaemon(true);
|
||||||
|
return thread;
|
||||||
|
});
|
||||||
|
|
||||||
|
public void sync(Entity entity) {
|
||||||
|
if (!VectorClient.status){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
entity.snapshotFeatures().forEach(this::upsert);
|
||||||
|
entity.snapshotImpressions().forEach(this::upsert);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void upsert(String content, Entity.IndexableData indexableData){
|
public void upsert(String text, Entity.IndexableData indexableData){
|
||||||
// TODO update vector for content when embedding/vector client boundary is finalized.
|
if (VectorClient.status){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String modelId = VectorClient.VECTOR_MODEL_ID;
|
||||||
|
if (indexableData.getVector(modelId) != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
executor.execute(() -> {
|
||||||
|
float[] vector = VectorClient.INSTANCE.compute(text);
|
||||||
|
indexableData.updateVector(modelId,vector);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user