Add file as conversation storage.#76
This commit is contained in:
parent
a7b263e2eb
commit
29a65a0086
9
.gitignore
vendored
9
.gitignore
vendored
|
|
@ -283,12 +283,5 @@ __pycache__/
|
||||||
*.btm.cs
|
*.btm.cs
|
||||||
*.odx.cs
|
*.odx.cs
|
||||||
*.xsd.cs
|
*.xsd.cs
|
||||||
/BotSharp.WebHost/App_Data/BotSharp.db
|
data
|
||||||
/BotSharp.UI
|
|
||||||
/BotSharp.WebHost/App_Data/Projects
|
|
||||||
/BotSharp.WebHost/PublishOutput
|
|
||||||
/Data
|
|
||||||
/docs/_build
|
/docs/_build
|
||||||
*.RestApi.xml
|
|
||||||
/BotSharp.WebHost/App_Data/AgentStorage
|
|
||||||
/BotSharp.WebHost/App_Data/SessionStorage
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ public interface IAgentService
|
||||||
{
|
{
|
||||||
Task<Agent> CreateAgent(Agent agent);
|
Task<Agent> CreateAgent(Agent agent);
|
||||||
Task<List<Agent>> GetAgents();
|
Task<List<Agent>> GetAgents();
|
||||||
|
Task<Agent> GetAgent(string id);
|
||||||
Task<bool> DeleteAgent(string id);
|
Task<bool> DeleteAgent(string id);
|
||||||
Task UpdateAgent(Agent agent);
|
Task UpdateAgent(Agent agent);
|
||||||
|
string GetAgentDataDir(string agentId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,4 +22,8 @@
|
||||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Infrastructures\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
using BotSharp.Abstraction.Infrastructures.ContentTransfers;
|
|
||||||
|
|
||||||
namespace BotSharp.Abstraction.Conversations;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// IChatServiceZone is used to manage the chat function.
|
|
||||||
/// When user send message to controller, all the registered service zone will process the message respectively.
|
|
||||||
/// </summary>
|
|
||||||
public interface IChatServiceZone : IServiceZone
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +1,14 @@
|
||||||
using BotSharp.Abstraction.Models;
|
using BotSharp.Abstraction.Conversations.Models;
|
||||||
|
|
||||||
namespace BotSharp.Abstraction.Conversations;
|
namespace BotSharp.Abstraction.Conversations;
|
||||||
|
|
||||||
public interface IConversationService
|
public interface IConversationService
|
||||||
{
|
{
|
||||||
void AddDialog(RoleDialogModel dialog);
|
Task<Conversation> NewConversation(Conversation conversation);
|
||||||
List<RoleDialogModel> GetDialogHistory(string sessionId);
|
Task<List<Conversation>> GetConversations();
|
||||||
void CleanHistory();
|
Task DeleteConversation(string id);
|
||||||
|
Task<string> SendMessage(string agentId, string conversationId, RoleDialogModel lastDalog);
|
||||||
|
Task<string> SendMessage(string agentId, string conversationId, List<RoleDialogModel> wholeDialogs);
|
||||||
|
List<RoleDialogModel> GetDialogHistory(string agentId, string conversationId);
|
||||||
|
Task CleanHistory(string agentId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
using BotSharp.Abstraction.Conversations.Models;
|
||||||
|
|
||||||
|
namespace BotSharp.Abstraction.Conversations;
|
||||||
|
|
||||||
|
public interface IConversationStorage
|
||||||
|
{
|
||||||
|
void InitStorage(string agentId, string conversationId);
|
||||||
|
void Append(string agentId, string conversationId, RoleDialogModel dialog);
|
||||||
|
List<RoleDialogModel> GetDialogs(string agentId, string conversationId);
|
||||||
|
}
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
using BotSharp.Abstraction.Conversations.Models;
|
|
||||||
|
|
||||||
namespace BotSharp.Abstraction.Conversations;
|
|
||||||
|
|
||||||
public interface ISessionService
|
|
||||||
{
|
|
||||||
Task<Session> NewSession(Session sess);
|
|
||||||
Task<List<Session>> GetSessions();
|
|
||||||
Task DeleteSession(string sessionId);
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
namespace BotSharp.Abstraction.Conversations.Models;
|
namespace BotSharp.Abstraction.Conversations.Models;
|
||||||
|
|
||||||
public class Session
|
public class Conversation
|
||||||
{
|
{
|
||||||
public string Id { get; set; } = string.Empty;
|
public string Id { get; set; } = string.Empty;
|
||||||
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 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,7 +0,0 @@
|
||||||
namespace BotSharp.Abstraction.Conversations.Models;
|
|
||||||
|
|
||||||
public class MessageModel
|
|
||||||
{
|
|
||||||
public string From { get; set; }
|
|
||||||
public string Content { get; set; }
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
namespace BotSharp.Abstraction.Conversations.Models;
|
||||||
|
|
||||||
|
public class RoleDialogModel
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// user, system, assistant
|
||||||
|
/// </summary>
|
||||||
|
public string Role { get; set; }
|
||||||
|
public string Text { get; set; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{Role}: {Text}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,5 +2,5 @@ namespace BotSharp.Abstraction.Conversations.Settings;
|
||||||
|
|
||||||
public class ConversationSetting
|
public class ConversationSetting
|
||||||
{
|
{
|
||||||
|
public string ChatCompletion { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
using BotSharp.Abstraction.Models;
|
|
||||||
|
|
||||||
namespace BotSharp.Abstraction.Infrastructures.ContentTransmitters;
|
|
||||||
|
|
||||||
public class ContentContainer
|
|
||||||
{
|
|
||||||
public string UserId { get; set; }
|
|
||||||
public string SessionId { get; set; }
|
|
||||||
public string AgentId { get; set; }
|
|
||||||
public List<RoleDialogModel> Conversations { get; set; }
|
|
||||||
public RoleDialogModel Output { get; set; }
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
using BotSharp.Abstraction.Infrastructures.ContentTransfers;
|
|
||||||
|
|
||||||
namespace BotSharp.Abstraction.Infrastructures.ContentTransmitters;
|
|
||||||
|
|
||||||
public interface IContentTransfer
|
|
||||||
{
|
|
||||||
Task<TransportResult> Transport(ContentContainer input);
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
using BotSharp.Abstraction.Infrastructures.ContentTransmitters;
|
|
||||||
|
|
||||||
namespace BotSharp.Abstraction.Infrastructures.ContentTransfers;
|
|
||||||
|
|
||||||
public interface IServiceZone
|
|
||||||
{
|
|
||||||
int Priority { get; }
|
|
||||||
Task Serving(ContentContainer content);
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
namespace BotSharp.Abstraction.Infrastructures.ContentTransfers;
|
|
||||||
|
|
||||||
public class TransportResult
|
|
||||||
{
|
|
||||||
public bool IsSuccess { get; set; }
|
|
||||||
public List<string> Messages { get; set; }
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
using BotSharp.Abstraction.Models;
|
using BotSharp.Abstraction.Agents.Models;
|
||||||
|
using BotSharp.Abstraction.Conversations.Models;
|
||||||
|
|
||||||
namespace BotSharp.Abstraction.MLTasks;
|
namespace BotSharp.Abstraction.MLTasks;
|
||||||
|
|
||||||
public interface IChatCompletion
|
public interface IChatCompletion
|
||||||
{
|
{
|
||||||
Task<string> GetChatCompletionsAsync(List<RoleDialogModel> conversations);
|
Task<string> GetChatCompletionsAsync(Agent agent, List<RoleDialogModel> conversations);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
namespace BotSharp.Abstraction.Models;
|
|
||||||
|
|
||||||
public class RoleDialogModel
|
|
||||||
{
|
|
||||||
public string Role { get; set; }
|
|
||||||
public string Text { get; set; }
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
using BotSharp.Abstraction.Agents;
|
|
||||||
using BotSharp.Abstraction.ApiAdapters;
|
using BotSharp.Abstraction.ApiAdapters;
|
||||||
using BotSharp.Core.Agents.ViewModels;
|
using BotSharp.Core.Agents.ViewModels;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
namespace BotSharp.Core.Agents.Services;
|
|
||||||
|
|
||||||
public partial class AgentService : IChatServiceZone
|
|
||||||
{
|
|
||||||
public int Priority => 10;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Prepare agent profile and configurations
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="content"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task Serving(ContentContainer content)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using BotSharp.Abstraction.Agents.Models;
|
using BotSharp.Abstraction.Agents.Models;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace BotSharp.Core.Agents.Services;
|
namespace BotSharp.Core.Agents.Services;
|
||||||
|
|
||||||
|
|
@ -12,4 +13,20 @@ public partial class AgentService
|
||||||
select agent.ToAgent();
|
select agent.ToAgent();
|
||||||
return query.ToList();
|
return query.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<Agent> GetAgent(string id)
|
||||||
|
{
|
||||||
|
var db = _services.GetRequiredService<AgentDbContext>();
|
||||||
|
var query = from agent in db.Agent
|
||||||
|
where agent.OwnerId == _user.Id && agent.Id == id
|
||||||
|
select agent.ToAgent();
|
||||||
|
|
||||||
|
var profile = query.FirstOrDefault();
|
||||||
|
var dir = GetAgentDataDir(id);
|
||||||
|
|
||||||
|
profile.Instruction = File.ReadAllText(Path.Combine(dir, "instruction.txt"));
|
||||||
|
profile.Samples = File.ReadAllText(Path.Combine(dir, "samples.txt"));
|
||||||
|
|
||||||
|
return profile;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,6 @@ public partial class AgentService
|
||||||
|
|
||||||
record.Name = agent.Name;
|
record.Name = agent.Name;
|
||||||
record.Description = agent.Description;
|
record.Description = agent.Description;
|
||||||
record.Instruction = agent.Instruction;
|
|
||||||
record.Samples = agent.Samples;
|
|
||||||
record.UpdatedDateTime = DateTime.UtcNow;
|
record.UpdatedDateTime = DateTime.UtcNow;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace BotSharp.Core.Agents.Services;
|
namespace BotSharp.Core.Agents.Services;
|
||||||
|
|
||||||
public partial class AgentService : IAgentService
|
public partial class AgentService : IAgentService
|
||||||
|
|
@ -10,4 +12,14 @@ public partial class AgentService : IAgentService
|
||||||
_services = services;
|
_services = services;
|
||||||
_user = user;
|
_user = user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string GetAgentDataDir(string agentId)
|
||||||
|
{
|
||||||
|
var dir = Path.Combine("data", agentId);
|
||||||
|
if (!Directory.Exists(dir))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(dir);
|
||||||
|
}
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using BotSharp.Abstraction.Conversations.Settings;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
|
@ -11,14 +12,14 @@ public static class BotSharpServiceCollectionExtensions
|
||||||
services.AddScoped<IUserService, UserService>();
|
services.AddScoped<IUserService, UserService>();
|
||||||
|
|
||||||
services.AddScoped<IAgentService, AgentService>();
|
services.AddScoped<IAgentService, AgentService>();
|
||||||
services.AddScoped<IChatServiceZone, AgentService>();
|
|
||||||
|
|
||||||
services.AddScoped<ISessionService, SessionService>();
|
var convsationSettings = new ConversationSetting();
|
||||||
|
config.Bind("Conversation", convsationSettings);
|
||||||
|
services.AddSingleton((IServiceProvider x) => convsationSettings);
|
||||||
|
|
||||||
|
services.AddScoped<IConversationStorage, ConversationStorage>();
|
||||||
services.AddScoped<IConversationService, ConversationService>();
|
services.AddScoped<IConversationService, ConversationService>();
|
||||||
|
|
||||||
services.AddScoped<IContentTransfer, ContentTransfer>();
|
|
||||||
|
|
||||||
RegisterRepository(services, config);
|
RegisterRepository(services, config);
|
||||||
|
|
||||||
RegisterPlugins(services, config);
|
RegisterPlugins(services, config);
|
||||||
|
|
@ -46,17 +47,11 @@ public static class BotSharpServiceCollectionExtensions
|
||||||
{
|
{
|
||||||
var databaseSettings = new DatabaseSettings();
|
var databaseSettings = new DatabaseSettings();
|
||||||
config.Bind("Database", databaseSettings);
|
config.Bind("Database", databaseSettings);
|
||||||
services.AddSingleton((IServiceProvider x) =>
|
services.AddSingleton((IServiceProvider x) => databaseSettings);
|
||||||
{
|
|
||||||
return databaseSettings;
|
|
||||||
});
|
|
||||||
|
|
||||||
var myDatabaseSettings = new MyDatabaseSettings();
|
var myDatabaseSettings = new MyDatabaseSettings();
|
||||||
config.Bind("Database", myDatabaseSettings);
|
config.Bind("Database", myDatabaseSettings);
|
||||||
services.AddSingleton((IServiceProvider x) =>
|
services.AddSingleton((IServiceProvider x) => databaseSettings);
|
||||||
{
|
|
||||||
return databaseSettings;
|
|
||||||
});
|
|
||||||
|
|
||||||
services.AddScoped((IServiceProvider x) =>
|
services.AddScoped((IServiceProvider x) =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -21,50 +21,39 @@ public class ConversationController : ControllerBase, IApiAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("/conversation/{agentId}")]
|
[HttpPost("/conversation/{agentId}")]
|
||||||
public async Task<SessionViewModel> NewSession([FromRoute] string agentId)
|
public async Task<ConversationViewModel> NewConversation([FromRoute] string agentId)
|
||||||
{
|
{
|
||||||
var service = _services.GetRequiredService<ISessionService>();
|
var service = _services.GetRequiredService<IConversationService>();
|
||||||
var sess = new Session
|
var sess = new Conversation
|
||||||
{
|
{
|
||||||
AgentId = agentId
|
AgentId = agentId
|
||||||
};
|
};
|
||||||
sess = await service.NewSession(sess);
|
sess = await service.NewConversation(sess);
|
||||||
return SessionViewModel.FromSession(sess);
|
return ConversationViewModel.FromSession(sess);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpDelete("/conversation/{agentId}/{sessionId}")]
|
[HttpDelete("/conversation/{agentId}/{conversationId}")]
|
||||||
public async Task DeleteSession([FromRoute] string agentId, [FromRoute] string sessionId)
|
public async Task DeleteConversation([FromRoute] string agentId, [FromRoute] string conversationId)
|
||||||
{
|
{
|
||||||
var service = _services.GetRequiredService<ISessionService>();
|
var service = _services.GetRequiredService<IConversationService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("/conversation/{agentId}/{sessionId}")]
|
[HttpPost("/conversation/{agentId}/{conversationId}")]
|
||||||
public async Task<MessageResponseModel> SendMessage([FromRoute] string agentId,
|
public async Task<MessageResponseModel> SendMessage([FromRoute] string agentId,
|
||||||
[FromRoute] string sessionId,
|
[FromRoute] string conversationId,
|
||||||
[FromBody] NewMessageModel input)
|
[FromBody] NewMessageModel input)
|
||||||
{
|
{
|
||||||
var transmitter = _services.GetRequiredService<IContentTransfer>();
|
var conv = _services.GetRequiredService<IConversationService>();
|
||||||
|
|
||||||
var container = new ContentContainer
|
var result = await conv.SendMessage(agentId, conversationId, new RoleDialogModel
|
||||||
{
|
{
|
||||||
AgentId = agentId,
|
Role = "user",
|
||||||
SessionId = sessionId,
|
Text = input.Text
|
||||||
Conversations = new List<RoleDialogModel>
|
});
|
||||||
{
|
|
||||||
new RoleDialogModel
|
|
||||||
{
|
|
||||||
Role = "user",
|
|
||||||
Text = input.Text
|
|
||||||
}
|
|
||||||
},
|
|
||||||
UserId = _user.Id
|
|
||||||
};
|
|
||||||
|
|
||||||
var result = await transmitter.Transport(container);
|
|
||||||
|
|
||||||
return new MessageResponseModel
|
return new MessageResponseModel
|
||||||
{
|
{
|
||||||
Content = result.IsSuccess ? container.Output.Text : result.Messages.First()
|
Content = result
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,52 +1,100 @@
|
||||||
using BotSharp.Abstraction.Conversations;
|
using BotSharp.Abstraction.Conversations.Models;
|
||||||
using BotSharp.Abstraction.Models;
|
using BotSharp.Abstraction.Conversations.Settings;
|
||||||
using System;
|
using BotSharp.Abstraction.MLTasks;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace BotSharp.Core.Conversations.Services;
|
namespace BotSharp.Core.Conversations.Services;
|
||||||
|
|
||||||
public class ConversationService : IConversationService
|
public class ConversationService : IConversationService
|
||||||
{
|
{
|
||||||
Dictionary<string, List<RoleDialogModel>> _history;
|
private readonly IServiceProvider _services;
|
||||||
|
private readonly IUserIdentity _user;
|
||||||
|
private readonly ConversationSetting _settings;
|
||||||
|
private readonly IConversationStorage _storage;
|
||||||
|
|
||||||
public ConversationService()
|
public ConversationService(IServiceProvider services,
|
||||||
|
IUserIdentity user,
|
||||||
|
ConversationSetting settings,
|
||||||
|
IConversationStorage storage)
|
||||||
{
|
{
|
||||||
_history = new Dictionary<string, List<RoleDialogModel>>();
|
_services = services;
|
||||||
|
_user = user;
|
||||||
|
_settings = settings;
|
||||||
|
_storage = storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddDialog(RoleDialogModel dialog)
|
public Task DeleteConversation(string id)
|
||||||
{
|
|
||||||
_history[Guid.Empty.ToString()].Add(dialog);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CleanHistory()
|
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteSession()
|
public async Task<List<Conversation>> GetConversations()
|
||||||
|
{
|
||||||
|
var db = _services.GetRequiredService<AgentDbContext>();
|
||||||
|
var query = from sess in db.Conversation
|
||||||
|
where sess.UserId == _user.Id
|
||||||
|
orderby sess.CreatedTime descending
|
||||||
|
select sess.ToConversation();
|
||||||
|
return query.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Conversation> NewConversation(Conversation sess)
|
||||||
|
{
|
||||||
|
var db = _services.GetRequiredService<AgentDbContext>();
|
||||||
|
|
||||||
|
var record = ConversationRecord.FromConversation(sess);
|
||||||
|
record.Id = Guid.NewGuid().ToString();
|
||||||
|
record.UserId = _user.Id;
|
||||||
|
record.Title = "New Conversation";
|
||||||
|
|
||||||
|
db.Transaction<IAgentTable>(delegate
|
||||||
|
{
|
||||||
|
db.Add<IAgentTable>(record);
|
||||||
|
});
|
||||||
|
|
||||||
|
_storage.InitStorage(sess.AgentId, record.Id);
|
||||||
|
|
||||||
|
return record.ToConversation();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> SendMessage(string agentId, string conversationId, RoleDialogModel lastDalog)
|
||||||
|
{
|
||||||
|
_storage.Append(agentId, conversationId, lastDalog);
|
||||||
|
|
||||||
|
var wholeDialogs = GetDialogHistory(agentId, conversationId);
|
||||||
|
|
||||||
|
var response = await SendMessage(agentId, conversationId, wholeDialogs);
|
||||||
|
|
||||||
|
_storage.Append(agentId, conversationId, new RoleDialogModel
|
||||||
|
{
|
||||||
|
Role = "assistant",
|
||||||
|
Text = response
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> SendMessage(string agentId, string conversationId, List<RoleDialogModel> wholeDialogs)
|
||||||
|
{
|
||||||
|
var agent = await _services.GetRequiredService<IAgentService>().GetAgent(agentId);
|
||||||
|
var chat = GetChatCompletion();
|
||||||
|
var response = await chat.GetChatCompletionsAsync(agent, wholeDialogs);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IChatCompletion GetChatCompletion()
|
||||||
|
{
|
||||||
|
var completions = _services.GetServices<IChatCompletion>();
|
||||||
|
return completions.FirstOrDefault(x => x.GetType().FullName.Contains(_settings.ChatCompletion));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task CleanHistory(string agentId)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<string> GetAllSessions()
|
public List<RoleDialogModel> GetDialogHistory(string agentId, string conversationId)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return _storage.GetDialogs(agentId, conversationId);
|
||||||
}
|
|
||||||
|
|
||||||
public List<RoleDialogModel> GetDialogHistory()
|
|
||||||
{
|
|
||||||
return _history[Guid.Empty.ToString()];
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<RoleDialogModel> GetDialogHistory(string sessionId)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public string NewSession()
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
using BotSharp.Abstraction.Conversations.Models;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace BotSharp.Core.Conversations.Services;
|
||||||
|
|
||||||
|
public class ConversationStorage : IConversationStorage
|
||||||
|
{
|
||||||
|
private readonly IAgentService _agent;
|
||||||
|
public ConversationStorage(IAgentService agent)
|
||||||
|
{
|
||||||
|
_agent = agent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Append(string agentId, string conversationId, RoleDialogModel dialog)
|
||||||
|
{
|
||||||
|
var conversationFile = GetStorageFile(agentId, conversationId);
|
||||||
|
File.AppendAllText(conversationFile, $"{dialog.Role}: {dialog.Text}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<RoleDialogModel> GetDialogs(string agentId, string conversationId)
|
||||||
|
{
|
||||||
|
var conversationFile = GetStorageFile(agentId, conversationId);
|
||||||
|
var dialogs = File.ReadAllLines(conversationFile);
|
||||||
|
return dialogs.Select(x =>
|
||||||
|
{
|
||||||
|
var pos = x.IndexOf(':');
|
||||||
|
var role = x.Substring(0, pos);
|
||||||
|
var text = x.Substring(pos + 1);
|
||||||
|
return new RoleDialogModel
|
||||||
|
{
|
||||||
|
Role = role,
|
||||||
|
Text = text
|
||||||
|
};
|
||||||
|
}).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InitStorage(string agentId, string conversationId)
|
||||||
|
{
|
||||||
|
var dir = _agent.GetAgentDataDir(agentId);
|
||||||
|
var dialogDir = Path.Combine(dir, "conversations");
|
||||||
|
if (!Directory.Exists(dialogDir))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(dialogDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
var conversationFile = Path.Combine(dialogDir, conversationId + ".txt");
|
||||||
|
if (!File.Exists(conversationFile))
|
||||||
|
{
|
||||||
|
File.WriteAllLines(conversationFile, new string[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetStorageFile(string agentId, string conversationId)
|
||||||
|
{
|
||||||
|
var dir = _agent.GetAgentDataDir(agentId);
|
||||||
|
var dialogDir = Path.Combine(dir, "conversations");
|
||||||
|
return Path.Combine(dialogDir, conversationId + ".txt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
using BotSharp.Abstraction.Conversations;
|
|
||||||
using BotSharp.Abstraction.Conversations.Models;
|
|
||||||
using BotSharp.Abstraction.Users;
|
|
||||||
|
|
||||||
namespace BotSharp.Core.Conversations.Services;
|
|
||||||
|
|
||||||
public class SessionService : ISessionService
|
|
||||||
{
|
|
||||||
private readonly IServiceProvider _services;
|
|
||||||
private readonly IUserIdentity _user;
|
|
||||||
|
|
||||||
public SessionService(IServiceProvider services, IUserIdentity user)
|
|
||||||
{
|
|
||||||
_services = services;
|
|
||||||
_user = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task DeleteSession(string sessionId)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<List<Session>> GetSessions()
|
|
||||||
{
|
|
||||||
var db = _services.GetRequiredService<AgentDbContext>();
|
|
||||||
var query = from sess in db.Session
|
|
||||||
where sess.UserId == _user.Id
|
|
||||||
orderby sess.CreatedTime descending
|
|
||||||
select sess.ToSession();
|
|
||||||
return query.ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Session> NewSession(Session sess)
|
|
||||||
{
|
|
||||||
var db = _services.GetRequiredService<AgentDbContext>();
|
|
||||||
|
|
||||||
var record = SessionRecord.FromSession(sess);
|
|
||||||
record.Id = Guid.NewGuid().ToString();
|
|
||||||
record.UserId = _user.Id;
|
|
||||||
record.Title = "New Session";
|
|
||||||
|
|
||||||
db.Transaction<IAgentTable>(delegate
|
|
||||||
{
|
|
||||||
db.Add<IAgentTable>(record);
|
|
||||||
});
|
|
||||||
|
|
||||||
return record.ToSession();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
namespace BotSharp.Core.Conversations.ViewModels;
|
||||||
|
|
||||||
|
public class ConversationCreationModel
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@ using BotSharp.Abstraction.Conversations.Models;
|
||||||
|
|
||||||
namespace BotSharp.Core.Conversations.ViewModels;
|
namespace BotSharp.Core.Conversations.ViewModels;
|
||||||
|
|
||||||
public class SessionViewModel
|
public class ConversationViewModel
|
||||||
{
|
{
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
public string AgentId { get; set; }
|
public string AgentId { get; set; }
|
||||||
|
|
@ -10,9 +10,9 @@ public class SessionViewModel
|
||||||
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;
|
||||||
|
|
||||||
public static SessionViewModel FromSession(Session sess)
|
public static ConversationViewModel FromSession(Conversation sess)
|
||||||
{
|
{
|
||||||
return new SessionViewModel
|
return new ConversationViewModel
|
||||||
{
|
{
|
||||||
Id = sess.Id,
|
Id = sess.Id,
|
||||||
AgentId = sess.AgentId,
|
AgentId = sess.AgentId,
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
using BotSharp.Abstraction.Conversations.Models;
|
|
||||||
|
|
||||||
namespace BotSharp.Core.Conversations.ViewModels;
|
|
||||||
|
|
||||||
public class SessionCreationModel
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
namespace BotSharp.Core.Infrastructures;
|
|
||||||
|
|
||||||
public class ContentTransfer : IContentTransfer
|
|
||||||
{
|
|
||||||
private readonly IServiceProvider _services;
|
|
||||||
|
|
||||||
public ContentTransfer(IServiceProvider services)
|
|
||||||
{
|
|
||||||
_services = services;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<TransportResult> Transport(ContentContainer input)
|
|
||||||
{
|
|
||||||
input.Output = new RoleDialogModel();
|
|
||||||
|
|
||||||
var result = new TransportResult
|
|
||||||
{
|
|
||||||
IsSuccess = true,
|
|
||||||
Messages = new List<string>()
|
|
||||||
};
|
|
||||||
|
|
||||||
var zones = _services.GetServices<IChatServiceZone>()
|
|
||||||
.OrderBy(x => x.Priority)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
foreach (var zone in zones)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await zone.Serving(input);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
result.IsSuccess = false;
|
|
||||||
result.Messages.Add(ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -9,14 +9,17 @@ public class KnowledgeService : IKnowledgeService
|
||||||
{
|
{
|
||||||
private readonly IServiceProvider _services;
|
private readonly IServiceProvider _services;
|
||||||
private readonly KnowledgeBaseSettings _settings;
|
private readonly KnowledgeBaseSettings _settings;
|
||||||
|
private readonly IAgentService _agentService;
|
||||||
private readonly ITextChopper _textChopper;
|
private readonly ITextChopper _textChopper;
|
||||||
|
|
||||||
public KnowledgeService(IServiceProvider services,
|
public KnowledgeService(IServiceProvider services,
|
||||||
KnowledgeBaseSettings settings,
|
KnowledgeBaseSettings settings,
|
||||||
|
IAgentService agentService,
|
||||||
ITextChopper textChopper)
|
ITextChopper textChopper)
|
||||||
{
|
{
|
||||||
_services = services;
|
_services = services;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
|
_agentService = agentService;
|
||||||
_textChopper = textChopper;
|
_textChopper = textChopper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -30,13 +33,8 @@ public class KnowledgeService : IKnowledgeService
|
||||||
});
|
});
|
||||||
|
|
||||||
// Store chunks in local file system
|
// Store chunks in local file system
|
||||||
var knowledgeStoreDir = Path.Combine("knowledge_base");
|
var agentDataDir = _agentService.GetAgentDataDir(knowledge.AgentId);
|
||||||
if (!Directory.Exists(knowledgeStoreDir))
|
var knowledgePath = Path.Combine(agentDataDir, "knowledge.txt");
|
||||||
{
|
|
||||||
Directory.CreateDirectory(knowledgeStoreDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
var knowledgePath = Path.Combine(knowledgeStoreDir, knowledge.AgentId + ".txt");
|
|
||||||
File.WriteAllLines(knowledgePath, lines);
|
File.WriteAllLines(knowledgePath, lines);
|
||||||
|
|
||||||
var db = GetVectorDb();
|
var db = GetVectorDb();
|
||||||
|
|
@ -57,7 +55,8 @@ public class KnowledgeService : IKnowledgeService
|
||||||
var vector = textEmbedding.GetVector(retrievalModel.Question);
|
var vector = textEmbedding.GetVector(retrievalModel.Question);
|
||||||
|
|
||||||
// Scan local knowledge directory
|
// Scan local knowledge directory
|
||||||
var chunks = File.ReadAllLines(Path.Combine("knowledge_base", retrievalModel.AgentId + ".txt"));
|
var agentDataDir = _agentService.GetAgentDataDir(retrievalModel.AgentId);
|
||||||
|
var chunks = File.ReadAllLines(Path.Combine(agentDataDir, "knowledge.txt"));
|
||||||
|
|
||||||
// Vector search
|
// Vector search
|
||||||
var result = await GetVectorDb().Search(retrievalModel.AgentId, vector);
|
var result = await GetVectorDb().Search(retrievalModel.AgentId, vector);
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
|
using BotSharp.Abstraction.Agents.Models;
|
||||||
|
using BotSharp.Abstraction.Conversations.Models;
|
||||||
|
using BotSharp.Abstraction.MLTasks;
|
||||||
using LLama;
|
using LLama;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace BotSharp.Core.Plugins.LLamaSharp;
|
namespace BotSharp.Core.Plugins.LLamaSharp;
|
||||||
|
|
||||||
public class ChatCompletionProvider : IChatServiceZone
|
public class ChatCompletionProvider : IChatCompletion
|
||||||
{
|
{
|
||||||
private readonly IChatModel _model;
|
private readonly IChatModel _model;
|
||||||
private readonly LlamaSharpSettings _settings;
|
private readonly LlamaSharpSettings _settings;
|
||||||
|
|
@ -42,6 +45,21 @@ public class ChatCompletionProvider : IChatServiceZone
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task<string> GetChatCompletionsAsync(Agent agent, List<RoleDialogModel> conversations)
|
||||||
|
{
|
||||||
|
string totalResponse = "";
|
||||||
|
var prompt = GetInstruction();
|
||||||
|
var content = string.Join("\n ", conversations.Select(x => $"{x.Role}: {x.Text.Replace("user:", "")}")).Trim();
|
||||||
|
content += "\n assistant: ";
|
||||||
|
foreach (var response in _model.Chat(content, prompt, "UTF-8"))
|
||||||
|
{
|
||||||
|
Console.Write(response);
|
||||||
|
totalResponse += response;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult(totalResponse);
|
||||||
|
}
|
||||||
|
|
||||||
public List<RoleDialogModel> GetChatSamples()
|
public List<RoleDialogModel> GetChatSamples()
|
||||||
{
|
{
|
||||||
var samples = new List<RoleDialogModel>();
|
var samples = new List<RoleDialogModel>();
|
||||||
|
|
@ -80,19 +98,4 @@ public class ChatCompletionProvider : IChatServiceZone
|
||||||
|
|
||||||
return instruction;
|
return instruction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Serving(ContentContainer content)
|
|
||||||
{
|
|
||||||
string output = "";
|
|
||||||
var prompt = GetInstruction();
|
|
||||||
var conversations = string.Join("\n ", content.Conversations.Select(x => $"{x.Role}: {x.Text.Replace("user:", "")}")).Trim();
|
|
||||||
conversations += "\n assistant: ";
|
|
||||||
foreach (var response in _model.Chat(conversations, prompt, "UTF-8"))
|
|
||||||
{
|
|
||||||
Console.Write(response);
|
|
||||||
output += response;
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using BotSharp.Abstraction.MLTasks;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
namespace BotSharp.Core.Plugins.LLamaSharp;
|
namespace BotSharp.Core.Plugins.LLamaSharp;
|
||||||
|
|
@ -10,6 +11,6 @@ public class LLamaSharpPlugin : IBotSharpPlugin
|
||||||
config.Bind("LlamaSharp", llamaSharpSettings);
|
config.Bind("LlamaSharp", llamaSharpSettings);
|
||||||
services.AddSingleton(x => llamaSharpSettings);
|
services.AddSingleton(x => llamaSharpSettings);
|
||||||
|
|
||||||
services.AddScoped<IServiceZone, ChatCompletionProvider>();
|
services.AddScoped<IChatCompletion, ChatCompletionProvider>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using BotSharp.Abstraction.VectorStorage;
|
using BotSharp.Abstraction.VectorStorage;
|
||||||
|
using Tensorflow;
|
||||||
using Tensorflow.NumPy;
|
using Tensorflow.NumPy;
|
||||||
|
|
||||||
namespace BotSharp.Core.Plugins.MemVecDb;
|
namespace BotSharp.Core.Plugins.MemVecDb;
|
||||||
|
|
@ -21,15 +22,17 @@ public class MemVectorDatabase : IVectorDb
|
||||||
|
|
||||||
public Task<List<int>> Search(string collectionName, float[] vector, int limit = 10)
|
public Task<List<int>> Search(string collectionName, float[] vector, int limit = 10)
|
||||||
{
|
{
|
||||||
var cosineList = new List<double>();
|
var similarities = new float[_vectors[collectionName].Count];
|
||||||
for (int i = 0; i < _vectors[collectionName].Count; i++)
|
for (int i = 0; i < _vectors[collectionName].Count; i++)
|
||||||
{
|
{
|
||||||
var p = CalCosineSimilarity(vector, _vectors[collectionName][i].Vector);
|
similarities[i] = CalCosineSimilarity(vector, _vectors[collectionName][i].Vector);
|
||||||
cosineList.Add(p);
|
|
||||||
}
|
}
|
||||||
var similarities = cosineList.ToArray();
|
|
||||||
var indice = np.argsort(similarities).ToArray<int>()
|
var indice = np.argsort(similarities).ToArray<int>()
|
||||||
.Reverse().Take(limit).ToList();
|
.Reverse()
|
||||||
|
.Take(limit)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
return Task.FromResult(indice);
|
return Task.FromResult(indice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -44,24 +47,8 @@ public class MemVectorDatabase : IVectorDb
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private double CalCosineSimilarity(float[] vector1, float[] vector2)
|
private float CalCosineSimilarity(float[] a, float[] b)
|
||||||
{
|
{
|
||||||
NDArray a = vector1;
|
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b));
|
||||||
NDArray b = vector2;
|
|
||||||
double num = np.dot(a, b);
|
|
||||||
if(num == 0)
|
|
||||||
{
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
b = np.square(a);
|
|
||||||
var x = np.sqrt(np.sum(b));
|
|
||||||
var x3 = np.sum(np.square(vector2));
|
|
||||||
double num2 = np.sqrt(x) * np.sqrt(x3);
|
|
||||||
if(num2 == 0)
|
|
||||||
{
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
return num / num2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,5 +4,5 @@ public class AgentDbContext : Database
|
||||||
{
|
{
|
||||||
public IQueryable<UserRecord> User => Table<UserRecord>();
|
public IQueryable<UserRecord> User => Table<UserRecord>();
|
||||||
public IQueryable<AgentRecord> Agent => Table<AgentRecord>();
|
public IQueryable<AgentRecord> Agent => Table<AgentRecord>();
|
||||||
public IQueryable<SessionRecord> Session => Table<SessionRecord>();
|
public IQueryable<ConversationRecord> Conversation => Table<ConversationRecord>();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ using MongoDB.Bson.Serialization.IdGenerators;
|
||||||
|
|
||||||
namespace BotSharp.Core.Repository.Collections;
|
namespace BotSharp.Core.Repository.Collections;
|
||||||
|
|
||||||
public class Conversation : IMongoDbCollection
|
public class ConversationCollection : IMongoDbCollection
|
||||||
{
|
{
|
||||||
[BsonId(IdGenerator = typeof(ObjectIdGenerator))]
|
[BsonId(IdGenerator = typeof(ObjectIdGenerator))]
|
||||||
public ObjectId Id { get; set; }
|
public ObjectId Id { get; set; }
|
||||||
|
|
@ -15,7 +15,7 @@ public class Conversation : IMongoDbCollection
|
||||||
public string Model { get; set; }
|
public string Model { get; set; }
|
||||||
|
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public List<MessageModel> Messages { get; set; }
|
public List<RoleDialogModel> Messages { get; set; }
|
||||||
|
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
public DateTime UpdatedAt { get; set; }
|
public DateTime UpdatedAt { get; set; }
|
||||||
|
|
@ -18,18 +18,6 @@ public class AgentRecord : DbRecord, IAgentTable
|
||||||
[MaxLength(512)]
|
[MaxLength(512)]
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Instruction
|
|
||||||
/// </summary>
|
|
||||||
[StringLength(int.MaxValue)]
|
|
||||||
public string Instruction { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Samples
|
|
||||||
/// </summary>
|
|
||||||
[StringLength(int.MaxValue)]
|
|
||||||
public string Samples { get; set; }
|
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public DateTime CreatedDateTime { get; set; }
|
public DateTime CreatedDateTime { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace BotSharp.Core.Repository.DbTables;
|
namespace BotSharp.Core.Repository.DbTables;
|
||||||
|
|
||||||
[Table("Session")]
|
[Table("Conversation")]
|
||||||
public class SessionRecord : DbRecord, IAgentTable
|
public class ConversationRecord : DbRecord, IAgentTable
|
||||||
{
|
{
|
||||||
[Required]
|
[Required]
|
||||||
[MaxLength(36)]
|
[MaxLength(36)]
|
||||||
|
|
@ -24,22 +24,22 @@ public class SessionRecord : DbRecord, IAgentTable
|
||||||
[Required]
|
[Required]
|
||||||
public DateTime CreatedTime { get; set; } = DateTime.UtcNow;
|
public DateTime CreatedTime { get; set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
public static SessionRecord FromSession(Session sess)
|
public static ConversationRecord FromConversation(Conversation conv)
|
||||||
{
|
{
|
||||||
return new SessionRecord
|
return new ConversationRecord
|
||||||
{
|
{
|
||||||
AgentId = sess.AgentId,
|
AgentId = conv.AgentId,
|
||||||
UserId = sess.UserId,
|
UserId = conv.UserId,
|
||||||
Id = sess.Id,
|
Id = conv.Id,
|
||||||
Title = sess.Title,
|
Title = conv.Title,
|
||||||
CreatedTime = sess.CreatedTime,
|
CreatedTime = conv.CreatedTime,
|
||||||
UpdatedTime = sess.UpdatedTime
|
UpdatedTime = conv.UpdatedTime
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public Session ToSession()
|
public Conversation ToConversation()
|
||||||
{
|
{
|
||||||
return new Session
|
return new Conversation
|
||||||
{
|
{
|
||||||
Id = Id,
|
Id = Id,
|
||||||
Title = Title,
|
Title = Title,
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
using BotSharp.Core.Repository.Collections;
|
using BotSharp.Core.Repository.Collections;
|
||||||
using EntityFrameworkCore.BootKit;
|
|
||||||
using MongoDB.Driver;
|
using MongoDB.Driver;
|
||||||
|
|
||||||
namespace BotSharp.Core.Repository;
|
namespace BotSharp.Core.Repository;
|
||||||
|
|
||||||
public class MongoDbContext : Database
|
public class MongoDbContext : Database
|
||||||
{
|
{
|
||||||
public IMongoCollection<Conversation> Conversations
|
public IMongoCollection<ConversationCollection> Conversations
|
||||||
=> Collection<Conversation>("conversations");
|
=> Collection<ConversationCollection>("conversations");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,8 @@ global using BotSharp.Abstraction.Plugins;
|
||||||
global using EntityFrameworkCore.BootKit;
|
global using EntityFrameworkCore.BootKit;
|
||||||
global using BotSharp.Abstraction.Agents;
|
global using BotSharp.Abstraction.Agents;
|
||||||
global using BotSharp.Abstraction.Conversations;
|
global using BotSharp.Abstraction.Conversations;
|
||||||
global using BotSharp.Abstraction.Infrastructures.ContentTransmitters;
|
|
||||||
global using BotSharp.Abstraction.Infrastructures.ContentTransfers;
|
|
||||||
global using BotSharp.Abstraction.Knowledges;
|
global using BotSharp.Abstraction.Knowledges;
|
||||||
global using BotSharp.Abstraction.Users;
|
global using BotSharp.Abstraction.Users;
|
||||||
global using BotSharp.Abstraction.Models;
|
|
||||||
global using BotSharp.Core.Repository;
|
global using BotSharp.Core.Repository;
|
||||||
global using BotSharp.Core.Repository.Abstraction;
|
global using BotSharp.Core.Repository.Abstraction;
|
||||||
global using BotSharp.Core.Repository.DbTables;
|
global using BotSharp.Core.Repository.DbTables;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
using BotSharp.Abstraction.Conversations;
|
|
||||||
using BotSharp.Abstraction.MLTasks;
|
using BotSharp.Abstraction.MLTasks;
|
||||||
using BotSharp.Abstraction.Plugins;
|
using BotSharp.Abstraction.Plugins;
|
||||||
using BotSharp.Plugin.AzureOpenAI.Providers;
|
using BotSharp.Plugin.AzureOpenAI.Providers;
|
||||||
using BotSharp.Plugin.AzureOpenAI.Services;
|
|
||||||
using BotSharp.Plugin.AzureOpenAI.Settings;
|
using BotSharp.Plugin.AzureOpenAI.Settings;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
@ -19,6 +17,5 @@ public class AzureOpenAiPlugin : IBotSharpPlugin
|
||||||
|
|
||||||
services.AddSingleton<ITextCompletion, TextCompletionProvider>();
|
services.AddSingleton<ITextCompletion, TextCompletionProvider>();
|
||||||
services.AddScoped<IChatCompletion, ChatCompletionProvider>();
|
services.AddScoped<IChatCompletion, ChatCompletionProvider>();
|
||||||
services.AddScoped<IChatServiceZone, ChatService>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
using Azure;
|
using Azure;
|
||||||
using Azure.AI.OpenAI;
|
using Azure.AI.OpenAI;
|
||||||
using BotSharp.Abstraction.Infrastructures.ContentTransfers;
|
using BotSharp.Abstraction.Agents.Models;
|
||||||
using BotSharp.Abstraction.Infrastructures.ContentTransmitters;
|
using BotSharp.Abstraction.Conversations.Models;
|
||||||
using BotSharp.Abstraction.MLTasks;
|
using BotSharp.Abstraction.MLTasks;
|
||||||
using BotSharp.Abstraction.Models;
|
|
||||||
using BotSharp.Plugin.AzureOpenAI.Settings;
|
using BotSharp.Plugin.AzureOpenAI.Settings;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
@ -21,7 +20,7 @@ public class ChatCompletionProvider : IChatCompletion
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task GetChatCompletionsAsync(List<RoleDialogModel> conversations,
|
/*public async Task GetChatCompletionsAsync(List<RoleDialogModel> conversations,
|
||||||
Func<string, Task> onChunkReceived)
|
Func<string, Task> onChunkReceived)
|
||||||
{
|
{
|
||||||
var client = new OpenAIClient(new Uri(_settings.Endpoint), new AzureKeyCredential(_settings.ApiKey));
|
var client = new OpenAIClient(new Uri(_settings.Endpoint), new AzureKeyCredential(_settings.ApiKey));
|
||||||
|
|
@ -44,14 +43,14 @@ public class ChatCompletionProvider : IChatCompletion
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
}
|
}*/
|
||||||
|
|
||||||
public List<RoleDialogModel> GetChatSamples()
|
public List<RoleDialogModel> GetChatSamples(string sampleText)
|
||||||
{
|
{
|
||||||
var samples = new List<RoleDialogModel>();
|
var samples = new List<RoleDialogModel>();
|
||||||
if (!string.IsNullOrEmpty(_settings.ChatSampleFile))
|
if (!string.IsNullOrEmpty(sampleText))
|
||||||
{
|
{
|
||||||
var lines = File.ReadAllLines(_settings.ChatSampleFile);
|
var lines = sampleText.Split('\n');
|
||||||
for (int i = 0; i < lines.Length; i++)
|
for (int i = 0; i < lines.Length; i++)
|
||||||
{
|
{
|
||||||
var line = lines[i];
|
var line = lines[i];
|
||||||
|
|
@ -68,19 +67,11 @@ public class ChatCompletionProvider : IChatCompletion
|
||||||
return samples;
|
return samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetInstruction()
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(_settings.InstructionFile))
|
|
||||||
{
|
|
||||||
return File.ReadAllText(_settings.InstructionFile);
|
|
||||||
}
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<string> GetChatCompletionsAsync(List<RoleDialogModel> conversations)
|
public async Task<string> GetChatCompletionsAsync(Agent agent, List<RoleDialogModel> conversations)
|
||||||
{
|
{
|
||||||
var client = new OpenAIClient(new Uri(_settings.Endpoint), new AzureKeyCredential(_settings.ApiKey));
|
var client = new OpenAIClient(new Uri(_settings.Endpoint), new AzureKeyCredential(_settings.ApiKey));
|
||||||
var chatCompletionsOptions = PrepareOptions(conversations);
|
var chatCompletionsOptions = PrepareOptions(agent, conversations);
|
||||||
|
|
||||||
var response = await client.GetChatCompletionsStreamingAsync(_settings.DeploymentModel.ChatCompletionModel, chatCompletionsOptions);
|
var response = await client.GetChatCompletionsStreamingAsync(_settings.DeploymentModel.ChatCompletionModel, chatCompletionsOptions);
|
||||||
using StreamingChatCompletions streaming = response.Value;
|
using StreamingChatCompletions streaming = response.Value;
|
||||||
|
|
@ -100,18 +91,17 @@ public class ChatCompletionProvider : IChatCompletion
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChatCompletionsOptions PrepareOptions(List<RoleDialogModel> conversations)
|
private ChatCompletionsOptions PrepareOptions(Agent agent, List<RoleDialogModel> conversations)
|
||||||
{
|
{
|
||||||
var prompt = GetInstruction();
|
|
||||||
var chatCompletionsOptions = new ChatCompletionsOptions()
|
var chatCompletionsOptions = new ChatCompletionsOptions()
|
||||||
{
|
{
|
||||||
Messages =
|
Messages =
|
||||||
{
|
{
|
||||||
new ChatMessage(ChatRole.System, prompt)
|
new ChatMessage(ChatRole.System, agent.Instruction)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var message in GetChatSamples())
|
foreach (var message in GetChatSamples(agent.Samples))
|
||||||
{
|
{
|
||||||
chatCompletionsOptions.Messages.Add(new ChatMessage(message.Role, message.Text));
|
chatCompletionsOptions.Messages.Add(new ChatMessage(message.Role, message.Text));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
using Azure.AI.OpenAI;
|
|
||||||
using BotSharp.Abstraction.Conversations;
|
|
||||||
using BotSharp.Abstraction.Infrastructures.ContentTransmitters;
|
|
||||||
using BotSharp.Abstraction.MLTasks;
|
|
||||||
using BotSharp.Abstraction.Models;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace BotSharp.Plugin.AzureOpenAI.Services;
|
|
||||||
|
|
||||||
public class ChatService : IChatServiceZone
|
|
||||||
{
|
|
||||||
private readonly IChatCompletion _chatCompletion;
|
|
||||||
|
|
||||||
public ChatService(IChatCompletion chatCompletion)
|
|
||||||
{
|
|
||||||
_chatCompletion = chatCompletion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Priority => 100;
|
|
||||||
|
|
||||||
public async Task Serving(ContentContainer content)
|
|
||||||
{
|
|
||||||
var output = await _chatCompletion.GetChatCompletionsAsync(content.Conversations);
|
|
||||||
|
|
||||||
content.Output = new RoleDialogModel
|
|
||||||
{
|
|
||||||
Role = ChatRole.Assistant.ToString(),
|
|
||||||
Text = output
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -13,8 +13,9 @@ using System;
|
||||||
using Azure.AI.OpenAI;
|
using Azure.AI.OpenAI;
|
||||||
using BotSharp.Abstraction.ApiAdapters;
|
using BotSharp.Abstraction.ApiAdapters;
|
||||||
using BotSharp.Plugin.ChatbotUI.ViewModels;
|
using BotSharp.Plugin.ChatbotUI.ViewModels;
|
||||||
using BotSharp.Abstraction.Infrastructures.ContentTransmitters;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using BotSharp.Abstraction.Conversations;
|
||||||
|
using BotSharp.Abstraction.Conversations.Models;
|
||||||
|
|
||||||
namespace BotSharp.Plugin.ChatbotUI.Controllers;
|
namespace BotSharp.Plugin.ChatbotUI.Controllers;
|
||||||
|
|
||||||
|
|
@ -64,22 +65,11 @@ public class ChatbotUiController : ControllerBase, IApiAdapter
|
||||||
Text = x.Content
|
Text = x.Content
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
/*await _chatCompletionProvider.GetChatCompletionsAsync(conversations,
|
var conv = _services.GetRequiredService<IConversationService>();
|
||||||
async content =>
|
|
||||||
{
|
|
||||||
await OnChunkReceived(outputStream, content);
|
|
||||||
});*/
|
|
||||||
|
|
||||||
var transmitter = _services.GetRequiredService<IContentTransfer>();
|
var result = await conv.SendMessage("", "", conversations.Last());
|
||||||
|
|
||||||
var container = new ContentContainer
|
await OnChunkReceived(outputStream, result);
|
||||||
{
|
|
||||||
Conversations = conversations
|
|
||||||
};
|
|
||||||
|
|
||||||
var result = await transmitter.Transport(container);
|
|
||||||
|
|
||||||
await OnChunkReceived(outputStream, container.Output.Text);
|
|
||||||
await OnEventCompleted(outputStream);
|
await OnEventCompleted(outputStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
using BotSharp.Abstraction.Conversations;
|
|
||||||
using BotSharp.Abstraction.Infrastructures.ContentTransmitters;
|
|
||||||
using BotSharp.Abstraction.Models;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Senparc.NeuChar.App.AppStore;
|
using Senparc.NeuChar.App.AppStore;
|
||||||
using Senparc.NeuChar.Entities;
|
using Senparc.NeuChar.Entities;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
using BotSharp.Abstraction.Conversations;
|
using BotSharp.Abstraction.Conversations;
|
||||||
using BotSharp.Abstraction.Infrastructures.ContentTransmitters;
|
using BotSharp.Abstraction.Conversations.Models;
|
||||||
using BotSharp.Abstraction.Models;
|
using BotSharp.Abstraction.Models;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
|
|
@ -22,41 +22,23 @@ namespace BotSharp.Plugin.WeChat
|
||||||
ILogger<WeChatBackgroundService> logger)
|
ILogger<WeChatBackgroundService> logger)
|
||||||
{
|
{
|
||||||
|
|
||||||
this._service = service;
|
_service = service;
|
||||||
this._logger = logger;
|
_logger = logger;
|
||||||
this._queue = Channel.CreateUnbounded<WeChatMessage>();
|
_queue = Channel.CreateUnbounded<WeChatMessage>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task HandleTextMessageAsync(string openid, string message)
|
private async Task HandleTextMessageAsync(string openid, string message)
|
||||||
{
|
{
|
||||||
var scoped = _service.CreateScope().ServiceProvider;
|
var scoped = _service.CreateScope().ServiceProvider;
|
||||||
var conversationService = scoped.GetRequiredService<IConversationService>();
|
var conversationService = scoped.GetRequiredService<IConversationService>();
|
||||||
var contentTransfer = scoped.GetRequiredService<IContentTransfer>();
|
|
||||||
|
|
||||||
var conversations = conversationService.GetDialogHistory(openid);
|
var result = await conversationService.SendMessage(openid, Guid.Empty.ToString(), new RoleDialogModel
|
||||||
conversations.Add(new RoleDialogModel
|
|
||||||
{
|
{
|
||||||
Role = "User",
|
Role = "user",
|
||||||
Text = message,
|
Text = message,
|
||||||
});
|
});
|
||||||
|
|
||||||
var container = new ContentContainer
|
await ReplyTextMessageAsync(openid, result);
|
||||||
{
|
|
||||||
Conversations = conversations
|
|
||||||
};
|
|
||||||
|
|
||||||
var result = await contentTransfer.Transport(container);
|
|
||||||
|
|
||||||
if (result.IsSuccess)
|
|
||||||
{
|
|
||||||
var output = container.Output.Text.Trim();
|
|
||||||
await ReplyTextMessageAsync(openid, output);
|
|
||||||
conversationService.AddDialog(new RoleDialogModel()
|
|
||||||
{
|
|
||||||
Role = "Assistant",
|
|
||||||
Text = output,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ReplyTextMessageAsync(string openid, string content)
|
private async Task ReplyTextMessageAsync(string openid, string content)
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
user: Hi
|
|
||||||
assistant: Hello, I'm a AI assistant to help you schedule meeting.
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
Transcript of a dialog, where the User interacts with an Assistant named Bob. Bob is helpful, kind, honest, good at writing, and never fails to answer the User's requests immediately and with precision.
|
|
||||||
|
|
||||||
User: Hello, Bob.
|
|
||||||
Bob: Hello. How may I help you today?
|
|
||||||
User: Please tell me the largest city in Europe.
|
|
||||||
Bob: Sure. The largest city in Europe is Moscow, the capital of Russia.
|
|
||||||
User:
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
|
@ -8,25 +8,22 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Remove="data\**" />
|
||||||
<Compile Remove="knowledge_chunks\**" />
|
<Compile Remove="knowledge_chunks\**" />
|
||||||
|
<Compile Remove="Prompts\**" />
|
||||||
|
<Content Remove="data\**" />
|
||||||
<Content Remove="knowledge_chunks\**" />
|
<Content Remove="knowledge_chunks\**" />
|
||||||
|
<Content Remove="Prompts\**" />
|
||||||
|
<EmbeddedResource Remove="data\**" />
|
||||||
<EmbeddedResource Remove="knowledge_chunks\**" />
|
<EmbeddedResource Remove="knowledge_chunks\**" />
|
||||||
|
<EmbeddedResource Remove="Prompts\**" />
|
||||||
|
<None Remove="data\**" />
|
||||||
<None Remove="knowledge_chunks\**" />
|
<None Remove="knowledge_chunks\**" />
|
||||||
|
<None Remove="Prompts\**" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Remove="crawl-300d-2M-subword.bin" />
|
<None Remove="crawl-300d-2M-subword.bin" />
|
||||||
<None Remove="Prompts\chat-samples.txt" />
|
|
||||||
<None Remove="Prompts\chat-with-bob.txt" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Content Include="Prompts\chat-samples.txt">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="Prompts\chat-with-bob.txt">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
"Conversation": {
|
"Conversation": {
|
||||||
|
"ChatCompletion": "AzureOpenAI.Providers.ChatCompletionProvider"
|
||||||
},
|
},
|
||||||
|
|
||||||
"LlamaSharp": {
|
"LlamaSharp": {
|
||||||
|
|
@ -48,7 +48,7 @@
|
||||||
"Master": "mongodb://localhost:27017/chat-ui"
|
"Master": "mongodb://localhost:27017/chat-ui"
|
||||||
},
|
},
|
||||||
"Agent": {
|
"Agent": {
|
||||||
"Master": "Data Source=(localdb)\\ProjectModels;Initial Catalog=Agent;Integrated Security=True;Connect Timeout=30;Encrypt=False;Trust Server Certificate=False;Application Intent=ReadWrite;Multi Subnet Failover=False",
|
"Master": "Data Source=(localdb)\\ProjectModels;Initial Catalog=BotSharp;Integrated Security=True;Connect Timeout=30;Encrypt=False;Trust Server Certificate=False;Application Intent=ReadWrite;Multi Subnet Failover=False",
|
||||||
"Slavers": []
|
"Slavers": []
|
||||||
},
|
},
|
||||||
"UseCamelCase": true,
|
"UseCamelCase": true,
|
||||||
|
|
@ -70,7 +70,7 @@
|
||||||
"KnowledgeBase": {
|
"KnowledgeBase": {
|
||||||
"VectorDb": "MemVectorDatabase",
|
"VectorDb": "MemVectorDatabase",
|
||||||
"TextEmbedding": "fastTextEmbeddingProvider",
|
"TextEmbedding": "fastTextEmbeddingProvider",
|
||||||
"TextCompletion": "TextCompletionProvider"
|
"TextCompletion": "AzureOpenAI.Providers.TextCompletionProvider"
|
||||||
},
|
},
|
||||||
|
|
||||||
"PluginLoader": {
|
"PluginLoader": {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue