add ConversationTimeoutService
This commit is contained in:
parent
f12f6c63c3
commit
e467a7bd01
|
|
@ -8,6 +8,7 @@ public interface IConversationService
|
|||
void SetConversationId(string conversationId, List<string> states);
|
||||
Task<Conversation> GetConversation(string id);
|
||||
Task<List<Conversation>> GetConversations();
|
||||
Task<List<Conversation>> GetLastConversations();
|
||||
Task DeleteConversation(string id);
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ public interface IBotSharpRepository
|
|||
void UpdateConversationStates(string conversationId, List<StateKeyValue> states);
|
||||
Conversation GetConversation(string conversationId);
|
||||
List<Conversation> GetConversations(string userId);
|
||||
List<Conversation> GetLastConversations();
|
||||
void AddExectionLogs(string conversationId, List<string> logs);
|
||||
List<string> GetExectionLogs(string conversationId);
|
||||
#endregion
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@
|
|||
<PackageReference Include="Colorful.Console" Version="1.2.15" />
|
||||
<PackageReference Include="EntityFrameworkCore.BootKit" Version="6.2.1" />
|
||||
<PackageReference Include="Fluid.Core" Version="2.5.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -51,6 +51,12 @@ public partial class ConversationService : IConversationService
|
|||
return conversations.OrderByDescending(x => x.CreatedTime).ToList();
|
||||
}
|
||||
|
||||
public async Task<List<Conversation>> GetLastConversations()
|
||||
{
|
||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||
return db.GetLastConversations();
|
||||
}
|
||||
|
||||
public async Task<Conversation> NewConversation(Conversation sess)
|
||||
{
|
||||
var db = _services.GetRequiredService<IBotSharpRepository>();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
using Microsoft.Extensions.Hosting;
|
||||
using System.Threading;
|
||||
|
||||
namespace BotSharp.Core.Infrastructures
|
||||
{
|
||||
public class ConversationTimeoutService : BackgroundService
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly ILogger<ConversationTimeoutService> _logger;
|
||||
|
||||
public ConversationTimeoutService(IServiceProvider services, ILogger<ConversationTimeoutService> logger)
|
||||
{
|
||||
_services = services;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
_logger.LogInformation("Conversation Timeout Service is running.");
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
stoppingToken.ThrowIfCancellationRequested();
|
||||
var delay = Task.Delay(TimeSpan.FromMinutes(1));
|
||||
try
|
||||
{
|
||||
await CloseIdleConversationsAsync(TimeSpan.FromMinutes(10));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"Error occurred closing conversations.");
|
||||
}
|
||||
await delay;
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
}
|
||||
|
||||
public override async Task StopAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
_logger.LogInformation("Conversation Timeout Service is stopping.");
|
||||
await base.StopAsync(stoppingToken);
|
||||
}
|
||||
|
||||
private async Task CloseIdleConversationsAsync(TimeSpan conversationIdleTimeout)
|
||||
{
|
||||
using var scope = _services.CreateScope();
|
||||
var conversationService = scope.ServiceProvider.GetRequiredService<IConversationService>();
|
||||
var hooks = scope.ServiceProvider.GetServices<IConversationHook>()
|
||||
.OrderBy(x => x.Priority)
|
||||
.ToList();
|
||||
var moment = DateTime.UtcNow.Add(-conversationIdleTimeout);
|
||||
var conversations =
|
||||
(await conversationService.GetLastConversations())
|
||||
.Where(c => c.CreatedTime <= moment);
|
||||
foreach (var conversation in conversations)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = new RoleDialogModel(AgentRole.Assistant, "End the conversation due to timeout.")
|
||||
{
|
||||
StopCompletion = true,
|
||||
FunctionName = "conversation_end"
|
||||
};
|
||||
|
||||
foreach (var hook in hooks)
|
||||
{
|
||||
await hook.OnConversationEnding(response);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"Error occurred closing conversation #{conversation.Id}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -131,6 +131,11 @@ public class BotSharpDbContext : Database, IBotSharpRepository
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public List<Conversation> GetLastConversations()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public string GetConversationDialog(string conversationId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
|
|
|||
|
|
@ -735,6 +735,28 @@ public class FileRepository : IBotSharpRepository
|
|||
return records;
|
||||
}
|
||||
|
||||
public List<Conversation> GetLastConversations()
|
||||
{
|
||||
var records = new List<Conversation>();
|
||||
var dir = Path.Combine(_dbSettings.FileRepository, _conversationSettings.DataDir);
|
||||
|
||||
foreach (var d in Directory.GetDirectories(dir))
|
||||
{
|
||||
var path = Path.Combine(d, "conversation.json");
|
||||
if (!File.Exists(path)) continue;
|
||||
|
||||
var json = File.ReadAllText(path);
|
||||
var record = JsonSerializer.Deserialize<Conversation>(json, _options);
|
||||
if (record != null)
|
||||
{
|
||||
records.Add(record);
|
||||
}
|
||||
}
|
||||
return records.GroupBy(r => r.UserId)
|
||||
.Select(g => g.OrderByDescending(x => x.CreatedTime).First())
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public void AddExectionLogs(string conversationId, List<string> logs)
|
||||
{
|
||||
if (string.IsNullOrEmpty(conversationId) || logs.IsNullOrEmpty()) return;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ namespace BotSharp.Core.Users.Services;
|
|||
public class UserIdentity : IUserIdentity
|
||||
{
|
||||
private readonly IHttpContextAccessor _contextAccessor;
|
||||
private IEnumerable<Claim> _claims => _contextAccessor.HttpContext.User.Claims;
|
||||
private IEnumerable<Claim> _claims => _contextAccessor.HttpContext?.User.Claims!;
|
||||
|
||||
public UserIdentity(IHttpContextAccessor contextAccessor)
|
||||
{
|
||||
|
|
@ -15,14 +15,14 @@ public class UserIdentity : IUserIdentity
|
|||
|
||||
|
||||
public string Id
|
||||
=> _claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier)?.Value;
|
||||
=> _claims?.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier)?.Value!;
|
||||
|
||||
public string Email
|
||||
=> _claims.FirstOrDefault(x => x.Type == ClaimTypes.Email)?.Value;
|
||||
=> _claims?.FirstOrDefault(x => x.Type == ClaimTypes.Email)?.Value!;
|
||||
|
||||
public string FirstName
|
||||
=> _claims.FirstOrDefault(x => x.Type == ClaimTypes.GivenName)?.Value;
|
||||
=> _claims?.FirstOrDefault(x => x.Type == ClaimTypes.GivenName)?.Value!;
|
||||
|
||||
public string LastName
|
||||
=> _claims.FirstOrDefault(x => x.Type == ClaimTypes.Surname)?.Value;
|
||||
=> _claims?.FirstOrDefault(x => x.Type == ClaimTypes.Surname)?.Value!;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -727,6 +727,24 @@ public class MongoRepository : IBotSharpRepository
|
|||
return records;
|
||||
}
|
||||
|
||||
public List<Conversation> GetLastConversations()
|
||||
{
|
||||
var records = new List<Conversation>();
|
||||
var conversations = _dc.Conversations.Aggregate()
|
||||
.Group(c => c.UserId,
|
||||
g => g.OrderByDescending(x => x.CreatedTime).First())
|
||||
.ToList();
|
||||
return conversations.Select(c => new Conversation()
|
||||
{
|
||||
Id = c.Id.ToString(),
|
||||
AgentId = c.AgentId.ToString(),
|
||||
UserId = c.UserId.ToString(),
|
||||
Title = c.Title,
|
||||
CreatedTime = c.CreatedTime,
|
||||
UpdatedTime = c.UpdatedTime
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
public void AddExectionLogs(string conversationId, List<string> logs)
|
||||
{
|
||||
if (string.IsNullOrEmpty(conversationId) || logs.IsNullOrEmpty()) return;
|
||||
|
|
|
|||
Loading…
Reference in a new issue