From 77b14bf4c7db2190958086f3dcdffe21e6c6b06a Mon Sep 17 00:00:00 2001 From: stasex Date: Wed, 25 Oct 2023 14:16:11 +0300 Subject: [PATCH] changed the logic for product search and set up the integration test --- .../Controllers/ProductsSearchController.cs | 4 +- .../Services/ProductService.cs | 23 +++++----- .../TestExtentions/DbInitializer.cs | 45 ++++++++++++++++++- .../Tests/ProductsTests.cs | 7 +-- .../ProductTests.cs | 12 +++-- 5 files changed, 71 insertions(+), 20 deletions(-) diff --git a/ShoppingAssistantApi.Api/Controllers/ProductsSearchController.cs b/ShoppingAssistantApi.Api/Controllers/ProductsSearchController.cs index 6873127..7dd9949 100644 --- a/ShoppingAssistantApi.Api/Controllers/ProductsSearchController.cs +++ b/ShoppingAssistantApi.Api/Controllers/ProductsSearchController.cs @@ -1,10 +1,12 @@ -using Microsoft.AspNetCore.Mvc; +using HotChocolate.Authorization; +using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using ShoppingAssistantApi.Application.IServices; using ShoppingAssistantApi.Application.Models.CreateDtos; namespace ShoppingAssistantApi.Api.Controllers; +[Authorize] public class ProductsSearchController : BaseController { private readonly IProductService _productService; diff --git a/ShoppingAssistantApi.Infrastructure/Services/ProductService.cs b/ShoppingAssistantApi.Infrastructure/Services/ProductService.cs index ce0fad0..b4d4739 100644 --- a/ShoppingAssistantApi.Infrastructure/Services/ProductService.cs +++ b/ShoppingAssistantApi.Infrastructure/Services/ProductService.cs @@ -1,4 +1,6 @@ using System.Diagnostics; +using MongoDB.Bson; +using ShoppingAssistantApi.Application.IRepositories; using ShoppingAssistantApi.Application.IServices; using ShoppingAssistantApi.Application.Models.CreateDtos; using ShoppingAssistantApi.Application.Models.Dtos; @@ -15,22 +17,23 @@ public class ProductService : IProductService private readonly IWishlistsService _wishlistsService; private readonly IOpenAiService _openAiService; - - public ProductService(IOpenAiService openAiService, IWishlistsService wishlistsService) + private readonly IMessagesRepository _messagesRepository; + + public ProductService(IOpenAiService openAiService, IWishlistsService wishlistsService, IMessagesRepository messagesRepository) { _openAiService = openAiService; _wishlistsService = wishlistsService; + _messagesRepository = messagesRepository; } public async IAsyncEnumerable SearchProductAsync(string wishlistId, MessageCreateDto message, CancellationToken cancellationToken) { - var isFirstMessage = _wishlistsService - .GetMessagesPageFromPersonalWishlistAsync(wishlistId, 1, 1, cancellationToken).Result; + var isFirstMessage = await _messagesRepository.GetCountAsync(message=>message.WishlistId==ObjectId.Parse((wishlistId)), cancellationToken); var chatRequest = new ChatCompletionRequest(); - if (isFirstMessage==null) + if (isFirstMessage==0) { chatRequest = new ChatCompletionRequest { @@ -38,7 +41,7 @@ public class ProductService : IProductService { new OpenAiMessage { - Role = OpenAiRole.System.ToString(), + Role = OpenAiRole.System.ToString().ToLower(), Content = "You are a Shopping Assistant that helps people find product recommendations. Ask user additional questions if more context needed." + "\nYou must return data with one of the prefixes:" + "\n[Question] - return question" + @@ -49,7 +52,7 @@ public class ProductService : IProductService new OpenAiMessage() { - Role = OpenAiRole.Assistant.ToString(), + Role = OpenAiRole.System.ToString().ToLower(), Content = "What are you looking for?" } }, @@ -80,10 +83,10 @@ public class ProductService : IProductService }; } - if(isFirstMessage!=null) + if(isFirstMessage!=0) { var previousMessages = _wishlistsService - .GetMessagesPageFromPersonalWishlistAsync(wishlistId, 1, 1, cancellationToken).Result.Items.ToList(); + .GetMessagesPageFromPersonalWishlistAsync(wishlistId, 1, 50, cancellationToken).Result.Items.ToList(); var messagesForOpenAI = new List(); foreach (var item in previousMessages ) @@ -91,7 +94,7 @@ public class ProductService : IProductService messagesForOpenAI.Add( new OpenAiMessage() { - Role = item.Role, + Role = item.Role.ToLower(), Content = item.Text }); } diff --git a/ShoppingAssistantApi.Tests/TestExtentions/DbInitializer.cs b/ShoppingAssistantApi.Tests/TestExtentions/DbInitializer.cs index 811cce6..a89df14 100644 --- a/ShoppingAssistantApi.Tests/TestExtentions/DbInitializer.cs +++ b/ShoppingAssistantApi.Tests/TestExtentions/DbInitializer.cs @@ -107,6 +107,8 @@ public class DbInitializer var wishlistId1 = ObjectId.Parse("ab79cde6f69abcd3efab65cd"); var wishlistId2 = ObjectId.Parse("ab6c2c2d9edf39abcd1ef9ab"); + var wishlistId3 = ObjectId.Parse("ab7c8c2d9edf39abcd1ef9ab"); + var wishlistId4 = ObjectId.Parse("ab8c8c2d9edf39abcd1ef9ab"); var wishlists = new Wishlist[] { @@ -125,7 +127,23 @@ public class DbInitializer Type = WishlistTypes.Product.ToString(), CreatedById = user2.Id, CreatedDateUtc = DateTime.UtcNow - } + }, + new Wishlist + { + Id = wishlistId3, + Name = "Test For Search", + Type = WishlistTypes.Product.ToString(), + CreatedById = user1.Id, + CreatedDateUtc = DateTime.UtcNow + }, + new Wishlist + { + Id = wishlistId4, + Name = "Test For Answer", + Type = WishlistTypes.Product.ToString(), + CreatedById = user1.Id, + CreatedDateUtc = DateTime.UtcNow + }, }; await wishlistsCollection.InsertManyAsync(wishlists); @@ -142,6 +160,8 @@ public class DbInitializer var wishlistId1 = ObjectId.Parse("ab79cde6f69abcd3efab65cd"); var wishlistId2 = ObjectId.Parse("ab6c2c2d9edf39abcd1ef9ab"); + var wishlistId3 = ObjectId.Parse("ab7c8c2d9edf39abcd1ef9ab"); + var wishlistId4 = ObjectId.Parse("ab8c8c2d9edf39abcd1ef9ab"); var messages = new Message[] { @@ -197,7 +217,28 @@ public class DbInitializer WishlistId = wishlistId2, CreatedById = user2.Id, CreatedDateUtc = DateTime.UtcNow - } + }, + new Message + { + Text = "You are a Shopping Assistant that helps people find product recommendations. Ask user additional questions if more context needed." + + "\nYou must return data with one of the prefixes:" + + "\n[Question] - return question" + + "\n[Suggestions] - return semicolon separated suggestion how to answer to a question" + + "\n[Message] - return text" + + "\n[Products] - return semicolon separated product names", + Role = "system", + WishlistId = wishlistId4, + CreatedById = user2.Id, + CreatedDateUtc = DateTime.UtcNow + }, + new Message + { + Text = "What are you looking for?", + Role = "system", + WishlistId = wishlistId4, + CreatedById = user2.Id, + CreatedDateUtc = DateTime.UtcNow + }, }; await messagesCollection.InsertManyAsync(messages); diff --git a/ShoppingAssistantApi.Tests/Tests/ProductsTests.cs b/ShoppingAssistantApi.Tests/Tests/ProductsTests.cs index 21ea9fe..686d057 100644 --- a/ShoppingAssistantApi.Tests/Tests/ProductsTests.cs +++ b/ShoppingAssistantApi.Tests/Tests/ProductsTests.cs @@ -18,12 +18,13 @@ public class ProductsTests : TestsBase [Fact] public async Task StreamDataToClient_ReturnsExpectedResponse() { + await LoginAsync("wishlists@gmail.com", "Yuiop12345"); // Arrange - var wishlistId = "ab79cde6f69abcd3efab65cd"; - var message = new MessageCreateDto { Text = "Your message text" }; + var wishlistId = "ab8c8c2d9edf39abcd1ef9ab"; + var message = new MessageCreateDto { Text = "I want new powerful laptop" }; // Act - var response = await _httpClient.PostAsJsonAsync($"http://127.0.0.1:5183//api/products/search/{wishlistId}", message); + var response = await _httpClient.PostAsJsonAsync($"http://127.0.0.1:5183/api/ProductsSearch/search/{wishlistId}", message); // Assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); diff --git a/ShoppingAssistantApi.UnitTests/ProductTests.cs b/ShoppingAssistantApi.UnitTests/ProductTests.cs index 2c2ac96..6bf5b67 100644 --- a/ShoppingAssistantApi.UnitTests/ProductTests.cs +++ b/ShoppingAssistantApi.UnitTests/ProductTests.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using MongoDB.Bson; using Moq; using Newtonsoft.Json.Linq; +using ShoppingAssistantApi.Application.IRepositories; using ShoppingAssistantApi.Application.IServices; using ShoppingAssistantApi.Application.Models.CreateDtos; using ShoppingAssistantApi.Application.Models.Dtos; @@ -21,13 +22,16 @@ public class ProductTests private IProductService _productService; - public Mock _wishListServiceMock; + private Mock _wishListServiceMock; - public ProductTests() + private IMessagesRepository _messagesRepository; + + public ProductTests(IMessagesRepository messagesRepository) { + _messagesRepository = messagesRepository; _openAiServiceMock = new Mock(); _wishListServiceMock = new Mock(); - _productService = new ProductService(_openAiServiceMock.Object, _wishListServiceMock.Object); + _productService = new ProductService(_openAiServiceMock.Object, _wishListServiceMock.Object, _messagesRepository); } [Fact] @@ -116,7 +120,7 @@ public class ProductTests var message = new MessageCreateDto { Text = "Your message text" }; var cancellationToken = new CancellationToken(); - var productService = new ProductService(_openAiServiceMock.Object, _wishListServiceMock.Object); + var productService = new ProductService(_openAiServiceMock.Object, _wishListServiceMock.Object, _messagesRepository); var expectedSseData = new List {