@@ -190,6 +170,14 @@
+
+
+
+
diff --git a/Nop.Plugin.Misc.AIPlugin/FruitBankSettings.cs b/Nop.Plugin.Misc.AIPlugin/FruitBankSettings.cs
index 5a8a960..351324b 100644
--- a/Nop.Plugin.Misc.AIPlugin/FruitBankSettings.cs
+++ b/Nop.Plugin.Misc.AIPlugin/FruitBankSettings.cs
@@ -15,6 +15,16 @@ namespace Nop.Plugin.Misc.FruitBankPlugin
///
public string ModelName { get; set; } = "gpt-3.5-turbo";
+ ///
+ /// Gets or sets the AI API key
+ ///
+ public string OpenAIApiKey { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the AI API model name
+ ///
+ public string OpenAIModelName { get; set; } = "gpt-3.5-turbo";
+
///
/// Gets or sets a value indicating whether the AI plugin is enabled
///
@@ -25,6 +35,11 @@ namespace Nop.Plugin.Misc.FruitBankPlugin
///
public string ApiBaseUrl { get; set; } = "https://api.openai.com/v1";
+ ///
+ /// Gets or sets the API base URL (useful for different AI providers)
+ ///
+ public string OpenAIApiBaseUrl { get; set; } = "https://api.openai.com/v1";
+
///
/// Gets or sets the maximum number of tokens for AI responses
///
diff --git a/Nop.Plugin.Misc.AIPlugin/Helpers/TextHelper.cs b/Nop.Plugin.Misc.AIPlugin/Helpers/TextHelper.cs
new file mode 100644
index 0000000..ea6a708
--- /dev/null
+++ b/Nop.Plugin.Misc.AIPlugin/Helpers/TextHelper.cs
@@ -0,0 +1,271 @@
+using System;
+using System.Text.RegularExpressions;
+using System.Text;
+using System.Collections.Generic;
+
+
+namespace Nop.Plugin.Misc.FruitBankPlugin.Helpers;
+public static class TextHelper
+{
+ // Special character replacement map
+ private static readonly Dictionary
HungarianSpecialCharacterMap = new()
+ {
+ { "/", " per " },
+ { "@", " kukac " },
+ { "#", " kettőskereszt " },
+ { "&", " és " },
+ //{ ",", " vessző " },
+ { " = ", " egyenlő " }, // Example, you can add more
+ //{ " - ", " mínusz " } // Example, you can add more
+ };
+
+ private static readonly Dictionary EnglishSpecialCharacterMap = new()
+ {
+ { "/", " slash " },
+ { "@", " at " },
+ { "#", " hashtag " },
+ { "&", " and " },
+ //{ ",", " vessző " },
+ { " = ", " equals " }, // Example, you can add more
+ //{ " - ", " mínusz " } // Example, you can add more
+ };
+
+ public static string ReplaceNumbersAndSpecialCharacters(string text, string language)
+ {
+ // Save parts that should be skipped (emails, URLs, dates)
+ var protectedParts = new Dictionary();
+
+ // Protect dates like 2024.05.06
+ text = Regex.Replace(text, @"\b\d{4}\.\d{2}\.\d{2}\b", match =>
+ {
+ string key = $"__DATE__{protectedParts.Count}__";
+ protectedParts[key] = match.Value;
+ return key;
+ });
+
+ // Remove anything between [] including the brackets themselves
+ text = Regex.Replace(text, @"\[[^\]]*\]", "");
+
+ // First replace floats (keep this BEFORE integers)
+ text = Regex.Replace(text, @"\b\d+\.\d+\b", match =>
+ {
+ var parts = match.Value.Split('.');
+ var integerPart = int.Parse(parts[0]);
+ var decimalPart = int.Parse(parts[1]);
+ if(language == "Hungarian")
+ {
+ return $"{NumberToHungarian(integerPart)} egész {NumberToHungarian(decimalPart)} {(parts[1].Length == 1 ? "tized" : parts[1].Length == 2 ? "század" : "ezred")}";
+ }
+ else
+ {
+ return $"{NumberToEnglish(integerPart)} point {NumberToEnglish(decimalPart)}";
+ }
+ });
+
+ // Then replace integers
+ text = Regex.Replace(text, @"\b\d+\b", match =>
+ {
+ int number = int.Parse(match.Value);
+ if(language == "Hungarian")
+ {
+ return NumberToHungarian(number);
+ }
+ else
+ {
+ return NumberToEnglish(number);
+ }
+ });
+
+ // Replace special characters from dictionary
+ if(language == "Hungarian")
+ {
+ foreach (var kvp in HungarianSpecialCharacterMap)
+ {
+ text = text.Replace(kvp.Key, kvp.Value);
+ }
+ }
+ else
+ {
+ foreach (var kvp in EnglishSpecialCharacterMap)
+ {
+ text = text.Replace(kvp.Key, kvp.Value);
+ }
+ }
+
+ // Replace dots surrounded by spaces (optional)
+ //text = Regex.Replace(text, @" (?=\.)|(?<=\.) ", " pont ");
+
+ // Restore protected parts
+ foreach (var kvp in protectedParts)
+ {
+ text = text.Replace(kvp.Key, kvp.Value);
+ }
+
+ return text;
+ }
+
+
+ public static string NumberToHungarian(int number)
+ {
+ if (number == 0) return "nulla";
+
+ string[] units = { "", "egy", "két", "három", "négy", "öt", "hat", "hét", "nyolc", "kilenc" };
+ string[] tens = { "", "tíz", "húsz", "harminc", "negyven", "ötven", "hatvan", "hetven", "nyolcvan", "kilencven" };
+ string[] tensAlternate = { "", "tizen", "huszon", "harminc", "negyven", "ötven", "hatvan", "hetven", "nyolcvan", "kilencven" };
+
+ StringBuilder result = new StringBuilder();
+
+ if (number >= 1000)
+ {
+ int thousands = number / 1000;
+ if (thousands == 1)
+ result.Append("ezer");
+ else
+ {
+ result.Append(NumberToHungarian(thousands));
+ result.Append("ezer");
+ }
+ number %= 1000;
+ }
+
+ if (number >= 100)
+ {
+ int hundreds = number / 100;
+ if (hundreds == 1)
+ result.Append("száz");
+ else
+ {
+ result.Append(NumberToHungarian(hundreds));
+ result.Append("száz");
+ }
+ number %= 100;
+ }
+
+ if (number >= 10)
+ {
+ int tensPart = number / 10;
+ result.Append(tensAlternate[tensPart]);
+ number %= 10;
+ }
+
+ if (number > 0)
+ {
+ // "két" instead of "kettő" in compound numbers
+ if (number == 2 && result.Length > 0)
+ result.Append("két");
+ else
+ result.Append(units[number]);
+ }
+
+ return result.ToString();
+ }
+
+ public static string NumberToEnglish(int number)
+ {
+ if (number == 0) return "zero";
+
+ string[] units = { "", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
+ string[] tens = { "", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninty" };
+
+ StringBuilder result = new StringBuilder();
+
+ if (number >= 1000)
+ {
+ int thousands = number / 1000;
+ if (thousands == 1)
+ result.Append("thousand");
+ else
+ {
+ result.Append(NumberToHungarian(thousands));
+ result.Append("thousand");
+ }
+ number %= 1000;
+ }
+
+ if (number >= 100)
+ {
+ int hundreds = number / 100;
+ if (hundreds == 1)
+ result.Append("hundred");
+ else
+ {
+ result.Append(NumberToHungarian(hundreds));
+ result.Append("hundred");
+ }
+ number %= 100;
+ }
+
+ if (number >= 10)
+ {
+ //int tensPart = number / 10;
+ //result.Append(tens[tensPart]);
+ //number %= 10;
+ switch (number)
+ {
+ case 10:
+ result.Append("ten");
+ break;
+ case 11:
+ result.Append("eleven");
+ break;
+ case 12:
+ result.Append("twelve");
+ break;
+ case 13:
+ result.Append("thirteen");
+ break;
+ case 14:
+ result.Append("fourteen");
+ break;
+ case 15:
+ result.Append("fifteen");
+ break;
+ case 16:
+ result.Append("sixteen");
+ break;
+ case 17:
+ result.Append("seventeen");
+ break;
+ case 18:
+ result.Append("eighteen");
+ break;
+ case 19:
+ result.Append("nineteen");
+ break;
+ }
+ }
+
+ return result.ToString();
+ }
+
+ public static string FixJsonWithoutAI(string aiResponse)
+ {
+ if (aiResponse.StartsWith("```"))
+ {
+
+ //Console.WriteLine("FIXING ``` in AI Response.");
+ aiResponse = aiResponse.Substring(3);
+ if (aiResponse.StartsWith("json"))
+ {
+ aiResponse = aiResponse.Substring(4);
+ }
+ if (aiResponse.StartsWith("html"))
+ {
+ aiResponse = aiResponse.Substring(4);
+ }
+ aiResponse = aiResponse.Substring(0, aiResponse.Length - 3);
+ }
+
+
+
+ return aiResponse;
+ }
+
+ public static string RemoveTabs(string text)
+ {
+ if (string.IsNullOrEmpty(text)) return text;
+ return text.Replace("\t", ""); // Simple replace — remove all tab characters
+ }
+
+
+}
diff --git a/Nop.Plugin.Misc.AIPlugin/Infrastructure/PluginNopStartup.cs b/Nop.Plugin.Misc.AIPlugin/Infrastructure/PluginNopStartup.cs
index 6b7355b..cc0b172 100644
--- a/Nop.Plugin.Misc.AIPlugin/Infrastructure/PluginNopStartup.cs
+++ b/Nop.Plugin.Misc.AIPlugin/Infrastructure/PluginNopStartup.cs
@@ -75,6 +75,7 @@ public class PluginNopStartup : INopStartup
services.AddScoped();
services.AddScoped();
services.AddScoped();
+ services.AddScoped();
//services.AddScoped();
services.AddScoped();
services.AddControllersWithViews(options =>
diff --git a/Nop.Plugin.Misc.AIPlugin/Infrastructure/RouteProvider.cs b/Nop.Plugin.Misc.AIPlugin/Infrastructure/RouteProvider.cs
index fb332f8..45e2ff0 100644
--- a/Nop.Plugin.Misc.AIPlugin/Infrastructure/RouteProvider.cs
+++ b/Nop.Plugin.Misc.AIPlugin/Infrastructure/RouteProvider.cs
@@ -81,6 +81,11 @@ public class RouteProvider : IRouteProvider
name: "Plugin.FruitBank.Admin.Shipping.UploadFile",
pattern: "Admin/Shipping/UploadFile",
defaults: new { controller = "Shipping", action = "UploadFile", area = AreaNames.ADMIN });
+
+ endpointRouteBuilder.MapControllerRoute(
+ name: "Plugin.FruitBank.Admin.Shipping.ReloadPartialView",
+ pattern: "Admin/Shipping/ReloadPartialView",
+ defaults: new { controller = "Shipping", action = "ReloadPartialView", area = AreaNames.ADMIN });
}
///
diff --git a/Nop.Plugin.Misc.AIPlugin/Nop.Plugin.Misc.FruitBankPlugin.csproj b/Nop.Plugin.Misc.AIPlugin/Nop.Plugin.Misc.FruitBankPlugin.csproj
index 36e5345..6c035be 100644
--- a/Nop.Plugin.Misc.AIPlugin/Nop.Plugin.Misc.FruitBankPlugin.csproj
+++ b/Nop.Plugin.Misc.AIPlugin/Nop.Plugin.Misc.FruitBankPlugin.csproj
@@ -146,6 +146,9 @@
+
+ Always
+
Always
diff --git a/Nop.Plugin.Misc.AIPlugin/Services/AICalculationService.cs b/Nop.Plugin.Misc.AIPlugin/Services/AICalculationService.cs
index ebf9462..0ca2439 100644
--- a/Nop.Plugin.Misc.AIPlugin/Services/AICalculationService.cs
+++ b/Nop.Plugin.Misc.AIPlugin/Services/AICalculationService.cs
@@ -2,6 +2,7 @@
using Nop.Core;
using Nop.Core.Domain.Customers;
using Nop.Core.Domain.Stores;
+using Nop.Plugin.Misc.FruitBankPlugin.Helpers;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
@@ -14,6 +15,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services
public class AICalculationService
{
private readonly CerebrasAPIService _cerebrasApiService;
+ private readonly OpenAIApiService _openAIApiService;
private readonly IStoreContext _storeContext;
public AICalculationService(CerebrasAPIService cerebrasApiService, IStoreContext storeContext)
{
@@ -33,5 +35,18 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services
var response = await _cerebrasApiService.GetSimpleResponseAsync(systemMessage, userMessage);
return response;
}
+
+ public async Task GetOpenAIPDFAnalyzisFromText(string pdfText, string userQuestion)
+ {
+ string systemMessage = $"You are a helpful assistant of a webshop, you work in the administration area, with the ADMIN user. The ADMIN user is asking you questions about a PDF document, that you have access to. The content of the PDF document is the following: {pdfText}";
+ var response = await _cerebrasApiService.GetSimpleResponseAsync(systemMessage, userQuestion);
+
+ var fixedResponse = TextHelper.FixJsonWithoutAI(response);
+
+ return fixedResponse;
+ }
+
+
+
}
}
diff --git a/Nop.Plugin.Misc.AIPlugin/Services/OpenAIApiService.cs b/Nop.Plugin.Misc.AIPlugin/Services/OpenAIApiService.cs
index d29f13e..4ae453b 100644
--- a/Nop.Plugin.Misc.AIPlugin/Services/OpenAIApiService.cs
+++ b/Nop.Plugin.Misc.AIPlugin/Services/OpenAIApiService.cs
@@ -30,8 +30,8 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services
_httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {GetApiKey()}");
}
- public string GetApiKey() => _fruitBankSettings.ApiKey;
- public string GetModelName() => _fruitBankSettings.ModelName;
+ public string GetApiKey() => _fruitBankSettings.OpenAIApiKey;
+ public string GetModelName() => _fruitBankSettings.OpenAIModelName;
public void RegisterCallback(Action callback, Action onCompleteCallback, Action onErrorCallback)
{