add upload vector knowledge files
This commit is contained in:
parent
c3e048d1a7
commit
16c50075ee
|
|
@ -61,4 +61,8 @@ public interface IFileStorageService
|
|||
bool SaveSpeechFile(string conversationId, string fileName, BinaryData data);
|
||||
BinaryData GetSpeechFile(string conversationId, string fileName);
|
||||
#endregion
|
||||
|
||||
#region Knowledge
|
||||
bool SaveKnowledgeFiles(string collectionName, string fileId, string fileName, Stream stream);
|
||||
#endregion
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ public interface IKnowledgeService
|
|||
#endregion
|
||||
|
||||
#region Document
|
||||
Task<UploadKnowledgeResponse> UploadVectorKnowledge(string collectionName, IEnumerable<InputFileModel> files);
|
||||
#endregion
|
||||
|
||||
#region Common
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
namespace BotSharp.Abstraction.Knowledges.Models;
|
||||
|
||||
public class UploadKnowledgeResponse
|
||||
{
|
||||
[JsonPropertyName("success")]
|
||||
public IEnumerable<string> Success { get; set; } = new List<string>();
|
||||
|
||||
[JsonPropertyName("failed")]
|
||||
public IEnumerable<string> Failed { get; set; } = new List<string>();
|
||||
}
|
||||
|
|
@ -44,6 +44,13 @@ public static class StringExtensions
|
|||
return str1.Equals(str2, option);
|
||||
}
|
||||
|
||||
public static string RemoveWhiteSpaces(this string? str)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(str)) return string.Empty;
|
||||
|
||||
return str.Replace(" ", "").Replace("\t", "").Replace("\n", "").Replace("\r", "");
|
||||
}
|
||||
|
||||
public static string JsonContent(this string text)
|
||||
{
|
||||
var m = Regex.Match(text, @"\{(?:[^{}]|(?<open>\{)|(?<-open>\}))+(?(open)(?!))\}");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
using System.IO;
|
||||
|
||||
namespace BotSharp.Core.Files.Services;
|
||||
|
||||
public partial class LocalFileStorageService
|
||||
{
|
||||
public bool SaveKnowledgeFiles(string collectionName, string fileId, string fileName, Stream stream)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(collectionName) || string.IsNullOrWhiteSpace(fileId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var dir = Path.Combine(_baseDir, KNOWLEDGE_FOLDER, KNOWLEDGE_DOC_FOLDER, collectionName, fileId);
|
||||
if (ExistDirectory(dir))
|
||||
{
|
||||
Directory.Delete(dir);
|
||||
}
|
||||
Directory.CreateDirectory(dir);
|
||||
|
||||
var filePath = Path.Combine(dir, fileName);
|
||||
using var fs = File.Create(filePath);
|
||||
stream.CopyTo(fs);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning($"Error when saving knowledge file (Collection: {collectionName}, File name: {fileName}). {ex.Message}\r\n{ex.InnerException}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,8 @@ public partial class LocalFileStorageService : IFileStorageService
|
|||
private const string USER_AVATAR_FOLDER = "avatar";
|
||||
private const string SESSION_FOLDER = "sessions";
|
||||
private const string TEXT_TO_SPEECH_FOLDER = "speeches";
|
||||
private const string KNOWLEDGE_FOLDER = "knowledgebase";
|
||||
private const string KNOWLEDGE_DOC_FOLDER = "document";
|
||||
|
||||
public LocalFileStorageService(
|
||||
BotSharpDatabaseSettings dbSettings,
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ public partial class FileRepository : IBotSharpRepository
|
|||
private const string AGENT_RESPONSES_FOLDER = "responses";
|
||||
private const string AGENT_TASKS_FOLDER = "tasks";
|
||||
private const string USERS_FOLDER = "users";
|
||||
private const string KNOWLEDGE_FOLDER = "knowledge";
|
||||
private const string KNOWLEDGE_FOLDER = "knowledgebase";
|
||||
private const string VECTOR_FOLDER = "vector";
|
||||
private const string COLLECTION_CONFIG_FILE = "collection-config.json";
|
||||
|
||||
|
|
|
|||
|
|
@ -366,8 +366,7 @@ public class ConversationController : ControllerBase
|
|||
|
||||
#region Files and attachments
|
||||
[HttpPost("/conversation/{conversationId}/attachments")]
|
||||
public IActionResult UploadAttachments([FromRoute] string conversationId,
|
||||
IFormFile[] files)
|
||||
public IActionResult UploadAttachments([FromRoute] string conversationId, IFormFile[] files)
|
||||
{
|
||||
if (files != null && files.Length > 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -99,29 +99,6 @@ public class KnowledgeBaseController : ControllerBase
|
|||
{
|
||||
return await _knowledgeService.DeleteVectorCollectionData(collection, id);
|
||||
}
|
||||
|
||||
[HttpPost("/knowledge/vector/{collection}/upload")]
|
||||
public async Task<IActionResult> UploadVectorKnowledge([FromRoute] string collection, IFormFile file, [FromForm] int? startPageNum, [FromForm] int? endPageNum)
|
||||
{
|
||||
var setttings = _services.GetRequiredService<FileCoreSettings>();
|
||||
var textConverter = _services.GetServices<IPdf2TextConverter>().FirstOrDefault(x => x.Provider == setttings.Pdf2TextConverter.Provider);
|
||||
|
||||
var filePath = Path.GetTempFileName();
|
||||
using (var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||
{
|
||||
await file.CopyToAsync(stream);
|
||||
await stream.FlushAsync();
|
||||
}
|
||||
|
||||
var content = await textConverter.ConvertPdfToText(filePath, startPageNum, endPageNum);
|
||||
await _knowledgeService.FeedVectorKnowledge(collection, new KnowledgeCreationModel
|
||||
{
|
||||
Content = content
|
||||
});
|
||||
|
||||
System.IO.File.Delete(filePath);
|
||||
return Ok(new { count = 1, file.Length });
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
|
@ -144,7 +121,35 @@ public class KnowledgeBaseController : ControllerBase
|
|||
|
||||
|
||||
#region Document
|
||||
//[HttpPost("/knowledge/vector/{collection}/upload")]
|
||||
//public async Task<IActionResult> UploadVectorKnowledge([FromRoute] string collection, IFormFile file, [FromForm] int? startPageNum, [FromForm] int? endPageNum)
|
||||
//{
|
||||
// var setttings = _services.GetRequiredService<FileCoreSettings>();
|
||||
// var textConverter = _services.GetServices<IPdf2TextConverter>().FirstOrDefault(x => x.Provider == setttings.Pdf2TextConverter.Provider);
|
||||
|
||||
// var filePath = Path.GetTempFileName();
|
||||
// using (var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||
// {
|
||||
// await file.CopyToAsync(stream);
|
||||
// await stream.FlushAsync();
|
||||
// }
|
||||
|
||||
// var content = await textConverter.ConvertPdfToText(filePath, startPageNum, endPageNum);
|
||||
// await _knowledgeService.FeedVectorKnowledge(collection, new KnowledgeCreationModel
|
||||
// {
|
||||
// Content = content
|
||||
// });
|
||||
|
||||
// System.IO.File.Delete(filePath);
|
||||
// return Ok(new { count = 1, file.Length });
|
||||
//}
|
||||
|
||||
[HttpPost("/knowledge/vector/{collection}/upload")]
|
||||
public async Task<UploadKnowledgeResponse> UploadVectorKnowledge([FromRoute] string collection, [FromBody] VectorKnowledgeUploadRequest request)
|
||||
{
|
||||
var response = await _knowledgeService.UploadVectorKnowledge(collection, request.Files);
|
||||
return response;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Common
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
namespace BotSharp.OpenAPI.ViewModels.Knowledges;
|
||||
|
||||
public class VectorKnowledgeUploadRequest
|
||||
{
|
||||
public IEnumerable<InputFileModel> Files { get; set; } = new List<InputFileModel>();
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@ public class NativeWhisperProvider : IAudioCompletion
|
|||
private readonly IFileStorageService _fileStorage;
|
||||
private readonly ILogger<NativeWhisperProvider> _logger;
|
||||
|
||||
public string Provider => "native";
|
||||
public string Provider => "native-whisper";
|
||||
|
||||
public NativeWhisperProvider(
|
||||
BotSharpDatabaseSettings dbSettings,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,89 @@
|
|||
using BotSharp.Abstraction.Files;
|
||||
using BotSharp.Abstraction.Files.Models;
|
||||
using BotSharp.Abstraction.Files.Utilities;
|
||||
|
||||
namespace BotSharp.Plugin.KnowledgeBase.Services;
|
||||
|
||||
public partial class KnowledgeService
|
||||
{
|
||||
public async Task<UploadKnowledgeResponse> UploadVectorKnowledge(string collectionName, IEnumerable<InputFileModel> files)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(collectionName))
|
||||
{
|
||||
return new UploadKnowledgeResponse
|
||||
{
|
||||
Success = [],
|
||||
Failed = files.Select(x => x.FileName)
|
||||
};
|
||||
}
|
||||
|
||||
var fileStoreage = _services.GetRequiredService<IFileStorageService>();
|
||||
var cleanCollectionName = collectionName.RemoveWhiteSpaces();
|
||||
var successFiles = new List<string>();
|
||||
var failedFiles = new List<string>();
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(file.FileData) || string.IsNullOrWhiteSpace(file.FileName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var dataIds = new List<string>();
|
||||
|
||||
try
|
||||
{
|
||||
// Chop text
|
||||
var (contentType, bytes) = FileUtility.GetFileInfoFromData(file.FileData);
|
||||
using var stream = new MemoryStream(bytes);
|
||||
using var reader = new StreamReader(stream);
|
||||
var content = await reader.ReadToEndAsync();
|
||||
|
||||
// Save file
|
||||
var fileId = Guid.NewGuid().ToString();
|
||||
var saved = fileStoreage.SaveKnowledgeFiles(cleanCollectionName, fileId, file.FileName, stream);
|
||||
reader.Close();
|
||||
stream.Close();
|
||||
|
||||
if (!saved)
|
||||
{
|
||||
failedFiles.Add(file.FileName);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Text embedding
|
||||
var vectorDb = GetVectorDb();
|
||||
var textEmbedding = GetTextEmbedding(collectionName);
|
||||
var vector = await textEmbedding.GetVectorAsync(content);
|
||||
|
||||
// Save to vector db
|
||||
var dataId = Guid.NewGuid();
|
||||
await vectorDb.Upsert(collectionName, dataId, vector, content, new Dictionary<string, string>
|
||||
{
|
||||
{ "fileName", file.FileName },
|
||||
{ "fileId", fileId },
|
||||
{ "page", "0" }
|
||||
});
|
||||
|
||||
dataIds.Add(dataId.ToString());
|
||||
successFiles.Add(file.FileName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"Error when processing knowledge file ({file.FileName}). {ex.Message}\r\n{ex.InnerException}");
|
||||
failedFiles.Add(file.FileName);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return new UploadKnowledgeResponse
|
||||
{
|
||||
Success = successFiles,
|
||||
Failed = failedFiles
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public async Task FeedVectorKnowledge(string collectionName, KnowledgeCreationModel knowledge)
|
||||
{
|
||||
var index = 0;
|
||||
|
|
@ -24,4 +106,7 @@ public partial class KnowledgeService
|
|||
Console.WriteLine($"Saved vector {index}/{lines.Count}: {line}\n");
|
||||
}
|
||||
}
|
||||
|
||||
#region Private methods
|
||||
#endregion
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,7 +141,8 @@
|
|||
"Enable": true,
|
||||
"BatchSize": 50,
|
||||
"MessageLimit": 2,
|
||||
"BufferHours": 12
|
||||
"BufferHours": 12,
|
||||
"ExcludeAgentIds": []
|
||||
},
|
||||
"RateLimit": {
|
||||
"MaxConversationPerDay": 100,
|
||||
|
|
|
|||
Loading…
Reference in a new issue