Merge pull request #93 from hchen2020/master
Adjust conversation history format.
This commit is contained in:
commit
4c3cb6bf8e
|
|
@ -8,7 +8,7 @@ public interface IConversationService
|
|||
Task<Conversation> GetConversation(string id);
|
||||
Task<List<Conversation>> GetConversations();
|
||||
Task DeleteConversation(string id);
|
||||
Task<bool> SendMessage(string agentId, string conversationId, RoleDialogModel lastDalog, Func<RoleDialogModel, Task> onMessageReceived);
|
||||
Task<bool> SendMessage(string agentId, string conversationId, RoleDialogModel lastDalog, Func<RoleDialogModel, Task> onMessageReceived, Func<RoleDialogModel, Task> onFunctionExecuting);
|
||||
Task<bool> SendMessage(string agentId, string conversationId, List<RoleDialogModel> wholeDialogs, Func<RoleDialogModel, Task> onMessageReceived);
|
||||
List<RoleDialogModel> GetDialogHistory(string agentId, string conversationId, int lastCount = 20);
|
||||
Task CleanHistory(string agentId);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ public class RoleDialogModel
|
|||
/// user, system, assistant, function
|
||||
/// </summary>
|
||||
public string Role { get; set; }
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
public string Content { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace BotSharp.Abstraction.Functions.Models;
|
||||
|
||||
public class FunctionExecutionResult<T> where T : new()
|
||||
{
|
||||
private readonly string _name;
|
||||
|
||||
public FunctionExecutionResult(string name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
[JsonPropertyName("function_name")]
|
||||
public string Name => _name;
|
||||
|
||||
[JsonPropertyName("execution_result")]
|
||||
public T Result { get; set; } = new T();
|
||||
}
|
||||
|
|
@ -19,5 +19,6 @@ public class FunctionExecutionValidationResult
|
|||
public string ValidationStatus { get; set; }
|
||||
|
||||
[JsonPropertyName("validation_message")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public string ValidationMessage { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,9 @@ public class ConversationController : ControllerBase, IApiAdapter
|
|||
await conv.SendMessage(agentId, conversationId, new RoleDialogModel("user", input.Text), async msg =>
|
||||
{
|
||||
response.Text += msg.Content;
|
||||
}, async fn =>
|
||||
{
|
||||
|
||||
});
|
||||
|
||||
return response;
|
||||
|
|
|
|||
|
|
@ -67,7 +67,9 @@ public class ConversationService : IConversationService
|
|||
return record.ToConversation();
|
||||
}
|
||||
|
||||
public async Task<bool> SendMessage(string agentId, string conversationId, RoleDialogModel lastDalog, Func<RoleDialogModel, Task> onMessageReceived)
|
||||
public async Task<bool> SendMessage(string agentId, string conversationId, RoleDialogModel lastDalog,
|
||||
Func<RoleDialogModel, Task> onMessageReceived,
|
||||
Func<RoleDialogModel, Task> onFunctionExecuting)
|
||||
{
|
||||
_storage.Append(agentId, conversationId, lastDalog);
|
||||
|
||||
|
|
@ -81,6 +83,8 @@ public class ConversationService : IConversationService
|
|||
var functions = _services.GetServices<IFunctionCallback>().Where(x => x.Name == msg.FunctionName);
|
||||
foreach (var fn in functions)
|
||||
{
|
||||
await onFunctionExecuting(msg);
|
||||
|
||||
msg.ExecutionResult = await fn.Execute(msg.Content);
|
||||
|
||||
var result = msg.ExecutionResult.Replace("\r", " ").Replace("\n", " ");
|
||||
|
|
|
|||
|
|
@ -14,20 +14,34 @@ public class ConversationStorage : IConversationStorage
|
|||
public void Append(string agentId, string conversationId, RoleDialogModel dialog)
|
||||
{
|
||||
var conversationFile = GetStorageFile(agentId, conversationId);
|
||||
File.AppendAllText(conversationFile, $"{dialog.Role}: {dialog.Content}\n");
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"{dialog.Role}|{dialog.CreatedAt}|{dialog.FunctionName}");
|
||||
sb.AppendLine($" - {dialog.Content}");
|
||||
var conversation = sb.ToString();
|
||||
File.AppendAllText(conversationFile, conversation);
|
||||
}
|
||||
|
||||
public List<RoleDialogModel> GetDialogs(string agentId, string conversationId)
|
||||
{
|
||||
var conversationFile = GetStorageFile(agentId, conversationId);
|
||||
var dialogs = File.ReadAllLines(conversationFile);
|
||||
return dialogs.Select(x =>
|
||||
|
||||
var results = new List<RoleDialogModel>();
|
||||
for (int i = 0; i < dialogs.Length; i += 2)
|
||||
{
|
||||
var pos = x.IndexOf(':');
|
||||
var role = x.Substring(0, pos);
|
||||
var text = x.Substring(pos + 1);
|
||||
return new RoleDialogModel(role, text);
|
||||
}).ToList();
|
||||
var meta = dialogs[i];
|
||||
var dialog = dialogs[i + 1];
|
||||
var role = meta.Split('|')[0];
|
||||
var createdAt = DateTime.Parse(meta.Split('|')[1]);
|
||||
var text = dialog.Substring(4);
|
||||
var funcName = meta.Split('|')[2];
|
||||
results.Add(new RoleDialogModel(role, text)
|
||||
{
|
||||
FunctionName = funcName,
|
||||
CreatedAt = createdAt
|
||||
});
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public void InitStorage(string agentId, string conversationId)
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@ using BotSharp.Abstraction.Conversations.Models;
|
|||
using BotSharp.Abstraction.Functions.Models;
|
||||
using BotSharp.Abstraction.MLTasks;
|
||||
using BotSharp.Plugin.AzureOpenAI.Settings;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
|
@ -15,10 +17,12 @@ namespace BotSharp.Plugin.AzureOpenAI.Providers;
|
|||
public class ChatCompletionProvider : IChatCompletion
|
||||
{
|
||||
private readonly AzureOpenAiSettings _settings;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public ChatCompletionProvider(AzureOpenAiSettings settings)
|
||||
public ChatCompletionProvider(AzureOpenAiSettings settings, ILogger<ChatCompletionProvider> logger)
|
||||
{
|
||||
_settings = settings;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public string GetChatCompletions(Agent agent, List<RoleDialogModel> conversations)
|
||||
|
|
@ -38,6 +42,8 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
output += message.Content;
|
||||
}
|
||||
|
||||
_logger.LogInformation(output);
|
||||
|
||||
return output.Trim();
|
||||
}
|
||||
|
||||
|
|
@ -113,9 +119,7 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
await onMessageReceived(funcContextIn);
|
||||
|
||||
// After function is executed, pass the result to LLM
|
||||
var fnResult = JsonSerializer.Deserialize<FunctionExecutionResult<object>>(funcContextIn.ExecutionResult);
|
||||
var fnJsonResult = JsonSerializer.Serialize(fnResult.Result);
|
||||
chatCompletionsOptions.Messages.Add(new ChatMessage(ChatRole.Function, fnJsonResult)
|
||||
chatCompletionsOptions.Messages.Add(new ChatMessage(ChatRole.Function, funcContextIn.ExecutionResult)
|
||||
{
|
||||
Name = funcContextIn.FunctionName
|
||||
});
|
||||
|
|
@ -124,6 +128,9 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
|
||||
choice = response.Value.Choices[0];
|
||||
message = choice.Message;
|
||||
|
||||
_logger.LogInformation(message.Content);
|
||||
|
||||
await onMessageReceived(new RoleDialogModel(ChatRole.Assistant.ToString(), message.Content));
|
||||
|
||||
return true;
|
||||
|
|
@ -161,6 +168,9 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
continue;
|
||||
Console.Write(message.Content);
|
||||
output += message.Content;
|
||||
|
||||
_logger.LogInformation(message.Content);
|
||||
|
||||
await onMessageReceived(new RoleDialogModel(message.Role.ToString(), message.Content));
|
||||
}
|
||||
|
||||
|
|
@ -205,10 +215,9 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
{
|
||||
if (message.Role == ChatRole.Function)
|
||||
{
|
||||
var funcContext = JsonSerializer.Deserialize<FunctionExecutionResult<object>>(message.Content);
|
||||
chatCompletionsOptions.Messages.Add(new ChatMessage(message.Role, message.Content)
|
||||
{
|
||||
Name = funcContext.Name
|
||||
Name = message.FunctionName
|
||||
});
|
||||
}
|
||||
else
|
||||
|
|
@ -217,6 +226,7 @@ public class ChatCompletionProvider : IChatCompletion
|
|||
}
|
||||
}
|
||||
|
||||
_logger.LogInformation(string.Join("\n", chatCompletionsOptions.Messages.Select(x => $"{x.Role}: {x.Content}")));
|
||||
return chatCompletionsOptions;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ using System.Text;
|
|||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Refit;
|
||||
|
||||
namespace BotSharp.Plugin.MetaMessenger.Controllers;
|
||||
|
||||
|
|
@ -58,7 +59,6 @@ public class WebhookController : ControllerBase
|
|||
|
||||
// TODO validate request
|
||||
// https://developers.facebook.com/docs/messenger-platform/webhooks#verification-requests
|
||||
|
||||
try
|
||||
{
|
||||
// received message
|
||||
|
|
@ -69,10 +69,6 @@ public class WebhookController : ControllerBase
|
|||
string content = "";
|
||||
var sessionId = req.Entry[0].Messaging[0].Sender.Id;
|
||||
var input = req.Entry[0].Messaging[0].Message.Text;
|
||||
var result = await conv.SendMessage(agentId, sessionId, new RoleDialogModel("user", input), async msg =>
|
||||
{
|
||||
content = msg.Content;
|
||||
});
|
||||
|
||||
var setting = _services.GetRequiredService<MetaMessengerSetting>();
|
||||
var messenger = _services.GetRequiredService<IMessengerGraphAPI>();
|
||||
|
|
@ -80,14 +76,65 @@ public class WebhookController : ControllerBase
|
|||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
};
|
||||
|
||||
// Marking seen
|
||||
/*await messenger.SendMessage(setting.ApiVersion, setting.PageId, new SendingMessageRequest
|
||||
{
|
||||
AccessToken = setting.PageAccessToken,
|
||||
Recipient = JsonSerializer.Serialize(new { Id = sessionId }, jsonOpt),
|
||||
SenderAction = SenderActionEnum.MarkSeen
|
||||
});*/
|
||||
|
||||
// Typing on
|
||||
await messenger.SendMessage(setting.ApiVersion, setting.PageId, new SendingMessageRequest
|
||||
{
|
||||
AccessToken = setting.PageAccessToken,
|
||||
Recipient = JsonSerializer.Serialize(new { Id = sessionId }, jsonOpt),
|
||||
SenderAction = SenderActionEnum.TypingOn
|
||||
});
|
||||
|
||||
// Go to LLM
|
||||
var result = await conv.SendMessage(agentId, sessionId, new RoleDialogModel("user", input), async msg =>
|
||||
{
|
||||
content = msg.Content;
|
||||
}, async fn =>
|
||||
{
|
||||
await messenger.SendMessage(setting.ApiVersion, setting.PageId, new SendingMessageRequest
|
||||
{
|
||||
AccessToken = setting.PageAccessToken,
|
||||
Recipient = JsonSerializer.Serialize(new { Id = sessionId }, jsonOpt),
|
||||
Message = JsonSerializer.Serialize(new { Text = "I'm pulling the relevent information, please wait a second ..." }, jsonOpt)
|
||||
});
|
||||
|
||||
await messenger.SendMessage(setting.ApiVersion, setting.PageId, new SendingMessageRequest
|
||||
{
|
||||
AccessToken = setting.PageAccessToken,
|
||||
Recipient = JsonSerializer.Serialize(new { Id = sessionId }, jsonOpt),
|
||||
SenderAction = SenderActionEnum.TypingOn
|
||||
});
|
||||
});
|
||||
|
||||
// Response to user
|
||||
await messenger.SendMessage(setting.ApiVersion, setting.PageId, new SendingMessageRequest
|
||||
{
|
||||
AccessToken = setting.PageAccessToken,
|
||||
Recipient = JsonSerializer.Serialize(new { Id = sessionId }, jsonOpt),
|
||||
Message = JsonSerializer.Serialize(new { Text = content }, jsonOpt)
|
||||
});
|
||||
|
||||
// Typing off
|
||||
await messenger.SendMessage(setting.ApiVersion, setting.PageId, new SendingMessageRequest
|
||||
{
|
||||
AccessToken = setting.PageAccessToken,
|
||||
Recipient = JsonSerializer.Serialize(new { Id = sessionId }, jsonOpt),
|
||||
SenderAction = SenderActionEnum.TypingOff
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (ApiException ex)
|
||||
{
|
||||
Console.WriteLine(ex.Content);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.ToString());
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
using System.Runtime.Serialization;
|
||||
|
||||
namespace BotSharp.Plugin.MetaMessenger.MessagingModels;
|
||||
|
||||
public enum SenderActionEnum
|
||||
{
|
||||
[EnumMember(Value = "typing_on")]
|
||||
TypingOn,
|
||||
[EnumMember(Value = "typing_off")]
|
||||
TypingOff,
|
||||
[EnumMember(Value = "mark_seen")]
|
||||
MarkSeen
|
||||
}
|
||||
|
|
@ -24,4 +24,7 @@ public class SendingMessageRequest
|
|||
|
||||
[AliasAs("messaging_type")]
|
||||
public string MessagingType { get; set; } = "RESPONSE";
|
||||
|
||||
[AliasAs("sender_action")]
|
||||
public SenderActionEnum? SenderAction { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,9 @@ namespace BotSharp.Plugin.WeChat
|
|||
var result = await conversationService.SendMessage(AgentId, latestConversationId, new RoleDialogModel("user", message), async msg =>
|
||||
{
|
||||
await ReplyTextMessageAsync(openid, msg.Content);
|
||||
}, async fn =>
|
||||
{
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue