Merge branch 'master' into wechat-plugin

This commit is contained in:
xbotter 2023-06-27 07:14:43 +08:00 committed by GitHub
commit 9774a601b2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 220 additions and 80 deletions

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>

View file

@ -3,6 +3,5 @@ namespace BotSharp.Abstraction.Knowledges.Models;
public class KnowledgeFeedModel
{
public string AgentId { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string Content { get; set; } = string.Empty;
}

View file

@ -1,4 +1,4 @@
namespace BotSharp.Abstraction.Knowledges;
namespace BotSharp.Abstraction.VectorStorage;
public interface IVectorDb
{

View file

@ -11,9 +11,11 @@ namespace BotSharp.Core.Agents;
public class AgentController : ControllerBase, IApiAdapter
{
private readonly IAgentService _agentService;
public AgentController(IAgentService agentService)
private readonly IUserIdentity _user;
public AgentController(IAgentService agentService, IUserIdentity user)
{
_agentService = agentService;
_user = user;
}
[HttpPost("/agent")]
@ -23,6 +25,16 @@ public class AgentController : ControllerBase, IApiAdapter
return AgentViewModel.FromAgent(createdAgent);
}
[HttpPut("/agent/{agentId}")]
public async Task UpdateAgent([FromRoute] string agentId,
[FromBody] AgentUpdateModel agent)
{
var model = agent.ToAgent();
model.Id = agentId;
model.OwerId = _user.Id;
await _agentService.UpdateAgent(model);
}
[HttpGet("/agents")]
public async Task<List<AgentViewModel>> GetAgents()
{

View file

@ -11,6 +11,6 @@ public partial class AgentService : IChatServiceZone
/// <returns></returns>
public async Task Serving(ContentContainer content)
{
}
}

View file

@ -6,6 +6,17 @@ public partial class AgentService
{
public async Task UpdateAgent(Agent agent)
{
throw new NotImplementedException();
var db = _services.GetRequiredService<AgentDbContext>();
db.Transaction<IAgentTable>(delegate
{
var record = db.Agent.FirstOrDefault(x => x.OwnerId == agent.OwerId && x.Id == agent.Id);
record.Name = agent.Name;
record.Description = agent.Description;
record.Instruction = agent.Instruction;
record.Samples = agent.Samples;
record.UpdatedDateTime = DateTime.UtcNow;
});
}
}

View file

@ -1,8 +1,30 @@
using BotSharp.Abstraction.Agents.Models;
namespace BotSharp.Core.Agents.ViewModels;
public class AgentUpdateModel
{
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
/// <summary>
/// Instruction
/// </summary>
public string Instruction { get; set; }
/// <summary>
/// Samples
/// </summary>
public string Samples { get; set; }
public Agent ToAgent()
{
return new Agent
{
Name = Name,
Description = Description,
Instruction = Instruction,
Samples = Samples
};
}
}

View file

@ -67,7 +67,7 @@
<PackageReference Include="LLamaSharp" Version="0.3.0" />
<PackageReference Include="LLamaSharp.Backend.Cuda11" Version="0.3.0" />
<PackageReference Include="PdfPig" Version="0.1.8" />
<PackageReference Include="TensorFlow.Keras" Version="0.10.5" />
<PackageReference Include="TensorFlow.Keras" Version="0.11.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
</ItemGroup>

View file

@ -17,9 +17,6 @@ public static class BotSharpServiceCollectionExtensions
services.AddScoped<IConversationService, ConversationService>();
services.AddScoped<ITextChopper, TextChopperService>();
services.AddScoped<IKnowledgeService, KnowledgeService>();
services.AddScoped<IContentTransfer, ContentTransfer>();
RegisterRepository(services, config);

View file

@ -1,5 +1,3 @@
using Microsoft.AspNetCore.Mvc;
namespace BotSharp.Core.Conversations.ViewModels;
public class NewMessageModel

View file

@ -1,24 +0,0 @@
namespace BotSharp.Core.Knowledges;
public class KnowledgeBase : IVectorDb
{
public Task CreateCollection(string collectionName, int dim)
{
throw new NotImplementedException();
}
public Task<List<string>> GetCollections()
{
throw new NotImplementedException();
}
public Task<List<int>> Search(string collectionName, float[] vector, int limit = 10)
{
throw new NotImplementedException();
}
public Task Upsert(string collectionName, int id, float[] vector)
{
throw new NotImplementedException();
}
}

View file

@ -0,0 +1,17 @@
using BotSharp.Core.Plugins.Knowledges.Services;
using Microsoft.Extensions.Configuration;
namespace BotSharp.Core.Plugins.Knowledges;
public class KnowledgeBasePlugin : IBotSharpPlugin
{
public void RegisterDI(IServiceCollection services, IConfiguration config)
{
var settings = new KnowledgeBaseSettings();
config.Bind("KnowledgeBase", settings);
services.AddSingleton(x => settings);
services.AddScoped<ITextChopper, TextChopperService>();
services.AddScoped<IKnowledgeService, KnowledgeService>();
}
}

View file

@ -0,0 +1,7 @@
namespace BotSharp.Core.Plugins.Knowledges;
public class KnowledgeBaseSettings
{
public string VectorDb { get; set; }
public string TextEmbedding { get; set; }
}

View file

@ -1,5 +1,4 @@
using BotSharp.Abstraction.ApiAdapters;
using BotSharp.Abstraction.Knowledges;
using BotSharp.Abstraction.Knowledges.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
@ -8,7 +7,7 @@ using System.IO;
using UglyToad.PdfPig.Content;
using UglyToad.PdfPig;
namespace BotSharp.Core.Knowledges;
namespace BotSharp.Core.Plugins.Knowledges;
[Authorize]
[ApiController]
@ -31,7 +30,7 @@ public class KnowledgeController : ControllerBase, IApiAdapter
}
[HttpPost("/knowledge/{agentId}")]
public async Task<IActionResult> FeedKnowledge([FromRoute] string agentId, [FromForm] string name, List<IFormFile> files)
public async Task<IActionResult> FeedKnowledge([FromRoute] string agentId, List<IFormFile> files)
{
long size = files.Sum(f => f.Length);
@ -62,7 +61,6 @@ public class KnowledgeController : ControllerBase, IApiAdapter
await _knowledgeService.Feed(new KnowledgeFeedModel
{
AgentId = agentId,
Name = name,
Content = content
});
}

View file

@ -1,25 +1,26 @@
using BotSharp.Abstraction.Knowledges.Models;
using System.IO;
using BotSharp.Abstraction.MLTasks;
using BotSharp.Abstraction.VectorStorage;
namespace BotSharp.Core.Knowledges.Services;
namespace BotSharp.Core.Plugins.Knowledges.Services;
public class KnowledgeService : IKnowledgeService
{
private readonly ITextEmbedding _textEmbedding;
private readonly IServiceProvider _services;
private readonly KnowledgeBaseSettings _settings;
private readonly ITextCompletion _textCompletion;
private readonly ITextChopper _textChopper;
private readonly IVectorDb _db;
public KnowledgeService(ITextEmbedding textEmbedding,
ITextCompletion textCompletion,
ITextChopper textChopper,
IVectorDb db)
public KnowledgeService(IServiceProvider services,
KnowledgeBaseSettings settings,
ITextCompletion textCompletion,
ITextChopper textChopper)
{
_textEmbedding = textEmbedding;
_services = services;
_settings = settings;
_textCompletion = textCompletion;
_textChopper = textChopper;
_db = db;
}
public async Task Feed(KnowledgeFeedModel knowledge)
@ -33,25 +34,30 @@ public class KnowledgeService : IKnowledgeService
// Store chunks in local file system
var knowledgeStoreDir = Path.Combine("knowledge_chunks", knowledge.AgentId);
if(!Directory.Exists(knowledgeStoreDir))
if (!Directory.Exists(knowledgeStoreDir))
{
Directory.CreateDirectory(knowledgeStoreDir);
}
var knowledgePath = Path.Combine(knowledgeStoreDir, knowledge.Name);
var knowledgePath = Path.Combine(knowledgeStoreDir, "chuncks");
File.WriteAllLines(knowledgePath + ".txt", lines);
await _db.CreateCollection(knowledge.Name, _textEmbedding.Dimension);
var db = GetVectorDb();
var textEmbedding = GetTextEmbedding();
await db.CreateCollection(knowledge.AgentId, textEmbedding.Dimension);
foreach (var line in lines)
{
await _db.Upsert(knowledge.Name, idStart, _textEmbedding.GetVector(line));
var vec = textEmbedding.GetVector(line);
await db.Upsert(knowledge.AgentId, idStart, vec);
idStart++;
}
}
public async Task<string> GetAnswer(KnowledgeRetrievalModel retrievalModel)
{
var vector = _textEmbedding.GetVector(retrievalModel.Question);
var textEmbedding = GetTextEmbedding();
var vector = textEmbedding.GetVector(retrievalModel.Question);
// Scan local knowledge directory
var knowledgeName = "";
@ -64,7 +70,7 @@ public class KnowledgeService : IKnowledgeService
}
// Vector search
var result = await _db.Search(knowledgeName, vector);
var result = await GetVectorDb().Search(knowledgeName, vector);
// Restore
var prompt = "";
@ -80,4 +86,18 @@ public class KnowledgeService : IKnowledgeService
var completion = await _textCompletion.GetCompletion(prompt);
return completion;
}
public IVectorDb GetVectorDb()
{
var db = _services.GetServices<IVectorDb>()
.FirstOrDefault(x => x.GetType().Name == _settings.VectorDb);
return db;
}
public ITextEmbedding GetTextEmbedding()
{
var embedding = _services.GetServices<ITextEmbedding>()
.FirstOrDefault(x => x.GetType().Name == _settings.TextEmbedding);
return embedding;
}
}

View file

@ -1,6 +1,6 @@
using BotSharp.Abstraction.Knowledges.Models;
namespace BotSharp.Core.Knowledges.Services;
namespace BotSharp.Core.Plugins.Knowledges.Services;
public class TextChopperService : ITextChopper
{
@ -10,8 +10,8 @@ public class TextChopperService : ITextChopper
var currentPos = 0;
while (currentPos < content.Length)
{
var len = content.Length - currentPos > option.Size ?
option.Size :
var len = content.Length - currentPos > option.Size ?
option.Size :
content.Length - currentPos;
var chunk = content.Substring(currentPos, len);
chunks.Add(chunk);

View file

@ -1,7 +1,7 @@
using LLama;
using System.IO;
namespace BotSharp.Plugins.LLamaSharp;
namespace BotSharp.Core.Plugins.LLamaSharp;
public class ChatCompletionProvider : IChatServiceZone
{

View file

@ -1,6 +1,6 @@
using Microsoft.Extensions.Configuration;
namespace BotSharp.Plugins.LLamaSharp;
namespace BotSharp.Core.Plugins.LLamaSharp;
public class LLamaSharpPlugin : IBotSharpPlugin
{

View file

@ -1,4 +1,4 @@
namespace BotSharp.Plugins.LLamaSharp;
namespace BotSharp.Core.Plugins.LLamaSharp;
public class LlamaSharpSettings
{

View file

@ -0,0 +1,12 @@
using BotSharp.Abstraction.VectorStorage;
using Microsoft.Extensions.Configuration;
namespace BotSharp.Core.Plugins.MemVecDb;
public class MemVecDbPlugin : IBotSharpPlugin
{
public void RegisterDI(IServiceCollection services, IConfiguration config)
{
services.AddSingleton<IVectorDb, MemVectorDatabase>();
}
}

View file

@ -0,0 +1,36 @@
using BotSharp.Abstraction.VectorStorage;
namespace BotSharp.Core.Plugins.MemVecDb;
public class MemVectorDatabase : IVectorDb
{
private readonly Dictionary<string, int> _collections = new Dictionary<string, int>();
private readonly Dictionary<string, List<VecRecord>> _vectors = new Dictionary<string, List<VecRecord>>();
public Task CreateCollection(string collectionName, int dim)
{
_collections[collectionName] = dim;
_vectors[collectionName] = new List<VecRecord>();
return Task.CompletedTask;
}
public Task<List<string>> GetCollections()
{
return Task.FromResult(_collections.Select(x => x.Key).ToList());
}
public Task<List<int>> Search(string collectionName, float[] vector, int limit = 10)
{
throw new NotImplementedException();
}
public Task Upsert(string collectionName, int id, float[] vector)
{
_vectors[collectionName].Add(new VecRecord
{
Id = id,
Vector = vector
});
return Task.CompletedTask;
}
}

View file

@ -0,0 +1,8 @@
namespace BotSharp.Core.Plugins.MemVecDb;
public class VecRecord
{
public int Id { get; set; }
public float[] Vector { get; set; }
public string Text { get; set; }
}

View file

@ -11,13 +11,25 @@ public class AgentRecord : DbRecord, IAgentTable
[MaxLength(64)]
public string Name { get; set; } = string.Empty;
[MaxLength(512)]
public string? Description { get; set; }
[Required]
[MaxLength(36)]
public string OwnerId { get; set; } = string.Empty;
[MaxLength(512)]
public string Description { get; set; }
/// <summary>
/// Instruction
/// </summary>
[StringLength(int.MaxValue)]
public string Instruction { get; set; }
/// <summary>
/// Samples
/// </summary>
[StringLength(int.MaxValue)]
public string Samples { get; set; }
[Required]
public DateTime CreatedDateTime { get; set; }

View file

@ -19,6 +19,5 @@ global using BotSharp.Core.Repository.DbTables;
global using BotSharp.Core.Agents.Services;
global using BotSharp.Core.Conversations.Services;
global using BotSharp.Core.Infrastructures;
global using BotSharp.Core.Knowledges.Services;
global using BotSharp.Core.Plugins;
global using BotSharp.Core.Users.Services;

View file

@ -19,6 +19,6 @@ public class AzureOpenAiPlugin : IBotSharpPlugin
services.AddSingleton<ITextCompletion, TextCompletionProvider>();
services.AddScoped<IChatCompletion, ChatCompletionProvider>();
services.AddScoped<IChatServiceZone, ChatCompletionService>();
services.AddScoped<IChatServiceZone, ChatService>();
}
}

View file

@ -7,11 +7,11 @@ using System.Threading.Tasks;
namespace BotSharp.Plugin.AzureOpenAI.Services;
public class ChatCompletionService : IChatServiceZone
public class ChatService : IChatServiceZone
{
private readonly IChatCompletion _chatCompletion;
public ChatCompletionService(IChatCompletion chatCompletion)
public ChatService(IChatCompletion chatCompletion)
{
_chatCompletion = chatCompletion;
}

View file

@ -1,6 +1,6 @@
using BotSharp.Abstraction.Knowledges;
using BotSharp.Abstraction.MLTasks;
using BotSharp.Abstraction.Plugins;
using BotSharp.Abstraction.VectorStorage;
using BotSharp.Plugin.MetaAI.Providers;
using BotSharp.Plugin.MetaAI.Settings;
using Microsoft.Extensions.Configuration;

View file

@ -1,4 +1,4 @@
using BotSharp.Abstraction.Knowledges;
using BotSharp.Abstraction.VectorStorage;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

View file

@ -10,7 +10,17 @@ public class fastTextEmbeddingProvider : ITextEmbedding
private FastTextWrapper _fastText;
private readonly fastTextSetting _settings;
public int Dimension => _fastText.GetModelDimension();
public int Dimension
{
get
{
if (!_fastText.IsModelReady())
{
_fastText.LoadModel(_settings.ModelPath);
}
return _fastText.GetModelDimension();
}
}
public fastTextEmbeddingProvider(fastTextSetting settings)
{
@ -21,15 +31,15 @@ public class fastTextEmbeddingProvider : ITextEmbedding
{
throw new FileNotFoundException($"Can't load pre-trained word vectors from {settings.ModelPath}.\n Try to download from https://fasttext.cc/docs/en/english-vectors.html.");
}
if (!_fastText.IsModelReady())
{
_fastText.LoadModel(_settings.ModelPath);
}
}
public float[] GetVector(string text)
{
if (!_fastText.IsModelReady())
{
_fastText.LoadModel(_settings.ModelPath);
}
return _fastText.GetSentenceVector(text);
}
}

View file

@ -1,4 +1,4 @@
using BotSharp.Abstraction.Knowledges;
using BotSharp.Abstraction.VectorStorage;
using QdrantCSharp;
using QdrantCSharp.Enums;
using QdrantCSharp.Models;

View file

@ -1,5 +1,5 @@
using BotSharp.Abstraction.Knowledges;
using BotSharp.Abstraction.Plugins;
using BotSharp.Abstraction.VectorStorage;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

View file

@ -67,6 +67,10 @@
"WeixinAppSecret": "#{WeixinAppSecret}#"
},
"KnowledgeBase": {
"VectorDb": "MemVecDbProvider"
},
"PluginLoader": {
"Assemblies": [
"BotSharp.Core",
@ -77,6 +81,8 @@
"BotSharp.Plugin.WeChat"
],
"Plugins": [
"KnowledgeBasePlugin",
"MemVecDbPlugin",
// "LLamaSharpPlugin",
"AzureOpenAiPlugin",
"MetaAiPlugin",