feat(macos): enable meeting integrations

This commit is contained in:
dh
2026-08-06 08:19:26 +02:00
parent 9542c05ea4
commit 2af7933a1b
27 changed files with 1999 additions and 227 deletions
@@ -4,8 +4,6 @@ using MeetingAssistant.Speakers;
using MeetingAssistant.Workflow;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using System.Drawing;
using System.Drawing.Imaging;
#pragma warning disable CA1416
@@ -117,11 +115,7 @@ public sealed class MeetingScreenshotServiceTests
var croppedPath = Assert.Single(Directory.GetFiles(
Path.Combine(Path.GetDirectoryName(fixture.Artifacts.AssistantContextPath)!, "Attachments"),
"*-cropped.png"));
using (var cropped = new Bitmap(croppedPath))
{
Assert.Equal(2, cropped.Width);
Assert.Equal(2, cropped.Height);
}
Assert.Equal((2, 2), PngTestFixture.ReadDimensions(await File.ReadAllBytesAsync(croppedPath)));
var context = await File.ReadAllTextAsync(fixture.Artifacts.AssistantContextPath);
var screenshotIndex = context.IndexOf("![Screenshot 00:00:10]", StringComparison.Ordinal);
@@ -133,6 +127,38 @@ public sealed class MeetingScreenshotServiceTests
Assert.Contains("Shared screen text", context);
}
[Fact]
public async Task CaptureKeepsSuccessfulOcrTextWhenCropperRejectsCoordinates()
{
var fixture = await ScreenshotFixture.CreateAsync(options =>
{
options.Screenshots.Ocr.Enabled = true;
});
var ocr = new CapturingScreenshotOcrClient(
"Readable text survives.",
new ScreenshotCropCoordinates(99, 99, 10, 10));
var service = fixture.CreateService(
new FixedScreenshotCapture(CreatePngBytes(4, 4)),
ocr,
screenshotImageCropper: new RejectingScreenshotImageCropper());
await service.CaptureAsync(
fixture.Artifacts,
DateTimeOffset.Parse("2026-05-26T10:00:00+02:00"),
DateTimeOffset.Parse("2026-05-26T10:00:10+02:00"),
fixture.Options,
CancellationToken.None);
await service.WaitForPendingOcrAsync(
fixture.Artifacts,
TimeSpan.FromSeconds(5),
CancellationToken.None);
var context = await File.ReadAllTextAsync(fixture.Artifacts.AssistantContextPath);
Assert.Contains("Readable text survives.", context);
Assert.DoesNotContain("_OCR failed", context);
Assert.DoesNotContain("![Cropped screenshot]", context);
}
[Fact]
public async Task CaptureAddsOcrAttendeesToMeetingNoteThroughCanonicalizer()
{
@@ -454,7 +480,8 @@ public sealed class MeetingScreenshotServiceTests
IActiveWindowScreenshotCapture capture,
IScreenshotOcrClient ocrClient,
ISpeakerIdentityAttendeeCanonicalizer? attendeeCanonicalizer = null,
IMeetingWorkflowEngine? meetingWorkflowEngine = null)
IMeetingWorkflowEngine? meetingWorkflowEngine = null,
IScreenshotImageCropper? screenshotImageCropper = null)
{
return new MeetingScreenshotService(
capture,
@@ -462,12 +489,28 @@ public sealed class MeetingScreenshotServiceTests
NoteStore,
attendeeCanonicalizer ?? PassthroughSpeakerIdentityAttendeeCanonicalizer.Instance,
ocrClient,
screenshotImageCropper ??
capture as IScreenshotImageCropper ??
new UnavailableScreenshotImageCropper(),
NullLogger<MeetingScreenshotService>.Instance,
meetingWorkflowEngine);
}
}
private sealed class FixedScreenshotCapture : IActiveWindowScreenshotCapture
private sealed class RejectingScreenshotImageCropper : IScreenshotImageCropper
{
public Task<string?> SaveCroppedScreenshotAsync(
string screenshotPath,
ScreenshotCropCoordinates crop,
CancellationToken cancellationToken)
{
throw new InvalidDataException("The crop is outside image bounds.");
}
}
private sealed class FixedScreenshotCapture :
IActiveWindowScreenshotCapture,
IScreenshotImageCropper
{
private readonly byte[] bytes;
@@ -480,6 +523,21 @@ public sealed class MeetingScreenshotServiceTests
{
return Task.FromResult(new ActiveWindowScreenshot(bytes, "Demo Window"));
}
public async Task<string?> SaveCroppedScreenshotAsync(
string screenshotPath,
ScreenshotCropCoordinates crop,
CancellationToken cancellationToken)
{
var croppedPath = Path.Combine(
Path.GetDirectoryName(screenshotPath)!,
$"{Path.GetFileNameWithoutExtension(screenshotPath)}-cropped.png");
await File.WriteAllBytesAsync(
croppedPath,
PngTestFixture.Solid(2, 2),
cancellationToken);
return croppedPath;
}
}
private sealed class CapturingScreenshotOcrClient : IScreenshotOcrClient
@@ -614,15 +672,7 @@ public sealed class MeetingScreenshotServiceTests
private static byte[] CreatePngBytes(int width, int height)
{
using var bitmap = new Bitmap(width, height);
using (var graphics = Graphics.FromImage(bitmap))
{
graphics.Clear(Color.White);
}
using var stream = new MemoryStream();
bitmap.Save(stream, ImageFormat.Png);
return stream.ToArray();
return PngTestFixture.Solid(width, height);
}
private static string ExtractScreenshotOcrId(string context)