add conversation collection
This commit is contained in:
parent
c897209fda
commit
4cc74e596a
|
|
@ -6,6 +6,7 @@ public class Conversation
|
||||||
public string AgentId { get; set; } = string.Empty;
|
public string AgentId { get; set; } = string.Empty;
|
||||||
public string UserId { get; set; } = string.Empty;
|
public string UserId { get; set; } = string.Empty;
|
||||||
public string Title { get; set; } = string.Empty;
|
public string Title { get; set; } = string.Empty;
|
||||||
|
public string Dialog { get; set; }
|
||||||
|
|
||||||
public DateTime UpdatedTime { get; set; } = DateTime.UtcNow;
|
public DateTime UpdatedTime { get; set; } = DateTime.UtcNow;
|
||||||
public DateTime CreatedTime { get; set; } = DateTime.UtcNow;
|
public DateTime CreatedTime { get; set; } = DateTime.UtcNow;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,19 @@
|
||||||
|
using BotSharp.Abstraction.Repositories.Models;
|
||||||
|
|
||||||
namespace BotSharp.Abstraction.Conversations.Models;
|
namespace BotSharp.Abstraction.Conversations.Models;
|
||||||
|
|
||||||
public class ConversationState : Dictionary<string, string>
|
public class ConversationState : Dictionary<string, string>
|
||||||
{
|
{
|
||||||
|
public ConversationState()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConversationState(List<KeyValueModel> pairs)
|
||||||
|
{
|
||||||
|
foreach (var pair in pairs)
|
||||||
|
{
|
||||||
|
this[pair.Key] = pair.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using BotSharp.Abstraction.Repositories.Models;
|
||||||
using BotSharp.Abstraction.Repositories.Records;
|
using BotSharp.Abstraction.Repositories.Records;
|
||||||
using BotSharp.Abstraction.Routing.Models;
|
using BotSharp.Abstraction.Routing.Models;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
@ -27,4 +28,14 @@ public interface IBotSharpRepository
|
||||||
|
|
||||||
AgentRecord GetAgent(string agentId);
|
AgentRecord GetAgent(string agentId);
|
||||||
List<string> GetAgentResponses(string agentId);
|
List<string> GetAgentResponses(string agentId);
|
||||||
|
|
||||||
|
void CreateNewConversation(ConversationRecord conversation);
|
||||||
|
string GetConversationDialog(string conversationId);
|
||||||
|
void UpdateConversationDialog(string conversationId, string dialogs);
|
||||||
|
|
||||||
|
List<KeyValueModel> GetConversationState(string conversationId);
|
||||||
|
void UpdateConversationState(string conversationId, List<KeyValueModel> state);
|
||||||
|
|
||||||
|
ConversationRecord GetConversation(string conversationId);
|
||||||
|
List<ConversationRecord> GetConversations(string userId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
namespace BotSharp.Abstraction.Repositories.Models;
|
||||||
|
|
||||||
|
public class KeyValueModel
|
||||||
|
{
|
||||||
|
public string Key { get; set; }
|
||||||
|
public string Value { get; set; }
|
||||||
|
|
||||||
|
public KeyValueModel()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyValueModel(string key, string value)
|
||||||
|
{
|
||||||
|
Key = key;
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
using BotSharp.Abstraction.Conversations.Models;
|
using BotSharp.Abstraction.Conversations.Models;
|
||||||
|
using BotSharp.Abstraction.Repositories.Models;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace BotSharp.Abstraction.Repositories.Records;
|
namespace BotSharp.Abstraction.Repositories.Records;
|
||||||
|
|
||||||
|
|
@ -15,6 +17,12 @@ public class ConversationRecord : RecordBase
|
||||||
[MaxLength(64)]
|
[MaxLength(64)]
|
||||||
public string Title { get; set; } = string.Empty;
|
public string Title { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public string Dialog { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public List<KeyValueModel> State { get; set; }
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public DateTime UpdatedTime { get; set; } = DateTime.UtcNow;
|
public DateTime UpdatedTime { get; set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
|
|
@ -29,6 +37,8 @@ public class ConversationRecord : RecordBase
|
||||||
UserId = conv.UserId,
|
UserId = conv.UserId,
|
||||||
Id = conv.Id,
|
Id = conv.Id,
|
||||||
Title = conv.Title,
|
Title = conv.Title,
|
||||||
|
Dialog = conv.Dialog,
|
||||||
|
State = conv.State?.Select(x => new KeyValueModel(x.Key, x.Value))?.ToList() ?? new List<KeyValueModel>(),
|
||||||
CreatedTime = conv.CreatedTime,
|
CreatedTime = conv.CreatedTime,
|
||||||
UpdatedTime = conv.UpdatedTime
|
UpdatedTime = conv.UpdatedTime
|
||||||
};
|
};
|
||||||
|
|
@ -42,6 +52,8 @@ public class ConversationRecord : RecordBase
|
||||||
Title = Title,
|
Title = Title,
|
||||||
UserId = UserId,
|
UserId = UserId,
|
||||||
AgentId = AgentId,
|
AgentId = AgentId,
|
||||||
|
Dialog = Dialog,
|
||||||
|
State = new ConversationState(State),
|
||||||
CreatedTime = CreatedTime,
|
CreatedTime = CreatedTime,
|
||||||
UpdatedTime = UpdatedTime
|
UpdatedTime = UpdatedTime
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -20,13 +20,7 @@ public partial class AgentService
|
||||||
public async Task<Agent> GetAgent(string id)
|
public async Task<Agent> GetAgent(string id)
|
||||||
{
|
{
|
||||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||||
//var query = from agent in db.Agent
|
|
||||||
// where agent.Id == id
|
|
||||||
// select agent.ToAgent();
|
|
||||||
|
|
||||||
//var profile = query.FirstOrDefault();
|
|
||||||
var profile = db.GetAgent(id)?.ToAgent();
|
var profile = db.GetAgent(id)?.ToAgent();
|
||||||
//var dir = GetAgentDataDir(id);
|
|
||||||
|
|
||||||
var instructionFile = profile?.Instruction;
|
var instructionFile = profile?.Instruction;
|
||||||
if (instructionFile != null)
|
if (instructionFile != null)
|
||||||
|
|
|
||||||
|
|
@ -36,21 +36,26 @@ public partial class ConversationService : IConversationService
|
||||||
public async Task<Conversation> GetConversation(string id)
|
public async Task<Conversation> GetConversation(string id)
|
||||||
{
|
{
|
||||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||||
var query = from sess in db.Conversation
|
//var query = from sess in db.Conversation
|
||||||
where sess.Id == id
|
// where sess.Id == id
|
||||||
orderby sess.CreatedTime descending
|
// orderby sess.CreatedTime descending
|
||||||
select sess.ToConversation();
|
// select sess.ToConversation();
|
||||||
return query.FirstOrDefault();
|
|
||||||
|
var conversation = db.GetConversation(id);
|
||||||
|
return conversation?.ToConversation();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<Conversation>> GetConversations()
|
public async Task<List<Conversation>> GetConversations()
|
||||||
{
|
{
|
||||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||||
var query = from sess in db.Conversation
|
//var query = from sess in db.Conversation
|
||||||
where sess.UserId == _user.Id
|
// where sess.UserId == _user.Id
|
||||||
orderby sess.CreatedTime descending
|
// orderby sess.CreatedTime descending
|
||||||
select sess.ToConversation();
|
// select sess.ToConversation();
|
||||||
return query.ToList();
|
|
||||||
|
var user = db.User.FirstOrDefault(x => x.ExternalId == _user.Id);
|
||||||
|
var conversations = db.GetConversations(user?.Id);
|
||||||
|
return conversations.Select(x => x.ToConversation()).OrderByDescending(x => x.CreatedTime).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Conversation> NewConversation(Conversation sess)
|
public async Task<Conversation> NewConversation(Conversation sess)
|
||||||
|
|
@ -66,26 +71,7 @@ public partial class ConversationService : IConversationService
|
||||||
record.UserId = sess.UserId.IfNullOrEmptyAs(foundUserId);
|
record.UserId = sess.UserId.IfNullOrEmptyAs(foundUserId);
|
||||||
record.Title = "New Conversation";
|
record.Title = "New Conversation";
|
||||||
|
|
||||||
//db.Transaction<IBotSharpTable>(delegate
|
db.CreateNewConversation(record);
|
||||||
//{
|
|
||||||
// db.Add<IBotSharpTable>(record);
|
|
||||||
//});
|
|
||||||
|
|
||||||
var dir = Path.Combine(dbSettings.FileRepository, conversationSettings.DataDir, record.Id);
|
|
||||||
if (!Directory.Exists(dir))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(dir);
|
|
||||||
}
|
|
||||||
var path = Path.Combine(dir, "conversation.json");
|
|
||||||
File.WriteAllText(path, JsonSerializer.Serialize(record, new JsonSerializerOptions
|
|
||||||
{
|
|
||||||
PropertyNameCaseInsensitive = true,
|
|
||||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
||||||
WriteIndented = true
|
|
||||||
}));
|
|
||||||
|
|
||||||
_storage.InitStorage(record.Id);
|
|
||||||
|
|
||||||
return record.ToConversation();
|
return record.ToConversation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using BotSharp.Abstraction.Conversations.Models;
|
using BotSharp.Abstraction.Conversations.Models;
|
||||||
using BotSharp.Abstraction.Repositories;
|
using BotSharp.Abstraction.Repositories;
|
||||||
|
using BotSharp.Abstraction.Repositories.Models;
|
||||||
using BotSharp.Abstraction.Repositories.Records;
|
using BotSharp.Abstraction.Repositories.Records;
|
||||||
using MongoDB.Bson;
|
using MongoDB.Bson;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
@ -20,6 +21,7 @@ public class ConversationStateService : IConversationStateService, IDisposable
|
||||||
private BotSharpDatabaseSettings _dbSettings;
|
private BotSharpDatabaseSettings _dbSettings;
|
||||||
private string _conversationId;
|
private string _conversationId;
|
||||||
private string _file;
|
private string _file;
|
||||||
|
private List<KeyValueModel> _savedStates;
|
||||||
|
|
||||||
public ConversationStateService(ILogger<ConversationStateService> logger,
|
public ConversationStateService(ILogger<ConversationStateService> logger,
|
||||||
IServiceProvider services,
|
IServiceProvider services,
|
||||||
|
|
@ -65,18 +67,13 @@ public class ConversationStateService : IConversationStateService, IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
_state = new ConversationState();
|
_state = new ConversationState();
|
||||||
|
_savedStates = _db.GetConversationState(_conversationId);
|
||||||
|
|
||||||
_file = GetStorageFile(_conversationId);
|
if (_savedStates != null)
|
||||||
//_file = GetConversationState(_conversationId);
|
|
||||||
|
|
||||||
if (_file != null)
|
|
||||||
{
|
{
|
||||||
var dict = File.ReadAllLines(_file);
|
foreach (var data in _savedStates)
|
||||||
//var dict = _file.SplitByNewLine();
|
|
||||||
|
|
||||||
foreach (var line in dict)
|
|
||||||
{
|
{
|
||||||
_state[line.Split('=')[0]] = line.Split('=')[1];
|
_state[data.Key] = data.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -92,32 +89,20 @@ public class ConversationStateService : IConversationStateService, IDisposable
|
||||||
|
|
||||||
public void Save()
|
public void Save()
|
||||||
{
|
{
|
||||||
//var states = new StringBuilder();
|
var states = new List<KeyValueModel>();
|
||||||
//var conversation = _db.Conversation.FirstOrDefault(x => x.Id == _conversationId);
|
|
||||||
|
|
||||||
var states = new List<string>();
|
|
||||||
|
|
||||||
foreach (var dic in _state)
|
foreach (var dic in _state)
|
||||||
{
|
{
|
||||||
states.Add($"{dic.Key}={dic.Value}");
|
states.Add(new KeyValueModel(dic.Key, dic.Value));
|
||||||
//states.AppendLine($"{dic.Key}={dic.Value}");
|
|
||||||
}
|
}
|
||||||
File.WriteAllLines(_file, states);
|
|
||||||
_logger.LogInformation($"Saved state {_conversationId}");
|
|
||||||
|
|
||||||
//if (conversation != null)
|
_db.UpdateConversationState(_conversationId, states);
|
||||||
//{
|
_logger.LogInformation($"Saved state {_conversationId}");
|
||||||
// conversation.State = states.ToString();
|
|
||||||
// _db.Transaction<IBotSharpTable>(delegate
|
|
||||||
// {
|
|
||||||
// _db.Add<IBotSharpTable>(conversation);
|
|
||||||
// });
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CleanState()
|
public void CleanState()
|
||||||
{
|
{
|
||||||
File.Delete(_file);
|
//File.Delete(_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetStorageFile(string conversationId)
|
private string GetStorageFile(string conversationId)
|
||||||
|
|
@ -136,33 +121,6 @@ public class ConversationStateService : IConversationStateService, IDisposable
|
||||||
return stateFile;
|
return stateFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
//private string GetConversationState(string conversationId)
|
|
||||||
//{
|
|
||||||
// var conversation = _db.Conversation.FirstOrDefault(x => x.Id == conversationId);
|
|
||||||
// if (conversation == null)
|
|
||||||
// {
|
|
||||||
// var user = _db.User.FirstOrDefault(x => x.ExternalId == _user.Id);
|
|
||||||
// var record = new ConversationRecord()
|
|
||||||
// {
|
|
||||||
// Id = ObjectId.GenerateNewId().ToString(),
|
|
||||||
// //AgentId = _agentSettings.RouterId,
|
|
||||||
// UserId = user?.Id ?? ObjectId.GenerateNewId().ToString(),
|
|
||||||
// Title = "New Conversation",
|
|
||||||
// Dialog = string.Empty,
|
|
||||||
// State = string.Empty
|
|
||||||
// };
|
|
||||||
|
|
||||||
// _db.Transaction<IBotSharpTable>(delegate
|
|
||||||
// {
|
|
||||||
// _db.Add<IBotSharpTable>(record);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// conversation = _db.Conversation.FirstOrDefault(x => x.Id == record.Id);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return conversation.State ?? string.Empty;
|
|
||||||
//}
|
|
||||||
|
|
||||||
public string GetState(string name)
|
public string GetState(string name)
|
||||||
{
|
{
|
||||||
if (!_state.ContainsKey(name))
|
if (!_state.ContainsKey(name))
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,6 @@
|
||||||
using BotSharp.Abstraction.Agents.Enums;
|
using BotSharp.Abstraction.Agents.Enums;
|
||||||
using BotSharp.Abstraction.Agents.Settings;
|
|
||||||
using BotSharp.Abstraction.Conversations.Models;
|
|
||||||
using BotSharp.Abstraction.Repositories;
|
using BotSharp.Abstraction.Repositories;
|
||||||
using BotSharp.Abstraction.Repositories.Records;
|
|
||||||
using MongoDB.Bson;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Tensorflow;
|
|
||||||
|
|
||||||
namespace BotSharp.Core.Conversations.Services;
|
namespace BotSharp.Core.Conversations.Services;
|
||||||
|
|
||||||
|
|
@ -29,12 +24,9 @@ public class ConversationStorage : IConversationStorage
|
||||||
|
|
||||||
public void Append(string conversationId, string agentId, RoleDialogModel dialog)
|
public void Append(string conversationId, string agentId, RoleDialogModel dialog)
|
||||||
{
|
{
|
||||||
//var dialogs = GetConversationDialogs(conversationId);
|
|
||||||
//var sb = new StringBuilder(dialogs);
|
|
||||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||||
|
var dialogText = db.GetConversationDialog(conversationId);
|
||||||
var conversationFile = GetStorageFile(conversationId);
|
var sb = new StringBuilder(dialogText);
|
||||||
var sb = new StringBuilder();
|
|
||||||
|
|
||||||
if (dialog.Role == AgentRole.Function)
|
if (dialog.Role == AgentRole.Function)
|
||||||
{
|
{
|
||||||
|
|
@ -63,24 +55,15 @@ public class ConversationStorage : IConversationStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
var updatedDialogs = sb.ToString();
|
var updatedDialogs = sb.ToString();
|
||||||
File.AppendAllText(conversationFile, updatedDialogs);
|
//File.AppendAllText(conversationFile, updatedDialogs);
|
||||||
|
db.UpdateConversationDialog(conversationId, updatedDialogs);
|
||||||
//var conversation = db.Conversation.FirstOrDefault(x => x.Id == conversationId);
|
|
||||||
//conversation.AgentId = agentId;
|
|
||||||
//conversation.Dialog = updatedDialogs;
|
|
||||||
//db.Transaction<IBotSharpTable>(delegate
|
|
||||||
//{
|
|
||||||
// db.Add<IBotSharpTable>(conversation);
|
|
||||||
//});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<RoleDialogModel> GetDialogs(string conversationId)
|
public List<RoleDialogModel> GetDialogs(string conversationId)
|
||||||
{
|
{
|
||||||
var conversationFile = GetStorageFile(conversationId);
|
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||||
var dialogs = File.ReadAllLines(conversationFile);
|
var dialogText = db.GetConversationDialog(conversationId);
|
||||||
|
var dialogs = dialogText.SplitByNewLine();
|
||||||
//var conversationFile = GetConversationDialogs(conversationId);
|
|
||||||
//var dialogs = conversationFile.SplitByNewLine();
|
|
||||||
|
|
||||||
var results = new List<RoleDialogModel>();
|
var results = new List<RoleDialogModel>();
|
||||||
for (int i = 0; i < dialogs.Length; i += 2)
|
for (int i = 0; i < dialogs.Length; i += 2)
|
||||||
|
|
@ -113,8 +96,6 @@ public class ConversationStorage : IConversationStorage
|
||||||
{
|
{
|
||||||
File.WriteAllLines(file, new string[0]);
|
File.WriteAllLines(file, new string[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetConversationDialogs(conversationId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetStorageFile(string conversationId)
|
private string GetStorageFile(string conversationId)
|
||||||
|
|
@ -126,30 +107,4 @@ public class ConversationStorage : IConversationStorage
|
||||||
}
|
}
|
||||||
return Path.Combine(dir, "dialogs.txt");
|
return Path.Combine(dir, "dialogs.txt");
|
||||||
}
|
}
|
||||||
|
|
||||||
//private string GetConversationDialogs(string conversationId)
|
|
||||||
//{
|
|
||||||
// var db = _services.GetRequiredService<IBotSharpRepository>();
|
|
||||||
// var conversation = db.Conversation.FirstOrDefault(x => x.Id == conversationId);
|
|
||||||
// if (conversation == null)
|
|
||||||
// {
|
|
||||||
// var user = db.User.FirstOrDefault(x => x.ExternalId == _user.Id);
|
|
||||||
// var record = new ConversationRecord()
|
|
||||||
// {
|
|
||||||
// Id = ObjectId.GenerateNewId().ToString(),
|
|
||||||
// //AgentId = _agentSettings.RouterId,
|
|
||||||
// UserId = user?.Id ?? ObjectId.GenerateNewId().ToString(),
|
|
||||||
// Title = "New Conversation"
|
|
||||||
// };
|
|
||||||
|
|
||||||
// db.Transaction<IBotSharpTable>(delegate
|
|
||||||
// {
|
|
||||||
// db.Add<IBotSharpTable>(record);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// conversation = db.Conversation.FirstOrDefault(x => x.Id == record.Id);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return conversation.Dialog ?? string.Empty;
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using BotSharp.Abstraction.Repositories;
|
using BotSharp.Abstraction.Repositories;
|
||||||
|
using BotSharp.Abstraction.Repositories.Models;
|
||||||
using BotSharp.Abstraction.Repositories.Records;
|
using BotSharp.Abstraction.Repositories.Records;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
|
||||||
|
|
@ -106,4 +107,39 @@ public class BotSharpDbContext : Database, IBotSharpRepository
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void CreateNewConversation(ConversationRecord conversation)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetConversationDialog(string conversationId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateConversationDialog(string conversationId, string dialogs)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<KeyValueModel> GetConversationState(string conversationId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateConversationState(string conversationId, List<KeyValueModel> state)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConversationRecord GetConversation(string conversationId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ConversationRecord> GetConversations(string userId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,14 @@
|
||||||
|
using BotSharp.Abstraction.Conversations.Models;
|
||||||
|
using BotSharp.Abstraction.Conversations.Settings;
|
||||||
using BotSharp.Abstraction.Functions.Models;
|
using BotSharp.Abstraction.Functions.Models;
|
||||||
using BotSharp.Abstraction.Repositories;
|
using BotSharp.Abstraction.Repositories;
|
||||||
|
using BotSharp.Abstraction.Repositories.Models;
|
||||||
using BotSharp.Abstraction.Repositories.Records;
|
using BotSharp.Abstraction.Repositories.Records;
|
||||||
|
using MongoDB.Driver.Core.Operations;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using static Tensorflow.TensorShapeProto.Types;
|
||||||
|
using Tensorflow;
|
||||||
|
using FunctionDef = BotSharp.Abstraction.Functions.Models.FunctionDef;
|
||||||
|
|
||||||
namespace BotSharp.Core.Repository;
|
namespace BotSharp.Core.Repository;
|
||||||
|
|
||||||
|
|
@ -401,4 +408,181 @@ public class FileRepository : IBotSharpRepository
|
||||||
var functions = functionDefs.Select(x => JsonSerializer.Serialize(x, _options)).ToList();
|
var functions = functionDefs.Select(x => JsonSerializer.Serialize(x, _options)).ToList();
|
||||||
return functions;
|
return functions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void CreateNewConversation(ConversationRecord conversation)
|
||||||
|
{
|
||||||
|
var dir = Path.Combine(_dbSettings.FileRepository, _conversationSetting.DataDir, conversation.Id);
|
||||||
|
if (!Directory.Exists(dir))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
var convDir = Path.Combine(dir, "conversation.json");
|
||||||
|
if (!File.Exists(convDir))
|
||||||
|
{
|
||||||
|
File.WriteAllText(convDir, JsonSerializer.Serialize(conversation, _options));
|
||||||
|
}
|
||||||
|
|
||||||
|
var dialogDir = Path.Combine(dir, "dialogs.txt");
|
||||||
|
if (!File.Exists(dialogDir))
|
||||||
|
{
|
||||||
|
File.WriteAllText(dialogDir, string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
var stateDir = Path.Combine(dir, "state.dict");
|
||||||
|
if (!File.Exists(stateDir))
|
||||||
|
{
|
||||||
|
File.WriteAllText(stateDir, string.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetConversationDialog(string conversationId)
|
||||||
|
{
|
||||||
|
var convDir = FindConversationDirectory(conversationId);
|
||||||
|
if (!string.IsNullOrEmpty(convDir))
|
||||||
|
{
|
||||||
|
var dialogDir = Path.Combine(convDir, "dialogs.txt");
|
||||||
|
if (File.Exists(dialogDir))
|
||||||
|
{
|
||||||
|
return File.ReadAllText(dialogDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateConversationDialog(string conversationId, string dialogs)
|
||||||
|
{
|
||||||
|
var convDir = FindConversationDirectory(conversationId);
|
||||||
|
if (!string.IsNullOrEmpty(convDir))
|
||||||
|
{
|
||||||
|
var dialogDir = Path.Combine(convDir, "dialogs.txt");
|
||||||
|
if (File.Exists(dialogDir))
|
||||||
|
{
|
||||||
|
File.WriteAllText(dialogDir, dialogs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<KeyValueModel> GetConversationState(string conversationId)
|
||||||
|
{
|
||||||
|
var curStates = new List<KeyValueModel>();
|
||||||
|
var convDir = FindConversationDirectory(conversationId);
|
||||||
|
if (!string.IsNullOrEmpty(convDir))
|
||||||
|
{
|
||||||
|
var stateDir = Path.Combine(convDir, "state.dict");
|
||||||
|
if (File.Exists(stateDir))
|
||||||
|
{
|
||||||
|
var dict = File.ReadAllLines(stateDir);
|
||||||
|
foreach (var line in dict)
|
||||||
|
{
|
||||||
|
var data = line.Split('=');
|
||||||
|
curStates.Add(new KeyValueModel(data[0], data[1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return curStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string? FindConversationDirectory(string conversationId)
|
||||||
|
{
|
||||||
|
var dir = Path.Combine(_dbSettings.FileRepository, _conversationSetting.DataDir);
|
||||||
|
|
||||||
|
foreach (var d in Directory.GetDirectories(dir))
|
||||||
|
{
|
||||||
|
var path = Path.Combine(d, "conversation.json");
|
||||||
|
if (!File.Exists(path)) continue;
|
||||||
|
|
||||||
|
var json = File.ReadAllText(path);
|
||||||
|
var conv = JsonSerializer.Deserialize<ConversationRecord>(json, _options);
|
||||||
|
if (conv != null && conv.Id == conversationId)
|
||||||
|
{
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateConversationState(string conversationId, List<KeyValueModel> state)
|
||||||
|
{
|
||||||
|
var localStates = new List<string>();
|
||||||
|
var convDir = FindConversationDirectory(conversationId);
|
||||||
|
if (!string.IsNullOrEmpty(convDir))
|
||||||
|
{
|
||||||
|
var stateDir = Path.Combine(convDir, "state.dict");
|
||||||
|
if (File.Exists(stateDir))
|
||||||
|
{
|
||||||
|
foreach (var data in state)
|
||||||
|
{
|
||||||
|
localStates.Add($"{data.Key}={data.Value}");
|
||||||
|
}
|
||||||
|
File.WriteAllLines(stateDir, localStates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConversationRecord GetConversation(string conversationId)
|
||||||
|
{
|
||||||
|
var convDir = FindConversationDirectory(conversationId);
|
||||||
|
if (!string.IsNullOrEmpty(convDir))
|
||||||
|
{
|
||||||
|
var convFile = Path.Combine(convDir, "conversation.json");
|
||||||
|
var record = JsonSerializer.Deserialize<ConversationRecord>(convFile);
|
||||||
|
|
||||||
|
var dialogFile = Path.Combine(convDir, "dialogs.txt");
|
||||||
|
if (record != null && File.Exists(dialogFile))
|
||||||
|
{
|
||||||
|
record.Dialog = File.ReadAllText(dialogFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
var stateFile = Path.Combine(convDir, "state.dict");
|
||||||
|
if (record != null && File.Exists(stateFile))
|
||||||
|
{
|
||||||
|
var states = File.ReadLines(stateFile);
|
||||||
|
record.State = states.Select(x => new KeyValueModel(x.Split('=')[0], x.Split('=')[1])).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ConversationRecord> GetConversations(string userId)
|
||||||
|
{
|
||||||
|
var records = new List<ConversationRecord>();
|
||||||
|
var dir = Path.Combine(_dbSettings.FileRepository, _conversationSetting.DataDir);
|
||||||
|
|
||||||
|
foreach (var d in Directory.GetDirectories(dir))
|
||||||
|
{
|
||||||
|
var path = Path.Combine(d, "conversation.json");
|
||||||
|
if (!File.Exists(path)) continue;
|
||||||
|
|
||||||
|
var json = File.ReadAllText(path);
|
||||||
|
var record = JsonSerializer.Deserialize<ConversationRecord>(json, _options);
|
||||||
|
if (record != null && record.UserId == userId)
|
||||||
|
{
|
||||||
|
var dialogFile = Path.Combine(d, "dialogs.txt");
|
||||||
|
if (File.Exists(dialogFile))
|
||||||
|
{
|
||||||
|
record.Dialog = File.ReadAllText(dialogFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
var stateFile = Path.Combine(d, "state.dict");
|
||||||
|
if (File.Exists(stateFile))
|
||||||
|
{
|
||||||
|
var states = File.ReadLines(stateFile);
|
||||||
|
record.State = states.Select(x => new KeyValueModel(x.Split('=')[0], x.Split('=')[1])).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
records.Add(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return records;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,24 +31,15 @@ public class Router : IAgentRouting
|
||||||
|
|
||||||
public RoutingItem[] GetRoutingRecords()
|
public RoutingItem[] GetRoutingRecords()
|
||||||
{
|
{
|
||||||
var agentSettings = _services.GetRequiredService<AgentSettings>();
|
|
||||||
var dbSettings = _services.GetRequiredService<BotSharpDatabaseSettings>();
|
|
||||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||||
//var filePath = Path.Combine(dbSettings.FileRepository, agentSettings.DataDir, "route.json");
|
|
||||||
//var records = JsonSerializer.Deserialize<RoutingItem[]>(File.ReadAllText(filePath));
|
|
||||||
|
|
||||||
var records = db.RoutingItem.Select(x => x.ToRoutingItem()).ToArray();
|
var records = db.RoutingItem.Select(x => x.ToRoutingItem()).ToArray();
|
||||||
|
|
||||||
// check if routing profile is specified
|
|
||||||
//filePath = Path.Combine(dbSettings.FileRepository, agentSettings.DataDir, "routing-profile.json");
|
|
||||||
|
|
||||||
var profiles = db.RoutingProfile.ToList();
|
var profiles = db.RoutingProfile.ToList();
|
||||||
|
|
||||||
if (profiles != null && profiles.Any())
|
if (profiles != null && profiles.Any())
|
||||||
{
|
{
|
||||||
var state = _services.GetRequiredService<IConversationStateService>();
|
var state = _services.GetRequiredService<IConversationStateService>();
|
||||||
var name = state.GetState("channel");
|
var name = state.GetState("channel");
|
||||||
//var profiles = JsonSerializer.Deserialize<RoutingProfile[]>(File.ReadAllText(filePath));
|
|
||||||
var specifiedProfile = profiles.FirstOrDefault(x => x.Name == name);
|
var specifiedProfile = profiles.FirstOrDefault(x => x.Name == name);
|
||||||
if (specifiedProfile != null)
|
if (specifiedProfile != null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -96,11 +96,9 @@ public class UserService : IUserService
|
||||||
|
|
||||||
public async Task<User> GetMyProfile()
|
public async Task<User> GetMyProfile()
|
||||||
{
|
{
|
||||||
var userId = _user.Id;
|
|
||||||
|
|
||||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||||
var user = (from u in db.User
|
var user = (from u in db.User
|
||||||
where u.Id == userId
|
where u.ExternalId == _user.Id
|
||||||
select new User
|
select new User
|
||||||
{
|
{
|
||||||
Id = u.Id,
|
Id = u.Id,
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
using BotSharp.Abstraction.Repositories.Models;
|
||||||
|
|
||||||
namespace BotSharp.Plugin.MongoStorage.Collections;
|
namespace BotSharp.Plugin.MongoStorage.Collections;
|
||||||
|
|
||||||
public class ConversationCollection : MongoBase
|
public class ConversationCollection : MongoBase
|
||||||
|
|
@ -5,6 +7,8 @@ public class ConversationCollection : MongoBase
|
||||||
public Guid AgentId { get; set; }
|
public Guid AgentId { get; set; }
|
||||||
public Guid UserId { get; set; }
|
public Guid UserId { get; set; }
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
|
public string Dialog { get; set; }
|
||||||
|
public List<KeyValueModel> State { get; set; }
|
||||||
|
|
||||||
public DateTime CreatedTime { get; set; }
|
public DateTime CreatedTime { get; set; }
|
||||||
public DateTime UpdatedTime { get; set; }
|
public DateTime UpdatedTime { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
using BotSharp.Abstraction.Agents.Models;
|
||||||
|
using BotSharp.Abstraction.Conversations.Models;
|
||||||
|
using BotSharp.Abstraction.Repositories.Models;
|
||||||
using BotSharp.Plugin.MongoStorage.Collections;
|
using BotSharp.Plugin.MongoStorage.Collections;
|
||||||
|
|
||||||
namespace BotSharp.Plugin.MongoStorage.Repository;
|
namespace BotSharp.Plugin.MongoStorage.Repository;
|
||||||
|
|
@ -210,6 +213,8 @@ public class MongoRepository : IBotSharpRepository
|
||||||
AgentId = Guid.Parse(x.AgentId),
|
AgentId = Guid.Parse(x.AgentId),
|
||||||
UserId = Guid.Parse(x.UserId),
|
UserId = Guid.Parse(x.UserId),
|
||||||
Title = x.Title,
|
Title = x.Title,
|
||||||
|
Dialog = x.Dialog,
|
||||||
|
State = x.State,
|
||||||
CreatedTime = x.CreatedTime,
|
CreatedTime = x.CreatedTime,
|
||||||
UpdatedTime = x.UpdatedTime
|
UpdatedTime = x.UpdatedTime
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
@ -221,6 +226,8 @@ public class MongoRepository : IBotSharpRepository
|
||||||
.Set(x => x.AgentId, conversation.AgentId)
|
.Set(x => x.AgentId, conversation.AgentId)
|
||||||
.Set(x => x.UserId, conversation.UserId)
|
.Set(x => x.UserId, conversation.UserId)
|
||||||
.Set(x => x.Title, conversation.Title)
|
.Set(x => x.Title, conversation.Title)
|
||||||
|
.Set(x => x.Dialog, conversation.Dialog)
|
||||||
|
.Set(x => x.State, conversation.State)
|
||||||
.Set(x => x.CreatedTime, conversation.CreatedTime)
|
.Set(x => x.CreatedTime, conversation.CreatedTime)
|
||||||
.Set(x => x.UpdatedTime, conversation.UpdatedTime);
|
.Set(x => x.UpdatedTime, conversation.UpdatedTime);
|
||||||
_dc.Conversations.UpdateOne(filter, update, _options);
|
_dc.Conversations.UpdateOne(filter, update, _options);
|
||||||
|
|
@ -444,4 +451,116 @@ public class MongoRepository : IBotSharpRepository
|
||||||
var foundAgent = Agent.FirstOrDefault(x => x.Id == agentId);
|
var foundAgent = Agent.FirstOrDefault(x => x.Id == agentId);
|
||||||
return foundAgent;
|
return foundAgent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void CreateNewConversation(ConversationRecord conversation)
|
||||||
|
{
|
||||||
|
if (conversation == null) return;
|
||||||
|
|
||||||
|
var collection = new ConversationCollection
|
||||||
|
{
|
||||||
|
Id = Guid.Parse(conversation.Id),
|
||||||
|
AgentId = Guid.Parse(conversation.AgentId),
|
||||||
|
UserId = Guid.Parse(conversation.UserId),
|
||||||
|
Title = conversation.Title,
|
||||||
|
Dialog = string.Empty,
|
||||||
|
State = new List<KeyValueModel>(),
|
||||||
|
CreatedTime = DateTime.UtcNow,
|
||||||
|
UpdatedTime = DateTime.UtcNow,
|
||||||
|
};
|
||||||
|
|
||||||
|
_dc.Conversations.InsertOne(collection);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetConversationDialog(string conversationId)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(conversationId)) return string.Empty;
|
||||||
|
|
||||||
|
var filterById = Builders<ConversationCollection>.Filter.Eq(x => x.Id, Guid.Parse(conversationId));
|
||||||
|
var foundConversation = _dc.Conversations.Find(filterById).FirstOrDefault();
|
||||||
|
if (foundConversation == null) return string.Empty;
|
||||||
|
|
||||||
|
return foundConversation.Dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateConversationDialog(string conversationId, string dialogs)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(conversationId)) return;
|
||||||
|
|
||||||
|
var filterById = Builders<ConversationCollection>.Filter.Eq(x => x.Id, Guid.Parse(conversationId));
|
||||||
|
var foundConversation = _dc.Conversations.Find(filterById).FirstOrDefault();
|
||||||
|
if (foundConversation == null) return;
|
||||||
|
|
||||||
|
var update = Builders<ConversationCollection>.Update
|
||||||
|
.Set(x => x.Dialog, dialogs)
|
||||||
|
.Set(x => x.UpdatedTime, DateTime.UtcNow);
|
||||||
|
|
||||||
|
_dc.Conversations.UpdateOne(filterById, update);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<KeyValueModel> GetConversationState(string conversationId)
|
||||||
|
{
|
||||||
|
var states = new List<KeyValueModel>();
|
||||||
|
if (string.IsNullOrEmpty(conversationId)) return states;
|
||||||
|
|
||||||
|
var filterById = Builders<ConversationCollection>.Filter.Eq(x => x.Id, Guid.Parse(conversationId));
|
||||||
|
var foundConversation = _dc.Conversations.Find(filterById).FirstOrDefault();
|
||||||
|
if (foundConversation == null) return states;
|
||||||
|
|
||||||
|
var savedStates = foundConversation.State ?? new List<KeyValueModel>();
|
||||||
|
return savedStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateConversationState(string conversationId, List<KeyValueModel> state)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(conversationId)) return;
|
||||||
|
|
||||||
|
var filterById = Builders<ConversationCollection>.Filter.Eq(x => x.Id, Guid.Parse(conversationId));
|
||||||
|
var foundConversation = _dc.Conversations.Find(filterById).FirstOrDefault();
|
||||||
|
if (foundConversation == null) return;
|
||||||
|
|
||||||
|
var update = Builders<ConversationCollection>.Update
|
||||||
|
.Set(x => x.State, state)
|
||||||
|
.Set(x => x.UpdatedTime, DateTime.UtcNow);
|
||||||
|
|
||||||
|
_dc.Conversations.UpdateOne(filterById, update);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConversationRecord GetConversation(string conversationId)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(conversationId)) return null;
|
||||||
|
|
||||||
|
var filterById = Builders<ConversationCollection>.Filter.Eq(x => x.Id, Guid.Parse(conversationId));
|
||||||
|
var found = _dc.Conversations.Find(filterById).FirstOrDefault();
|
||||||
|
|
||||||
|
return found != null ? new ConversationRecord
|
||||||
|
{
|
||||||
|
Id = found.Id.ToString(),
|
||||||
|
AgentId = found.AgentId.ToString(),
|
||||||
|
UserId = found.UserId.ToString(),
|
||||||
|
Title = found.Title,
|
||||||
|
Dialog = found.Dialog,
|
||||||
|
State = found.State,
|
||||||
|
CreatedTime = found.CreatedTime,
|
||||||
|
UpdatedTime = found.UpdatedTime
|
||||||
|
}: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ConversationRecord> GetConversations(string userId)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(userId)) return new List<ConversationRecord>();
|
||||||
|
|
||||||
|
var filterByUserId = Builders<ConversationCollection>.Filter.Eq(x => x.UserId, Guid.Parse(userId));
|
||||||
|
var conversations = _dc.Conversations.Find(filterByUserId).ToList();
|
||||||
|
return conversations.Select(x => new ConversationRecord
|
||||||
|
{
|
||||||
|
Id = x.Id.ToString(),
|
||||||
|
AgentId = x.AgentId.ToString(),
|
||||||
|
UserId = x.UserId.ToString(),
|
||||||
|
Title = x.Title,
|
||||||
|
Dialog = x.Dialog,
|
||||||
|
State = x.State,
|
||||||
|
CreatedTime = x.CreatedTime,
|
||||||
|
UpdatedTime = x.UpdatedTime
|
||||||
|
}).ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue