AIPLugin
This commit is contained in:
parent
4b2cd32870
commit
e03a9cf6db
|
|
@ -0,0 +1,164 @@
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Routing;
|
||||||
|
using Nop.Plugin.Misc.AIPlugin.Components;
|
||||||
|
using Nop.Services.Cms;
|
||||||
|
using Nop.Services.Configuration;
|
||||||
|
using Nop.Services.Localization;
|
||||||
|
using Nop.Services.Plugins;
|
||||||
|
using Nop.Services.Security;
|
||||||
|
using Nop.Web.Framework.Infrastructure;
|
||||||
|
using Nop.Web.Framework.Menu;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Nop.Plugin.Misc.AIPlugin
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Main plugin class
|
||||||
|
/// </summary>
|
||||||
|
public class AIPlugin : BasePlugin, IWidgetPlugin
|
||||||
|
{
|
||||||
|
protected readonly IActionContextAccessor _actionContextAccessor;
|
||||||
|
private readonly ISettingService _settingService;
|
||||||
|
//private readonly IWebHelper _webHelper;
|
||||||
|
protected readonly IPermissionService _permissionService;
|
||||||
|
protected readonly ILocalizationService _localizationService;
|
||||||
|
protected readonly IUrlHelperFactory _urlHelperFactory;
|
||||||
|
private readonly IAdminMenu _adminMenu;
|
||||||
|
|
||||||
|
//handle AdminMenuCreatedEvent
|
||||||
|
|
||||||
|
|
||||||
|
public AIPlugin(IActionContextAccessor actionContextAccessor,
|
||||||
|
ISettingService settingService,
|
||||||
|
//IWebHelper webHelper,
|
||||||
|
ILocalizationService localizationService,
|
||||||
|
IPermissionService permissionService,
|
||||||
|
IUrlHelperFactory urlHelperFactory,
|
||||||
|
IAdminMenu adminMenu)
|
||||||
|
{
|
||||||
|
_actionContextAccessor = actionContextAccessor;
|
||||||
|
_settingService = settingService;
|
||||||
|
//_webHelper = webHelper;
|
||||||
|
_localizationService = localizationService;
|
||||||
|
_urlHelperFactory = urlHelperFactory;
|
||||||
|
_adminMenu = adminMenu;
|
||||||
|
_permissionService = permissionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- INSTALL ---
|
||||||
|
public override async Task InstallAsync()
|
||||||
|
{
|
||||||
|
// Default settings
|
||||||
|
var settings = new OpenAiSettings
|
||||||
|
{
|
||||||
|
ApiKey = string.Empty
|
||||||
|
};
|
||||||
|
await _settingService.SaveSettingAsync(settings);
|
||||||
|
|
||||||
|
await base.InstallAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- UNINSTALL ---
|
||||||
|
public override async Task UninstallAsync()
|
||||||
|
{
|
||||||
|
await _settingService.DeleteSettingAsync<OpenAiSettings>();
|
||||||
|
await base.UninstallAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- WIDGETS ---
|
||||||
|
public bool HideInWidgetList => false;
|
||||||
|
|
||||||
|
public Task<IList<string>> GetWidgetZonesAsync()
|
||||||
|
{
|
||||||
|
return Task.FromResult<IList<string>>(new List<string> { PublicWidgetZones.ProductBoxAddinfoBefore, PublicWidgetZones.ProductDetailsBottom });
|
||||||
|
}
|
||||||
|
|
||||||
|
//public string GetWidgetViewComponentName(string widgetZone)
|
||||||
|
//{
|
||||||
|
// return "ProductAIWidget"; // A ViewComponent neve
|
||||||
|
//}
|
||||||
|
|
||||||
|
// --- ADMIN MENÜ ---
|
||||||
|
//public async Task ManageSiteMapAsync(AdminMenuItem rootNode)
|
||||||
|
//{
|
||||||
|
// if (!await _permissionService.AuthorizeAsync(StandardPermission.Configuration.MANAGE_PLUGINS))
|
||||||
|
// return;
|
||||||
|
|
||||||
|
// var pluginNode = new AdminMenuItem
|
||||||
|
// {
|
||||||
|
// SystemName = "AIPlugin.Configure",
|
||||||
|
// Title = "AI Assistant",
|
||||||
|
// Url = $"{_webHelper.GetStoreLocation()}Admin/AIPluginAdmin/Configure",
|
||||||
|
// Visible = true
|
||||||
|
// };
|
||||||
|
// rootNode.ChildNodes.Add(pluginNode);
|
||||||
|
// //return Task.CompletedTask;
|
||||||
|
//}
|
||||||
|
|
||||||
|
public async Task ManageSiteMapAsync(AdminMenuItem rootNode)
|
||||||
|
{
|
||||||
|
if (!await _permissionService.AuthorizeAsync(StandardPermission.Configuration.MANAGE_PLUGINS))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var configurationItem = rootNode.ChildNodes.FirstOrDefault(node => node.SystemName.Equals("Configuration"));
|
||||||
|
if (configurationItem is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var shippingItem = configurationItem.ChildNodes.FirstOrDefault(node => node.SystemName.Equals("Shipping"));
|
||||||
|
var widgetsItem = configurationItem.ChildNodes.FirstOrDefault(node => node.SystemName.Equals("Widgets"));
|
||||||
|
if (shippingItem is null && widgetsItem is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var index = shippingItem is not null ? configurationItem.ChildNodes.IndexOf(shippingItem) : -1;
|
||||||
|
if (index < 0)
|
||||||
|
index = widgetsItem is not null ? configurationItem.ChildNodes.IndexOf(widgetsItem) : -1;
|
||||||
|
if (index < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
configurationItem.ChildNodes.Insert(index + 1, new AdminMenuItem
|
||||||
|
{
|
||||||
|
|
||||||
|
Visible = true,
|
||||||
|
SystemName = "AI plugins",
|
||||||
|
Title = await _localizationService.GetResourceAsync("Plugins.Misc.SignalRApi.Menu.AI"),
|
||||||
|
IconClass = "far fa-dot-circle",
|
||||||
|
ChildNodes = new List<AdminMenuItem>
|
||||||
|
{
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
// SystemName = "AIPlugin.Configure",
|
||||||
|
// Title = "AI Assistant",
|
||||||
|
// Url = $"{_webHelper.GetStoreLocation()}Admin/AIPluginAdmin/Configure",
|
||||||
|
// Visible = true
|
||||||
|
Visible = true,
|
||||||
|
SystemName = PluginDescriptor.SystemName,
|
||||||
|
Title = PluginDescriptor.FriendlyName,
|
||||||
|
IconClass = "far fa-circle",
|
||||||
|
Url = _adminMenu.GetMenuItemUrl("AIPlugin", "Configure"),
|
||||||
|
//Url = "Admin/SignalRApi/Configure",
|
||||||
|
//ControllerName = "SignalRApi",
|
||||||
|
//ActionName = "Configure",
|
||||||
|
//RouteValues = new RouteValueDictionary { { "area", AreaNames.ADMIN } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetConfigurationPageUrl()
|
||||||
|
{
|
||||||
|
return _urlHelperFactory.GetUrlHelper(_actionContextAccessor.ActionContext).RouteUrl("Plugin.Misc.AIPlugin.Configure");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type GetWidgetViewComponent(string widgetZone)
|
||||||
|
{
|
||||||
|
if (widgetZone is null)
|
||||||
|
throw new ArgumentNullException(nameof(widgetZone));
|
||||||
|
|
||||||
|
var zones = GetWidgetZonesAsync().Result;
|
||||||
|
|
||||||
|
return zones.Any(widgetZone.Equals) ? typeof(ProductAIWidgetViewComponent) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Nop.Plugin.Misc.AIPlugin.Areas.Admin.Models;
|
||||||
|
using Nop.Plugin.Misc.AIPlugin;
|
||||||
|
//using Nop.Plugin.Misc.AIPlugin;
|
||||||
|
using Nop.Services.Configuration;
|
||||||
|
using Nop.Web.Framework.Controllers;
|
||||||
|
using Nop.Services.Messages;
|
||||||
|
|
||||||
|
namespace Nop.Plugin.Misc.AIPlugin.Controllers
|
||||||
|
{
|
||||||
|
[Area("Admin")]
|
||||||
|
public class AIPluginAdminController : BasePluginController
|
||||||
|
{
|
||||||
|
private readonly INotificationService _notificationService;
|
||||||
|
private readonly ISettingService _settingService;
|
||||||
|
private readonly OpenAiSettings _settings;
|
||||||
|
|
||||||
|
public AIPluginAdminController(INotificationService notificationService, ISettingService settingService, OpenAiSettings settings)
|
||||||
|
{
|
||||||
|
_notificationService = notificationService;
|
||||||
|
_settingService = settingService;
|
||||||
|
_settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult Configure()
|
||||||
|
{
|
||||||
|
var model = new ConfigureModel
|
||||||
|
{
|
||||||
|
ApiKey = _settings.ApiKey
|
||||||
|
};
|
||||||
|
return View("~/Plugins/Misc.AIPlugin/Views/Configure/Configure.cshtml", model);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IActionResult> Configure(ConfigureModel model)
|
||||||
|
{
|
||||||
|
_settings.ApiKey = model.ApiKey;
|
||||||
|
await _settingService.SaveSettingAsync(_settings);
|
||||||
|
_notificationService.SuccessNotification("Beállítások mentve.");
|
||||||
|
return RedirectToAction("Configure");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
using Nop.Web.Framework.Mvc.ModelBinding;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Nop.Plugin.Misc.AIPlugin.Areas.Admin.Models
|
||||||
|
{
|
||||||
|
public record ConfigureModel
|
||||||
|
{
|
||||||
|
[NopResourceDisplayName("Plugins.AIPlugin.Fields.ApiKey")]
|
||||||
|
public string ApiKey { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
@model Nop.Plugin.Misc.AIPlugin.Models.ConfigureModel
|
||||||
|
|
||||||
|
@{
|
||||||
|
Layout = "_AdminLayout";
|
||||||
|
Html.SetActiveMenuItemSystemName("AiAssistant.Configure");
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2>AI Assistant Plugin - Beállítások</h2>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form asp-controller="AiAssistantAdmin" asp-action="Configure" method="post">
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="ApiKey"></label>
|
||||||
|
<input asp-for="ApiKey" class="form-control" />
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Mentés</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
@inherits Nop.Web.Framework.Mvc.Razor.NopRazorPage<TModel>
|
||||||
|
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
|
@addTagHelper *, Nop.Web.Framework
|
||||||
|
|
||||||
|
@using Microsoft.AspNetCore.Mvc.ViewFeatures
|
||||||
|
@using Nop.Web.Framework.UI
|
||||||
|
@using Nop.Web.Framework.Extensions
|
||||||
|
@using System.Text.Encodings.Web
|
||||||
|
@using Nop.Services.Events
|
||||||
|
@using Nop.Web.Framework.Events
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Nop.Web.Framework.Components;
|
||||||
|
|
||||||
|
namespace Nop.Plugin.Misc.AIPlugin.Components;
|
||||||
|
|
||||||
|
[ViewComponent(Name = "Custom")]
|
||||||
|
public class CustomViewComponent : NopViewComponent
|
||||||
|
{
|
||||||
|
public CustomViewComponent()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public IViewComponentResult Invoke(int productId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Nop.Web.Framework.Components;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Nop.Plugin.Misc.AIPlugin.Components
|
||||||
|
{
|
||||||
|
|
||||||
|
[ViewComponent(Name = "ProductAIWidget")]
|
||||||
|
public class ProductAIWidgetViewComponent : NopViewComponent
|
||||||
|
{
|
||||||
|
public IViewComponentResult Invoke(string widgetZone, object additionalData)
|
||||||
|
{
|
||||||
|
if(additionalData is Nop.Web.Models.Catalog.ProductOverviewModel)
|
||||||
|
{
|
||||||
|
var product = additionalData as Nop.Web.Models.Catalog.ProductOverviewModel;
|
||||||
|
|
||||||
|
if (product == null)
|
||||||
|
return Content(""); // ne rendereljen semmit, ha nincs product
|
||||||
|
return View("~/Plugins/Misc.AIPlugin/Views/ProductAIListWidget.cshtml", product);
|
||||||
|
}
|
||||||
|
else if (additionalData is Nop.Web.Models.Catalog.ProductDetailsModel)
|
||||||
|
{
|
||||||
|
var product = additionalData as Nop.Web.Models.Catalog.ProductDetailsModel;
|
||||||
|
|
||||||
|
if (product == null)
|
||||||
|
return Content(""); // ne rendereljen semmit, ha nincs product
|
||||||
|
return View("~/Plugins/Misc.AIPlugin/Views/ProductAIWidget.cshtml", product);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Content(""); // ne rendereljen semmit, ha nem productDetailModel vagy productOverviewModel
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
using Nop.Core;
|
||||||
|
|
||||||
|
namespace Nop.Plugin.Misc.AIPlugin.Domains;
|
||||||
|
|
||||||
|
public partial class CustomTable : BaseEntity
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Razor;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Nop.Core.Infrastructure;
|
||||||
|
|
||||||
|
namespace Nop.Plugin.Misc.AIPlugin.Infrastructure;
|
||||||
|
|
||||||
|
public class PluginNopStartup : INopStartup
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Add and configure any of the middleware
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">Collection of service descriptors</param>
|
||||||
|
/// <param name="configuration">Configuration of the application</param>
|
||||||
|
public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.Configure<RazorViewEngineOptions>(options =>
|
||||||
|
{
|
||||||
|
options.ViewLocationExpanders.Add(new ViewLocationExpander());
|
||||||
|
});
|
||||||
|
|
||||||
|
//register services and interfaces
|
||||||
|
//services.AddScoped<CustomModelFactory, ICustomerModelFactory>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configure the using of added middleware
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="application">Builder for configuring an application's request pipeline</param>
|
||||||
|
public void Configure(IApplicationBuilder application)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets order of this startup configuration implementation
|
||||||
|
/// </summary>
|
||||||
|
public int Order => 3000;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
using Microsoft.AspNetCore.Routing;
|
||||||
|
using Nop.Web.Framework.Mvc.Routing;
|
||||||
|
|
||||||
|
namespace Nop.Plugin.Misc.AIPlugin.Infrastructure;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents plugin route provider
|
||||||
|
/// </summary>
|
||||||
|
public class RouteProvider : IRouteProvider
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Register routes
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="endpointRouteBuilder">Route builder</param>
|
||||||
|
public void RegisterRoutes(IEndpointRouteBuilder endpointRouteBuilder)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a priority of route provider
|
||||||
|
/// </summary>
|
||||||
|
public int Priority => 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
using Microsoft.AspNetCore.Mvc.Razor;
|
||||||
|
|
||||||
|
namespace Nop.Plugin.Misc.AIPlugin.Infrastructure;
|
||||||
|
|
||||||
|
public class ViewLocationExpander : IViewLocationExpander
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked by a <see cref="T:Microsoft.AspNetCore.Mvc.Razor.RazorViewEngine" /> to determine the values that would be consumed by this instance
|
||||||
|
/// of <see cref="T:Microsoft.AspNetCore.Mvc.Razor.IViewLocationExpander" />. The calculated values are used to determine if the view location
|
||||||
|
/// has changed since the last time it was located.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The <see cref="T:Microsoft.AspNetCore.Mvc.Razor.ViewLocationExpanderContext" /> for the current view location
|
||||||
|
/// expansion operation.</param>
|
||||||
|
public void PopulateValues(ViewLocationExpanderContext context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked by a <see cref="T:Microsoft.AspNetCore.Mvc.Razor.RazorViewEngine" /> to determine potential locations for a view.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The <see cref="T:Microsoft.AspNetCore.Mvc.Razor.ViewLocationExpanderContext" /> for the current view location
|
||||||
|
/// expansion operation.</param>
|
||||||
|
/// <param name="viewLocations">The sequence of view locations to expand.</param>
|
||||||
|
/// <returns>A list of expanded view locations.</returns>
|
||||||
|
public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
|
||||||
|
{
|
||||||
|
if (context.AreaName == "Admin")
|
||||||
|
{
|
||||||
|
viewLocations = new[] { $"/Plugins/Nop.Plugin.Misc.AIPlugin/Areas/Admin/Views/{context.ControllerName}/{context.ViewName}.cshtml" }.Concat(viewLocations);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
viewLocations = new[] { $"/Plugins/Nop.Plugin.Misc.AIPlugin/Views/{context.ControllerName}/{context.ViewName}.cshtml" }.Concat(viewLocations);
|
||||||
|
}
|
||||||
|
|
||||||
|
return viewLocations;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
using FluentMigrator.Builders.Create.Table;
|
||||||
|
using Nop.Data.Mapping.Builders;
|
||||||
|
using Nop.Plugin.Misc.AIPlugin.Domains;
|
||||||
|
|
||||||
|
namespace Nop.Plugin.Misc.AIPlugin.Mapping.Builders;
|
||||||
|
|
||||||
|
public class PluginBuilder : NopEntityBuilder<CustomTable>
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Apply entity configuration
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="table">Create table expression builder</param>
|
||||||
|
public override void MapEntity(CreateTableExpressionBuilder table)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
using Nop.Data.Mapping;
|
||||||
|
|
||||||
|
namespace Nop.Plugin.Misc.AIPlugin.Mapping;
|
||||||
|
|
||||||
|
public partial class NameCompatibility : INameCompatibility
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets table name for mapping with the type
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<Type, string> TableNames => new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets column name for mapping with the entity's property and type
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<(Type, string), string> ColumnName => new();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
using FluentMigrator;
|
||||||
|
using Nop.Data.Extensions;
|
||||||
|
using Nop.Data.Migrations;
|
||||||
|
using Nop.Plugin.Misc.AIPlugin.Domains;
|
||||||
|
|
||||||
|
namespace Nop.Plugin.Misc.AIPlugin.Migrations;
|
||||||
|
|
||||||
|
//2024-10-31
|
||||||
|
[NopMigration("2025-08-29 12:07:22", "Nop.Plugin.Misc.AIPlugin schema", MigrationProcessType.Installation)]
|
||||||
|
public class SchemaMigration : AutoReversingMigration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Collect the UP migration expressions
|
||||||
|
/// </summary>
|
||||||
|
public override void Up()
|
||||||
|
{
|
||||||
|
Create.TableFor<CustomTable>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<OutputPath>$(SolutionDir)\Presentation\Nop.Web\Plugins\Misc.AIPlugin</OutputPath>
|
||||||
|
<OutDir>$(OutputPath)</OutDir>
|
||||||
|
<!--Set this parameter to true to get the dlls copied from the NuGet cache to the output of your project.
|
||||||
|
You need to set this parameter to true if your plugin has a nuget package
|
||||||
|
to ensure that the dlls copied from the NuGet cache to the output of your project-->
|
||||||
|
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="logo.jpg" />
|
||||||
|
<None Remove="plugin.json" />
|
||||||
|
<None Remove="Views\_ViewImports.cshtml" />
|
||||||
|
<None Remove="Areas\Admin\Views\_ViewImports.cshtml" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="logo.jpg">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="plugin.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Views\_ViewImports.cshtml">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Areas\Admin\Views\_ViewImports.cshtml">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="Areas\Admin\Views\_ViewImports.cshtml">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="Views\_ViewImports.cshtml">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="$(SolutionDir)\Presentation\Nop.Web\Nop.Web.csproj" />
|
||||||
|
<ClearPluginAssemblies Include="$(SolutionDir)\Build\ClearPluginAssemblies.proj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Areas\Admin\Components\" />
|
||||||
|
<Folder Include="Areas\Admin\Extensions\" />
|
||||||
|
<Folder Include="Areas\Admin\Factories\" />
|
||||||
|
<Folder Include="Areas\Admin\Validators\" />
|
||||||
|
<Folder Include="Controllers\" />
|
||||||
|
<Folder Include="Extensions\" />
|
||||||
|
<Folder Include="Factories\" />
|
||||||
|
<Folder Include="Models\" />
|
||||||
|
<Folder Include="Validators\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="Views\ProductAIListWidget.cshtml">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Views\ProductAIWidget.cshtml">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- This target execute after "Build" target -->
|
||||||
|
<Target Name="NopTarget" AfterTargets="Build">
|
||||||
|
<MSBuild Projects="@(ClearPluginAssemblies)" Properties="PluginPath=$(OutDir)" Targets="NopClear" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
using global::Nop.Core.Configuration;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Nop.Plugin.Misc.AIPlugin
|
||||||
|
{
|
||||||
|
public class OpenAiSettings : ISettings
|
||||||
|
{
|
||||||
|
public string ApiKey { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
using Nop.Plugin.Misc.AIPlugin;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Nop.Services.Configuration;
|
||||||
|
|
||||||
|
namespace Nop.Plugin.Misc.AIPlugin.Services
|
||||||
|
{
|
||||||
|
|
||||||
|
public class OpenAiService
|
||||||
|
{
|
||||||
|
private readonly OpenAiSettings _settings;
|
||||||
|
|
||||||
|
public OpenAiService(OpenAiSettings settings)
|
||||||
|
{
|
||||||
|
_settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> AskAsync(string prompt)
|
||||||
|
{
|
||||||
|
using var client = new HttpClient();
|
||||||
|
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _settings.ApiKey);
|
||||||
|
|
||||||
|
var body = new
|
||||||
|
{
|
||||||
|
model = "gpt-4o-mini",
|
||||||
|
messages = new[]
|
||||||
|
{
|
||||||
|
new { role = "system", content = "You are a helpful assistant." },
|
||||||
|
new { role = "user", content = prompt }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var content = new StringContent(JsonSerializer.Serialize(body), Encoding.UTF8, "application/json");
|
||||||
|
var response = await client.PostAsync("https://api.openai.com/v1/chat/completions", content);
|
||||||
|
|
||||||
|
var json = await response.Content.ReadAsStringAsync();
|
||||||
|
using var doc = JsonDocument.Parse(json);
|
||||||
|
|
||||||
|
return doc.RootElement.GetProperty("choices")[0].GetProperty("message").GetProperty("content").GetString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
@model Nop.Web.Models.Catalog.ProductOverviewModel
|
||||||
|
|
||||||
|
@if (Model != null)
|
||||||
|
{
|
||||||
|
<div class="ai-question-box">
|
||||||
|
<h5>Kérdezz a termékről!</h5>
|
||||||
|
<textarea id="ai-question"></textarea>
|
||||||
|
<button id="ask-ai-btn" class="btn btn-primary">Kérdezz</button>
|
||||||
|
<div id="ai-answer"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$("#ask-ai-btn").click(function() {
|
||||||
|
$.post("/AiAssistant/Ask", { productId: "@Model.Id", question: $("#ai-question").val() }, function (data) {
|
||||||
|
$("#ai-answer").html(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
@model Nop.Web.Models.Catalog.ProductDetailsModel
|
||||||
|
|
||||||
|
@if (Model != null)
|
||||||
|
{
|
||||||
|
<div class="ai-question-box">
|
||||||
|
<h5>Kérdezz a termékről!</h5>
|
||||||
|
<textarea id="ai-question"></textarea>
|
||||||
|
<button id="ask-ai-btn" class="btn btn-primary">Kérdezz</button>
|
||||||
|
<div id="ai-answer"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$("#ask-ai-btn").click(function() {
|
||||||
|
$.post("/AiAssistant/Ask", { productId: "@Model.Id", question: $("#ai-question").val() }, function (data) {
|
||||||
|
$("#ai-answer").html(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
@inherits Nop.Web.Framework.Mvc.Razor.NopRazorPage<TModel>
|
||||||
|
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
|
@addTagHelper *, Nop.Web.Framework
|
||||||
|
|
||||||
|
@using Microsoft.AspNetCore.Mvc.ViewFeatures
|
||||||
|
@using Nop.Web.Framework.UI
|
||||||
|
@using Nop.Web.Framework.Extensions
|
||||||
|
@using System.Text.Encodings.Web
|
||||||
|
@using Nop.Services.Events
|
||||||
|
@using Nop.Web.Framework.Events
|
||||||
|
@using Nop.Web.Framework.Infrastructure
|
||||||
|
@using Nop.Plugin.Misc.AIPlugin
|
||||||
|
@* @using Nop.Plugin.Misc.AIPlugin.Models *@
|
||||||
|
@using Nop.Plugin.Misc.AIPlugin.Services
|
||||||
|
@* @using Nop.Plugin.Misc.AIPlugin.Hubs *@
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 3.0 KiB |
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"Group": "Misc",
|
||||||
|
"FriendlyName": "AIPlugin",
|
||||||
|
"SystemName": "Misc.AIPlugin",
|
||||||
|
"Version": "1.00",
|
||||||
|
"SupportedVersions": [
|
||||||
|
"4.80"
|
||||||
|
],
|
||||||
|
"Author": "Adam Gelencser",
|
||||||
|
"DisplayOrder": 1,
|
||||||
|
"FileName": "Nop.Plugin.Misc.AIPlugin.dll",
|
||||||
|
"Description": ""
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue