Clean code approvements, refractoring
This commit is contained in:
parent
85589532d7
commit
4effccf3a7
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
height: auto;
|
||||
}
|
||||
|
||||
video {
|
||||
#myVideo {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;}
|
||||
}
|
||||
|
|
@ -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;}
|
||||
}
|
||||
|
|
@ -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;}
|
||||
}
|
||||
|
|
@ -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;}
|
||||
}
|
||||
|
|
@ -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;}
|
||||
}
|
||||
|
|
@ -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;}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
Loading…
Reference in New Issue