File repository.

This commit is contained in:
hchen2020 2023-08-09 23:53:22 -05:00
parent 451c55f4e2
commit 1543dd6ce9
15 changed files with 279 additions and 37 deletions

View file

@ -7,5 +7,4 @@ public interface IConversationStorage
void InitStorage(string conversationId);
void Append(string conversationId, RoleDialogModel dialog);
List<RoleDialogModel> GetDialogs(string conversationId);
string GetConversationDataDir();
}

View file

@ -2,6 +2,7 @@ namespace BotSharp.Abstraction.Conversations.Settings;
public class ConversationSetting
{
public string DataDir { get; set; }
public string ChatCompletion { get; set; }
public bool EnableKnowledgeBase { get; set; }
}

View file

@ -6,11 +6,12 @@ public partial class AgentService
{
public async Task<Agent> CreateAgent(Agent agent)
{
var db = _services.GetRequiredService<BotSharpDbContext>();
var db = _services.GetRequiredService<IBotSharpRepository>();
var record = (from a in db.Agent
join ua in db.UserAgent on a.Id equals ua.AgentId
where ua.UserId == _user.Id && a.Name == agent.Name
join u in db.User on ua.UserId equals u.Id
where (ua.UserId == _user.Id || u.ExternalId == _user.Id) && a.Name == agent.Name
select a).FirstOrDefault();
if (record != null)

View file

@ -8,7 +8,7 @@ public partial class AgentService
{
public async Task<List<Agent>> GetAgents()
{
var db = _services.GetRequiredService<BotSharpDbContext>();
var db = _services.GetRequiredService<IBotSharpRepository>();
var query = from a in db.Agent
join ua in db.UserAgent on a.Id equals ua.AgentId
where ua.UserId == _user.Id
@ -18,7 +18,7 @@ public partial class AgentService
public async Task<Agent> GetAgent(string id)
{
var db = _services.GetRequiredService<BotSharpDbContext>();
var db = _services.GetRequiredService<IBotSharpRepository>();
var query = from agent in db.Agent
where agent.Id == id
select agent.ToAgent();

View file

@ -7,7 +7,7 @@ public partial class AgentService
{
public async Task UpdateAgent(Agent agent)
{
var db = _services.GetRequiredService<BotSharpDbContext>();
var db = _services.GetRequiredService<IBotSharpRepository>();
db.Transaction<IBotSharpTable>(delegate
{

View file

@ -10,7 +10,10 @@ public partial class AgentService : IAgentService
private readonly IUserIdentity _user;
private readonly AgentSettings _settings;
public AgentService(IServiceProvider services, ILogger<AgentService> logger, IUserIdentity user, AgentSettings settings)
public AgentService(IServiceProvider services,
ILogger<AgentService> logger,
IUserIdentity user,
AgentSettings settings)
{
_services = services;
_logger = logger;
@ -20,12 +23,14 @@ public partial class AgentService : IAgentService
public string GetDataDir()
{
return Path.Combine(_settings.DataDir);
var dbSettings = _services.GetRequiredService<MyDatabaseSettings>();
return Path.Combine(dbSettings.FileRepository);
}
public string GetAgentDataDir(string agentId)
{
var dir = Path.Combine(_settings.DataDir, "agents", agentId);
var dbSettings = _services.GetRequiredService<MyDatabaseSettings>();
var dir = Path.Combine(dbSettings.FileRepository, _settings.DataDir, agentId);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);

View file

@ -37,13 +37,17 @@ public static class BotSharpServiceCollectionExtensions
var myDatabaseSettings = new MyDatabaseSettings();
config.Bind("Database", myDatabaseSettings);
services.AddSingleton((IServiceProvider x) => databaseSettings);
services.AddSingleton((IServiceProvider x) => myDatabaseSettings);
services.AddScoped((IServiceProvider x)
=> DataContextHelper.GetDbContext<MongoDbContext, Tdb>(myDatabaseSettings, x));
services.AddScoped((IServiceProvider x)
=> DataContextHelper.GetDbContext<BotSharpDbContext, Tdb>(myDatabaseSettings, x));
services.AddScoped<IBotSharpRepository>(sp =>
{
return myDatabaseSettings.Default == "FileRepository" ?
new FileRepository(myDatabaseSettings, sp) :
DataContextHelper.GetDbContext<BotSharpDbContext, Tdb>(myDatabaseSettings, sp);
});
return services;
}

View file

@ -35,7 +35,7 @@ public class ConversationService : IConversationService
public async Task<Conversation> GetConversation(string id)
{
var db = _services.GetRequiredService<BotSharpDbContext>();
var db = _services.GetRequiredService<IBotSharpRepository>();
var query = from sess in db.Conversation
where sess.Id == id
orderby sess.CreatedTime descending
@ -45,7 +45,7 @@ public class ConversationService : IConversationService
public async Task<List<Conversation>> GetConversations()
{
var db = _services.GetRequiredService<BotSharpDbContext>();
var db = _services.GetRequiredService<IBotSharpRepository>();
var query = from sess in db.Conversation
where sess.UserId == _user.Id
orderby sess.CreatedTime descending
@ -55,7 +55,7 @@ public class ConversationService : IConversationService
public async Task<Conversation> NewConversation(Conversation sess)
{
var db = _services.GetRequiredService<BotSharpDbContext>();
var db = _services.GetRequiredService<IBotSharpRepository>();
var record = ConversationRecord.FromConversation(sess);
record.Id = sess.Id.IfNullOrEmptyAs(Guid.NewGuid().ToString());

View file

@ -9,13 +9,13 @@ namespace BotSharp.Core.Conversations.Services;
public class ConversationStateService : IConversationStateService, IDisposable
{
private ConversationState _state;
private IAgentService _agentService;
private MyDatabaseSettings _dbSettings;
private string _conversationId;
private string _file;
public ConversationStateService(IAgentService agentService)
public ConversationStateService(MyDatabaseSettings dbSettings)
{
_agentService = agentService;
_dbSettings = dbSettings;
}
public void SetState(string name, string value)
@ -65,8 +65,12 @@ public class ConversationStateService : IConversationStateService, IDisposable
private string GetStorageFile(string conversationId)
{
var dir = _agentService.GetDataDir();
return Path.Combine(dir, "conversations", conversationId + ".state");
var dir = Path.Combine(_dbSettings.FileRepository, "conversations", conversationId);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
return Path.Combine(dir, "state.dict");
}
public string GetState(string name)

View file

@ -6,9 +6,11 @@ namespace BotSharp.Core.Conversations.Services;
public class ConversationStorage : IConversationStorage
{
private readonly IAgentService _agent;
public ConversationStorage(IAgentService agent)
private readonly MyDatabaseSettings _dbSettings;
public ConversationStorage(IAgentService agent, MyDatabaseSettings dbSettings)
{
_agent = agent;
_dbSettings = dbSettings;
}
public void Append(string conversationId, RoleDialogModel dialog)
@ -55,17 +57,11 @@ public class ConversationStorage : IConversationStorage
private string GetStorageFile(string conversationId)
{
var dir = GetConversationDataDir();
return Path.Combine(dir, conversationId + ".txt");
}
public string GetConversationDataDir()
{
var dir = Path.Combine(_agent.GetDataDir(), "conversations");
var dir = Path.Combine(_dbSettings.FileRepository, "conversations", conversationId);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
return dir;
return Path.Combine(dir, "dialogs.txt");
}
}

View file

@ -1,9 +1,60 @@
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BotSharp.Core.Repository;
public class BotSharpDbContext : Database
public class BotSharpDbContext : Database, IBotSharpRepository
{
public IQueryable<UserRecord> User => Table<UserRecord>();
public IQueryable<AgentRecord> Agent => Table<AgentRecord>();
public IQueryable<UserAgentRecord> UserAgent => Table<UserAgentRecord>();
public IQueryable<ConversationRecord> Conversation => Table<ConversationRecord>();
public int Transaction<TTableInterface>(Action action)
{
DatabaseFacade database = base.GetMaster(typeof(TTableInterface)).Database;
int num = 0;
if (database.CurrentTransaction == null)
{
using (Microsoft.EntityFrameworkCore.Storage.IDbContextTransaction dbContextTransaction = database.BeginTransaction())
{
try
{
action();
num = base.SaveChanges();
dbContextTransaction.Commit();
return num;
}
catch (Exception ex)
{
dbContextTransaction.Rollback();
if (ex.Message.Contains("See the inner exception for details"))
{
throw ex.InnerException;
}
throw ex;
}
}
}
try
{
action();
return base.SaveChanges();
}
catch (Exception ex2)
{
if (database.CurrentTransaction != null)
{
database.CurrentTransaction.Rollback();
}
if (ex2.Message.Contains("See the inner exception for details"))
{
throw ex2.InnerException;
}
throw ex2;
}
}
}

View file

@ -0,0 +1,173 @@
using System.IO;
using System.Text.Json;
namespace BotSharp.Core.Repository;
public class FileRepository : IBotSharpRepository
{
private readonly MyDatabaseSettings _dbSettings;
private readonly IServiceProvider _services;
private JsonSerializerOptions _options;
public FileRepository(MyDatabaseSettings dbSettings, IServiceProvider services)
{
_dbSettings = dbSettings;
_services = services;
_options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
};
}
private List<UserRecord> _users;
public IQueryable<UserRecord> User
{
get
{
if (_users != null)
{
return _users.AsQueryable();
}
var dir = Path.Combine(_dbSettings.FileRepository, "users");
_users = new List<UserRecord>();
foreach (var d in Directory.GetDirectories(dir))
{
var json = File.ReadAllText(Path.Combine(d, "user.json"));
_users.Add(JsonSerializer.Deserialize<UserRecord>(json, _options));
}
return _users.AsQueryable();
}
}
private List<AgentRecord> _agents;
public IQueryable<AgentRecord> Agent
{
get
{
if (_agents != null)
{
return _agents.AsQueryable();
}
var agentSettings = _services.GetService<AgentSettings>();
var dir = Path.Combine(_dbSettings.FileRepository, agentSettings.DataDir);
_agents = new List<AgentRecord>();
foreach (var d in Directory.GetDirectories(dir))
{
var json = File.ReadAllText(Path.Combine(d, "agent.json"));
_agents.Add(JsonSerializer.Deserialize<AgentRecord>(json, _options));
}
return _agents.AsQueryable();
}
}
private List<UserAgentRecord> _userAgents;
public IQueryable<UserAgentRecord> UserAgent
{
get
{
if (_userAgents != null)
{
return _userAgents.AsQueryable();
}
var dir = Path.Combine(_dbSettings.FileRepository, "users");
_userAgents = new List<UserAgentRecord>();
foreach (var d in Directory.GetDirectories(dir))
{
var json = File.ReadAllText(Path.Combine(d, "agents.json"));
_userAgents.AddRange(JsonSerializer.Deserialize<List<UserAgentRecord>>(json, _options));
}
return _userAgents.AsQueryable();
}
}
private List<ConversationRecord> _conversations;
public IQueryable<ConversationRecord> Conversation
{
get
{
if (_conversations != null)
{
return _conversations.AsQueryable();
}
var convSettings = _services.GetService<ConversationSetting>();
var dir = Path.Combine(_dbSettings.FileRepository, convSettings.DataDir);
_conversations = new List<ConversationRecord>();
foreach (var d in Directory.GetDirectories(dir))
{
var json = File.ReadAllText(Path.Combine(d, "conversation.json"));
_conversations.Add(JsonSerializer.Deserialize<ConversationRecord>(json, _options));
}
return _conversations.AsQueryable();
}
}
public void Add<TTableInterface>(object entity)
{
_conversations = Conversation.ToList();
if (entity is ConversationRecord conversation)
{
_conversations.Add(conversation);
_changedTableNames.Add(nameof(ConversationRecord));
}
else if (entity is AgentRecord agent)
{
_agents.Add(agent);
_changedTableNames.Add(nameof(AgentRecord));
}
}
List<string> _changedTableNames = new List<string>();
public int Transaction<TTableInterface>(Action action)
{
_changedTableNames.Clear();
action();
// Persist to disk
foreach (var table in _changedTableNames)
{
if (table == nameof(ConversationRecord))
{
var convSettings = _services.GetService<ConversationSetting>();
foreach (var conversation in _conversations)
{
var dir = Path.Combine(_dbSettings.FileRepository,
convSettings.DataDir,
conversation.Id);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
var path = Path.Combine(dir, "conversation.json");
File.WriteAllText(path, JsonSerializer.Serialize(conversation, _options));
}
}
else if (table == nameof(AgentRecord))
{
var agentSettings = _services.GetService<AgentSettings>();
foreach (var agent in _agents)
{
var dir = Path.Combine(_dbSettings.FileRepository,
agentSettings.DataDir,
agent.Id);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
var path = Path.Combine(dir, "agent.json");
File.WriteAllText(path, JsonSerializer.Serialize(agent, _options));
}
}
}
return _changedTableNames.Count;
}
}

View file

@ -0,0 +1,11 @@
namespace BotSharp.Core.Repository;
public interface IBotSharpRepository
{
IQueryable<UserRecord> User { get; }
IQueryable<AgentRecord> Agent { get; }
IQueryable<UserAgentRecord> UserAgent { get; }
IQueryable<ConversationRecord> Conversation { get; }
int Transaction<TTableInterface>(Action action);
void Add<TTableInterface>(object entity);
}

View file

@ -3,6 +3,7 @@ namespace BotSharp.Core.Repository;
public class MyDatabaseSettings : DatabaseSettings
{
public string[] Assemblies { get; set; }
public string FileRepository { get; set; }
public DbConnectionSetting MongoDb { get; set; }
public DbConnectionSetting BotSharp { get; set; }
}

View file

@ -1,9 +1,5 @@
using BotSharp.Abstraction.Users;
using BotSharp.Abstraction.Users.Models;
using BotSharp.Core.Infrastructures;
using BotSharp.Core.Repository.DbTables;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
@ -23,7 +19,7 @@ public class UserService : IUserService
public async Task<User> CreateUser(User user)
{
var db = _services.GetRequiredService<BotSharpDbContext>();
var db = _services.GetRequiredService<IBotSharpRepository>();
var record = db.User.FirstOrDefault(x => x.Email == user.Email.ToLower());
if (record != null)
{
@ -49,7 +45,7 @@ public class UserService : IUserService
var base64 = Encoding.UTF8.GetString(Convert.FromBase64String(authorization));
var (userEmail, password) = base64.SplitAsTuple(":");
var db = _services.GetRequiredService<BotSharpDbContext>();
var db = _services.GetRequiredService<IBotSharpRepository>();
var record = db.User.FirstOrDefault(x => x.Email == userEmail);
if (record == null)
{
@ -104,7 +100,7 @@ public class UserService : IUserService
{
var userId = _user.Id;
var db = _services.GetRequiredService<BotSharpDbContext>();
var db = _services.GetRequiredService<IBotSharpRepository>();
var user = (from u in db.User
where u.Id == userId
select new User