| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
-
- namespace Yuuna.Recognition.Speech
- {
- using Google.Apis.Auth.OAuth2;
- using Google.Cloud.Speech.V1;
- using Grpc.Auth;
- using Grpc.Core;
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Threading;
- public sealed class SpeechRecognizer : ISpeechRecognizer
- {
- private readonly SpeechClient _speech;
- private readonly RecognitionConfig _config;
- private readonly IRecorder _recorder;
- private readonly object _lock = new object();
- private volatile bool _started;
- /// <summary>
- /// 建立新 <see cref="ISpeechRecognizer"/> 實體。
- /// </summary>
- /// <param name="secret"></param>
- /// <returns></returns>
- public static ISpeechRecognizer Create(string secret)
- {
- if (string.IsNullOrWhiteSpace(secret))
- throw new ArgumentException("secret is null or empty.", nameof(secret));
- return new SpeechRecognizer(new FileInfo(secret));
- }
- private SpeechRecognizer(FileInfo secret)
- {
- if (secret is null)
- throw new ArgumentNullException(nameof(secret));
- if (!secret.Exists)
- throw new FileNotFoundException("secret file not found.", secret.FullName);
- var credential = GoogleCredential.FromFile(secret.FullName);
- var channel = new Channel(SpeechClient.DefaultEndpoint.Host, credential.ToChannelCredentials());
- this._speech = SpeechClient.Create(channel);
- this._config = new RecognitionConfig
- {
- Encoding = RecognitionConfig.Types.AudioEncoding.Linear16,
- SampleRateHertz = 16_000,
- LanguageCode = Thread.CurrentThread.CurrentCulture.Name,
- };
- this._recorder = new WaveRecorder();
- this._recorder.Completed += this.OnComplete;
- }
- private void OnComplete(Stream stream)
- {
- lock (this._lock)
- {
- var wavStream = RecognitionAudio.FromStream(stream);
- var response = this._speech.Recognize(this._config, wavStream);
- var alternatives =
- from r in response.Results
- from a in r.Alternatives
- select new AlternativeBridge(a) as IAlternative;
- this.RecognizeCompleted?.Invoke(alternatives.ToList());
- }
- }
- public event Action<IReadOnlyList<IAlternative>> RecognizeCompleted;
- public IDisposable Recognize()
- {
- lock (this._lock)
- {
- if (this._started)
- return null;
- this._started = true;
- return new Duration(this._recorder, () =>
- {
- this._started = false;
- });
- }
- }
- }
- }
|