diff --git a/BLAIzor.csproj b/BLAIzor.csproj index 35ed0f9..d2ed224 100644 --- a/BLAIzor.csproj +++ b/BLAIzor.csproj @@ -7,6 +7,13 @@ BLAIzor + + + + + + + @@ -30,9 +37,11 @@ - + + + @@ -57,6 +66,9 @@ Always + + Always + Always diff --git a/BLAIzor.sln b/BLAIzor.sln index b40073c..b649b0b 100644 --- a/BLAIzor.sln +++ b/BLAIzor.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 17.10.35004.147 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BLAIzor", "BLAIzor.csproj", "{A7A021E4-C303-4DF0-B55B-CE3233137085}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SeemGen.Tests", "SeemGen.Tests\SeemGen.Tests.csproj", "{9B3FF465-BD0D-F50F-F19B-E2D1338E7FE6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +17,10 @@ Global {A7A021E4-C303-4DF0-B55B-CE3233137085}.Debug|Any CPU.Build.0 = Debug|Any CPU {A7A021E4-C303-4DF0-B55B-CE3233137085}.Release|Any CPU.ActiveCfg = Release|Any CPU {A7A021E4-C303-4DF0-B55B-CE3233137085}.Release|Any CPU.Build.0 = Release|Any CPU + {9B3FF465-BD0D-F50F-F19B-E2D1338E7FE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9B3FF465-BD0D-F50F-F19B-E2D1338E7FE6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9B3FF465-BD0D-F50F-F19B-E2D1338E7FE6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9B3FF465-BD0D-F50F-F19B-E2D1338E7FE6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Components/App.razor b/Components/App.razor index c5981d1..11dffec 100644 --- a/Components/App.razor +++ b/Components/App.razor @@ -12,6 +12,7 @@ + @@ -23,6 +24,7 @@ + @* - + + diff --git a/Components/Layout/MainLayout.razor b/Components/Layout/MainLayout.razor index 1ec84bc..d98ce7d 100644 --- a/Components/Layout/MainLayout.razor +++ b/Components/Layout/MainLayout.razor @@ -1,6 +1,6 @@ @using BLAIzor.Services @inherits LayoutComponentBase - + @Body
diff --git a/Components/Pages/CreateForm.razor b/Components/Pages/CreateForm.razor index 966e2c4..1605fcf 100644 --- a/Components/Pages/CreateForm.razor +++ b/Components/Pages/CreateForm.razor @@ -8,7 +8,7 @@ @using BLAIzor.Components.Layout @attribute [Authorize] @layout AdminLayout -@inject ContentEditorService ContentEditorService +@inject ContentEditorAIService ContentEditorAIService

Create a new from from pdf or word

@@ -68,7 +68,7 @@ private async Task> CallAiForFieldExtraction(string plainText) { - var jsonResult = await ContentEditorService.AnalyzeGroupedFormFieldsFromText(plainText); + var jsonResult = await ContentEditorAIService.AnalyzeGroupedFormFieldsFromText(plainText); Console.WriteLine($"📄 PDF form AI response: {jsonResult}"); try diff --git a/Components/Pages/Index.razor b/Components/Pages/Index.razor index d158f86..d9a0877 100644 --- a/Components/Pages/Index.razor +++ b/Components/Pages/Index.razor @@ -1,4 +1,4 @@ -@page "/" +@page "/" @page "/menu/{topic?}" @inherits MainPageBase @using BLAIzor.Models @@ -21,44 +21,52 @@ -
- -
+
+ +
-
- Home - - @* +
+ Home + @{ + if(SiteInfo!= null) + { + if (!string.IsNullOrEmpty(SiteInfo.BackgroundVideo)) + { + + } + } + } + @* *@ -
+
- @*
*@ + @*
*@ -
-
+
@@ -190,19 +199,6 @@ private string ChatGptResponse = string.Empty; private bool isRecording = false; - // private string FirstColumnClass = ""; - // private bool isEmailFormVisible = false; - - // private ContactFormModel ContactFormModel = new(); - // // private string? SuccessMessage; - // // private string? ErrorMessage; - // private string? DocumentEmailAddress = ""; - - private string dynamicallyLoadedCss = string.Empty; - - private string Menu; - - private void AllowAIVoice() { AiVoicePermitted = true; @@ -210,7 +206,7 @@ private void MuteAI() { AiVoicePermitted = false; - } + } protected override async Task OnAfterRenderAsync(bool firstRender) { @@ -234,7 +230,7 @@ SelectedBrandName = "default"; } Subdomain = HttpContextAccessor.HttpContext?.Items["Subdomain"]?.ToString(); - SiteInfo = await _scopedContentService.GetSiteInfoByNameAsync(Subdomain); + SiteInfo = await _contentEditorService.GetSiteInfoByNameAsync(Subdomain); if (SiteInfo != null && SiteInfo.IsPublished) { @@ -253,6 +249,8 @@ STTEnabled = false; } _scopedContentService.SelectedSiteId = SiteId; + ContentCollectionName = SiteInfo.VectorCollectionName ?? "default_content_collection"; + Console.Write("------------------------"); // Load the CSS template for the selected brand from the database @@ -273,16 +271,19 @@ Console.Write($"------------------------ {SiteInfo.MenuItems}, {SiteId}, {SiteInfo.TemplateId}, {SiteInfo.SiteName}"); Menu = await GetMenuList(SiteId); + MenuItems = await GetMenuItems(SiteId); if (string.IsNullOrEmpty(HtmlContent.ToString())) { - if(!string.IsNullOrWhiteSpace(topic)) + if (!string.IsNullOrWhiteSpace(topic)) { UserInput = topic; - await ChatGptService.ProcessContentRequest(SessionId, UserInput, SiteId, (int)SiteInfo.TemplateId!, TemplateCollectionName, Menu, true); + await ChatGptService.ProcessContentRequest(SessionId, UserInput, SiteId, (int)SiteInfo.TemplateId!, ContentCollectionName, Menu, true); } else - { + { await ChatGptService.GetChatGptWelcomeMessage(SessionId, SiteId, TemplateCollectionName, Menu); + SiteModel = await ChatGptService.InitSite(SessionId, SiteId, TemplateCollectionName, Menu); + //await ChatGptService.ProcessContentRequest(SessionId, MenuItems.FirstOrDefault(), SiteId, (int)SiteInfo.TemplateId!, TemplateCollectionName, Menu, true); } // HtmlContent = await ChatGptService.GetChatGptWelcomeMessage(); // UserInput = "Sumerize for me, what is this website about, and what can I do on this website?"; @@ -340,7 +341,7 @@ VoiceEnabled = configuration?.GetSection("AiSettings")?.GetValue("VoiceActivated") ?? false; } - private async void UpdateContent(string receivedSessionId, string content) + private async void UpdateContent(string receivedSessionId, string content, MenuItem? menuItem) { if (receivedSessionId == SessionId) // Only accept messages meant for this tab { diff --git a/Components/Pages/MainPageBase.cs b/Components/Pages/MainPageBase.cs index 3794794..87ce250 100644 --- a/Components/Pages/MainPageBase.cs +++ b/Components/Pages/MainPageBase.cs @@ -1,19 +1,17 @@ using BLAIzor.Models; using BLAIzor.Services; -using Google.Api; using Google.Cloud.Speech.V1; using Microsoft.AspNetCore.Components; using Microsoft.JSInterop; -using System.Collections; +using Radzen; using System.Text; using System.Text.Json; -using UglyToad.PdfPig.DocumentLayoutAnalysis; namespace BLAIzor.Components.Pages { public class MainPageBase : ComponentBase - { + { public string SelectedBrandName = "default"; [Inject] protected ScopedContentService _scopedContentService { get; set; } [Inject] protected ContentEditorService _contentEditorService { get; set; } @@ -21,6 +19,7 @@ namespace BLAIzor.Components.Pages [Inject] protected HttpClient Http { get; set; } [Inject] protected IJSRuntime jsRuntime { get; set; } [Inject] protected AIService ChatGptService { get; set; } + [Inject] NotificationService NotificationService { get; set; } public static readonly Dictionary _instances = new(); @@ -34,6 +33,7 @@ namespace BLAIzor.Components.Pages public string StatusContent = ""; public string UserInput = string.Empty; public string TemplateCollectionName = "html_snippets"; + public string ContentCollectionName = ""; public bool VoiceEnabled; public bool TTSEnabled; @@ -49,6 +49,13 @@ namespace BLAIzor.Components.Pages // private string? ErrorMessage; public string? DocumentEmailAddress = ""; + public string Menu; + public List MenuItems = new(); + public string dynamicallyLoadedCss = string.Empty; + public MenuItem currentMenuItem = new(); + + public WebsiteContentModel SiteModel = new(); + public void DoSharedWork() { // Logic here @@ -91,13 +98,13 @@ namespace BLAIzor.Components.Pages public async Task> GetMenuItems(int siteId) { - List menuItems = (await _contentEditorService.GetMenuItemsBySiteIdAsync(siteId)).Where(m => m.ShowInMainMenu == true).OrderBy(m => m.SortOrder).ToList(); + List menuItems = (await _contentEditorService.GetMenuItemsBySiteIdWithChildrenAsync(siteId)).Where(m => m.ShowInMainMenu == true).OrderBy(m => m.SortOrder).ToList(); return menuItems; } private string GetApiKey() => - configuration?.GetSection("ElevenLabsAPI")?.GetValue("ApiKey") ?? string.Empty; + configuration?.GetSection("ElevenLabsAPI")?.GetValue("ApiKey") ?? string.Empty; public async Task ConvertTextToSpeech(string textContent) { @@ -211,14 +218,26 @@ namespace BLAIzor.Components.Pages { HtmlContent.Clear(); var menu = await GetMenuList(SiteId); - var menuItem = (await GetMenuItems(SiteId)).Where(m => m.Name == input).FirstOrDefault(); + var menuList = await GetMenuItems(SiteId); + + var menuItem = CompareMenuItemNames(input, menuList); if (menuItem == null) { - await ChatGptService.ProcessContentRequest(SessionId, input, SiteId, (int)SiteInfo.TemplateId!, TemplateCollectionName, menu, forceUnmodified); + await ChatGptService.ProcessContentRequest(SessionId, input, SiteId, (int)SiteInfo.TemplateId!, ContentCollectionName, menu, forceUnmodified); } else { - await ChatGptService.ProcessContentRequest(SessionId, menuItem, SiteId, (int)SiteInfo.TemplateId!, TemplateCollectionName, menu, forceUnmodified); + currentMenuItem = menuItem; + if (!string.IsNullOrEmpty(menuItem.StoredHtml)) + { + + HtmlContent.Clear(); + HtmlContent.Append(menuItem.StoredHtml); + } + else + { + await ChatGptService.ProcessContentRequest(SessionId, menuItem, SiteId, (int)SiteInfo.TemplateId!, ContentCollectionName, menu, forceUnmodified); + } } UserInput = string.Empty; } @@ -296,16 +315,40 @@ namespace BLAIzor.Components.Pages Console.Write("openEmail with: " + emailAddress); } - public async Task SendMessage() { Console.WriteLine("Button clicked!"); var menu = await GetMenuList(SiteId); HtmlContent.Clear(); - await ChatGptService.ProcessUserIntent(SessionId, UserInput, SiteId, (int)SiteInfo.TemplateId!, TemplateCollectionName, menu); + await ChatGptService.ProcessUserIntent(SessionId, UserInput, SiteId, (int)SiteInfo.TemplateId!, ContentCollectionName, menu); UserInput = string.Empty; } + public MenuItem CompareMenuItemNames(string input, List menuList) + { + var parent = menuList.FirstOrDefault(ml => ml.Name == input); + if (parent != null) + { + return parent; + } + + foreach (var item in menuList) + { + var child = item.Children.FirstOrDefault(ch => ch.Name == input); + if (child != null) + { + return child; + } + } + return null; // or throw, or return a default + } + + public void ShowNotification(NotificationMessage message) + { + NotificationService.Notify(message); + } + + } } diff --git a/Components/Pages/ManageContentGroups.razor b/Components/Pages/ManageContentGroups.razor new file mode 100644 index 0000000..8678003 --- /dev/null +++ b/Components/Pages/ManageContentGroups.razor @@ -0,0 +1,127 @@ +@page "/site/{SiteInfoId:int}/content-groups" +@using BLAIzor.Components.Layout +@using BLAIzor.Models +@using BLAIzor.Services +@using Microsoft.AspNetCore.Components.Authorization +@layout AdminLayout +@inject ContentEditorService contentEditorService +@inject NavigationManager Navigation +@attribute [Authorize] + +@if (isLoading) +{ +

Loading content groups...

+} +else +{ + @foreach (var group in groups) + { + if (selectedGroupId == group.Id) + { + +
+ + +
+ + + +
+
+
+ } + else + { +
+
+ @group.Name
+ @group.Type +
+ +
+ } + } + + +} + + + +@code { + [Parameter] + public int SiteInfoId { get; set; } + + private List groups = new(); + private bool isLoading = true; + + private int? selectedGroupId = null; + + private void SelectGroup(int groupId) + { + selectedGroupId = groupId; + } + + private void DeselectGroup() + { + selectedGroupId = null; + } + + + protected override async Task OnInitializedAsync() + { + isLoading = true; + groups = (await contentEditorService.GetContentGroupsBySiteInfoIdAsync(SiteInfoId)) + .Where(g => g.SiteInfoId == SiteInfoId) + .OrderByDescending(g => g.LastUpdated) + .ToList(); + isLoading = false; + } + + private void EditGroup(ContentGroup group) + { + Navigation.NavigateTo($"/content-group/{group.Id}/items"); + } + + private async Task SaveGroup(ContentGroup group) + { + group.LastUpdated = DateTime.UtcNow; + group.Version = group.Version + 1; + var result = await contentEditorService.UpdateContentGroupByIdAsync(group); + if(result != null) ; + } + + private async Task DeleteGroup(ContentGroup group) + { + + var result = await contentEditorService.DeleteContentGroupByIdAsync(group.Id); ; + groups.Remove(group); + } + + private async Task AddNewGroup() + { + var newGroup = new ContentGroup + { + SiteInfoId = SiteInfoId, + Name = "New Group", + Slug = $"group-{DateTime.UtcNow.Ticks}", + Type = "manual", + VectorSize = 384, + EmbeddingModel = "default", + CreatedAt = DateTime.UtcNow, + LastUpdated = DateTime.UtcNow, + Version = 1 + }; + var result = await contentEditorService.CreateContentGroupAsync(newGroup); + if(result!=null) + { + groups.Insert(0, newGroup); + } + } + +} diff --git a/Components/Pages/ManageSiteInfo.razor b/Components/Pages/ManageSiteInfo.razor index dc13f66..41d124e 100644 --- a/Components/Pages/ManageSiteInfo.razor +++ b/Components/Pages/ManageSiteInfo.razor @@ -5,33 +5,35 @@ @using BLAIzor.Services @using Microsoft.AspNetCore.Components.Authorization @layout AdminLayout -@inject ScopedContentService SiteInfoService +@inject ContentEditorService _contentEditorService @inject AuthenticationStateProvider AuthenticationStateProvider @inject CustomAuthenticationStateProvider CustomAuthProvider -

Site Information

- +