using MeetingAssistant.Transcription; using MeetingAssistant.MeetingNotes; using Microsoft.Extensions.Options; namespace MeetingAssistant.Recording; public sealed class VaultTranscriptStore : ITranscriptStore { private readonly MeetingAssistantOptions options; private readonly ILogger logger; public VaultTranscriptStore(IOptions options, ILogger logger) { this.options = options.Value; this.logger = logger; } public async Task CreateSessionAsync(CancellationToken cancellationToken) { return await CreateSessionAsync(options, DateTimeOffset.Now, cancellationToken); } public async Task CreateSessionAsync( MeetingAssistantOptions options, DateTimeOffset startedAt, CancellationToken cancellationToken) { var folder = VaultPath.Resolve(options.Vault, options.Vault.TranscriptsFolder); Directory.CreateDirectory(folder); var fileName = MeetingArtifactFileNames.Create(startedAt, MeetingArtifactFileNames.Transcript); var path = Path.Combine(folder, fileName); await File.WriteAllTextAsync(path, $"# Meeting Transcript{Environment.NewLine}{Environment.NewLine}", cancellationToken); logger.LogInformation("Created meeting transcript file {TranscriptPath}", path); return new TranscriptSession(path); } public Task AppendLineAsync(TranscriptSession session, string line, CancellationToken cancellationToken) { return AppendToBodyAsync(session.TranscriptPath, line + Environment.NewLine, cancellationToken); } public Task ReplaceLinesAsync( TranscriptSession session, IReadOnlyList replacementLines, CancellationToken cancellationToken) { var existing = File.Exists(session.TranscriptPath) ? File.ReadAllText(session.TranscriptPath) : ""; var (frontmatter, _) = MeetingArtifactFrontmatterRenderer.Split(existing); var body = "# Meeting Transcript" + Environment.NewLine + Environment.NewLine + string.Concat(replacementLines.Select(line => line + Environment.NewLine)); var content = string.IsNullOrWhiteSpace(frontmatter) ? body : "---" + Environment.NewLine + frontmatter + Environment.NewLine + "---" + Environment.NewLine + Environment.NewLine + body; return File.WriteAllTextAsync(session.TranscriptPath, content, cancellationToken); } public async Task UpdateMetadataAsync( TranscriptSession session, MeetingSessionArtifacts artifacts, MeetingNote meetingNote, CancellationToken cancellationToken) { var body = File.Exists(session.TranscriptPath) ? MeetingArtifactFrontmatterRenderer.Split(await File.ReadAllTextAsync(session.TranscriptPath, cancellationToken)).Body : "# Meeting Transcript" + Environment.NewLine + Environment.NewLine; var frontmatter = MeetingArtifactFrontmatterRenderer.Create( artifacts, meetingNote, MeetingArtifactFrontmatterRenderer.DefaultTitle(meetingNote, "Meeting Transcript"), session.TranscriptPath); await File.WriteAllTextAsync( session.TranscriptPath, MeetingArtifactFrontmatterRenderer.Render(frontmatter, body), cancellationToken); } private static async Task AppendToBodyAsync( string path, string text, CancellationToken cancellationToken) { if (!File.Exists(path)) { await File.AppendAllTextAsync(path, text, cancellationToken); return; } var content = await File.ReadAllTextAsync(path, cancellationToken); var (frontmatter, body) = MeetingArtifactFrontmatterRenderer.Split(content); if (string.IsNullOrWhiteSpace(frontmatter)) { await File.AppendAllTextAsync(path, text, cancellationToken); return; } var updated = "---" + Environment.NewLine + frontmatter + Environment.NewLine + "---" + Environment.NewLine + Environment.NewLine + body + text; await File.WriteAllTextAsync(path, updated, cancellationToken); } }