455 lines
18 KiB
Plaintext
455 lines
18 KiB
Plaintext
@page "/"
|
|
@page "/menu/{topic?}"
|
|
@inherits MainPageBase
|
|
@using BLAIzor.Models
|
|
@using BLAIzor.Services
|
|
@using BLAIzor.Components.Partials
|
|
@using Google.Cloud.Speech.V1
|
|
@using Microsoft.AspNetCore.Identity.UI.Services
|
|
@using System.Text
|
|
@using System.Net
|
|
@using System.Text.Json
|
|
@using Sidio.Sitemap.Blazor
|
|
@rendermode InteractiveServer
|
|
@inject NavigationManager _navigationManager
|
|
@inject IHttpContextAccessor HttpContextAccessor
|
|
@inject DesignTemplateService DesignTemplateService
|
|
@inject CssTemplateService CssTemplateService
|
|
@inject CssInjectorService CssService
|
|
@attribute [Sitemap]
|
|
|
|
<ErrorBoundary>
|
|
<ChildContent>
|
|
|
|
<div class="page" style="z-index: 1">
|
|
<NewNavMenu Menu="@MenuItems" BrandName="@SelectedBrandName" SiteId="SiteId" OnMenuClicked=@MenuClick></NewNavMenu>
|
|
<main>
|
|
|
|
<article class="content text-center" style="position: relative; z-index: 4;">
|
|
|
|
<PageTitle>Home</PageTitle>
|
|
@{
|
|
if (SiteInfo != null)
|
|
{
|
|
if (!string.IsNullOrEmpty(SiteInfo.BackgroundVideo))
|
|
{
|
|
<VideoComponent site="SiteInfo" />
|
|
}
|
|
}
|
|
}
|
|
@* <HeadContent>
|
|
|
|
<style id="seemgen-style">@dynamicallyLoadedCss</style>
|
|
|
|
</HeadContent> *@
|
|
|
|
<div id="maincontrol">
|
|
|
|
|
|
@* <div class="hoverslide"> *@
|
|
|
|
<div class="displaysearch">
|
|
<div class="searchBox">
|
|
@if (VoiceEnabled)
|
|
{
|
|
if (STTEnabled)
|
|
{
|
|
<button id="recButton" class="voicebutton bg-panel-gradient" onclick="startRecording()"><i class="fa-solid fa-microphone"></i></button>
|
|
<button id="stopButton" class="voicebutton bg-danger" onclick="stopRecording()" hidden><i class="fa-solid fa-microphone-slash"></i></button>
|
|
}
|
|
}
|
|
<input @oninput="(e) => UserInput = e.Value.ToString()"
|
|
@onkeydown="@Enter" class="searchInput" type="text" name="" value="@UserInput" placeholder="Ask any question">
|
|
<button data-hint="ask anything" class="searchButton border-0" @onclick="SendUserQuery" href="#">
|
|
<i class="fa-solid fa-hexagon-nodes-bolt" style="font-size:20px"></i>
|
|
</button>
|
|
</div>
|
|
|
|
@{
|
|
@if (VoiceEnabled)
|
|
{
|
|
// if (STTEnabled)
|
|
// {
|
|
// <button id="recButton" class="btn btn-primary voicebutton" onclick="startRecording()"><i class="fa-solid fa-microphone"></i></button>
|
|
// <button id="stopButton" class="btn btn-primary voicebutton" onclick="stopRecording()" hidden><i class="fa-solid fa-microphone-slash"></i></button>
|
|
// }
|
|
|
|
if (TTSEnabled)
|
|
{
|
|
if (!AiVoicePermitted)
|
|
{
|
|
<button data-hint="listen" class="btn btn-primary voicebutton" style="display: inline-block" @onclick="AllowAIVoice">
|
|
<i class="fa-solid fa-volume-xmark"></i>
|
|
|
|
</button>
|
|
}
|
|
else
|
|
{
|
|
<button data-hint="listen" class="btn btn-primary voicebutton" style="display: inline-block" @onclick="MuteAI"><i class="fa-solid fa-volume-high"></i></button>
|
|
}
|
|
<audio id="audioPlayer" hidden style="display: none;"></audio>
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
</div>
|
|
|
|
@* Type anything *@
|
|
|
|
@* </div> *@
|
|
</div>
|
|
|
|
|
|
<div id="currentContent">
|
|
<p id="recordingText"></p>
|
|
<AnimateOnRender CssClass="animate__animated animate__backInUp">
|
|
@{
|
|
if (!string.IsNullOrEmpty(HtmlContent.ToString()))
|
|
{
|
|
|
|
if (isEmailFormVisible)
|
|
{
|
|
<div class="container-fluid">
|
|
<div class="row">
|
|
<div class="pt-5 @FirstColumnClass">
|
|
@((MarkupString)HtmlContent.ToString())
|
|
</div>
|
|
<div class="pt-5 col-12 col-md-6">
|
|
<ContactFormComponent ContactFormModel="@ContactFormModel" DocumentEmailAddress="@DocumentEmailAddress" OnDataChanged="@ContentChangedInForm"></ContactFormComponent>
|
|
<button @onclick="CancelEmail" class="btn btn-primary">Cancel</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
}
|
|
else
|
|
{
|
|
<div class="pt-5 @FirstColumnClass">
|
|
@((MarkupString)HtmlContent.ToString())
|
|
</div>
|
|
}
|
|
}
|
|
else
|
|
{
|
|
<div class="text-center row" style="height: 70vh;">
|
|
<p>@StatusContent</p>
|
|
<div class="mydiv"></div>
|
|
<div class="mydiv"></div>
|
|
<div class="mydiv"></div>
|
|
<div class="mydiv"></div>
|
|
<div class="mydiv"></div>
|
|
|
|
|
|
</div>
|
|
}
|
|
|
|
|
|
}
|
|
</AnimateOnRender>
|
|
</div>
|
|
|
|
<button class="btn btn-primary" @onclick="HomeClick"><i class="fa-solid fa-rotate"></i></button>
|
|
@* <FormWizardComponent SessionId="@sessionId"></FormWizardComponent> *@
|
|
|
|
</article>
|
|
</main>
|
|
<FooterComponent MenuString="@Menu" OnMenuClicked=@MenuClick></FooterComponent>
|
|
</div>
|
|
|
|
</ChildContent>
|
|
<ErrorContent Context="ex">
|
|
<p role="alert">An error occurred: @ex.Message</p>
|
|
<p>Please try again later.</p>
|
|
@* You can log the exception here if you want *@
|
|
@{
|
|
Console.WriteLine($"Error caught by ErrorBoundary: {ex.Message}");
|
|
}
|
|
</ErrorContent>
|
|
</ErrorBoundary>
|
|
|
|
<script>
|
|
|
|
var sessionId = null;
|
|
|
|
function setSessionId(id) {
|
|
sessionId = id;
|
|
console.log("Session ID set:", sessionId);
|
|
}
|
|
|
|
function callAI(inputString) {
|
|
console.log(sessionId);
|
|
DotNet.invokeMethodAsync('BLAIzor', 'CallCSharpMethod2', inputString, sessionId, false)
|
|
.then(response => console.log(response))
|
|
.catch(error => console.error(error));
|
|
}
|
|
|
|
</script>
|
|
<script>
|
|
function openCalendar(calendlyUserName) {
|
|
console.log(calendlyUserName);
|
|
Calendly.initPopupWidget({
|
|
url: 'https://calendly.com/' + calendlyUserName + '?name=JohnDoe&email=john.doe@example.com'
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<script>
|
|
function openContactForm(emailAddress) {
|
|
console.log(emailAddress);
|
|
if (emailAddress) {
|
|
DotNet.invokeMethodAsync('BLAIzor', 'OpenEmailForm2', emailAddress)
|
|
}
|
|
}
|
|
</script>
|
|
|
|
@code {
|
|
[Parameter]
|
|
public string? topic { get; set; }
|
|
// public static Index myHome;
|
|
private string? Subdomain;
|
|
|
|
private string ChatGptResponse = string.Empty;
|
|
private bool isRecording = false;
|
|
|
|
private void AllowAIVoice()
|
|
{
|
|
AiVoicePermitted = true;
|
|
}
|
|
private void MuteAI()
|
|
{
|
|
AiVoicePermitted = false;
|
|
}
|
|
|
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
{
|
|
if (firstRender)
|
|
{
|
|
await _logger.InfoAsync("Index component OnafterRender.", $"{SiteId}");
|
|
await jsRuntime.InvokeVoidAsync("setSessionId", SessionId);
|
|
await jsRuntime.InvokeVoidAsync("initHints");
|
|
|
|
// sessionId = Guid.NewGuid().ToString();
|
|
// _instances[sessionId] = this;
|
|
|
|
Console.Write($"\n\n SessionId: {SessionId}\n\n");
|
|
// _scopedContentService.OnBrandNameChanged += HandleBrandNameChanged;
|
|
if (!string.IsNullOrEmpty(_scopedContentService.SelectedBrandName))
|
|
{
|
|
SelectedBrandName = _scopedContentService.SelectedBrandName;
|
|
}
|
|
else
|
|
{
|
|
_scopedContentService.SelectedBrandName = "default";
|
|
SelectedBrandName = "default";
|
|
}
|
|
Subdomain = HttpContextAccessor.HttpContext?.Items["Subdomain"]?.ToString();
|
|
SiteInfo = await _contentEditorService.GetSiteInfoByNameAsync(Subdomain);
|
|
if (SiteInfo != null && SiteInfo.IsPublished)
|
|
{
|
|
|
|
SiteId = SiteInfo.Id;
|
|
|
|
_scopedContentService.SelectedBrandName = SiteInfo.SiteName;
|
|
|
|
TTSEnabled = SiteInfo.TTSActive;
|
|
STTEnabled = SiteInfo.STTActive;
|
|
}
|
|
else
|
|
{
|
|
SiteId = 1;
|
|
_scopedContentService.SelectedBrandName = "default";
|
|
TTSEnabled = false;
|
|
STTEnabled = false;
|
|
}
|
|
_scopedContentService.SelectedSiteId = SiteId;
|
|
ContentCollectionName = SiteInfo.VectorCollectionName ?? "default_content_collection";
|
|
|
|
|
|
Console.Write("------------------------");
|
|
// Load the CSS template for the selected brand from the database
|
|
var designTemplate = await DesignTemplateService.GetByIdAsync((int)SiteInfo.TemplateId!);
|
|
var cssTemplate = await CssTemplateService.GetByDesignTemplateIdAsync((int)SiteInfo.TemplateId);
|
|
TemplateCollectionName = designTemplate.QDrandCollectionName;
|
|
|
|
if (cssTemplate != null)
|
|
{
|
|
dynamicallyLoadedCss = cssTemplate.CssContent; // Assuming Content holds the CSS string
|
|
var cssPath = await CssTemplateService.SaveTempCssFileAsync(dynamicallyLoadedCss, SessionId);
|
|
await jsRuntime.InvokeVoidAsync("seemgen.injectCssFile", cssPath);
|
|
|
|
//await CssService.ApplyCssAsync(dynamicallyLoadedCss);
|
|
}
|
|
|
|
|
|
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))
|
|
{
|
|
UserInput = topic;
|
|
await ChatGptService.InitSite(SessionId, SiteInfo, TemplateCollectionName, Menu);
|
|
await ChatGptService.ProcessContentRequest(SessionId, UserInput, SiteId, (int)SiteInfo.TemplateId!, ContentCollectionName, Menu, true);
|
|
}
|
|
else
|
|
{
|
|
await ChatGptService.InitSite(SessionId, SiteInfo, TemplateCollectionName, Menu);
|
|
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?";
|
|
// await ChatGptService.ProcessUserIntent(SessionId, UserInput, SiteId, (int)SiteInfo.TemplateId!, CollectionName, Menu);
|
|
}
|
|
UserInput = string.Empty;
|
|
// await InvokeAsync(StateHasChanged);
|
|
_initVoicePending = true;
|
|
}
|
|
|
|
if (_initVoicePending)
|
|
{
|
|
Console.WriteLine("PENDING VOICE--------------------------------------------------");
|
|
_initVoicePending = false;
|
|
await jsRuntime.InvokeVoidAsync("initVoiceRecorder", "ProcessAudio2");
|
|
}
|
|
}
|
|
|
|
public async void MenuClick(string menuName)
|
|
{
|
|
await CallCSharpMethod2(menuName, SessionId, true);
|
|
}
|
|
|
|
public void HomeClick()
|
|
{
|
|
//ChatGptService.OnContentReceived -= UpdateContent;
|
|
ChatGptService.OnContentReceived -= UpdateContent;
|
|
_navigationManager.Refresh(true);
|
|
}
|
|
|
|
private void CancelEmail()
|
|
{
|
|
FirstColumnClass = "";
|
|
isEmailFormVisible = false;
|
|
StateHasChanged();
|
|
}
|
|
|
|
public Index()
|
|
{
|
|
myHome = this; // Set the static reference to the current instance
|
|
}
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
await _logger.InfoAsync("Index component initialized.", $"{SiteId}");
|
|
_scopedContentService.OnBrandNameChanged += HandleBrandNameChanged;
|
|
// ChatGptService.OnContentReceived += UpdateContent;
|
|
ChatGptService.OnContentReceived += UpdateContent;
|
|
ChatGptService.OnContentReceiveFinished += UpdateFinished;
|
|
// ChatGptService.OnStatusChangeReceived += UpdateStatus;
|
|
ChatGptService.OnStatusChangeReceived += UpdateStatus;
|
|
ChatGptService.OnTextContentAvailable += UpdateTextContentForVoice;
|
|
SessionId = _scopedContentService.SessionId;
|
|
_instances[SessionId] = this;
|
|
VoiceEnabled = configuration?.GetSection("AiSettings")?.GetValue<bool>("VoiceActivated") ?? false;
|
|
}
|
|
|
|
private async void UpdateContent(string receivedSessionId, string content, MenuItem? menuItem)
|
|
{
|
|
if (receivedSessionId == SessionId) // Only accept messages meant for this tab
|
|
{
|
|
|
|
HtmlContent.Clear();
|
|
HtmlContent.Append(content);
|
|
//InvokeAsync(StateHasChanged); // Ensures UI updates dynamically
|
|
await InvokeAsync(() =>
|
|
{
|
|
StateHasChanged();
|
|
});
|
|
//_scopedContentService.CurrentDOM = await jsRuntime.InvokeAsync<string>("getDivContent", "currentContent");
|
|
}
|
|
}
|
|
|
|
// private async void UpdateTextContentForVoice(string receivedSessionId, string content)
|
|
// {
|
|
// Console.WriteLine("UPDATETEXTCONTENT called");
|
|
// if (receivedSessionId == SessionId) // Only accept messages meant for this tab
|
|
// {
|
|
|
|
// TextContent = content;
|
|
// await ConvertTextToSpeech(content);
|
|
// //_scopedContentService.CurrentDOM = await jsRuntime.InvokeAsync<string>("getDivContent", "currentContent");
|
|
// }
|
|
// }
|
|
|
|
private async void UpdateFinished(string receivedSessionId)
|
|
{
|
|
if (receivedSessionId == SessionId) // Only accept messages meant for this tab
|
|
{
|
|
Console.WriteLine("Content update finished");
|
|
var result = await jsRuntime.InvokeAsync<object>("getDivContent", "currentContent");
|
|
//await ConvertTextToSpeech();
|
|
_scopedContentService.CurrentDOM = JsonSerializer.Serialize(result);
|
|
Console.Write(_scopedContentService.CurrentDOM);
|
|
}
|
|
}
|
|
|
|
private async Task ContentChangedInForm()
|
|
{
|
|
var result = await jsRuntime.InvokeAsync<object>("getDivContent", "currentContent");
|
|
_scopedContentService.CurrentDOM = JsonSerializer.Serialize(result);
|
|
Console.Write(_scopedContentService.CurrentDOM);
|
|
}
|
|
|
|
private async void UpdateStatus(string receivedSessionId, string content)
|
|
{
|
|
if (receivedSessionId == SessionId) // Only accept messages meant for this tab
|
|
{
|
|
StatusContent = content;
|
|
//InvokeAsync(StateHasChanged); // Ensures UI updates dynamically
|
|
await InvokeAsync(() =>
|
|
{
|
|
StateHasChanged();
|
|
});
|
|
}
|
|
}
|
|
|
|
public async Task Enter(KeyboardEventArgs e)
|
|
{
|
|
if (e.Code == "Enter" || e.Code == "NumpadEnter")
|
|
{
|
|
var menu = await GetMenuList(SiteId);
|
|
HtmlContent.Clear();
|
|
string input = "Please tell me more about: " + UserInput;
|
|
await ChatGptService.ProcessUserIntent(SessionId, input, SiteId, (int)SiteInfo.TemplateId!, TemplateCollectionName, menu);
|
|
UserInput = string.Empty;
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
dynamicallyLoadedCss = "";
|
|
HtmlContent.Clear();
|
|
_scopedContentService.OnBrandNameChanged -= HandleBrandNameChanged;
|
|
ChatGptService.OnContentReceived -= UpdateContent;
|
|
ChatGptService.OnContentReceiveFinished -= UpdateFinished;
|
|
ChatGptService.OnStatusChangeReceived -= UpdateStatus;
|
|
ChatGptService.OnTextContentAvailable -= UpdateTextContentForVoice;
|
|
}
|
|
|
|
public async ValueTask DisposeAsync()
|
|
{
|
|
await CssTemplateService.DeleteSessionCssFile(SessionId);
|
|
_scopedContentService.OnBrandNameChanged -= HandleBrandNameChanged;
|
|
ChatGptService.OnContentReceived -= UpdateContent;
|
|
ChatGptService.OnContentReceiveFinished -= UpdateFinished;
|
|
ChatGptService.OnStatusChangeReceived -= UpdateStatus;
|
|
ChatGptService.OnTextContentAvailable -= UpdateTextContentForVoice;
|
|
}
|
|
|
|
|
|
}
|