diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/Dtos/ConversationCreateDto.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/Dtos/ConversationCreateDto.cs new file mode 100644 index 000000000..8112305b2 --- /dev/null +++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/Dtos/ConversationCreateDto.cs @@ -0,0 +1,8 @@ +using Volo.Abp.Validation; + +namespace LINGYUN.Abp.AIManagement.Chats.Dtos; +public class ConversationCreateDto +{ + [DynamicStringLength(typeof(ConversationRecordConsts), nameof(ConversationRecordConsts.MaxNameLength))] + public string? Name { get; set; } +} diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/Dtos/ConversationDto.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/Dtos/ConversationDto.cs new file mode 100644 index 000000000..8f5945c95 --- /dev/null +++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/Dtos/ConversationDto.cs @@ -0,0 +1,14 @@ +using System; +using Volo.Abp.Application.Dtos; + +namespace LINGYUN.Abp.AIManagement.Chats.Dtos; +public class ConversationDto : AuditedEntityDto +{ + public string Name { get; set; } + + public DateTime CreatedAt { get; set; } + + public DateTime ExpiredAt { get; set; } + + public DateTime? UpdateAt { get; set; } +} diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/Dtos/ConversationGetListInput.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/Dtos/ConversationGetListInput.cs new file mode 100644 index 000000000..d3b889f48 --- /dev/null +++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/Dtos/ConversationGetListInput.cs @@ -0,0 +1,7 @@ +using Volo.Abp.Application.Dtos; + +namespace LINGYUN.Abp.AIManagement.Chats.Dtos; +public class ConversationGetListInput : PagedAndSortedResultRequestDto +{ + public string? Filter { get; set; } +} diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/Dtos/ConversationUpdateDto.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/Dtos/ConversationUpdateDto.cs new file mode 100644 index 000000000..4469eba6d --- /dev/null +++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/Dtos/ConversationUpdateDto.cs @@ -0,0 +1,10 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Validation; + +namespace LINGYUN.Abp.AIManagement.Chats.Dtos; +public class ConversationUpdateDto +{ + [Required] + [DynamicStringLength(typeof(ConversationRecordConsts), nameof(ConversationRecordConsts.MaxNameLength))] + public string Name { get; set; } +} diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/IConversationAppService.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/IConversationAppService.cs new file mode 100644 index 000000000..a59c397cb --- /dev/null +++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application.Contracts/LINGYUN/Abp/AIManagement/Chats/IConversationAppService.cs @@ -0,0 +1,14 @@ +using LINGYUN.Abp.AIManagement.Chats.Dtos; +using System; +using Volo.Abp.Application.Services; + +namespace LINGYUN.Abp.AIManagement.Chats; +public interface IConversationAppService : + ICrudAppService< + ConversationDto, + Guid, + ConversationGetListInput, + ConversationCreateDto, + ConversationUpdateDto> +{ +} diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application/LINGYUN/Abp/AIManagement/Chats/ConversationAppService.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application/LINGYUN/Abp/AIManagement/Chats/ConversationAppService.cs new file mode 100644 index 000000000..203747602 --- /dev/null +++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Application/LINGYUN/Abp/AIManagement/Chats/ConversationAppService.cs @@ -0,0 +1,82 @@ +using LINGYUN.Abp.AIManagement.Chats.Dtos; +using LINGYUN.Abp.AIManagement.Localization; +using Microsoft.Extensions.Options; +using System; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Application.Services; +using Volo.Abp.Domain.Repositories; + +namespace LINGYUN.Abp.AIManagement.Chats; +public class ConversationAppService : + CrudAppService< + ConversationRecord, + ConversationDto, + Guid, + ConversationGetListInput, + ConversationCreateDto, + ConversationUpdateDto>, + IConversationAppService +{ + private readonly ConversationCleanupOptions _cleanupOptions; + public ConversationAppService( + IRepository repository, + IOptions cleanupOptions) + : base(repository) + { + _cleanupOptions = cleanupOptions.Value; + + LocalizationResource = typeof(AIManagementResource); + ObjectMapperContext = typeof(AbpAIManagementApplicationModule); + } + + protected async override Task> CreateFilteredQueryAsync(ConversationGetListInput input) + { + var queryable = await base.CreateFilteredQueryAsync(input); + + return queryable + .WhereIf(!input.Filter.IsNullOrWhiteSpace(), x => x.Name.Contains(input.Filter!)); + } + + protected override ConversationRecord MapToEntity(ConversationCreateDto createInput) + { + var createdAt = Clock.Now; + var expiredTime = createdAt.Add(_cleanupOptions.ExpiredTime); + var conversationName = createInput.Name ?? L["NewConversation"]; + return new ConversationRecord( + GuidGenerator.Create(), + conversationName, + createdAt, + expiredTime, + CurrentTenant.Id); + } + + protected override void MapToEntity(ConversationUpdateDto updateInput, ConversationRecord entity) + { + if (!string.Equals(entity.Name, updateInput.Name, StringComparison.InvariantCultureIgnoreCase)) + { + entity.SetName(updateInput.Name); + } + } + + protected override ConversationDto MapToGetOutputDto(ConversationRecord entity) + { + return new ConversationDto + { + Id = entity.Id, + CreatedAt = entity.CreatedAt, + ExpiredAt = entity.ExpiredAt, + CreationTime = entity.CreationTime, + CreatorId = entity.CreatorId, + LastModificationTime = entity.LastModificationTime, + LastModifierId = entity.LastModifierId, + Name = entity.Name, + UpdateAt = entity.UpdateAt, + }; + } + + protected override ConversationDto MapToGetListOutputDto(ConversationRecord entity) + { + return MapToGetOutputDto(entity); + } +} diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Chats/ConversationRecord.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Chats/ConversationRecord.cs index cd81fcac6..10192ab8b 100644 --- a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Chats/ConversationRecord.cs +++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Chats/ConversationRecord.cs @@ -31,4 +31,9 @@ public class ConversationRecord : AuditedEntity, IMultiTenant TenantId = tenantId; } + + public void SetName(string name) + { + Name = Check.NotNullOrWhiteSpace(name, nameof(name), ConversationRecordConsts.MaxNameLength); + } } diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.HttpApi/LINGYUN/Abp/AIManagement/Chats/ConversationController.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.HttpApi/LINGYUN/Abp/AIManagement/Chats/ConversationController.cs new file mode 100644 index 000000000..e90aced0b --- /dev/null +++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.HttpApi/LINGYUN/Abp/AIManagement/Chats/ConversationController.cs @@ -0,0 +1,52 @@ +using LINGYUN.Abp.AIManagement.Chats.Dtos; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Application.Dtos; +using Volo.Abp.AspNetCore.Mvc; + +namespace LINGYUN.Abp.AIManagement.Chats; + +[Controller] +[RemoteService(Name = AIManagementRemoteServiceConsts.RemoteServiceName)] +[Area(AIManagementRemoteServiceConsts.ModuleName)] +[Route($"api/{AIManagementRemoteServiceConsts.ModuleName}/chats/conversations")] +public class ConversationController : AbpControllerBase, IConversationAppService +{ + private readonly IConversationAppService _service; + public ConversationController(IConversationAppService service) + { + _service = service; + } + + [HttpPost] + public virtual Task CreateAsync(ConversationCreateDto input) + { + return _service.CreateAsync(input); + } + + [HttpDelete("{id}")] + public virtual Task DeleteAsync(Guid id) + { + return _service.DeleteAsync(id); + } + + [HttpGet("{id}")] + public virtual Task GetAsync(Guid id) + { + return _service.GetAsync(id); + } + + [HttpGet] + public virtual Task> GetListAsync(ConversationGetListInput input) + { + return _service.GetListAsync(input); + } + + [HttpPut("{id}")] + public virtual Task UpdateAsync(Guid id, ConversationUpdateDto input) + { + return _service.UpdateAsync(id, input); + } +}