Clean code approvements, refractoring

This commit is contained in:
Adam 2025-06-12 12:54:17 +02:00
parent 85589532d7
commit 4effccf3a7
15 changed files with 2033 additions and 672 deletions

View File

@ -1,5 +1,6 @@
@page "/"
@page "/menu/{topic?}"
@inherits SharedDisplayLogic
@using BLAIzor.Models
@using BLAIzor.Services
@using BLAIzor.Components.Partials
@ -9,20 +10,20 @@
@using System.Net
@using System.Text.Json
@using Sidio.Sitemap.Blazor
@inject AIService ChatGptService
@* @inject AIService ChatGptService *@
@rendermode InteractiveServer
@inject IJSRuntime jsRuntime;
@inject IConfiguration configuration
@* @inject IJSRuntime jsRuntime; *@
@* @inject IConfiguration configuration *@
@inject ContentService _contentService
@inject ContentEditorService _contentEditorService
@inject ScopedContentService _scopedContentService
@* @inject ContentEditorService _contentEditorService *@
@* @inject ScopedContentService _scopedContentService *@
@* @inject IEmailSender _emailService *@
@inject NavigationManager _navigationManager
@inject IHttpContextAccessor HttpContextAccessor
@inject DesignTemplateService DesignTemplateService
@inject CssTemplateService CssTemplateService
@inject CssInjectorService CssService
@inject HttpClient Http
@* @inject HttpClient Http *@
@attribute [Sitemap]
<ErrorBoundary>
<ChildContent>
@ -32,7 +33,7 @@
<article class="content text-center" style="position: relative; z-index: 4;">
<PageTitle>Home</PageTitle>
<VideoComponent SelectedBrandName="@selectedBrandName" />
<VideoComponent SelectedBrandName="@SelectedBrandName" />
@* <HeadContent>
<style id="seemgen-style">@dynamicallyLoadedCss</style>
@ -55,81 +56,92 @@
</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(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" @onclick="AllowAIVoice">
<i class="fa-solid fa-volume-xmark"></i>
</button>
}
else
{
<button data-hint="listen" class="btn btn-primary voicebutton" @onclick="MuteAI"><i class="fa-solid fa-volume-high"></i></button>
}
<audio id="audioPlayer" hidden style="display: none;"></audio>
}
}
}
if(TTSEnabled)
{
if (!AiVoicePermitted)
{
<button data-hint="listen" class="btn btn-primary voicebutton" @onclick="AllowAIVoice">
<i class="fa-solid fa-volume-xmark"></i>
</button>
</div>
@* Type anything *@
@* </div> *@
</div>
<p id="recordingText"></p>
<div id="currentContent">
@{
if (!string.IsNullOrEmpty(HtmlContent.ToString()))
{
if (isEmailFormVisible)
{
<div class="conteiner-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
{
<button data-hint="listen" class="btn btn-primary voicebutton" @onclick="MuteAI"><i class="fa-solid fa-volume-high"></i></button>
<div class="pt-5 @FirstColumnClass">
@((MarkupString)HtmlContent.ToString())
</div>
}
<audio id="audioPlayer" hidden style="display: none;"></audio>
}
}
}
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>
}
@* Type anything *@
@* </div> *@
</div>
<p id="recordingText"></p>
<div 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>
<button class="btn btn-primary" @onclick="HomeClick"><i class="fa-solid fa-rotate"></i></button>
@* <FormWizardComponent SessionId="@sessionId"></FormWizardComponent> *@
</div>
}
}
</div>
<button class="btn btn-primary" @onclick="HomeClick"><i class="fa-solid fa-rotate"></i></button>
@* <FormWizardComponent SessionId="@sessionId"></FormWizardComponent> *@
</article>
</main>
</div>
</article>
</main>
</div>
</ChildContent>
<ErrorContent Context="ex">
<p role="alert">An error occurred: @ex.Message</p>
@ -178,40 +190,23 @@
@code {
[Parameter]
public string? topic { get; set; }
public static Index myHome;
// public static Index myHome;
private string? Subdomain;
public int SiteId;
public SiteInfo SiteInfo;
private StringBuilder HtmlContent = new StringBuilder("");
private string TextContent = "";
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 string FirstColumnClass = "";
// private bool isEmailFormVisible = false;
// private ContactFormModel ContactFormModel = new();
// // private string? SuccessMessage;
// // private string? ErrorMessage;
// private string? DocumentEmailAddress = "";
private ContactFormModel ContactFormModel = new();
// private string? SuccessMessage;
// private string? ErrorMessage;
private string? DocumentEmailAddress = "";
private string selectedBrandName = "default";
private string dynamicallyLoadedCss = string.Empty;
private string collectionName = "html_snippets";
private string sessionId;
private static readonly Dictionary<string, Index> _instances = new();
private string Menu;
private bool VoiceEnabled;
private bool TTSEnabled;
private bool STTEnabled;
private bool _initVoicePending = false;
private bool welcomeStage = true;
private bool AiVoicePermitted = false;
private string GetApiKey() =>
configuration?.GetSection("ElevenLabsAPI")?.GetValue<string>("ApiKey") ?? string.Empty;
private void AllowAIVoice()
@ -223,84 +218,26 @@
AiVoicePermitted = false;
}
private async Task ConvertTextToSpeech()
{
// string plainText = WebUtility.HtmlDecode(HtmlContent.ToString());
if (string.IsNullOrWhiteSpace(TextContent) || VoiceEnabled == false || TTSEnabled == false || welcomeStage || !AiVoicePermitted)
return;
Console.WriteLine("------------------------------OMGOMGOMG TTS call!!!!-------------");
var requestContent = new
{
text = TextContent,
// model_id = "eleven_multilingual_v2",
model_id = "eleven_flash_v2_5",
voice_settings = new
{
stability = 0.5,
similarity_boost = 0.75,
speed = 1
}
};
var requestJson = JsonSerializer.Serialize(requestContent);
string voiceId;
if(SiteInfo.voiceId != null)
{
voiceId = SiteInfo.voiceId;
}
else
{
voiceId = "rE22Kc7UGoQj4zdHNYvd";
}
// string voiceId = "yyPLNYHg3CvjlSdSOdLh";
var httpRequest = new HttpRequestMessage(HttpMethod.Post, $"https://api.elevenlabs.io/v1/text-to-speech/{voiceId}/stream")
{
Content = new StringContent(requestJson, Encoding.UTF8, "application/json")
};
httpRequest.Headers.Add("xi-api-key", GetApiKey());
var response = await Http.SendAsync(httpRequest);
if (response.IsSuccessStatusCode)
{
var audioBytes = await response.Content.ReadAsByteArrayAsync();
var base64Audio = Convert.ToBase64String(audioBytes);
var audioDataUrl = $"data:audio/mpeg;base64,{base64Audio}";
await jsRuntime.InvokeVoidAsync("playAudio", audioDataUrl);
}
else
{
// Handle error response
var errorContent = await response.Content.ReadAsStringAsync();
Console.Error.WriteLine($"Error: {errorContent}");
}
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await jsRuntime.InvokeVoidAsync("setSessionId", sessionId);
await jsRuntime.InvokeVoidAsync("setSessionId", SessionId);
await jsRuntime.InvokeVoidAsync("initHints");
// sessionId = Guid.NewGuid().ToString();
// _instances[sessionId] = this;
Console.Write($"\n\n SessionId: {sessionId}\n\n");
Console.Write($"\n\n SessionId: {SessionId}\n\n");
// _scopedContentService.OnBrandNameChanged += HandleBrandNameChanged;
if (!string.IsNullOrEmpty(_scopedContentService.SelectedBrandName))
{
selectedBrandName = _scopedContentService.SelectedBrandName;
SelectedBrandName = _scopedContentService.SelectedBrandName;
}
else
{
_scopedContentService.SelectedBrandName = "default";
selectedBrandName = "default";
SelectedBrandName = "default";
}
Subdomain = HttpContextAccessor.HttpContext?.Items["Subdomain"]?.ToString();
SiteInfo = await _scopedContentService.GetSiteInfoByNameAsync(Subdomain);
@ -327,12 +264,12 @@
// 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;
CollectionName = designTemplate.QDrandCollectionName;
if (cssTemplate != null)
{
dynamicallyLoadedCss = cssTemplate.CssContent; // Assuming Content holds the CSS string
var cssPath = await CssTemplateService.SaveTempCssFileAsync(dynamicallyLoadedCss, sessionId);
var cssPath = await CssTemplateService.SaveTempCssFileAsync(dynamicallyLoadedCss, SessionId);
await jsRuntime.InvokeVoidAsync("seemgen.injectCssFile", cssPath);
//await CssService.ApplyCssAsync(dynamicallyLoadedCss);
@ -341,21 +278,21 @@
Console.Write($"------------------------ {SiteInfo.MenuItems}, {SiteId}, {SiteInfo.TemplateId}, {SiteInfo.SiteName}");
Menu = await GetMenuList();
Menu = await GetMenuList(SiteId);
if (string.IsNullOrEmpty(HtmlContent.ToString()))
{
if(!string.IsNullOrWhiteSpace(topic))
{
UserInput = topic;
await ChatGptService.ProcessContentRequest(sessionId, UserInput, SiteId, (int)SiteInfo.TemplateId!, collectionName, Menu, true);
await ChatGptService.ProcessContentRequest(SessionId, UserInput, SiteId, (int)SiteInfo.TemplateId!, CollectionName, Menu, true);
}
else
{
await ChatGptService.GetChatGptWelcomeMessage(sessionId, SiteId, Menu);
await ChatGptService.GetChatGptWelcomeMessage(SessionId, SiteId, Menu);
}
// 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);
// await ChatGptService.ProcessUserIntent(SessionId, UserInput, SiteId, (int)SiteInfo.TemplateId!, CollectionName, Menu);
}
UserInput = string.Empty;
// await InvokeAsync(StateHasChanged);
@ -372,7 +309,7 @@
public async void MenuClick(string menuName)
{
await CallCSharpMethod2(menuName, sessionId, true);
await CallCSharpMethod2(menuName, SessionId, true);
}
public void HomeClick()
@ -394,105 +331,6 @@
myHome = this; // Set the static reference to the current instance
}
[JSInvokable("OpenEmailForm2")]
public static async void OpenEmailForm2(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";
DocumentEmailAddress = emailAddress;
isEmailFormVisible = true;
StateHasChanged();
var result = await jsRuntime.InvokeAsync<object>("getDivContent", "currentContent");
_scopedContentService.CurrentDOM = JsonSerializer.Serialize(result);
// Console.Write($"{_scopedContentService.CurrentDOM}");
}
[JSInvokable("CallCSharpMethod2")]
public static async Task CallCSharpMethod2(string input, string sessionId, bool forceUnModified = false)
{
// if (myHome != null)
// {
// await myHome.HandleJsCall(input, );
// }
if (_instances.TryGetValue(sessionId, out var instance))
{
await instance.HandleJsCall(input, sessionId, forceUnModified);
}
Console.Write("Button clicked:" + input);
}
[JSInvokable("ProcessAudio2")]
public static async Task ProcessAudio2(string base64Audio, string sessionId)
{
Console.Write("audio incoming");
if (myHome != null)
{
if (myHome.STTEnabled == false) return;
Console.WriteLine("STT ENABLED -------------------------------------------------------------------------------");
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, sessionId);
}
}
}
}
private async Task SendMessage()
{
Console.WriteLine("Button clicked!");
var menu = await GetMenuList();
HtmlContent.Clear();
await ChatGptService.ProcessUserIntent(sessionId, UserInput, SiteId, (int)SiteInfo.TemplateId!, collectionName, menu);
UserInput = string.Empty;
}
protected override async Task OnInitializedAsync()
{
_scopedContentService.OnBrandNameChanged += HandleBrandNameChanged;
@ -502,15 +340,15 @@
// ChatGptService.OnStatusChangeReceived += UpdateStatus;
AIService.OnStatusChangeReceived += UpdateStatus;
AIService.OnTextContentAvailable += UpdateTextContentForVoice;
sessionId = Guid.NewGuid().ToString();
_instances[sessionId] = this;
SessionId = Guid.NewGuid().ToString();
_instances[SessionId] = this;
VoiceEnabled = configuration?.GetSection("AiSettings")?.GetValue<bool>("VoiceActivated") ?? false;
}
private async void UpdateContent(string receivedSessionId, string content)
{
if (receivedSessionId == sessionId) // Only accept messages meant for this tab
if (receivedSessionId == SessionId) // Only accept messages meant for this tab
{
HtmlContent.Clear();
@ -526,18 +364,19 @@
private async void UpdateTextContentForVoice(string receivedSessionId, string content)
{
if (receivedSessionId == sessionId) // Only accept messages meant for this tab
Console.WriteLine("UPDATETEXTCONTENT called");
if (receivedSessionId == SessionId) // Only accept messages meant for this tab
{
TextContent = content;
await ConvertTextToSpeech();
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
if (receivedSessionId == SessionId) // Only accept messages meant for this tab
{
Console.WriteLine("Content update finished");
var result = await jsRuntime.InvokeAsync<object>("getDivContent", "currentContent");
@ -556,7 +395,7 @@
private async void UpdateStatus(string receivedSessionId, string content)
{
if (receivedSessionId == sessionId) // Only accept messages meant for this tab
if (receivedSessionId == SessionId) // Only accept messages meant for this tab
{
StatusContent = content;
//InvokeAsync(StateHasChanged); // Ensures UI updates dynamically
@ -571,93 +410,14 @@
{
if (e.Code == "Enter" || e.Code == "NumpadEnter")
{
var menu = await GetMenuList();
var menu = await GetMenuList(SiteId);
HtmlContent.Clear();
string input = "Please tell me more about: " + UserInput;
await ChatGptService.ProcessUserIntent(sessionId, input, SiteId, (int)SiteInfo.TemplateId!, collectionName, menu);
await ChatGptService.ProcessUserIntent(SessionId, input, SiteId, (int)SiteInfo.TemplateId!, CollectionName, menu);
UserInput = string.Empty;
}
}
public async Task HandleVoiceCommand(string input, string sessionId)
{
// 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;
await DisplayMenuContent(input, forceUnmodified);
UserInput = string.Empty;
await InvokeAsync(StateHasChanged);
}
private async Task SendUserQuery()
{
welcomeStage = false;
if (!string.IsNullOrEmpty(UserInput))
{
HtmlContent.Clear();
var menu = await GetMenuList();
await ChatGptService.ProcessUserIntent(sessionId, UserInput, SiteId, (int)SiteInfo.TemplateId!, collectionName, menu);
UserInput = string.Empty;
}
}
private async Task DisplayMenuContent(string input, bool forceUnmodified)
{
welcomeStage = false;
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 = "";
@ -671,7 +431,7 @@
public async ValueTask DisposeAsync()
{
await CssTemplateService.DeleteSessionCssFile(sessionId);
await CssTemplateService.DeleteSessionCssFile(SessionId);
}

View File

@ -1,5 +1,6 @@
@page "/preview/{siteid:int}"
@page "/preview/{siteid:int}/{topic?}"
@inherits SharedDisplayLogic
@using BLAIzor.Models
@using BLAIzor.Services
@using Google.Cloud.Speech.V1
@ -9,20 +10,20 @@
@using System.Text.Json
@using System.Net
@inject AIService ChatGptService
@* @inject AIService ChatGptService *@
@rendermode InteractiveServer
@inject IJSRuntime jsRuntime;
@inject IConfiguration configuration
@* @inject IJSRuntime jsRuntime; *@
@* @inject IConfiguration configuration *@
@inject ContentService _contentService
@inject ContentEditorService _contentEditorService
@inject ScopedContentService _scopedContentService
@* @inject ContentEditorService _contentEditorService *@
@* @inject ScopedContentService _scopedContentService *@
@inject IEmailSender _emailService
@inject NavigationManager _navigationManager
@inject IHttpContextAccessor HttpContextAccessor
@inject DesignTemplateService DesignTemplateService
@inject CssTemplateService CssTemplateService
@inject CssInjectorService CssService
@inject HttpClient Http
@* @inject HttpClient Http *@
<div class="page" style="z-index: 1">
@ -31,7 +32,7 @@
<article class="content text-center" style="position: relative; z-index: 4;">
<PageTitle>Home</PageTitle>
<VideoComponent SelectedBrandName="@selectedBrandName" />
<VideoComponent SelectedBrandName="@SelectedBrandName" />
@* <HeadContent>
@if (!string.IsNullOrEmpty(dynamicallyLoadedCss))
@ -98,14 +99,28 @@
@{
if (!string.IsNullOrEmpty(HtmlContent.ToString()))
{
<div class="pt-5 @FirstColumnClass">
@((MarkupString)HtmlContent.ToString())
</div>
// <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 class="conteiner-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>
}
}
@ -141,7 +156,7 @@
function callAI(inputString) {
console.log(sessionId);
DotNet.invokeMethodAsync('BLAIzor', 'CallCSharpMethod3', inputString, sessionId, false)
DotNet.invokeMethodAsync('BLAIzor', 'CallCSharpMethod2', inputString, sessionId, false)
.then(response => console.log(response))
.catch(error => console.error(error));
}
@ -159,54 +174,30 @@
<script>
function openContactForm(emailAddress) {
console.log(emailAddress);
console.log(emailAddress);
if (emailAddress) {
DotNet.invokeMethodAsync('BLAIzor', 'OpenEmailForm3', emailAddress)
if (emailAddress) {
DotNet.invokeMethodAsync('BLAIzor', 'OpenEmailForm2', emailAddress)
}
}
}
</script>
@code {
public static Preview myHome;
// public static Preview myHome;
private string? Subdomain;
[Parameter]
public int siteid { get; set; }
[Parameter]
public string? topic { get; set; }
public SiteInfo SiteInfo;
private StringBuilder HtmlContent = new();
private string TextContent = "";
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;
private bool VoiceEnabled;
private bool TTSEnabled;
private bool STTEnabled;
private bool _initVoicePending = false;
private bool welcomeStage = true;
private bool AiVoicePermitted = false;
private string GetApiKey() =>
configuration?.GetSection("ElevenLabsAPI")?.GetValue<string>("ApiKey") ?? string.Empty;
private void AllowAIVoice()
{
@ -217,69 +208,12 @@
AiVoicePermitted = false;
}
private async Task ConvertTextToSpeech()
{
// string plainText = WebUtility.HtmlDecode(HtmlContent.ToString());
if (string.IsNullOrWhiteSpace(TextContent) || VoiceEnabled == false || TTSEnabled == false || welcomeStage || !AiVoicePermitted)
return;
Console.WriteLine("------------------------------OMGOMGOMG TTS call!!!!-------------");
var requestContent = new
{
text = TextContent,
// model_id = "eleven_multilingual_v2",
model_id = "eleven_flash_v2_5",
voice_settings = new
{
stability = 0.5,
similarity_boost = 0.75,
speed = 1.1
}
};
var requestJson = JsonSerializer.Serialize(requestContent);
string voiceId;
if (SiteInfo.voiceId != null)
{
voiceId = SiteInfo.voiceId;
}
else
{
voiceId = "rE22Kc7UGoQj4zdHNYvd";
}
// string voiceId = "yyPLNYHg3CvjlSdSOdLh";
var httpRequest = new HttpRequestMessage(HttpMethod.Post, $"https://api.elevenlabs.io/v1/text-to-speech/{voiceId}/stream")
{
Content = new StringContent(requestJson, Encoding.UTF8, "application/json")
};
httpRequest.Headers.Add("xi-api-key", GetApiKey());
var response = await Http.SendAsync(httpRequest);
if (response.IsSuccessStatusCode)
{
var audioBytes = await response.Content.ReadAsByteArrayAsync();
var base64Audio = Convert.ToBase64String(audioBytes);
var audioDataUrl = $"data:audio/mpeg;base64,{base64Audio}";
await jsRuntime.InvokeVoidAsync("playAudio", audioDataUrl);
}
else
{
// Handle error response
var errorContent = await response.Content.ReadAsStringAsync();
Console.Error.WriteLine($"Error: {errorContent}");
}
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await jsRuntime.InvokeVoidAsync("setSessionId", sessionId);
await jsRuntime.InvokeVoidAsync("setSessionId", SessionId);
await jsRuntime.InvokeVoidAsync("initHints");
}
@ -288,7 +222,7 @@
{
Console.WriteLine("PENDING VOICE--------------------------------------------------");
_initVoicePending = false;
await jsRuntime.InvokeVoidAsync("initVoiceRecorder", "ProcessAudio3");
await jsRuntime.InvokeVoidAsync("initVoiceRecorder", "ProcessAudio2");
}
}
@ -300,7 +234,7 @@
public async void MenuClick(string menuName)
{
await CallCSharpMethod3(menuName, sessionId, true);
await CallCSharpMethod2(menuName, SessionId, true);
}
public void HomeClick()
@ -341,110 +275,40 @@
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);
}
// [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)
{
if (myHome.STTEnabled == false) return;
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;
}
// 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}");
// }
protected override async Task OnParametersSetAsync()
{
sessionId = Guid.NewGuid().ToString();
_instances[sessionId] = this;
SessionId = Guid.NewGuid().ToString();
SiteId = siteid;
_instances[SessionId] = this;
_scopedContentService.OnBrandNameChanged += HandleBrandNameChanged;
selectedBrandName = _scopedContentService.SelectedBrandName;
SelectedBrandName = _scopedContentService.SelectedBrandName;
// Subdomain = HttpContextAccessor.HttpContext?.Items["Subdomain"]?.ToString();
SiteInfo = await _scopedContentService.GetSiteInfoByIdAsync(siteid);
SiteInfo = await _scopedContentService.GetSiteInfoByIdAsync(SiteId);
if (SiteInfo != null)
{
// siteid = SiteInfo.Id;
// SiteId = SiteInfo.Id;
_scopedContentService.SelectedBrandName = SiteInfo.SiteName.ToLower();
TTSEnabled = SiteInfo.TTSActive;
@ -454,24 +318,24 @@
}
else
{
// siteid = 1;
// SiteId = 1;
_scopedContentService.SelectedBrandName = "default";
TTSEnabled = false;
STTEnabled = false;
}
_scopedContentService.SelectedSiteId = siteid;
_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;
CollectionName = designTemplate.QDrandCollectionName;
if (cssTemplate != null)
{
dynamicallyLoadedCss = cssTemplate.CssContent; // Assuming Content holds the CSS string
var cssPath = await CssTemplateService.SaveTempCssFileAsync(dynamicallyLoadedCss, sessionId);
var cssPath = await CssTemplateService.SaveTempCssFileAsync(dynamicallyLoadedCss, SessionId);
await jsRuntime.InvokeVoidAsync("seemgen.injectCssFile", cssPath);
}
@ -484,17 +348,17 @@
AIService.OnStatusChangeReceived += UpdateStatus;
AIService.OnTextContentAvailable += UpdateTextContentForVoice;
Menu = await GetMenuList();
Menu = await GetMenuList(SiteId);
if (string.IsNullOrEmpty(HtmlContent.ToString()))
{
if (!string.IsNullOrWhiteSpace(topic))
{
UserInput = topic;
await ChatGptService.ProcessContentRequest(sessionId, UserInput, siteid, (int)SiteInfo.TemplateId!, collectionName, Menu, true);
await ChatGptService.ProcessContentRequest(SessionId, UserInput, SiteId, (int)SiteInfo.TemplateId!, CollectionName, Menu, true);
}
else
{
await ChatGptService.GetChatGptWelcomeMessage(sessionId, siteid, Menu);
await ChatGptService.GetChatGptWelcomeMessage(SessionId, SiteId, Menu);
}
}
@ -504,7 +368,7 @@
private async void UpdateContent(string receivedSessionId, string content)
{
if (receivedSessionId == sessionId) // Only accept messages meant for this tab
if (receivedSessionId == SessionId) // Only accept messages meant for this tab
{
HtmlContent.Clear();
HtmlContent.Append(content);
@ -519,18 +383,18 @@
private async void UpdateTextContentForVoice(string receivedSessionId, string content)
{
if (receivedSessionId == sessionId) // Only accept messages meant for this tab
if (receivedSessionId == SessionId) // Only accept messages meant for this tab
{
TextContent = content;
await ConvertTextToSpeech();
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
if (receivedSessionId == SessionId) // Only accept messages meant for this tab
{
Console.WriteLine("Content update finished");
var result = await jsRuntime.InvokeAsync<object>("getDivContent", "currentContent");
@ -548,7 +412,7 @@
private async void UpdateStatus(string receivedSessionId, string content)
{
if (receivedSessionId == sessionId) // Only accept messages meant for this tab
if (receivedSessionId == SessionId) // Only accept messages meant for this tab
{
StatusContent = content;
//InvokeAsync(StateHasChanged); // Ensures UI updates dynamically
@ -564,93 +428,34 @@
if (e.Code == "Enter" || e.Code == "NumpadEnter")
{
HtmlContent.Clear();
var menu = await GetMenuList();
await ChatGptService.ProcessUserIntent(sessionId, UserInput, siteid, (int)SiteInfo.TemplateId!, collectionName, menu);
var menu = await GetMenuList(SiteId);
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);
// public async Task HandleVoiceCommand(string input)
// {
// // HtmlContent = string.Empty;
// UserInput = input;
// await InvokeAsync(StateHasChanged);
await SendUserQuery();
//UserInput = string.Empty;
}
// 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()
{
welcomeStage = false;
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)
{
welcomeStage = false;
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();
});
}
// private async Task SendUserQuery()
// {
// welcomeStage = false;
// if (!string.IsNullOrEmpty(UserInput))
// {
// HtmlContent.Clear();
// var menu = await GetMenuList(SiteId);
// Console.Write($"\n\n Input: {UserInput} \n\n");
// await ChatGptService.ProcessUserIntent(SessionId, UserInput, SiteId, (int)SiteInfo.TemplateId!, CollectionName, menu);
// UserInput = string.Empty;
// }
// }
public void Dispose()
{
@ -663,6 +468,6 @@
public async ValueTask DisposeAsync()
{
await CssTemplateService.DeleteSessionCssFile(sessionId);
await CssTemplateService.DeleteSessionCssFile(SessionId);
}
}

View File

@ -0,0 +1,311 @@
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 System.Text;
using System.Text.Json;
using UglyToad.PdfPig.DocumentLayoutAnalysis;
namespace BLAIzor.Components.Pages
{
public class SharedDisplayLogic : ComponentBase
{
public string SelectedBrandName = "default";
[Inject] protected ScopedContentService _scopedContentService { get; set; }
[Inject] protected ContentEditorService _contentEditorService { get; set; }
[Inject] protected IConfiguration configuration { get; set; }
[Inject] protected HttpClient Http { get; set; }
[Inject] protected IJSRuntime jsRuntime { get; set; }
[Inject] protected AIService ChatGptService { get; set; }
public static readonly Dictionary<string, SharedDisplayLogic> _instances = new();
public string SessionId;
public static SharedDisplayLogic myHome;
public int SiteId;
public SiteInfo SiteInfo;
public StringBuilder HtmlContent = new StringBuilder("");
public string TextContent = "";
public string StatusContent = "";
public string UserInput = string.Empty;
public string CollectionName = "html_snippets";
public bool VoiceEnabled;
public bool TTSEnabled;
public bool STTEnabled;
public bool _initVoicePending = false;
public bool welcomeStage = true;
public bool AiVoicePermitted = false;
public string FirstColumnClass = "";
public bool isEmailFormVisible = false;
public ContactFormModel ContactFormModel = new();
// private string? SuccessMessage;
// private string? ErrorMessage;
public string? DocumentEmailAddress = "";
public void DoSharedWork()
{
// Logic here
}
public async void HandleBrandNameChanged()
{
SelectedBrandName = _scopedContentService.SelectedBrandName;
//await InvokeAsync(() =>
// {
// StateHasChanged();
// });
try
{
StateHasChanged();
//await Task.Run(() =>
//{
// StateHasChanged();
//}).ConfigureAwait(false);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
public async Task<string> GetMenuList(int siteId)
{
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;
}
public async Task<List<MenuItem>> GetMenuItems(int siteId)
{
List<MenuItem> menuItems = (await _contentEditorService.GetMenuItemsBySiteIdAsync(siteId)).Where(m => m.ShowInMainMenu == true).OrderBy(m => m.SortOrder).ToList();
return menuItems;
}
private string GetApiKey() =>
configuration?.GetSection("ElevenLabsAPI")?.GetValue<string>("ApiKey") ?? string.Empty;
public async Task ConvertTextToSpeech(string textContent)
{
// string plainText = WebUtility.HtmlDecode(HtmlContent.ToString());
if (string.IsNullOrWhiteSpace(textContent) || VoiceEnabled == false || TTSEnabled == false || welcomeStage || !AiVoicePermitted)
return;
Console.WriteLine("------------------------------OMGOMGOMG TTS call!!!!-------------");
var requestContent = new
{
text = textContent,
// model_id = "eleven_multilingual_v2",
model_id = "eleven_flash_v2_5",
voice_settings = new
{
stability = 0.5,
similarity_boost = 0.75,
speed = 1.1
}
};
var requestJson = JsonSerializer.Serialize(requestContent);
string voiceId;
if (SiteInfo.voiceId != null)
{
voiceId = SiteInfo.voiceId;
}
else
{
voiceId = "rE22Kc7UGoQj4zdHNYvd";
}
// string voiceId = "yyPLNYHg3CvjlSdSOdLh";
var httpRequest = new HttpRequestMessage(HttpMethod.Post, $"https://api.elevenlabs.io/v1/text-to-speech/{voiceId}/stream")
{
Content = new StringContent(requestJson, Encoding.UTF8, "application/json")
};
httpRequest.Headers.Add("xi-api-key", GetApiKey());
var response = await Http.SendAsync(httpRequest);
if (response.IsSuccessStatusCode)
{
var audioBytes = await response.Content.ReadAsByteArrayAsync();
var base64Audio = Convert.ToBase64String(audioBytes);
var audioDataUrl = $"data:audio/mpeg;base64,{base64Audio}";
await jsRuntime.InvokeVoidAsync("playAudio", audioDataUrl);
}
else
{
// Handle error response
var errorContent = await response.Content.ReadAsStringAsync();
Console.Error.WriteLine($"Error: {errorContent}");
}
}
[JSInvokable("CallCSharpMethod2")]
public static async Task CallCSharpMethod2(string input, string sessionId, bool forceUnModified = false)
{
// if (myHome != null)
// {
// await myHome.HandleJsCall(input, );
// }
if (_instances.TryGetValue(sessionId, out var instance))
{
await instance.HandleJsCall(input, sessionId, forceUnModified);
}
Console.Write("Button clicked:" + input);
}
public async Task HandleJsCall(string input, string sessionId, bool forceUnmodified)
{
HtmlContent.Clear();
await InvokeAsync(StateHasChanged);
UserInput = input;
await DisplayMenuContent(input, forceUnmodified);
UserInput = string.Empty;
await InvokeAsync(StateHasChanged);
}
public async Task HandleVoiceCommand(string input, string sessionId)
{
// HtmlContent = string.Empty;
UserInput = input;
await InvokeAsync(StateHasChanged);
await SendUserQuery();
//UserInput = string.Empty;
}
public async Task SendUserQuery()
{
welcomeStage = false;
if (!string.IsNullOrEmpty(UserInput))
{
HtmlContent.Clear();
var menu = await GetMenuList(SiteId);
await ChatGptService.ProcessUserIntent(SessionId, UserInput, SiteId, (int)SiteInfo.TemplateId!, CollectionName, menu);
UserInput = string.Empty;
}
}
public async Task DisplayMenuContent(string input, bool forceUnmodified)
{
welcomeStage = false;
if (!string.IsNullOrEmpty(UserInput))
{
HtmlContent.Clear();
var menu = await GetMenuList(SiteId);
var menuItem = (await GetMenuItems(SiteId)).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;
}
}
public async Task DisplayEmailForm(string emailAddress)
{
FirstColumnClass = "col-12 col-md-6";
DocumentEmailAddress = emailAddress;
isEmailFormVisible = true;
StateHasChanged();
var result = await jsRuntime.InvokeAsync<object>("getDivContent", "currentContent");
_scopedContentService.CurrentDOM = JsonSerializer.Serialize(result);
// Console.Write($"{_scopedContentService.CurrentDOM}");
}
[JSInvokable("ProcessAudio2")]
public static async Task ProcessAudio2(string base64Audio, string SessionId)
{
Console.Write("audio incoming");
if (myHome != null)
{
if (myHome.STTEnabled == false) return;
Console.WriteLine("STT ENABLED -------------------------------------------------------------------------------");
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, SessionId);
}
}
}
}
[JSInvokable("OpenEmailForm2")]
public static async void OpenEmailForm2(string emailAddress)
{
if (myHome != null)
{
await myHome.DisplayEmailForm(emailAddress);
}
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!, CollectionName, menu);
UserInput = string.Empty;
}
}
}

View File

@ -5,7 +5,7 @@
height: auto;
}
video {
#myVideo {
position: fixed;
right: 0;
top: 0;

View File

@ -139,9 +139,30 @@ public static class TextHelper
return result.ToString();
}
public static string FixJsonWithoutAI(string aiResponse)
{
if (aiResponse.StartsWith("```"))
{
//Console.WriteLine("FIXING ``` in AI Response.");
aiResponse = aiResponse.Substring(3);
if (aiResponse.StartsWith("json"))
{
aiResponse = aiResponse.Substring(4);
}
aiResponse = aiResponse.Substring(0, aiResponse.Length - 3);
}
return aiResponse;
}
public static string RemoveTabs(string text)
{
if (string.IsNullOrEmpty(text)) return text;
return text.Replace("\t", ""); // Simple replace — remove all tab characters
}
}

View File

@ -1267,7 +1267,7 @@ namespace BLAIzor.Services
//Console.WriteLine("AI Response:");
//Console.WriteLine(aiResponse);
aiResponse = FixJsonWithoutAI(aiResponse);
aiResponse = TextHelper.FixJsonWithoutAI(aiResponse);
aiResponse = TextHelper.RemoveTabs(aiResponse);
layoutPlan = System.Text.Json.JsonSerializer.Deserialize<LayoutPlan>(aiResponse, new JsonSerializerOptions
{
@ -1303,24 +1303,7 @@ namespace BLAIzor.Services
return layoutPlan;
}
private string FixJsonWithoutAI(string aiResponse)
{
if (aiResponse.StartsWith("```"))
{
//Console.WriteLine("FIXING ``` in AI Response.");
aiResponse = aiResponse.Substring(3);
if (aiResponse.StartsWith("json"))
{
aiResponse = aiResponse.Substring(4);
}
aiResponse = aiResponse.Substring(0, aiResponse.Length - 3);
}
return aiResponse;
}
public async Task DisplayHtml(string sessionId, string interMediateResult, string methodToCall = "", string methodParameter = "")//, string[]? topics = null)
{

View File

@ -0,0 +1,168 @@
@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap');
.card {
background-color: rgba(255, 255, 255, 0.3);
backdrop-filter: blur(2px);
}
.table {
color: #f2d8bb !important;
}
.navbar-collapse {
height: 100vh;
text-align: center !important;
align-content: center;
}
.navbar-collapse .nav-link {
font-size: 1.2rem;
letter-spacing: 2px;
}
.navbar-collapse .nav-item:not(:last-child) {
padding: 0.2em 1em;
}
.navbar {
background-color: #022c28;
color: #d0eae9;
}
.nav-link {
color: #d0eae9 !important;
}
.content {
top: 60px;
}
body {
background-color: #022c28;
background-attachment: fixed;
background-position: center;
background-size: cover;
color: aqua;
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 300;
font-style: normal;
font-size: 1rem; /* Base size */
}
h1 {
font-weight: 700;
font-size: 2.5rem;
padding-top: 30px;
padding-bottom: 10px;
}
h2 {
font-weight: 500;
font-size: 2rem;
padding-top: 15px;
padding-bottom: 10px;
}
h3 {
font-weight: 400;
font-size: 1.6rem;
padding-top: 10px;
padding-bottom: 10px;
}
p {
color: #fff;
font-size: 1.1rem;
}
li {
color: #fff;
font-size: 1rem;
text-align: center;
}
.btn-primary {
color: #d0eae9;
background-color: #014d4e;
border: 0px;
margin: 5px;
}
.btn-primary:hover {
color: #fff;
background-color: #086262;
border: 0px;
}
.row {
padding-bottom: 30px;
margin: 0 auto !important;
}
.searchInput::placeholder {
color: #d0eae9;
}
#myVideo {
position: fixed;
right: 0;
top: -100px;
min-width: 100%;
min-height: 100%;
transform: translateX(calc((100% - 100vw) / 2));
}
.img-fluid {
max-height: 50vh;
width: auto;
border-radius: 15px;
}
.sp-img {
box-shadow: 10px 10px 30px 0px rgba(0,0,0,0.75);
-webkit-box-shadow: 10px 10px 30px 0px rgba(0,0,0,0.75);
-moz-box-shadow: 10px 10px 30px 0px rgba(0,0,0,0.75);
}
.col {
align-items: center;
display: flex;
}
.form-select {
background-color: rgba(255, 255, 255, 0.2);
border-radius: 5px;
display: unset !important;
color: #fff;
}
.list-group-item,
.bg-light {
background-color: rgb(11 24 23 / 76%) !important;
backdrop-filter: blur(8px) !important;
}
.text-primary {
--bs-text-opacity: 1;
color: aqua;
}
/* 🔽 Mobile Responsiveness */
@media (max-width: 768px) {
h1 { font-size: 2rem; }
h2 { font-size: 1.6rem; }
h3 { font-size: 1.4rem; }
p, li { font-size: 1rem; }
.navbar-collapse .nav-link { font-size: 1.1rem; }
p {text-align: justify;}
}
@media (max-width: 480px) {
h1 { font-size: 1.6rem; }
h2 { font-size: 1.3rem; }
h3 { font-size: 1.1rem; }
p, li { font-size: 0.95rem; }
.navbar-collapse .nav-link { font-size: 1rem; }
p {text-align: justify;}
}

View File

@ -0,0 +1,168 @@
@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap');
.card {
background-color: rgba(255, 255, 255, 0.3);
backdrop-filter: blur(2px);
}
.table {
color: #f2d8bb !important;
}
.navbar-collapse {
height: 100vh;
text-align: center !important;
align-content: center;
}
.navbar-collapse .nav-link {
font-size: 1.2rem;
letter-spacing: 2px;
}
.navbar-collapse .nav-item:not(:last-child) {
padding: 0.2em 1em;
}
.navbar {
background-color: #022c28;
color: #d0eae9;
}
.nav-link {
color: #d0eae9 !important;
}
.content {
top: 60px;
}
body {
background-color: #022c28;
background-attachment: fixed;
background-position: center;
background-size: cover;
color: aqua;
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 300;
font-style: normal;
font-size: 1rem; /* Base size */
}
h1 {
font-weight: 700;
font-size: 2.5rem;
padding-top: 30px;
padding-bottom: 10px;
}
h2 {
font-weight: 500;
font-size: 2rem;
padding-top: 15px;
padding-bottom: 10px;
}
h3 {
font-weight: 400;
font-size: 1.6rem;
padding-top: 10px;
padding-bottom: 10px;
}
p {
color: #fff;
font-size: 1.1rem;
}
li {
color: #fff;
font-size: 1rem;
text-align: center;
}
.btn-primary {
color: #d0eae9;
background-color: #014d4e;
border: 0px;
margin: 5px;
}
.btn-primary:hover {
color: #fff;
background-color: #086262;
border: 0px;
}
.row {
padding-bottom: 30px;
margin: 0 auto !important;
}
.searchInput::placeholder {
color: #d0eae9;
}
#myVideo {
position: fixed;
right: 0;
top: -100px;
min-width: 100%;
min-height: 100%;
transform: translateX(calc((100% - 100vw) / 2));
}
.img-fluid {
max-height: 50vh;
width: auto;
border-radius: 15px;
}
.sp-img {
box-shadow: 10px 10px 30px 0px rgba(0,0,0,0.75);
-webkit-box-shadow: 10px 10px 30px 0px rgba(0,0,0,0.75);
-moz-box-shadow: 10px 10px 30px 0px rgba(0,0,0,0.75);
}
.col {
align-items: center;
display: flex;
}
.form-select {
background-color: rgba(255, 255, 255, 0.2);
border-radius: 5px;
display: unset !important;
color: #fff;
}
.list-group-item,
.bg-light {
background-color: rgb(11 24 23 / 76%) !important;
backdrop-filter: blur(8px) !important;
}
.text-primary {
--bs-text-opacity: 1;
color: aqua;
}
/* 🔽 Mobile Responsiveness */
@media (max-width: 768px) {
h1 { font-size: 2rem; }
h2 { font-size: 1.6rem; }
h3 { font-size: 1.4rem; }
p, li { font-size: 1rem; }
.navbar-collapse .nav-link { font-size: 1.1rem; }
p {text-align: justify;}
}
@media (max-width: 480px) {
h1 { font-size: 1.6rem; }
h2 { font-size: 1.3rem; }
h3 { font-size: 1.1rem; }
p, li { font-size: 0.95rem; }
.navbar-collapse .nav-link { font-size: 1rem; }
p {text-align: justify;}
}

View File

@ -0,0 +1,168 @@
@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap');
.card {
background-color: rgba(255, 255, 255, 0.3);
backdrop-filter: blur(2px);
}
.table {
color: #f2d8bb !important;
}
.navbar-collapse {
height: 100vh;
text-align: center !important;
align-content: center;
}
.navbar-collapse .nav-link {
font-size: 1.2rem;
letter-spacing: 2px;
}
.navbar-collapse .nav-item:not(:last-child) {
padding: 0.2em 1em;
}
.navbar {
background-color: #022c28;
color: #d0eae9;
}
.nav-link {
color: #d0eae9 !important;
}
.content {
top: 60px;
}
body {
background-color: #022c28;
background-attachment: fixed;
background-position: center;
background-size: cover;
color: aqua;
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 300;
font-style: normal;
font-size: 1rem; /* Base size */
}
h1 {
font-weight: 700;
font-size: 2.5rem;
padding-top: 30px;
padding-bottom: 10px;
}
h2 {
font-weight: 500;
font-size: 2rem;
padding-top: 15px;
padding-bottom: 10px;
}
h3 {
font-weight: 400;
font-size: 1.6rem;
padding-top: 10px;
padding-bottom: 10px;
}
p {
color: #fff;
font-size: 1.1rem;
}
li {
color: #fff;
font-size: 1rem;
text-align: center;
}
.btn-primary {
color: #d0eae9;
background-color: #014d4e;
border: 0px;
margin: 5px;
}
.btn-primary:hover {
color: #fff;
background-color: #086262;
border: 0px;
}
.row {
padding-bottom: 30px;
margin: 0 auto !important;
}
.searchInput::placeholder {
color: #d0eae9;
}
#myVideo {
position: fixed;
right: 0;
top: -100px;
min-width: 100%;
min-height: 100%;
transform: translateX(calc((100% - 100vw) / 2));
}
.img-fluid {
max-height: 50vh;
width: auto;
border-radius: 15px;
}
.sp-img {
box-shadow: 10px 10px 30px 0px rgba(0,0,0,0.75);
-webkit-box-shadow: 10px 10px 30px 0px rgba(0,0,0,0.75);
-moz-box-shadow: 10px 10px 30px 0px rgba(0,0,0,0.75);
}
.col {
align-items: center;
display: flex;
}
.form-select {
background-color: rgba(255, 255, 255, 0.2);
border-radius: 5px;
display: unset !important;
color: #fff;
}
.list-group-item,
.bg-light {
background-color: rgb(11 24 23 / 76%) !important;
backdrop-filter: blur(8px) !important;
}
.text-primary {
--bs-text-opacity: 1;
color: aqua;
}
/* 🔽 Mobile Responsiveness */
@media (max-width: 768px) {
h1 { font-size: 2rem; }
h2 { font-size: 1.6rem; }
h3 { font-size: 1.4rem; }
p, li { font-size: 1rem; }
.navbar-collapse .nav-link { font-size: 1.1rem; }
p {text-align: justify;}
}
@media (max-width: 480px) {
h1 { font-size: 1.6rem; }
h2 { font-size: 1.3rem; }
h3 { font-size: 1.1rem; }
p, li { font-size: 0.95rem; }
.navbar-collapse .nav-link { font-size: 1rem; }
p {text-align: justify;}
}

View File

@ -0,0 +1,168 @@
@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap');
.card {
background-color: rgba(255, 255, 255, 0.3);
backdrop-filter: blur(2px);
}
.table {
color: #f2d8bb !important;
}
.navbar-collapse {
height: 100vh;
text-align: center !important;
align-content: center;
}
.navbar-collapse .nav-link {
font-size: 1.2rem;
letter-spacing: 2px;
}
.navbar-collapse .nav-item:not(:last-child) {
padding: 0.2em 1em;
}
.navbar {
background-color: #022c28;
color: #d0eae9;
}
.nav-link {
color: #d0eae9 !important;
}
.content {
top: 60px;
}
body {
background-color: #022c28;
background-attachment: fixed;
background-position: center;
background-size: cover;
color: aqua;
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 300;
font-style: normal;
font-size: 1rem; /* Base size */
}
h1 {
font-weight: 700;
font-size: 2.5rem;
padding-top: 30px;
padding-bottom: 10px;
}
h2 {
font-weight: 500;
font-size: 2rem;
padding-top: 15px;
padding-bottom: 10px;
}
h3 {
font-weight: 400;
font-size: 1.6rem;
padding-top: 10px;
padding-bottom: 10px;
}
p {
color: #fff;
font-size: 1.1rem;
}
li {
color: #fff;
font-size: 1rem;
text-align: center;
}
.btn-primary {
color: #d0eae9;
background-color: #014d4e;
border: 0px;
margin: 5px;
}
.btn-primary:hover {
color: #fff;
background-color: #086262;
border: 0px;
}
.row {
padding-bottom: 30px;
margin: 0 auto !important;
}
.searchInput::placeholder {
color: #d0eae9;
}
#myVideo {
position: fixed;
right: 0;
top: -100px;
min-width: 100%;
min-height: 100%;
transform: translateX(calc((100% - 100vw) / 2));
}
.img-fluid {
max-height: 50vh;
width: auto;
border-radius: 15px;
}
.sp-img {
box-shadow: 10px 10px 30px 0px rgba(0,0,0,0.75);
-webkit-box-shadow: 10px 10px 30px 0px rgba(0,0,0,0.75);
-moz-box-shadow: 10px 10px 30px 0px rgba(0,0,0,0.75);
}
.col {
align-items: center;
display: flex;
}
.form-select {
background-color: rgba(255, 255, 255, 0.2);
border-radius: 5px;
display: unset !important;
color: #fff;
}
.list-group-item,
.bg-light {
background-color: rgb(11 24 23 / 76%) !important;
backdrop-filter: blur(8px) !important;
}
.text-primary {
--bs-text-opacity: 1;
color: aqua;
}
/* 🔽 Mobile Responsiveness */
@media (max-width: 768px) {
h1 { font-size: 2rem; }
h2 { font-size: 1.6rem; }
h3 { font-size: 1.4rem; }
p, li { font-size: 1rem; }
.navbar-collapse .nav-link { font-size: 1.1rem; }
p {text-align: justify;}
}
@media (max-width: 480px) {
h1 { font-size: 1.6rem; }
h2 { font-size: 1.3rem; }
h3 { font-size: 1.1rem; }
p, li { font-size: 0.95rem; }
.navbar-collapse .nav-link { font-size: 1rem; }
p {text-align: justify;}
}

View File

@ -0,0 +1,168 @@
@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap');
.card {
background-color: rgba(255, 255, 255, 0.3);
backdrop-filter: blur(2px);
}
.table {
color: #f2d8bb !important;
}
.navbar-collapse {
height: 100vh;
text-align: center !important;
align-content: center;
}
.navbar-collapse .nav-link {
font-size: 1.2rem;
letter-spacing: 2px;
}
.navbar-collapse .nav-item:not(:last-child) {
padding: 0.2em 1em;
}
.navbar {
background-color: #022c28;
color: #d0eae9;
}
.nav-link {
color: #d0eae9 !important;
}
.content {
top: 60px;
}
body {
background-color: #022c28;
background-attachment: fixed;
background-position: center;
background-size: cover;
color: aqua;
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 300;
font-style: normal;
font-size: 1rem; /* Base size */
}
h1 {
font-weight: 700;
font-size: 2.5rem;
padding-top: 30px;
padding-bottom: 10px;
}
h2 {
font-weight: 500;
font-size: 2rem;
padding-top: 15px;
padding-bottom: 10px;
}
h3 {
font-weight: 400;
font-size: 1.6rem;
padding-top: 10px;
padding-bottom: 10px;
}
p {
color: #fff;
font-size: 1.1rem;
}
li {
color: #fff;
font-size: 1rem;
text-align: center;
}
.btn-primary {
color: #d0eae9;
background-color: #014d4e;
border: 0px;
margin: 5px;
}
.btn-primary:hover {
color: #fff;
background-color: #086262;
border: 0px;
}
.row {
padding-bottom: 30px;
margin: 0 auto !important;
}
.searchInput::placeholder {
color: #d0eae9;
}
#myVideo {
position: fixed;
right: 0;
top: -100px;
min-width: 100%;
min-height: 100%;
transform: translateX(calc((100% - 100vw) / 2));
}
.img-fluid {
max-height: 50vh;
width: auto;
border-radius: 15px;
}
.sp-img {
box-shadow: 10px 10px 30px 0px rgba(0,0,0,0.75);
-webkit-box-shadow: 10px 10px 30px 0px rgba(0,0,0,0.75);
-moz-box-shadow: 10px 10px 30px 0px rgba(0,0,0,0.75);
}
.col {
align-items: center;
display: flex;
}
.form-select {
background-color: rgba(255, 255, 255, 0.2);
border-radius: 5px;
display: unset !important;
color: #fff;
}
.list-group-item,
.bg-light {
background-color: rgb(11 24 23 / 76%) !important;
backdrop-filter: blur(8px) !important;
}
.text-primary {
--bs-text-opacity: 1;
color: aqua;
}
/* 🔽 Mobile Responsiveness */
@media (max-width: 768px) {
h1 { font-size: 2rem; }
h2 { font-size: 1.6rem; }
h3 { font-size: 1.4rem; }
p, li { font-size: 1rem; }
.navbar-collapse .nav-link { font-size: 1.1rem; }
p {text-align: justify;}
}
@media (max-width: 480px) {
h1 { font-size: 1.6rem; }
h2 { font-size: 1.3rem; }
h3 { font-size: 1.1rem; }
p, li { font-size: 0.95rem; }
.navbar-collapse .nav-link { font-size: 1rem; }
p {text-align: justify;}
}

View File

@ -0,0 +1,168 @@
@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap');
.card {
background-color: rgba(255, 255, 255, 0.3);
backdrop-filter: blur(2px);
}
.table {
color: #f2d8bb !important;
}
.navbar-collapse {
height: 100vh;
text-align: center !important;
align-content: center;
}
.navbar-collapse .nav-link {
font-size: 1.2rem;
letter-spacing: 2px;
}
.navbar-collapse .nav-item:not(:last-child) {
padding: 0.2em 1em;
}
.navbar {
background-color: #022c28;
color: #d0eae9;
}
.nav-link {
color: #d0eae9 !important;
}
.content {
top: 60px;
}
body {
background-color: #022c28;
background-attachment: fixed;
background-position: center;
background-size: cover;
color: aqua;
font-family: "Montserrat", sans-serif;
font-optical-sizing: auto;
font-weight: 300;
font-style: normal;
font-size: 1rem; /* Base size */
}
h1 {
font-weight: 700;
font-size: 2.5rem;
padding-top: 30px;
padding-bottom: 10px;
}
h2 {
font-weight: 500;
font-size: 2rem;
padding-top: 15px;
padding-bottom: 10px;
}
h3 {
font-weight: 400;
font-size: 1.6rem;
padding-top: 10px;
padding-bottom: 10px;
}
p {
color: #fff;
font-size: 1.1rem;
}
li {
color: #fff;
font-size: 1rem;
text-align: center;
}
.btn-primary {
color: #d0eae9;
background-color: #014d4e;
border: 0px;
margin: 5px;
}
.btn-primary:hover {
color: #fff;
background-color: #086262;
border: 0px;
}
.row {
padding-bottom: 30px;
margin: 0 auto !important;
}
.searchInput::placeholder {
color: #d0eae9;
}
#myVideo {
position: fixed;
right: 0;
top: -100px;
min-width: 100%;
min-height: 100%;
transform: translateX(calc((100% - 100vw) / 2));
}
.img-fluid {
max-height: 50vh;
width: auto;
border-radius: 15px;
}
.sp-img {
box-shadow: 10px 10px 30px 0px rgba(0,0,0,0.75);
-webkit-box-shadow: 10px 10px 30px 0px rgba(0,0,0,0.75);
-moz-box-shadow: 10px 10px 30px 0px rgba(0,0,0,0.75);
}
.col {
align-items: center;
display: flex;
}
.form-select {
background-color: rgba(255, 255, 255, 0.2);
border-radius: 5px;
display: unset !important;
color: #fff;
}
.list-group-item,
.bg-light {
background-color: rgb(11 24 23 / 76%) !important;
backdrop-filter: blur(8px) !important;
}
.text-primary {
--bs-text-opacity: 1;
color: aqua;
}
/* 🔽 Mobile Responsiveness */
@media (max-width: 768px) {
h1 { font-size: 2rem; }
h2 { font-size: 1.6rem; }
h3 { font-size: 1.4rem; }
p, li { font-size: 1rem; }
.navbar-collapse .nav-link { font-size: 1.1rem; }
p {text-align: justify;}
}
@media (max-width: 480px) {
h1 { font-size: 1.6rem; }
h2 { font-size: 1.3rem; }
h3 { font-size: 1.1rem; }
p, li { font-size: 0.95rem; }
.navbar-collapse .nav-link { font-size: 1rem; }
p {text-align: justify;}
}

View File

@ -0,0 +1,473 @@
/*@import url('https://fonts.googleapis.com/css2?family=Quicksand&display=swap');*/
@import url('https://fonts.googleapis.com/css?family=Comfortaa:400,700,300');
.rz-html-editor-content {
background-color: #00000033;
}
.form-group {
margin-bottom: 5px;
}
/*search*/
p {
font-size: large;
/*text-align: justify;*/
}
li {
list-style: none;
}
label {
display: none;
}
.btn {
background: rgba(255, 255, 255, 0.5);
border: 0;
color: #000000;
/* width: 98%; */
font-weight: bold;
border-radius: 20px;
/*min-height: 50px;*/
transition: all 0.2s ease;
padding: 10px;
margin-top: 10px;
}
.btn:hover{
background: #e5b984;
color:#000000;
}
.menubtn {
background: rgba(255, 255, 255, 0.5);
border: 0;
color: #000000;
width: fit-content;
font-weight: bold;
border-radius: 20px;
height: 40px;
transition: all 0.2s ease;
padding: 10px;
margin: 10px;
}
.btn:active {
background: rgba(255, 255, 255, 1);
}
.btn:hover {
background: rgba(255, 255, 255, 0.8);
}
img {
border-radius: 20px !important;
}
input.search_bar{
border: none;
outline: none;
width: 75px;
border-radius: 55px;
margin: 0 auto;
font-size: 1.3em;
color: #0d2840;
padding: 15px 30px 15px 45px;
transition: all .3s cubic-bezier(0,0,.5,1.5);
box-shadow: 0 3px 10px -2px rgba(0,0,0,.1);
background: rgba(255, 255, 255, 0.3) url(https://i.imgur.com/seveWIw.png) no-repeat center center;
}
input.search_bar:focus{
width: 100%;
background-position: calc(100% - 35px) center
}
/*Removes default x in search fields (webkit only i guess)*/
input[type=search]::-webkit-search-cancel-button {
-webkit-appearance: none;
}
/*Changes the color of the placeholder*/
::-webkit-input-placeholder {
color: #0d2840;
opacity: .5;
}
:-moz-placeholder {
color: #0d2840;
opacity: .5;
}
::-moz-placeholder {
color: #0d2840;
opacity: .5;
}
:-ms-input-placeholder {
color: #0d2840;
opacity: .5;
}
/*search*/
/*Search2*/
.searchBox {
width: 60px;
background: rgba(255, 255, 255, 0.3);
height: 60px;
border-radius: 40px;
padding: 10px;
margin: 0 auto;
transition: 0.8s;
}
.searchInput:active > .searchBox{
width:100%
}
.searchInput:focus > .searchBox {
width: 100%
}
.searchBox:hover {
width: 100%;
}
.searchBox:hover > .searchInput {
width: calc(100% - 60px);
padding: 0 6px;
}
.searchBox:hover > .searchButton {
background: white;
color: #2f3640;
}
.searchButton {
color: white;
float: right;
width: 40px;
height: 40px;
border-radius: 50%;
background-color: #e493d0;
background-image: radial-gradient(closest-side, rgba(235, 105, 78, 1), rgba(235, 105, 78, 0)), radial-gradient(closest-side, rgba(243, 11, 164, 1), rgba(243, 11, 164, 0)), radial-gradient(closest-side, rgba(254, 234, 131, 1), rgba(254, 234, 131, 0)), radial-gradient(closest-side, rgba(170, 142, 245, 1), rgba(170, 142, 245, 0)), radial-gradient(closest-side, rgba(248, 192, 147, 1), rgba(248, 192, 147, 0));
background-size: 130vmax 130vmax, 80vmax 80vmax, 90vmax 90vmax, 110vmax 110vmax, 90vmax 90vmax;
background-position: -80vmax -80vmax, 60vmax -30vmax, 10vmax 10vmax, -30vmax -10vmax, 50vmax 50vmax;
background-repeat: no-repeat;
animation: 10s movement linear infinite;
display: flex;
justify-content: center;
align-items: center;
}
.searchInput {
border: none;
background: none;
outline: none;
font-size: 1.3em !important;
color: #0d2840 !important;
float: left;
padding: 0;
color: white;
font-size: 16px;
transition: 0.4s;
line-height: 40px;
width: 0px;
}
/*Search2*/
.event {
border-radius: 20px !important;
background-color: rgba(255, 255, 255, 0.2) !important;
backdrop-filter: blur(20px);
border: 0;
box-shadow: 0 2px 20px rgba(0, 0, 0, 0.06), 0 2px 4px rgba(0, 0, 0, 0.07);
transition: all 0.15s ease;
}
/*card design*/
.card {
border-radius: 20px !important;
overflow: hidden;
background-color: rgba(255, 255, 255, 0.2) !important;
backdrop-filter: blur(20px);
border: 0;
box-shadow: 0 2px 20px rgba(0, 0, 0, 0.06), 0 2px 4px rgba(0, 0, 0, 0.07);
transition: all 0.15s ease;
}
.card:hover {
box-shadow: 0 6px 30px rgba(0, 0, 0, 0.1), 0 10px 8px rgba(0, 0, 0, 0.015);
}
.card-body .card-title {
font-family: 'Lato', sans-serif;
font-weight: 700;
letter-spacing: 0.3px;
font-size: 24px;
color: #121212;
}
.card-text {
font-family: 'Lato', sans-serif;
font-weight: 400;
font-size: 15px;
letter-spacing: 0.3px;
color: #4E4E4E;
}
.card .container {
width: 88%;
/*background: #F0EEF8;*/
border-radius: 30px;
/*height: 140px;*/
display: flex;
align-items: center;
justify-content: center;
}
.container:hover > img {
transform: scale(1.2);
}
.container img {
/*padding: 75px;*/
/*margin-top: -40px;
margin-bottom: -40px;*/
transition: 0.4s ease;
cursor: pointer;
}
/*card design*/
/*bg*/
:root {
font-size: 15px;
}
body {
font-family: 'Comfortaa', 'Arial Narrow', Arial, sans-serif;
/*font-family: 'Quicksand', sans-serif;*/
margin: 0;
min-height: 100vh;
background-color: #e493d0;
background-image: radial-gradient(closest-side, rgba(235, 105, 78, 1), rgba(235, 105, 78, 0)), radial-gradient(closest-side, rgba(243, 11, 164, 1), rgba(243, 11, 164, 0)), radial-gradient(closest-side, rgba(254, 234, 131, 1), rgba(254, 234, 131, 0)), radial-gradient(closest-side, rgba(170, 142, 245, 1), rgba(170, 142, 245, 0)), radial-gradient(closest-side, rgba(248, 192, 147, 1), rgba(248, 192, 147, 0));
background-size: 130vmax 130vmax, 80vmax 80vmax, 90vmax 90vmax, 110vmax 110vmax, 90vmax 90vmax;
background-position: -80vmax -80vmax, 60vmax -30vmax, 10vmax 10vmax, -30vmax -10vmax, 50vmax 50vmax;
background-repeat: no-repeat;
/*animation: 10s movement linear infinite;*/
}
body::after {
content: '';
display: block;
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
.myspan {
position: relative;
z-index: 10;
display: flex;
min-height: 100vh;
width: 100%;
justify-content: center;
align-items: center;
font-size: 5rem;
color: transparent;
text-shadow: 0px 0px 1px rgba(255, 255, 255, .6), 0px 4px 4px rgba(0, 0, 0, .05);
letter-spacing: .2rem;
}
/*@keyframes movement {
0%, 100% {
background-size: 130vmax 130vmax, 80vmax 80vmax, 90vmax 90vmax, 110vmax 110vmax, 90vmax 90vmax;
background-position: -80vmax -80vmax, 60vmax -30vmax, 10vmax 10vmax, -30vmax -10vmax, 50vmax 50vmax;
}
25% {
background-size: 100vmax 100vmax, 90vmax 90vmax, 100vmax 100vmax, 90vmax 90vmax, 60vmax 60vmax;
background-position: -60vmax -90vmax, 50vmax -40vmax, 0vmax -20vmax, -40vmax -20vmax, 40vmax 60vmax;
}
50% {
background-size: 80vmax 80vmax, 110vmax 110vmax, 80vmax 80vmax, 60vmax 60vmax, 80vmax 80vmax;
background-position: -50vmax -70vmax, 40vmax -30vmax, 10vmax 0vmax, 20vmax 10vmax, 30vmax 70vmax;
}
75% {
background-size: 90vmax 90vmax, 90vmax 90vmax, 100vmax 100vmax, 90vmax 90vmax, 70vmax 70vmax;
background-position: -50vmax -40vmax, 50vmax -30vmax, 20vmax 0vmax, -10vmax 10vmax, 40vmax 60vmax;
}
}*/
/*bg*/
.mytextarea {
background-color: rgba(255, 255, 255, 0.3);
backdrop-filter: blur(20px);
padding: 10px;
border-radius: 25px !important;
border-width: 0px;
height: unset !important;
}
.mytextarea:active {
border-width: 0px;
}
.mytextarea:focus-visible {
background-color: rgba(255, 255, 255, 0.5);
border-width: 0px !important;
outline: -webkit-focus-ring-color auto 0px;
outline-color: transparent;
}
.navbar-toggler-icon {
/*background-image: var(--bs-navbar-toggler-icon-bg);*/
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e;");
z-index: 10;
}
.navbar-brand {
font-size: 1.7rem;
}
.form-select {
background-color: rgba(255, 255, 255, 0.2);
border-radius: 55px;
}
.form-select > option {
background-color: rgba(255, 255, 255, 0.2)
}
.contactform-overlay {
position: fixed;
z-index: 100;
height: 100vh;
width: 100%;
padding: 100px;
top: 0px;
left: 0px;
/* padding-top: 10vh; */
backdrop-filter: blur(20px);
/* background-color: rgba(1, 1, 1, .4); */
}
.form-control {
background-color: rgba(255,255,255,0.4);
border-radius: 25px;
height: 50px;
}
.contactform-close-overlay {
position: relative;
height: 10vh;
}
.contactform-popup-content {
height: 80vh;
margin: 0px;
padding: 0px;
}
.contactform-popup-close {
position: relative;
height: 10vh;
z-index: 80;
}
.calendly-overlay {
position: absolute;
z-index: 100;
height: 100vh;
width: 100%;
top: 0px;
/* padding-top: 10vh; */
backdrop-filter: blur(20px);
/* background-color: rgba(1, 1, 1, .4); */
}
.calendly-close-overlay {
position: relative;
height: 10vh;
}
.calendly-popup-content {
height: 80vh;
margin: 0px;
padding: 0px;
}
.calendly-popup-close {
position: relative;
height: 10vh;
z-index: 80;
}
#myVideo {
position: fixed;
right: 0;
bottom: 0;
min-width: 100%;
min-height: 100%;
}
.form-select {
display: unset !important;
}
.navbar-collapse {
height: 100vh;
/*display: flex;
align-items: center;
justify-content: center;*/
text-align: center !important;
align-content: center;
overflow-y: scroll;
}
.navbar-collapse .nav-link {
font-size: 1.5em;
letter-spacing: 2px;
}
.navbar-collapse .nav-item:not(:last-child) {
border-bottom: 1px solid gray;
padding: 0.2em 4em;
}
.navbar {
background-color: #ffffff;
color: #000;
}
.nav-link {
color: #000;
}
.voicebutton {
width: 42.5px;
}
.content {
top: 60px;
}
.img-fluid {
max-height: 50vh;
}