diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentRole.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentRole.cs index 4cab43d6..f9547d5a 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentRole.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentRole.cs @@ -3,21 +3,7 @@ namespace BotSharp.Abstraction.Agents.Enums; public class AgentRole { public const string System = "system"; - - /// - /// AI Assistant - /// public const string Assistant = "assistant"; - - /// - /// Client - /// public const string User = "user"; - public const string Function = "function"; - - /// - /// Customer service representative (CSR) - /// - public const string CSR = "csr"; } diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/UserAgent.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/UserAgent.cs index 55033a04..b6eab94d 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/UserAgent.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/UserAgent.cs @@ -5,6 +5,7 @@ public class UserAgent public string Id { get; set; } = string.Empty; public string UserId { get; set; } = string.Empty; public string AgentId { get; set; } = string.Empty; + public bool Editable { get; set; } public DateTime UpdatedTime { get; set; } = DateTime.UtcNow; public DateTime CreatedTime { get; set; } = DateTime.UtcNow; } diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs index f13466b7..3d82500c 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs @@ -77,7 +77,7 @@ public abstract class ConversationHookBase : IConversationHook return Task.CompletedTask; } - public virtual Task OnConversationInitialized(Conversation message) + public virtual Task OnConversationInitialized(Conversation conversation) { return Task.CompletedTask; } diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs index 4cc6af36..66342ffb 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs @@ -9,7 +9,7 @@ public interface IBotSharpRepository #region User User? GetUserByEmail(string email); - User? GetUserByExternalId(string externalId); + User? GetUserById(string id); void CreateUser(User user); #endregion diff --git a/src/Infrastructure/BotSharp.Abstraction/Users/IUserService.cs b/src/Infrastructure/BotSharp.Abstraction/Users/IUserService.cs index f54782ce..35d74aa4 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Users/IUserService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Users/IUserService.cs @@ -4,6 +4,7 @@ namespace BotSharp.Abstraction.Users; public interface IUserService { + Task GetUser(string id); Task CreateUser(User user); Task GetToken(string authorization); Task GetMyProfile(); diff --git a/src/Infrastructure/BotSharp.Abstraction/Users/Models/User.cs b/src/Infrastructure/BotSharp.Abstraction/Users/Models/User.cs index 7253f4db..a56e505f 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Users/Models/User.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Users/Models/User.cs @@ -1,3 +1,5 @@ +using BotSharp.Abstraction.Users.Enums; + namespace BotSharp.Abstraction.Users.Models; public class User @@ -9,6 +11,7 @@ public class User public string Salt { get; set; } = string.Empty; public string Password { get; set; } = string.Empty; public string? ExternalId { get; set; } + public string Role { get; set; } = UserRole.Client; public DateTime UpdatedTime { get; set; } = DateTime.UtcNow; public DateTime CreatedTime { get; set; } = DateTime.UtcNow; } diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs index 5e29d9a8..2253710c 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs @@ -42,7 +42,7 @@ public partial class AgentService .SetResponses(foundAgent.Responses); } - var user = _db.GetUserByExternalId(_user.Id); + var user = _db.GetUserById(_user.Id); var userAgentRecord = new UserAgent { Id = Guid.NewGuid().ToString(), diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.RefreshAgents.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.RefreshAgents.cs index fa24f404..7d0d4ced 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.RefreshAgents.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.RefreshAgents.cs @@ -13,7 +13,7 @@ public partial class AgentService var dbSettings = _services.GetRequiredService(); var agentDir = Path.Combine(dbSettings.FileRepository, _agentSettings.DataDir); - var user = _db.GetUserByExternalId(_user.Id); + var user = _db.GetUserById(_user.Id); var agents = new List(); var userAgents = new List(); diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs index 20bfb7cf..92022dca 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs @@ -1,4 +1,6 @@ using BotSharp.Abstraction.Repositories; +using BotSharp.Abstraction.Users.Enums; +using BotSharp.Abstraction.Users.Models; namespace BotSharp.Core.Conversations.Services; @@ -46,15 +48,15 @@ public partial class ConversationService : IConversationService public async Task> GetConversations() { var db = _services.GetRequiredService(); - var user = db.GetUserByExternalId(_user.Id); - var conversations = db.GetConversations(user?.Id); + var user = db.GetUserById(_user.Id); + var conversations = db.GetConversations(user.Role == UserRole.CSR ? null : user?.Id); return conversations.OrderByDescending(x => x.CreatedTime).ToList(); } public async Task NewConversation(Conversation sess) { var db = _services.GetRequiredService(); - var user = db.GetUserByExternalId(_user.Id); + var user = db.GetUserById(_user.Id); var foundUserId = user?.Id ?? string.Empty; var record = sess; diff --git a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs index 4b2383bc..93339d3d 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs @@ -169,7 +169,7 @@ public class BotSharpDbContext : Database, IBotSharpRepository throw new NotImplementedException(); } - public User? GetUserByExternalId(string externalId) + public User? GetUserById(string id) { throw new NotImplementedException(); } diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs index 517bd0f7..e77e160a 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs @@ -726,7 +726,7 @@ public class FileRepository : IBotSharpRepository var json = File.ReadAllText(path); var record = JsonSerializer.Deserialize(json, _options); - if (record != null && record.UserId == userId) + if (record != null && (record.UserId == userId || userId == null)) { records.Add(record); } @@ -769,9 +769,9 @@ public class FileRepository : IBotSharpRepository return Users.FirstOrDefault(x => x.Email == email); } - public User? GetUserByExternalId(string externalId) + public User? GetUserById(string id = null) { - return Users.FirstOrDefault(x => x.ExternalId == externalId); + return Users.FirstOrDefault(x => x.ExternalId == id || x.Id == id); } public void CreateUser(User user) diff --git a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs index 30fa131f..d832cc13 100644 --- a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs +++ b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs @@ -97,7 +97,15 @@ public class UserService : IUserService public async Task GetMyProfile() { var db = _services.GetRequiredService(); - var user = db.GetUserByExternalId(_user.Id); + var user = db.GetUserById(_user.Id); + return user; + } + + [MemoryCache(60)] + public async Task GetUser(string id) + { + var db = _services.GetRequiredService(); + var user = db.GetUserById(id); return user; } } diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index 7b5d83b0..39fc861a 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -2,6 +2,7 @@ using BotSharp.Abstraction.ApiAdapters; using BotSharp.Abstraction.Conversations.Models; using BotSharp.Abstraction.Models; using BotSharp.OpenAPI.ViewModels.Conversations; +using BotSharp.OpenAPI.ViewModels.Users; using Microsoft.AspNetCore.Http; using System.Net.Http.Headers; @@ -27,7 +28,8 @@ public class ConversationController : ControllerBase, IApiAdapter var service = _services.GetRequiredService(); var conv = new Conversation { - AgentId = agentId + AgentId = agentId, + UserId = _user.Id }; conv = await service.NewConversation(conv); config.States.ForEach(x => conv.States[x.Split('=')[0]] = x.Split('=')[1]); @@ -35,6 +37,34 @@ public class ConversationController : ControllerBase, IApiAdapter return ConversationViewModel.FromSession(conv); } + [HttpGet("/conversations/{agentId}")] + public async Task> GetConversations() + { + var service = _services.GetRequiredService(); + var conversations = await service.GetConversations(); + var userService = _services.GetRequiredService(); + var list = conversations.Select(x => new ConversationViewModel + { + Id = x.Id, + AgentId = x.AgentId, + Title = x.Title, + User = new UserViewModel + { + Id = x.UserId, + }, + CreatedTime = x.CreatedTime, + UpdatedTime = x.UpdatedTime + }).ToList(); + + foreach (var item in list) + { + var user = await userService.GetUser(item.User.Id); + item.User = UserViewModel.FromUser(user); + } + + return list; + } + [HttpDelete("/conversation/{agentId}/{conversationId}")] public async Task DeleteConversation([FromRoute] string agentId, [FromRoute] string conversationId) { diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/ConversationViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/ConversationViewModel.cs index f47c5cd6..ee819cf1 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/ConversationViewModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/ConversationViewModel.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.Conversations.Models; +using BotSharp.OpenAPI.ViewModels.Users; namespace BotSharp.OpenAPI.ViewModels.Conversations; @@ -7,6 +8,7 @@ public class ConversationViewModel public string Id { get; set; } public string AgentId { get; set; } public string Title { get; set; } = string.Empty; + public UserViewModel User { get; set; } = new UserViewModel(); public DateTime UpdatedTime { get; set; } = DateTime.UtcNow; public DateTime CreatedTime { get; set; } = DateTime.UtcNow; @@ -15,6 +17,10 @@ public class ConversationViewModel return new ConversationViewModel { Id = sess.Id, + User = new UserViewModel + { + Id = sess.UserId + }, AgentId = sess.AgentId, Title = sess.Title, CreatedTime = sess.CreatedTime, diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserViewModel.cs index 4e452334..5bed438e 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserViewModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserViewModel.cs @@ -9,6 +9,8 @@ public class UserViewModel public string LastName { get; set; } public string Email { get; set; } + public string FullName => $"{FirstName} {LastName}"; + public static UserViewModel FromUser(User user) { return new UserViewModel diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs index 0009e0aa..aacd623b 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs @@ -768,9 +768,9 @@ public class MongoRepository : IBotSharpRepository } : null; } - public User? GetUserByExternalId(string externalId) + public User? GetUserById(string id) { - var user = _dc.Users.AsQueryable().FirstOrDefault(x => x.ExternalId == externalId); + var user = _dc.Users.AsQueryable().FirstOrDefault(x => x.Id == id || x.ExternalId == id); return user != null ? new User { Id = user.Id, diff --git a/src/Plugins/BotSharp.Plugin.Qdrant/BotSharp.Plugin.Qdrant.csproj b/src/Plugins/BotSharp.Plugin.Qdrant/BotSharp.Plugin.Qdrant.csproj index aa9ca00d..e8f32d39 100644 --- a/src/Plugins/BotSharp.Plugin.Qdrant/BotSharp.Plugin.Qdrant.csproj +++ b/src/Plugins/BotSharp.Plugin.Qdrant/BotSharp.Plugin.Qdrant.csproj @@ -1,4 +1,4 @@ - + netstandard2.1 @@ -10,7 +10,7 @@ - + diff --git a/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs b/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs index 1d7aac14..3bc4e8fb 100644 --- a/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs +++ b/src/Plugins/BotSharp.Plugin.Qdrant/QdrantDb.cs @@ -1,9 +1,8 @@ using BotSharp.Abstraction.Agents; using BotSharp.Abstraction.VectorStorage; using Microsoft.Extensions.DependencyInjection; -using QdrantCSharp; -using QdrantCSharp.Enums; -using QdrantCSharp.Models; +using Qdrant.Client; +using Qdrant.Client.Grpc; using System; using System.Collections.Generic; using System.IO; @@ -14,7 +13,7 @@ namespace BotSharp.Plugin.Qdrant; public class QdrantDb : IVectorDb { - private readonly QdrantHttpClient _client; + private readonly QdrantClient _client; private readonly QdrantSetting _setting; private readonly IServiceProvider _services; @@ -23,9 +22,9 @@ public class QdrantDb : IVectorDb { _setting = setting; _services = services; - _client = new QdrantHttpClient + _client = new QdrantClient ( - url: _setting.Url, + host: _setting.Url, apiKey: _setting.ApiKey ); } @@ -33,8 +32,8 @@ public class QdrantDb : IVectorDb public async Task> GetCollections() { // List all the collections - var collections = await _client.GetCollections(); - return collections.Result.Collections.Select(x => x.Name).ToList(); + var collections = await _client.ListCollectionsAsync(); + return collections.ToList(); } public async Task CreateCollection(string collectionName, int dim) @@ -43,7 +42,11 @@ public class QdrantDb : IVectorDb if (!collections.Contains(collectionName)) { // Create a new collection - await _client.CreateCollection(collectionName, new VectorParams(size: dim, distance: Distance.COSINE)); + await _client.CreateCollectionAsync(collectionName, new VectorParams() + { + Size = (ulong)dim, + Distance = Distance.Cosine + }); var agentService = _services.GetRequiredService(); var agentDataDir = agentService.GetAgentDataDir(collectionName); @@ -52,7 +55,7 @@ public class QdrantDb : IVectorDb } // Get collection info - var collectionInfo = await _client.GetCollection(collectionName); + var collectionInfo = await _client.GetCollectionInfoAsync(collectionName); if (collectionInfo == null) { throw new Exception($"Create {collectionName} failed."); @@ -62,9 +65,16 @@ 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.UpsertAsync(collectionName, points: new List { - new PointStruct(id: id, vector: vector) + new PointStruct() + { + Id = new PointId() + { + Num = (ulong)id, + }, + Vectors = vector + } }); // Store chunks in local file system @@ -76,13 +86,13 @@ public class QdrantDb : IVectorDb public async Task> Search(string collectionName, float[] vector, int limit = 5) { - var result = await _client.Search(collectionName, vector, limit); + var result = await _client.SearchAsync(collectionName, vector, limit: (ulong)limit); var agentService = _services.GetRequiredService(); var agentDataDir = agentService.GetAgentDataDir(collectionName); var knowledgePath = Path.Combine(agentDataDir, "knowledge.txt"); var texts = File.ReadAllLines(knowledgePath); - return result.Result.Select(x => texts[x.Id]).ToList(); + return result.Select(x => texts[x.Id.Num]).ToList(); } }