diff --git a/BLAIzor.csproj b/BLAIzor.csproj index 2a947ee..35ed0f9 100644 --- a/BLAIzor.csproj +++ b/BLAIzor.csproj @@ -63,6 +63,9 @@ Always + + Always + Always diff --git a/Components/Pages/AgentTest.razor b/Components/Pages/AgentTest.razor new file mode 100644 index 0000000..130cff1 --- /dev/null +++ b/Components/Pages/AgentTest.razor @@ -0,0 +1,33 @@ +@page "/agent" +@using System.Text.Json +@using System.Text +@inject HttpClient Http +@inject IJSRuntime JS +@inject IConfiguration _configuration + + +
+ +
+ +
+ Home + + + + + + + + +
+
+
+@code { + private string Menu = "Tanulás, Gyakorlás, Tesztelés, Vizsgázás"; + + public async void MenuClick(string menuName) + { + //await CallCSharpMethod2(menuName, sessionId, true); + } +} diff --git a/Components/Pages/AgentTestKids.razor b/Components/Pages/AgentTestKids.razor new file mode 100644 index 0000000..c5ef4db --- /dev/null +++ b/Components/Pages/AgentTestKids.razor @@ -0,0 +1,102 @@ +@page "/kids" +@using BLAIzor.Services +@inject IJSRuntime JS +@inject OpenAIApiService openAiApiService + + + + + + + + + + +
+ +
+
+ Kids + + @if (ImageUrl is not null) + { +
+ +
+ } + @if (IsLoading) + { +

🎨 Kép készül... kis türelmet kérek!

+ } +
+
+
+ +@code { + private string Menu = "Tanulás, Gyakorlás, Tesztelés, Vizsgázás"; + + private string? ImageUrl; + private bool IsLoading = false; + + protected override void OnInitialized() + { + // Hook the static bridge to this instance + IllustrationBridge.OnPromptReceived = async (prompt) => + { + await GenerateImageFromPrompt(prompt); + }; + } + + private async Task GenerateImageFromPrompt(string prompt) + { + Console.WriteLine($"[Component] Generating image for: {prompt}"); + IsLoading = true; + ImageUrl = null; + StateHasChanged(); + + ImageUrl = await openAiApiService.GenerateImageAsync(prompt + ", watercolor, amazing colors"); + + IsLoading = false; + StateHasChanged(); + } + + public void MenuClick(string menuName) + { + // Optional: handle menu actions + } + + protected override void OnAfterRender(bool firstRender) + { + if (firstRender) + { + JS.InvokeVoidAsync("initTools"); + } + } +} diff --git a/Components/Pages/Index.razor b/Components/Pages/Index.razor index 779fb81..160239e 100644 --- a/Components/Pages/Index.razor +++ b/Components/Pages/Index.razor @@ -5,6 +5,7 @@ @using Google.Cloud.Speech.V1 @using Microsoft.AspNetCore.Identity.UI.Services @using System.Text +@using System.Net @using System.Text.Json @using Sidio.Sitemap.Blazor @inject AIService ChatGptService @@ -20,6 +21,7 @@ @inject DesignTemplateService DesignTemplateService @inject CssTemplateService CssTemplateService @inject CssInjectorService CssService +@inject HttpClient Http @attribute [Sitemap]
@@ -35,7 +37,7 @@ *@ -
+
@*
*@ @@ -44,16 +46,29 @@ + @{ + @if(VoiceEnabled) + { + if(STTEnabled) + { + + + } - + if(TTSEnabled) + { + + + } + } + } -
@@ -120,57 +135,6 @@ .catch(error => console.error(error)); } - var mediaRecorder; - var audioChunks = []; - var recButton = document.getElementById("recButton"); - var stopButton = document.getElementById("stopButton"); - var recText = document.getElementById("recordingText"); - - navigator.permissions.query({name: 'microphone'}).then(function (result) { - if (result.state == 'granted') { - } else if (result.state == 'prompt') { - } else if (result.state == 'denied') { - } - result.onchange = function () {}; - }); - - async function startRecording() { - if (recButton) { - recButton.hidden = true; - stopButton.hidden = false; - recText.textContent = "recording..."; - } - const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); - mediaRecorder = new MediaRecorder(stream); - - mediaRecorder.ondataavailable = event => audioChunks.push(event.data); - mediaRecorder.onstop = () => { - const audioBlob = new Blob(audioChunks, { type: 'audio/wav' }); - audioChunks = []; - console.log("media stopped"); - const reader = new FileReader(); - reader.onload = () => { - const base64Audio = reader.result.split(',')[1]; - DotNet.invokeMethodAsync('BLAIzor', 'ProcessAudio2', base64Audio, sessionId); - }; - reader.readAsDataURL(audioBlob); - }; - - mediaRecorder.start(); - } - - function stopRecording() { - mediaRecorder.stop(); - var recButton = document.getElementById("recButton"); - var stopButton = document.getElementById("stopButton"); - var recText = document.getElementById("recordingText"); - mediaRecorder.stream.getTracks().forEach(track => track.stop()); // Free memory - if (stopButton) { - stopButton.hidden = true; - recButton.hidden = false; - recText.textContent = ""; - } - } - - @code { 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; @@ -216,13 +179,78 @@ private string sessionId; private static readonly Dictionary _instances = new(); private string Menu; + private bool VoiceEnabled; + private bool TTSEnabled; + private bool STTEnabled; + private bool _initVoicePending = false; + private bool welcomeStage = true; + + + private string GetApiKey() => + configuration?.GetSection("ElevenLabsAPI")?.GetValue("ApiKey") ?? string.Empty; + + + private void MuteAI() + { + TTSEnabled = false; + } + + private async Task ConvertTextToSpeech() + { + // string plainText = WebUtility.HtmlDecode(HtmlContent.ToString()); + + if (string.IsNullOrWhiteSpace(TextContent) || VoiceEnabled == false || TTSEnabled == false || welcomeStage) + 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 = "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("initHints"); // sessionId = Guid.NewGuid().ToString(); // _instances[sessionId] = this; @@ -246,12 +274,16 @@ SiteId = SiteInfo.Id; _scopedContentService.SelectedBrandName = SiteInfo.SiteName; + + TTSEnabled = SiteInfo.TTSActive; + STTEnabled = SiteInfo.STTActive; } else { SiteId = 1; _scopedContentService.SelectedBrandName = "default"; - + TTSEnabled = false; + STTEnabled = false; } _scopedContentService.SelectedSiteId = SiteId; @@ -282,8 +314,15 @@ // await ChatGptService.ProcessUserIntent(sessionId, UserInput, SiteId, (int)SiteInfo.TemplateId!, collectionName, Menu); } UserInput = string.Empty; - await InvokeAsync(StateHasChanged); + // await InvokeAsync(StateHasChanged); + _initVoicePending = true; + } + if (_initVoicePending) + { + Console.WriteLine("PENDING VOICE--------------------------------------------------"); + _initVoicePending = false; + await jsRuntime.InvokeVoidAsync("initVoiceRecorder", "ProcessAudio2"); } } @@ -355,6 +394,8 @@ 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") { @@ -416,9 +457,11 @@ AIService.OnContentReceiveFinished += UpdateFinished; // ChatGptService.OnStatusChangeReceived += UpdateStatus; AIService.OnStatusChangeReceived += UpdateStatus; - + AIService.OnTextContentAvailable += UpdateTextContentForVoice; sessionId = Guid.NewGuid().ToString(); _instances[sessionId] = this; + + VoiceEnabled = configuration?.GetSection("AiSettings")?.GetValue("VoiceActivated") ?? false; } private async void UpdateContent(string receivedSessionId, string content) @@ -437,12 +480,24 @@ } } + private async void UpdateTextContentForVoice(string receivedSessionId, string content) + { + if (receivedSessionId == sessionId) // Only accept messages meant for this tab + { + + TextContent = content; + await ConvertTextToSpeech(); + //_scopedContentService.CurrentDOM = await jsRuntime.InvokeAsync("getDivContent", "currentContent"); + } + } + private async void UpdateFinished(string receivedSessionId) { if (receivedSessionId == sessionId) // Only accept messages meant for this tab { Console.WriteLine("Content update finished"); var result = await jsRuntime.InvokeAsync("getDivContent", "currentContent"); + //await ConvertTextToSpeech(); _scopedContentService.CurrentDOM = JsonSerializer.Serialize(result); Console.Write(_scopedContentService.CurrentDOM); } @@ -502,6 +557,7 @@ private async Task SendUserQuery() { + welcomeStage = false; if (!string.IsNullOrEmpty(UserInput)) { HtmlContent.Clear(); @@ -513,18 +569,19 @@ 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) + 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); + await ChatGptService.ProcessContentRequest(sessionId, menuItem, SiteId, (int)SiteInfo.TemplateId!, collectionName, menu, forceUnmodified); } UserInput = string.Empty; } @@ -565,6 +622,7 @@ AIService.OnContentReceived -= UpdateContent; AIService.OnContentReceiveFinished -= UpdateFinished; AIService.OnStatusChangeReceived -= UpdateStatus; + AIService.OnTextContentAvailable -= UpdateTextContentForVoice; } public async ValueTask DisposeAsync() diff --git a/Components/Pages/ManageSiteInfo.razor b/Components/Pages/ManageSiteInfo.razor index 0a71da6..8973ce5 100644 --- a/Components/Pages/ManageSiteInfo.razor +++ b/Components/Pages/ManageSiteInfo.razor @@ -16,6 +16,10 @@ Brand name: +