From 7c5c994397d4914b7a4f253a652982ec33a0544d Mon Sep 17 00:00:00 2001 From: Gille <4317663+helix4u@users.noreply.github.com> Date: Tue, 25 Aug 2026 01:54:20 -0600 Subject: [PATCH] fix(teams): request supported transcript content format --- plugins/teams_pipeline/meetings.py | 7 ++- tests/plugins/test_teams_pipeline_meetings.py | 46 ++++++++++++++++++- tests/tools/test_microsoft_graph_client.py | 24 ++++++++++ tools/microsoft_graph_client.py | 2 +- 4 files changed, 75 insertions(+), 4 deletions(-) diff --git a/plugins/teams_pipeline/meetings.py b/plugins/teams_pipeline/meetings.py index d7236dea22..c6f6ec3d9c 100644 --- a/plugins/teams_pipeline/meetings.py +++ b/plugins/teams_pipeline/meetings.py @@ -334,7 +334,12 @@ async def download_transcript_text( with tempfile.NamedTemporaryFile(prefix="teams-transcript-", suffix=suffix, delete=False) as handle: destination = Path(handle.name) try: - await client.download_to_file(_transcript_download_path(meeting_ref, transcript), destination) + # Graph's transcript /content endpoint rejects JSON content negotiation. + await client.download_to_file( + _transcript_download_path(meeting_ref, transcript), + destination, + headers={"Accept": "text/vtt"}, + ) text = destination.read_text(encoding=encoding).strip() except MicrosoftGraphAPIError as exc: raise _wrap_graph_error( diff --git a/tests/plugins/test_teams_pipeline_meetings.py b/tests/plugins/test_teams_pipeline_meetings.py index 20760fbc45..4199f4cf1c 100644 --- a/tests/plugins/test_teams_pipeline_meetings.py +++ b/tests/plugins/test_teams_pipeline_meetings.py @@ -1,8 +1,14 @@ from __future__ import annotations +from pathlib import Path + import pytest -from plugins.teams_pipeline.meetings import resolve_meeting_reference +from plugins.teams_pipeline.meetings import ( + download_transcript_text, + resolve_meeting_reference, +) +from plugins.teams_pipeline.models import MeetingArtifact, TeamsMeetingRef class FakeGraphClient: @@ -32,4 +38,40 @@ async def test_join_url_can_use_organizer_scoped_graph_lookup(): "/users/organizer-1/onlineMeetings", {"$filter": "JoinWebUrl eq 'https://teams.microsoft.com/meet/code'"}, ) - ] \ No newline at end of file + ] + + +@pytest.mark.anyio +async def test_transcript_download_requests_graph_vtt_content(): + class FakeDownloadClient: + def __init__(self): + self.calls = [] + + async def download_to_file(self, path, destination, *, headers=None): + self.calls.append((path, headers)) + Path(destination).write_text( + "WEBVTT\n\n00:00:00.000 --> 00:00:01.000\nHello\n", + encoding="utf-8", + ) + return {"content_type": "text/vtt"} + + client = FakeDownloadClient() + meeting = TeamsMeetingRef( + meeting_id="meeting-1", + organizer_user_id="organizer-1", + ) + transcript = MeetingArtifact( + artifact_type="transcript", + artifact_id="transcript-1", + display_name="transcript.vtt", + ) + + text = await download_transcript_text(client, meeting, transcript) + + assert text.startswith("WEBVTT") + assert client.calls == [ + ( + "/users/organizer-1/onlineMeetings/meeting-1/transcripts/transcript-1/content", + {"Accept": "text/vtt"}, + ) + ] diff --git a/tests/tools/test_microsoft_graph_client.py b/tests/tools/test_microsoft_graph_client.py index 6aa5b1dfa8..e053eab744 100644 --- a/tests/tools/test_microsoft_graph_client.py +++ b/tests/tools/test_microsoft_graph_client.py @@ -76,6 +76,30 @@ class TestMicrosoftGraphClient: assert len(calls) == 2 assert sleeps == [3.0] + async def test_download_accepts_stream_content_by_default(self, tmp_path: Path): + captured_accept: list[str] = [] + + def handler(request: httpx.Request) -> httpx.Response: + captured_accept.append(request.headers["Accept"]) + return httpx.Response( + 200, + content=b"recording-bytes", + headers={"content-type": "video/mp4"}, + ) + + client = MicrosoftGraphClient( + _make_provider(), + transport=httpx.MockTransport(handler), + ) + destination = tmp_path / "recording.mp4" + + result = await client.download_to_file( + "/recordings/recording-1/content", destination + ) + + assert captured_accept == ["*/*"] + assert destination.read_bytes() == b"recording-bytes" + assert result["content_type"] == "video/mp4" async def test_invalid_json_response_raises_client_error(self): def handler(request: httpx.Request) -> httpx.Response: diff --git a/tools/microsoft_graph_client.py b/tools/microsoft_graph_client.py index a6d1a4be15..60831801bf 100644 --- a/tools/microsoft_graph_client.py +++ b/tools/microsoft_graph_client.py @@ -181,7 +181,7 @@ class MicrosoftGraphClient: ) request_headers = { "Authorization": f"Bearer {token}", - "Accept": "application/json", + "Accept": "*/*", "User-Agent": self.user_agent, } if headers: