diff --git a/ej2-javascript-toc.html b/ej2-javascript-toc.html index 3645e0557..8d784f8a2 100644 --- a/ej2-javascript-toc.html +++ b/ej2-javascript-toc.html @@ -174,12 +174,25 @@
  • Azure Open AI
  • +
  • + Ollama LLM +
  • Toolbar items
  • Custom views
  • File attachments
  • Templates
  • +
  • Speech + +
  • Appearance
  • Accessibility
  • Methods
  • diff --git a/ej2-javascript/ai-assistview/ai-integrations/es5-ollama-llm-integration.md b/ej2-javascript/ai-assistview/ai-integrations/es5-ollama-llm-integration.md new file mode 100644 index 000000000..82a4e4062 --- /dev/null +++ b/ej2-javascript/ai-assistview/ai-integrations/es5-ollama-llm-integration.md @@ -0,0 +1,99 @@ +--- +layout: post +title: LLM Model in ##Platform_Name## AI AssistView control | Syncfusion +description: Checkout and learn about Integration of LLM Model with ##Platform_Name## AI AssistView control of Syncfusion Essential JS 2 and more. +platform: ej2-javascript +control: AI AssistView +publishingplatform: ##Platform_Name## +documentation: ug +domainurl: ##DomainURL## +--- + +# LLM via Ollama With JavaScript AI AssistView control + +The Syncfusion AI AssistView supports integration with [LLM via Ollama](https://ollama.com), enabling advanced conversational AI features in your applications. This control acts as a UI for a support bot, where user prompts are sent to the selected AI service via API calls. + +## Prerequisites + +* Requires `Node.js` (v16 or higher) and `npm`. +* [Ollama](https://ollama.com) application should be installed to run and manage LLM models locally. + +## Step 1: Getting Started with the AI AssistView control + +Before integrating LLM model, ensure that the Syncfusion AI AssistView control is correctly rendered in your application: + +[ JavaScript Getting Started Guide](../getting-started) + +## Step 2: Install Dependencies + +Download and install `Ollama` based on your operating system: + +{% tabs %} +{% highlight ts tabtitle="Windows" %} + +1. Visit [Windows](https://ollama.com/download) +2. Click `Download for Windows` to get the `.exe installer`. +3. Run `OllamaSetup.exe` and follow the wizard to install. + +{% endhighlight %} + +{% highlight ts tabtitle="MAC" %} + +1. Visit [macOS](https://ollama.com/download/mac) +2. Click `Download for macOS` to get `.dmg file` +3. Install it by following the wizard. + +{% endhighlight %} + +{% highlight ts tabtitle="main.ts" %} + +1. Visit [Linux](https://ollama.com/download/linux) +2. Run the below command to install Ollama in your system + +```bash + +curl -fsSL https://ollama.ai/install.sh | sh + +``` + +{% endhighlight %} +{% endtabs %} + +## Step 3: Install and Run an Ollama Model + +1. Download and run a model using the following command. Replace `deepseek-r1` with your preferred model (e.g., `llama3`, `phi4`). See the [Ollama model](https://ollama.com/search) library for available models + +```bash + +ollama run deepseek-r1 + +``` + +2. Once the model download is complete, start the Ollama server to make the model accessible: + +```bash + +ollama serve + +``` + +## Step 4: Configure AI AssistView in JavaScript + +Create JavaScript application to integrate the `Ollama` model with AI AssistView control with the respective files + +{% tabs %} +{% highlight js tabtitle="index.js" %} +{% include code-snippet/ai-assistview/ai-integrations/llm-model/index.js %} +{% endhighlight %} +{% highlight html tabtitle="index.html" %} +{% include code-snippet/ai-assistview/ai-integrations/llm-model/index.html %} +{% endhighlight %} +{% endtabs %} + +{% previewsample "page.domainurl/code-snippet/ai-assistview/ai-integrations/llm-model" %} + +## Step 5: Run and Test + +Now, run the `index.html` in web browser, it will render the **Syncfusion® JavaScript AI AssistView** control. + +Open the hosted link to interact with AI model where you can enter prompts and receive responses from the `Ollama` model. diff --git a/ej2-javascript/ai-assistview/ai-integrations/ollama-llm-integration.md b/ej2-javascript/ai-assistview/ai-integrations/ollama-llm-integration.md new file mode 100644 index 000000000..8a477436b --- /dev/null +++ b/ej2-javascript/ai-assistview/ai-integrations/ollama-llm-integration.md @@ -0,0 +1,114 @@ +--- +layout: post +title: LLM Model in ##Platform_Name## AI AssistView control | Syncfusion +description: Checkout and learn about Integration of LLM Model with ##Platform_Name## AI AssistView control of Syncfusion Essential JS 2 and more. +platform: ej2-javascript +control: AI AssistView +publishingplatform: ##Platform_Name## +documentation: ug +domainurl: ##DomainURL## +--- + +# Integration of LLM via Ollama With TypeScript AI AssistView control + +The Syncfusion AI AssistView supports integration with [LLM via Ollama](https://ollama.com), enabling advanced conversational AI features in your applications. This control acts as a UI for a support bot, where user prompts are sent to the selected AI service via API calls. + +## Prerequisites + +* Requires `Node.js` (v16 or higher) and `npm`. +* [Ollama](https://ollama.com) application should be installed to run and manage LLM models locally. +* Syncfusion AI AssistView for React `@syncfusion/ej2-interactive-chat` installed in your project. + +## Step 1: Getting Started with the AI AssistView control + +Before integrating LLM model, ensure that the Syncfusion AI AssistView control is correctly rendered in your application: + +[ TypeScript Getting Started Guide](../getting-started) + +## Step 2: Install Dependencies + +* Install the Syncfusion AI AssistView in your project + +```bash + +npm install @syncfusion/ej2-interactive-chat --save + +``` + +* Download and install `Ollama` based on your operating system: + +{% tabs %} +{% highlight ts tabtitle="Windows" %} + +1. Visit [Windows](https://ollama.com/download) +2. Click `Download for Windows` to get the `.exe installer`. +3. Run `OllamaSetup.exe` and follow the wizard to install. + +{% endhighlight %} + +{% highlight ts tabtitle="MAC" %} + +1. Visit [macOS](https://ollama.com/download/mac) +2. Click `Download for macOS` to get `.dmg file` +3. Install it by following the wizard. + +{% endhighlight %} + +{% highlight ts tabtitle="main.ts" %} + +1. Visit [Linux](https://ollama.com/download/linux) +2. Run the below command to install Ollama in your system + +```bash + +curl -fsSL https://ollama.ai/install.sh | sh + +``` + +{% endhighlight %} +{% endtabs %} + +## Step 3: Install and Run an Ollama Model + +1. Download and run a model using the following command. Replace `deepseek-r1` with your preferred model (e.g., `llama3`, `phi4`). See the [Ollama model](https://ollama.com/search) library for available models + +```bash + +ollama run deepseek-r1 + +``` + +2. Once the model download is complete, start the Ollama server to make the model accessible: + +```bash + +ollama serve + +``` + +## Step 4: Integrate AI AssistView in TypeScript + +Create TypeScript application to integrate the `Ollama` model with AI AssistView control with the respective files + +{% tabs %} +{% highlight ts tabtitle="index.ts" %} +{% include code-snippet/ai-assistview/ai-integrations/llm-model/index.ts %} +{% endhighlight %} +{% highlight html tabtitle="index.html" %} +{% include code-snippet/ai-assistview/ai-integrations/llm-model/index.html %} +{% endhighlight %} +{% endtabs %} + +{% previewsample "page.domainurl/code-snippet/ai-assistview/ai-integrations/llm-model" %} + +## Step 5: Run and Test + +Run the application in the browser using the following command. + +```bash + +npm start + +``` + +Open the hosted link to interact with your AI model where you can enter prompts and receive responses from the `Ollama` model. diff --git a/ej2-javascript/ai-assistview/speech/es5-speech-to-text.md b/ej2-javascript/ai-assistview/speech/es5-speech-to-text.md new file mode 100644 index 000000000..299554620 --- /dev/null +++ b/ej2-javascript/ai-assistview/speech/es5-speech-to-text.md @@ -0,0 +1,43 @@ +--- +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-javascript +control: AI AssistView +publishingplatform: ##Platform_Name## +documentation: ug +domainurl: ##DomainURL## +--- + +# Speech-to-Text in JavaScript AI AssistView + +The Syncfusion JavaScript 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 JavaScript application. + - [JavaScript Getting Started Guide](../js/es5-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 JavaScript AI AssistView control](../ai-integrations/es5-openai-integration) + +## Configure Speech-to-Text + +To enable Speech-to-Text functionality, modify the `index.js` file to incorporate the Web Speech API. The [SpeechToText](https://ej2.syncfusion.com/javascript/documentation/speech-to-text/es5-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 js tabtitle="index.js" %} +{% include code-snippet/ai-assistview/speech/stt/index.js %} +{% endhighlight %} +{% highlight html tabtitle="index.html" %} +{% include code-snippet/ai-assistview/speech/stt/index.html %} +{% endhighlight %} +{% endtabs %} + +{% previewsample "page.domainurl/code-snippet/ai-assistview/speech/stt" %} + +## See Also + +* [Text-to-Speech](./es5-text-to-speech.md) diff --git a/ej2-javascript/ai-assistview/speech/es5-text-to-speech.md b/ej2-javascript/ai-assistview/speech/es5-text-to-speech.md new file mode 100644 index 000000000..fd8fb9d44 --- /dev/null +++ b/ej2-javascript/ai-assistview/speech/es5-text-to-speech.md @@ -0,0 +1,43 @@ +--- +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-javascript +control: AI AssistView +publishingplatform: ##Platform_Name## +documentation: ug +domainurl: ##DomainURL## +--- + +# Text-to-Speech in JavaScript AI AssistView + +The Syncfusion JavaScript 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 JavaScript application. + - [JavaScript Getting Started Guide](../js/es5-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 JavaScript AI AssistView control](../ai-integrations/es5-openai-integration) + +## Configure Text-to-Speech + +To enable Text-to-Speech functionality, modify the `index.js` file to incorporate the Web Speech API. A custom `Read Aloud` button is added to the response toolbar using the [responseToolbarSettings](https://ej2.syncfusion.com/javascript/documentation/api/ai-assistview/#responsetoolbarsettings) property. When clicked, the [itemClicked](https://ej2.syncfusion.com/javascript/documentation/api/ai-assistview/responsetoolbarsettingsmodel/#itemclicked) event extracts plain text from the generated AI response and use the browser SpeechSynthesis API to read it aloud. + +{% tabs %} +{% highlight js tabtitle="index.js" %} +{% include code-snippet/ai-assistview/speech/tts/index.js %} +{% endhighlight %} +{% highlight html tabtitle="index.html" %} +{% include code-snippet/ai-assistview/speech/tts/index.html %} +{% endhighlight %} +{% endtabs %} + +{% previewsample "page.domainurl/code-snippet/ai-assistview/speech/tts" %} + +## See Also + +* [Speech-to-Text](./es5-speech-to-text.md) diff --git a/ej2-javascript/ai-assistview/speech/speech-to-text.md b/ej2-javascript/ai-assistview/speech/speech-to-text.md new file mode 100644 index 000000000..0d1701e19 --- /dev/null +++ b/ej2-javascript/ai-assistview/speech/speech-to-text.md @@ -0,0 +1,43 @@ +--- +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-javascript +control: AI AssistView +publishingplatform: ##Platform_Name## +documentation: ug +domainurl: ##DomainURL## +--- + +# Speech-to-Text in TypeScript AI AssistView + +The Syncfusion TypeScript 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 TypeScript application. + - [TypeScript Getting Started Guide](../ts/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 TypeScript AI AssistView control](../ai-integrations/openai-integration) + +## Configure Speech-to-Text + +To enable Speech-to-Text functionality, modify the `index.ts` file to incorporate the Web Speech API. The [SpeechToText](https://ej2.syncfusion.com/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 ts tabtitle="index.ts" %} +{% include code-snippet/ai-assistview/speech/stt/index.ts %} +{% endhighlight %} +{% highlight html tabtitle="index.html" %} +{% include code-snippet/ai-assistview/speech/stt/index.html %} +{% endhighlight %} +{% endtabs %} + +{% previewsample "page.domainurl/code-snippet/ai-assistview/speech/stt" %} + +## See Also + +* [Text-to-Speech](./text-to-speech.md) diff --git a/ej2-javascript/ai-assistview/speech/text-to-speech.md b/ej2-javascript/ai-assistview/speech/text-to-speech.md new file mode 100644 index 000000000..4fc869d98 --- /dev/null +++ b/ej2-javascript/ai-assistview/speech/text-to-speech.md @@ -0,0 +1,43 @@ +--- +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-javascript +control: AI AssistView +publishingplatform: ##Platform_Name## +documentation: ug +domainurl: ##DomainURL## +--- + +# Text-to-Speech in TypeScript 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 TypeScript application. + - [TypeScript Getting Started Guide](../ts/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 TypeScript AI AssistView control](../ai-integrations/openai-integration) + +## Configure Text-to-Speech + +To enable Text-to-Speech functionality, modify the `index.ts` file to incorporate the Web Speech API. A custom `Read Aloud` button is added to the response toolbar using the [responseToolbarSettings](https://ej2.syncfusion.com/documentation/api/ai-assistview/#responsetoolbarsettings) property. When clicked, the [itemClicked](https://ej2.syncfusion.com/documentation/api/ai-assistview/responsetoolbarsettingsmodel/#itemclicked) event extracts plain text from the generated AI response and use the browser SpeechSynthesis API to read it aloud. + +{% tabs %} +{% highlight ts tabtitle="index.ts" %} +{% include code-snippet/ai-assistview/speech/tts/index.ts %} +{% endhighlight %} +{% highlight html tabtitle="index.html" %} +{% include code-snippet/ai-assistview/speech/tts/index.html %} +{% endhighlight %} +{% endtabs %} + +{% previewsample "page.domainurl/code-snippet/ai-assistview/speech/tts" %} + +## See Also + +* [Speech-to-Text](./speech-to-text.md) diff --git a/ej2-javascript/chat-ui/js/es5-getting-started.md b/ej2-javascript/chat-ui/js/es5-getting-started.md index 7457a3f4e..3f59130fc 100644 --- a/ej2-javascript/chat-ui/js/es5-getting-started.md +++ b/ej2-javascript/chat-ui/js/es5-getting-started.md @@ -23,6 +23,7 @@ The list of dependencies required to use the Chat UI control in your application |-- @syncfusion/ej2-navigations |-- @syncfusion/ej2-inputs |-- @syncfusion/ej2-buttons + |-- @syncfusion/ej2-dropdowns |-- @syncfusion/ej2-popups |-- @syncfusion/ej2-dropdowns ``` diff --git a/ej2-javascript/chat-ui/ts/getting-started.md b/ej2-javascript/chat-ui/ts/getting-started.md index cf506ee6e..a81558cdb 100644 --- a/ej2-javascript/chat-ui/ts/getting-started.md +++ b/ej2-javascript/chat-ui/ts/getting-started.md @@ -25,6 +25,7 @@ The list of dependencies required to use the Chat UI control in your application |-- @syncfusion/ej2-navigations |-- @syncfusion/ej2-inputs |-- @syncfusion/ej2-buttons + |-- @syncfusion/ej2-dropdowns |-- @syncfusion/ej2-popups |-- @syncfusion/ej2-dropdowns ``` diff --git a/ej2-javascript/code-snippet/ai-assistview/ai-integrations/gemini-ai/index.ts b/ej2-javascript/code-snippet/ai-assistview/ai-integrations/gemini-ai/index.ts index 3243af378..e4ca725e6 100644 --- a/ej2-javascript/code-snippet/ai-assistview/ai-integrations/gemini-ai/index.ts +++ b/ej2-javascript/code-snippet/ai-assistview/ai-integrations/gemini-ai/index.ts @@ -1,4 +1,5 @@ -import { AIAssistView, PromptRequestEventArgs } from '@syncfusion/ej2-interactive-chat'; + + import { AIAssistView, PromptRequestEventArgs } from '@syncfusion/ej2-interactive-chat'; import { GoogleGenerativeAI } from '@google/generative-ai'; import { marked } from 'marked'; diff --git a/ej2-javascript/code-snippet/ai-assistview/ai-integrations/llm-model/index.css b/ej2-javascript/code-snippet/ai-assistview/ai-integrations/llm-model/index.css new file mode 100644 index 000000000..8b6e75380 --- /dev/null +++ b/ej2-javascript/code-snippet/ai-assistview/ai-integrations/llm-model/index.css @@ -0,0 +1,22 @@ +#container { + visibility: hidden; + margin: 20px auto; + width: 350px; +} + +#loader { + color: #008cff; + height: 40px; + left: 45%; + position: absolute; + top: 45%; + width: 30%; +} + +.banner-content { + text-align: center; +} + +.banner-content .e-assistview-icon:before { + font-size: 25px; +} \ No newline at end of file diff --git a/ej2-javascript/code-snippet/ai-assistview/ai-integrations/llm-model/index.js b/ej2-javascript/code-snippet/ai-assistview/ai-integrations/llm-model/index.js new file mode 100644 index 000000000..6e7d918b0 --- /dev/null +++ b/ej2-javascript/code-snippet/ai-assistview/ai-integrations/llm-model/index.js @@ -0,0 +1,71 @@ +var suggestions = [ + 'What are the best tools for organizing my tasks?', + 'How can I maintain work-life balance effectively?', +]; +var stopStreaming = false; + +// Initialize AI AssistView +var aiAssist = new ej.interactivechat.AIAssistView({ + bannerTemplate: + '', + promptSuggestions: suggestions, + toolbarSettings: { + items: [{ iconCss: 'e-icons e-refresh', align: 'Right' }], + itemClicked: toolbarItemClicked, + }, + promptRequest:onPromptrequest, + stopRespondingClick: handleStopResponse +}); +async function onPromptrequest(args) { + var lastResponse = ""; + var defaultResponse = "⚠️ Something went wrong while connecting to the AI service. Please check your Ollama application running background."; + try { + // Send request to Ollama API + var response = await fetch('http://localhost:11434/api/generate', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + model: 'deepseek-r1', + prompt: `### Instruction:\nRespond in up to 5 lines.\n\n### Input:\n${args.prompt}`, + stream: false, + }), + }); + var reply = await response.json(); + var responseUpdateRate = 10; + async function streamResponse(response) { + var i = 0; + var responseLength = response.length; + while (i < responseLength && !stopStreaming) { + lastResponse += response[i]; + i++; + if (i % responseUpdateRate === 0 || i === responseLength) { + var htmlResponse =marked.parse(lastResponse); + aiAssist.addPromptResponse(htmlResponse, i === responseLength); + aiAssist.scrollToBottom(); + } + await new Promise(resolve => setTimeout(resolve, 15)); // Delay before the next chunk + } + aiAssist.promptSuggestions = suggestions; + } + if(response) { + stopStreaming = false; + streamResponse(reply.response); + } + + } catch (error) { + aiAssist.addPromptResponse(defaultResponse, true); + aiAssist.promptSuggestions = suggestions; + } +} + +aiAssist.appendTo('#llmAssist'); + +function handleStopResponse() { + stopStreaming = true; +} + +function toolbarItemClicked(args) { + if (args.item?.iconCss === 'e-icons e-refresh') { + aiAssist.prompts = []; + aiAssist.promptSuggestions = suggestions; + }} \ No newline at end of file diff --git a/ej2-javascript/code-snippet/ai-assistview/ai-integrations/llm-model/index.ts b/ej2-javascript/code-snippet/ai-assistview/ai-integrations/llm-model/index.ts new file mode 100644 index 000000000..dae3e8d06 --- /dev/null +++ b/ej2-javascript/code-snippet/ai-assistview/ai-integrations/llm-model/index.ts @@ -0,0 +1,74 @@ +import { AIAssistView, PromptRequestEventArgs, ToolbarItemClickedEventArgs } from "@syncfusion/ej2-interactive-chat"; +import marked from 'marked'; + +const suggestions = [ + 'What are the best tools for organizing my tasks?', + 'How can I maintain work-life balance effectively?', +]; +let stopStreaming: boolean = false; + +// Initialize AI AssistView +const aiAssist = new AIAssistView({ + bannerTemplate: + '', + promptSuggestions: suggestions, + toolbarSettings: { + items: [{ iconCss: 'e-icons e-refresh', align: 'Right' }], + itemClicked: toolbarItemClicked, + }, + promptRequest:onPromptrequest, + stopRespondingClick: handleStopResponse +}); +async function onPromptrequest(args: PromptRequestEventArgs) { + let lastResponse = ""; + const defaultResponse = "⚠️ Something went wrong while connecting to the AI service. Please check your Ollama application running background."; + try { + // Send request to Ollama API + const response = await fetch('http://localhost:11434/api/generate', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + model: 'deepseek-r1', + prompt: `### Instruction:\nRespond in up to 5 lines.\n\n### Input:\n${args.prompt}`, + stream: false, + }), + }); + const reply = await response.json(); + const responseUpdateRate = 10; + async function streamResponse(response:string) { + let i = 0; + const responseLength = response.length; + while (i < responseLength && !stopStreaming) { + lastResponse += response[i]; + i++; + if (i % responseUpdateRate === 0 || i === responseLength) { + const htmlResponse =marked.parse(lastResponse); + aiAssist.addPromptResponse(htmlResponse, i === responseLength); + aiAssist.scrollToBottom(); + } + await new Promise(resolve => setTimeout(resolve, 15)); // Delay before the next chunk + } + aiAssist.promptSuggestions = suggestions; + } + if(response) { + stopStreaming = false; + streamResponse(reply.response); + } + + } catch (error) { + aiAssist.addPromptResponse(defaultResponse, true); + aiAssist.promptSuggestions = suggestions; + } +} +// Append the AI AssistView to the container +aiAssist.appendTo('#llmAssist'); + +function handleStopResponse(): void { + stopStreaming = true; +} + +function toolbarItemClicked(args: ToolbarItemClickedEventArgs) { + if (args.item?.iconCss === 'e-icons e-refresh') { + aiAssist.prompts = []; + aiAssist.promptSuggestions = suggestions; + }} \ No newline at end of file diff --git a/ej2-javascript/code-snippet/ai-assistview/ai-integrations/llm-model/js/index.html b/ej2-javascript/code-snippet/ai-assistview/ai-integrations/llm-model/js/index.html new file mode 100644 index 000000000..a7c85d5a3 --- /dev/null +++ b/ej2-javascript/code-snippet/ai-assistview/ai-integrations/llm-model/js/index.html @@ -0,0 +1,28 @@ + + + + + EJ2 AI AssistView + + + + + + + + + + + + + + + + + +
    Loading....
    +
    +
    +
    + + \ No newline at end of file diff --git a/ej2-javascript/code-snippet/ai-assistview/ai-integrations/llm-model/systemjs.config.js b/ej2-javascript/code-snippet/ai-assistview/ai-integrations/llm-model/systemjs.config.js new file mode 100644 index 000000000..43ee5a2e9 --- /dev/null +++ b/ej2-javascript/code-snippet/ai-assistview/ai-integrations/llm-model/systemjs.config.js @@ -0,0 +1,37 @@ +System.config({ + transpiler: "typescript", + typescriptOptions: { + compilerOptions: { + target: "umd", + module: "commonjs", + moduleResolution: "node", + emitDecoratorMetadata: true, + experimentalDecorators: true + } + }, + paths: { + "syncfusion:": "https://cdn.syncfusion.com/ej2/20.3.56/" + }, + map: { + main: "index.ts", + typescript: "https://unpkg.com/typescript@2.2.2/lib/typescript.js", + "@syncfusion/ej2-base": "syncfusion:ej2-base/dist/ej2-base.umd.min.js", + "@syncfusion/ej2-interactive-chat": "syncfusion:ej2-interactive-chat/dist/ej2-interactive-chat.umd.min.js", + "@syncfusion/ej2-inputs": "syncfusion:ej2-inputs/dist/ej2-inputs.umd.min.js", + "@syncfusion/ej2-data": "syncfusion:ej2-data/dist/ej2-data.umd.min.js", + "@syncfusion/ej2-buttons": "syncfusion:ej2-buttons/dist/ej2-buttons.umd.min.js", + "@syncfusion/ej2-popups": "syncfusion:ej2-popups/dist/ej2-popups.umd.min.js", + "@syncfusion/ej2-splitbuttons": "syncfusion:ej2-splitbuttons/dist/ej2-splitbuttons.umd.min.js", + "@syncfusion/ej2-lists": "syncfusion:ej2-lists/dist/ej2-lists.umd.min.js", + "@syncfusion/ej2-dropdowns": "syncfusion:ej2-dropdowns/dist/ej2-dropdowns.umd.min.js", + "@syncfusion/ej2-navigations": "syncfusion:ej2-navigations/dist/ej2-navigations.umd.min.js", + "@syncfusion/ej2-notifications": "syncfusion:ej2-notifications/dist/ej2-notifications.umd.min.js", + "@google/generative-ai": "https://www.npmjs.com/package/@google/generative-ai/v/0.24.1", + "marked": "https://cdn.jsdelivr.net/npm/marked/marked.min.js" + } +}); + +System.import('index.ts').catch(console.error.bind(console)).then(function () { + document.getElementById('loader').style.display = "none"; + document.getElementById('container').style.visibility = "visible"; +}); \ No newline at end of file diff --git a/ej2-javascript/code-snippet/ai-assistview/ai-integrations/llm-model/ts/index.html b/ej2-javascript/code-snippet/ai-assistview/ai-integrations/llm-model/ts/index.html new file mode 100644 index 000000000..2a628f16a --- /dev/null +++ b/ej2-javascript/code-snippet/ai-assistview/ai-integrations/llm-model/ts/index.html @@ -0,0 +1,27 @@ + + + + + EJ2 AI AssistView + + + + + + + + + + + + + + + + +
    Loading....
    +
    +
    +
    + + \ No newline at end of file diff --git a/ej2-javascript/code-snippet/ai-assistview/ai-integrations/open-ai/index.ts b/ej2-javascript/code-snippet/ai-assistview/ai-integrations/open-ai/index.ts index dfba8f2f7..0aa372ccd 100644 --- a/ej2-javascript/code-snippet/ai-assistview/ai-integrations/open-ai/index.ts +++ b/ej2-javascript/code-snippet/ai-assistview/ai-integrations/open-ai/index.ts @@ -1,11 +1,11 @@ import { AIAssistView } from '@syncfusion/ej2-interactive-chat'; import marked from 'marked'; -// Initialize Open API (using OpenAI API in this case) -const azureOpenAIApiKey = 'YOUR_AZURE_OPENAI_API_KEY'; // replace your key -const azureOpenAIEndpoint = 'YOUR_AZURE_OPENAI_API_ENDPOINT'; // replace your endpoint -const azureOpenAIApiVersion = 'YOUR_AZURE_OPENAI_API_VERSION'; // replace to match your resource -const azureDeploymentName = 'YOUR_DEPLOYMENT_NAME'; // your Azure OpenAI deployment name +// Initialize Gemini API (using OpenAI API in this case) +const azureOpenAIApiKey = ''; // replace your key +const azureOpenAIEndpoint = ''; // replace your endpoint +const azureOpenAIApiVersion = ''; // replace to match your resource +const azureDeploymentName = ''; // your Azure OpenAI deployment name let stopStreaming = false; let suggestions = [ 'What are the best tools for organizing my tasks?', diff --git a/ej2-javascript/code-snippet/ai-assistview/speech/stt/index.css b/ej2-javascript/code-snippet/ai-assistview/speech/stt/index.css new file mode 100644 index 000000000..e6f375108 --- /dev/null +++ b/ej2-javascript/code-snippet/ai-assistview/speech/stt/index.css @@ -0,0 +1,89 @@ +#container { + visibility: hidden; + margin: 20px auto; + width: 350px; +} + +#loader { + color: #008cff; + height: 40px; + left: 45%; + position: absolute; + top: 45%; + width: 30%; +} + +.integration-speechtotext-section { + height: 350px; + width: 650px; + margin: 0 auto; +} + +.integration-speechtotext-section .e-view-container { + margin: auto; +} +.integration-speechtotext-section .e-banner-view { + margin-left: 0; +} +.integration-speechtotext-section .banner-content .e-listen-icon:before { + font-size: 25px; +} + +.integration-speechtotext-section .banner-content { + display: flex; + flex-direction: column; + gap: 10px; + text-align: center; +} + +.integration-speechtotext-section #assistview-sendButton { + width: 40px; + height: 40px; + font-size: 20px; + border: none; + background: none; + cursor: pointer; +} + +.integration-speechtotext-section #speechToText.visible, +.integration-speechtotext-section #assistview-sendButton.visible { + display: inline-block; +} + +.integration-speechtotext-section #speechToText, +.integration-speechtotext-section #assistview-sendButton { + display: none; +} + +@media only screen and (max-width: 750px) { + .integration-speechtotext-section { + width: 100%; + } +} + +.integration-speechtotext-section .e-footer-wrapper { + display: flex; + border: 1px solid #c1c1c1; + padding: 5px 5px 5px 10px; + margin: 5px 5px 0 5px; + border-radius: 30px; +} + +.integration-speechtotext-section .content-editor { + width: 100%; + overflow-y: auto; + font-size: 14px; + min-height: 25px; + max-height: 200px; + padding: 10px; +} + +.integration-speechtotext-section .content-editor[contentEditable='true']:empty:before { + content: attr(placeholder); + color: #6b7280; + font-style: italic; +} + +.integration-speechtotext-section .option-container { + align-self: flex-end; +} \ No newline at end of file diff --git a/ej2-javascript/code-snippet/ai-assistview/speech/stt/index.js b/ej2-javascript/code-snippet/ai-assistview/speech/stt/index.js new file mode 100644 index 000000000..fa5b6dc0f --- /dev/null +++ b/ej2-javascript/code-snippet/ai-assistview/speech/stt/index.js @@ -0,0 +1,154 @@ +const azureOpenAIApiKey = 'Your_AzureOpenAIApiKey'; // replace your key +const azureOpenAIEndpoint = 'Your_AzureOpenAIEndpoint'; // replace your endpoint +const azureOpenAIApiVersion = 'Your_AzureOpenAIApiVersion'; // replace to match your resource +const azureDeploymentName = 'Your_AzureDeploymentName'; // your Azure OpenAI deployment name +var stopStreaming = false; +loadExternalFile(); +var aiAssistView = new ej.interactivechat.AIAssistView({ + toolbarSettings: { + items: [{ iconCss: 'e-icons e-refresh', align: 'Right' }], + itemClicked: toolbarItemClicked, + }, + promptToolbarSettings: { + itemClicked: (args) => { + if (args.item.iconCss === "e-icons e-assist-edit") { + const assistviewFooter = document.querySelector('#assistview-footer'); + assistviewFooter.innerHTML = aiAssistView.prompts[args.dataIndex].prompt; + toggleButtons(); + } + } + }, + footerTemplate: "#footerContent", + bannerTemplate: "#bannerContent", + promptRequest: onPromptRequest, + stopRespondingClick: handleStopResponse +}); +aiAssistView.appendTo('#aiAssistView'); + +// Initialize Speech-to-Text component +var speechToTextObj = new ej.inputs.SpeechToText({ + transcriptChanged: onTranscriptChange, + onStop: onListeningStop, + created: onCreated, + cssClass: 'e-flat' +}); +speechToTextObj.appendTo('#speechToText'); + +function toolbarItemClicked(args) { + if (args.item.iconCss === 'e-icons e-refresh') { + aiAssistView.prompts = []; + stopStreaming = true; // Ensure streaming is stopped on refresh + } +} + +async function streamResponse(response) { + var lastResponse = ""; + var responseUpdateRate = 10; + var i = 0; + var responseLength = response.length; + while (i < responseLength && !stopStreaming) { + lastResponse += response[i]; + i++; + if (i % responseUpdateRate === 0 || i === responseLength) { + var htmlResponse = marked.parse(lastResponse); + aiAssistView.addPromptResponse(htmlResponse, i === responseLength); + aiAssistView.scrollToBottom(); + } + await new Promise(resolve => setTimeout(resolve, 15)); + } + toggleButtons(); +} + +function onPromptRequest(args) { + if (!args?.prompt?.trim() || !aiAssistView) return; + stopStreaming = false; + var url = + azureOpenAIEndpoint.replace(/\/$/, '') + + `/openai/deployments/${encodeURIComponent(azureDeploymentName)}/chat/completions` + + `?api-version=${encodeURIComponent(azureOpenAIApiVersion)}`; + fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: azureOpenAIApiKey, + }, + body: JSON.stringify({ + model: 'gpt-4o-mini', + messages: [{ role: 'user', content: args.prompt }], + max_tokens: 150, + stream: false + }), + }) + .then(response => response.json()) + .then(reply => { + var responseText = reply.choices[0].message.content.trim() || 'No response received.'; + stopStreaming = false; + streamResponse(responseText); + }) + .catch(error => { + aiAssistView.addPromptResponse('⚠️ Something went wrong while connecting to the AI service. Please check your API key, Deployment model, endpoint or try again later.', true); + stopStreaming = true; + toggleButtons(); + }); +} + +// Updates transcript in the input area when speech-to-text transcribes +function onTranscriptChange(args) { + document.querySelector('#assistview-footer').innerText = args.transcript; +} + +// Handles actions when speech listening stops +function onListeningStop() { + toggleButtons(); +} + +// Handles actions after component creation +function onCreated() { + var assistviewFooter = document.querySelector('#assistview-footer'); + var sendButton = document.querySelector('#assistview-sendButton'); + + sendButton.addEventListener('click', sendIconClicked); + assistviewFooter.addEventListener('input', toggleButtons); + + assistviewFooter.addEventListener('keydown', function (e) { + if (e.key === 'Enter' && !e.shiftKey) { + sendIconClicked(); + e.preventDefault(); // Prevent the default behavior of the Enter key + } + }); + + toggleButtons(); +} + +// Toggles the visibility of the send and speech-to-text buttons +function toggleButtons() { + var assistviewFooter = document.querySelector('#assistview-footer'); + var sendButton = document.querySelector('#assistview-sendButton'); + var speechButton = document.querySelector('#speechToText'); + + var hasText = assistviewFooter.innerText.trim() !== ''; + sendButton.classList.toggle('visible', hasText); + speechButton.classList.toggle('visible', !hasText); + + if (!hasText && (assistviewFooter.innerHTML === '
    ' || !assistviewFooter.innerHTML.trim())) { + assistviewFooter.innerHTML = ''; + } +} + +// Handles send button click event +function sendIconClicked() { + var assistviewFooter = document.querySelector('#assistview-footer'); + aiAssistView.executePrompt(assistviewFooter.innerText); + assistviewFooter.innerText = ""; +} + +function handleStopResponse() { + stopStreaming = true; + toggleButtons(); +} + +function loadExternalFile() { + var script = document.createElement('script'); + script.src = 'https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.19/marked.js'; + document.getElementsByTagName('head')[0].appendChild(script); +} diff --git a/ej2-javascript/code-snippet/ai-assistview/speech/stt/index.ts b/ej2-javascript/code-snippet/ai-assistview/speech/stt/index.ts new file mode 100644 index 000000000..d23ef7473 --- /dev/null +++ b/ej2-javascript/code-snippet/ai-assistview/speech/stt/index.ts @@ -0,0 +1,152 @@ +import { AIAssistView, ToolbarItemClickedEventArgs, PromptRequestEventArgs } from '@syncfusion/ej2-interactive-chat'; +import { SpeechToText, TranscriptChangedEventArgs } from '@syncfusion/ej2-inputs'; +import marked from 'marked'; + +// Initialize Gemini API (using OpenAI API in this case) +const azureOpenAIApiKey = 'Your_AzureOpenAIApiKey'; // replace your key +const azureOpenAIEndpoint = 'Your_AzureOpenAIEndpoint'; // replace your endpoint +const azureOpenAIApiVersion = 'Your_AzureOpenAIApiVersion'; // replace to match your resource +const azureDeploymentName = 'Your_AzureDeploymentName'; // your Azure OpenAI deployment name +let stopStreaming = false; + +// Initialize AI AssistView +let aiAssistView = new AIAssistView({ + toolbarSettings: { + items: [{ iconCss: 'e-icons e-refresh', align: 'Right' }], + itemClicked: toolbarItemClicked, + }, + promptToolbarSettings: { + itemClicked: (args: ToolbarItemClickedEventArgs) => { + if (args.item.iconCss === "e-icons e-assist-edit") { + const assistviewFooter: HTMLElement = document.querySelector('#assistview-footer'); + assistviewFooter.innerHTML = aiAssistView.prompts[args.dataIndex].prompt; + toggleButtons(); + } + } + }, + footerTemplate: "#footerContent", + bannerTemplate: "#bannerContent", + promptRequest: onPromptRequest, + stopRespondingClick: handleStopResponse +}); +aiAssistView.appendTo('#aiAssistView'); + +// Initialize Speech-to-Text component +let speechToTextObj: SpeechToText = new SpeechToText({ + transcriptChanged: onTranscriptChange, + onStop: onListeningStop, + created: onCreated, + cssClass: 'e-flat', +}); +speechToTextObj.appendTo('#speechToText'); + +function toolbarItemClicked(args: ToolbarItemClickedEventArgs) { + if (args.item.iconCss === 'e-icons e-refresh') { + aiAssistView.prompts = []; + stopStreaming = true; // Ensure streaming is stopped on refresh + } +} + +async function streamResponse(response: string) { + let lastResponse = ""; + const responseUpdateRate = 10; + let i = 0; + const responseLength = response.length; + while (i < responseLength && !stopStreaming) { + lastResponse += response[i]; + i++; + if (i % responseUpdateRate === 0 || i === responseLength) { + const htmlResponse = marked.parse(lastResponse); + aiAssistView.addPromptResponse(htmlResponse, i === responseLength); + aiAssistView.scrollToBottom(); + } + await new Promise(resolve => setTimeout(resolve, 15)); // Delay before the next chunk + } + toggleButtons(); +} + +function onPromptRequest(args: PromptRequestEventArgs) { + if (!args?.prompt?.trim() || !aiAssistView) return; + stopStreaming = false; + const url = + azureOpenAIEndpoint.replace(/\/$/, '') + + `/openai/deployments/${encodeURIComponent(azureDeploymentName)}/chat/completions` + + `?api-version=${encodeURIComponent(azureOpenAIApiVersion)}`; + + fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: azureOpenAIApiKey, + }, + body: JSON.stringify({ + model: 'gpt-4o-mini', + messages: [{ role: 'user', content: args.prompt }], + max_tokens: 150, + stream: false + }), + }) + .then(response => response.json()) + .then(reply => { + const responseText = reply.choices[0].message.content.trim() || 'No response received.'; + stopStreaming = false; + streamResponse(responseText); + }) + .catch((error: unknown) => { + aiAssistView.addPromptResponse('⚠️ Something went wrong while connecting to the AI service. Please check your API key, Deployment model, endpoint or try again later.', true); + stopStreaming = true; + toggleButtons(); + }); +} + +// Handles actions when speech listening stops +function onListeningStop() { + toggleButtons(); +} + +function onTranscriptChange(args: TranscriptChangedEventArgs): void { + (document.querySelector('#assistview-footer') as HTMLElement).innerText = args.transcript; +} + +// Handles actions after component creation +function onCreated(): void { + let assistviewFooter = document.querySelector('#assistview-footer') as HTMLElement; + let sendButton = document.querySelector('#assistview-sendButton') as HTMLElement; + + sendButton.addEventListener('click', sendIconClicked); + assistviewFooter.addEventListener('input', toggleButtons); + + assistviewFooter.addEventListener('keydown', function (e) { + if (e.key === 'Enter' && !e.shiftKey) { + sendIconClicked(); + e.preventDefault(); // Prevent the default behavior of the Enter key + } + }); + toggleButtons(); +} + +// Toggles the visibility of the send and speech-to-text buttons +function toggleButtons(): void { + let assistviewFooter = document.querySelector('#assistview-footer') as HTMLElement; + let sendButton = document.querySelector('#assistview-sendButton') as HTMLElement; + let speechButton = document.querySelector('#speechToText') as HTMLElement; + + let hasText = assistviewFooter.innerText.trim() !== ''; + sendButton.classList.toggle('visible', hasText); + speechButton.classList.toggle('visible', !hasText); + + if (!hasText && (assistviewFooter.innerHTML === '
    ' || !assistviewFooter.innerHTML.trim())) { + assistviewFooter.innerHTML = ''; + } +} + +// Handles send button click event +function sendIconClicked(): void { + var assistviewFooter = document.querySelector('#assistview-footer') as HTMLElement; + aiAssistView.executePrompt(assistviewFooter.innerText); + assistviewFooter.innerText = ''; +} + +function handleStopResponse() { + stopStreaming = true; +} diff --git a/ej2-javascript/code-snippet/ai-assistview/speech/stt/js/index.html b/ej2-javascript/code-snippet/ai-assistview/speech/stt/js/index.html new file mode 100644 index 000000000..63b2da000 --- /dev/null +++ b/ej2-javascript/code-snippet/ai-assistview/speech/stt/js/index.html @@ -0,0 +1,46 @@ + + + + + EJ2 AI AssistView + + + + + + + + + + + + + + + + + + +
    Loading....
    +
    +
    +
    + + + + + + \ No newline at end of file diff --git a/ej2-javascript/code-snippet/ai-assistview/speech/stt/systemjs.config.js b/ej2-javascript/code-snippet/ai-assistview/speech/stt/systemjs.config.js new file mode 100644 index 000000000..43ee5a2e9 --- /dev/null +++ b/ej2-javascript/code-snippet/ai-assistview/speech/stt/systemjs.config.js @@ -0,0 +1,37 @@ +System.config({ + transpiler: "typescript", + typescriptOptions: { + compilerOptions: { + target: "umd", + module: "commonjs", + moduleResolution: "node", + emitDecoratorMetadata: true, + experimentalDecorators: true + } + }, + paths: { + "syncfusion:": "https://cdn.syncfusion.com/ej2/20.3.56/" + }, + map: { + main: "index.ts", + typescript: "https://unpkg.com/typescript@2.2.2/lib/typescript.js", + "@syncfusion/ej2-base": "syncfusion:ej2-base/dist/ej2-base.umd.min.js", + "@syncfusion/ej2-interactive-chat": "syncfusion:ej2-interactive-chat/dist/ej2-interactive-chat.umd.min.js", + "@syncfusion/ej2-inputs": "syncfusion:ej2-inputs/dist/ej2-inputs.umd.min.js", + "@syncfusion/ej2-data": "syncfusion:ej2-data/dist/ej2-data.umd.min.js", + "@syncfusion/ej2-buttons": "syncfusion:ej2-buttons/dist/ej2-buttons.umd.min.js", + "@syncfusion/ej2-popups": "syncfusion:ej2-popups/dist/ej2-popups.umd.min.js", + "@syncfusion/ej2-splitbuttons": "syncfusion:ej2-splitbuttons/dist/ej2-splitbuttons.umd.min.js", + "@syncfusion/ej2-lists": "syncfusion:ej2-lists/dist/ej2-lists.umd.min.js", + "@syncfusion/ej2-dropdowns": "syncfusion:ej2-dropdowns/dist/ej2-dropdowns.umd.min.js", + "@syncfusion/ej2-navigations": "syncfusion:ej2-navigations/dist/ej2-navigations.umd.min.js", + "@syncfusion/ej2-notifications": "syncfusion:ej2-notifications/dist/ej2-notifications.umd.min.js", + "@google/generative-ai": "https://www.npmjs.com/package/@google/generative-ai/v/0.24.1", + "marked": "https://cdn.jsdelivr.net/npm/marked/marked.min.js" + } +}); + +System.import('index.ts').catch(console.error.bind(console)).then(function () { + document.getElementById('loader').style.display = "none"; + document.getElementById('container').style.visibility = "visible"; +}); \ No newline at end of file diff --git a/ej2-javascript/code-snippet/ai-assistview/speech/stt/ts/index.html b/ej2-javascript/code-snippet/ai-assistview/speech/stt/ts/index.html new file mode 100644 index 000000000..56709ead1 --- /dev/null +++ b/ej2-javascript/code-snippet/ai-assistview/speech/stt/ts/index.html @@ -0,0 +1,43 @@ + + + + + EJ2 AI AssistView + + + + + + + + + + + + + + + + +
    Loading....
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/ej2-javascript/code-snippet/ai-assistview/speech/tts/index.css b/ej2-javascript/code-snippet/ai-assistview/speech/tts/index.css new file mode 100644 index 000000000..367ade8f6 --- /dev/null +++ b/ej2-javascript/code-snippet/ai-assistview/speech/tts/index.css @@ -0,0 +1,37 @@ +#container { + visibility: hidden; + margin: 20px auto; + width: 350px; +} + +#loader { + color: #008cff; + height: 40px; + left: 45%; + position: absolute; + top: 45%; + width: 30%; +} + +.integration-texttospeech-section { + height: 350px; + width: 650px; + margin: 0 auto; +} + +.integration-texttospeech-section .e-view-container { + margin: auto; +} +.integration-texttospeech-section .e-banner-view { + margin-left: 0; +} +.integration-texttospeech-section .banner-content .e-audio:before { + font-size: 25px; +} + +.integration-texttospeech-section .banner-content { + display: flex; + flex-direction: column; + gap: 10px; + text-align: center; +} \ No newline at end of file diff --git a/ej2-javascript/code-snippet/ai-assistview/speech/tts/index.js b/ej2-javascript/code-snippet/ai-assistview/speech/tts/index.js new file mode 100644 index 000000000..d5496fae0 --- /dev/null +++ b/ej2-javascript/code-snippet/ai-assistview/speech/tts/index.js @@ -0,0 +1,117 @@ +const azureOpenAIApiKey = 'Your_AzureOpenAIApiKey'; // replace your key +const azureOpenAIEndpoint = 'Your_AzureOpenAIEndpoint'; // replace your endpoint +const azureOpenAIApiVersion = 'Your_AzureOpenAIApiVersion'; // replace to match your resource +const azureDeploymentName = 'Your_AzureDeploymentName'; // your Azure OpenAI deployment name +var stopStreaming = false; +var currentUtterance; +loadExternalFile(); +var aiAssistView = new ej.interactivechat.AIAssistView({ + toolbarSettings: { + items: [{ iconCss: 'e-icons e-refresh', align: 'Right' }], + itemClicked: toolbarItemClicked, + }, + responseToolbarSettings: { + items: [ + { type: 'Button', iconCss: 'e-icons e-assist-copy', tooltip: 'Copy' }, + { type: 'Button', iconCss: 'e-icons e-audio', tooltip: 'Read Aloud' }, + { type: 'Button', iconCss: 'e-icons e-assist-like', tooltip: 'Like' }, + { type: 'Button', iconCss: 'e-icons e-assist-dislike', tooltip: 'Need Improvement' }, + ], + itemClicked: onResponseToolbarItemClicked + }, + bannerTemplate: "#bannerContent", + promptRequest: onPromptRequest, + stopRespondingClick: handleStopResponse +}); + +function toolbarItemClicked(args) { + if (args.item.iconCss === 'e-icons e-refresh') { + aiAssistView.prompts = []; + stopStreaming = true; // Ensure streaming is stopped on refresh + } +} + +function onResponseToolbarItemClicked(args) { + const responseHtml = aiAssistView.prompts[args.dataIndex].response; + if (responseHtml) { + const tempDiv = document.createElement('div'); + tempDiv.innerHTML = responseHtml; + const text = (tempDiv.textContent || tempDiv.innerText || '').trim(); + if (args.item.iconCss === 'e-icons e-audio' || args.item.iconCss === 'e-icons e-assist-stop') { + if (currentUtterance) { + speechSynthesis.cancel(); + currentUtterance = null; + aiAssistView.responseToolbarSettings.items[1].iconCss = 'e-icons e-audio'; + aiAssistView.responseToolbarSettings.items[1].tooltip = 'Read Aloud'; + } else { + const utterance = new SpeechSynthesisUtterance(text); + utterance.onend = () => { + currentUtterance = null; + aiAssistView.responseToolbarSettings.items[1].iconCss = 'e-icons e-audio'; + aiAssistView.responseToolbarSettings.items[1].tooltip = 'Read Aloud'; + }; + speechSynthesis.speak(utterance); + currentUtterance = utterance; + aiAssistView.responseToolbarSettings.items[1].iconCss = 'e-icons e-assist-stop'; + aiAssistView.responseToolbarSettings.items[1].tooltip = 'Stop'; + } + } + } +} + +async function streamResponse(response) { + var lastResponse = ""; + var responseUpdateRate = 10; + var i = 0; + var responseLength = response.length; + while (i < responseLength && !stopStreaming) { + lastResponse += response[i]; + i++; + if (i % responseUpdateRate === 0 || i === responseLength) { + var htmlResponse = marked.parse(lastResponse); + aiAssistView.addPromptResponse(htmlResponse, i === responseLength); + aiAssistView.scrollToBottom(); + } + await new Promise(resolve => setTimeout(resolve, 15)); + } +} + +function onPromptRequest(args) { + var url = + azureOpenAIEndpoint.replace(/\/$/, '') + + `/openai/deployments/${encodeURIComponent(azureDeploymentName)}/chat/completions` + + `?api-version=${encodeURIComponent(azureOpenAIApiVersion)}`; + fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: azureOpenAIApiKey, + }, + body: JSON.stringify({ + model: 'gpt-4o-mini', + messages: [{ role: 'user', content: args.prompt }], + max_tokens: 150, + stream: false + }), + }) + .then(response => response.json()) + .then(reply => { + var responseText = reply.choices[0].message.content.trim() || 'No response received.'; + stopStreaming = false; + streamResponse(responseText); + }) + .catch(error => { + aiAssistView.addPromptResponse('⚠️ Something went wrong while connecting to the AI service. Please check your API key, Deployment model, endpoint or try again later.', true); + stopStreaming = true; + }); +} + +function handleStopResponse() { + stopStreaming = true; +} +function loadExternalFile() { + var script = document.createElement('script'); + script.src = 'https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.19/marked.js'; + document.getElementsByTagName('head')[0].appendChild(script); +} +aiAssistView.appendTo('#aiAssistView'); \ No newline at end of file diff --git a/ej2-javascript/code-snippet/ai-assistview/speech/tts/index.ts b/ej2-javascript/code-snippet/ai-assistview/speech/tts/index.ts new file mode 100644 index 000000000..5fdb569d4 --- /dev/null +++ b/ej2-javascript/code-snippet/ai-assistview/speech/tts/index.ts @@ -0,0 +1,117 @@ +import { AIAssistView, ToolbarItemClickedEventArgs, PromptRequestEventArgs } from '@syncfusion/ej2-interactive-chat'; +import marked from 'marked'; + +const azureOpenAIApiKey = 'Your_AzureOpenAIApiKey'; // replace your key +const azureOpenAIEndpoint = 'Your_AzureOpenAIEndpoint'; // replace your endpoint +const azureOpenAIApiVersion = 'Your_AzureOpenAIApiVersion'; // replace to match your resource +const azureDeploymentName = 'Your_AzureDeploymentName'; // your Azure OpenAI deployment name +let stopStreaming = false; +let currentUtterance; +// Initialize AI AssistView +let aiAssistView = new AIAssistView({ + toolbarSettings: { + items: [{ iconCss: 'e-icons e-refresh', align: 'Right' }], + itemClicked: toolbarItemClicked, + }, + responseToolbarSettings: { + items: [ + { type: 'Button', iconCss: 'e-icons e-assist-copy', tooltip: 'Copy' }, + { type: 'Button', iconCss: 'e-icons e-audio', tooltip: 'Read Aloud' }, + { type: 'Button', iconCss: 'e-icons e-assist-like', tooltip: 'Like' }, + { type: 'Button', iconCss: 'e-icons e-assist-dislike', tooltip: 'Need Improvement' }, + ], + itemClicked: onResponseToolbarItemClicked + }, + bannerTemplate: "#bannerContent", + promptRequest: onPromptRequest, + stopRespondingClick: handleStopResponse +}); + +function toolbarItemClicked(args: ToolbarItemClickedEventArgs) { + if (args.item.iconCss === 'e-icons e-refresh') { + aiAssistView.prompts = []; + stopStreaming = true; // Ensure streaming is stopped on refresh + } +} + +function onResponseToolbarItemClicked(args: ToolbarItemClickedEventArgs) { + const responseHtml = aiAssistView.prompts[args.dataIndex].response; + if (responseHtml) { + const tempDiv = document.createElement('div'); + tempDiv.innerHTML = responseHtml; + const text = (tempDiv.textContent || tempDiv.innerText || '').trim(); + if (args.item.iconCss === 'e-icons e-audio' || args.item.iconCss === 'e-icons e-assist-stop') { + if (currentUtterance) { + speechSynthesis.cancel(); + currentUtterance = null; + aiAssistView.responseToolbarSettings.items[1].iconCss = 'e-icons e-audio'; + aiAssistView.responseToolbarSettings.items[1].tooltip = 'Read Aloud'; + } else { + const utterance = new SpeechSynthesisUtterance(text); + utterance.onend = () => { + currentUtterance = null; + aiAssistView.responseToolbarSettings.items[1].iconCss = 'e-icons e-audio'; + aiAssistView.responseToolbarSettings.items[1].tooltip = 'Read Aloud'; + }; + speechSynthesis.speak(utterance); + currentUtterance = utterance; + aiAssistView.responseToolbarSettings.items[1].iconCss = 'e-icons e-assist-stop'; + aiAssistView.responseToolbarSettings.items[1].tooltip = 'Stop'; + } + } + } +} + +async function streamResponse(response: string) { + let lastResponse = ""; + const responseUpdateRate = 10; + let i = 0; + const responseLength = response.length; + while (i < responseLength && !stopStreaming) { + lastResponse += response[i]; + i++; + if (i % responseUpdateRate === 0 || i === responseLength) { + const htmlResponse = marked.parse(lastResponse); + aiAssistView.addPromptResponse(htmlResponse, i === responseLength); + aiAssistView.scrollToBottom(); + } + await new Promise(resolve => setTimeout(resolve, 15)); // Delay before the next chunk + } +} + +function onPromptRequest(args: PromptRequestEventArgs) { + const url = + azureOpenAIEndpoint.replace(/\/$/, '') + + `/openai/deployments/${encodeURIComponent(azureDeploymentName)}/chat/completions` + + `?api-version=${encodeURIComponent(azureOpenAIApiVersion)}`; + + fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: azureOpenAIApiKey, + }, + body: JSON.stringify({ + model: 'gpt-4o-mini', + messages: [{ role: 'user', content: args.prompt }], + max_tokens: 150, + stream: false + }), + }) + .then(response => response.json()) + .then(reply => { + const responseText = reply.choices[0].message.content.trim() || 'No response received.'; + stopStreaming = false; + streamResponse(responseText); + }) + .catch((error: unknown) => { + aiAssistView.addPromptResponse('⚠️ Something went wrong while connecting to the AI service. Please check your API key, Deployment model, endpoint or try again later.', true); + stopStreaming = true; + }); +} + +function handleStopResponse() { + stopStreaming = true; +} + // Render AI AssistView + aiAssistView.appendTo('#aiAssistView'); \ No newline at end of file diff --git a/ej2-javascript/code-snippet/ai-assistview/speech/tts/js/index.html b/ej2-javascript/code-snippet/ai-assistview/speech/tts/js/index.html new file mode 100644 index 000000000..591b6cd83 --- /dev/null +++ b/ej2-javascript/code-snippet/ai-assistview/speech/tts/js/index.html @@ -0,0 +1,34 @@ + + + + + EJ2 AI AssistView + + + + + + + + + + + + + + + + + +
    Loading....
    +
    +
    +
    + + + \ No newline at end of file diff --git a/ej2-javascript/code-snippet/ai-assistview/speech/tts/systemjs.config.js b/ej2-javascript/code-snippet/ai-assistview/speech/tts/systemjs.config.js new file mode 100644 index 000000000..43ee5a2e9 --- /dev/null +++ b/ej2-javascript/code-snippet/ai-assistview/speech/tts/systemjs.config.js @@ -0,0 +1,37 @@ +System.config({ + transpiler: "typescript", + typescriptOptions: { + compilerOptions: { + target: "umd", + module: "commonjs", + moduleResolution: "node", + emitDecoratorMetadata: true, + experimentalDecorators: true + } + }, + paths: { + "syncfusion:": "https://cdn.syncfusion.com/ej2/20.3.56/" + }, + map: { + main: "index.ts", + typescript: "https://unpkg.com/typescript@2.2.2/lib/typescript.js", + "@syncfusion/ej2-base": "syncfusion:ej2-base/dist/ej2-base.umd.min.js", + "@syncfusion/ej2-interactive-chat": "syncfusion:ej2-interactive-chat/dist/ej2-interactive-chat.umd.min.js", + "@syncfusion/ej2-inputs": "syncfusion:ej2-inputs/dist/ej2-inputs.umd.min.js", + "@syncfusion/ej2-data": "syncfusion:ej2-data/dist/ej2-data.umd.min.js", + "@syncfusion/ej2-buttons": "syncfusion:ej2-buttons/dist/ej2-buttons.umd.min.js", + "@syncfusion/ej2-popups": "syncfusion:ej2-popups/dist/ej2-popups.umd.min.js", + "@syncfusion/ej2-splitbuttons": "syncfusion:ej2-splitbuttons/dist/ej2-splitbuttons.umd.min.js", + "@syncfusion/ej2-lists": "syncfusion:ej2-lists/dist/ej2-lists.umd.min.js", + "@syncfusion/ej2-dropdowns": "syncfusion:ej2-dropdowns/dist/ej2-dropdowns.umd.min.js", + "@syncfusion/ej2-navigations": "syncfusion:ej2-navigations/dist/ej2-navigations.umd.min.js", + "@syncfusion/ej2-notifications": "syncfusion:ej2-notifications/dist/ej2-notifications.umd.min.js", + "@google/generative-ai": "https://www.npmjs.com/package/@google/generative-ai/v/0.24.1", + "marked": "https://cdn.jsdelivr.net/npm/marked/marked.min.js" + } +}); + +System.import('index.ts').catch(console.error.bind(console)).then(function () { + document.getElementById('loader').style.display = "none"; + document.getElementById('container').style.visibility = "visible"; +}); \ No newline at end of file diff --git a/ej2-javascript/code-snippet/ai-assistview/speech/tts/ts/index.html b/ej2-javascript/code-snippet/ai-assistview/speech/tts/ts/index.html new file mode 100644 index 000000000..9fd245f26 --- /dev/null +++ b/ej2-javascript/code-snippet/ai-assistview/speech/tts/ts/index.html @@ -0,0 +1,33 @@ + + + + + EJ2 AI AssistView + + + + + + + + + + + + + + + + +
    Loading....
    +
    +
    +
    + + + \ No newline at end of file diff --git a/ej2-typescript-toc.html b/ej2-typescript-toc.html index 0c26f71a0..4d8a3fa95 100644 --- a/ej2-typescript-toc.html +++ b/ej2-typescript-toc.html @@ -179,12 +179,25 @@
  • Azure Open AI
  • +
  • + Ollama LLM +
  • Toolbar items
  • Custom views
  • File attachments
  • Templates
  • +
  • Speech + +
  • Appearance
  • Accessibility
  • Methods