diff --git a/DemoApp/App.xaml b/DemoApp/App.xaml
index 572b06c..17c8054 100644
--- a/DemoApp/App.xaml
+++ b/DemoApp/App.xaml
@@ -83,7 +83,23 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/DemoApp/Controls/NarrateModelControl.xaml.cs b/DemoApp/Controls/NarrateModelControl.xaml.cs
new file mode 100644
index 0000000..86e812e
--- /dev/null
+++ b/DemoApp/Controls/NarrateModelControl.xaml.cs
@@ -0,0 +1,188 @@
+using DemoApp.Common;
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Data;
+using TensorStack.Common;
+using TensorStack.WPF;
+using TensorStack.WPF.Controls;
+
+namespace DemoApp.Controls
+{
+ ///
+ /// Interaction logic for NarrateModelControl.xaml
+ ///
+ public partial class NarrateModelControl : BaseControl
+ {
+ private ListCollectionView _modelCollectionView;
+ private Device _selectedDevice;
+ private NarrateModel _selectedModel;
+ private Device _currentDevice;
+ private NarrateModel _currentModel;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public NarrateModelControl()
+ {
+ LoadCommand = new AsyncRelayCommand(LoadAsync, CanLoad);
+ UnloadCommand = new AsyncRelayCommand(UnloadAsync, CanUnload);
+ InitializeComponent();
+ }
+
+ public static readonly DependencyProperty SettingsProperty = DependencyProperty.Register(nameof(Settings), typeof(Settings), typeof(NarrateModelControl), new PropertyMetadata((c) => c.OnSettingsChanged()));
+ public static readonly DependencyProperty IsSelectionValidProperty = DependencyProperty.Register(nameof(IsSelectionValid), typeof(bool), typeof(NarrateModelControl));
+ public static readonly DependencyProperty CurrentPipelineProperty = DependencyProperty.Register(nameof(CurrentPipeline), typeof(PipelineModel), typeof(NarrateModelControl), new PropertyMetadata((c) => c.OnPipelineChanged()));
+
+ public event EventHandler SelectionChanged;
+ public AsyncRelayCommand LoadCommand { get; }
+ public AsyncRelayCommand UnloadCommand { get; }
+
+ public Settings Settings
+ {
+ get { return (Settings)GetValue(SettingsProperty); }
+ set { SetValue(SettingsProperty, value); }
+ }
+
+ public bool IsSelectionValid
+ {
+ get { return (bool)GetValue(IsSelectionValidProperty); }
+ set { SetValue(IsSelectionValidProperty, value); }
+ }
+
+ public PipelineModel CurrentPipeline
+ {
+ get { return (PipelineModel)GetValue(CurrentPipelineProperty); }
+ set { SetValue(CurrentPipelineProperty, value); }
+ }
+
+ public Device SelectedDevice
+ {
+ get { return _selectedDevice; }
+ set { SetProperty(ref _selectedDevice, value); }
+ }
+
+ public NarrateModel SelectedModel
+ {
+ get { return _selectedModel; }
+ set { SetProperty(ref _selectedModel, value); }
+ }
+
+ public ListCollectionView ModelCollectionView
+ {
+ get { return _modelCollectionView; }
+ set { SetProperty(ref _modelCollectionView, value); }
+ }
+
+ private async Task LoadAsync()
+ {
+ if (!await IsModelValidAsync())
+ return;
+
+ _currentDevice = SelectedDevice;
+ _currentModel = SelectedModel;
+ CurrentPipeline = new PipelineModel
+ {
+ Device = _currentDevice,
+ NarrateModel = _currentModel
+ };
+ }
+
+
+ private bool CanLoad()
+ {
+ var isReloadRequired = SelectedDevice is not null
+ && SelectedModel is not null
+ && HasCurrentChanged();
+
+ var isSelectionValid = !isReloadRequired;
+ if (IsSelectionValid != isSelectionValid)
+ IsSelectionValid = isSelectionValid;
+
+ return isReloadRequired;
+ }
+
+
+ private Task UnloadAsync()
+ {
+ _currentModel = default;
+ CurrentPipeline = new PipelineModel
+ {
+ Device = _selectedDevice
+ };
+
+ return Task.CompletedTask;
+ }
+
+
+ private bool CanUnload()
+ {
+ return _currentModel is not null;
+ }
+
+
+ private bool HasCurrentChanged()
+ {
+ return _currentDevice != SelectedDevice
+ || _currentModel != SelectedModel;
+ }
+
+
+ private Task OnSettingsChanged()
+ {
+ ModelCollectionView = new ListCollectionView(Settings.NarrateModels);
+ ModelCollectionView.Filter = (obj) =>
+ {
+ if (obj is not NarrateModel viewModel)
+ return false;
+
+ if (_selectedDevice == null)
+ return false;
+
+ return viewModel.SupportedDevices?.Contains(_selectedDevice.Type) ?? false;
+ };
+
+ SelectedDevice = Settings.DefaultDevice;
+ return Task.CompletedTask;
+ }
+
+
+ private void Device_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
+ {
+ ModelCollectionView?.Refresh();
+ if (ModelCollectionView is not null)
+ {
+ SelectedModel = ModelCollectionView.Cast().FirstOrDefault(x => x == _currentModel || x.IsDefault);
+ }
+ }
+
+
+ private Task OnPipelineChanged()
+ {
+ SelectedDevice = CurrentPipeline?.Device ?? Settings.DefaultDevice;
+ if (CurrentPipeline?.NarrateModel is not null)
+ {
+ SelectedModel = CurrentPipeline.NarrateModel;
+ }
+
+ _currentDevice = CurrentPipeline?.Device;
+ _currentModel = CurrentPipeline?.NarrateModel;
+ SelectionChanged?.Invoke(this, CurrentPipeline);
+ return Task.CompletedTask;
+ }
+
+
+ private async Task IsModelValidAsync()
+ {
+ if (_selectedModel is null)
+ return false;
+
+ if (_selectedModel.IsValid)
+ return true;
+
+ return await _selectedModel.DownloadAsync(Path.Combine(Settings.DirectoryModel, "Narrate"));
+ }
+ }
+}
diff --git a/DemoApp/DemoApp.csproj b/DemoApp/DemoApp.csproj
index 85ecec1..ab5274c 100644
--- a/DemoApp/DemoApp.csproj
+++ b/DemoApp/DemoApp.csproj
@@ -2,7 +2,7 @@
WinExe
- net9.0-windows10.0.17763.0
+ net10.0-windows10.0.17763.0
x64
true
Images\Icon.ico
diff --git a/DemoApp/MainWindow.xaml b/DemoApp/MainWindow.xaml
index a041f36..c46f1da 100644
--- a/DemoApp/MainWindow.xaml
+++ b/DemoApp/MainWindow.xaml
@@ -335,6 +335,24 @@
+
+
+
+
diff --git a/DemoApp/Properties/PublishProfiles/SelfContained_DML.pubxml b/DemoApp/Properties/PublishProfiles/SelfContained.pubxml
similarity index 89%
rename from DemoApp/Properties/PublishProfiles/SelfContained_DML.pubxml
rename to DemoApp/Properties/PublishProfiles/SelfContained.pubxml
index aa9c6a1..9460904 100644
--- a/DemoApp/Properties/PublishProfiles/SelfContained_DML.pubxml
+++ b/DemoApp/Properties/PublishProfiles/SelfContained.pubxml
@@ -7,7 +7,7 @@
bin\Build\DemoApp
FileSystem
<_TargetId>Folder
- net9.0-windows10.0.17763.0
+ net10.0-windows10.0.17763.0
win-x64
true
true
diff --git a/DemoApp/Services/HistoryService.cs b/DemoApp/Services/HistoryService.cs
index 74adda5..d390e89 100644
--- a/DemoApp/Services/HistoryService.cs
+++ b/DemoApp/Services/HistoryService.cs
@@ -1,11 +1,11 @@
-using DemoApp;
-using DemoApp.Common;
+using DemoApp.Common;
using DemoApp.Views;
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
+using TensorStack.Audio;
using TensorStack.Common.Common;
using TensorStack.Image;
using TensorStack.Video;
@@ -55,6 +55,8 @@ public async Task InitializeAsync()
historyItem = await Json.LoadAsync(historyFile.FullName);
if (historyFile.Name.StartsWith("Diffusion_"))
historyItem = await Json.LoadAsync(historyFile.FullName);
+ if (historyFile.Name.StartsWith("Narrate_"))
+ historyItem = await Json.LoadAsync(historyFile.FullName);
if (historyItem == null)
continue;
@@ -153,6 +155,23 @@ public async Task AddAsync(VideoInputStream videoStream, T
}
+ ///
+ /// Add new Audio to the history timeline
+ ///
+ ///
+ /// The audio.
+ /// The history.
+ /// A Task<AudioInput> representing the asynchronous operation.
+ public async Task AddAsync(AudioInput audio, T history) where T : HistoryItem
+ {
+ SetSavePath(history);
+ await audio.SaveAsync(history.MediaPath);
+ await Json.SaveAsync(history, history.FilePath);
+ _historyCollection.Add(history);
+ return audio;
+ }
+
+
///
/// Gets the save path.
///
@@ -169,6 +188,8 @@ private void SetSavePath(HistoryItem history)
View.VideoUpscale => "Upscale",
View.VideoExtractor => "Extractor",
+
+ View.AudioNarrate => "Narrate",
_ => throw new NotImplementedException()
};
@@ -182,6 +203,8 @@ private void SetSavePath(HistoryItem history)
View.VideoUpscale => _settings.DirectoryHistory,
View.VideoExtractor => _settings.DirectoryHistory,
+
+ View.AudioNarrate => _settings.DirectoryHistory,
_ => throw new NotImplementedException()
});
@@ -189,6 +212,7 @@ private void SetSavePath(HistoryItem history)
{
MediaType.Image => "png",
MediaType.Video => "mp4",
+ MediaType.Audio => "wav",
_ => throw new NotImplementedException()
};
@@ -212,5 +236,6 @@ public interface IHistoryService
Task AddAsync(ImageInput image, T history) where T : HistoryItem;
Task AddAsync(VideoInputStream videoStream, T history) where T : HistoryItem;
+ Task AddAsync(AudioInput audio, T history) where T : HistoryItem;
}
}
diff --git a/DemoApp/Services/NarrateService.cs b/DemoApp/Services/NarrateService.cs
new file mode 100644
index 0000000..9a489ba
--- /dev/null
+++ b/DemoApp/Services/NarrateService.cs
@@ -0,0 +1,196 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using TensorStack.Common;
+using TensorStack.Common.Pipeline;
+using TensorStack.Common.Tensor;
+using DemoApp.Common;
+using TensorStack.Providers;
+using TensorStack.TextGeneration.Common;
+using TensorStack.TextGeneration.Pipelines.Supertonic;
+
+namespace DemoApp.Services
+{
+ public class NarrateService : ServiceBase, INarrateService
+ {
+ private readonly Settings _settings;
+ private IPipeline _narratePipeline;
+ private PipelineModel _currentPipeline;
+ private CancellationTokenSource _cancellationTokenSource;
+ private bool _isLoaded;
+ private bool _isLoading;
+ private bool _isExecuting;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The settings.
+ public NarrateService(Settings settings)
+ {
+ _settings = settings;
+ }
+
+ ///
+ /// Gets the pipeline.
+ ///
+ public PipelineModel Pipeline => _currentPipeline;
+
+ ///
+ /// Gets a value indicating whether this instance is loaded.
+ ///
+ public bool IsLoaded
+ {
+ get { return _isLoaded; }
+ private set { SetProperty(ref _isLoaded, value); }
+ }
+
+ ///
+ /// Gets a value indicating whether this instance is loading.
+ ///
+ public bool IsLoading
+ {
+ get { return _isLoading; }
+ private set { SetProperty(ref _isLoading, value); NotifyPropertyChanged(nameof(CanCancel)); }
+ }
+
+ ///
+ /// Gets a value indicating whether this instance is executing.
+ ///
+ public bool IsExecuting
+ {
+ get { return _isExecuting; }
+ private set { SetProperty(ref _isExecuting, value); NotifyPropertyChanged(nameof(CanCancel)); }
+ }
+
+ ///
+ /// Gets a value indicating whether this instance can cancel.
+ ///
+ public bool CanCancel => _isLoading || _isExecuting;
+
+
+ ///
+ /// Load the upscale pipeline
+ ///
+ /// The configuration.
+ public async Task LoadAsync(PipelineModel pipeline)
+ {
+ try
+ {
+ IsLoaded = false;
+ IsLoading = true;
+ using (_cancellationTokenSource = new CancellationTokenSource())
+ {
+ var cancellationToken = _cancellationTokenSource.Token;
+ if (_narratePipeline != null)
+ await _narratePipeline.UnloadAsync(cancellationToken);
+
+ _currentPipeline = pipeline;
+ var device = pipeline.Device;
+ var model = pipeline.NarrateModel;
+ var provider = device.GetProvider();
+ _narratePipeline = SupertonicPipeline.Create(model.Path, provider);
+ await Task.Run(() => _narratePipeline.LoadAsync(cancellationToken), cancellationToken);
+ }
+ }
+ catch (OperationCanceledException)
+ {
+ _narratePipeline?.Dispose();
+ _narratePipeline = null;
+ _currentPipeline = null;
+ throw;
+ }
+ finally
+ {
+ IsLoaded = true;
+ IsLoading = false;
+ }
+ }
+
+
+ ///
+ /// Execute the pipeline.
+ ///
+ /// The options.
+ public async Task ExecuteAsync(NarrateRequest options)
+ {
+ try
+ {
+ IsExecuting = true;
+ using (_cancellationTokenSource = new CancellationTokenSource())
+ {
+ var pipeline = _narratePipeline as IPipeline;
+ var pipelineOptions = new SupertonicOptions
+ {
+ TextInput = options.InputText,
+ VoiceStyle = options.VoiceStyle,
+ Steps = options.Steps,
+ Speed = options.Speed,
+ SilenceDuration = options.SilenceDuration,
+ Seed = options.Seed,
+ };
+
+ return await pipeline.RunAsync(pipelineOptions, cancellationToken: _cancellationTokenSource.Token);
+ }
+ }
+ finally
+ {
+ IsExecuting = false;
+ }
+ }
+
+
+ ///
+ /// Cancel the running task (Load or Execute)
+ ///
+ public async Task CancelAsync()
+ {
+ await _cancellationTokenSource.SafeCancelAsync();
+ }
+
+
+ ///
+ /// Unload the pipeline
+ ///
+ public async Task UnloadAsync()
+ {
+ if (_narratePipeline != null)
+ {
+ await _cancellationTokenSource.SafeCancelAsync();
+ await _narratePipeline.UnloadAsync();
+ _narratePipeline.Dispose();
+ _narratePipeline = null;
+ _currentPipeline = null;
+ }
+
+ IsLoaded = false;
+ IsLoading = false;
+ IsExecuting = false;
+ }
+ }
+
+
+ public interface INarrateService
+ {
+ PipelineModel Pipeline { get; }
+ bool IsLoaded { get; }
+ bool IsLoading { get; }
+ bool IsExecuting { get; }
+ bool CanCancel { get; }
+ Task LoadAsync(PipelineModel pipeline);
+ Task UnloadAsync();
+ Task CancelAsync();
+ Task ExecuteAsync(NarrateRequest options);
+ }
+
+
+ public record NarrateRequest
+ {
+ public string InputText { get; set; }
+ public string VoiceStyle { get; set; }
+ public int Steps { get; set; } = 5;
+ public float Speed { get; set; } = 1f;
+ public float SilenceDuration { get; set; } = 0.3f;
+ public int Seed { get; set; }
+ }
+
+}
diff --git a/DemoApp/Settings.cs b/DemoApp/Settings.cs
index fd41579..c113db6 100644
--- a/DemoApp/Settings.cs
+++ b/DemoApp/Settings.cs
@@ -30,6 +30,7 @@ public class Settings : IUIConfiguration
public ObservableCollection DetectModels { get; set; }
public ObservableCollection TextModels { get; set; }
public ObservableCollection TranscribeModels { get; set; }
+ public ObservableCollection NarrateModels { get; set; }
public void Initialize()
@@ -72,6 +73,10 @@ private void ScanModels()
foreach (var transcribeModel in TranscribeModels)
transcribeModel.Initialize(transcribeDirectory);
+ var narrateDirectory = Path.Combine(DirectoryModel, "Narrate");
+ foreach (var narrateModel in NarrateModels)
+ narrateModel.Initialize(narrateDirectory);
+
var diffusionDirectory = Path.Combine(DirectoryModel, "Diffusion");
foreach (var diffusionModel in DiffusionModels)
diffusionModel.Initialize(diffusionDirectory);
@@ -129,7 +134,6 @@ public void SetDefault(TextModel model)
model.IsDefault = true;
}
-
public void SetDefault(TranscribeModel model)
{
foreach (var existing in TextModels)
@@ -138,5 +142,14 @@ public void SetDefault(TranscribeModel model)
}
model.IsDefault = true;
}
+
+ public void SetDefault(NarrateModel model)
+ {
+ foreach (var existing in NarrateModels)
+ {
+ existing.IsDefault = false;
+ }
+ model.IsDefault = true;
+ }
}
}
\ No newline at end of file
diff --git a/DemoApp/Settings.json b/DemoApp/Settings.json
index acad620..ddd4593 100644
--- a/DemoApp/Settings.json
+++ b/DemoApp/Settings.json
@@ -557,6 +557,137 @@
]
}
],
+ "ExtractorModels": [
+ {
+ "Id": 1,
+ "Name": "Canny",
+ "Type": "Default",
+ "SupportedDevices": [ "CPU", "GPU" ],
+ "Channels": 3,
+ "SampleSize": 0,
+ "OutputChannels": 1,
+ "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/Canny/model.onnx?download=true" ]
+ },
+ {
+ "Id": 2,
+ "Name": "SoftEdge",
+ "Type": "Default",
+ "IsDefault": true,
+ "SupportedDevices": [ "CPU", "GPU" ],
+ "Channels": 3,
+ "SampleSize": 0,
+ "OutputChannels": 1,
+ "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/SoftEdge/model.onnx?download=true" ]
+ },
+ {
+ "Id": 3,
+ "Name": "Depth",
+ "Type": "Default",
+ "SupportedDevices": [ "CPU", "GPU" ],
+ "Channels": 3,
+ "SampleSize": 0,
+ "OutputChannels": 1,
+ "OutputNormalization": "MinMaxOneToOne",
+ "IsDynamicOutput": true,
+ "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/Depth/model.onnx?download=true" ]
+ },
+ {
+ "Id": 4,
+ "Name": "LineDrawing",
+ "Type": "Default",
+ "SupportedDevices": [ "CPU", "GPU" ],
+ "Channels": 3,
+ "SampleSize": 0,
+ "OutputChannels": 1,
+ "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/LineDrawing/model.onnx?download=true" ]
+ },
+ {
+ "Id": 5,
+ "Name": "DepthAnything-Small",
+ "Type": "Default",
+ "SupportedDevices": [ "CPU", "GPU" ],
+ "Channels": 3,
+ "SampleSize": 0,
+ "OutputChannels": 1,
+ "IsDynamicOutput": true,
+ "OutputNormalization": "MinMaxOneToOne",
+ "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/DepthAnything-Small/model.onnx?download=true" ]
+ },
+ {
+ "Id": 6,
+ "Name": "DepthAnything-Base",
+ "Type": "Default",
+ "SupportedDevices": [ "CPU", "GPU" ],
+ "Channels": 3,
+ "SampleSize": 0,
+ "OutputChannels": 1,
+ "IsDynamicOutput": true,
+ "OutputNormalization": "MinMaxOneToOne",
+ "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/DepthAnything-Base/model.onnx?download=true" ]
+ },
+ {
+ "Id": 8,
+ "Name": "DepthAnything-Large",
+ "Type": "Default",
+ "SupportedDevices": [ "CPU", "GPU" ],
+ "Channels": 3,
+ "SampleSize": 0,
+ "OutputChannels": 1,
+ "IsDynamicOutput": true,
+ "OutputNormalization": "MinMaxOneToOne",
+ "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/DepthAnything-Large/model.onnx?download=true" ]
+ },
+ {
+ "Id": 9,
+ "Name": "BiRefNet",
+ "Type": "Background",
+ "SupportedDevices": [ "CPU", "GPU" ],
+ "Channels": 3,
+ "SampleSize": 1024,
+ "OutputChannels": 1,
+ "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/BiRefNet/model.onnx?download=true" ]
+ },
+ {
+ "Id": 10,
+ "Name": "RMBG 1.4",
+ "Type": "Background",
+ "SupportedDevices": [ "CPU", "GPU" ],
+ "IsDefault": true,
+ "Channels": 3,
+ "SampleSize": 1024,
+ "OutputChannels": 1,
+ "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/RMBGv1.4/model.onnx?download=true" ]
+ },
+ {
+ "Id": 11,
+ "Name": "RMBG 2.0",
+ "Type": "Background",
+ "SupportedDevices": [ "CPU", "GPU" ],
+ "Channels": 3,
+ "SampleSize": 1024,
+ "OutputChannels": 1,
+ "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/RMBGv2.0/model.onnx?download=true" ]
+ },
+ {
+ "Id": 12,
+ "Name": "RTMO - Body7",
+ "Type": "Pose",
+ "SupportedDevices": [ "CPU", "GPU" ],
+ "IsDefault": true,
+ "Channels": 3,
+ "SampleSize": 640,
+ "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/Pose-Body7/model.onnx?download=true" ]
+ },
+ {
+ "Id": 13,
+ "Name": "RTMO - Coco",
+ "Type": "Pose",
+ "SupportedDevices": [ "CPU", "GPU" ],
+ "Channels": 3,
+ "SampleSize": 640,
+ "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/Pose-Coco/model.onnx?download=true" ]
+ }
+ ],
"DetectModels": [
{
"Id": 1,
@@ -609,7 +740,8 @@
]
}
],
- "TranscribeModels": [{
+ "TranscribeModels": [
+ {
"Id": 1,
"Name": "Whisper-Tiny",
"IsDefault": true,
@@ -696,135 +828,31 @@
]
}
],
- "ExtractorModels": [
+ "NarrateModels": [
{
"Id": 1,
- "Name": "Canny",
- "Type": "Default",
- "SupportedDevices": [ "CPU", "GPU" ],
- "Channels": 3,
- "SampleSize": 0,
- "OutputChannels": 1,
- "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/Canny/model.onnx?download=true" ]
- },
- {
- "Id": 2,
- "Name": "SoftEdge",
- "Type": "Default",
+ "Name": "Supertonic",
"IsDefault": true,
"SupportedDevices": [ "CPU", "GPU" ],
- "Channels": 3,
- "SampleSize": 0,
- "OutputChannels": 1,
- "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/SoftEdge/model.onnx?download=true" ]
- },
- {
- "Id": 3,
- "Name": "Depth",
- "Type": "Default",
- "SupportedDevices": [ "CPU", "GPU" ],
- "Channels": 3,
- "SampleSize": 0,
- "OutputChannels": 1,
- "OutputNormalization": "MinMaxOneToOne",
- "IsDynamicOutput": true,
- "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/Depth/model.onnx?download=true" ]
- },
- {
- "Id": 4,
- "Name": "LineDrawing",
- "Type": "Default",
- "SupportedDevices": [ "CPU", "GPU" ],
- "Channels": 3,
- "SampleSize": 0,
- "OutputChannels": 1,
- "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/LineDrawing/model.onnx?download=true" ]
- },
- {
- "Id": 5,
- "Name": "DepthAnything-Small",
- "Type": "Default",
- "SupportedDevices": [ "CPU", "GPU" ],
- "Channels": 3,
- "SampleSize": 0,
- "OutputChannels": 1,
- "IsDynamicOutput": true,
- "OutputNormalization": "MinMaxOneToOne",
- "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/DepthAnything-Small/model.onnx?download=true" ]
- },
- {
- "Id": 6,
- "Name": "DepthAnything-Base",
- "Type": "Default",
- "SupportedDevices": [ "CPU", "GPU" ],
- "Channels": 3,
- "SampleSize": 0,
- "OutputChannels": 1,
- "IsDynamicOutput": true,
- "OutputNormalization": "MinMaxOneToOne",
- "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/DepthAnything-Base/model.onnx?download=true" ]
- },
- {
- "Id": 8,
- "Name": "DepthAnything-Large",
- "Type": "Default",
- "SupportedDevices": [ "CPU", "GPU" ],
- "Channels": 3,
- "SampleSize": 0,
- "OutputChannels": 1,
- "IsDynamicOutput": true,
- "OutputNormalization": "MinMaxOneToOne",
- "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/DepthAnything-Large/model.onnx?download=true" ]
- },
- {
- "Id": 9,
- "Name": "BiRefNet",
- "Type": "Background",
- "SupportedDevices": [ "CPU", "GPU" ],
- "Channels": 3,
- "SampleSize": 1024,
- "OutputChannels": 1,
- "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/BiRefNet/model.onnx?download=true" ]
- },
- {
- "Id": 10,
- "Name": "RMBG 1.4",
- "Type": "Background",
- "SupportedDevices": [ "CPU", "GPU" ],
- "IsDefault": true,
- "Channels": 3,
- "SampleSize": 1024,
- "OutputChannels": 1,
- "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/RMBGv1.4/model.onnx?download=true" ]
- },
- {
- "Id": 11,
- "Name": "RMBG 2.0",
- "Type": "Background",
- "SupportedDevices": [ "CPU", "GPU" ],
- "Channels": 3,
- "SampleSize": 1024,
- "OutputChannels": 1,
- "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/RMBGv2.0/model.onnx?download=true" ]
- },
- {
- "Id": 12,
- "Name": "RTMO - Body7",
- "Type": "Pose",
- "SupportedDevices": [ "CPU", "GPU" ],
- "IsDefault": true,
- "Channels": 3,
- "SampleSize": 640,
- "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/Pose-Body7/model.onnx?download=true" ]
- },
- {
- "Id": 13,
- "Name": "RTMO - Coco",
- "Type": "Pose",
- "SupportedDevices": [ "CPU", "GPU" ],
- "Channels": 3,
- "SampleSize": 640,
- "UrlPaths": [ "https://huggingface.co/saddam213/DemoApp/resolve/main/Extractor/Pose-Coco/model.onnx?download=true" ]
+ "MaxLength": 512,
+ "Voices": [ "Female1", "Female2", "Female3", "Female4", "Female5", "Male1", "Male2", "Male3", "Male4", "Male5" ],
+ "UrlPaths": [
+ "https://huggingface.co/saddam213/DemoApp/resolve/main/Text/Supertonic/duration_predictor.onnx?download=true",
+ "https://huggingface.co/saddam213/DemoApp/resolve/main/Text/Supertonic/text_encoder.onnx?download=true",
+ "https://huggingface.co/saddam213/DemoApp/resolve/main/Text/Supertonic/unicode_indexer.json?download=true",
+ "https://huggingface.co/saddam213/DemoApp/resolve/main/Text/Supertonic/vector_estimator.onnx?download=true",
+ "https://huggingface.co/saddam213/DemoApp/resolve/main/Text/Supertonic/vocoder.onnx?download=true",
+ "https://huggingface.co/saddam213/DemoApp/resolve/main/Text/Supertonic/voice_styles/Female1.json?download=true",
+ "https://huggingface.co/saddam213/DemoApp/resolve/main/Text/Supertonic/voice_styles/Female2.json?download=true",
+ "https://huggingface.co/saddam213/DemoApp/resolve/main/Text/Supertonic/voice_styles/Female3.json?download=true",
+ "https://huggingface.co/saddam213/DemoApp/resolve/main/Text/Supertonic/voice_styles/Female4.json?download=true",
+ "https://huggingface.co/saddam213/DemoApp/resolve/main/Text/Supertonic/voice_styles/Female5.json?download=true",
+ "https://huggingface.co/saddam213/DemoApp/resolve/main/Text/Supertonic/voice_styles/Male1.json?download=true",
+ "https://huggingface.co/saddam213/DemoApp/resolve/main/Text/Supertonic/voice_styles/Male2.json?download=true",
+ "https://huggingface.co/saddam213/DemoApp/resolve/main/Text/Supertonic/voice_styles/Male3.json?download=true",
+ "https://huggingface.co/saddam213/DemoApp/resolve/main/Text/Supertonic/voice_styles/Male4.json?download=true",
+ "https://huggingface.co/saddam213/DemoApp/resolve/main/Text/Supertonic/voice_styles/Male5.json?download=true"
+ ]
}
]
}
\ No newline at end of file
diff --git a/DemoApp/Views/AudioNarrateView.xaml b/DemoApp/Views/AudioNarrateView.xaml
new file mode 100644
index 0000000..a691521
--- /dev/null
+++ b/DemoApp/Views/AudioNarrateView.xaml
@@ -0,0 +1,136 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/DemoApp/Views/AudioNarrateView.xaml.cs b/DemoApp/Views/AudioNarrateView.xaml.cs
new file mode 100644
index 0000000..2784006
--- /dev/null
+++ b/DemoApp/Views/AudioNarrateView.xaml.cs
@@ -0,0 +1,200 @@
+using DemoApp.Common;
+using DemoApp.Services;
+using System;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading.Tasks;
+using TensorStack.Audio;
+using TensorStack.WPF;
+using TensorStack.WPF.Controls;
+using TensorStack.WPF.Services;
+
+namespace DemoApp.Views
+{
+ ///
+ /// Interaction logic for AudioNarrateView.xaml
+ ///
+ public partial class AudioNarrateView : ViewBase
+ {
+ private PipelineModel _currentPipeline;
+ private string _selectedVoice;
+ private AudioInput _audioResult;
+ private int _steps = 10;
+ private float _speed = 1f;
+ private string _inputText;
+ private int _seed;
+
+ public AudioNarrateView(Settings settings, NavigationService navigationService, IHistoryService historyService, INarrateService narrateService)
+ : base(settings, navigationService, historyService)
+ {
+ NarrateService = narrateService;
+ ExecuteCommand = new AsyncRelayCommand(ExecuteAsync, CanExecute);
+ CancelCommand = new AsyncRelayCommand(CancelAsync, CanCancel);
+ Voices = new ObservableCollection();
+ InitializeComponent();
+ }
+
+ public override int Id => (int)View.AudioNarrate;
+ public INarrateService NarrateService { get; }
+ public AsyncRelayCommand ExecuteCommand { get; }
+ public AsyncRelayCommand CancelCommand { get; }
+ public ObservableCollection Voices { get; }
+
+
+ public PipelineModel CurrentPipeline
+ {
+ get { return _currentPipeline; }
+ set { SetProperty(ref _currentPipeline, value); }
+ }
+
+ public string SelectedVoice
+ {
+ get { return _selectedVoice; }
+ set { SetProperty(ref _selectedVoice, value); }
+ }
+
+ public string InputText
+ {
+ get { return _inputText; }
+ set { SetProperty(ref _inputText, value); }
+ }
+
+ public float Speed
+ {
+ get { return _speed; }
+ set { SetProperty(ref _speed, value); }
+ }
+
+ public int Steps
+ {
+ get { return _steps; }
+ set { SetProperty(ref _steps, value); }
+ }
+
+ public int Seed
+ {
+ get { return _seed; }
+ set { SetProperty(ref _seed, value); }
+ }
+
+ public AudioInput AudioResult
+ {
+ get { return _audioResult; }
+ set { SetProperty(ref _audioResult, value); }
+ }
+
+
+ public override Task OpenAsync(OpenViewArgs args = null)
+ {
+ CurrentPipeline = NarrateService.Pipeline;
+ return base.OpenAsync(args);
+ }
+
+
+ private async Task ExecuteAsync()
+ {
+ var timestamp = Stopwatch.GetTimestamp();
+ Progress.Indeterminate("Generating Results...");
+ try
+ {
+ // Generate Result
+ var result = await NarrateService.ExecuteAsync(new NarrateRequest
+ {
+ InputText = _inputText,
+ Speed = _speed,
+ Steps = _steps,
+ Seed = _seed,
+ VoiceStyle = _selectedVoice
+ });
+
+ // Save History
+ var resultAudio = new AudioInput(result);
+ AudioResult = await HistoryService.AddAsync(resultAudio, new NarrateItem
+ {
+ Source = View.AudioNarrate,
+ MediaType = MediaType.Audio,
+ Model = _currentPipeline.NarrateModel.Name,
+ Voice = _selectedVoice,
+ Seed = _seed,
+ Speed = _speed,
+ Steps = _steps,
+ Channels = resultAudio.Channels,
+ SampleRate = resultAudio.SampleRate,
+ Duration = resultAudio.Duration,
+ InputText = _inputText,
+ Timestamp = DateTime.UtcNow
+ });
+
+ Debug.WriteLine($"[{GetType().Name}] [ExecuteAsync] - Complete: {Stopwatch.GetElapsedTime(timestamp)}");
+ }
+ catch (OperationCanceledException)
+ {
+ Debug.WriteLine($"[{GetType().Name}] [ExecuteAsync] - Cancelled: {Stopwatch.GetElapsedTime(timestamp)}");
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"[{GetType().Name}] [ExecuteAsync] - Error: {Stopwatch.GetElapsedTime(timestamp)}");
+ await DialogService.ShowErrorAsync("ExecuteAsync", ex.Message);
+ }
+
+ Progress.Clear();
+ }
+
+
+ private bool CanExecute()
+ {
+ return !string.IsNullOrEmpty(_inputText) && NarrateService.IsLoaded && !NarrateService.IsExecuting;
+ }
+
+
+ private async Task CancelAsync()
+ {
+ await NarrateService.CancelAsync();
+ }
+
+
+ private bool CanCancel()
+ {
+ return NarrateService.CanCancel;
+ }
+
+
+ private async Task LoadPipelineAsync()
+ {
+ if (_currentPipeline?.NarrateModel == null)
+ {
+ await NarrateService.UnloadAsync();
+ return;
+ }
+
+ var timestamp = Stopwatch.GetTimestamp();
+ Progress.Indeterminate();
+
+ await NarrateService.LoadAsync(_currentPipeline);
+ Settings.SetDefault(_currentPipeline.NarrateModel);
+
+ var model = _currentPipeline.NarrateModel;
+
+
+ if (model.Voices != null)
+ {
+ foreach (var prefix in model.Voices)
+ {
+ Voices.Add(prefix);
+ }
+ SelectedVoice = Voices.FirstOrDefault();
+ }
+
+ Progress.Clear();
+ Debug.WriteLine($"[{GetType().Name}] [LoadAsync] - {Stopwatch.GetElapsedTime(timestamp)}");
+ }
+
+
+ protected async void SelectedPipelineChanged(object sender, PipelineModel pipeline)
+ {
+ await LoadPipelineAsync();
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/DemoApp/Views/AudioTranscribeView.xaml b/DemoApp/Views/AudioTranscribeView.xaml
index 618a075..95bda43 100644
--- a/DemoApp/Views/AudioTranscribeView.xaml
+++ b/DemoApp/Views/AudioTranscribeView.xaml
@@ -55,7 +55,9 @@
-
+
+
+
diff --git a/DemoApp/Views/View.cs b/DemoApp/Views/View.cs
index 3307dcd..6261358 100644
--- a/DemoApp/Views/View.cs
+++ b/DemoApp/Views/View.cs
@@ -21,7 +21,7 @@ public enum View
VideoInterpolation = 302,
AudioTranscribe = 400,
-
+ AudioNarrate = 401,
}
@@ -71,7 +71,8 @@ public static class ViewManager
{ View.VideoInterpolation, ViewCategory.Video },
// Audio
- { View.AudioTranscribe, ViewCategory.Audio }
+ { View.AudioTranscribe, ViewCategory.Audio },
+ { View.AudioNarrate, ViewCategory.Audio }
};