From dae8aef31f92ea28bd6a283f651cdeeec3ab3040 Mon Sep 17 00:00:00 2001 From: Ho Ngoc Hai Date: Thu, 26 Mar 2026 18:12:11 +0700 Subject: [PATCH] feat(settings): add AI Assistant configuration panel ShopSettings.razor: new "AI Assistant" section with: - Enable/disable toggle - Provider dropdown (OpenAI / OpenRouter / Claude) - Model input with per-provider placeholder - API Key input (password with show/hide toggle) - Per-provider hint text for getting API keys - System Prompt textarea (optional, default used if empty) - Save button with success/error feedback - Config loads on init, saves via BFF PUT /api/bff/ai/config Co-Authored-By: Claude Opus 4.6 (1M context) --- .../Pages/Admin/Shop/ShopSettings.razor | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Shop/ShopSettings.razor b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Shop/ShopSettings.razor index f7e835cd..1a294018 100644 --- a/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Shop/ShopSettings.razor +++ b/apps/web-client-tpos-net/src/WebClientTpos.Client/Pages/Admin/Shop/ShopSettings.razor @@ -78,6 +78,80 @@ } +@* ─── EN: AI Assistant Configuration ─── *@ +@* ─── VI: Cấu hình AI Assistant ─── *@ +
+
+

+ + AI Assistant +

+
+
+
+
+
Kích hoạt AI Assistant
+
Cho phép sử dụng trợ lý AI trong quản lý cửa hàng
+
+ +
+ + @if (_aiEnabled) + { +
+
+ + +
+
+ + "gpt-4o", "openrouter" => "anthropic/claude-sonnet-4", "claude" => "claude-sonnet-4-20250514", _ => "gpt-4o" })" + style="width:100%;padding:10px 14px;border-radius:8px;background:var(--admin-bg-elevated);border:1px solid var(--admin-border-subtle);color:var(--admin-text-primary);font-size:14px;" /> +
+
+ +
+ +
+ + +
+
+ @(_aiProvider switch { + "openai" => "Lấy API key tại platform.openai.com/api-keys", + "openrouter" => "Lấy API key tại openrouter.ai/keys", + "claude" => "Lấy API key tại console.anthropic.com/settings/keys", + _ => "" + }) +
+
+ +
+ + +
+ +
+ + @if (_aiMessage != null) + { + @_aiMessage + } +
+ } +
+
+ @* ─── EN: Publish / Activate shop (when Draft) ─── *@ @* ─── VI: Kích hoạt cửa hàng (khi đang ở trạng thái Draft) ─── *@ @if (ShopVerticalHelper.IsSetup(ShopStatus)) @@ -187,7 +261,49 @@ protected override async Task OnInitializedAsync() { if (ShopId != Guid.Empty) + { await LoadShopSettings(); + await LoadAiConfig(); + } + } + + private async Task LoadAiConfig() + { + try + { + var config = await DataService.GetAiChatConfigAsync(ShopId); + if (config != null) + { + _aiEnabled = config.Enabled; + _aiProvider = config.Provider ?? "openai"; + _aiApiKey = config.ApiKeyMasked ?? ""; + _aiModel = config.Model ?? ""; + _aiSystemPrompt = config.SystemPrompt ?? ""; + } + } + catch { /* AI config not found — defaults are fine */ } + } + + private async Task SaveAiConfig() + { + _aiSaving = true; + _aiMessage = null; + StateHasChanged(); + try + { + var ok = await DataService.UpdateAiChatConfigAsync(ShopId, new + { + provider = _aiProvider, + apiKey = _aiApiKey, + model = string.IsNullOrWhiteSpace(_aiModel) ? null : _aiModel, + systemPrompt = string.IsNullOrWhiteSpace(_aiSystemPrompt) ? null : _aiSystemPrompt, + enabled = _aiEnabled + }); + _aiSuccess = ok; + _aiMessage = ok ? "Đã lưu cấu hình AI!" : "Lỗi khi lưu."; + } + catch (Exception ex) { _aiSuccess = false; _aiMessage = $"Lỗi: {ex.Message}"; } + finally { _aiSaving = false; StateHasChanged(); } } private async Task LoadShopSettings() @@ -242,6 +358,18 @@ StateHasChanged(); } + // EN: AI config state + // VI: Trạng thái cấu hình AI + private bool _aiEnabled; + private string _aiProvider = "openai"; + private string _aiApiKey = ""; + private string _aiModel = ""; + private string _aiSystemPrompt = ""; + private bool _showApiKey; + private bool _aiSaving; + private string? _aiMessage; + private bool _aiSuccess; + // EN: Publish state // VI: Trạng thái kích hoạt private bool _isPublishing;