temp save

This commit is contained in:
Jicheng Lu 2025-08-05 15:46:07 -05:00
parent 3dee140638
commit de3b36368c
9 changed files with 88 additions and 23 deletions

View file

@ -23,8 +23,7 @@ public interface IVectorDb
=> throw new NotImplementedException();
Task<bool> Upsert(string collectionName, Guid id, float[] vector, string text, Dictionary<string, object>? payload = null)
=> throw new NotImplementedException();
Task<IEnumerable<VectorCollectionData>> Search(string collectionName, float[] vector, IEnumerable<string>? fields,
int limit = 5, float confidence = 0.5f, bool withVector = false)
Task<IEnumerable<VectorCollectionData>> Search(string collectionName, float[] vector, VectorSearchOptions? options = null)
=> throw new NotImplementedException();
Task<bool> DeleteCollectionData(string collectionName, List<Guid> ids)
=> throw new NotImplementedException();

View file

@ -8,8 +8,8 @@ public class VectorFilter : StringIdPagination
/// <summary>
/// For keyword search
/// </summary>
[JsonPropertyName("search_pairs")]
public IEnumerable<KeyValue>? SearchPairs { get; set; }
[JsonPropertyName("filters")]
public IEnumerable<KeyValue>? Filters { get; set; }
/// <summary>

View file

@ -4,8 +4,21 @@ namespace BotSharp.Abstraction.VectorStorage.Models;
public class VectorSearchOptions
{
public IEnumerable<string>? Fields { get; set; } = new List<string> { KnowledgePayloadName.Text, KnowledgePayloadName.Answer };
public IEnumerable<string>? Fields { get; set; } = [KnowledgePayloadName.Text, KnowledgePayloadName.Answer];
public IEnumerable<KeyValue>? Filters { get; set; }
public int? Limit { get; set; } = 5;
public float? Confidence { get; set; } = 0.5f;
public bool WithVector { get; set; }
public static VectorSearchOptions Default()
{
return new()
{
Fields = [KnowledgePayloadName.Text, KnowledgePayloadName.Answer],
Filters = null,
Limit = 5,
Confidence = 0.5f,
WithVector = false
};
}
}

View file

@ -59,6 +59,7 @@ public class KnowledgeBaseController : ControllerBase
var options = new VectorSearchOptions
{
Fields = request.Fields,
Filters = request.Filters,
Limit = request.Limit ?? 5,
Confidence = request.Confidence ?? 0.5f,
WithVector = request.WithVector
@ -123,6 +124,18 @@ public class KnowledgeBaseController : ControllerBase
{
return await _knowledgeService.DeleteVectorCollectionAllData(collection);
}
[HttpPost("/knowledge/vector/{collection}/payload/index")]
public async Task<bool> CreateCollectionPayloadIndex()
{
return false;
}
[HttpDelete("/knowledge/vector/{collection}/payload/index")]
public async Task<bool> DeleteCollectionPayloadIndex()
{
return false;
}
#endregion

View file

@ -10,6 +10,9 @@ public class SearchVectorKnowledgeRequest
[JsonPropertyName("fields")]
public IEnumerable<string>? Fields { get; set; }
[JsonPropertyName("filters")]
public IEnumerable<KeyValue>? Filters { get; set; }
[JsonPropertyName("limit")]
public int? Limit { get; set; } = 5;

View file

@ -1,3 +1,4 @@
using System.Linq;
using Tensorflow.NumPy;
namespace BotSharp.Plugin.KnowledgeBase.MemVecDb;
@ -44,24 +45,24 @@ public class MemoryVectorDb : IVectorDb
throw new NotImplementedException();
}
public async Task<IEnumerable<VectorCollectionData>> Search(string collectionName, float[] vector,
IEnumerable<string>? fields, int limit = 5, float confidence = 0.5f, bool withVector = false)
public async Task<IEnumerable<VectorCollectionData>> Search(string collectionName, float[] vector, VectorSearchOptions? options = null)
{
if (!_vectors.ContainsKey(collectionName))
{
return new List<VectorCollectionData>();
}
options ??= VectorSearchOptions.Default();
var similarities = VectorHelper.CalCosineSimilarity(vector, _vectors[collectionName]);
var results = np.argsort(similarities).ToArray<int>()
.Reverse()
.Take(limit)
.Take(options.Limit.GetValueOrDefault())
.Select(i => new VectorCollectionData
{
Data = new Dictionary<string, object> { { "text", _vectors[collectionName][i].Text } },
Score = similarities[i],
Vector = withVector ? _vectors[collectionName][i].Vector : null,
Vector = options.WithVector ? _vectors[collectionName][i].Vector : null,
})
.ToList();

View file

@ -308,7 +308,7 @@ public partial class KnowledgeService
// Vector search
var db = GetVectorDb();
var found = await db.Search(collectionName, vector, options.Fields, limit: options.Limit ?? 5, confidence: options.Confidence ?? 0.5f, withVector: options.WithVector);
var found = await db.Search(collectionName, vector, options);
var results = found.Select(x => VectorSearchResult.CopyFrom(x)).ToList();
return results;

View file

@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Qdrant.Client;
using Qdrant.Client.Grpc;
using System.Collections;
using System.Net.Http;
using System.Net.Mime;
using System.Text.Json;
@ -142,9 +143,9 @@ public class QdrantDb : IVectorDb
// Build query filter
Filter? queryFilter = null;
if (!filter.SearchPairs.IsNullOrEmpty())
if (!filter.Filters.IsNullOrEmpty())
{
var conditions = filter.SearchPairs.Select(x => new Condition
var conditions = filter.Filters.Select(x => new Condition
{
Field = new FieldCondition
{
@ -308,8 +309,7 @@ public class QdrantDb : IVectorDb
return result.Status == UpdateStatus.Completed;
}
public async Task<IEnumerable<VectorCollectionData>> Search(string collectionName, float[] vector,
IEnumerable<string>? fields, int limit = 5, float confidence = 0.5f, bool withVector = false)
public async Task<IEnumerable<VectorCollectionData>> Search(string collectionName, float[] vector, VectorSearchOptions? options = null)
{
var results = new List<VectorCollectionData>();
@ -319,19 +319,42 @@ public class QdrantDb : IVectorDb
return results;
}
options ??= VectorSearchOptions.Default();
var payloadSelector = new WithPayloadSelector { Enable = true };
if (fields != null)
if (!options.Fields.IsNullOrEmpty())
{
payloadSelector.Include = new PayloadIncludeSelector { Fields = { fields.ToArray() } };
payloadSelector.Include = new PayloadIncludeSelector { Fields = { options.Fields.ToArray() } };
}
Filter? queryFilter = null;
if (!options.Filters.IsNullOrEmpty())
{
var conditions = options.Filters.Select(x => new Condition
{
Field = new FieldCondition
{
Key = x.Key,
Match = new Match { Text = x.Value },
}
});
queryFilter = new Filter
{
Should =
{
conditions
}
};
}
var client = GetClient();
var points = await client.SearchAsync(collectionName,
vector,
limit: (ulong)limit,
scoreThreshold: confidence,
limit: (ulong)options.Limit.GetValueOrDefault(),
scoreThreshold: options.Confidence,
filter: queryFilter,
payloadSelector: payloadSelector,
vectorsSelector: withVector);
vectorsSelector: options.WithVector);
results = points.Select(x => new VectorCollectionData
{
@ -377,6 +400,19 @@ public class QdrantDb : IVectorDb
var result = await client.DeleteAsync(collectionName, new Filter());
return result.Status == UpdateStatus.Completed;
}
//public async Task<bool> CreateCollectionPayloadIndex(string collectionName)
//{
// var exist = await DoesCollectionExist(collectionName);
// if (!exist)
// {
// return false;
// }
// var client = GetClient();
// var result = await client.CreatePayloadIndexAsync(collectionName, "text", PayloadSchemaType.Keyword);
//}
#endregion
#region Snapshots

View file

@ -64,10 +64,10 @@ namespace BotSharp.Plugin.SemanticKernel
return result;
}
public async Task<IEnumerable<VectorCollectionData>> Search(string collectionName, float[] vector,
IEnumerable<string>? fields, int limit = 5, float confidence = 0.5f, bool withVector = false)
public async Task<IEnumerable<VectorCollectionData>> Search(string collectionName, float[] vector, VectorSearchOptions? options = null)
{
var results = _memoryStore.GetNearestMatchesAsync(collectionName, vector, limit);
options ??= VectorSearchOptions.Default();
var results = _memoryStore.GetNearestMatchesAsync(collectionName, vector, options.Limit.GetValueOrDefault());
var resultTexts = new List<VectorCollectionData>();
await foreach (var (record, score) in results)
@ -76,7 +76,7 @@ namespace BotSharp.Plugin.SemanticKernel
{
Data = new Dictionary<string, object> { { "text", record.Metadata.Text } },
Score = score,
Vector = withVector ? record.Embedding.ToArray() : null
Vector = options.WithVector ? record.Embedding.ToArray() : null
});
}