Add file as conversation storage.#76

This commit is contained in:
Haiping Chen 2023-06-27 13:31:13 -05:00
parent a7b263e2eb
commit 29a65a0086
51 changed files with 337 additions and 482 deletions

9
.gitignore vendored
View file

@ -283,12 +283,5 @@ __pycache__/
*.btm.cs
*.odx.cs
*.xsd.cs
/BotSharp.WebHost/App_Data/BotSharp.db
/BotSharp.UI
/BotSharp.WebHost/App_Data/Projects
/BotSharp.WebHost/PublishOutput
/Data
data
/docs/_build
*.RestApi.xml
/BotSharp.WebHost/App_Data/AgentStorage
/BotSharp.WebHost/App_Data/SessionStorage

View file

@ -9,6 +9,8 @@ public interface IAgentService
{
Task<Agent> CreateAgent(Agent agent);
Task<List<Agent>> GetAgents();
Task<Agent> GetAgent(string id);
Task<bool> DeleteAgent(string id);
Task UpdateAgent(Agent agent);
string GetAgentDataDir(string agentId);
}

View file

@ -22,4 +22,8 @@
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Infrastructures\" />
</ItemGroup>
</Project>

View file

@ -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
{
}

View file

@ -1,10 +1,14 @@
using BotSharp.Abstraction.Models;
using BotSharp.Abstraction.Conversations.Models;
namespace BotSharp.Abstraction.Conversations;
public interface IConversationService
{
void AddDialog(RoleDialogModel dialog);
List<RoleDialogModel> GetDialogHistory(string sessionId);
void CleanHistory();
Task<Conversation> NewConversation(Conversation conversation);
Task<List<Conversation>> GetConversations();
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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -1,11 +1,12 @@
namespace BotSharp.Abstraction.Conversations.Models;
public class Session
public class Conversation
{
public string Id { get; set; } = string.Empty;
public string AgentId { get; set; } = string.Empty;
public string UserId { get; set; } = string.Empty;
public string Title { get; set; } = string.Empty;
public DateTime UpdatedTime { get; set; } = DateTime.UtcNow;
public DateTime CreatedTime { get; set; } = DateTime.UtcNow;
}

View file

@ -1,7 +0,0 @@
namespace BotSharp.Abstraction.Conversations.Models;
public class MessageModel
{
public string From { get; set; }
public string Content { get; set; }
}

View file

@ -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}";
}
}

View file

@ -2,5 +2,5 @@ namespace BotSharp.Abstraction.Conversations.Settings;
public class ConversationSetting
{
public string ChatCompletion { get; set; }
}

View file

@ -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; }
}

View file

@ -1,8 +0,0 @@
using BotSharp.Abstraction.Infrastructures.ContentTransfers;
namespace BotSharp.Abstraction.Infrastructures.ContentTransmitters;
public interface IContentTransfer
{
Task<TransportResult> Transport(ContentContainer input);
}

View file

@ -1,9 +0,0 @@
using BotSharp.Abstraction.Infrastructures.ContentTransmitters;
namespace BotSharp.Abstraction.Infrastructures.ContentTransfers;
public interface IServiceZone
{
int Priority { get; }
Task Serving(ContentContainer content);
}

View file

@ -1,7 +0,0 @@
namespace BotSharp.Abstraction.Infrastructures.ContentTransfers;
public class TransportResult
{
public bool IsSuccess { get; set; }
public List<string> Messages { get; set; }
}

View file

@ -1,8 +1,9 @@
using BotSharp.Abstraction.Models;
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Conversations.Models;
namespace BotSharp.Abstraction.MLTasks;
public interface IChatCompletion
{
Task<string> GetChatCompletionsAsync(List<RoleDialogModel> conversations);
Task<string> GetChatCompletionsAsync(Agent agent, List<RoleDialogModel> conversations);
}

View file

@ -1,7 +0,0 @@
namespace BotSharp.Abstraction.Models;
public class RoleDialogModel
{
public string Role { get; set; }
public string Text { get; set; }
}

View file

@ -1,4 +1,3 @@
using BotSharp.Abstraction.Agents;
using BotSharp.Abstraction.ApiAdapters;
using BotSharp.Core.Agents.ViewModels;
using Microsoft.AspNetCore.Authorization;

View file

@ -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)
{
}
}

View file

@ -1,4 +1,5 @@
using BotSharp.Abstraction.Agents.Models;
using System.IO;
namespace BotSharp.Core.Agents.Services;
@ -12,4 +13,20 @@ public partial class AgentService
select agent.ToAgent();
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;
}
}

View file

@ -14,8 +14,6 @@ public partial class AgentService
record.Name = agent.Name;
record.Description = agent.Description;
record.Instruction = agent.Instruction;
record.Samples = agent.Samples;
record.UpdatedDateTime = DateTime.UtcNow;
});
}

View file

@ -1,3 +1,5 @@
using System.IO;
namespace BotSharp.Core.Agents.Services;
public partial class AgentService : IAgentService
@ -10,4 +12,14 @@ public partial class AgentService : IAgentService
_services = services;
_user = user;
}
public string GetAgentDataDir(string agentId)
{
var dir = Path.Combine("data", agentId);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
return dir;
}
}

View file

@ -1,3 +1,4 @@
using BotSharp.Abstraction.Conversations.Settings;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
@ -11,14 +12,14 @@ public static class BotSharpServiceCollectionExtensions
services.AddScoped<IUserService, UserService>();
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<IContentTransfer, ContentTransfer>();
RegisterRepository(services, config);
RegisterPlugins(services, config);
@ -46,17 +47,11 @@ public static class BotSharpServiceCollectionExtensions
{
var databaseSettings = new DatabaseSettings();
config.Bind("Database", databaseSettings);
services.AddSingleton((IServiceProvider x) =>
{
return databaseSettings;
});
services.AddSingleton((IServiceProvider x) => databaseSettings);
var myDatabaseSettings = new MyDatabaseSettings();
config.Bind("Database", myDatabaseSettings);
services.AddSingleton((IServiceProvider x) =>
{
return databaseSettings;
});
services.AddSingleton((IServiceProvider x) => databaseSettings);
services.AddScoped((IServiceProvider x) =>
{

View file

@ -21,50 +21,39 @@ public class ConversationController : ControllerBase, IApiAdapter
}
[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 sess = new Session
var service = _services.GetRequiredService<IConversationService>();
var sess = new Conversation
{
AgentId = agentId
};
sess = await service.NewSession(sess);
return SessionViewModel.FromSession(sess);
sess = await service.NewConversation(sess);
return ConversationViewModel.FromSession(sess);
}
[HttpDelete("/conversation/{agentId}/{sessionId}")]
public async Task DeleteSession([FromRoute] string agentId, [FromRoute] string sessionId)
[HttpDelete("/conversation/{agentId}/{conversationId}")]
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,
[FromRoute] string sessionId,
[FromRoute] string conversationId,
[FromBody] NewMessageModel input)
{
var transmitter = _services.GetRequiredService<IContentTransfer>();
var conv = _services.GetRequiredService<IConversationService>();
var container = new ContentContainer
{
AgentId = agentId,
SessionId = sessionId,
Conversations = new List<RoleDialogModel>
{
new RoleDialogModel
var result = await conv.SendMessage(agentId, conversationId, new RoleDialogModel
{
Role = "user",
Text = input.Text
}
},
UserId = _user.Id
};
var result = await transmitter.Transport(container);
});
return new MessageResponseModel
{
Content = result.IsSuccess ? container.Output.Text : result.Messages.First()
Content = result
};
}
}

View file

@ -1,52 +1,100 @@
using BotSharp.Abstraction.Conversations;
using BotSharp.Abstraction.Models;
using System;
using System.Collections.Generic;
using System.Text;
using BotSharp.Abstraction.Conversations.Models;
using BotSharp.Abstraction.Conversations.Settings;
using BotSharp.Abstraction.MLTasks;
namespace BotSharp.Core.Conversations.Services;
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)
{
_history[Guid.Empty.ToString()].Add(dialog);
}
public void CleanHistory()
public Task DeleteConversation(string id)
{
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();
}
public List<string> GetAllSessions()
public List<RoleDialogModel> GetDialogHistory(string agentId, string conversationId)
{
throw new NotImplementedException();
}
public List<RoleDialogModel> GetDialogHistory()
{
return _history[Guid.Empty.ToString()];
}
public List<RoleDialogModel> GetDialogHistory(string sessionId)
{
throw new NotImplementedException();
}
public string NewSession()
{
throw new NotImplementedException();
return _storage.GetDialogs(agentId, conversationId);
}
}

View file

@ -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");
}
}

View file

@ -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();
}
}

View file

@ -0,0 +1,6 @@
namespace BotSharp.Core.Conversations.ViewModels;
public class ConversationCreationModel
{
}

View file

@ -2,7 +2,7 @@ using BotSharp.Abstraction.Conversations.Models;
namespace BotSharp.Core.Conversations.ViewModels;
public class SessionViewModel
public class ConversationViewModel
{
public string Id { get; set; }
public string AgentId { get; set; }
@ -10,9 +10,9 @@ public class SessionViewModel
public DateTime UpdatedTime { 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,
AgentId = sess.AgentId,

View file

@ -1,8 +0,0 @@
using BotSharp.Abstraction.Conversations.Models;
namespace BotSharp.Core.Conversations.ViewModels;
public class SessionCreationModel
{
}

View file

@ -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;
}
}

View file

@ -9,14 +9,17 @@ public class KnowledgeService : IKnowledgeService
{
private readonly IServiceProvider _services;
private readonly KnowledgeBaseSettings _settings;
private readonly IAgentService _agentService;
private readonly ITextChopper _textChopper;
public KnowledgeService(IServiceProvider services,
KnowledgeBaseSettings settings,
IAgentService agentService,
ITextChopper textChopper)
{
_services = services;
_settings = settings;
_agentService = agentService;
_textChopper = textChopper;
}
@ -30,13 +33,8 @@ public class KnowledgeService : IKnowledgeService
});
// Store chunks in local file system
var knowledgeStoreDir = Path.Combine("knowledge_base");
if (!Directory.Exists(knowledgeStoreDir))
{
Directory.CreateDirectory(knowledgeStoreDir);
}
var knowledgePath = Path.Combine(knowledgeStoreDir, knowledge.AgentId + ".txt");
var agentDataDir = _agentService.GetAgentDataDir(knowledge.AgentId);
var knowledgePath = Path.Combine(agentDataDir, "knowledge.txt");
File.WriteAllLines(knowledgePath, lines);
var db = GetVectorDb();
@ -57,7 +55,8 @@ public class KnowledgeService : IKnowledgeService
var vector = textEmbedding.GetVector(retrievalModel.Question);
// 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
var result = await GetVectorDb().Search(retrievalModel.AgentId, vector);

View file

@ -1,9 +1,12 @@
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Conversations.Models;
using BotSharp.Abstraction.MLTasks;
using LLama;
using System.IO;
namespace BotSharp.Core.Plugins.LLamaSharp;
public class ChatCompletionProvider : IChatServiceZone
public class ChatCompletionProvider : IChatCompletion
{
private readonly IChatModel _model;
private readonly LlamaSharpSettings _settings;
@ -42,6 +45,21 @@ public class ChatCompletionProvider : IChatServiceZone
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()
{
var samples = new List<RoleDialogModel>();
@ -80,19 +98,4 @@ public class ChatCompletionProvider : IChatServiceZone
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();
}
}

View file

@ -1,3 +1,4 @@
using BotSharp.Abstraction.MLTasks;
using Microsoft.Extensions.Configuration;
namespace BotSharp.Core.Plugins.LLamaSharp;
@ -10,6 +11,6 @@ public class LLamaSharpPlugin : IBotSharpPlugin
config.Bind("LlamaSharp", llamaSharpSettings);
services.AddSingleton(x => llamaSharpSettings);
services.AddScoped<IServiceZone, ChatCompletionProvider>();
services.AddScoped<IChatCompletion, ChatCompletionProvider>();
}
}

View file

@ -1,4 +1,5 @@
using BotSharp.Abstraction.VectorStorage;
using Tensorflow;
using Tensorflow.NumPy;
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)
{
var cosineList = new List<double>();
var similarities = new float[_vectors[collectionName].Count];
for (int i = 0; i < _vectors[collectionName].Count; i++)
{
var p = CalCosineSimilarity(vector, _vectors[collectionName][i].Vector);
cosineList.Add(p);
similarities[i] = CalCosineSimilarity(vector, _vectors[collectionName][i].Vector);
}
var similarities = cosineList.ToArray();
var indice = np.argsort(similarities).ToArray<int>()
.Reverse().Take(limit).ToList();
.Reverse()
.Take(limit)
.ToList();
return Task.FromResult(indice);
}
@ -44,24 +47,8 @@ public class MemVectorDatabase : IVectorDb
return Task.CompletedTask;
}
private double CalCosineSimilarity(float[] vector1, float[] vector2)
private float CalCosineSimilarity(float[] a, float[] b)
{
NDArray a = vector1;
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;
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b));
}
}

View file

@ -4,5 +4,5 @@ public class AgentDbContext : Database
{
public IQueryable<UserRecord> User => Table<UserRecord>();
public IQueryable<AgentRecord> Agent => Table<AgentRecord>();
public IQueryable<SessionRecord> Session => Table<SessionRecord>();
public IQueryable<ConversationRecord> Conversation => Table<ConversationRecord>();
}

View file

@ -5,7 +5,7 @@ using MongoDB.Bson.Serialization.IdGenerators;
namespace BotSharp.Core.Repository.Collections;
public class Conversation : IMongoDbCollection
public class ConversationCollection : IMongoDbCollection
{
[BsonId(IdGenerator = typeof(ObjectIdGenerator))]
public ObjectId Id { get; set; }
@ -15,7 +15,7 @@ public class Conversation : IMongoDbCollection
public string Model { 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 UpdatedAt { get; set; }

View file

@ -18,18 +18,6 @@ public class AgentRecord : DbRecord, IAgentTable
[MaxLength(512)]
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]
public DateTime CreatedDateTime { get; set; }

View file

@ -4,8 +4,8 @@ using System.ComponentModel.DataAnnotations.Schema;
namespace BotSharp.Core.Repository.DbTables;
[Table("Session")]
public class SessionRecord : DbRecord, IAgentTable
[Table("Conversation")]
public class ConversationRecord : DbRecord, IAgentTable
{
[Required]
[MaxLength(36)]
@ -24,22 +24,22 @@ public class SessionRecord : DbRecord, IAgentTable
[Required]
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,
UserId = sess.UserId,
Id = sess.Id,
Title = sess.Title,
CreatedTime = sess.CreatedTime,
UpdatedTime = sess.UpdatedTime
AgentId = conv.AgentId,
UserId = conv.UserId,
Id = conv.Id,
Title = conv.Title,
CreatedTime = conv.CreatedTime,
UpdatedTime = conv.UpdatedTime
};
}
public Session ToSession()
public Conversation ToConversation()
{
return new Session
return new Conversation
{
Id = Id,
Title = Title,

View file

@ -1,11 +1,10 @@
using BotSharp.Core.Repository.Collections;
using EntityFrameworkCore.BootKit;
using MongoDB.Driver;
namespace BotSharp.Core.Repository;
public class MongoDbContext : Database
{
public IMongoCollection<Conversation> Conversations
=> Collection<Conversation>("conversations");
public IMongoCollection<ConversationCollection> Conversations
=> Collection<ConversationCollection>("conversations");
}

View file

@ -8,11 +8,8 @@ global using BotSharp.Abstraction.Plugins;
global using EntityFrameworkCore.BootKit;
global using BotSharp.Abstraction.Agents;
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.Users;
global using BotSharp.Abstraction.Models;
global using BotSharp.Core.Repository;
global using BotSharp.Core.Repository.Abstraction;
global using BotSharp.Core.Repository.DbTables;

View file

@ -1,8 +1,6 @@
using BotSharp.Abstraction.Conversations;
using BotSharp.Abstraction.MLTasks;
using BotSharp.Abstraction.Plugins;
using BotSharp.Plugin.AzureOpenAI.Providers;
using BotSharp.Plugin.AzureOpenAI.Services;
using BotSharp.Plugin.AzureOpenAI.Settings;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
@ -19,6 +17,5 @@ public class AzureOpenAiPlugin : IBotSharpPlugin
services.AddSingleton<ITextCompletion, TextCompletionProvider>();
services.AddScoped<IChatCompletion, ChatCompletionProvider>();
services.AddScoped<IChatServiceZone, ChatService>();
}
}

View file

@ -1,9 +1,8 @@
using Azure;
using Azure.AI.OpenAI;
using BotSharp.Abstraction.Infrastructures.ContentTransfers;
using BotSharp.Abstraction.Infrastructures.ContentTransmitters;
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Conversations.Models;
using BotSharp.Abstraction.MLTasks;
using BotSharp.Abstraction.Models;
using BotSharp.Plugin.AzureOpenAI.Settings;
using System;
using System.Collections.Generic;
@ -21,7 +20,7 @@ public class ChatCompletionProvider : IChatCompletion
_settings = settings;
}
public async Task GetChatCompletionsAsync(List<RoleDialogModel> conversations,
/*public async Task GetChatCompletionsAsync(List<RoleDialogModel> conversations,
Func<string, Task> onChunkReceived)
{
var client = new OpenAIClient(new Uri(_settings.Endpoint), new AzureKeyCredential(_settings.ApiKey));
@ -44,14 +43,14 @@ public class ChatCompletionProvider : IChatCompletion
}
Console.WriteLine();
}
}*/
public List<RoleDialogModel> GetChatSamples()
public List<RoleDialogModel> GetChatSamples(string sampleText)
{
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++)
{
var line = lines[i];
@ -68,19 +67,11 @@ public class ChatCompletionProvider : IChatCompletion
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 chatCompletionsOptions = PrepareOptions(conversations);
var chatCompletionsOptions = PrepareOptions(agent, conversations);
var response = await client.GetChatCompletionsStreamingAsync(_settings.DeploymentModel.ChatCompletionModel, chatCompletionsOptions);
using StreamingChatCompletions streaming = response.Value;
@ -100,18 +91,17 @@ public class ChatCompletionProvider : IChatCompletion
return output;
}
private ChatCompletionsOptions PrepareOptions(List<RoleDialogModel> conversations)
private ChatCompletionsOptions PrepareOptions(Agent agent, List<RoleDialogModel> conversations)
{
var prompt = GetInstruction();
var chatCompletionsOptions = new ChatCompletionsOptions()
{
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));
}

View file

@ -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
};
}
}

View file

@ -13,8 +13,9 @@ using System;
using Azure.AI.OpenAI;
using BotSharp.Abstraction.ApiAdapters;
using BotSharp.Plugin.ChatbotUI.ViewModels;
using BotSharp.Abstraction.Infrastructures.ContentTransmitters;
using Microsoft.Extensions.DependencyInjection;
using BotSharp.Abstraction.Conversations;
using BotSharp.Abstraction.Conversations.Models;
namespace BotSharp.Plugin.ChatbotUI.Controllers;
@ -64,22 +65,11 @@ public class ChatbotUiController : ControllerBase, IApiAdapter
Text = x.Content
}).ToList();
/*await _chatCompletionProvider.GetChatCompletionsAsync(conversations,
async content =>
{
await OnChunkReceived(outputStream, content);
});*/
var conv = _services.GetRequiredService<IConversationService>();
var transmitter = _services.GetRequiredService<IContentTransfer>();
var result = await conv.SendMessage("", "", conversations.Last());
var container = new ContentContainer
{
Conversations = conversations
};
var result = await transmitter.Transport(container);
await OnChunkReceived(outputStream, container.Output.Text);
await OnChunkReceived(outputStream, result);
await OnEventCompleted(outputStream);
}

View file

@ -1,6 +1,3 @@
using BotSharp.Abstraction.Conversations;
using BotSharp.Abstraction.Infrastructures.ContentTransmitters;
using BotSharp.Abstraction.Models;
using Microsoft.Extensions.DependencyInjection;
using Senparc.NeuChar.App.AppStore;
using Senparc.NeuChar.Entities;

View file

@ -1,5 +1,5 @@
using BotSharp.Abstraction.Conversations;
using BotSharp.Abstraction.Infrastructures.ContentTransmitters;
using BotSharp.Abstraction.Conversations.Models;
using BotSharp.Abstraction.Models;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
@ -22,41 +22,23 @@ namespace BotSharp.Plugin.WeChat
ILogger<WeChatBackgroundService> logger)
{
this._service = service;
this._logger = logger;
this._queue = Channel.CreateUnbounded<WeChatMessage>();
_service = service;
_logger = logger;
_queue = Channel.CreateUnbounded<WeChatMessage>();
}
private async Task HandleTextMessageAsync(string openid, string message)
{
var scoped = _service.CreateScope().ServiceProvider;
var conversationService = scoped.GetRequiredService<IConversationService>();
var contentTransfer = scoped.GetRequiredService<IContentTransfer>();
var conversations = conversationService.GetDialogHistory(openid);
conversations.Add(new RoleDialogModel
var result = await conversationService.SendMessage(openid, Guid.Empty.ToString(), new RoleDialogModel
{
Role = "User",
Role = "user",
Text = message,
});
var container = new ContentContainer
{
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,
});
}
await ReplyTextMessageAsync(openid, result);
}
private async Task ReplyTextMessageAsync(string openid, string content)

View file

@ -1,2 +0,0 @@
user: Hi
assistant: Hello, I'm a AI assistant to help you schedule meeting.

View file

@ -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:

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
@ -8,25 +8,22 @@
</PropertyGroup>
<ItemGroup>
<Compile Remove="data\**" />
<Compile Remove="knowledge_chunks\**" />
<Compile Remove="Prompts\**" />
<Content Remove="data\**" />
<Content Remove="knowledge_chunks\**" />
<Content Remove="Prompts\**" />
<EmbeddedResource Remove="data\**" />
<EmbeddedResource Remove="knowledge_chunks\**" />
<EmbeddedResource Remove="Prompts\**" />
<None Remove="data\**" />
<None Remove="knowledge_chunks\**" />
<None Remove="Prompts\**" />
</ItemGroup>
<ItemGroup>
<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>

View file

@ -14,7 +14,7 @@
},
"Conversation": {
"ChatCompletion": "AzureOpenAI.Providers.ChatCompletionProvider"
},
"LlamaSharp": {
@ -48,7 +48,7 @@
"Master": "mongodb://localhost:27017/chat-ui"
},
"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": []
},
"UseCamelCase": true,
@ -70,7 +70,7 @@
"KnowledgeBase": {
"VectorDb": "MemVectorDatabase",
"TextEmbedding": "fastTextEmbeddingProvider",
"TextCompletion": "TextCompletionProvider"
"TextCompletion": "AzureOpenAI.Providers.TextCompletionProvider"
},
"PluginLoader": {