Add meeting assistant speech and summary automation

This commit is contained in:
2026-05-21 09:55:39 +02:00
parent 1e97d2b9ff
commit 48d98d9cbb
63 changed files with 5143 additions and 151 deletions
@@ -8,10 +8,14 @@ namespace MeetingAssistant.Recording;
public sealed class MicrophoneAudioSource : IMeetingAudioSource
{
private readonly MeetingAssistantOptions options;
private readonly ILogger<MicrophoneAudioSource> logger;
public MicrophoneAudioSource(IOptions<MeetingAssistantOptions> options)
public MicrophoneAudioSource(
IOptions<MeetingAssistantOptions> options,
ILogger<MicrophoneAudioSource> logger)
{
this.options = options.Value;
this.logger = logger;
}
public IAsyncEnumerable<AudioChunk> CaptureAsync(CancellationToken cancellationToken)
@@ -22,19 +26,37 @@ public sealed class MicrophoneAudioSource : IMeetingAudioSource
private IAsyncEnumerable<AudioChunk> CaptureAsync(IWaveIn capture, CancellationToken cancellationToken)
{
capture.WaveFormat = new WaveFormat(options.Recording.SampleRate, 16, options.Recording.Channels);
return CaptureWith(capture, cancellationToken);
return CaptureWith(capture, "microphone", logger, cancellationToken);
}
internal static async IAsyncEnumerable<AudioChunk> CaptureWith(
IWaveIn capture,
string sourceName,
ILogger logger,
[System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken)
{
var channel = Channel.CreateUnbounded<AudioChunk>();
var chunks = 0;
capture.DataAvailable += (_, args) =>
{
if (args.BytesRecorded <= 0)
{
return;
}
var buffer = new byte[args.BytesRecorded];
Buffer.BlockCopy(args.Buffer, 0, buffer, 0, args.BytesRecorded);
if (Interlocked.Increment(ref chunks) == 1)
{
logger.LogInformation(
"Audio capture source {SourceName} produced first chunk: {ByteCount} bytes at {SampleRate} Hz/{Channels} channel(s)",
sourceName,
args.BytesRecorded,
capture.WaveFormat.SampleRate,
capture.WaveFormat.Channels);
}
channel.Writer.TryWrite(new AudioChunk(buffer, capture.WaveFormat.SampleRate, capture.WaveFormat.Channels));
};
capture.RecordingStopped += (_, args) =>
@@ -51,6 +73,11 @@ public sealed class MicrophoneAudioSource : IMeetingAudioSource
try
{
using var registration = cancellationToken.Register(capture.StopRecording);
logger.LogInformation(
"Starting audio capture source {SourceName} at {SampleRate} Hz/{Channels} channel(s)",
sourceName,
capture.WaveFormat.SampleRate,
capture.WaveFormat.Channels);
capture.StartRecording();
await foreach (var chunk in channel.Reader.ReadAllAsync(cancellationToken))
@@ -68,10 +95,14 @@ public sealed class MicrophoneAudioSource : IMeetingAudioSource
public sealed class SystemAudioSource : IMeetingAudioSource
{
private readonly MeetingAssistantOptions options;
private readonly ILogger<SystemAudioSource> logger;
public SystemAudioSource(IOptions<MeetingAssistantOptions> options)
public SystemAudioSource(
IOptions<MeetingAssistantOptions> options,
ILogger<SystemAudioSource> logger)
{
this.options = options.Value;
this.logger = logger;
}
public IAsyncEnumerable<AudioChunk> CaptureAsync(CancellationToken cancellationToken)
@@ -81,6 +112,6 @@ public sealed class SystemAudioSource : IMeetingAudioSource
WaveFormat = new WaveFormat(options.Recording.SampleRate, 16, options.Recording.Channels)
};
return MicrophoneAudioSource.CaptureWith(capture, cancellationToken);
return MicrophoneAudioSource.CaptureWith(capture, "system", logger, cancellationToken);
}
}