diff --git a/AiAssistview/AiAssistview.csproj b/AiAssistview/AiAssistview.csproj index 9f7c8eda..0bdc3012 100644 --- a/AiAssistview/AiAssistview.csproj +++ b/AiAssistview/AiAssistview.csproj @@ -7,8 +7,13 @@ - - + + + + + + + diff --git a/AiAssistview/Components/App.razor b/AiAssistview/Components/App.razor index 464bbe8c..58cc9291 100644 --- a/AiAssistview/Components/App.razor +++ b/AiAssistview/Components/App.razor @@ -17,14 +17,14 @@ display: flex; } - .content table { - display: block; - margin: 50px 10px; - } + .content table { + display: block; + margin: 50px 10px; + } .aiassist-container { - margin: 10% auto; - } + margin: 10% auto; + } diff --git a/AiAssistview/Components/Pages/AiIntegration/AiIntegrationNav.razor b/AiAssistview/Components/Pages/AiIntegration/AiIntegrationNav.razor index 8fae75f2..abee4eff 100644 --- a/AiAssistview/Components/Pages/AiIntegration/AiIntegrationNav.razor +++ b/AiAssistview/Components/Pages/AiIntegration/AiIntegrationNav.razor @@ -1,8 +1,8 @@ diff --git a/AiAssistview/Components/Pages/AiIntegration/OpenAiIntegration.razor b/AiAssistview/Components/Pages/AiIntegration/OpenAiIntegration.razor index ae8d7a69..e1a61ce8 100644 --- a/AiAssistview/Components/Pages/AiIntegration/OpenAiIntegration.razor +++ b/AiAssistview/Components/Pages/AiIntegration/OpenAiIntegration.razor @@ -1,7 +1,7 @@ @page "/openaiintegration" @rendermode InteractiveServer -@using AIAssistView_AzureAI.Components.Services +@using AIAssistview.Components.Services @using Syncfusion.Blazor.InteractiveChat @using Syncfusion.Blazor.Navigations @inject AzureOpenAIService OpenAIService diff --git a/AiAssistview/Components/Pages/Speech/SpeechNav.razor b/AiAssistview/Components/Pages/Speech/SpeechNav.razor index c66904f5..e884faf0 100644 --- a/AiAssistview/Components/Pages/Speech/SpeechNav.razor +++ b/AiAssistview/Components/Pages/Speech/SpeechNav.razor @@ -1,7 +1,7 @@
- 1.Gemini Integration - 2.open AI Integration + 1.Gemini Integration

+ 2.open AI Integration

3.Ollama LLM Integration
diff --git a/AiAssistview/Components/Pages/Speech/SpeechToText.razor b/AiAssistview/Components/Pages/Speech/SpeechToText.razor index 899305d3..0bbbce8a 100644 --- a/AiAssistview/Components/Pages/Speech/SpeechToText.razor +++ b/AiAssistview/Components/Pages/Speech/SpeechToText.razor @@ -2,7 +2,7 @@ @rendermode InteractiveServer @using Syncfusion.Blazor.InteractiveChat -@using AssistView_OpenAI.Components.Services +@using AIAssistview.Components.Services @using Syncfusion.Blazor.Navigations @using Syncfusion.Blazor.Inputs @using Syncfusion.Blazor.Buttons @@ -174,7 +174,7 @@ display: none; } -@media only screen and (max-width: 750px) { +@@media only screen and (max-width: 750px) { .integration-speechtotext-section { width: 100%; } diff --git a/AiAssistview/Components/Pages/Speech/TextToSpeech.razor b/AiAssistview/Components/Pages/Speech/TextToSpeech.razor index 16f8c2f5..6262971c 100644 --- a/AiAssistview/Components/Pages/Speech/TextToSpeech.razor +++ b/AiAssistview/Components/Pages/Speech/TextToSpeech.razor @@ -2,7 +2,7 @@ @rendermode InteractiveServer @using Syncfusion.Blazor.InteractiveChat -@using AssistView_OpenAI.Components.Services +@using AIAssistview.Components.Services @using Syncfusion.Blazor.Navigations @inject AzureOpenAIService OpenAIService @inject IJSRuntime JSRuntime @@ -42,7 +42,7 @@ private string audioTooltip = "Read Aloud"; private bool IsSpeaking = false; // If component class name isn’t Home (file is not Home.razor), update DotNetObjectReference to match the actual component type. - private DotNetObjectReference? dotNetRef; + private DotNetObjectReference? dotNetRef; protected override void OnInitialized() { @@ -159,7 +159,7 @@ gap: 10px; text-align: center; } -@media only screen and (max-width: 750px) { +@@media only screen and (max-width: 750px) { .integration-texttospeech-section { width: 100%; } diff --git a/AiAssistview/Components/Service/AzureOpenaiService.cs b/AiAssistview/Components/Service/AzureOpenaiService.cs new file mode 100644 index 00000000..bbe7e290 --- /dev/null +++ b/AiAssistview/Components/Service/AzureOpenaiService.cs @@ -0,0 +1,87 @@ +using System.Text.Json; +using Markdig; +using System.Text.RegularExpressions; + +namespace AIAssistview.Components.Services +{ + public class AzureOpenAIService + { + private readonly HttpClient _httpClient; + private readonly string _endpoint; + private readonly string _apiKey; + private readonly string _deploymentName; + + public AzureOpenAIService(HttpClient httpClient, string endpoint, string apiKey, string deploymentName) + { + _httpClient = httpClient; + _endpoint = endpoint; + _apiKey = apiKey; + _deploymentName = deploymentName; + } + + public async IAsyncEnumerable GetChatResponseStreamAsync(string prompt) + { + var request = new + { + messages = new[] { new { role = "user", content = prompt } }, + max_tokens = 500, + }; + + var url = $"{_endpoint}/openai/deployments/{_deploymentName}/chat/completions?api-version=2024-02-15-preview"; + _httpClient.DefaultRequestHeaders.Add("api-key", _apiKey); + + Stream responseStream = null; + List results = new List(); + + try + { + var response = await _httpClient.PostAsJsonAsync(url, request); + + if (response.IsSuccessStatusCode) + { + responseStream = await response.Content.ReadAsStreamAsync(); + using var jsonDocument = JsonDocument.Parse(responseStream); + var choices = jsonDocument.RootElement.GetProperty("choices"); + if (choices.GetArrayLength() > 0) + { + var content = choices[0].GetProperty("message").GetProperty("content").GetString(); + var htmlContent = Markdown.ToHtml(content); + htmlContent = Regex.Replace(htmlContent, @"\s+", " ").Trim(); + // Collect each character to the results list before yielding + foreach (var chunk in htmlContent) + { + results.Add(chunk.ToString()); + } + } + else + { + results.Add("Error: No choices returned in the response."); + } + } + else + { + var error = await response.Content.ReadAsStringAsync(); + results.Add($"Error: {error}"); + } + } + catch (Exception ex) + { + // Collect the error message to be yielded later + results.Add($"Error: {ex.Message}"); + } + finally + { + if (responseStream != null) + { + responseStream.Dispose(); + } + } + + // Now yield each collected result + foreach (var result in results) + { + yield return result; + } + } + } +} \ No newline at end of file diff --git a/AiAssistview/Program.cs b/AiAssistview/Program.cs index 65d3c904..ae40bd41 100644 --- a/AiAssistview/Program.cs +++ b/AiAssistview/Program.cs @@ -1,6 +1,10 @@ using AiAssistview.Components; -using AIAssistView_AzureAI.Components.Services; using Syncfusion.Blazor; +using AIAssistview.Components.Services; +using Microsoft.Extensions.AI; +using OllamaSharp; +using Azure.AI.OpenAI; +using Azure; var builder = WebApplication.CreateBuilder(args); @@ -8,7 +12,7 @@ builder.Services.AddRazorComponents() .AddInteractiveServerComponents(); builder.Services.AddSyncfusionBlazor(); - +builder.Services.AddHttpClient(); builder.Services.AddScoped(sp => { var httpClientFactory = sp.GetRequiredService(); @@ -21,6 +25,13 @@ return new AzureOpenAIService(httpClient, endpoint, apiKey, deploymentName); }); +builder.Services.AddDistributedMemoryCache(); + +// Ollama configuration +builder.Services.AddChatClient(new OllamaApiClient(new Uri("http://localhost:11434/"), "llama3.2")) + .UseDistributedCache() + .UseLogging(); + var app = builder.Build(); // Configure the HTTP request pipeline. diff --git a/AiAssistview/wwwroot/Script/speechtotext.js b/AiAssistview/wwwroot/Script/speechtotext.js new file mode 100644 index 00000000..1b83ba61 --- /dev/null +++ b/AiAssistview/wwwroot/Script/speechtotext.js @@ -0,0 +1,32 @@ +// Checks if the contenteditable element contains meaningful text and cleans up. +window.isFooterContainsValue = function (elementref) { + if (!elementref) return ""; + + const text = (elementref.innerText || "").trim(); + + // If empty, normalize stray
or empty HTML to empty string + if (text === "") { + const html = (elementref.innerHTML || "").trim(); + if (html === "
" || html === "") { + elementref.innerHTML = ""; + } + return ""; + } + + return elementref.innerText || ""; +}; + +// Clears the text content of a contenteditable element. +window.emptyFooterValue = function (elementref) { + if (elementref) { + elementref.innerText = ""; + } +}; + +// Updates the text content of a contenteditable element with a specified value. +window.updateContentEditableDiv = function (element, value) { + if (element) { + // Using innerText preserves plain text; switch to innerHTML if you need HTML. + element.innerText = value || ""; + } +}; \ No newline at end of file
- 1.SpeechToText + 1.SpeechToText

2.TextToSpeech