diff --git a/.idea/.idea.VisionAsist/.idea/avalonia.xml b/.idea/.idea.VisionAsist/.idea/avalonia.xml index 68b7239..7aedc74 100644 --- a/.idea/.idea.VisionAsist/.idea/avalonia.xml +++ b/.idea/.idea.VisionAsist/.idea/avalonia.xml @@ -4,6 +4,7 @@ diff --git a/VisionAsist.sln.DotSettings.user b/VisionAsist.sln.DotSettings.user new file mode 100644 index 0000000..c79a889 --- /dev/null +++ b/VisionAsist.sln.DotSettings.user @@ -0,0 +1,2 @@ + + ForceIncluded \ No newline at end of file diff --git a/VisionAsist/Models/Core.cs b/VisionAsist/Models/Core.cs new file mode 100644 index 0000000..ff50500 --- /dev/null +++ b/VisionAsist/Models/Core.cs @@ -0,0 +1,35 @@ +using System; +using System.Threading.Tasks; +namespace VisionAsist.Models; + +public class Core +{ + public static TrigerCore triger = new(); + public static string TextAsist; + static Core() + { + Console.OutputEncoding = System.Text.Encoding.UTF8; + Console.InputEncoding = System.Text.Encoding.UTF8; + + } + public static void StartListing() + { + // Подписываемся на событие новых слов + triger.OnRecognized += word => + { + Console.OutputEncoding = System.Text.Encoding.UTF8; + Console.InputEncoding = System.Text.Encoding.UTF8; + Console.WriteLine(word); // печатаем сразу, как распознано + TextAsist = triger.RecognizedText; + }; + + // Запускаем запись + triger.StartRecording(); + } + + static public async void StopListing () + { + triger.StopRecording(); + + } +} \ No newline at end of file diff --git a/VisionAsist/Models/Selector.cs b/VisionAsist/Models/Selector.cs new file mode 100644 index 0000000..a0c1651 --- /dev/null +++ b/VisionAsist/Models/Selector.cs @@ -0,0 +1,6 @@ +namespace VisionAsist.Models; + +public class Selector +{ + +} \ No newline at end of file diff --git a/VisionAsist/Models/TrigerCore.cs b/VisionAsist/Models/TrigerCore.cs new file mode 100644 index 0000000..58da054 --- /dev/null +++ b/VisionAsist/Models/TrigerCore.cs @@ -0,0 +1,76 @@ +using System; +using System.IO; +using Vosk; +using System.Text.Json; +using NAudio.Wave; +using Avalonia.Controls; +using Avalonia.Threading; + +namespace VisionAsist.Models; + +public class TrigerCore +{ + + private WaveInEvent? _waveIn; + private Model? _model; + private VoskRecognizer? _rec; + private readonly object _voskLock = new(); + public string RecognizedText { get; private set; } = ""; + + + public TrigerCore() + { + string VoskPath = Path.Combine(AppContext.BaseDirectory, "models/Vosk/"); + if (!Directory.Exists(VoskPath)) + throw new DirectoryNotFoundException($"Модель не найдена по пути: {VoskPath}"); + + _model = new Model(VoskPath); + _rec = new VoskRecognizer(_model, 16000.0f); + + } + + public void StartRecording() + { + if (_waveIn != null || _rec == null) return; + + _waveIn = new WaveInEvent { WaveFormat = new WaveFormat(16000, 1) }; + _waveIn.DataAvailable += OnDataAvailable; + _waveIn.StartRecording(); + } + + + public void StopRecording() + { + _waveIn?.StopRecording(); + _waveIn?.Dispose(); + _waveIn = null; + } + public event Action? OnRecognized; + + private void OnDataAvailable(object? sender, WaveInEventArgs e) + { + lock (_voskLock) + { + if (_rec != null && _rec.AcceptWaveform(e.Buffer, e.BytesRecorded)) + { + var json = _rec.Result(); + using var doc = JsonDocument.Parse(json); + var result = doc.RootElement.GetProperty("text").GetString(); + + if (!string.IsNullOrWhiteSpace(result)) + { + RecognizedText += result + " "; + OnRecognized?.Invoke(result); // уведомляем подписчиков + } + } + } + } + + protected void Stop() + { + StopRecording(); + _rec?.Dispose(); + _model?.Dispose(); + + } +} \ No newline at end of file diff --git a/VisionAsist/Program.cs b/VisionAsist/Program.cs index 724369f..c60ff59 100644 --- a/VisionAsist/Program.cs +++ b/VisionAsist/Program.cs @@ -11,7 +11,7 @@ sealed class Program [STAThread] public static void Main(string[] args) => BuildAvaloniaApp() .StartWithClassicDesktopLifetime(args); - + // Avalonia configuration, don't remove; also used by visual designer. public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() diff --git a/VisionAsist/ViewModels/MainWindowViewModel.cs b/VisionAsist/ViewModels/MainWindowViewModel.cs index 8045d8a..348c556 100644 --- a/VisionAsist/ViewModels/MainWindowViewModel.cs +++ b/VisionAsist/ViewModels/MainWindowViewModel.cs @@ -1,6 +1,45 @@ -namespace VisionAsist.ViewModels; +using System; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using VisionAsist.Models; +namespace VisionAsist.ViewModels; public partial class MainWindowViewModel : ViewModelBase { - public string Greeting { get; } = "Welcome to Avalonia!"; + [ObservableProperty] + private bool isListening; + [ObservableProperty] + private string recognizedtext; + private Action? _coreHandler; + + partial void OnIsListeningChanged(bool value) + { + if (value) + { + Core.StartListing(); + + // Сохраняем ссылку на обработчик + _coreHandler = word => + { + + Avalonia.Threading.Dispatcher.UIThread.Post(() => + { + Recognizedtext = Core.TextAsist; + }); + }; + + Core.triger.OnRecognized += _coreHandler; + } + else + { + Core.StopListing(); + + // Правильная отписка + if (_coreHandler != null) + { + Core.triger.OnRecognized -= _coreHandler; + _coreHandler = null; + } + } + } } \ No newline at end of file diff --git a/VisionAsist/ViewModels/SettingsViewModel.cs b/VisionAsist/ViewModels/SettingsViewModel.cs new file mode 100644 index 0000000..8c5803f --- /dev/null +++ b/VisionAsist/ViewModels/SettingsViewModel.cs @@ -0,0 +1,6 @@ +namespace VisionAsist.ViewModels; + +public class SettingsViewModel : ViewModelBase +{ + +} \ No newline at end of file diff --git a/VisionAsist/ViewModels/ViewModelBase.cs b/VisionAsist/ViewModels/ViewModelBase.cs index 6791e51..e718eca 100644 --- a/VisionAsist/ViewModels/ViewModelBase.cs +++ b/VisionAsist/ViewModels/ViewModelBase.cs @@ -1,7 +1,11 @@ -using CommunityToolkit.Mvvm.ComponentModel; +using System; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; namespace VisionAsist.ViewModels; -public abstract class ViewModelBase : ObservableObject +public partial class ViewModelBase : ObservableObject { + } \ No newline at end of file diff --git a/VisionAsist/Views/MainWindow.axaml b/VisionAsist/Views/MainWindow.axaml index 61252da..f6a3159 100644 --- a/VisionAsist/Views/MainWindow.axaml +++ b/VisionAsist/Views/MainWindow.axaml @@ -7,14 +7,30 @@ x:Class="VisionAsist.Views.MainWindow" x:DataType="vm:MainWindowViewModel" Icon="/Assets/avalonia-logo.ico" - Title="VisionAsist"> + Title="VisionAsist" Height="400" Width="600"> - - + + +