2023-06-17 02:42:35 +00:00
|
|
|
using BotSharp.Abstraction.Knowledges.Models;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using BotSharp.Abstraction.MLTasks;
|
|
|
|
|
|
|
|
|
|
namespace BotSharp.Core.Knowledges.Services;
|
|
|
|
|
|
|
|
|
|
public class KnowledgeService : IKnowledgeService
|
|
|
|
|
{
|
|
|
|
|
private readonly ITextEmbedding _textEmbedding;
|
|
|
|
|
private readonly ITextCompletion _textCompletion;
|
2023-06-18 18:15:00 +00:00
|
|
|
private readonly ITextChopper _textChopper;
|
2023-06-18 02:56:22 +00:00
|
|
|
private readonly IVectorDb _db;
|
2023-06-18 18:15:00 +00:00
|
|
|
|
2023-06-18 02:56:22 +00:00
|
|
|
public KnowledgeService(ITextEmbedding textEmbedding,
|
|
|
|
|
ITextCompletion textCompletion,
|
2023-06-18 18:15:00 +00:00
|
|
|
ITextChopper textChopper,
|
2023-06-18 02:56:22 +00:00
|
|
|
IVectorDb db)
|
2023-06-17 02:42:35 +00:00
|
|
|
{
|
|
|
|
|
_textEmbedding = textEmbedding;
|
|
|
|
|
_textCompletion = textCompletion;
|
2023-06-18 18:15:00 +00:00
|
|
|
_textChopper = textChopper;
|
2023-06-18 02:56:22 +00:00
|
|
|
_db = db;
|
2023-06-17 02:42:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task Feed(KnowledgeFeedModel knowledge)
|
|
|
|
|
{
|
|
|
|
|
var idStart = 0;
|
2023-06-18 18:15:00 +00:00
|
|
|
var lines = _textChopper.Chop(knowledge.Content, new ChunkOption
|
|
|
|
|
{
|
|
|
|
|
Size = 256,
|
|
|
|
|
Conjunction = 32
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Store chunks in local file system
|
|
|
|
|
var knowledgeStoreDir = Path.Combine("knowledge_chunks", knowledge.AgentId);
|
|
|
|
|
if(!Directory.Exists(knowledgeStoreDir))
|
|
|
|
|
{
|
|
|
|
|
Directory.CreateDirectory(knowledgeStoreDir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var knowledgePath = Path.Combine(knowledgeStoreDir, knowledge.Name);
|
|
|
|
|
File.WriteAllLines(knowledgePath + ".txt", lines);
|
2023-06-17 02:42:35 +00:00
|
|
|
|
2023-06-18 18:15:00 +00:00
|
|
|
await _db.CreateCollection(knowledge.Name, _textEmbedding.Dimension);
|
2023-06-17 02:42:35 +00:00
|
|
|
foreach (var line in lines)
|
|
|
|
|
{
|
2023-06-18 18:15:00 +00:00
|
|
|
await _db.Upsert(knowledge.Name, idStart, _textEmbedding.GetVector(line));
|
2023-06-17 02:42:35 +00:00
|
|
|
idStart++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-18 18:15:00 +00:00
|
|
|
public async Task<string> GetAnswer(KnowledgeRetrievalModel retrievalModel)
|
2023-06-17 02:42:35 +00:00
|
|
|
{
|
2023-06-18 18:15:00 +00:00
|
|
|
var vector = _textEmbedding.GetVector(retrievalModel.Question);
|
|
|
|
|
|
|
|
|
|
// Scan local knowledge directory
|
|
|
|
|
var knowledgeName = "";
|
|
|
|
|
var chunks = new string[0];
|
|
|
|
|
|
|
|
|
|
foreach (var file in Directory.GetFiles(Path.Combine("knowledge_chunks", retrievalModel.AgentId)))
|
|
|
|
|
{
|
|
|
|
|
knowledgeName = new FileInfo(file).Name.Split('.').First();
|
|
|
|
|
chunks = File.ReadAllLines(file);
|
|
|
|
|
}
|
2023-06-17 02:42:35 +00:00
|
|
|
|
|
|
|
|
// Vector search
|
2023-06-18 18:15:00 +00:00
|
|
|
var result = await _db.Search(knowledgeName, vector);
|
2023-06-17 02:42:35 +00:00
|
|
|
|
2023-06-18 18:15:00 +00:00
|
|
|
// Restore
|
2023-06-17 02:42:35 +00:00
|
|
|
var prompt = "";
|
2023-06-18 02:56:22 +00:00
|
|
|
foreach (var r in result)
|
2023-06-17 02:42:35 +00:00
|
|
|
{
|
2023-06-18 18:15:00 +00:00
|
|
|
prompt += chunks[r] + "\n";
|
2023-06-17 02:42:35 +00:00
|
|
|
}
|
|
|
|
|
|
2023-06-18 18:15:00 +00:00
|
|
|
prompt += "\r\n###\r\n";
|
2023-06-17 02:42:35 +00:00
|
|
|
prompt += "Answer the user's question based on the content provided above, and your reply should be as concise and organized as possible.\r\n";
|
2023-06-18 18:15:00 +00:00
|
|
|
prompt += $"Question: {retrievalModel.Question}\r\nAnswer: ";
|
2023-06-17 02:42:35 +00:00
|
|
|
|
|
|
|
|
var completion = await _textCompletion.GetCompletion(prompt);
|
|
|
|
|
return completion;
|
|
|
|
|
}
|
|
|
|
|
}
|