This commit is contained in:
Jicheng Lu 2024-10-18 15:50:39 -05:00
parent cc6074fdfb
commit d84c8995d1
13 changed files with 82 additions and 11 deletions

View file

@ -12,6 +12,7 @@ public interface IConversationService
Task<Conversation> GetConversation(string id);
Task<PagedItems<Conversation>> GetConversations(ConversationFilter filter);
Task<Conversation> UpdateConversationTitle(string id, string title);
Task<bool> UpdateConversationTags(string conversationId, List<string> tags);
Task<bool> UpdateConversationMessage(string conversationId, UpdateMessageRequest request);
Task<List<Conversation>> GetLastConversations();
Task<List<string>> GetIdleConversations(int batchSize, int messageLimit, int bufferHours, IEnumerable<string> excludeAgentIds);

View file

@ -15,10 +15,10 @@ public class Conversation
public string Title { get; set; } = string.Empty;
[JsonIgnore]
public List<DialogElement> Dialogs { get; set; } = new List<DialogElement>();
public List<DialogElement> Dialogs { get; set; } = new();
[JsonIgnore]
public Dictionary<string, string> States { get; set; } = new Dictionary<string, string>();
public Dictionary<string, string> States { get; set; } = new();
public string Status { get; set; } = ConversationStatus.Open;
@ -26,6 +26,8 @@ public class Conversation
public int DialogCount { get; set; }
public List<string> Tags { get; set; } = new();
public DateTime UpdatedTime { get; set; } = DateTime.UtcNow;
public DateTime CreatedTime { get; set; } = DateTime.UtcNow;
}

View file

@ -22,5 +22,7 @@ public class ConversationFilter
/// <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 IEnumerable<KeyValue>? States { get; set; } = [];
public IEnumerable<string>? Tags { get; set; } = [];
}

View file

@ -72,6 +72,7 @@ public interface IBotSharpRepository
Conversation GetConversation(string conversationId);
PagedItems<Conversation> GetConversations(ConversationFilter filter);
void UpdateConversationTitle(string conversationId, string title);
bool UpdateConversationTags(string conversationId, List<string> tags);
bool UpdateConversationMessage(string conversationId, UpdateMessageRequest request);
void UpdateConversationBreakpoint(string conversationId, ConversationBreakpoint breakpoint);
ConversationBreakpoint? GetConversationBreakpoint(string conversationId);

View file

@ -51,6 +51,12 @@ public partial class ConversationService : IConversationService
return conversation;
}
public async Task<bool> UpdateConversationTags(string conversationId, List<string> tags)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
return db.UpdateConversationTags(conversationId, tags);
}
public async Task<bool> UpdateConversationMessage(string conversationId, UpdateMessageRequest request)
{
var db = _services.GetRequiredService<IBotSharpRepository>();

View file

@ -161,6 +161,9 @@ public class BotSharpDbContext : Database, IBotSharpRepository
public void UpdateConversationTitle(string conversationId, string title)
=> throw new NotImplementedException();
public bool UpdateConversationTags(string conversationId, List<string> tags)
=> throw new NotImplementedException();
public bool UpdateConversationMessage(string conversationId, UpdateMessageRequest request)
=> throw new NotImplementedException();

View file

@ -1,8 +1,5 @@
using BotSharp.Abstraction.Loggers.Models;
using BotSharp.Abstraction.Repositories.Models;
using System.Globalization;
using System.IO;
using System.Xml.Linq;
namespace BotSharp.Core.Repository
{
@ -13,6 +10,7 @@ namespace BotSharp.Core.Repository
var utcNow = DateTime.UtcNow;
conversation.CreatedTime = utcNow;
conversation.UpdatedTime = utcNow;
conversation.Tags = conversation.Tags ?? new();
var dir = Path.Combine(_dbSettings.FileRepository, _conversationSettings.DataDir, conversation.Id);
if (!Directory.Exists(dir))
@ -134,6 +132,24 @@ namespace BotSharp.Core.Repository
}
}
public bool UpdateConversationTags(string conversationId, List<string> tags)
{
if (string.IsNullOrEmpty(conversationId)) return false;
var convDir = FindConversationDirectory(conversationId);
if (string.IsNullOrEmpty(convDir)) return false;
var convFile = Path.Combine(convDir, CONVERSATION_FILE);
if (!File.Exists(convFile)) return false;
var json = File.ReadAllText(convFile);
var conv = JsonSerializer.Deserialize<Conversation>(json, _options);
conv.Tags = tags ?? new();
conv.UpdatedTime = DateTime.UtcNow;
File.WriteAllText(convFile, JsonSerializer.Serialize(conv, _options));
return true;
}
public bool UpdateConversationMessage(string conversationId, UpdateMessageRequest request)
{
if (string.IsNullOrEmpty(conversationId)) return false;
@ -354,6 +370,10 @@ namespace BotSharp.Core.Repository
{
matched = matched && record.CreatedTime >= filter.StartTime.Value;
}
if (filter?.Tags != null && filter.Tags.Any())
{
matched = matched && !record.Tags.IsNullOrEmpty() && record.Tags.Exists(t => filter.Tags.Contains(t));
}
// Check states
if (filter != null && !filter.States.IsNullOrEmpty())

View file

@ -202,7 +202,7 @@ public class ConversationController : ControllerBase
public async Task<bool> UpdateConversationTitle([FromRoute] string conversationId, [FromBody] UpdateConversationTitleModel newTile)
{
var userService = _services.GetRequiredService<IUserService>();
var conversationService = _services.GetRequiredService<IConversationService>();
var conv = _services.GetRequiredService<IConversationService>();
var user = await userService.GetUser(_user.Id);
var filter = new ConversationFilter
@ -210,17 +210,24 @@ public class ConversationController : ControllerBase
Id = conversationId,
UserId = user.Role != UserRole.Admin ? user.Id : null
};
var conversations = await conversationService.GetConversations(filter);
var conversations = await conv.GetConversations(filter);
if (conversations.Items.IsNullOrEmpty())
{
return false;
}
var response = await conversationService.UpdateConversationTitle(conversationId, newTile.NewTitle);
var response = await conv.UpdateConversationTitle(conversationId, newTile.NewTitle);
return response != null;
}
[HttpPut("/conversation/{conversationId}/update-tags")]
public async Task<bool> UpdateConversationTags([FromRoute] string conversationId, [FromBody] UpdateConversationRequest request)
{
var conv = _services.GetRequiredService<IConversationService>();
return await conv.UpdateConversationTags(conversationId, request.Tags);
}
[HttpPut("/conversation/{conversationId}/update-message")]
public async Task<bool> UpdateConversationMessage([FromRoute] string conversationId, [FromBody] UpdateMessageModel model)
{

View file

@ -29,6 +29,8 @@ public class ConversationViewModel
public string Status { get; set; }
public Dictionary<string, string> States { get; set; }
public List<string> Tags { get; set; } = new();
[JsonPropertyName("updated_time")]
public DateTime UpdatedTime { get; set; } = DateTime.UtcNow;
[JsonPropertyName("created_time")]
@ -48,6 +50,7 @@ public class ConversationViewModel
Channel = sess.Channel,
Status = sess.Status,
TaskId = sess.TaskId,
Tags = sess.Tags ?? new(),
CreatedTime = sess.CreatedTime,
UpdatedTime = sess.UpdatedTime
};

View file

@ -0,0 +1,6 @@
namespace BotSharp.OpenAPI.ViewModels.Conversations;
public class UpdateConversationRequest
{
public List<string> Tags { get; set; } = [];
}

View file

@ -9,6 +9,7 @@ public class ConversationDocument : MongoBase
public string Channel { get; set; }
public string Status { get; set; }
public int DialogCount { get; set; }
public List<string> Tags { get; set; }
public DateTime CreatedTime { get; set; }
public DateTime UpdatedTime { get; set; }
}

View file

@ -6,5 +6,3 @@ public abstract class MongoBase
[BsonId(IdGenerator = typeof(StringGuidIdGenerator))]
public string Id { get; set; }
}

View file

@ -19,6 +19,7 @@ public partial class MongoRepository
Channel = conversation.Channel,
TaskId = conversation.TaskId,
Status = conversation.Status,
Tags = conversation.Tags ?? new(),
CreatedTime = utcNow,
UpdatedTime = utcNow
};
@ -108,6 +109,19 @@ public partial class MongoRepository
_dc.Conversations.UpdateOne(filterConv, updateConv);
}
public bool UpdateConversationTags(string conversationId, List<string> tags)
{
if (string.IsNullOrEmpty(conversationId)) return false;
var filter = Builders<ConversationDocument>.Filter.Eq(x => x.Id, conversationId);
var update = Builders<ConversationDocument>.Update
.Set(x => x.Tags, tags ?? new())
.Set(x => x.UpdatedTime, DateTime.UtcNow);
var res = _dc.Conversations.UpdateOne(filter, update);
return res.ModifiedCount > 0;
}
public bool UpdateConversationMessage(string conversationId, UpdateMessageRequest request)
{
if (string.IsNullOrEmpty(conversationId)) return false;
@ -254,6 +268,7 @@ public partial class MongoRepository
Dialogs = dialogElements,
States = curStates,
DialogCount = conv.DialogCount,
Tags = conv.Tags,
CreatedTime = conv.CreatedTime,
UpdatedTime = conv.UpdatedTime
};
@ -297,6 +312,10 @@ public partial class MongoRepository
{
convFilters.Add(convBuilder.Gte(x => x.CreatedTime, filter.StartTime.Value));
}
if (filter?.Tags != null && filter.Tags.Any())
{
convFilters.Add(convBuilder.AnyIn(x => x.Tags, filter.Tags));
}
// Filter states
var stateFilters = new List<FilterDefinition<ConversationStateDocument>>();
@ -349,6 +368,7 @@ public partial class MongoRepository
Channel = x.Channel,
Status = x.Status,
DialogCount = x.DialogCount,
Tags = x.Tags ?? new(),
CreatedTime = x.CreatedTime,
UpdatedTime = x.UpdatedTime
}).ToList();
@ -375,6 +395,7 @@ public partial class MongoRepository
Channel = c.Channel,
Status = c.Status,
DialogCount = c.DialogCount,
Tags = c.Tags ?? new(),
CreatedTime = c.CreatedTime,
UpdatedTime = c.UpdatedTime
}).ToList();