Make meeting lifecycle stateful

This commit is contained in:
2026-05-27 12:55:17 +02:00
parent d607b957bb
commit e85274829a
91 changed files with 4076 additions and 479 deletions
@@ -1,29 +1,75 @@
using MeetingAssistant.LaunchProfiles;
using Microsoft.Extensions.Options;
namespace MeetingAssistant.Transcription;
public sealed class ConfiguredSpeechRecognitionPipelineFactory : ISpeechRecognitionPipelineFactory
{
private readonly IServiceProvider services;
private readonly IReadOnlyDictionary<string, ISpeechRecognitionPipelineBuilder> builders;
private readonly MeetingAssistantOptions options;
private readonly ILaunchProfileOptionsProvider? launchProfiles;
public ConfiguredSpeechRecognitionPipelineFactory(
IServiceProvider services,
IEnumerable<ISpeechRecognitionPipelineBuilder> builders,
IOptions<MeetingAssistantOptions> options)
: this(builders, options, launchProfiles: null)
{
}
public ConfiguredSpeechRecognitionPipelineFactory(
IEnumerable<ISpeechRecognitionPipelineBuilder> builders,
IOptions<MeetingAssistantOptions> options,
ILaunchProfileOptionsProvider? launchProfiles)
{
this.services = services;
this.options = options.Value;
this.launchProfiles = launchProfiles;
this.builders = builders
.GroupBy(builder => builder.ProviderName, StringComparer.OrdinalIgnoreCase)
.ToDictionary(
group => group.Key,
group => group.Count() == 1
? group.Single()
: throw new InvalidOperationException(
$"Speech recognition pipeline provider '{group.Key}' is registered more than once."),
StringComparer.OrdinalIgnoreCase);
if (this.builders.Count == 0)
{
throw new InvalidOperationException("No speech recognition pipeline builders are registered.");
}
}
public ISpeechRecognitionPipeline Create()
{
return options.Recording.TranscriptionProvider switch
{
"funasr" => ActivatorUtilities.CreateInstance<FunAsrSpeechRecognitionPipeline>(services),
"whisper-local" => ActivatorUtilities.CreateInstance<WhisperLocalSpeechRecognitionPipeline>(services),
"azure-speech" => ActivatorUtilities.CreateInstance<AzureSpeechRecognitionPipeline>(services),
_ => throw new InvalidOperationException(
$"Unsupported speech recognition pipeline '{options.Recording.TranscriptionProvider}'.")
};
return Create(null);
}
public ISpeechRecognitionPipeline Create(string? launchProfileName)
{
var profileOptions = ResolveOptions(launchProfileName);
if (!builders.TryGetValue(profileOptions.Recording.TranscriptionProvider, out var builder))
{
throw new InvalidOperationException(
$"Unsupported speech recognition pipeline '{profileOptions.Recording.TranscriptionProvider}'.");
}
return builder.Create(profileOptions);
}
private MeetingAssistantOptions ResolveOptions(string? launchProfileName)
{
if (launchProfiles is not null)
{
return launchProfiles.GetRequiredProfile(launchProfileName).Options;
}
if (string.IsNullOrWhiteSpace(launchProfileName) ||
launchProfileName.Equals(ConfigurationLaunchProfileOptionsProvider.DefaultProfileName, StringComparison.OrdinalIgnoreCase))
{
return options;
}
throw new InvalidOperationException(
$"Launch profile '{launchProfileName}' was requested, but no launch profile provider is registered.");
}
}