add conv state filter

This commit is contained in:
Jicheng Lu 2024-03-08 16:02:08 -06:00
parent 538461db50
commit 0d91a2b558
5 changed files with 90 additions and 15 deletions

View file

@ -16,4 +16,15 @@ public class ConversationFilter
/// Agent task id
/// </summary>
public string? TaskId { get; set; }
/// <summary>
/// Check whether each key in the list is in the conversation states and its value equals to target value if not empty
/// </summary>
public IEnumerable<KeyValue> States { get; set; } = new List<KeyValue>();
}
public class KeyValue
{
public string Key { get; set; }
public string? Value { get; set; }
}

View file

@ -103,11 +103,23 @@ namespace BotSharp.Core.Repository
var convDir = FindConversationDirectory(conversationId);
if (!string.IsNullOrEmpty(convDir))
{
var dialogDir = Path.Combine(convDir, DIALOG_FILE);
if (File.Exists(dialogDir))
var dialogFile = Path.Combine(convDir, DIALOG_FILE);
if (File.Exists(dialogFile))
{
var texts = ParseDialogElements(dialogs);
File.AppendAllLines(dialogDir, texts);
File.AppendAllLines(dialogFile, texts);
}
var convFile = Path.Combine(convDir, CONVERSATION_FILE);
if (File.Exists(convFile))
{
var json = File.ReadAllText(convFile);
var conv = JsonSerializer.Deserialize<Conversation>(json, _options);
if (conv != null)
{
conv.UpdatedTime = DateTime.UtcNow;
File.WriteAllText(convFile, JsonSerializer.Serialize(conv, _options));
}
}
}
}
@ -219,10 +231,10 @@ namespace BotSharp.Core.Repository
var totalDirs = Directory.GetDirectories(dir);
foreach (var d in totalDirs)
{
var path = Path.Combine(d, CONVERSATION_FILE);
if (!File.Exists(path)) continue;
var convFile = Path.Combine(d, CONVERSATION_FILE);
if (!File.Exists(convFile)) continue;
var json = File.ReadAllText(path);
var json = File.ReadAllText(convFile);
var record = JsonSerializer.Deserialize<Conversation>(json, _options);
if (record == null) continue;
@ -234,6 +246,30 @@ namespace BotSharp.Core.Repository
if (filter?.UserId != null) matched = matched && record.UserId == filter.UserId;
if (filter?.TaskId != null) matched = matched && record.TaskId == filter.TaskId;
// Check states
if (filter != null && !filter.States.IsNullOrEmpty())
{
var stateFile = Path.Combine(d, STATE_FILE);
var convStates = CollectConversationStates(stateFile);
foreach (var pair in filter.States)
{
if (pair == null || string.IsNullOrWhiteSpace(pair.Key)) continue;
var foundState = convStates.FirstOrDefault(x => x.Key.IsEqualTo(pair.Key));
if (foundState == null)
{
matched = false;
break;
}
if (!string.IsNullOrWhiteSpace(pair.Value))
{
var curValue = foundState.Values.LastOrDefault()?.Data;
matched = matched && pair.Value.IsEqualTo(curValue);
}
}
}
if (!matched) continue;
records.Add(record);
}
@ -288,7 +324,7 @@ namespace BotSharp.Core.Repository
var json = File.ReadAllText(convFile);
var conv = JsonSerializer.Deserialize<Conversation>(json, _options);
if (conv == null || conv.CreatedTime > utcNow.AddHours(-bufferHours))
if (conv == null || conv.UpdatedTime > utcNow.AddHours(-bufferHours))
{
continue;
}

View file

@ -24,9 +24,8 @@ namespace BotSharp.OpenAPI.BackgroundServices
var delay = Task.Delay(TimeSpan.FromHours(1));
try
{
await CloseIdleConversationsAsync(TimeSpan.FromMinutes(10));
await CleanIdleConversationsAsync();
await CloseIdleConversationsAsync(TimeSpan.FromMinutes(10));
}
catch (Exception ex)
{

View file

@ -33,8 +33,8 @@ public class ConversationController : ControllerBase
return ConversationViewModel.FromSession(conv);
}
[HttpGet("/conversations")]
public async Task<PagedItems<ConversationViewModel>> GetConversations([FromQuery] ConversationFilter filter)
[HttpPost("/conversations")]
public async Task<PagedItems<ConversationViewModel>> GetConversations([FromBody] ConversationFilter filter)
{
var service = _services.GetRequiredService<IConversationService>();
var conversations = await service.GetConversations(filter);

View file

@ -3,6 +3,7 @@ using BotSharp.Abstraction.Repositories.Filters;
using BotSharp.Abstraction.Repositories.Models;
using BotSharp.Plugin.MongoStorage.Collections;
using BotSharp.Plugin.MongoStorage.Models;
using System.Text.RegularExpressions;
namespace BotSharp.Plugin.MongoStorage.Repository;
@ -224,6 +225,35 @@ public partial class MongoRepository
if (!string.IsNullOrEmpty(filter.UserId)) filters.Add(builder.Eq(x => x.UserId, filter.UserId));
if (!string.IsNullOrEmpty(filter.TaskId)) filters.Add(builder.Eq(x => x.TaskId, filter.TaskId));
// Check states
if (!filter.States.IsNullOrEmpty())
{
var targetConvIds = new List<string>();
foreach (var pair in filter.States)
{
if (pair == null || string.IsNullOrWhiteSpace(pair.Key)) continue;
var query = _dc.ConversationStates.AsQueryable();
var convIds = query.AsEnumerable().Where(x =>
{
var foundState = x.States.FirstOrDefault(s => s.Key.IsEqualTo(pair.Key));
if (foundState == null) return false;
if (!string.IsNullOrWhiteSpace(pair.Value))
{
return pair.Value.IsEqualTo(foundState.Values.LastOrDefault()?.Data);
}
return true;
}).Select(x => x.ConversationId).ToList();
targetConvIds = targetConvIds.Concat(convIds).Distinct().ToList();
}
filters.Add(builder.In(x => x.Id, targetConvIds));
}
var filterDef = builder.And(filters);
var sortDef = Builders<ConversationDocument>.Sort.Descending(x => x.CreatedTime);
var pager = filter?.Pager ?? new Pagination();
@ -258,7 +288,7 @@ public partial class MongoRepository
{
var records = new List<Conversation>();
var conversations = _dc.Conversations.Aggregate()
.Group(c => c.UserId, g => g.OrderByDescending(x => x.CreatedTime).First())
.Group(c => c.UserId, g => g.First(x => x.CreatedTime == g.Select(y => y.CreatedTime).Max()))
.ToList();
return conversations.Select(c => new Conversation()
{
@ -276,7 +306,6 @@ public partial class MongoRepository
public List<string> GetIdleConversations(int batchSize, int messageLimit, int bufferHours)
{
var page = 1;
var pageLimit = 10;
var batchLimit = 50;
var utcNow = DateTime.UtcNow;
var conversationIds = new List<string>();
@ -286,11 +315,11 @@ public partial class MongoRepository
batchSize = batchLimit;
}
while (true && page < pageLimit)
while (true)
{
var skip = (page - 1) * batchSize;
var candidates = _dc.Conversations.AsQueryable()
.Where(x => x.CreatedTime <= utcNow.AddHours(-bufferHours))
.Where(x => x.UpdatedTime <= utcNow.AddHours(-bufferHours))
.Skip(skip)
.Take(batchSize)
.Select(x => x.Id)