+
@Body
diff --git a/Components/Layout/PreviewLayout.razor b/Components/Layout/PreviewLayout.razor
new file mode 100644
index 0000000..70d46c4
--- /dev/null
+++ b/Components/Layout/PreviewLayout.razor
@@ -0,0 +1,65 @@
+@using BLAIzor.Services
+@inherits LayoutComponentBase
+@inject ScopedContentService _scopedContentService;
+@inject NavigationManager _navigationManager;
+
+
+
+
+
+ @* *@
+
+
+ @Body
+
+
+
+
+
+ An unhandled error has occurred.
+
Reload
+
🗙
+
+
+
+
+
+
+@code{
+
+ public void HomeClick()
+ {
+ _navigationManager.Refresh(true);
+ }
+
+ protected override void OnInitialized()
+ {
+
+ }
+
+
+}
diff --git a/Components/Layout/PreviewLayout.razor.css b/Components/Layout/PreviewLayout.razor.css
new file mode 100644
index 0000000..038baf1
--- /dev/null
+++ b/Components/Layout/PreviewLayout.razor.css
@@ -0,0 +1,96 @@
+.page {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+}
+
+main {
+ flex: 1;
+}
+
+.sidebar {
+ background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
+}
+
+.top-row {
+ background-color: #f7f7f7;
+ border-bottom: 1px solid #d6d5d5;
+ justify-content: flex-end;
+ height: 3.5rem;
+ display: flex;
+ align-items: center;
+}
+
+ .top-row ::deep a, .top-row ::deep .btn-link {
+ white-space: nowrap;
+ margin-left: 1.5rem;
+ text-decoration: none;
+ }
+
+ .top-row ::deep a:hover, .top-row ::deep .btn-link:hover {
+ text-decoration: underline;
+ }
+
+ .top-row ::deep a:first-child {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+@media (max-width: 640.98px) {
+ .top-row {
+ justify-content: space-between;
+ }
+
+ .top-row ::deep a, .top-row ::deep .btn-link {
+ margin-left: 0;
+ }
+}
+
+@media (min-width: 641px) {
+ .page {
+ flex-direction: row;
+ }
+
+ .sidebar {
+ width: 250px;
+ height: 100vh;
+ position: sticky;
+ top: 0;
+ }
+
+ .top-row {
+ position: sticky;
+ top: 0;
+ z-index: 1;
+ }
+
+ .top-row.auth ::deep a:first-child {
+ flex: 1;
+ text-align: right;
+ width: 0;
+ }
+
+ .top-row, article {
+ padding-left: 2rem !important;
+ padding-right: 1.5rem !important;
+ }
+}
+
+#blazor-error-ui {
+ background: lightyellow;
+ bottom: 0;
+ box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
+ display: none;
+ left: 0;
+ padding: 0.6rem 1.25rem 0.7rem 1.25rem;
+ position: fixed;
+ width: 100%;
+ z-index: 1000;
+}
+
+ #blazor-error-ui .dismiss {
+ cursor: pointer;
+ position: absolute;
+ right: 0.75rem;
+ top: 0.5rem;
+ }
diff --git a/Components/Pages/CreateForm.razor b/Components/Pages/CreateForm.razor
new file mode 100644
index 0000000..966e2c4
--- /dev/null
+++ b/Components/Pages/CreateForm.razor
@@ -0,0 +1,91 @@
+@page "/createform/{SiteId:int}"
+@using System.IO
+@using BLAIzor.Models
+@using BLAIzor.Services
+@using Microsoft.AspNetCore.Components.Forms
+@using System.Text
+@using UglyToad.PdfPig
+@using BLAIzor.Components.Layout
+@attribute [Authorize]
+@layout AdminLayout
+@inject ContentEditorService ContentEditorService
+
+Create a new from from pdf or word
+
+
+
+@if (ExtractedFields.Any())
+{
+ Extracted Fields:
+
+ @foreach (var field in ExtractedFields)
+ {
+ - @field.GroupName: @field.Fields.Count (@(field.Repeatable?"Repeatable":"Non repeateble"))
+ }
+
+
+
+
+}
+
+@code {
+ [Parameter]
+ public int SiteId { get; set; }
+ private string PdfText = string.Empty;
+ private List ExtractedFields = new();
+
+ private async Task HandleFileSelected(InputFileChangeEventArgs e)
+ {
+ var file = e.File;
+ if (file == null || !file.ContentType.Contains("pdf")) return;
+
+ var tempPath = Path.Combine(Path.GetTempPath(), file.Name);
+
+ await using (var stream = file.OpenReadStream())
+ await using (var fileStream = File.Create(tempPath))
+ {
+ await stream.CopyToAsync(fileStream);
+ }
+
+ PdfText = ExtractPdfText(tempPath);
+
+ // Call OpenAI to analyze and extract structured fields
+ ExtractedFields = await CallAiForFieldExtraction(PdfText);
+ }
+
+ private string ExtractPdfText(string filePath)
+ {
+ var sb = new StringBuilder();
+ using (var document = PdfDocument.Open(filePath))
+ {
+ foreach (var page in document.GetPages())
+ {
+ sb.AppendLine(page.Text);
+ }
+ }
+ return sb.ToString();
+ }
+
+ private async Task> CallAiForFieldExtraction(string plainText)
+ {
+ var jsonResult = await ContentEditorService.AnalyzeGroupedFormFieldsFromText(plainText);
+ Console.WriteLine($"📄 PDF form AI response: {jsonResult}");
+
+ try
+ {
+ var groups = System.Text.Json.JsonSerializer.Deserialize>(jsonResult, new System.Text.Json.JsonSerializerOptions
+ {
+ PropertyNameCaseInsensitive = true
+ });
+
+ return groups ?? new List();
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"❌ Error parsing AI JSON: {ex.Message}");
+ return new List();
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/Components/Pages/EditTemplate.razor b/Components/Pages/EditTemplate.razor
index bd4eb47..a142a7c 100644
--- a/Components/Pages/EditTemplate.razor
+++ b/Components/Pages/EditTemplate.razor
@@ -15,13 +15,7 @@
Edit Design Template
-
- @* *@
- @if (!string.IsNullOrEmpty(currentCssTemplate.CssContent))
- {
-
- }
-
+
@if (isLoading)
{
@@ -32,15 +26,21 @@ else
+
+
+
+
+
-
-
-
-
+
+
+
+
-
@@ -48,26 +48,20 @@ else
-
-
-
-
-
-
+
-
-
+
+
@* *@
@@ -78,18 +72,46 @@ else
- foreach(var snippet in SnippetList)
- {
-
- }
+
+
+
+
+ @{
+ foreach (var snippet in SnippetList)
+ {
+
+
+
+ }
+ }
+
+
+
+
+
+
+
+
-
+
+
}
+
+
@code {
[Parameter]
public int TemplateId { get; set; }
@@ -100,17 +122,27 @@ else
private bool hasCss = false;
private bool hasCollection = false;
private List
SnippetList = [];
+ private string SessionId;
+ private static readonly Dictionary _instances = new();
protected override async Task OnInitializedAsync()
{
- await LoadTemplate();
+ SessionId = Guid.NewGuid().ToString();
+ _instances[SessionId] = this;
+
+
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
+ await JSRuntime.InvokeVoidAsync("setSessionId", SessionId);
await JSRuntime.InvokeVoidAsync("setHtmlEditorSourceMode");
+ await LoadTemplate();
+ var cssPath = await CssTemplateService.SaveTempCssFileAsync(currentCssTemplate.CssContent, SessionId);
+ await JSRuntime.InvokeVoidAsync("seemgen.injectCssFile", cssPath);
+
}
}
@@ -123,21 +155,21 @@ else
currentCssTemplate = await CssTemplateService.GetByDesignTemplateIdAsync(TemplateId);
var currentCollection = await QDrantService.GetCollectionByNameAsync(currentTemplate.QDrandCollectionName);
Console.Write(currentCollection);
- if(currentCssTemplate == null)
+ if (currentCssTemplate == null)
{
hasCss = false;
currentCssTemplate = new();
- currentCssTemplate.DesignTemplateId = TemplateId;
+ currentCssTemplate.DesignTemplateId = TemplateId;
}
else
{
hasCss = true;
}
- if(!string.IsNullOrEmpty(currentCollection))
+ if (!string.IsNullOrEmpty(currentCollection))
{
hasCollection = true;
var collectionCount = await QDrantService.GetCollectionCount(currentTemplate.QDrandCollectionName);
- for(int i=1; i <= collectionCount; i++)
+ for (int i = 1; i <= collectionCount; i++)
{
var snippet = await QDrantService.GetSnippetAsync(i, currentTemplate.QDrandCollectionName);
var selectedPoint = JsonConvert.DeserializeObject(snippet)!;
@@ -149,11 +181,12 @@ else
}
else
{
- //let's create a collection
+ //let's create a collection
var result = QDrantService.CreateQdrantCollectionAsync(currentTemplate.QDrandCollectionName);
}
isLoading = false;
+ await InvokeAsync(StateHasChanged);
}
private async Task SaveTemplate()
@@ -161,7 +194,7 @@ else
isLoading = true;
currentCssTemplate.CssContent = currentCssTemplate.CssContent.Trim();
- if(hasCss)
+ if (hasCss)
{
// Update the CSS template content
currentCssTemplate.LastUpdated = DateTime.UtcNow;
@@ -214,11 +247,11 @@ else
private async Task SaveSnippets()
{
//I want to update all items without gaps in the ids always 1 to x
- for (int i=1; i<=SnippetList.Count(); i++)
+ for (int i = 1; i <= SnippetList.Count(); i++)
{
- SnippetList[i-1].Id = i;
+ SnippetList[i - 1].Id = i;
- }
+ }
await HtmlSnippetProcessor.ProcessAndStoreTemplateSnippetAsync(currentTemplate.QDrandCollectionName, SnippetList);
}
diff --git a/Components/Pages/Index.razor b/Components/Pages/Index.razor
index 49e7bc5..2e65a0d 100644
--- a/Components/Pages/Index.razor
+++ b/Components/Pages/Index.razor
@@ -44,7 +44,7 @@
UserInput = e.Value.ToString()"
@onkeydown="@Enter" class="searchInput" type="text" name="" value="@UserInput" placeholder="Ask any question">
-
@@ -114,7 +114,7 @@
function callAI(inputString) {
console.log(sessionId);
- DotNet.invokeMethodAsync('BLAIzor', 'CallCSharpMethod2', inputString, sessionId)
+ DotNet.invokeMethodAsync('BLAIzor', 'CallCSharpMethod2', inputString, sessionId, false)
.then(response => console.log(response))
.catch(error => console.error(error));
}
@@ -288,7 +288,7 @@
public async void MenuClick(string menuName)
{
- await CallCSharpMethod2(menuName, sessionId);
+ await CallCSharpMethod2(menuName, sessionId, true);
}
public void HomeClick()
@@ -333,7 +333,7 @@
[JSInvokable("CallCSharpMethod2")]
- public static async Task CallCSharpMethod2(string input, string sessionId)
+ public static async Task CallCSharpMethod2(string input, string sessionId, bool forceUnModified = false)
{
// if (myHome != null)
// {
@@ -342,7 +342,7 @@
if (_instances.TryGetValue(sessionId, out var instance))
{
- await instance.HandleJsCall("Please tell me more about: " + input, sessionId);
+ await instance.HandleJsCall(input, sessionId, forceUnModified);
}
Console.Write("Button clicked:" + input);
}
@@ -485,21 +485,21 @@
UserInput = input;
await InvokeAsync(StateHasChanged);
- await ProcessWordFile();
+ await SendUserQuery();
//UserInput = string.Empty;
}
- public async Task HandleJsCall(string input, string sessionId)
+ public async Task HandleJsCall(string input, string sessionId, bool forceUnmodified)
{
HtmlContent.Clear();
await InvokeAsync(StateHasChanged);
UserInput = input;
- await ProcessWordFile();
+ await DisplayMenuContent(input, forceUnmodified);
UserInput = string.Empty;
await InvokeAsync(StateHasChanged);
}
- private async Task ProcessWordFile()
+ private async Task SendUserQuery()
{
if (!string.IsNullOrEmpty(UserInput))
{
@@ -510,6 +510,17 @@
}
}
+ private async Task DisplayMenuContent(string input, bool forceUnmodified)
+ {
+ if (!string.IsNullOrEmpty(UserInput))
+ {
+ HtmlContent.Clear();
+ var menu = await GetMenuList();
+ await ChatGptService.ProcessContentRequest(sessionId, UserInput, SiteId, (int)SiteInfo.TemplateId!, collectionName, menu, forceUnmodified);
+ UserInput = string.Empty;
+ }
+ }
+
private async Task GetMenuList()
{
List
+
+Forms linked to this site
+
+@if (siteInfo.FormDefinitions?.Count > 0)
+{
+
+ @foreach (var form in siteInfo.FormDefinitions)
+ {
+ -
+
+ @form.Title
+ @form.CreatedAt.ToString("yyyy-MM-dd HH:mm")
+
+ Edit
+
+ }
+
+}
+else
+{
+ No forms added yet.
+}
+
+
+ Add New Form
+
+
+
@code {
[Parameter]
public int SiteId { get; set; }
@@ -55,7 +83,7 @@
userId = CustomAuthProvider.GetUserId();
userName = CustomAuthProvider.GetUserName();
}
- siteInfo = await SiteInfoService.GetSiteInfoByIdAsync(SiteId) ?? new SiteInfo();
+ siteInfo = await SiteInfoService.GetSiteInfoWithFormsByIdAsync(SiteId) ?? new SiteInfo();
}
private async Task SaveSiteInfo()
diff --git a/Components/Pages/Preview.razor b/Components/Pages/Preview.razor
index baee92e..4235990 100644
--- a/Components/Pages/Preview.razor
+++ b/Components/Pages/Preview.razor
@@ -47,7 +47,7 @@
UserInput = e.Value.ToString()"
@onkeydown="@Enter" class="searchInput" type="text" name="" value="@UserInput" placeholder="Ask any question">
-
+
@@ -114,7 +114,7 @@
function callAI(inputString) {
console.log(sessionId);
- DotNet.invokeMethodAsync('BLAIzor', 'CallCSharpMethod3', inputString, sessionId)
+ DotNet.invokeMethodAsync('BLAIzor', 'CallCSharpMethod3', inputString, sessionId, false)
.then(response => console.log(response))
.catch(error => console.error(error));
}
@@ -220,7 +220,7 @@
public async void MenuClick(string menuName)
{
- await CallCSharpMethod3(menuName, sessionId);
+ await CallCSharpMethod3(menuName, sessionId, true);
}
public void HomeClick()
@@ -284,12 +284,12 @@
[JSInvokable("CallCSharpMethod3")]
- public static async Task CallCSharpMethod3(string input, string sessionId)
+ public static async Task CallCSharpMethod3(string input, string sessionId, bool forceUnmodified)
{
if (_instances.TryGetValue(sessionId, out var instance))
{
- await instance.HandleJsCall("Please search for me: " + input, sessionId);
+ await instance.HandleJsCall("Please search for me: " + input, sessionId, forceUnmodified);
}
Console.Write("Button clicked:" + input);
}
@@ -471,22 +471,22 @@
UserInput = input;
await InvokeAsync(StateHasChanged);
- await ProcessWordFile();
+ await SendUserQuery();
//UserInput = string.Empty;
}
- public async Task HandleJsCall(string input, string sessionId)
+ public async Task HandleJsCall(string input, string sessionId, bool forceUnmodified)
{
HtmlContent.Clear();
await InvokeAsync(StateHasChanged);
UserInput = input;
Console.Write($"\n\n Input: {input} \n\n");
- await ProcessWordFile();
+ await DisplayMenuContent(input, forceUnmodified);
UserInput = string.Empty;
await InvokeAsync(StateHasChanged);
}
- private async Task ProcessWordFile()
+ private async Task SendUserQuery()
{
if (!string.IsNullOrEmpty(UserInput))
{
@@ -498,6 +498,18 @@
}
}
+ private async Task DisplayMenuContent(string input, bool forceUnmodified)
+ {
+ Console.WriteLine($"DisplayMenuContent 1: {input}");
+ if (!string.IsNullOrEmpty(UserInput))
+ {
+ HtmlContent.Clear();
+ var menu = await GetMenuList();
+ await ChatGptService.ProcessContentRequest(sessionId, UserInput, siteid, (int)SiteInfo.TemplateId!, collectionName, menu, forceUnmodified);
+ UserInput = string.Empty;
+ }
+ }
+
private async Task GetMenuList()
{
List