SeemGen/Components/Pages/Preview.razor

562 lines
20 KiB
Plaintext

@page "/preview/{siteid:int}"
@using BLAIzor.Models
@using BLAIzor.Services
@using Google.Cloud.Speech.V1
@using Microsoft.AspNetCore.Identity.UI.Services
@using BLAIzor.Components.Partials
@using System.Text
@using System.Text.Json
@inject AIService ChatGptService
@rendermode InteractiveServer
@inject IJSRuntime jsRuntime;
@inject IConfiguration configuration
@inject ContentService _contentService
@inject ContentEditorService _contentEditorService
@inject ScopedContentService _scopedContentService
@inject IEmailSender _emailService
@inject NavigationManager _navigationManager
@inject IHttpContextAccessor HttpContextAccessor
@inject DesignTemplateService DesignTemplateService
@inject CssTemplateService CssTemplateService
@inject CssInjectorService CssService
<div class="page" style="z-index: 1">
<NavMenu MenuString="@Menu" OnMenuClicked=@MenuClick></NavMenu>
<main>
<article class="content container text-center" style="position: relative; z-index: 4;">
<PageTitle>Home</PageTitle>
<VideoComponent SelectedBrandName="@selectedBrandName"/>
@* <HeadContent>
@if (!string.IsNullOrEmpty(dynamicallyLoadedCss))
{
<style>@dynamicallyLoadedCss</style>
}
</HeadContent> *@
<div id="maincontrol">
@* <div class="hoverslide"> *@
<div class="displaysearch">
<div class="searchBox">
<input @oninput="(e) => UserInput = e.Value.ToString()"
@onkeydown="@Enter" class="searchInput" type="text" name="" value="@UserInput" placeholder="Ask any question">
<button class="searchButton border-0" @onclick="SendUserQuery" href="#">
<i class="fa-solid fa-magnifying-glass"></i>
</button>
</div>
<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>
</div>
@* Type anything *@
@* </div> *@
</div>
<p id="recordingText"></p>
<div class="row" id="currentContent">
@{
if (!string.IsNullOrEmpty(HtmlContent.ToString()))
{
<div class="pt-5 @FirstColumnClass">
@((MarkupString)HtmlContent.ToString())
</div>
if (isEmailFormVisible)
{
<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>
}
}
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>
}
}
</div>
<button class="btn btn-primary" @onclick="HomeClick"><i class="fa-solid fa-rotate"></i></button>
</article>
</main>
</div>
<script>
var sessionId = null;
function setSessionId(id) {
sessionId = id;
console.log("Session ID set:", sessionId);
}
function callAI(inputString) {
console.log(sessionId);
DotNet.invokeMethodAsync('BLAIzor', 'CallCSharpMethod3', inputString, sessionId, false)
.then(response => console.log(response))
.catch(error => console.error(error));
}
var mediaRecorder;
var audioChunks = [];
var recButton = document.getElementById("recButton");
var stopButton = document.getElementById("stopButton");
var recText = document.getElementById("recordingText");
async function startRecording() {
if (recButton) {
recButton.hidden = true;
stopButton.hidden = false;
recText.textContent = "recording...";
}
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.ondataavailable = event => audioChunks.push(event.data);
mediaRecorder.onstop = () => {
const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
audioChunks = [];
console.log("media stopped");
const reader = new FileReader();
reader.onload = () => {
const base64Audio = reader.result.split(',')[1];
DotNet.invokeMethodAsync('BLAIzor', 'ProcessAudio3', base64Audio, sessionId);
};
reader.readAsDataURL(audioBlob);
};
mediaRecorder.start();
}
function stopRecording() {
mediaRecorder.stop();
var recButton = document.getElementById("recButton");
var stopButton = document.getElementById("stopButton");
var recText = document.getElementById("recordingText");
mediaRecorder.stream.getTracks().forEach(track => track.stop()); // Free memory
if (stopButton) {
stopButton.hidden = true;
recButton.hidden = false;
recText.textContent = "";
}
}
</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', 'OpenEmailForm3', emailAddress)
}
}
</script>
@code {
public static Preview myHome;
private string? Subdomain;
[Parameter]
public int siteid { get; set; }
public SiteInfo SiteInfo;
private StringBuilder HtmlContent = new();
private string StatusContent = "";
private string UserInput = string.Empty;
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 selectedBrandName = "";
private string dynamicallyLoadedCss = string.Empty;
private string collectionName = "html_snippets";
private string sessionId;
private static readonly Dictionary<string, Preview> _instances = new();
private string Menu;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await jsRuntime.InvokeVoidAsync("setSessionId", sessionId);
}
}
public async void MenuClick(string menuName)
{
await CallCSharpMethod3(menuName, sessionId, true);
}
public void HomeClick()
{
//ChatGptService.OnContentReceived -= UpdateContent;
AIService.OnContentReceived -= UpdateContent;
_navigationManager.Refresh(true);
}
// private async Task HandleValidSubmit()
// {
// try
// {
// // Simulate sending an email
// await ((EmailService)_emailService).SendEmailAsync(ContactFormModel, DocumentEmailAddress);
// SuccessMessage = "Thank you for contacting us! Your message has been sent.";
// ErrorMessage = null;
// // Clear the form
// ContactFormModel = new();
// }
// catch (Exception ex)
// {
// ErrorMessage = "An error occurred while sending your message. Please try again later.";
// SuccessMessage = null;
// }
// }
private void CancelEmail()
{
FirstColumnClass = "";
isEmailFormVisible = false;
StateHasChanged();
}
public Preview()
{
myHome = this; // Set the static reference to the current instance
}
[JSInvokable("OpenEmailForm3")]
public static async void OpenEmailForm3(string emailAddress)
{
if (myHome != null)
{
await myHome.DisplayEmailForm(emailAddress);
}
Console.Write("openEmail with: " + emailAddress);
}
public async Task DisplayEmailForm(string emailAddress)
{
FirstColumnClass = "col-12 col-md-6";
isEmailFormVisible = true;
DocumentEmailAddress = emailAddress;
StateHasChanged();
var result = await jsRuntime.InvokeAsync<object>("getDivContent", "currentContent");
_scopedContentService.CurrentDOM = JsonSerializer.Serialize(result);
// Console.Write($"{_scopedContentService.CurrentDOM}");
}
[JSInvokable("CallCSharpMethod3")]
public static async Task CallCSharpMethod3(string input, string sessionId, bool forceUnmodified)
{
if (_instances.TryGetValue(sessionId, out var instance))
{
await instance.HandleJsCall(input, sessionId, forceUnmodified);
}
Console.Write("Button clicked:" + input);
}
[JSInvokable("ProcessAudio3")]
public static async Task ProcessAudio3(string base64Audio, string sessionId)
{
Console.Write("audio incoming");
if (myHome != null)
{
var languageCode = "hu-HU";
if (myHome._scopedContentService.SelectedLanguage == "Hungarian")
{
languageCode = "hu-HU";
}
else if (myHome._scopedContentService.SelectedLanguage == "English")
{
languageCode = "en-US";
}
else if (myHome._scopedContentService.SelectedLanguage == "German")
{
languageCode = "de-DE";
}
var credentialsPath = myHome.configuration.GetSection("GoogleAPI").GetValue<string>("CredentialsPath");
Console.Write(credentialsPath);
var builder = new SpeechClientBuilder
{
CredentialsPath = credentialsPath
};
var speech = builder.Build();
byte[] audioBytes = Convert.FromBase64String(base64Audio);
myHome.HtmlContent.Clear();
var response = await speech.RecognizeAsync(new RecognitionConfig
{
Encoding = RecognitionConfig.Types.AudioEncoding.Mp3,
SampleRateHertz = 48000, // Match the actual sample rate
LanguageCode = languageCode
}, RecognitionAudio.FromBytes(audioBytes));
Console.Write("BILLED: " + response.TotalBilledTime);
foreach (var result in response.Results)
{
//Console.Write("RESULT: " + result.Alternatives.Count);
foreach (var alternative in result.Alternatives)
{
//Console.WriteLine($"Transcription: {alternative.Transcript}");
await myHome.HandleVoiceCommand(alternative.Transcript);
}
}
}
}
private async Task SendMessage()
{
Console.WriteLine("Button clicked!");
var menu = await GetMenuList();
await ChatGptService.ProcessUserIntent(sessionId, UserInput, siteid, (int)SiteInfo.TemplateId!, collectionName, menu);
UserInput = string.Empty;
}
protected override async Task OnParametersSetAsync()
{
sessionId = Guid.NewGuid().ToString();
_instances[sessionId] = this;
_scopedContentService.OnBrandNameChanged += HandleBrandNameChanged;
selectedBrandName = _scopedContentService.SelectedBrandName;
// Subdomain = HttpContextAccessor.HttpContext?.Items["Subdomain"]?.ToString();
SiteInfo = await _scopedContentService.GetSiteInfoByIdAsync(siteid);
if (SiteInfo != null)
{
// siteid = SiteInfo.Id;
_scopedContentService.SelectedBrandName = SiteInfo.SiteName.ToLower();
Console.Write("Selected brand name:" + _scopedContentService.SelectedBrandName);
}
else
{
// siteid = 1;
_scopedContentService.SelectedBrandName = "default";
}
_scopedContentService.SelectedSiteId = siteid;
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);
collectionName = 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);
}
Console.Write("------------------------");
// ChatGptService.OnContentReceived += UpdateContent;
AIService.OnContentReceived += UpdateContent;
// ChatGptService.OnStatusChangeReceived += UpdateStatus;
AIService.OnStatusChangeReceived += UpdateStatus;
Menu = await GetMenuList();
if (string.IsNullOrEmpty(HtmlContent.ToString()))
{
// HtmlContent = await ChatGptService.GetChatGptWelcomeMessage();
await ChatGptService.GetChatGptWelcomeMessage(sessionId, siteid, Menu);
// UserInput = "Sumerize for me, what is this website about, and what can I do on this website? Please make sure you do not refer back to my question in any way. ";
// await ChatGptService.ProcessUserIntent(sessionId, UserInput, siteid, (int)SiteInfo.TemplateId!, collectionName, Menu);
}
UserInput = string.Empty;
}
private async void UpdateContent(string receivedSessionId, string content)
{
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 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");
_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")
{
HtmlContent.Clear();
var menu = await GetMenuList();
await ChatGptService.ProcessUserIntent(sessionId, UserInput, siteid, (int)SiteInfo.TemplateId!, collectionName, menu);
UserInput = string.Empty;
}
}
public async Task HandleVoiceCommand(string input)
{
// HtmlContent = string.Empty;
UserInput = input;
await InvokeAsync(StateHasChanged);
await SendUserQuery();
//UserInput = string.Empty;
}
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 DisplayMenuContent(input, forceUnmodified);
UserInput = string.Empty;
await InvokeAsync(StateHasChanged);
}
private async Task SendUserQuery()
{
if (!string.IsNullOrEmpty(UserInput))
{
HtmlContent.Clear();
var menu = await GetMenuList();
Console.Write($"\n\n Input: {UserInput} \n\n");
await ChatGptService.ProcessUserIntent(sessionId, UserInput, siteid, (int)SiteInfo.TemplateId!, collectionName, menu);
UserInput = string.Empty;
}
}
private async Task DisplayMenuContent(string input, bool forceUnmodified)
{
Console.WriteLine($"DisplayMenuContent 1: {input}");
if (!string.IsNullOrEmpty(UserInput))
{
HtmlContent.Clear();
var menu = await GetMenuList();
var menuItem = (await GetMenuItems()).Where(m => m.Name == input).FirstOrDefault();
if (menuItem == null)
{
await ChatGptService.ProcessContentRequest(sessionId, input, siteid, (int)SiteInfo.TemplateId!, collectionName, menu, forceUnmodified);
}
else
{
await ChatGptService.ProcessContentRequest(sessionId, menuItem, siteid, (int)SiteInfo.TemplateId!, collectionName, menu, forceUnmodified);
}
UserInput = string.Empty;
}
}
private async Task<string> GetMenuList()
{
List<MenuItem> menuItems = (await _contentEditorService.GetMenuItemsBySiteIdAsync(siteid)).Where(m => m.ShowInMainMenu == true).OrderBy(m => m.SortOrder).ToList();
string menuList = "";
foreach (MenuItem item in menuItems)
{
menuList += item.Name + ",";
}
return menuList;
}
private async Task<List<MenuItem>> GetMenuItems()
{
List<MenuItem> menuItems = (await _contentEditorService.GetMenuItemsBySiteIdAsync(siteid)).Where(m => m.ShowInMainMenu == true).OrderBy(m => m.SortOrder).ToList();
return menuItems;
}
private async void HandleBrandNameChanged()
{
selectedBrandName = _scopedContentService.SelectedBrandName;
//StateHasChanged();
await InvokeAsync(() =>
{
StateHasChanged();
});
}
public void Dispose()
{
dynamicallyLoadedCss = "";
HtmlContent.Clear();
_scopedContentService.OnBrandNameChanged -= HandleBrandNameChanged;
AIService.OnContentReceived -= UpdateContent;
AIService.OnStatusChangeReceived -= UpdateStatus;
}
public async ValueTask DisposeAsync()
{
await CssTemplateService.DeleteSessionCssFile(sessionId);
}
}