diff --git a/Legba.Engine/Legba.Engine.csproj b/Legba.Engine/Legba.Engine.csproj index ff15f3c..cf38ffc 100644 --- a/Legba.Engine/Legba.Engine.csproj +++ b/Legba.Engine/Legba.Engine.csproj @@ -5,7 +5,7 @@ true enable enable - 2.0.0.0 + 2.1.0.0 @@ -14,12 +14,13 @@ - - - - + + + + - + + diff --git a/Legba.Engine/Models/OpenAi/Message.cs b/Legba.Engine/Models/OpenAi/Message.cs index 04a008a..4d64281 100644 --- a/Legba.Engine/Models/OpenAi/Message.cs +++ b/Legba.Engine/Models/OpenAi/Message.cs @@ -37,34 +37,34 @@ public string DisplayText } [JsonIgnore] - public System.Windows.HorizontalAlignment MessageAlignment + public System.Windows.Media.Brush BackgroundColor { get { if (Role == Enums.Role.System || IsInitialSourceCode) { - return System.Windows.HorizontalAlignment.Center; + return System.Windows.Media.Brushes.Gold; } return IsSentByUser - ? System.Windows.HorizontalAlignment.Right - : System.Windows.HorizontalAlignment.Left; + ? System.Windows.Media.Brushes.LightBlue + : System.Windows.Media.Brushes.LightGray; } } [JsonIgnore] - public System.Windows.Media.Brush MessageBackground + public System.Windows.TextAlignment Alignment { get { if (Role == Enums.Role.System || IsInitialSourceCode) { - return System.Windows.Media.Brushes.Gold; + return System.Windows.TextAlignment.Center; } return IsSentByUser - ? System.Windows.Media.Brushes.LightBlue - : System.Windows.Media.Brushes.LightGray; + ? System.Windows.TextAlignment.Right + : System.Windows.TextAlignment.Left; } } } \ No newline at end of file diff --git a/Legba.Engine/Models/OpenAi/OpenAiResponse.cs b/Legba.Engine/Models/OpenAi/OpenAiResponse.cs index 7e08d2a..809b7e2 100644 --- a/Legba.Engine/Models/OpenAi/OpenAiResponse.cs +++ b/Legba.Engine/Models/OpenAi/OpenAiResponse.cs @@ -5,15 +5,15 @@ namespace Legba.Engine.Models.OpenAi; public class OpenAiResponse { [JsonPropertyName("id")] - public string Id { get; set; } + public string Id { get; set; } = string.Empty; [JsonPropertyName("object")] - public string _object { get; set; } + public string _object { get; set; } = string.Empty; [JsonPropertyName("created")] public int Created { get; set; } [JsonPropertyName("model")] - public string Model { get; set; } + public string Model { get; set; } = string.Empty; [JsonPropertyName("usage")] - public Usage Usage { get; set; } + public Usage Usage { get; set; } = new Usage(); [JsonPropertyName("choices")] public List Choices { get; set; } = new List(); } \ No newline at end of file diff --git a/Legba.Engine/Services/FileCollector.cs b/Legba.Engine/Services/FileCollector.cs index 85feab6..75349a5 100644 --- a/Legba.Engine/Services/FileCollector.cs +++ b/Legba.Engine/Services/FileCollector.cs @@ -9,12 +9,20 @@ public class FileCollector { #region Constants and Fields - private static readonly IReadOnlyList s_fileExtensionsToInclude = [".cs", ".vb", ".xaml"]; + private static readonly IReadOnlyList s_fileExtensionsToInclude = + [ + ".cs", ".vb", ".xaml", ".xaml.cs", ".xaml.vb", ".vsixmanifest", ".vsct", ".resx", + ".targets", ".props", ".ruleset", ".settings", ".cshtml", ".vbhtml", ".aspx", ".ascx" + ]; private static readonly IReadOnlyList s_excludedFilePatterns = - [ - new Regex(@"(AssemblyAttributes|AssemblyInfo|\.g|\.g\.i|\.Designer|\.generated)\.(cs|vb)$", - RegexOptions.IgnoreCase | RegexOptions.Compiled) - ]; + [ + new Regex( + @"(AssemblyInfo|AssemblyAttributes|\.g|\.g\.i|\.Designer|\.generated|\.razor\.cs|\.g\.cshtml|\.tt|\.t4|\.Reference)\.(cs|vb|xaml|cshtml)$", + RegexOptions.IgnoreCase | RegexOptions.Compiled) + ]; + + private static readonly IReadOnlyList s_excludedDirectories = + [ "bin", "obj", "node_modules", ".vs", "packages" ]; #endregion @@ -91,20 +99,22 @@ public static async Task> GetFilesFromFoldersAsync(string[ { ValidateFolderPaths(folderPaths); - var filePaths = new List(); + var filePaths = new ConcurrentBag(); - foreach (var folderPath in folderPaths) + await Parallel.ForEachAsync(folderPaths, async (folderPath, ct) => { - foreach (var extension in s_fileExtensionsToInclude) + await foreach (var file in Directory.EnumerateFiles(folderPath, "*.*", SearchOption.AllDirectories) + .ToAsyncEnumerable() + .Where(file => + s_fileExtensionsToInclude.Any(ext => file.EndsWith(ext, StringComparison.OrdinalIgnoreCase)) && + !s_excludedDirectories.Any(dir => file.Contains(Path.DirectorySeparatorChar + dir + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase)) && + !IsExcludedFile(file))) { - filePaths.AddRange( - Directory.GetFiles(folderPath, $"*{extension}", - SearchOption.AllDirectories)); + filePaths.Add(file); } - } + }); - return await Task.FromResult>( - filePaths.Where(f => !IsExcludedFile(f)).ToList().AsReadOnly()); + return filePaths.ToList().AsReadOnly(); } public static async Task> GetFilesFromFilesAsync(string[] filePaths) @@ -140,7 +150,7 @@ private static void ValidateFolderPaths(string[] folderPaths) var invalidPaths = folderPaths.Where(fp => !Directory.Exists(fp)).ToArray(); - if (invalidPaths.Any()) + if (invalidPaths.Length != 0) { throw new DirectoryNotFoundException("One or more folder paths do not exist: " + string.Join(", ", invalidPaths)); } @@ -155,7 +165,7 @@ private static void ValidateFilePaths(string[] filePaths) var invalidPaths = filePaths.Where(fp => !File.Exists(fp)).ToArray(); - if (invalidPaths.Any()) + if (invalidPaths.Length != 0) { throw new FileNotFoundException("One or more files do not exist: " + string.Join(", ", invalidPaths)); } diff --git a/Legba.Engine/ViewModels/AboutViewModel.cs b/Legba.Engine/ViewModels/AboutViewModel.cs index 387418d..dbdacc0 100644 --- a/Legba.Engine/ViewModels/AboutViewModel.cs +++ b/Legba.Engine/ViewModels/AboutViewModel.cs @@ -6,7 +6,7 @@ namespace Legba.Engine.ViewModels; public class AboutViewModel { - private int initialCopyrightYear = 2023; + private const int INITIAL_COPYRIGHT_YEAR = 2023; private static readonly Version s_version = Assembly.GetExecutingAssembly().GetName().Version; @@ -14,7 +14,7 @@ public class AboutViewModel public string VersionText => $"{s_version.Major}.{s_version.Minor}.{s_version.Revision}"; public string Copyright => - $"© {(DateTime.Now.Year == initialCopyrightYear ? $"{initialCopyrightYear}" : $"{initialCopyrightYear} - {DateTime.Now.Year}")}, Lilly Software Consulting"; + $"© {(DateTime.Now.Year == INITIAL_COPYRIGHT_YEAR ? $"{INITIAL_COPYRIGHT_YEAR}" : $"{INITIAL_COPYRIGHT_YEAR} - {DateTime.Now.Year}")}, Lilly Software Consulting"; public string License => "Licensed under the MIT License"; public string ContactInformation => diff --git a/Legba.Engine/ViewModels/ChatSessionViewModel.cs b/Legba.Engine/ViewModels/ChatSessionViewModel.cs index 5faf572..9e65a45 100644 --- a/Legba.Engine/ViewModels/ChatSessionViewModel.cs +++ b/Legba.Engine/ViewModels/ChatSessionViewModel.cs @@ -2,7 +2,10 @@ using Microsoft.Extensions.DependencyInjection; using System.Collections.ObjectModel; using System.Collections.Specialized; +using System.Windows; +using System.Windows.Documents; using System.Windows.Input; +using System.Windows.Media; namespace Legba.Engine.ViewModels; @@ -44,6 +47,7 @@ public ChatSession? ChatSession OnPropertyChanged(nameof(ChatSession)); OnPropertyChanged(nameof(HasChatSession)); OnPropertyChanged(nameof(HasChatMessages)); + OnPropertyChanged(nameof(MessagesDocument)); if (_chatSession != null) { @@ -52,6 +56,35 @@ public ChatSession? ChatSession } } + public FlowDocument MessagesDocument + { + get + { + var document = new FlowDocument(); + + if (ChatSession == null) + { + return document; + } + + foreach (var message in ChatSession.Messages) + { + var paragraph = new Paragraph(new Run(message.DisplayText)) + { + Margin = new Thickness(5), + TextAlignment = message.Alignment, + Background = message.BackgroundColor, + Padding = new Thickness(8), + FontSize = 14, + FontFamily = new FontFamily("Consolas") + }; + + document.Blocks.Add(paragraph); + } + + return document; + } + } public bool HasChatSession => ChatSession != null; public bool HasChatMessages => ChatSession?.Messages.Count > 0; @@ -80,6 +113,7 @@ public ChatSessionViewModel(IServiceProvider serviceProvider) private void Messages_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) { OnPropertyChanged(nameof(HasChatMessages)); + OnPropertyChanged(nameof(MessagesDocument)); } private void SelectModel(Settings.Model model) diff --git a/Legba/Legba.csproj b/Legba/Legba.csproj index e376f98..e10ae85 100644 --- a/Legba/Legba.csproj +++ b/Legba/Legba.csproj @@ -8,7 +8,7 @@ true True Images\LegbaIcon.ico - 2.0.0.0 + 2.1.0.0 f63a3566-54ef-4629-9a95-4254f119e9a0 @@ -24,12 +24,12 @@ - - - - - - + + + + + + diff --git a/Legba/MainWindow.xaml b/Legba/MainWindow.xaml index d04be1e..ddb2cdd 100644 --- a/Legba/MainWindow.xaml +++ b/Legba/MainWindow.xaml @@ -127,38 +127,15 @@ - - - - - - - - - - - - - - - - - - - - +