From 11dbfd9f52a474de3c1fee6266a4b34862728acc Mon Sep 17 00:00:00 2001 From: VigneshwaranGovindharajan <111413464+VigneshwaranGovindharajan@users.noreply.github.com> Date: Tue, 7 Oct 2025 18:37:44 +0530 Subject: [PATCH 1/3] 984607: Added UG content for AI AssistView integration with STT and TTS in Core and MVC. --- .../EJ2_ASP.MVC/speech/speech-to-text.md | 42 +++++++++++++++++++ .../EJ2_ASP.MVC/speech/text-to-speech.md | 42 +++++++++++++++++++ .../EJ2_ASP.NETCORE/speech/speech-to-text.md | 42 +++++++++++++++++++ .../EJ2_ASP.NETCORE/speech/text-to-speech.md | 42 +++++++++++++++++++ 4 files changed, 168 insertions(+) create mode 100644 ej2-asp-core-mvc/ai-assistview/EJ2_ASP.MVC/speech/speech-to-text.md create mode 100644 ej2-asp-core-mvc/ai-assistview/EJ2_ASP.MVC/speech/text-to-speech.md create mode 100644 ej2-asp-core-mvc/ai-assistview/EJ2_ASP.NETCORE/speech/speech-to-text.md create mode 100644 ej2-asp-core-mvc/ai-assistview/EJ2_ASP.NETCORE/speech/text-to-speech.md diff --git a/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.MVC/speech/speech-to-text.md b/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.MVC/speech/speech-to-text.md new file mode 100644 index 0000000000..7aaee82cd9 --- /dev/null +++ b/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.MVC/speech/speech-to-text.md @@ -0,0 +1,42 @@ +--- +layout: post +title: Speech-to-Text With ##Platform_Name## AI AssistView Control | Syncfusion +description: Checkout and learn about configuration of Speech-to-Text with Azure OpenAI in ##Platform_Name## AI AssistView control of Syncfusion Essential JS 2 and more. +platform: ej2-asp-core-mvc +control: Azure Open AI +publishingplatform: ##Platform_Name## +documentation: ug +--- + +# Speech-to-Text in ASP.NET MVC AI AssistView + +The Syncfusion ASP.NET MVC AI AssistView control supports `Speech-to-Text` functionality through the browser's [Web Speech API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API), enabling conversion of spoken words into text using the device's microphone. + +## Prerequisites + +Before integrating `Speech-to-Text`, ensure the following: + +1. The Syncfusion AI AssistView control is properly set up in your ASP.NET MVC application. + - [ASP.NET MVC Getting Started Guide](../getting-started) + +2. The AI AssistView control is integrated with [Azure OpenAI](https://microsoft.github.io/PartnerResources/skilling/ai-ml-academy/resources/openai). + - [Integration of Azure OpenAI With ASP.NET MVC AI AssistView control](../ai-integrations/openai-integration) + +## Configure Speech-to-Text + +To enable Speech-to-Text functionality, modify the `Index.cshtml` file to incorporate the Web Speech API. The [SpeechToText](https://ej2.syncfusion.com/aspnetmvc/documentation/speech-to-text/getting-started) control listens for microphone input, transcribes spoken words, and updates the AI AssistView's editable footer with the transcribed text. The transcribed text is then sent as a prompt to the Azure OpenAI service via the AI AssistView control. + +{% tabs %} +{% highlight razor tabtitle="CSHTML" %} +{% include code-snippet/ai-assistview/speech/stt/razor %} +{% endhighlight %} +{% highlight c# tabtitle="SpeechToText.cs" %} +{% include code-snippet/ai-assistview/speech/stt/speechtotextmvc.cs %} +{% endhighlight %} +{% endtabs %} + +![Integrating Speech-to-Text with AI AssistView](../images/assist-stt.png) + +## See Also + +* [Text-to-Speech](./text-to-speech) diff --git a/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.MVC/speech/text-to-speech.md b/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.MVC/speech/text-to-speech.md new file mode 100644 index 0000000000..a39af05f3d --- /dev/null +++ b/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.MVC/speech/text-to-speech.md @@ -0,0 +1,42 @@ +--- +layout: post +title: Text-to-Speech With ##Platform_Name## AI AssistView Control | Syncfusion +description: Checkout and learn about configuration of Text-to-Speech with Azure OpenAI in ##Platform_Name## AI AssistView control of Syncfusion Essential JS 2 and more. +platform: ej2-asp-core-mvc +control: Azure Open AI +publishingplatform: ##Platform_Name## +documentation: ug +--- + +# Text-to-Speech in ASP.NET MVC AI AssistView + +The Syncfusion TypeScript AI AssistView component supports `Text-to-Speech` (TTS) functionality using the browser's Web Speech API specifically using the [SpeechSynthesisUtterance](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance) interface to convert AI-generated response into spoken audio. + +## Prerequisites + +Before integrating `Text-to-Speech`, ensure the following: + +1. The Syncfusion AI AssistView control is properly set up in your ASP.NET MVC application. + - [ASP.NET MVC Getting Started Guide](../getting-started) + +2. The AI AssistView control is integrated with [Azure OpenAI](https://microsoft.github.io/PartnerResources/skilling/ai-ml-academy/resources/openai). + - [Integration of Azure OpenAI With ASP.NET MVC AI AssistView control](../ai-integrations/openai-integration) + +## Configure Text-to-Speech + +To enable Text-to-Speech functionality, modify the `Index.cshtml` file to incorporate the Web Speech API. A custom `Read Aloud` button is added to the response toolbar using the [ResponseToolbarSettings](https://help.syncfusion.com/cr/aspnetmvc-js2/Syncfusion.EJ2.InteractiveChat.AIAssistViewResponseToolbarSettings.html) property. When clicked, the [ItemClicked](https://help.syncfusion.com/cr/aspnetmvc-js2/Syncfusion.EJ2.InteractiveChat.AIAssistViewResponseToolbarSettings.html#Syncfusion_EJ2_InteractiveChat_AIAssistViewResponseToolbarSettings_ItemClicked) event extracts plain text from the generated AI response and use the browser SpeechSynthesis API to read it aloud. + +{% tabs %} +{% highlight razor tabtitle="CSHTML" %} +{% include code-snippet/ai-assistview/speech/tts/razor %} +{% endhighlight %} +{% highlight c# tabtitle="SpeechToText.cs" %} +{% include code-snippet/ai-assistview/speech/tts/texttospeechmvc.cs %} +{% endhighlight %} +{% endtabs %} + +![Integrating Text-to-Speech with AI AssistView](../images/assist-tts.png) + +## See Also + +* [Speech-to-Text](./speech-to-text) diff --git a/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.NETCORE/speech/speech-to-text.md b/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.NETCORE/speech/speech-to-text.md new file mode 100644 index 0000000000..7095814607 --- /dev/null +++ b/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.NETCORE/speech/speech-to-text.md @@ -0,0 +1,42 @@ +--- +layout: post +title: Speech-to-Text With ##Platform_Name## AI AssistView Control | Syncfusion +description: Checkout and learn about configuration of Speech-to-Text with Azure OpenAI in ##Platform_Name## AI AssistView control of Syncfusion Essential JS 2 and more. +platform: ej2-asp-core-mvc +control: Azure Open AI +publishingplatform: ##Platform_Name## +documentation: ug +--- + +# Speech-to-Text in ASP.NET Core AI AssistView + +The Syncfusion ASP.NET Core AI AssistView control supports `Speech-to-Text` functionality through the browser's [Web Speech API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API), enabling conversion of spoken words into text using the device's microphone. + +## Prerequisites + +Before integrating `Speech-to-Text`, ensure the following: + +1. The Syncfusion AI AssistView control is properly set up in your ASP.NET Core application. + - [ASP.NET Core Getting Started Guide](../getting-started) + +2. The AI AssistView control is integrated with [Azure OpenAI](https://microsoft.github.io/PartnerResources/skilling/ai-ml-academy/resources/openai). + - [Integration of Azure OpenAI With ASP.NET Core AI AssistView control](../ai-integrations/openai-integration) + +## Configure Speech-to-Text + +To enable Speech-to-Text functionality, modify the `Index.cshtml` file to incorporate the Web Speech API. The [SpeechToText](https://ej2.syncfusion.com/aspnetcore/documentation/speech-to-text/getting-started) control listens for microphone input, transcribes spoken words, and updates the AI AssistView's editable footer with the transcribed text. The transcribed text is then sent as a prompt to the Azure OpenAI service via the AI AssistView control. + +{% tabs %} +{% highlight razor tabtitle="CSHTML" %} +{% include code-snippet/ai-assistview/speech/stt/tagHelper %} +{% endhighlight %} +{% highlight c# tabtitle="Gemini.cs" %} +{% include code-snippet/ai-assistview/speech/stt/speechtotextcore.cs %} +{% endhighlight %} +{% endtabs %} + +![Integrating Speech-to-Text with AI AssistView](../images/assist-stt.png) + +## See Also + +* [Text-to-Speech](./text-to-speech) diff --git a/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.NETCORE/speech/text-to-speech.md b/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.NETCORE/speech/text-to-speech.md new file mode 100644 index 0000000000..18e447ee1a --- /dev/null +++ b/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.NETCORE/speech/text-to-speech.md @@ -0,0 +1,42 @@ +--- +layout: post +title: Text-to-Speech With ##Platform_Name## AI AssistView Control | Syncfusion +description: Checkout and learn about configuration of Text-to-Speech with Azure OpenAI in ##Platform_Name## AI AssistView control of Syncfusion Essential JS 2 and more. +platform: ej2-asp-core-mvc +control: Azure Open AI +publishingplatform: ##Platform_Name## +documentation: ug +--- + +# Text-to-Speech in ASP.NET Core AI AssistView + +The Syncfusion TypeScript AI AssistView component supports `Text-to-Speech` (TTS) functionality using the browser's Web Speech API specifically using the [SpeechSynthesisUtterance](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance) interface to convert AI-generated response into spoken audio. + +## Prerequisites + +Before integrating `Text-to-Speech`, ensure the following: + +1. The Syncfusion AI AssistView control is properly set up in your ASP.NET Core application. + - [ASP.NET Core Getting Started Guide](../getting-started) + +2. The AI AssistView control is integrated with [Azure OpenAI](https://microsoft.github.io/PartnerResources/skilling/ai-ml-academy/resources/openai). + - [Integration of Azure OpenAI With ASP.NET Core AI AssistView control](../ai-integrations/openai-integration) + +## Configure Text-to-Speech + +To enable Text-to-Speech functionality, modify the `Index.cshtml` file to incorporate the Web Speech API. A custom `Read Aloud` button is added to the response toolbar using the `e-aiassistview-responsetoolbarsettings` tag helper. When clicked, the [itemClicked](https://help.syncfusion.com/cr/aspnetcore-js2/Syncfusion.EJ2.InteractiveChat.AIAssistViewResponseToolbarSettings.html#Syncfusion_EJ2_InteractiveChat_AIAssistViewResponseToolbarSettings_ItemClicked) event extracts plain text from the generated AI response and use the browser SpeechSynthesis API to read it aloud. + +{% tabs %} +{% highlight razor tabtitle="CSHTML" %} +{% include code-snippet/ai-assistview/speech/tts/tagHelper %} +{% endhighlight %} +{% highlight c# tabtitle="Gemini.cs" %} +{% include code-snippet/ai-assistview/speech/tts/texttospeechcore.cs %} +{% endhighlight %} +{% endtabs %} + +![Integrating Text-to-Speech with AI AssistView](../images/assist-tts.png) + +## See Also + +* [Speech-to-Text](./speech-to-text) From 79c57409d1a22e8b8e991f3c1e154a9d42856af1 Mon Sep 17 00:00:00 2001 From: VigneshwaranGovindharajan <111413464+VigneshwaranGovindharajan@users.noreply.github.com> Date: Fri, 10 Oct 2025 17:14:57 +0530 Subject: [PATCH 2/3] 984607: Added UG content and code snippet for AI AssistView integration with STT and TTS. --- .../EJ2_ASP.MVC/speech/speech-to-text.md | 2 +- .../EJ2_ASP.MVC/speech/text-to-speech.md | 2 +- .../EJ2_ASP.NETCORE/speech/speech-to-text.md | 2 +- .../EJ2_ASP.NETCORE/speech/text-to-speech.md | 2 +- .../ai-assistview/images/aiassist-stt.png | Bin 0 -> 15195 bytes .../ai-assistview/images/aiassist-tts.png | Bin 0 -> 24454 bytes .../ai-assistview/speech/stt/razor | 252 ++++++++++++++++++ .../speech/stt/speechtotextcore.cs | 84 ++++++ .../speech/stt/speechtotextmvc.cs | 69 +++++ .../ai-assistview/speech/stt/tagHelper | 249 +++++++++++++++++ .../ai-assistview/speech/tts/razor | 154 +++++++++++ .../ai-assistview/speech/tts/tagHelper | 150 +++++++++++ .../speech/tts/texttospeechcore.cs | 89 +++++++ .../speech/tts/texttospeechmvc.cs | 79 ++++++ 14 files changed, 1130 insertions(+), 4 deletions(-) create mode 100644 ej2-asp-core-mvc/ai-assistview/images/aiassist-stt.png create mode 100644 ej2-asp-core-mvc/ai-assistview/images/aiassist-tts.png create mode 100644 ej2-asp-core-mvc/code-snippet/ai-assistview/speech/stt/razor create mode 100644 ej2-asp-core-mvc/code-snippet/ai-assistview/speech/stt/speechtotextcore.cs create mode 100644 ej2-asp-core-mvc/code-snippet/ai-assistview/speech/stt/speechtotextmvc.cs create mode 100644 ej2-asp-core-mvc/code-snippet/ai-assistview/speech/stt/tagHelper create mode 100644 ej2-asp-core-mvc/code-snippet/ai-assistview/speech/tts/razor create mode 100644 ej2-asp-core-mvc/code-snippet/ai-assistview/speech/tts/tagHelper create mode 100644 ej2-asp-core-mvc/code-snippet/ai-assistview/speech/tts/texttospeechcore.cs create mode 100644 ej2-asp-core-mvc/code-snippet/ai-assistview/speech/tts/texttospeechmvc.cs diff --git a/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.MVC/speech/speech-to-text.md b/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.MVC/speech/speech-to-text.md index 7aaee82cd9..4de77f98ca 100644 --- a/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.MVC/speech/speech-to-text.md +++ b/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.MVC/speech/speech-to-text.md @@ -35,7 +35,7 @@ To enable Speech-to-Text functionality, modify the `Index.cshtml` file to incorp {% endhighlight %} {% endtabs %} -![Integrating Speech-to-Text with AI AssistView](../images/assist-stt.png) +![Integrating Speech-to-Text with AI AssistView](images/aiassist-stt.png) ## See Also diff --git a/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.MVC/speech/text-to-speech.md b/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.MVC/speech/text-to-speech.md index a39af05f3d..394cb71033 100644 --- a/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.MVC/speech/text-to-speech.md +++ b/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.MVC/speech/text-to-speech.md @@ -35,7 +35,7 @@ To enable Text-to-Speech functionality, modify the `Index.cshtml` file to incorp {% endhighlight %} {% endtabs %} -![Integrating Text-to-Speech with AI AssistView](../images/assist-tts.png) +![Integrating Text-to-Speech with AI AssistView](images/aiassist-tts.png) ## See Also diff --git a/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.NETCORE/speech/speech-to-text.md b/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.NETCORE/speech/speech-to-text.md index 7095814607..0cc91748f4 100644 --- a/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.NETCORE/speech/speech-to-text.md +++ b/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.NETCORE/speech/speech-to-text.md @@ -35,7 +35,7 @@ To enable Speech-to-Text functionality, modify the `Index.cshtml` file to incorp {% endhighlight %} {% endtabs %} -![Integrating Speech-to-Text with AI AssistView](../images/assist-stt.png) +![Integrating Speech-to-Text with AI AssistView](images/aiassist-stt.png) ## See Also diff --git a/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.NETCORE/speech/text-to-speech.md b/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.NETCORE/speech/text-to-speech.md index 18e447ee1a..a5d6cd4c8a 100644 --- a/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.NETCORE/speech/text-to-speech.md +++ b/ej2-asp-core-mvc/ai-assistview/EJ2_ASP.NETCORE/speech/text-to-speech.md @@ -35,7 +35,7 @@ To enable Text-to-Speech functionality, modify the `Index.cshtml` file to incorp {% endhighlight %} {% endtabs %} -![Integrating Text-to-Speech with AI AssistView](../images/assist-tts.png) +![Integrating Text-to-Speech with AI AssistView](images/aiassist-tts.png) ## See Also diff --git a/ej2-asp-core-mvc/ai-assistview/images/aiassist-stt.png b/ej2-asp-core-mvc/ai-assistview/images/aiassist-stt.png new file mode 100644 index 0000000000000000000000000000000000000000..6bc4fef3119ff5a0bd20d13028f0304375c7abc4 GIT binary patch literal 15195 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 O$o!(!1>$*+n129kx0cNS literal 0 HcmV?d00001 diff --git a/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/stt/razor b/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/stt/razor new file mode 100644 index 0000000000..55d99d58ea --- /dev/null +++ b/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/stt/razor @@ -0,0 +1,252 @@ +@using Syncfusion.EJ2.InteractiveChat + +
+ @Html.EJS().AIAssistView("aiAssistView").BannerTemplate("#bannerContent").FooterTemplate("#footerContent").StopRespondingClick("stopRespondingClick").PromptRequest("onPromptRequest").Created("onCreated").ToolbarSettings(new AIAssistViewToolbarSettings() + { + Items = ViewBag.Items, + ItemClicked = "toolbarItemClicked" + }).PromptToolbarSettings(new AIAssistViewPromptToolbarSettings() + { + ItemClicked = "promptToolbarItemClicked" + }).Render() +
+ + +@Html.AntiForgeryToken() + + + + + + + + + \ No newline at end of file diff --git a/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/stt/speechtotextcore.cs b/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/stt/speechtotextcore.cs new file mode 100644 index 0000000000..59d9422bbd --- /dev/null +++ b/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/stt/speechtotextcore.cs @@ -0,0 +1,84 @@ +using Azure; +using Azure.AI.OpenAI; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using OpenAI.Chat; + +namespace WebApplication.Pages +{ + public class IndexModel : PageModel + { + + public IndexViewModel ViewModel { get; set; } = new IndexViewModel(); + public void OnGet() + { + // Initialize toolbar items + ViewModel.Items = new List + { + new ToolbarItemModel + { + iconCss = "e-icons e-refresh", + align = "Right", + } + }; + } + + public async Task OnPostGetAIResponse([FromBody] PromptRequest request) + { + try + { + _logger.LogInformation("Received request with prompt: {Prompt}", request?.Prompt); + + if (string.IsNullOrEmpty(request?.Prompt)) + { + _logger.LogWarning("Prompt is null or empty."); + return BadRequest("Prompt cannot be empty."); + } + + string endpoint = "Your_Azure_OpenAI_Endpoint"; // Replace with your Azure OpenAI endpoint + string apiKey = "YOUR_AZURE_OPENAI_API_KEY"; // Replace with your Azure OpenAI API key + string deploymentName = "YOUR_DEPLOYMENT_NAME"; // Replace with your Azure OpenAI deployment name (e.g., gpt-4o-mini) + + var credential = new AzureKeyCredential(apiKey); + var client = new AzureOpenAIClient(new Uri(endpoint), credential); + var chatClient = client.GetChatClient(deploymentName); + + var chatCompletionOptions = new ChatCompletionOptions(); + var completion = await chatClient.CompleteChatAsync( + new[] { new UserChatMessage(request.Prompt) }, + chatCompletionOptions + ); + string responseText = completion.Value.Content[0].Text; + if (string.IsNullOrEmpty(responseText)) + { + _logger.LogError("Azure OpenAI API returned no text."); + return BadRequest("No response from Azure OpenAI."); + } + + _logger.LogInformation("Azure OpenAI response received: {Response}", responseText); + return new JsonResult(responseText); + } + catch (Exception ex) + { + _logger.LogError("Exception in Azure OpenAI call: {Message}", ex.Message); + return BadRequest($"Error generating response: {ex.Message}"); + } + } + } + + public class IndexViewModel + { + public List Items { get; set; } = new List(); + } + + public class PromptRequest + { + public string Prompt { get; set; } + } + + public class ToolbarItemModel + { + public string align { get; set; } + public string iconCss { get; set; } + } +} diff --git a/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/stt/speechtotextmvc.cs b/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/stt/speechtotextmvc.cs new file mode 100644 index 0000000000..d7372ee5ad --- /dev/null +++ b/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/stt/speechtotextmvc.cs @@ -0,0 +1,69 @@ +using OpenAI; +using OpenAI.Chat; +using Azure; +using Azure.AI.OpenAI; + +namespace AssistViewDemo.Controllers +{ + public class HomeController : Controller + { + + public List Items { get; set; } = new List(); + + public IActionResult Index() + { + Items.Add(new ToolbarItemModel { iconCss = "e-icons e-refresh", align = "Right" }); + ViewBag.Items = Items; + return View(); + } + public class ToolbarItemModel + { + public string iconCss { get; set; } + public string align { get; set; } + } + [HttpPost] + public async Task GetAIResponse([FromBody] PromptRequest request) + { + try + { + _logger.LogInformation("Received request with prompt: {Prompt}", request?.Prompt); + + if (string.IsNullOrEmpty(request?.Prompt)) + { + _logger.LogWarning("Prompt is null or empty."); + return BadRequest("Prompt cannot be empty."); + } + + // Azure OpenAI configuration + string endpoint = "Your_Azure_OpenAI_Endpoint"; // Replace with your Azure OpenAI endpoint + string apiKey = "YOUR_AZURE_OPENAI_API_KEY"; // Replace with your Azure OpenAI API key + string deploymentName = "YOUR_DEPLOYMENT_NAME"; // Replace with your Azure OpenAI deployment name (e.g., gpt-4o-mini) + + var credential = new AzureKeyCredential(apiKey); + var client = new AzureOpenAIClient(new Uri(endpoint), credential); + var chatClient = client.GetChatClient(deploymentName); + + var chatCompletionOptions = new ChatCompletionOptions(); + var completion = await chatClient.CompleteChatAsync( + new[] { new UserChatMessage(request.Prompt) }, + chatCompletionOptions + ); + + string responseText = completion.Value.Content[0].Text; + if (string.IsNullOrEmpty(responseText)) + { + _logger.LogError("Azure OpenAI API returned no text."); + return BadRequest("No response from Azure OpenAI."); + } + + _logger.LogInformation("Azure OpenAI response received: {Response}", responseText); + return Json(responseText); + } + catch (Exception ex) + { + _logger.LogError("Exception in Azure OpenAI call: {Message}", ex.Message); + return BadRequest($"Error generating response: {ex.Message}"); + } + } + } +} \ No newline at end of file diff --git a/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/stt/tagHelper b/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/stt/tagHelper new file mode 100644 index 0000000000..4640eb84bf --- /dev/null +++ b/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/stt/tagHelper @@ -0,0 +1,249 @@ +@model IndexModel +@using Syncfusion.EJ2.InteractiveChat + +
+ + + + +
+ + + + + + + + \ No newline at end of file diff --git a/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/tts/razor b/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/tts/razor new file mode 100644 index 0000000000..dd184a6dc8 --- /dev/null +++ b/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/tts/razor @@ -0,0 +1,154 @@ +@using Syncfusion.EJ2.InteractiveChat + +
+ @Html.EJS().AIAssistView("aiAssistView").BannerTemplate("#bannerContent").StopRespondingClick("stopRespondingClick").PromptRequest("onPromptRequest").Created("onCreated").ToolbarSettings(new AIAssistViewToolbarSettings() + { + Items = ViewBag.Items, + ItemClicked = "toolbarItemClicked" + }).ResponseToolbarSettings(new AIAssistViewResponseToolbarSettings() + { + Items = ViewBag.ResponseItems, + ItemClicked = "onResponseToolbarItemClicked" + }).Render() +
+ + +@Html.AntiForgeryToken() + + + + + + + + \ No newline at end of file diff --git a/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/tts/tagHelper b/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/tts/tagHelper new file mode 100644 index 0000000000..fdfd26e68e --- /dev/null +++ b/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/tts/tagHelper @@ -0,0 +1,150 @@ +@model IndexModel +@using Syncfusion.EJ2.InteractiveChat + +
+ + + + +
+ + + + + + + \ No newline at end of file diff --git a/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/tts/texttospeechcore.cs b/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/tts/texttospeechcore.cs new file mode 100644 index 0000000000..2c1d75f7d9 --- /dev/null +++ b/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/tts/texttospeechcore.cs @@ -0,0 +1,89 @@ +using Azure; +using Azure.AI.OpenAI; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using OpenAI.Chat; + +namespace WebApplication.Pages +{ + public class IndexModel : PageModel + { + + public IndexViewModel ViewModel { get; set; } = new IndexViewModel(); + public void OnGet() + { + ViewModel.Items = new List + { + new ToolbarItemModel { iconCss = "e-icons e-refresh", align = "Right" } + }; + + ViewModel.ResponseItems = new List + { + new ToolbarItemModel { iconCss = "e-icons e-assist-copy", tooltip = "Copy" }, + new ToolbarItemModel { iconCss = "e-icons e-audio", tooltip = "Read Aloud" }, + new ToolbarItemModel { iconCss = "e-icons e-assist-like", tooltip = "Like" }, + new ToolbarItemModel { iconCss = "e-icons e-assist-dislike", tooltip = "Need Improvement" } + }; + } + + public async Task OnPostGetAIResponse([FromBody] PromptRequest request) + { + try + { + _logger.LogInformation("Received request with prompt: {Prompt}", request?.Prompt); + + if (string.IsNullOrEmpty(request?.Prompt)) + { + _logger.LogWarning("Prompt is null or empty."); + return BadRequest("Prompt cannot be empty."); + } + + string endpoint = "Your_Azure_OpenAI_Endpoint"; // Replace with your Azure OpenAI endpoint + string apiKey = "YOUR_AZURE_OPENAI_API_KEY"; // Replace with your Azure OpenAI API key + string deploymentName = "YOUR_DEPLOYMENT_NAME"; // Replace with your Azure OpenAI deployment name (e.g., gpt-4o-mini) + + var credential = new AzureKeyCredential(apiKey); + var client = new AzureOpenAIClient(new Uri(endpoint), credential); + var chatClient = client.GetChatClient(deploymentName); + + var chatCompletionOptions = new ChatCompletionOptions(); + var completion = await chatClient.CompleteChatAsync( + new[] { new UserChatMessage(request.Prompt) }, + chatCompletionOptions + ); + string responseText = completion.Value.Content[0].Text; + if (string.IsNullOrEmpty(responseText)) + { + _logger.LogError("Azure OpenAI API returned no text."); + return BadRequest("No response from Azure OpenAI."); + } + + _logger.LogInformation("Azure OpenAI response received: {Response}", responseText); + return new JsonResult(responseText); + } + catch (Exception ex) + { + _logger.LogError("Exception in Azure OpenAI call: {Message}", ex.Message); + return BadRequest($"Error generating response: {ex.Message}"); + } + } + } + + public class IndexViewModel + { + public List Items { get; set; } = new List(); + public List ResponseItems { get; set; } = new List(); + } + + public class PromptRequest + { + public string Prompt { get; set; } + } + + public class ToolbarItemModel + { + public string align { get; set; } + public string iconCss { get; set; } + public string tooltip { get; set; } + } +} diff --git a/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/tts/texttospeechmvc.cs b/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/tts/texttospeechmvc.cs new file mode 100644 index 0000000000..fda7540088 --- /dev/null +++ b/ej2-asp-core-mvc/code-snippet/ai-assistview/speech/tts/texttospeechmvc.cs @@ -0,0 +1,79 @@ +using OpenAI; +using OpenAI.Chat; +using Azure; +using Azure.AI.OpenAI; + +namespace AssistViewDemo.Controllers +{ + public class HomeController : Controller + { + + public List Items { get; set; } = new List(); + public List ResponseItems { get; set; } = new List(); + + public IActionResult Index() + { + Items.Add(new ToolbarItemModel { iconCss = "e-icons e-refresh", align = "Right" }); + ResponseItems = new List + { + new ToolbarItemModel { iconCss = "e-icons e-assist-copy", tooltip = "Copy" }, + new ToolbarItemModel { iconCss = "e-icons e-audio", tooltip = "Read Aloud" }, + new ToolbarItemModel { iconCss = "e-icons e-assist-like", tooltip = "Like" }, + new ToolbarItemModel { iconCss = "e-icons e-assist-dislike", tooltip = "Need Improvement" } + }; + ViewBag.Items = Items; + ViewBag.ResponseItems = ResponseItems; + return View(); + } + public class ToolbarItemModel + { + public string iconCss { get; set; } + public string align { get; set; } + public string tooltip { get; set; } + } + [HttpPost] + public async Task GetAIResponse([FromBody] PromptRequest request) + { + try + { + _logger.LogInformation("Received request with prompt: {Prompt}", request?.Prompt); + + if (string.IsNullOrEmpty(request?.Prompt)) + { + _logger.LogWarning("Prompt is null or empty."); + return BadRequest("Prompt cannot be empty."); + } + + // Azure OpenAI configuration + string endpoint = "Your_Azure_OpenAI_Endpoint"; // Replace with your Azure OpenAI endpoint + string apiKey = "YOUR_AZURE_OPENAI_API_KEY"; // Replace with your Azure OpenAI API key + string deploymentName = "YOUR_DEPLOYMENT_NAME"; // Replace with your Azure OpenAI deployment name (e.g., gpt-4o-mini) + + var credential = new AzureKeyCredential(apiKey); + var client = new AzureOpenAIClient(new Uri(endpoint), credential); + var chatClient = client.GetChatClient(deploymentName); + + var chatCompletionOptions = new ChatCompletionOptions(); + var completion = await chatClient.CompleteChatAsync( + new[] { new UserChatMessage(request.Prompt) }, + chatCompletionOptions + ); + + string responseText = completion.Value.Content[0].Text; + if (string.IsNullOrEmpty(responseText)) + { + _logger.LogError("Azure OpenAI API returned no text."); + return BadRequest("No response from Azure OpenAI."); + } + + _logger.LogInformation("Azure OpenAI response received: {Response}", responseText); + return Json(responseText); + } + catch (Exception ex) + { + _logger.LogError("Exception in Azure OpenAI call: {Message}", ex.Message); + return BadRequest($"Error generating response: {ex.Message}"); + } + } + } +} \ No newline at end of file From 9b6234f922b2d7787f9db29aa75bf2d2a70d9b8a Mon Sep 17 00:00:00 2001 From: VigneshwaranGovindharajan <111413464+VigneshwaranGovindharajan@users.noreply.github.com> Date: Mon, 13 Oct 2025 08:56:19 +0530 Subject: [PATCH 3/3] 984607: Added UG content and code snippet for AI AssistView integration with STT and TTS. --- .../ai-integrations/open-ai/openaicore.cs | 34 ++++++++++--------- .../ai-integrations/open-ai/tagHelper | 1 + ej2-asp-core-toc.html | 10 ++++++ ej2-asp-mvc-toc.html | 10 ++++++ 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/ej2-asp-core-mvc/code-snippet/ai-assistview/ai-integrations/open-ai/openaicore.cs b/ej2-asp-core-mvc/code-snippet/ai-assistview/ai-integrations/open-ai/openaicore.cs index 5bc65aba86..843b0dd7b6 100644 --- a/ej2-asp-core-mvc/code-snippet/ai-assistview/ai-integrations/open-ai/openaicore.cs +++ b/ej2-asp-core-mvc/code-snippet/ai-assistview/ai-integrations/open-ai/openaicore.cs @@ -1,6 +1,8 @@ -using OpenAI; using Azure; using Azure.AI.OpenAI; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using OpenAI.Chat; namespace WebApplication4.Pages { public class IndexModel : PageModel @@ -68,22 +70,22 @@ public async Task OnPostGetAIResponse([FromBody] PromptRequest re return BadRequest($"Error generating response: {ex.Message}"); } } - } + } - public class IndexViewModel - { - public List Items { get; set; } = new List(); - public string[] PromptSuggestionData { get; set; } - } + public class IndexViewModel + { + public List Items { get; set; } = new List(); + public string[] PromptSuggestionData { get; set; } + } - public class PromptRequest - { - public string Prompt { get; set; } - } + public class PromptRequest + { + public string Prompt { get; set; } + } - public class ToolbarItemModel - { - public string align { get; set; } - public string iconCss { get; set; } - } + public class ToolbarItemModel + { + public string align { get; set; } + public string iconCss { get; set; } } +} diff --git a/ej2-asp-core-mvc/code-snippet/ai-assistview/ai-integrations/open-ai/tagHelper b/ej2-asp-core-mvc/code-snippet/ai-assistview/ai-integrations/open-ai/tagHelper index 103c1b2da7..a7872fe9c6 100644 --- a/ej2-asp-core-mvc/code-snippet/ai-assistview/ai-integrations/open-ai/tagHelper +++ b/ej2-asp-core-mvc/code-snippet/ai-assistview/ai-integrations/open-ai/tagHelper @@ -1,3 +1,4 @@ +@model IndexModel @using Syncfusion.EJ2.InteractiveChat @{ ViewData["Title"] = "AI Assistance with Gemini"; diff --git a/ej2-asp-core-toc.html b/ej2-asp-core-toc.html index 87906aa233..ffbadf2e44 100644 --- a/ej2-asp-core-toc.html +++ b/ej2-asp-core-toc.html @@ -217,6 +217,16 @@
  • Custom views
  • File attachments
  • Templates
  • +
  • Speech + +
  • Appearance
  • Accessibility
  • Methods
  • diff --git a/ej2-asp-mvc-toc.html b/ej2-asp-mvc-toc.html index 631debb537..a5a150daec 100644 --- a/ej2-asp-mvc-toc.html +++ b/ej2-asp-mvc-toc.html @@ -171,6 +171,16 @@
  • Custom views
  • File attachments
  • Templates
  • +
  • Speech + +
  • Appearance
  • Accessibility
  • Methods