├── PiperUI ├── wpfui-icon-256.ico ├── Assets │ ├── wpfui-icon-1024.png │ ├── wpfui-icon-128.png │ └── wpfui-icon-256.png ├── Usings.cs ├── Resources │ └── Translations.cs ├── Models │ ├── DataColor.cs │ └── AppConfig.cs ├── App.xaml ├── Views │ ├── Pages │ │ ├── SettingsPage.xaml.cs │ │ ├── SettingsPage.xaml │ │ ├── DashboardPage.xaml │ │ └── DashboardPage.xaml.cs │ └── Windows │ │ ├── MainWindow.xaml.cs │ │ └── MainWindow.xaml ├── AssemblyInfo.cs ├── PiperUI.csproj ├── Helpers │ └── EnumToBooleanConverter.cs ├── ViewModels │ ├── Windows │ │ └── MainWindowViewModel.cs │ └── Pages │ │ ├── SettingsViewModel.cs │ │ └── DashboardViewModel.cs ├── Services │ └── ApplicationHostService.cs ├── app.manifest └── App.xaml.cs ├── README.md ├── PiperUI.sln ├── .gitattributes └── .gitignore /PiperUI/wpfui-icon-256.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K-Jadeja/PiperUI/master/PiperUI/wpfui-icon-256.ico -------------------------------------------------------------------------------- /PiperUI/Assets/wpfui-icon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K-Jadeja/PiperUI/master/PiperUI/Assets/wpfui-icon-1024.png -------------------------------------------------------------------------------- /PiperUI/Assets/wpfui-icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K-Jadeja/PiperUI/master/PiperUI/Assets/wpfui-icon-128.png -------------------------------------------------------------------------------- /PiperUI/Assets/wpfui-icon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/K-Jadeja/PiperUI/master/PiperUI/Assets/wpfui-icon-256.png -------------------------------------------------------------------------------- /PiperUI/Usings.cs: -------------------------------------------------------------------------------- 1 | global using CommunityToolkit.Mvvm.ComponentModel; 2 | global using CommunityToolkit.Mvvm.Input; 3 | global using System; 4 | global using System.Windows; 5 | global using Wpf.Ui.Contracts; 6 | global using Wpf.Ui.Services; 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PiperUI 2 | 3 | A user interface for creating voices with the Piper TTS. 4 | Uses the [Piper TTS](https://github.com/rhasspy/piper) for the text to speech, and [WPF UI](https://github.com/lepoco/wpfui) for the app theme / layout. 5 | 6 | ![image](https://github.com/natlamir/PiperUI/assets/137372478/7f85d001-c712-4452-b556-2fd2e3a4e549) 7 | 8 | -------------------------------------------------------------------------------- /PiperUI/Resources/Translations.cs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the MIT License. 2 | // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. 3 | // Copyright (C) Leszek Pomianowski and WPF UI Contributors. 4 | // All Rights Reserved. 5 | 6 | namespace PiperUI.Resources 7 | { 8 | public partial class Translations 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /PiperUI/Models/DataColor.cs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the MIT License. 2 | // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. 3 | // Copyright (C) Leszek Pomianowski and WPF UI Contributors. 4 | // All Rights Reserved. 5 | 6 | using System.Windows.Media; 7 | 8 | namespace PiperUI.Models 9 | { 10 | public struct DataColor 11 | { 12 | public Brush Color { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /PiperUI/Models/AppConfig.cs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the MIT License. 2 | // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. 3 | // Copyright (C) Leszek Pomianowski and WPF UI Contributors. 4 | // All Rights Reserved. 5 | 6 | namespace PiperUI.Models 7 | { 8 | public class AppConfig 9 | { 10 | public string ConfigurationsFolder { get; set; } 11 | 12 | public string AppPropertiesFileName { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /PiperUI/App.xaml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /PiperUI/Views/Pages/SettingsPage.xaml.cs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the MIT License. 2 | // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. 3 | // Copyright (C) Leszek Pomianowski and WPF UI Contributors. 4 | // All Rights Reserved. 5 | 6 | using PiperUI.ViewModels.Pages; 7 | using Wpf.Ui.Controls; 8 | 9 | namespace PiperUI.Views.Pages 10 | { 11 | public partial class SettingsPage : INavigableView 12 | { 13 | public SettingsViewModel ViewModel { get; } 14 | 15 | public SettingsPage(SettingsViewModel viewModel) 16 | { 17 | ViewModel = viewModel; 18 | DataContext = this; 19 | 20 | InitializeComponent(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /PiperUI/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the MIT License. 2 | // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. 3 | // Copyright (C) Leszek Pomianowski and WPF UI Contributors. 4 | // All Rights Reserved. 5 | 6 | using System.Windows; 7 | 8 | [assembly: ThemeInfo( 9 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 10 | //(used if a resource is not found in the page, 11 | // or application resource dictionaries) 12 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 13 | //(used if a resource is not found in the page, 14 | // app, or any theme specific resource dictionaries) 15 | )] 16 | -------------------------------------------------------------------------------- /PiperUI.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.34221.43 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PiperUI", "PiperUI\PiperUI.csproj", "{75A786A0-156E-4CF9-8A4C-2375161CF630}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {75A786A0-156E-4CF9-8A4C-2375161CF630}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {75A786A0-156E-4CF9-8A4C-2375161CF630}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {75A786A0-156E-4CF9-8A4C-2375161CF630}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {75A786A0-156E-4CF9-8A4C-2375161CF630}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {F4CB03C2-A521-4727-A607-0D3A27BAB6A5} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /PiperUI/Views/Windows/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the MIT License. 2 | // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. 3 | // Copyright (C) Leszek Pomianowski and WPF UI Contributors. 4 | // All Rights Reserved. 5 | 6 | using PiperUI.ViewModels.Windows; 7 | using Wpf.Ui.Controls; 8 | 9 | namespace PiperUI.Views.Windows 10 | { 11 | public partial class MainWindow 12 | { 13 | public MainWindowViewModel ViewModel { get; } 14 | 15 | public MainWindow( 16 | MainWindowViewModel viewModel, 17 | INavigationService navigationService, 18 | IServiceProvider serviceProvider, 19 | ISnackbarService snackbarService, 20 | IContentDialogService contentDialogService 21 | ) 22 | { 23 | Wpf.Ui.Appearance.Watcher.Watch(this); 24 | 25 | ViewModel = viewModel; 26 | DataContext = this; 27 | 28 | InitializeComponent(); 29 | 30 | navigationService.SetNavigationControl(NavigationView); 31 | snackbarService.SetSnackbarPresenter(SnackbarPresenter); 32 | contentDialogService.SetContentPresenter(RootContentDialog); 33 | 34 | NavigationView.SetServiceProvider(serviceProvider); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /PiperUI/PiperUI.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WinExe 5 | net7.0-windows 6 | app.manifest 7 | wpfui-icon-256.ico 8 | enable 9 | enable 10 | true 11 | wpfui-icon-128.png 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | True 38 | \ 39 | 40 | 41 | Always 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /PiperUI/Helpers/EnumToBooleanConverter.cs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the MIT License. 2 | // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. 3 | // Copyright (C) Leszek Pomianowski and WPF UI Contributors. 4 | // All Rights Reserved. 5 | 6 | using System.Globalization; 7 | using System.Windows.Data; 8 | 9 | namespace PiperUI.Helpers 10 | { 11 | internal class EnumToBooleanConverter : IValueConverter 12 | { 13 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 14 | { 15 | if (parameter is not String enumString) 16 | { 17 | throw new ArgumentException("ExceptionEnumToBooleanConverterParameterMustBeAnEnumName"); 18 | } 19 | 20 | if (!Enum.IsDefined(typeof(Wpf.Ui.Appearance.ThemeType), value)) 21 | { 22 | throw new ArgumentException("ExceptionEnumToBooleanConverterValueMustBeAnEnum"); 23 | } 24 | 25 | var enumValue = Enum.Parse(typeof(Wpf.Ui.Appearance.ThemeType), enumString); 26 | 27 | return enumValue.Equals(value); 28 | } 29 | 30 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 31 | { 32 | if (parameter is not String enumString) 33 | { 34 | throw new ArgumentException("ExceptionEnumToBooleanConverterParameterMustBeAnEnumName"); 35 | } 36 | 37 | return Enum.Parse(typeof(Wpf.Ui.Appearance.ThemeType), enumString); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /PiperUI/ViewModels/Windows/MainWindowViewModel.cs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the MIT License. 2 | // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. 3 | // Copyright (C) Leszek Pomianowski and WPF UI Contributors. 4 | // All Rights Reserved. 5 | 6 | using System.Collections.ObjectModel; 7 | using Wpf.Ui.Common; 8 | using Wpf.Ui.Controls; 9 | 10 | namespace PiperUI.ViewModels.Windows 11 | { 12 | public partial class MainWindowViewModel : ObservableObject 13 | { 14 | [ObservableProperty] 15 | private string _applicationTitle = "Piper"; 16 | 17 | [ObservableProperty] 18 | private ObservableCollection _menuItems = new() 19 | { 20 | new NavigationViewItem() 21 | { 22 | Content = "Piper", 23 | Icon = new SymbolIcon { Symbol = SymbolRegular.PersonFeedback16 }, 24 | TargetPageType = typeof(Views.Pages.DashboardPage) 25 | } 26 | }; 27 | 28 | [ObservableProperty] 29 | private ObservableCollection _footerMenuItems = new() 30 | { 31 | new NavigationViewItem() 32 | { 33 | Content = "Settings", 34 | Icon = new SymbolIcon { Symbol = SymbolRegular.Settings24 }, 35 | TargetPageType = typeof(Views.Pages.SettingsPage) 36 | } 37 | }; 38 | 39 | [ObservableProperty] 40 | private ObservableCollection _trayMenuItems = new() 41 | { 42 | new MenuItem { Header = "Home", Tag = "tray_home" } 43 | }; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /PiperUI/ViewModels/Pages/SettingsViewModel.cs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the MIT License. 2 | // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. 3 | // Copyright (C) Leszek Pomianowski and WPF UI Contributors. 4 | // All Rights Reserved. 5 | 6 | using Wpf.Ui.Controls; 7 | 8 | namespace PiperUI.ViewModels.Pages 9 | { 10 | public partial class SettingsViewModel : ObservableObject, INavigationAware 11 | { 12 | private bool _isInitialized = false; 13 | 14 | [ObservableProperty] 15 | private string _appVersion = String.Empty; 16 | 17 | [ObservableProperty] 18 | private Wpf.Ui.Appearance.ThemeType _currentTheme = Wpf.Ui.Appearance.ThemeType.Unknown; 19 | 20 | public void OnNavigatedTo() 21 | { 22 | if (!_isInitialized) 23 | InitializeViewModel(); 24 | } 25 | 26 | public void OnNavigatedFrom() { } 27 | 28 | private void InitializeViewModel() 29 | { 30 | CurrentTheme = Wpf.Ui.Appearance.Theme.GetAppTheme(); 31 | AppVersion = $"PiperUI - {GetAssemblyVersion()}"; 32 | 33 | _isInitialized = true; 34 | } 35 | 36 | private string GetAssemblyVersion() 37 | { 38 | return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version?.ToString() 39 | ?? String.Empty; 40 | } 41 | 42 | [RelayCommand] 43 | private void OnChangeTheme(string parameter) 44 | { 45 | switch (parameter) 46 | { 47 | case "theme_light": 48 | if (CurrentTheme == Wpf.Ui.Appearance.ThemeType.Light) 49 | break; 50 | 51 | Wpf.Ui.Appearance.Theme.Apply(Wpf.Ui.Appearance.ThemeType.Light); 52 | CurrentTheme = Wpf.Ui.Appearance.ThemeType.Light; 53 | 54 | break; 55 | 56 | default: 57 | if (CurrentTheme == Wpf.Ui.Appearance.ThemeType.Dark) 58 | break; 59 | 60 | Wpf.Ui.Appearance.Theme.Apply(Wpf.Ui.Appearance.ThemeType.Dark); 61 | CurrentTheme = Wpf.Ui.Appearance.ThemeType.Dark; 62 | 63 | break; 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /PiperUI/Views/Pages/SettingsPage.xaml: -------------------------------------------------------------------------------- 1 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 29 | 36 | 43 | 44 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /PiperUI/Services/ApplicationHostService.cs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the MIT License. 2 | // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. 3 | // Copyright (C) Leszek Pomianowski and WPF UI Contributors. 4 | // All Rights Reserved. 5 | 6 | using Microsoft.Extensions.DependencyInjection; 7 | using Microsoft.Extensions.Hosting; 8 | using PiperUI.Views.Pages; 9 | using PiperUI.Views.Windows; 10 | 11 | namespace PiperUI.Services 12 | { 13 | /// 14 | /// Managed host of the application. 15 | /// 16 | public class ApplicationHostService : IHostedService 17 | { 18 | private readonly IServiceProvider _serviceProvider; 19 | 20 | public ApplicationHostService(IServiceProvider serviceProvider) 21 | { 22 | _serviceProvider = serviceProvider; 23 | } 24 | 25 | /// 26 | /// Triggered when the application host is ready to start the service. 27 | /// 28 | /// Indicates that the start process has been aborted. 29 | public async Task StartAsync(CancellationToken cancellationToken) 30 | { 31 | await HandleActivationAsync(); 32 | } 33 | 34 | /// 35 | /// Triggered when the application host is performing a graceful shutdown. 36 | /// 37 | /// Indicates that the shutdown process should no longer be graceful. 38 | public async Task StopAsync(CancellationToken cancellationToken) 39 | { 40 | await Task.CompletedTask; 41 | } 42 | 43 | /// 44 | /// Creates main window during activation. 45 | /// 46 | private async Task HandleActivationAsync() 47 | { 48 | await Task.CompletedTask; 49 | 50 | if (!Application.Current.Windows.OfType().Any()) 51 | { 52 | var navigationWindow = _serviceProvider.GetRequiredService(); 53 | navigationWindow.Loaded += OnNavigationWindowLoaded; 54 | navigationWindow.Show(); 55 | } 56 | } 57 | 58 | private void OnNavigationWindowLoaded(object sender, RoutedEventArgs e) 59 | { 60 | if (sender is not MainWindow navigationWindow) 61 | { 62 | return; 63 | } 64 | 65 | navigationWindow.NavigationView.Navigate(typeof(DashboardPage)); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /PiperUI/ViewModels/Pages/DashboardViewModel.cs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the MIT License. 2 | // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. 3 | // Copyright (C) Leszek Pomianowski and WPF UI Contributors. 4 | // All Rights Reserved. 5 | 6 | using System.IO; 7 | 8 | namespace PiperUI.ViewModels.Pages 9 | { 10 | public partial class DashboardViewModel : ObservableObject 11 | { 12 | private Dictionary voiceData; // Your JSON data 13 | 14 | public DashboardViewModel() 15 | { 16 | InitializeData(); 17 | PopulateLanguageComboBox(); 18 | } 19 | 20 | [ObservableProperty] 21 | private int _counter = 0; 22 | 23 | [ObservableProperty] 24 | private List _languages = new List(); 25 | 26 | [ObservableProperty] 27 | private string selectedLanguage; 28 | 29 | [RelayCommand] 30 | private void OnCounterIncrement() 31 | { 32 | Counter++; 33 | } 34 | private void PopulateLanguageComboBox() 35 | { 36 | foreach (var voiceKey in voiceData.Keys) 37 | { 38 | string languageName = voiceData[voiceKey]["language"]["name_native"]; 39 | if (!_languages.Contains(languageName)) 40 | { 41 | _languages.Add(languageName); 42 | } 43 | } 44 | } 45 | 46 | private void ComboBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) 47 | { 48 | 49 | } 50 | 51 | private void InitializeData() 52 | { 53 | try 54 | { 55 | string filePath = "voices.json"; // Update the path to the location of your voices.json file 56 | 57 | if (File.Exists(filePath)) 58 | { 59 | string jsonData = File.ReadAllText(filePath); 60 | 61 | voiceData = Newtonsoft.Json.JsonConvert.DeserializeObject>(jsonData); 62 | 63 | if (voiceData == null) 64 | { 65 | // Handle the case where deserialization fails 66 | MessageBox.Show("Error loading JSON data."); 67 | } 68 | } 69 | else 70 | { 71 | // Handle the case where the file doesn't exist 72 | MessageBox.Show("File 'voices.json' not found."); 73 | } 74 | } 75 | catch (Exception ex) 76 | { 77 | // Handle exceptions appropriately 78 | MessageBox.Show($"An error occurred: {ex.Message}"); 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /PiperUI/Views/Windows/MainWindow.xaml: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | 29 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 54 | 55 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /PiperUI/Views/Pages/DashboardPage.xaml: -------------------------------------------------------------------------------- 1 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 48 | 49 | -------------------------------------------------------------------------------- /PiperUI/app.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 54 | 55 | 56 | 57 | PerMonitor 58 | true/PM 59 | true 60 | 61 | 62 | 63 | 64 | 65 | 66 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /PiperUI/App.xaml.cs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the MIT License. 2 | // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. 3 | // Copyright (C) Leszek Pomianowski and WPF UI Contributors. 4 | // All Rights Reserved. 5 | 6 | using Microsoft.Extensions.Configuration; 7 | using Microsoft.Extensions.DependencyInjection; 8 | using Microsoft.Extensions.Hosting; 9 | using PiperUI.Services; 10 | using PiperUI.ViewModels.Pages; 11 | using PiperUI.ViewModels.Windows; 12 | using PiperUI.Views.Pages; 13 | using PiperUI.Views.Windows; 14 | using System.IO; 15 | using System.Reflection; 16 | using System.Windows.Threading; 17 | 18 | namespace PiperUI 19 | { 20 | /// 21 | /// Interaction logic for App.xaml 22 | /// 23 | public partial class App 24 | { 25 | // The.NET Generic Host provides dependency injection, configuration, logging, and other services. 26 | // https://docs.microsoft.com/dotnet/core/extensions/generic-host 27 | // https://docs.microsoft.com/dotnet/core/extensions/dependency-injection 28 | // https://docs.microsoft.com/dotnet/core/extensions/configuration 29 | // https://docs.microsoft.com/dotnet/core/extensions/logging 30 | private static readonly IHost _host = Host 31 | .CreateDefaultBuilder() 32 | .ConfigureAppConfiguration(c => { c.SetBasePath(Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location)); }) 33 | .ConfigureServices((context, services) => 34 | { 35 | services.AddHostedService(); 36 | 37 | services.AddSingleton(); 38 | services.AddSingleton(); 39 | services.AddSingleton(); 40 | services.AddSingleton(); 41 | services.AddSingleton(); 42 | 43 | services.AddSingleton(); 44 | services.AddSingleton(); 45 | services.AddSingleton(); 46 | services.AddSingleton(); 47 | }).Build(); 48 | 49 | /// 50 | /// Gets registered service. 51 | /// 52 | /// Type of the service to get. 53 | /// Instance of the service or . 54 | public static T GetService() 55 | where T : class 56 | { 57 | return _host.Services.GetService(typeof(T)) as T; 58 | } 59 | 60 | /// 61 | /// Occurs when the application is loading. 62 | /// 63 | private void OnStartup(object sender, StartupEventArgs e) 64 | { 65 | _host.Start(); 66 | } 67 | 68 | /// 69 | /// Occurs when the application is closing. 70 | /// 71 | private async void OnExit(object sender, ExitEventArgs e) 72 | { 73 | await _host.StopAsync(); 74 | 75 | _host.Dispose(); 76 | } 77 | 78 | /// 79 | /// Occurs when an exception is thrown by an application but not handled. 80 | /// 81 | private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) 82 | { 83 | // For more info see https://docs.microsoft.com/en-us/dotnet/api/system.windows.application.dispatcherunhandledexception?view=windowsdesktop-6.0 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Oo]ut/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # ASP.NET Scaffolding 67 | ScaffoldingReadMe.txt 68 | 69 | # StyleCop 70 | StyleCopReport.xml 71 | 72 | # Files built by Visual Studio 73 | *_i.c 74 | *_p.c 75 | *_h.h 76 | *.ilk 77 | *.meta 78 | *.obj 79 | *.iobj 80 | *.pch 81 | *.pdb 82 | *.ipdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *_wpftmp.csproj 93 | *.log 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # CodeRush personal settings 313 | .cr/personal 314 | 315 | # Python Tools for Visual Studio (PTVS) 316 | __pycache__/ 317 | *.pyc 318 | 319 | # Cake - Uncomment if you are using it 320 | # tools/** 321 | # !tools/packages.config 322 | 323 | # Tabs Studio 324 | *.tss 325 | 326 | # Telerik's JustMock configuration file 327 | *.jmconfig 328 | 329 | # BizTalk build output 330 | *.btp.cs 331 | *.btm.cs 332 | *.odx.cs 333 | *.xsd.cs 334 | 335 | # OpenCover UI analysis results 336 | OpenCover/ 337 | 338 | # Azure Stream Analytics local run output 339 | ASALocalRun/ 340 | 341 | # MSBuild Binary and Structured Log 342 | *.binlog 343 | 344 | # NVidia Nsight GPU debugger configuration file 345 | *.nvuser 346 | 347 | # MFractors (Xamarin productivity tool) working folder 348 | .mfractor/ 349 | 350 | # Local History for Visual Studio 351 | .localhistory/ 352 | 353 | # BeatPulse healthcheck temp database 354 | healthchecksdb 355 | 356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 357 | MigrationBackup/ 358 | 359 | # Ionide (cross platform F# VS Code tools) working folder 360 | .ionide/ 361 | 362 | # Fody - auto-generated XML schema 363 | FodyWeavers.xsd -------------------------------------------------------------------------------- /PiperUI/Views/Pages/DashboardPage.xaml.cs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the MIT License. 2 | // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. 3 | // Copyright (C) Leszek Pomianowski and WPF UI Contributors. 4 | // All Rights Reserved. 5 | 6 | using PiperUI.ViewModels.Pages; 7 | using System; 8 | using System.Diagnostics; 9 | using System.IO; 10 | using System.Media; 11 | using System.Net; 12 | using System.Windows.Controls; 13 | using Wpf.Ui.Controls; 14 | 15 | namespace PiperUI.Views.Pages 16 | { 17 | public partial class DashboardPage : INavigableView 18 | { 19 | private Dictionary voiceData; // Your JSON data 20 | public DashboardViewModel ViewModel { get; } 21 | 22 | public DashboardPage(DashboardViewModel viewModel) 23 | { 24 | InitializeComponent(); 25 | InitializeData(); // Load your JSON data into voiceData 26 | PopulateLanguageComboBox(); 27 | PopulateCustomComboBox(); 28 | } 29 | 30 | private void pageLoad(object sender, RoutedEventArgs e) 31 | { 32 | // This will get the current WORKING directory (i.e. \bin\Debug) 33 | string workingDirectory = Environment.CurrentDirectory; 34 | // or: Directory.GetCurrentDirectory() gives the same result 35 | 36 | // This will get the current PROJECT bin directory (ie ../bin/) 37 | string projectDirectory = Directory.GetParent(workingDirectory).Parent.FullName; 38 | 39 | // This will get the current PROJECT directory 40 | string projectDirectory2 = Directory.GetParent(workingDirectory).Parent.Parent.FullName; 41 | } 42 | 43 | private void InitializeData() 44 | { 45 | try 46 | { 47 | string filePath = "voices.json"; // Update the path to the location of your voices.json file 48 | 49 | if (File.Exists(filePath)) 50 | { 51 | string jsonData = File.ReadAllText(filePath); 52 | 53 | voiceData = Newtonsoft.Json.JsonConvert.DeserializeObject>(jsonData); 54 | 55 | if (voiceData == null) 56 | { 57 | // Handle the case where deserialization fails 58 | System.Windows.MessageBox.Show("Error loading JSON data."); 59 | } 60 | } 61 | else 62 | { 63 | // Handle the case where the file doesn't exist 64 | System.Windows.MessageBox.Show("File 'voices.json' not found."); 65 | } 66 | } 67 | catch (Exception ex) 68 | { 69 | // Handle exceptions appropriately 70 | System.Windows.MessageBox.Show($"An error occurred: {ex.Message}"); 71 | } 72 | } 73 | 74 | private void PopulateCustomComboBox() 75 | { 76 | // Check if the folder exists 77 | if (Directory.Exists("custom")) 78 | { 79 | // Get all files with the ".onnx" extension in the folder 80 | string[] onnxFiles = Directory.GetFiles("custom", "*.onnx"); 81 | 82 | // Iterate through the files and add their names to the ComboBox 83 | foreach (string filePath in onnxFiles) 84 | { 85 | // Get the file name without extension 86 | string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filePath); 87 | 88 | // Add the file name to the ComboBox 89 | customComboBox.Items.Add(fileNameWithoutExtension); 90 | } 91 | } 92 | } 93 | 94 | private void PopulateLanguageComboBox() 95 | { 96 | foreach (var voiceKey in voiceData.Keys) 97 | { 98 | string languageName = voiceData[voiceKey]["language"]["name_native"]; 99 | if (!languageComboBox.Items.Contains(languageName)) 100 | { 101 | languageComboBox.Items.Add(languageName); 102 | } 103 | } 104 | } 105 | 106 | private void PopulateVoiceNameComboBox(string selectedLanguage) 107 | { 108 | voiceNameComboBox.Items.Clear(); 109 | 110 | foreach (var voiceKey in voiceData.Keys) 111 | { 112 | string languageName = voiceData[voiceKey]["language"]["name_native"]; 113 | string voiceName = voiceData[voiceKey]["name"]; 114 | 115 | if (languageName == selectedLanguage && !voiceNameComboBox.Items.Contains(voiceName)) 116 | { 117 | voiceNameComboBox.Items.Add(voiceName); 118 | } 119 | } 120 | } 121 | 122 | private void PopulateQualityComboBox(string selectedVoiceName) 123 | { 124 | qualityComboBox.Items.Clear(); 125 | 126 | foreach (var voiceKey in voiceData.Keys) 127 | { 128 | string voiceName = voiceData[voiceKey]["name"]; 129 | string quality = voiceData[voiceKey]["quality"]; 130 | 131 | if (voiceName == selectedVoiceName && !qualityComboBox.Items.Contains(quality)) 132 | { 133 | qualityComboBox.Items.Add(quality); 134 | } 135 | } 136 | } 137 | 138 | private void LanguageComboBox_SelectionChanged(object sender, RoutedEventArgs e) 139 | { 140 | string selectedLanguage = languageComboBox.SelectedItem as string; 141 | PopulateVoiceNameComboBox(selectedLanguage); 142 | } 143 | 144 | private void VoiceNameComboBox_SelectionChanged(object sender, RoutedEventArgs e) 145 | { 146 | string selectedVoiceName = voiceNameComboBox.SelectedItem as string; 147 | PopulateQualityComboBox(selectedVoiceName); 148 | } 149 | 150 | private async void GenerateButton_Click(object sender, RoutedEventArgs e) 151 | { 152 | string selectedVoiceName = voiceNameComboBox.SelectedItem as string; 153 | string selectedQuality = qualityComboBox.SelectedItem as string; 154 | string selectedLanguage = languageComboBox.SelectedItem as string; 155 | string customVoice = customComboBox.SelectedItem as string; 156 | 157 | if(!string.IsNullOrWhiteSpace(txtPrompt.Text) && customVoice != null) 158 | { 159 | await Task.Run(() => 160 | { 161 | CallPiper("custom", customVoice + ".onnx"); 162 | }); 163 | } 164 | else if (!string.IsNullOrWhiteSpace(txtPrompt.Text) && selectedLanguage != null && selectedVoiceName != null && selectedQuality != null) 165 | { 166 | string countryCode = GetCountryCode(selectedVoiceName, selectedQuality); 167 | string onnxFile = ""; 168 | 169 | if (countryCode != null && voiceData.ContainsKey(countryCode)) 170 | { 171 | onnxFile = await DownloadFiles(voiceData[countryCode]["files"]); 172 | } 173 | 174 | await Task.Run(() => 175 | { 176 | CallPiper("models", onnxFile); 177 | }); 178 | } 179 | else 180 | { 181 | System.Windows.MessageBox.Show("Make valid selections and enter a prompt"); 182 | } 183 | } 184 | 185 | private int GetNextFileNumber(string folderPath) 186 | { 187 | // Ensure the folder exists 188 | if (!Directory.Exists(folderPath)) 189 | { 190 | Directory.CreateDirectory(folderPath); 191 | } 192 | 193 | // Get all files with the .wav extension 194 | string[] files = Directory.GetFiles(folderPath, "*.wav"); 195 | 196 | // Determine the next file number 197 | int nextFileNumber = files.Length + 1; 198 | 199 | return nextFileNumber; 200 | } 201 | 202 | 203 | private void CallPiper(string modelFolder, string onnxFile) 204 | { 205 | string folderPath = "output"; // Replace with your actual folder path 206 | int nextFile = GetNextFileNumber(folderPath); 207 | 208 | if (!Directory.Exists("output")) 209 | Directory.CreateDirectory("output"); 210 | 211 | string prompt = ""; 212 | 213 | this.Dispatcher.Invoke(() => 214 | { 215 | prompt = txtPrompt.Text; 216 | }); 217 | 218 | string command = "chcp 65001 | echo '" + prompt.Replace("'", "''") + "' | piper --model " + modelFolder + "\\" + onnxFile + " --output_file output\\" + nextFile + ".wav"; 219 | 220 | ProcessStartInfo psi = new ProcessStartInfo 221 | { 222 | FileName = "cmd.exe", 223 | Arguments = $"/C \"{command}\"", 224 | RedirectStandardInput = true, 225 | RedirectStandardOutput = true, 226 | RedirectStandardError = true, 227 | UseShellExecute = false, 228 | CreateNoWindow = true, 229 | WorkingDirectory = Environment.CurrentDirectory 230 | }; 231 | 232 | Process process = new Process { StartInfo = psi }; 233 | process.Start(); 234 | 235 | string output = process.StandardOutput.ReadToEnd(); 236 | string error = process.StandardError.ReadToEnd(); 237 | 238 | process.WaitForExit(); 239 | int exitCode = process.ExitCode; 240 | 241 | process.Close(); 242 | SoundPlayer player = new SoundPlayer("output\\" + nextFile + ".wav"); 243 | player.Load(); 244 | player.Play(); 245 | } 246 | 247 | private string GetCountryCode(string selectedVoiceName, string selectedQuality) 248 | { 249 | foreach (var countryCode in voiceData.Keys) 250 | { 251 | if (countryCode.Contains(selectedVoiceName + "-" + selectedQuality)) 252 | return countryCode; 253 | } 254 | 255 | return null; // Handle the case where the country code is not found 256 | } 257 | 258 | private async Task DownloadFiles(dynamic files) 259 | { 260 | try 261 | { 262 | string resultFileName = string.Empty; 263 | 264 | foreach (var file in files) 265 | { 266 | string fileName = file.Name; 267 | if (!fileName.EndsWith(".onnx") && !fileName.EndsWith(".json")) 268 | continue; 269 | 270 | string fileUrl = @"https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/" + fileName + "?download=true"; 271 | 272 | if (!File.Exists("models\\" + System.IO.Path.GetFileName(fileName))) 273 | { 274 | lblGenerate.Content = "downloading file: " + fileName; 275 | 276 | using (WebClient client = new WebClient()) 277 | { 278 | if (!Directory.Exists("models")) 279 | Directory.CreateDirectory("models"); 280 | 281 | await Task.Run(() => client.DownloadFile(fileUrl, "models\\" + System.IO.Path.GetFileName(fileName))); 282 | 283 | if (fileName.EndsWith(".onnx")) 284 | resultFileName = System.IO.Path.GetFileName(fileName); 285 | } 286 | } 287 | else 288 | { 289 | lblGenerate.Content = ""; 290 | 291 | if (fileName.EndsWith(".onnx")) 292 | resultFileName = System.IO.Path.GetFileName(fileName); 293 | } 294 | } 295 | lblGenerate.Content = ""; 296 | return resultFileName; 297 | } 298 | catch (Exception ex) 299 | { 300 | System.Windows.MessageBox.Show($"An error occurred during file download: {ex.Message}"); 301 | return string.Empty; // Handle the exception by returning a default value 302 | } 303 | } 304 | 305 | private void qualityComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) 306 | { 307 | 308 | } 309 | 310 | private void customComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) 311 | { 312 | 313 | } 314 | 315 | private void ClearButton_Click(object sender, RoutedEventArgs e) 316 | { 317 | customComboBox.SelectedIndex = -1; 318 | } 319 | } 320 | } 321 | --------------------------------------------------------------------------------