196 lines
6.7 KiB
Plaintext
196 lines
6.7 KiB
Plaintext
@* @page "/site/{SiteId:int}/generate" *@
|
|
@using BLAIzor.Models
|
|
@using BLAIzor.Services
|
|
@inject HttpClient Http
|
|
@inject ContentEditorAIService contentEditorAIService
|
|
@inject ContentEditorService contentEditorService
|
|
@inject NavigationManager Navigation
|
|
|
|
<div class="container-fluid">
|
|
|
|
@if (!string.IsNullOrEmpty(errorMessage))
|
|
{
|
|
<p class="text-red-600">Error: @errorMessage</p>
|
|
}
|
|
else if (isLoading || GeneratedItems.Any())
|
|
{
|
|
|
|
<RadzenLayout Style="grid-template-areas: 'rz-sidebar rz-header' 'rz-sidebar rz-body'">
|
|
<RadzenHeader>
|
|
<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" Gap="0">
|
|
<RadzenSidebarToggle Click="@(() => sidebarExpanded = !sidebarExpanded)" />
|
|
<RadzenLabel Text=@(totalItemsToGenerate.ToString() + " page(s)") />
|
|
</RadzenStack>
|
|
</RadzenHeader>
|
|
<RadzenSidebar @bind-Expanded="@sidebarExpanded">
|
|
<RadzenPanelMenu>
|
|
@foreach (var item in GeneratedItems)
|
|
{
|
|
<RadzenPanelMenuItem Text="@item.Title" Icon="account_box" Click="@(() => SelectContent(item.Title))" />
|
|
}
|
|
|
|
</RadzenPanelMenu>
|
|
<button class="btn btn-primary mt-4" @onclick="SaveContent">Save All</button>
|
|
</RadzenSidebar>
|
|
<RadzenBody Style="padding: 0px !important">
|
|
@if (isLoading)
|
|
{
|
|
<p class="text-muted">Generating... please wait.</p>
|
|
//progress bar
|
|
<RadzenProgressBar Value="@generationProgress" ShowValue="true" Style="width: 100%;" />
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
if (SelectedItem != null)
|
|
{
|
|
<textarea class="w-100 p-2 rounded text-white bg-panel-gradient" style="min-height:500px" @bind="SelectedItem.Content"></textarea>
|
|
}
|
|
}
|
|
</RadzenBody>
|
|
</RadzenLayout>
|
|
|
|
}
|
|
else
|
|
{
|
|
<button class="btn btn-success" @onclick="GeneratePageList">Start Generation</button>
|
|
}
|
|
</div>
|
|
|
|
@code {
|
|
[Parameter]
|
|
public int SiteId { get; set; }
|
|
[Parameter] public string SessionId { get; set; } = string.Empty;
|
|
|
|
private SiteInfo site;
|
|
private bool isLoading = false;
|
|
private string errorMessage = string.Empty;
|
|
private List<ContentItem> GeneratedItems = new();
|
|
private ContentGroup defaultGroup;
|
|
private ContentItem SelectedItem;
|
|
|
|
private double generationProgress = 0.0;
|
|
private int totalItemsToGenerate = 0;
|
|
|
|
|
|
bool sidebarExpanded = true;
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
site = await contentEditorService.GetSiteInfoByIdAsync(SiteId);
|
|
var existingGroup = await contentEditorService.GetContentGroupsBySiteInfoIdAsync(SiteId);
|
|
if (!existingGroup.Any(x => x.Name == "Pages"))
|
|
{
|
|
defaultGroup = new ContentGroup
|
|
{
|
|
SiteInfoId = SiteId,
|
|
Name = "Pages",
|
|
Slug = "pages",
|
|
Type = "Page",
|
|
VectorSize = 1536,
|
|
EmbeddingModel = "openai",
|
|
Version = 0
|
|
};
|
|
// Save ContentGroup to DB (if not already exists)
|
|
var response = await contentEditorService.CreateContentGroupAsync(defaultGroup);
|
|
defaultGroup = response;
|
|
}
|
|
else
|
|
{
|
|
defaultGroup = existingGroup.FirstOrDefault(x => x.Name == "Pages");
|
|
}
|
|
|
|
}
|
|
|
|
private void SelectContent(string title)
|
|
{
|
|
SelectedItem = GeneratedItems.Where(x => x.Title == title).FirstOrDefault();
|
|
StateHasChanged();
|
|
}
|
|
|
|
private async Task GeneratePageList()
|
|
{
|
|
isLoading = true;
|
|
errorMessage = string.Empty;
|
|
GeneratedItems.Clear();
|
|
|
|
try
|
|
{
|
|
var pageListPrompt = $"Based on the following site description, list the main website pages in {site.DefaultLanguage} as a comma-separated list. " +
|
|
"Only return the page titles." +
|
|
$"Site Description: {site.SiteDescription}";
|
|
|
|
var pageListText = await contentEditorAIService.GetMenuSuggestionsAsync(SessionId, pageListPrompt);
|
|
|
|
var pageTitles = pageListText
|
|
.Split(',', StringSplitOptions.RemoveEmptyEntries)
|
|
.Select(t => t.Trim())
|
|
.Where(t => !string.IsNullOrWhiteSpace(t))
|
|
.Distinct()
|
|
.ToList();
|
|
|
|
totalItemsToGenerate = pageTitles.Count;
|
|
|
|
foreach (var title in pageTitles)
|
|
{
|
|
var itemPrompt = $"Write a full, well-structured website page text content in {site.DefaultLanguage} for a page titled {title}. " +
|
|
$"The tone should be {site.Persona}, and match the following site description: '{site.SiteDescription}' " +
|
|
"Include headers, clear sections, and persuasive copy.";
|
|
|
|
var content = await contentEditorAIService.GetGeneratedContentAsync(SessionId, itemPrompt);
|
|
|
|
GeneratedItems.Add(new ContentItem
|
|
{
|
|
Title = title,
|
|
Description = $"A {defaultGroup.Type} called {title} of a website called {site.SiteName}.",
|
|
Language = site.DefaultLanguage,
|
|
Content = content,
|
|
ContentGroupId = defaultGroup.Id,
|
|
Tags = title,
|
|
IsPublished = false,
|
|
Version = 0
|
|
});
|
|
generationProgress += 100.0 / totalItemsToGenerate;
|
|
// Refresh UI after each item is generated
|
|
StateHasChanged();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
errorMessage = ex.Message;
|
|
}
|
|
finally
|
|
{
|
|
SelectedItem = GeneratedItems.FirstOrDefault();
|
|
isLoading = false;
|
|
StateHasChanged();
|
|
}
|
|
}
|
|
|
|
|
|
private async Task SaveContent()
|
|
{
|
|
isLoading = true;
|
|
errorMessage = string.Empty;
|
|
try
|
|
{
|
|
foreach (var item in GeneratedItems)
|
|
{
|
|
//await Http.PostAsJsonAsync("/api/contentitem", item);
|
|
await contentEditorService.CreateContentItemAsync(item, site.VectorCollectionName);
|
|
}
|
|
|
|
Navigation.NavigateTo($"/site/{SiteId}/overview");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
errorMessage = ex.Message;
|
|
}
|
|
finally
|
|
{
|
|
isLoading = false;
|
|
}
|
|
}
|
|
}
|