feature: add generatePersonalWishlistName method, Api endpoint and tests

This commit is contained in:
cuqmbr 2023-10-23 22:44:42 +03:00
parent b1e878386e
commit b63d3e39c3
Signed by: cuqmbr
GPG Key ID: 2D72ED98B6CB200F
6 changed files with 118 additions and 2 deletions

View File

@ -11,6 +11,10 @@ public class WishlistsMutation
[Service] IWishlistsService wishlistsService)
=> wishlistsService.StartPersonalWishlistAsync(dto, cancellationToken);
public Task<WishlistDto> GenerateNameForPersonalWishlistAsync(string wishlistId, CancellationToken cancellationToken,
[Service] IWishlistsService wishlistsService)
=> wishlistsService.GenerateNameForPersonalWishlistAsync(wishlistId, cancellationToken);
public Task<MessageDto> AddMessageToPersonalWishlistAsync(string wishlistId, MessageCreateDto dto, CancellationToken cancellationToken,
[Service] IWishlistsService wishlistsService)
=> wishlistsService.AddMessageToPersonalWishlistAsync(wishlistId, dto, cancellationToken);

View File

@ -1,9 +1,12 @@
using System.Linq.Expressions;
using MongoDB.Bson;
using ShoppingAssistantApi.Domain.Entities;
namespace ShoppingAssistantApi.Application.IRepositories;
public interface IWishlistsRepository : IBaseRepository<Wishlist>
{
public Task<Wishlist> GetWishlistAsync(Expression<Func<Wishlist, bool>> predicate, CancellationToken cancellationToken);
Task<Wishlist> GetWishlistAsync(Expression<Func<Wishlist, bool>> predicate, CancellationToken cancellationToken);
Task<Wishlist> UpdateWishlistNameAsync(ObjectId id, string name, CancellationToken cancellationToken);
}

View File

@ -8,6 +8,8 @@ public interface IWishlistsService
{
Task<WishlistDto> StartPersonalWishlistAsync(WishlistCreateDto dto, CancellationToken cancellationToken);
Task<WishlistDto> GenerateNameForPersonalWishlistAsync(string wishlistId, CancellationToken cancellationToken);
Task<MessageDto> AddMessageToPersonalWishlistAsync(string wishlistId, MessageCreateDto dto, CancellationToken cancellationToken);
Task<PagedList<WishlistDto>> GetPersonalWishlistsPageAsync(int pageNumber, int pageSize, CancellationToken cancellationToken);

View File

@ -6,6 +6,7 @@ using ShoppingAssistantApi.Application.IRepositories;
using ShoppingAssistantApi.Application.IServices;
using ShoppingAssistantApi.Application.Models.CreateDtos;
using ShoppingAssistantApi.Application.Models.Dtos;
using ShoppingAssistantApi.Application.Models.OpenAi;
using ShoppingAssistantApi.Application.Paging;
using ShoppingAssistantApi.Domain.Entities;
using ShoppingAssistantApi.Domain.Enums;
@ -22,12 +23,16 @@ public class WishlistsService : IWishlistsService
private readonly IMapper _mapper;
public WishlistsService(IWishlistsRepository wishlistRepository, IMessagesRepository messageRepository, IProductsRepository productRepository, IMapper mapper)
private readonly IOpenAiService _openAiService;
public WishlistsService(IWishlistsRepository wishlistRepository, IMessagesRepository messageRepository,
IProductsRepository productRepository, IMapper mapper, IOpenAiService openAiService)
{
_wishlistsRepository = wishlistRepository;
_messagesRepository = messageRepository;
_productsRepository = productRepository;
_mapper = mapper;
_openAiService = openAiService;
}
public async Task<WishlistDto> StartPersonalWishlistAsync(WishlistCreateDto dto, CancellationToken cancellationToken)
@ -59,6 +64,41 @@ public class WishlistsService : IWishlistsService
return _mapper.Map<WishlistDto>(createdWishlist);
}
public async Task<WishlistDto> GenerateNameForPersonalWishlistAsync(string wishlistId, CancellationToken cancellationToken)
{
if (!ObjectId.TryParse(wishlistId, out var wishlistObjectId))
{
throw new InvalidDataException("Provided id is invalid.");
}
var wishlist = await TryGetPersonalWishlist(wishlistObjectId, cancellationToken);
var firstUserMessage = (await _messagesRepository.GetPageAsync(1, 1, x => x.WishlistId == wishlistObjectId && x.Role == MessageRoles.User.ToString(), cancellationToken)).First();
var chatCompletionRequest = new ChatCompletionRequest
{
Messages = new List<OpenAiMessage>(2)
{
new OpenAiMessage
{
Role = OpenAiRole.System.RequestConvert(),
Content = "You will be provided with a general information about some product and your task is to generate general (not specific to any company or brand) chat name where recommendations on which specific product to buy will be given. Only name he product without adverbs and adjectives\nExamples:\n - Prompt: Hub For Macbook. Answer: Macbook Hub\n - Prompt: What is the best power bank for MacBook with capacity 20000 mAh and power near 20V? Answer: Macbook Powerbank"
},
new OpenAiMessage
{
Role = OpenAiRole.User.RequestConvert(),
Content = firstUserMessage.Text
}
}
};
var openAiMessage = await _openAiService.GetChatCompletion(chatCompletionRequest, cancellationToken);
wishlist = await _wishlistsRepository.UpdateWishlistNameAsync(wishlist.Id, openAiMessage.Content, cancellationToken);
return _mapper.Map<WishlistDto>(wishlist);
}
public async Task<MessageDto> AddMessageToPersonalWishlistAsync(string wishlistId, MessageCreateDto dto, CancellationToken cancellationToken)
{
var newMessage = _mapper.Map<Message>(dto);

View File

@ -1,4 +1,5 @@
using System.Linq.Expressions;
using MongoDB.Bson;
using MongoDB.Driver;
using ShoppingAssistantApi.Application.IRepositories;
using ShoppingAssistantApi.Domain.Entities;
@ -14,4 +15,18 @@ public class WishlistsRepository : BaseRepository<Wishlist>, IWishlistsRepositor
{
return await (await _collection.FindAsync(predicate)).FirstOrDefaultAsync(cancellationToken);
}
public async Task<Wishlist> UpdateWishlistNameAsync(ObjectId wishlistId, string newName, CancellationToken cancellationToken)
{
var filterDefinition = Builders<Wishlist>.Filter.Eq(w => w.Id, wishlistId);
var updateDefinition = Builders<Wishlist>.Update.Set(w => w.Name, newName);
var options = new FindOneAndUpdateOptions<Wishlist>
{
ReturnDocument = ReturnDocument.After
};
return await _collection.FindOneAndUpdateAsync(filterDefinition, updateDefinition, options, cancellationToken);
}
}

View File

@ -61,6 +61,58 @@ public class WishlistsTests : TestsBase
Assert.Equal($"{WishlistTypes.Product} Search", wishlist.Name);
}
[Fact]
public async Task GenerateNameForPersonalWishlist_ValidWishlistId_ReturnsNewName()
{
await LoginAsync(TestingUserEmail, TestingUserPassword);
var startWishlistMutation = new
{
query = @"
mutation startPersonalWishlist($dto: WishlistCreateDtoInput!) {
startPersonalWishlist (dto: $dto) {
id, name, type, createdById
}
}",
variables = new
{
dto = new
{
firstMessageText = "Mechanical keyboard for programming",
type = WishlistTypes.Product.ToString()
}
}
};
var jsonObject = await SendGraphQlRequestAsync(startWishlistMutation);
var startWishlistResponse = (WishlistDto?) jsonObject?.data?.startPersonalWishlist?.ToObject<WishlistDto>();
Assert.NotNull(startWishlistResponse);
var generateWishlistNameMutation = new
{
query = @"
mutation genarateNameForPersonalWishlist($wishlistId: String!) {
generateNameForPersonalWishlist(wishlistId: $wishlistId) {
id, name, type, createdById
}
}",
variables = new
{
wishlistId = startWishlistResponse.Id
}
};
jsonObject = await SendGraphQlRequestAsync(generateWishlistNameMutation);
var generateWishlistNameResponse = (WishlistDto?) jsonObject?.data?.generateNameForPersonalWishlist?.ToObject<WishlistDto>();
Assert.NotNull(generateWishlistNameResponse);
Assert.Equal(startWishlistResponse.Id, generateWishlistNameResponse.Id);
Assert.NotEqual($"{startWishlistResponse.Type} Search", generateWishlistNameResponse.Name);
Assert.NotEqual(String.Empty, generateWishlistNameResponse.Name);
Assert.NotEqual(null, generateWishlistNameResponse.Name);
}
[Fact]
public async Task GetPersonalWishlistsPage_ValidPageNumberAndSize_ReturnsPage()
{