477 lines
16 KiB
C#
477 lines
16 KiB
C#
using BLAIzor.Models;
|
|
using Google.Protobuf.Collections;
|
|
using Newtonsoft.Json;
|
|
using Qdrant.Client;
|
|
using Qdrant.Client.Grpc;
|
|
using System.Text;
|
|
|
|
namespace BLAIzor.Services
|
|
{
|
|
public class QDrantService
|
|
{
|
|
public static IConfiguration? _configuration;
|
|
private string qdrantUrl = "https://fe7d5c9e-8cd1-4ad9-af5a-af2bf3b93219.europe-west3-0.gcp.cloud.qdrant.io:6333";
|
|
private readonly string _qdrantHost = "fe7d5c9e-8cd1-4ad9-af5a-af2bf3b93219.europe-west3-0.gcp.cloud.qdrant.io";
|
|
|
|
private string _apiKey = "";
|
|
|
|
public QDrantService(IConfiguration? configuration)
|
|
{
|
|
_configuration = configuration;
|
|
}
|
|
|
|
public string GetApiKey()
|
|
{
|
|
if (_configuration == null)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
if (_configuration.GetSection("QDrant") == null)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
return _configuration.GetSection("QDrant").GetValue<string>("ApiKey")!;
|
|
|
|
}
|
|
|
|
public async Task<int> GetCollectionCount(string collectionName)
|
|
{
|
|
|
|
var client = new QdrantClient(_qdrantHost, 6334, true, _apiKey);
|
|
var result = await client.CountAsync(
|
|
collectionName: collectionName,
|
|
exact: true
|
|
);
|
|
|
|
return Convert.ToInt32(result);
|
|
}
|
|
|
|
public async Task CreateQdrantCollectionAsync()
|
|
{
|
|
_apiKey = GetApiKey();
|
|
var httpClient = new HttpClient();
|
|
|
|
httpClient.DefaultRequestHeaders.Clear();
|
|
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_apiKey}");
|
|
|
|
var collectionName = "web_content";
|
|
var createCollectionPayload = new
|
|
{
|
|
vectors = new { size = 1536, distance = "Cosine" } // Adjust size based on embedding model
|
|
};
|
|
|
|
var content = new StringContent(JsonConvert.SerializeObject(createCollectionPayload), Encoding.UTF8, "application/json");
|
|
var response = await httpClient.PutAsync($"{qdrantUrl}/collections/{collectionName}", content);
|
|
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
Console.WriteLine("Collection created successfully!" + response.Content.ReadAsStringAsync());
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine($"Failed to create collection: {response.StatusCode}");
|
|
}
|
|
}
|
|
|
|
public async Task<string> GetCollectionBySiteIdAsync(int siteId)
|
|
{
|
|
return await GetCollectionByNameAsync("Site" + siteId);
|
|
}
|
|
|
|
public async Task<string> GetCollectionByTemplateIdAsync(int templateId)
|
|
{
|
|
|
|
return await GetCollectionByNameAsync("Template" + templateId);
|
|
|
|
}
|
|
|
|
public async Task<string> GetCollectionByNameAsync(string collectionName)
|
|
{
|
|
_apiKey = GetApiKey();
|
|
|
|
var client = new QdrantClient(_qdrantHost, 6334, true, _apiKey);
|
|
bool doesExist = await client.CollectionExistsAsync(collectionName);
|
|
if (doesExist)
|
|
{
|
|
var response = await client.GetCollectionInfoAsync(collectionName);
|
|
Console.Write(response);
|
|
if (response != null)
|
|
{
|
|
|
|
|
|
return response.PointsCount.ToString();
|
|
|
|
}
|
|
else
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine($"Failed to get collection");
|
|
return string.Empty;
|
|
}
|
|
|
|
}
|
|
|
|
public async Task CreateQdrantCollectionAsync(string collectionName)
|
|
{
|
|
_apiKey = GetApiKey();
|
|
var httpClient = new HttpClient();
|
|
|
|
httpClient.DefaultRequestHeaders.Clear();
|
|
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_apiKey}");
|
|
|
|
var createCollectionPayload = new
|
|
{
|
|
vectors = new { size = 1536, distance = "Cosine" } // Adjust size based on embedding model
|
|
};
|
|
|
|
var content = new StringContent(JsonConvert.SerializeObject(createCollectionPayload), Encoding.UTF8, "application/json");
|
|
var response = await httpClient.PutAsync($"{qdrantUrl}/collections/{collectionName}", content);
|
|
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
Console.WriteLine("Collection created successfully!" + response.Content.ReadAsStringAsync());
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine($"Failed to create collection: {response.StatusCode}");
|
|
}
|
|
}
|
|
|
|
public async Task<string> GetContentAsync(int siteId, int contentId)
|
|
{
|
|
_apiKey = GetApiKey();
|
|
var httpClient = new HttpClient();
|
|
|
|
httpClient.DefaultRequestHeaders.Clear();
|
|
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_apiKey}");
|
|
|
|
|
|
var response = await httpClient.GetAsync($"{qdrantUrl}/collections/Site{siteId.ToString()}/points/{contentId.ToString()}");
|
|
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
var result = await response.Content.ReadAsStringAsync();
|
|
//Console.WriteLine($"Query result: {result}");
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine($"Failed to query snippet: {response.StatusCode}");
|
|
return string.Empty;
|
|
}
|
|
}
|
|
|
|
public async Task<string> GetSnippetAsync(int snippetId, string collectionName)
|
|
{
|
|
_apiKey = GetApiKey();
|
|
var httpClient = new HttpClient();
|
|
|
|
httpClient.DefaultRequestHeaders.Clear();
|
|
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_apiKey}");
|
|
|
|
|
|
var response = await httpClient.GetAsync($"{qdrantUrl}/collections/{collectionName}/points/{snippetId}");
|
|
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
var result = await response.Content.ReadAsStringAsync();
|
|
//Console.WriteLine($"Query result: {result}");
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine($"Failed to query snippet: {response.StatusCode}");
|
|
return string.Empty;
|
|
}
|
|
}
|
|
|
|
public async Task<int> QuerySnippetAsync(float[] queryVector, int limit = 1, string collectionName = "html_snippets")
|
|
{
|
|
_apiKey = GetApiKey();
|
|
//var httpClient = new HttpClient();
|
|
|
|
//httpClient.DefaultRequestHeaders.Clear();
|
|
//httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_apiKey}");
|
|
|
|
//var queryPayload = new
|
|
//{
|
|
// vector = queryVector,
|
|
// limit = limit
|
|
//};
|
|
|
|
var client = new QdrantClient(
|
|
host: _qdrantHost,
|
|
https: true,
|
|
apiKey: _apiKey
|
|
);
|
|
|
|
var doesCollectionExist = await client.CollectionExistsAsync(collectionName);
|
|
if (doesCollectionExist)
|
|
{
|
|
IReadOnlyList<ScoredPoint> response = new List<ScoredPoint>();
|
|
|
|
response = await client.SearchAsync(
|
|
|
|
collectionName: collectionName,
|
|
vector: queryVector,
|
|
limit: 1
|
|
);
|
|
|
|
if (response.Count > 0)
|
|
{
|
|
int sId = -1;
|
|
var result = response.FirstOrDefault();
|
|
//Console.Write(result);
|
|
|
|
sId = Convert.ToInt32(result!.Id.Num);
|
|
|
|
//Console.Write($"Query result: {sId}");
|
|
return sId;
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine($"Failed to query snippet: {response.Count()}");
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine($"Failed to query snippet: no collection");
|
|
return 0;
|
|
}
|
|
//var content = new StringContent(JsonConvert.SerializeObject(queryPayload), Encoding.UTF8, "application/json");
|
|
//var response = await httpClient.PostAsync($"{qdrantUrl}/collections/{collectionName}/points/search", content);
|
|
|
|
|
|
}
|
|
|
|
public async Task<int[]> QueryContentAsync(int siteId, float[] queryVector, int limit = 1)
|
|
{
|
|
_apiKey = GetApiKey();
|
|
var httpClient = new HttpClient();
|
|
|
|
//httpClient.DefaultRequestHeaders.Clear();
|
|
//httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_apiKey}");
|
|
|
|
//var queryPayload = new
|
|
//{
|
|
// vector = queryVector,
|
|
// limit = limit
|
|
//};
|
|
|
|
var client = new QdrantClient(
|
|
host: _qdrantHost,
|
|
https: true,
|
|
apiKey: _apiKey
|
|
);
|
|
|
|
|
|
var response = await client.SearchAsync(
|
|
collectionName: $"Site{siteId}",
|
|
vector: queryVector,
|
|
//filter: MatchKeyword("city", "London"),
|
|
limit: 3
|
|
);
|
|
|
|
//var content = new StringContent(JsonConvert.SerializeObject(queryPayload), Encoding.UTF8, "application/json");
|
|
//var response = await httpClient.PostAsync($"{qdrantUrl}/collections/site{siteId}/points/search", content);
|
|
|
|
//if (response.IsSuccessStatusCode)
|
|
//{
|
|
// int[] sId = [];
|
|
// var result = await response.Content.ReadAsStringAsync();
|
|
// //Console.Write(result);
|
|
// if (!string.IsNullOrEmpty(result))
|
|
// {
|
|
// QDrantQueryResult qdr = JsonConvert.DeserializeObject<QDrantQueryResult>(result)!;
|
|
// int[] valami = new int[qdr.result.Count()];
|
|
// for (int i = 0; i < qdr.result.Count(); i++)
|
|
// {
|
|
// sId[i] = qdr.result[i].id;
|
|
// }
|
|
// sId.AddRange(valami);
|
|
// }
|
|
// //var result = await response.Content.ReadFromJsonAsync<QDrantQueryResult>();
|
|
// //Console.Write($"Query result: {sId}");
|
|
// return sId;
|
|
//}
|
|
//else
|
|
//{
|
|
// Console.WriteLine($"Failed to query snippet: {response.StatusCode}");
|
|
// int[] nullResult = [];
|
|
// return nullResult;
|
|
//}
|
|
if (response.Count() == 0)
|
|
{
|
|
int[] nullResult = [];
|
|
Console.Write("None found");
|
|
return nullResult;
|
|
}
|
|
else
|
|
{
|
|
int[] intResult = new int[response.Count()];
|
|
Console.Write("Found: " + response.FirstOrDefault()!.Id.Num);
|
|
for (int i = 0; i < response.Count(); i++)
|
|
{
|
|
intResult[i] = Convert.ToInt32(response[i].Id.Num);
|
|
}
|
|
return intResult;
|
|
}
|
|
|
|
}
|
|
|
|
public async Task QDrantInsertTest(List<int> ids, List<float[]> vectors, List<MapField<string, Value>> payloads)
|
|
{
|
|
_apiKey = GetApiKey();
|
|
|
|
var client = new QdrantClient(_qdrantHost, 6334, true, _apiKey);
|
|
var valamii = new List<PointStruct>();
|
|
for (int i = 0; i < ids.Count; i++)
|
|
{
|
|
valamii.Add(new PointStruct
|
|
{
|
|
Id = (ulong)ids[i],
|
|
Vectors = vectors[i],
|
|
Payload = { payloads[i] }
|
|
|
|
});
|
|
Console.WriteLine($"{valamii[i].Id} val bekerült {valamii[i].Payload["html"]}");
|
|
}
|
|
|
|
Console.WriteLine(valamii.Count);
|
|
|
|
await client.UpsertAsync(
|
|
collectionName: "html_snippets",
|
|
points: valamii
|
|
);
|
|
|
|
}
|
|
|
|
public async Task QDrantInsertPointAsync(int id, float[] vectors, MapField<string, Value> payload, string collectionName)
|
|
{
|
|
_apiKey = GetApiKey();
|
|
|
|
var client = new QdrantClient(_qdrantHost, 6334, true, _apiKey);
|
|
var pointStruct = new PointStruct();
|
|
|
|
pointStruct = new PointStruct
|
|
{
|
|
Id = (ulong)id,
|
|
Vectors = vectors,
|
|
Payload = { payload }
|
|
|
|
};
|
|
Console.WriteLine($"{pointStruct.Id} val bekerült.");
|
|
|
|
|
|
List<PointStruct> pointStructList = new List<PointStruct> { pointStruct };
|
|
|
|
var result = await client.UpsertAsync(
|
|
collectionName: collectionName,
|
|
points: pointStructList
|
|
);
|
|
|
|
Console.Write("QDrantUpsert: " + result.Status);
|
|
|
|
}
|
|
|
|
public async Task QDrantInsertManyAsync(List<int> ids, List<float[]> vectors, List<MapField<string, Value>> payloads, string collectionName)
|
|
{
|
|
_apiKey = GetApiKey();
|
|
|
|
var client = new QdrantClient(_qdrantHost, 6334, true, _apiKey);
|
|
var pointStructList = new List<PointStruct>();
|
|
for (int i = 0; i < ids.Count; i++)
|
|
{
|
|
pointStructList.Add(new PointStruct
|
|
{
|
|
Id = (ulong)ids[i],
|
|
Vectors = vectors[i],
|
|
Payload = { payloads[i] }
|
|
|
|
});
|
|
Console.WriteLine($"{pointStructList[i].Id} val bekerül {pointStructList[i].Payload["name"]}");
|
|
}
|
|
|
|
Console.WriteLine(pointStructList.Count);
|
|
|
|
await client.UpsertAsync(
|
|
collectionName: collectionName,
|
|
points: pointStructList
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
public class PointResult
|
|
{
|
|
public int id { get; set; }
|
|
public int version { get; set; }
|
|
public double score { get; set; }
|
|
}
|
|
|
|
public class QDrantQueryResult
|
|
{
|
|
public List<PointResult> result { get; set; }
|
|
public string status { get; set; }
|
|
public double time { get; set; }
|
|
}
|
|
|
|
// Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
|
|
//public class Payload
|
|
//{
|
|
// public string description { get; set; }
|
|
// public string type { get; set; }
|
|
// public string name { get; set; }
|
|
// public string html { get; set; }
|
|
//}
|
|
|
|
public class PointData
|
|
{
|
|
public int id { get; set; }
|
|
public HtmlSnippet payload { get; set; }
|
|
public List<double> vector { get; set; }
|
|
}
|
|
|
|
|
|
public class QDrantGetPointResult
|
|
{
|
|
public PointData result { get; set; }
|
|
public string status { get; set; }
|
|
public double time { get; set; }
|
|
}
|
|
|
|
public class QDrantGetContentPointResult
|
|
{
|
|
public ContentPointData result { get; set; }
|
|
public string status { get; set; }
|
|
public double time { get; set; }
|
|
}
|
|
|
|
public class ContentPointData
|
|
{
|
|
public int id { get; set; }
|
|
public ContentPayload payload { get; set; }
|
|
public List<double> vector { get; set; }
|
|
}
|
|
|
|
public class ContentPayload
|
|
{
|
|
public int id { get; set; }
|
|
public string uid { get; set; }
|
|
public string type { get; set; }
|
|
public int siteId { get; set; }
|
|
public string name { get; set; }
|
|
public string description { get; set; }
|
|
public string content { get; set; }
|
|
public DateTime lastUpdated { get; set; }
|
|
}
|
|
}
|