File repository.
This commit is contained in:
parent
451c55f4e2
commit
1543dd6ce9
|
|
@ -7,5 +7,4 @@ public interface IConversationStorage
|
|||
void InitStorage(string conversationId);
|
||||
void Append(string conversationId, RoleDialogModel dialog);
|
||||
List<RoleDialogModel> GetDialogs(string conversationId);
|
||||
string GetConversationDataDir();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
173
src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs
Normal file
173
src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue