AI finalized

This commit is contained in:
Adam 2026-02-10 23:03:29 +01:00
parent 15dbec5aad
commit 611df8f60f
5 changed files with 696 additions and 644 deletions

View File

@ -14,6 +14,7 @@ using Nop.Plugin.Misc.FruitBankPlugin.Helpers;
using Nop.Plugin.Misc.FruitBankPlugin.Services; using Nop.Plugin.Misc.FruitBankPlugin.Services;
using Nop.Plugin.Misc.FruitBankPlugin.Services.FileStorage; using Nop.Plugin.Misc.FruitBankPlugin.Services.FileStorage;
using Nop.Services.Catalog; using Nop.Services.Catalog;
using Nop.Services.Common;
using Nop.Services.Security; using Nop.Services.Security;
using Nop.Web.Framework; using Nop.Web.Framework;
using Nop.Web.Framework.Controllers; using Nop.Web.Framework.Controllers;
@ -31,31 +32,37 @@ namespace Nop.Plugin.Misc.FruitBank.Controllers
{ {
private readonly IPermissionService _permissionService; private readonly IPermissionService _permissionService;
private readonly OpenAIApiService _aiApiService; private readonly OpenAIApiService _aiApiService;
private readonly CerebrasAPIService _cerebrasApiService;
private readonly AICalculationService _aiCalculationService; private readonly AICalculationService _aiCalculationService;
private readonly IProductService _productService; private readonly IProductService _productService;
private readonly FruitBankDbContext _dbContext; private readonly FruitBankDbContext _dbContext;
private readonly PdfToImageService _pdfToImageService; private readonly PdfToImageService _pdfToImageService;
private readonly IWorkContext _workContext; private readonly IWorkContext _workContext;
private readonly FileStorageService _fileStorageService; private readonly FileStorageService _fileStorageService;
private readonly FruitBankAttributeService _fruitBankAttributeService;
public FileManagerController( public FileManagerController(
IPermissionService permissionService, IPermissionService permissionService,
OpenAIApiService aiApiService, OpenAIApiService aiApiService,
CerebrasAPIService cerebrasApiService,
AICalculationService aiCalculationService, AICalculationService aiCalculationService,
IProductService productService, IProductService productService,
FruitBankDbContext fruitBankDbContext, FruitBankDbContext fruitBankDbContext,
PdfToImageService pdfToImageService, PdfToImageService pdfToImageService,
IWorkContext workContext, IWorkContext workContext,
FileStorageService fileStorageService) FileStorageService fileStorageService,
FruitBankAttributeService fruitBankAttributeService)
{ {
_permissionService = permissionService; _permissionService = permissionService;
_aiApiService = aiApiService; _aiApiService = aiApiService;
_cerebrasApiService = cerebrasApiService;
_aiCalculationService = aiCalculationService; _aiCalculationService = aiCalculationService;
_productService = productService; _productService = productService;
_dbContext = fruitBankDbContext; _dbContext = fruitBankDbContext;
_pdfToImageService = pdfToImageService; _pdfToImageService = pdfToImageService;
_workContext = workContext; _workContext = workContext;
_fileStorageService = fileStorageService; _fileStorageService = fileStorageService;
_fruitBankAttributeService = fruitBankAttributeService;
} }
/// <summary> /// <summary>
@ -483,7 +490,8 @@ namespace Nop.Plugin.Misc.FruitBank.Controllers
deserializedProduct.name + "\n\n" + deserializedProduct.name + "\n\n" +
"Return the best matching product name from the catalog above (matching ALL details including size/grade), or 'NONE' if no good match exists."; "Return the best matching product name from the catalog above (matching ALL details including size/grade), or 'NONE' if no good match exists.";
var aiMatchedProductName = await _aiApiService.GetSimpleResponseAsync(systemPrompt, userPrompt); //var aiMatchedProductName = await _aiApiService.GetSimpleResponseAsync(systemPrompt, userPrompt);
var aiMatchedProductName = await _cerebrasApiService.GetSimpleResponseAsync(systemPrompt, userPrompt);
//var aiMatchedProductName = await _aiApiService.GetSimpleResponseAsync(aiMatchPrompt, deserializedProduct.name); //var aiMatchedProductName = await _aiApiService.GetSimpleResponseAsync(aiMatchPrompt, deserializedProduct.name);
Console.WriteLine($"AI matched product name for {deserializedProduct.name}: {aiMatchedProductName}"); Console.WriteLine($"AI matched product name for {deserializedProduct.name}: {aiMatchedProductName}");
@ -577,7 +585,8 @@ namespace Nop.Plugin.Misc.FruitBank.Controllers
deserializedProduct.name + "\n\n" + deserializedProduct.name + "\n\n" +
"Return the best matching product name from the catalog above that matches ALL details (size, grade, quality), or 'NONE' if no confident match exists."; "Return the best matching product name from the catalog above that matches ALL details (size, grade, quality), or 'NONE' if no confident match exists.";
var aiMatchedProductName2 = await _aiApiService.GetSimpleResponseAsync(systemPrompt2, userPrompt2); //var aiMatchedProductName2 = await _aiApiService.GetSimpleResponseAsync(systemPrompt2, userPrompt2);
var aiMatchedProductName2 = await _cerebrasApiService.GetSimpleResponseAsync(systemPrompt2, userPrompt2);
Console.WriteLine($"AI matched product name from hybrid catalog for {deserializedProduct.name}: {aiMatchedProductName2}"); Console.WriteLine($"AI matched product name from hybrid catalog for {deserializedProduct.name}: {aiMatchedProductName2}");
if (!string.IsNullOrEmpty(aiMatchedProductName2) && aiMatchedProductName2 != "NONE") if (!string.IsNullOrEmpty(aiMatchedProductName2) && aiMatchedProductName2 != "NONE")
@ -737,7 +746,8 @@ namespace Nop.Plugin.Misc.FruitBank.Controllers
partnerAnalysis + "\n\n" + partnerAnalysis + "\n\n" +
"Return ONLY the numeric ID of the matching partner, or '0' if no match found."; "Return ONLY the numeric ID of the matching partner, or '0' if no match found.";
var aiResponse = await _aiApiService.GetSimpleResponseAsync(systemPrompt, userPrompt); //var aiResponse = await _aiApiService.GetSimpleResponseAsync(systemPrompt, userPrompt);
var aiResponse = await _cerebrasApiService.GetSimpleResponseAsync(systemPrompt, userPrompt);
Console.WriteLine($"AI Partner Match Response: {aiResponse}"); Console.WriteLine($"AI Partner Match Response: {aiResponse}");
// Parse the ID // Parse the ID
@ -828,7 +838,8 @@ namespace Nop.Plugin.Misc.FruitBank.Controllers
"4. Return ONLY the company name, nothing else\n\n" + "4. Return ONLY the company name, nothing else\n\n" +
"If uncertain, return the most prominent non-FruitBank company name from the document."; "If uncertain, return the most prominent non-FruitBank company name from the document.";
var partnerAnalysis = await _aiApiService.GetSimpleResponseAsync(systemPrompt, userPrompt); //var partnerAnalysis = await _aiApiService.GetSimpleResponseAsync(systemPrompt, userPrompt);
var partnerAnalysis = await _cerebrasApiService.GetSimpleResponseAsync(systemPrompt, userPrompt);
// Clean up the response // Clean up the response
var cleanedPartnerName = CleanPartnerName(partnerAnalysis); var cleanedPartnerName = CleanPartnerName(partnerAnalysis);
@ -1087,6 +1098,17 @@ namespace Nop.Plugin.Misc.FruitBank.Controllers
Console.WriteLine("⚠ No original file provided - skipping file save"); Console.WriteLine("⚠ No original file provided - skipping file save");
} }
//everything done, let's update the genericattribute "IncomingQuantity" of the product
foreach (var item in shippingDocument.ShippingItems.Where(x => x.ProductId != null))
{
await _fruitBankAttributeService.InsertOrUpdateGenericAttributeAsync<Product, int>(
item.ProductId.Value,
"IncomingQuantity",
item.QuantityOnDocument
);
}
return Json(new return Json(new
{ {
success = true, success = true,

View File

@ -24,6 +24,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
{ {
private readonly IPermissionService _permissionService; private readonly IPermissionService _permissionService;
private readonly OpenAIApiService _aiApiService; private readonly OpenAIApiService _aiApiService;
private readonly CerebrasAPIService _cerebrasApiService;
private readonly ICustomerService _customerService; private readonly ICustomerService _customerService;
private readonly IProductService _productService; private readonly IProductService _productService;
private readonly FruitBankDbContext _dbContext; private readonly FruitBankDbContext _dbContext;
@ -31,12 +32,14 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
public VoiceOrderController( public VoiceOrderController(
IPermissionService permissionService, IPermissionService permissionService,
OpenAIApiService aiApiService, OpenAIApiService aiApiService,
CerebrasAPIService cerebrasApiService,
ICustomerService customerService, ICustomerService customerService,
IProductService productService, IProductService productService,
FruitBankDbContext dbContext) FruitBankDbContext dbContext)
{ {
_permissionService = permissionService; _permissionService = permissionService;
_aiApiService = aiApiService; _aiApiService = aiApiService;
_cerebrasApiService = cerebrasApiService;
_customerService = customerService; _customerService = customerService;
_productService = productService; _productService = productService;
_dbContext = dbContext; _dbContext = dbContext;
@ -320,6 +323,12 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
transcribedText = await _aiApiService.TranscribeAudioAsync(audioStream, fileName, language, customPrompt); transcribedText = await _aiApiService.TranscribeAudioAsync(audioStream, fileName, language, customPrompt);
} }
if(transcribedText.EndsWith(".") || transcribedText.EndsWith("!") || transcribedText.EndsWith("?"))
{
//remove trailing punctuation
transcribedText = transcribedText.Substring(0, transcribedText.Length - 1);
}
// Clean up temporary file // Clean up temporary file
try try
{ {
@ -412,9 +421,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Areas.Admin.Controllers
try try
{ {
// Get all customers with company names (increased limit) // Get all customers with company names (increased limit)
var allCustomersWithCompany = await _customerService.GetAllCustomersAsync( var allCustomersWithCompany = await _customerService.GetAllCustomersAsync(); // Increased from 500 to catch more companies
pageIndex: 0,
pageSize: 1000); // Increased from 500 to catch more companies
// Filter to only those with company names // Filter to only those with company names
var customersWithCompany = allCustomersWithCompany var customersWithCompany = allCustomersWithCompany
@ -441,7 +448,7 @@ CRITICAL MATCHING RULES (in priority order):
2. SUBSTRING MATCH: If the search term is contained within a company name (e.g., 'Junket' in 'Junket Silver Kft.') 2. SUBSTRING MATCH: If the search term is contained within a company name (e.g., 'Junket' in 'Junket Silver Kft.')
3. WORD MATCH: If all words from search term appear in company name (any order) 3. WORD MATCH: If all words from search term appear in company name (any order)
4. PARTIAL MATCH: If significant words overlap (e.g., 'Silver' matches 'Junket Silver') 4. PARTIAL MATCH: If significant words overlap (e.g., 'Silver' matches 'Junket Silver')
5. PHONETIC SIMILARITY: How it sounds when spoken 5. PHONETIC SIMILARITY: How it sounds when spoken in Hungarian (e.g. 'Ökotály' should be matched to 'Öcotáj')
6. ABBREVIATIONS: 'SFI' matches 'SFI Rotterdam B.V.' 6. ABBREVIATIONS: 'SFI' matches 'SFI Rotterdam B.V.'
EXAMPLES: EXAMPLES:
@ -461,7 +468,8 @@ OUTPUT FORMAT (JSON only):
Companies: Companies:
{companyList}"; {companyList}";
var aiResponse = await _aiApiService.GetSimpleResponseAsync(systemPrompt, userPrompt); //var aiResponse = await _aiApiService.GetSimpleResponseAsync(systemPrompt, userPrompt);
var aiResponse = await _cerebrasApiService.GetSimpleResponseAsync(systemPrompt, userPrompt);
Console.WriteLine($"[VoiceOrder] AI company matching response: {aiResponse}"); Console.WriteLine($"[VoiceOrder] AI company matching response: {aiResponse}");
@ -552,7 +560,8 @@ Output: [{""product"":""szőlő"",""quantity"":50}]";
var userPrompt = $"Parse this: {text}"; var userPrompt = $"Parse this: {text}";
var aiResponse = await _aiApiService.GetSimpleResponseAsync(systemPrompt, userPrompt); //var aiResponse = await _aiApiService.GetSimpleResponseAsync(systemPrompt, userPrompt);
var aiResponse = await _cerebrasApiService.GetSimpleResponseAsync(systemPrompt, userPrompt);
Console.WriteLine($"[VoiceOrder] AI Response: {aiResponse}"); Console.WriteLine($"[VoiceOrder] AI Response: {aiResponse}");

View File

@ -333,6 +333,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services
"TaxId", "TaxId",
customer.VatNumber); customer.VatNumber);
} }
_dbContext.Customers.Update(customer, false);
} }
} }
} }

View File

@ -840,7 +840,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services
role = "system", role = "system",
content = new object[] content = new object[]
{ {
new { type = "text", text = prompt }, new { type = "text", text = systemPrompt },
} }
}, },
new { new {