diff --git a/.gitignore b/.gitignore index 6e15e1e8..d9665d48 100644 --- a/.gitignore +++ b/.gitignore @@ -285,3 +285,4 @@ __pycache__/ *.xsd.cs data /docs/_build +*.bin diff --git a/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj b/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj index a4c3c091..a73c2169 100644 --- a/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj +++ b/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj @@ -23,10 +23,11 @@ - - + + + - + diff --git a/src/Infrastructure/BotSharp.Abstraction/Users/Models/Token.cs b/src/Infrastructure/BotSharp.Abstraction/Users/Models/Token.cs index f9155a9c..8f3d7f0d 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Users/Models/Token.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Users/Models/Token.cs @@ -1,10 +1,16 @@ +using System.Text.Json.Serialization; + namespace BotSharp.Abstraction.Users.Models; public class Token { + [JsonPropertyName("access_token")] public string AccessToken { get; set; } = string.Empty; + [JsonPropertyName("refresh_token")] public string RefreshToken { get; set; } = string.Empty; + [JsonPropertyName("token_type")] public string TokenType { get; set; } = string.Empty; + [JsonPropertyName("expires")] public int ExpireTime { get; set; } public string Scope { get; set; } = string.Empty; } diff --git a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj index b8c2cfaa..4f21e5b7 100644 --- a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj +++ b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj @@ -75,8 +75,7 @@ - - + diff --git a/src/Infrastructure/BotSharp.Core/Plugins/Knowledges/KnowledgeController.cs b/src/Infrastructure/BotSharp.Core/Plugins/Knowledges/KnowledgeController.cs index 5f613e5e..5f9ccff3 100644 --- a/src/Infrastructure/BotSharp.Core/Plugins/Knowledges/KnowledgeController.cs +++ b/src/Infrastructure/BotSharp.Core/Plugins/Knowledges/KnowledgeController.cs @@ -30,7 +30,7 @@ public class KnowledgeController : ControllerBase, IApiAdapter } [HttpPost("/knowledge/{agentId}")] - public async Task FeedKnowledge([FromRoute] string agentId, List files) + public async Task FeedKnowledge([FromRoute] string agentId, List files, [FromQuery] int? startPageNum, [FromQuery] int? endPageNum) { long size = files.Sum(f => f.Length); @@ -52,6 +52,16 @@ public class KnowledgeController : ControllerBase, IApiAdapter var content = ""; foreach (Page page in document.GetPages()) { + if (startPageNum.HasValue && page.Number < startPageNum.Value) + { + continue; + } + + if (endPageNum.HasValue && page.Number > endPageNum.Value) + { + continue; + } + content += page.Text; } diff --git a/src/Infrastructure/BotSharp.Core/Plugins/Knowledges/Services/KnowledgeService.cs b/src/Infrastructure/BotSharp.Core/Plugins/Knowledges/Services/KnowledgeService.cs index bde02fee..7f83a65a 100644 --- a/src/Infrastructure/BotSharp.Core/Plugins/Knowledges/Services/KnowledgeService.cs +++ b/src/Infrastructure/BotSharp.Core/Plugins/Knowledges/Services/KnowledgeService.cs @@ -24,8 +24,8 @@ public class KnowledgeService : IKnowledgeService var idStart = 0; var lines = _textChopper.Chop(knowledge.Content, new ChunkOption { - Size = 256, - Conjunction = 5, + Size = 1024, + Conjunction = 32, SplitByWord = true, }); @@ -38,6 +38,7 @@ public class KnowledgeService : IKnowledgeService var vec = textEmbedding.GetVector(line); await db.Upsert(knowledge.AgentId, idStart, vec, line); idStart++; + Console.WriteLine($"Saved vector {idStart}/{lines.Count}: {line}\n"); } } @@ -50,7 +51,7 @@ public class KnowledgeService : IKnowledgeService var result = await GetVectorDb().Search(retrievalModel.AgentId, vector, limit: 10); // Restore - return "### Helpful domain knowledges:\r\n" + string.Join("\n", result.Select((x, i) => $"{i + 1}: {x}")); + return string.Join("\n\n", result.Select((x, i) => $"{i + 1}: {x.Trim()}")); } public async Task GetAnswer(KnowledgeRetrievalModel retrievalModel) @@ -58,8 +59,13 @@ public class KnowledgeService : IKnowledgeService // Restore var prompt = await GetKnowledges(retrievalModel); - prompt += "\r\n### Answer user's question by utilizing the helpful domain knowledges above.\r\n"; - prompt += $"\r\nQuestion: {retrievalModel.Question}\r\nAnswer: "; + var sb = new StringBuilder(prompt); + sb.AppendLine(); + sb.AppendLine(); + sb.AppendLine("### Answer question based on the given information above. Try to response in bullet points if necessary. Please keep your answers concise and free of irrelevant information."); + sb.AppendLine($"Question: {retrievalModel.Question}"); + sb.AppendLine("Answer: "); + prompt = sb.ToString().Trim(); var completion = await GetTextCompletion().GetCompletion(prompt); return completion; @@ -68,14 +74,14 @@ public class KnowledgeService : IKnowledgeService public IVectorDb GetVectorDb() { var db = _services.GetServices() - .FirstOrDefault(x => x.GetType().Name == _settings.VectorDb); + .FirstOrDefault(x => x.GetType().FullName.EndsWith(_settings.VectorDb)); return db; } public ITextEmbedding GetTextEmbedding() { var embedding = _services.GetServices() - .FirstOrDefault(x => x.GetType().Name == _settings.TextEmbedding); + .FirstOrDefault(x => x.GetType().FullName.EndsWith(_settings.TextEmbedding)); return embedding; } diff --git a/src/Infrastructure/BotSharp.Core/Plugins/LLamaSharp/LLamaSharpPlugin.cs b/src/Infrastructure/BotSharp.Core/Plugins/LLamaSharp/LLamaSharpPlugin.cs index 92db8244..66bd11f8 100644 --- a/src/Infrastructure/BotSharp.Core/Plugins/LLamaSharp/LLamaSharpPlugin.cs +++ b/src/Infrastructure/BotSharp.Core/Plugins/LLamaSharp/LLamaSharpPlugin.cs @@ -12,7 +12,7 @@ public class LLamaSharpPlugin : IBotSharpPlugin services.AddSingleton(x => llamaSharpSettings); services.AddSingleton(); - services.AddScoped(); + services.AddSingleton(); services.AddScoped(); services.AddScoped(); } diff --git a/src/Infrastructure/BotSharp.Core/Plugins/LLamaSharp/TextEmbeddingProvider.cs b/src/Infrastructure/BotSharp.Core/Plugins/LLamaSharp/TextEmbeddingProvider.cs index a061df47..daa1ee8d 100644 --- a/src/Infrastructure/BotSharp.Core/Plugins/LLamaSharp/TextEmbeddingProvider.cs +++ b/src/Infrastructure/BotSharp.Core/Plugins/LLamaSharp/TextEmbeddingProvider.cs @@ -6,20 +6,24 @@ namespace BotSharp.Core.Plugins.LLamaSharp; public class TextEmbeddingProvider : ITextEmbedding { + private LLamaEmbedder _embedder; + private readonly LlamaSharpSettings _settings; private readonly IServiceProvider _services; - public int Dimension => throw new NotImplementedException(); + public int Dimension => 4096; - public TextEmbeddingProvider(IServiceProvider services) + public TextEmbeddingProvider(IServiceProvider services, LlamaSharpSettings settings) { _services = services; + _settings = settings; } public float[] GetVector(string text) { - var llama = _services.GetRequiredService(); + if (_embedder == null) + { + _embedder = new LLamaEmbedder(new ModelParams(_settings.ModelPath)); + } - var executor = new LLamaEmbedder(new ModelParams(llama.Settings.ModelPath)); - - return executor.GetEmbeddings(text); + return _embedder.GetEmbeddings(text); } } diff --git a/src/Infrastructure/BotSharp.Core/Plugins/MemVecDb/MemVectorDatabase.cs b/src/Infrastructure/BotSharp.Core/Plugins/MemVecDb/MemVectorDatabase.cs index 2bd188c3..0f41145a 100644 --- a/src/Infrastructure/BotSharp.Core/Plugins/MemVecDb/MemVectorDatabase.cs +++ b/src/Infrastructure/BotSharp.Core/Plugins/MemVecDb/MemVectorDatabase.cs @@ -1,8 +1,4 @@ using BotSharp.Abstraction.VectorStorage; -using System.Collections; -using System.IO; -using System.Numerics; -using Tensorflow; using Tensorflow.NumPy; namespace BotSharp.Core.Plugins.MemVecDb; @@ -67,12 +63,15 @@ public class MemVectorDatabase : IVectorDb private float[] CalCosineSimilarity(float[] vec, List records) { var similarities = new float[records.Count]; + var a = vec; + var normA = np.linalg.norm(a); + for (int i = 0; i < records.Count; i++) { - var a = vec; var b = records[i].Vector; - similarities[i] = np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)); + similarities[i] = np.dot(a, b) / (normA * np.linalg.norm(b)); } + return similarities; } } diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/TextCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/TextCompletionProvider.cs index 85fb2d25..80c9b9bc 100644 --- a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/TextCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/TextCompletionProvider.cs @@ -4,17 +4,20 @@ using BotSharp.Abstraction.MLTasks; using System; using System.Threading.Tasks; using BotSharp.Plugin.AzureOpenAI.Settings; +using Microsoft.Extensions.Logging; namespace BotSharp.Plugin.AzureOpenAI.Providers; public class TextCompletionProvider : ITextCompletion { private readonly AzureOpenAiSettings _settings; + private readonly ILogger _logger; bool _useAzureOpenAI = true; - public TextCompletionProvider(AzureOpenAiSettings settings) + public TextCompletionProvider(AzureOpenAiSettings settings, ILogger logger) { _settings = settings; + _logger = logger; } public async Task GetCompletion(string text) @@ -26,8 +29,8 @@ public class TextCompletionProvider : ITextCompletion { text }, - Temperature = 0.5f, - MaxTokens = 128 + Temperature = 1f, + MaxTokens = 256 }; var response = await client.GetCompletionsAsync( @@ -41,6 +44,8 @@ public class TextCompletionProvider : ITextCompletion completion += t.Text; }; + _logger.LogInformation(text + completion); + return completion.Trim(); } diff --git a/src/Plugins/BotSharp.Plugin.ChatbotUI/BotSharp.Plugin.ChatbotUI.csproj b/src/Plugins/BotSharp.Plugin.ChatbotUI/BotSharp.Plugin.ChatbotUI.csproj index c7d20f5f..2ac302ae 100644 --- a/src/Plugins/BotSharp.Plugin.ChatbotUI/BotSharp.Plugin.ChatbotUI.csproj +++ b/src/Plugins/BotSharp.Plugin.ChatbotUI/BotSharp.Plugin.ChatbotUI.csproj @@ -9,7 +9,6 @@ - diff --git a/src/Plugins/BotSharp.Plugin.MetaMessenger/Controllers/WebhookController.cs b/src/Plugins/BotSharp.Plugin.MetaMessenger/Controllers/WebhookController.cs index ab98cbe7..8b07cc42 100644 --- a/src/Plugins/BotSharp.Plugin.MetaMessenger/Controllers/WebhookController.cs +++ b/src/Plugins/BotSharp.Plugin.MetaMessenger/Controllers/WebhookController.cs @@ -31,11 +31,13 @@ public class WebhookController : ControllerBase _services = services; } - [HttpGet("/webhook")] + [HttpGet("/messenger/webhook/{agentId}")] public string Verificate([FromQuery(Name = "hub.mode")] string mode, [FromQuery(Name = "hub.verify_token")] string token, - [FromQuery(Name = "hub.challenge")] string challenge) + [FromQuery(Name = "hub.challenge")] string challenge, + [FromRoute] string agentId) { + Console.WriteLine(agentId); return challenge; } @@ -43,11 +45,12 @@ public class WebhookController : ControllerBase /// https://developers.facebook.com/docs/messenger-platform/webhooks /// /// - [HttpPost("/webhook")] - public async Task> Messages() + [HttpPost("/messenger/webhook/{agentId}")] + public async Task> Messages([FromRoute] string agentId) { using var stream = new StreamReader(Request.Body); var body = await stream.ReadToEndAsync(); + Console.WriteLine(body); var req = JsonSerializer.Deserialize(body, new JsonSerializerOptions { PropertyNameCaseInsensitive = true, @@ -66,7 +69,7 @@ public class WebhookController : ControllerBase string content = ""; var sessionId = req.Entry[0].Messaging[0].Sender.Id; var input = req.Entry[0].Messaging[0].Message.Text; - var result = await conv.SendMessage("", sessionId, new RoleDialogModel("user", input), async msg => + var result = await conv.SendMessage(agentId, sessionId, new RoleDialogModel("user", input), async msg => { content = msg.Content; }); diff --git a/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs b/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs index 632ad1ac..1d7aac14 100644 --- a/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs +++ b/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs @@ -62,10 +62,10 @@ public class QdrantDb : IVectorDb public async Task Upsert(string collectionName, int id, float[] vector, string text) { // Insert vectors - /*await _client.Upsert(collectionName, points: new List + await _client.Upsert(collectionName, points: new List { new PointStruct(id: id, vector: vector) - });*/ + }); // Store chunks in local file system var agentService = _services.GetRequiredService(); diff --git a/src/WebStarter/WebStarter.csproj b/src/WebStarter/WebStarter.csproj index 5dfc1631..41765502 100644 --- a/src/WebStarter/WebStarter.csproj +++ b/src/WebStarter/WebStarter.csproj @@ -27,6 +27,7 @@ + diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json index 48094800..33dba1e3 100644 --- a/src/WebStarter/appsettings.json +++ b/src/WebStarter/appsettings.json @@ -24,7 +24,7 @@ "LlamaSharp": { "Interactive": true, - "ModelPath": "C:\\Users\\haipi\\Downloads\\wizard-vicuna-13B.ggmlv3.q8_0.bin", + "ModelPath": "C:/Users/haipi/Downloads/llama-2-7b-chat.ggmlv3.q3_K_S.bin", "MaxContextLength": 1024, "NumberOfGpuLayer": 10 }, @@ -44,6 +44,13 @@ } }, + "MetaMessenger": { + "Endpoint": "https://graph.facebook.com", + "ApiVersion": "v17.0", + "PageId": "", + "PageAccessToken": "" + }, + "Database": { "MongoDb": { "Master": "mongodb://localhost:27017/chat-ui" @@ -71,7 +78,9 @@ "KnowledgeBase": { "VectorDb": "MemVectorDatabase", + // "VectorDb": "QdrantDb", "TextEmbedding": "fastTextEmbeddingProvider", + // "TextEmbedding": "LLamaSharp.TextEmbeddingProvider", "TextCompletion": "AzureOpenAI.Providers.TextCompletionProvider" // "TextCompletion": "LLamaSharp.TextCompletionProvider" }, diff --git a/tests/Dishwasher-Whirlpool.pdf b/tests/Dishwasher-Whirlpool.pdf new file mode 100644 index 00000000..19b559da Binary files /dev/null and b/tests/Dishwasher-Whirlpool.pdf differ