chore: import upstream snapshot with attribution
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:39:25 +08:00
commit db620d33df
5151 changed files with 925932 additions and 0 deletions
@@ -0,0 +1,106 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
import asyncio
import json
from pathlib import Path
from typing import Any
from unittest.mock import AsyncMock, MagicMock
import pytest
from azure.ai.contentunderstanding.models import AnalysisResult
FIXTURES_DIR = Path(__file__).parent / "fixtures"
def _load_fixture(name: str) -> dict[str, Any]:
return json.loads((FIXTURES_DIR / name).read_text()) # type: ignore[no-any-return]
@pytest.fixture
def pdf_fixture_raw() -> dict[str, Any]:
return _load_fixture("analyze_pdf_result.json")
@pytest.fixture
def pdf_analysis_result(pdf_fixture_raw: dict[str, Any]) -> AnalysisResult:
return AnalysisResult(pdf_fixture_raw)
@pytest.fixture
def audio_fixture_raw() -> dict[str, Any]:
return _load_fixture("analyze_audio_result.json")
@pytest.fixture
def audio_analysis_result(audio_fixture_raw: dict[str, Any]) -> AnalysisResult:
return AnalysisResult(audio_fixture_raw)
@pytest.fixture
def invoice_fixture_raw() -> dict[str, Any]:
return _load_fixture("analyze_invoice_result.json")
@pytest.fixture
def invoice_analysis_result(invoice_fixture_raw: dict[str, Any]) -> AnalysisResult:
return AnalysisResult(invoice_fixture_raw)
@pytest.fixture
def video_fixture_raw() -> dict[str, Any]:
return _load_fixture("analyze_video_result.json")
@pytest.fixture
def video_analysis_result(video_fixture_raw: dict[str, Any]) -> AnalysisResult:
return AnalysisResult(video_fixture_raw)
@pytest.fixture
def image_fixture_raw() -> dict[str, Any]:
return _load_fixture("analyze_image_result.json")
@pytest.fixture
def image_analysis_result(image_fixture_raw: dict[str, Any]) -> AnalysisResult:
return AnalysisResult(image_fixture_raw)
@pytest.fixture
def mock_cu_client() -> AsyncMock:
"""Create a mock ContentUnderstandingClient."""
client = AsyncMock()
client.close = AsyncMock()
return client
def make_mock_poller(result: AnalysisResult) -> AsyncMock:
"""Create a mock poller that returns the given result immediately."""
poller = AsyncMock()
poller.result = AsyncMock(return_value=result)
poller.continuation_token = MagicMock(return_value="mock_continuation_token")
poller.done = MagicMock(return_value=True)
return poller
def make_slow_poller(result: AnalysisResult, delay: float = 10.0) -> MagicMock:
"""Create a mock poller that simulates a timeout then eventually returns."""
poller = MagicMock()
async def slow_result() -> AnalysisResult:
await asyncio.sleep(delay)
return result
poller.result = slow_result
poller.continuation_token = MagicMock(return_value="mock_slow_continuation_token")
poller.done = MagicMock(return_value=False)
return poller
def make_failing_poller(error: Exception) -> AsyncMock:
"""Create a mock poller that raises an exception."""
poller = AsyncMock()
poller.result = AsyncMock(side_effect=error)
return poller
@@ -0,0 +1,13 @@
{
"id": "synthetic-audio-001",
"status": "Succeeded",
"analyzer_id": "prebuilt-audioSearch",
"api_version": "2025-05-01-preview",
"created_at": "2026-03-21T10:05:00Z",
"contents": [
{
"markdown": "## Call Center Recording\n\n**Duration:** 2 minutes 15 seconds\n**Speakers:** 2\n\n### Transcript\n\n**Speaker 1 (Agent):** Thank you for calling Contoso support. My name is Sarah. How can I help you today?\n\n**Speaker 2 (Customer):** Hi Sarah, I'm calling about my recent order number ORD-5678. It was supposed to arrive yesterday but I haven't received it.\n\n**Speaker 1 (Agent):** I'm sorry to hear that. Let me look up your order. Can you confirm your name and email address?\n\n**Speaker 2 (Customer):** Sure, it's John Smith, john.smith@example.com.\n\n**Speaker 1 (Agent):** Thank you, John. I can see your order was shipped on March 18th. It looks like there was a delay with the carrier. The updated delivery estimate is March 22nd.\n\n**Speaker 2 (Customer):** That's helpful, thank you. Is there anything I can do to track it?\n\n**Speaker 1 (Agent):** Yes, I'll send you a tracking link to your email right away. Is there anything else I can help with?\n\n**Speaker 2 (Customer):** No, that's all. Thanks for your help.\n\n**Speaker 1 (Agent):** You're welcome! Have a great day.",
"fields": {}
}
]
}
@@ -0,0 +1,857 @@
{
"analyzerId": "prebuilt-documentSearch",
"apiVersion": "2025-11-01",
"createdAt": "2026-03-21T22:44:21Z",
"stringEncoding": "codePoint",
"warnings": [],
"contents": [
{
"path": "input1",
"markdown": "# Contoso Q1 2025 Financial Summary\n\nTotal revenue for Q1 2025 was $42.7 million, an increase of 18% over Q1 2024.\nOperating expenses were $31.2 million. Net profit was $11.5 million. The largest\nrevenue segment was Cloud Services at $19.3 million, followed by Professional\nServices at $14.8 million and Product Licensing at $8.6 million. Headcount at end of\nQ1 was 1,247 employees across 8 offices worldwide.\n",
"fields": {
"Summary": {
"type": "string",
"valueString": "The document provides a financial summary for Contoso in Q1 2025, reporting total revenue of $42.7 million, an 18% increase from Q1 2024. Operating expenses were $31.2 million, resulting in a net profit of $11.5 million. The largest revenue segment was Cloud Services with $19.3 million, followed by Professional Services at $14.8 million and Product Licensing at $8.6 million. The company had 1,247 employees across 8 offices worldwide at the end of Q1.",
"spans": [
{
"offset": 37,
"length": 77
},
{
"offset": 115,
"length": 80
},
{
"offset": 196,
"length": 77
},
{
"offset": 274,
"length": 84
},
{
"offset": 359,
"length": 50
}
],
"confidence": 0.592,
"source": "D(1,212.0000,334.0000,1394.0000,334.0000,1394.0000,374.0000,212.0000,374.0000);D(1,213.0000,379.0000,1398.0000,379.0000,1398.0000,422.0000,213.0000,422.0000);D(1,212.0000,423.0000,1389.0000,423.0000,1389.0000,464.0000,212.0000,464.0000);D(1,213.0000,468.0000,1453.0000,468.0000,1453.0000,510.0000,213.0000,510.0000);D(1,213.0000,512.0000,1000.0000,512.0000,1000.0000,554.0000,213.0000,554.0000)"
}
},
"kind": "document",
"startPageNumber": 1,
"endPageNumber": 1,
"unit": "pixel",
"pages": [
{
"pageNumber": 1,
"angle": -0.0242,
"width": 1700,
"height": 2200,
"spans": [
{
"offset": 0,
"length": 410
}
],
"words": [
{
"content": "Contoso",
"span": {
"offset": 2,
"length": 7
},
"confidence": 0.99,
"source": "D(1,214,222,401,222,401,274,214,273)"
},
{
"content": "Q1",
"span": {
"offset": 10,
"length": 2
},
"confidence": 0.957,
"source": "D(1,414,222,473,222,473,275,414,274)"
},
{
"content": "2025",
"span": {
"offset": 13,
"length": 4
},
"confidence": 0.929,
"source": "D(1,494,222,607,222,607,276,494,275)"
},
{
"content": "Financial",
"span": {
"offset": 18,
"length": 9
},
"confidence": 0.975,
"source": "D(1,624,222,819,223,819,277,624,276)"
},
{
"content": "Summary",
"span": {
"offset": 28,
"length": 7
},
"confidence": 0.991,
"source": "D(1,836,223,1050,225,1050,279,836,277)"
},
{
"content": "Total",
"span": {
"offset": 37,
"length": 5
},
"confidence": 0.996,
"source": "D(1,212,335,287,334,288,374,212,373)"
},
{
"content": "revenue",
"span": {
"offset": 43,
"length": 7
},
"confidence": 0.994,
"source": "D(1,299,334,417,334,418,374,299,374)"
},
{
"content": "for",
"span": {
"offset": 51,
"length": 3
},
"confidence": 0.994,
"source": "D(1,427,334,467,334,467,374,427,374)"
},
{
"content": "Q1",
"span": {
"offset": 55,
"length": 2
},
"confidence": 0.944,
"source": "D(1,475,334,515,334,515,374,475,374)"
},
{
"content": "2025",
"span": {
"offset": 58,
"length": 4
},
"confidence": 0.876,
"source": "D(1,528,334,604,334,604,374,529,374)"
},
{
"content": "was",
"span": {
"offset": 63,
"length": 3
},
"confidence": 0.991,
"source": "D(1,613,334,672,334,672,374,613,374)"
},
{
"content": "$",
"span": {
"offset": 67,
"length": 1
},
"confidence": 0.999,
"source": "D(1,681,334,698,334,698,374,681,374)"
},
{
"content": "42.7",
"span": {
"offset": 68,
"length": 4
},
"confidence": 0.946,
"source": "D(1,700,334,765,334,765,374,700,374)"
},
{
"content": "million",
"span": {
"offset": 73,
"length": 7
},
"confidence": 0.977,
"source": "D(1,775,334,867,334,867,374,776,374)"
},
{
"content": ",",
"span": {
"offset": 80,
"length": 1
},
"confidence": 0.998,
"source": "D(1,870,334,877,334,877,374,870,374)"
},
{
"content": "an",
"span": {
"offset": 82,
"length": 2
},
"confidence": 0.998,
"source": "D(1,888,334,922,334,922,374,888,374)"
},
{
"content": "increase",
"span": {
"offset": 85,
"length": 8
},
"confidence": 0.991,
"source": "D(1,934,334,1058,335,1059,374,934,374)"
},
{
"content": "of",
"span": {
"offset": 94,
"length": 2
},
"confidence": 0.982,
"source": "D(1,1069,335,1098,335,1098,374,1069,374)"
},
{
"content": "18",
"span": {
"offset": 97,
"length": 2
},
"confidence": 0.963,
"source": "D(1,1108,335,1142,335,1142,374,1108,374)"
},
{
"content": "%",
"span": {
"offset": 99,
"length": 1
},
"confidence": 0.998,
"source": "D(1,1143,335,1171,335,1171,374,1143,374)"
},
{
"content": "over",
"span": {
"offset": 101,
"length": 4
},
"confidence": 0.946,
"source": "D(1,1181,335,1248,335,1248,374,1181,374)"
},
{
"content": "Q1",
"span": {
"offset": 106,
"length": 2
},
"confidence": 0.875,
"source": "D(1,1256,335,1295,335,1295,374,1256,374)"
},
{
"content": "2024",
"span": {
"offset": 109,
"length": 4
},
"confidence": 0.683,
"source": "D(1,1310,335,1384,335,1384,374,1310,374)"
},
{
"content": ".",
"span": {
"offset": 113,
"length": 1
},
"confidence": 0.991,
"source": "D(1,1385,335,1394,335,1394,374,1385,374)"
},
{
"content": "Operating",
"span": {
"offset": 115,
"length": 9
},
"confidence": 0.996,
"source": "D(1,213,380,358,380,358,422,213,422)"
},
{
"content": "expenses",
"span": {
"offset": 125,
"length": 8
},
"confidence": 0.997,
"source": "D(1,369,380,513,379,513,421,369,421)"
},
{
"content": "were",
"span": {
"offset": 134,
"length": 4
},
"confidence": 0.998,
"source": "D(1,521,379,595,379,595,421,521,421)"
},
{
"content": "$",
"span": {
"offset": 139,
"length": 1
},
"confidence": 0.999,
"source": "D(1,603,379,620,379,620,421,603,421)"
},
{
"content": "31.2",
"span": {
"offset": 140,
"length": 4
},
"confidence": 0.938,
"source": "D(1,623,379,686,379,686,421,623,421)"
},
{
"content": "million",
"span": {
"offset": 145,
"length": 7
},
"confidence": 0.913,
"source": "D(1,696,379,790,379,790,421,696,421)"
},
{
"content": ".",
"span": {
"offset": 152,
"length": 1
},
"confidence": 0.975,
"source": "D(1,793,379,800,379,800,421,793,421)"
},
{
"content": "Net",
"span": {
"offset": 154,
"length": 3
},
"confidence": 0.976,
"source": "D(1,811,379,862,379,862,420,811,421)"
},
{
"content": "profit",
"span": {
"offset": 158,
"length": 6
},
"confidence": 0.993,
"source": "D(1,871,379,947,379,947,420,871,420)"
},
{
"content": "was",
"span": {
"offset": 165,
"length": 3
},
"confidence": 0.997,
"source": "D(1,954,379,1012,379,1012,420,953,420)"
},
{
"content": "$",
"span": {
"offset": 169,
"length": 1
},
"confidence": 0.998,
"source": "D(1,1021,379,1039,379,1039,420,1021,420)"
},
{
"content": "11.5",
"span": {
"offset": 170,
"length": 4
},
"confidence": 0.954,
"source": "D(1,1043,379,1106,379,1106,421,1043,420)"
},
{
"content": "million",
"span": {
"offset": 175,
"length": 7
},
"confidence": 0.837,
"source": "D(1,1118,379,1208,379,1208,421,1118,421)"
},
{
"content": ".",
"span": {
"offset": 182,
"length": 1
},
"confidence": 0.978,
"source": "D(1,1210,379,1217,379,1217,421,1210,421)"
},
{
"content": "The",
"span": {
"offset": 184,
"length": 3
},
"confidence": 0.949,
"source": "D(1,1228,379,1285,379,1285,421,1228,421)"
},
{
"content": "largest",
"span": {
"offset": 188,
"length": 7
},
"confidence": 0.978,
"source": "D(1,1295,379,1398,379,1398,421,1295,421)"
},
{
"content": "revenue",
"span": {
"offset": 196,
"length": 7
},
"confidence": 0.995,
"source": "D(1,212,425,334,425,334,464,212,464)"
},
{
"content": "segment",
"span": {
"offset": 204,
"length": 7
},
"confidence": 0.996,
"source": "D(1,344,425,472,424,472,464,344,464)"
},
{
"content": "was",
"span": {
"offset": 212,
"length": 3
},
"confidence": 0.998,
"source": "D(1,480,424,541,424,541,464,480,464)"
},
{
"content": "Cloud",
"span": {
"offset": 216,
"length": 5
},
"confidence": 0.997,
"source": "D(1,550,424,636,424,637,464,551,464)"
},
{
"content": "Services",
"span": {
"offset": 222,
"length": 8
},
"confidence": 0.995,
"source": "D(1,647,424,774,424,774,464,647,464)"
},
{
"content": "at",
"span": {
"offset": 231,
"length": 2
},
"confidence": 0.996,
"source": "D(1,784,424,812,424,812,464,784,464)"
},
{
"content": "$",
"span": {
"offset": 234,
"length": 1
},
"confidence": 0.998,
"source": "D(1,820,424,837,424,837,464,820,464)"
},
{
"content": "19.3",
"span": {
"offset": 235,
"length": 4
},
"confidence": 0.879,
"source": "D(1,840,424,903,423,903,463,840,464)"
},
{
"content": "million",
"span": {
"offset": 240,
"length": 7
},
"confidence": 0.876,
"source": "D(1,915,423,1006,423,1006,463,915,463)"
},
{
"content": ",",
"span": {
"offset": 247,
"length": 1
},
"confidence": 0.999,
"source": "D(1,1008,423,1015,423,1015,463,1008,463)"
},
{
"content": "followed",
"span": {
"offset": 249,
"length": 8
},
"confidence": 0.978,
"source": "D(1,1026,423,1148,424,1148,463,1026,463)"
},
{
"content": "by",
"span": {
"offset": 258,
"length": 2
},
"confidence": 0.986,
"source": "D(1,1160,424,1194,424,1194,463,1160,463)"
},
{
"content": "Professional",
"span": {
"offset": 261,
"length": 12
},
"confidence": 0.965,
"source": "D(1,1204,424,1389,424,1389,463,1204,463)"
},
{
"content": "Services",
"span": {
"offset": 274,
"length": 8
},
"confidence": 0.991,
"source": "D(1,213,469,341,469,341,510,213,510)"
},
{
"content": "at",
"span": {
"offset": 283,
"length": 2
},
"confidence": 0.997,
"source": "D(1,352,469,380,469,380,510,352,510)"
},
{
"content": "$",
"span": {
"offset": 286,
"length": 1
},
"confidence": 0.998,
"source": "D(1,388,469,405,469,405,510,388,510)"
},
{
"content": "14.8",
"span": {
"offset": 287,
"length": 4
},
"confidence": 0.973,
"source": "D(1,410,469,472,469,472,510,410,510)"
},
{
"content": "million",
"span": {
"offset": 292,
"length": 7
},
"confidence": 0.987,
"source": "D(1,483,469,575,469,575,510,483,510)"
},
{
"content": "and",
"span": {
"offset": 300,
"length": 3
},
"confidence": 0.999,
"source": "D(1,585,469,638,469,638,510,585,510)"
},
{
"content": "Product",
"span": {
"offset": 304,
"length": 7
},
"confidence": 0.995,
"source": "D(1,652,469,765,469,765,510,652,510)"
},
{
"content": "Licensing",
"span": {
"offset": 312,
"length": 9
},
"confidence": 0.993,
"source": "D(1,777,469,914,469,914,510,777,510)"
},
{
"content": "at",
"span": {
"offset": 322,
"length": 2
},
"confidence": 0.998,
"source": "D(1,925,469,953,469,953,510,925,510)"
},
{
"content": "$",
"span": {
"offset": 325,
"length": 1
},
"confidence": 0.998,
"source": "D(1,961,469,978,469,978,510,961,510)"
},
{
"content": "8.6",
"span": {
"offset": 326,
"length": 3
},
"confidence": 0.958,
"source": "D(1,980,469,1025,469,1025,510,980,510)"
},
{
"content": "million",
"span": {
"offset": 330,
"length": 7
},
"confidence": 0.908,
"source": "D(1,1036,469,1128,468,1128,510,1036,510)"
},
{
"content": ".",
"span": {
"offset": 337,
"length": 1
},
"confidence": 0.987,
"source": "D(1,1130,468,1137,468,1137,510,1130,510)"
},
{
"content": "Headcount",
"span": {
"offset": 339,
"length": 9
},
"confidence": 0.934,
"source": "D(1,1150,468,1310,468,1310,510,1150,510)"
},
{
"content": "at",
"span": {
"offset": 349,
"length": 2
},
"confidence": 0.993,
"source": "D(1,1318,468,1348,468,1348,510,1318,510)"
},
{
"content": "end",
"span": {
"offset": 352,
"length": 3
},
"confidence": 0.947,
"source": "D(1,1355,468,1410,468,1410,510,1355,510)"
},
{
"content": "of",
"span": {
"offset": 356,
"length": 2
},
"confidence": 0.974,
"source": "D(1,1419,468,1453,468,1453,509,1419,509)"
},
{
"content": "Q1",
"span": {
"offset": 359,
"length": 2
},
"confidence": 0.931,
"source": "D(1,213,512,252,512,252,554,213,554)"
},
{
"content": "was",
"span": {
"offset": 362,
"length": 3
},
"confidence": 0.847,
"source": "D(1,267,512,326,512,326,554,267,554)"
},
{
"content": "1,247",
"span": {
"offset": 366,
"length": 5
},
"confidence": 0.523,
"source": "D(1,338,512,419,512,419,554,338,554)"
},
{
"content": "employees",
"span": {
"offset": 372,
"length": 9
},
"confidence": 0.972,
"source": "D(1,429,513,591,512,591,554,429,554)"
},
{
"content": "across",
"span": {
"offset": 382,
"length": 6
},
"confidence": 0.972,
"source": "D(1,601,512,697,512,697,554,601,554)"
},
{
"content": "8",
"span": {
"offset": 389,
"length": 1
},
"confidence": 0.946,
"source": "D(1,708,512,725,512,725,553,708,554)"
},
{
"content": "offices",
"span": {
"offset": 391,
"length": 7
},
"confidence": 0.95,
"source": "D(1,736,512,831,512,831,553,736,553)"
},
{
"content": "worldwide",
"span": {
"offset": 399,
"length": 9
},
"confidence": 0.988,
"source": "D(1,840,512,989,512,989,552,840,553)"
},
{
"content": ".",
"span": {
"offset": 408,
"length": 1
},
"confidence": 0.996,
"source": "D(1,991,512,1000,512,1000,552,991,552)"
}
],
"lines": [
{
"content": "Contoso Q1 2025 Financial Summary",
"source": "D(1,214,221,1050,225,1050,279,213,273)",
"span": {
"offset": 2,
"length": 33
}
},
{
"content": "Total revenue for Q1 2025 was $42.7 million, an increase of 18% over Q1 2024.",
"source": "D(1,212,334,1394,335,1394,374,212,374)",
"span": {
"offset": 37,
"length": 77
}
},
{
"content": "Operating expenses were $31.2 million. Net profit was $11.5 million. The largest",
"source": "D(1,213,379,1398,378,1398,421,213,422)",
"span": {
"offset": 115,
"length": 80
}
},
{
"content": "revenue segment was Cloud Services at $19.3 million, followed by Professional",
"source": "D(1,212,424,1389,423,1389,463,212,464)",
"span": {
"offset": 196,
"length": 77
}
},
{
"content": "Services at $14.8 million and Product Licensing at $8.6 million. Headcount at end of",
"source": "D(1,213,469,1453,468,1453,510,213,511)",
"span": {
"offset": 274,
"length": 84
}
},
{
"content": "Q1 was 1,247 employees across 8 offices worldwide.",
"source": "D(1,213,512,1000,512,1000,554,213,554)",
"span": {
"offset": 359,
"length": 50
}
}
]
}
],
"paragraphs": [
{
"role": "title",
"content": "Contoso Q1 2025 Financial Summary",
"source": "D(1,214,219,1050,225,1050,279,213,273)",
"span": {
"offset": 0,
"length": 35
}
},
{
"content": "Total revenue for Q1 2025 was $42.7 million, an increase of 18% over Q1 2024. Operating expenses were $31.2 million. Net profit was $11.5 million. The largest revenue segment was Cloud Services at $19.3 million, followed by Professional Services at $14.8 million and Product Licensing at $8.6 million. Headcount at end of Q1 was 1,247 employees across 8 offices worldwide.",
"source": "D(1,212,334,1453,333,1454,553,212,554)",
"span": {
"offset": 37,
"length": 372
}
}
],
"sections": [
{
"span": {
"offset": 0,
"length": 409
},
"elements": [
"/paragraphs/0",
"/paragraphs/1"
]
}
],
"analyzerId": "prebuilt-documentSearch",
"mimeType": "image/png"
}
]
}
@@ -0,0 +1,114 @@
{
"analyzerId": "prebuilt-invoice",
"apiVersion": "2025-11-01",
"createdAt": "2026-03-21T22:44:33Z",
"stringEncoding": "codePoint",
"warnings": [],
"contents": [
{
"markdown": "# Master Services Agreement\n\nClient: Alpine Industries Inc.\n\nContract Reference: MSA-2025-ALP-00847\n\nEffective Date: January 15, 2025\nPrepared for: Robert Chen, Chief Executive Officer, Alpine Industries Inc.\n\nAddress: 742 Evergreen Blvd, Denver, CO 80203\n\nThis Master Services Agreement (the 'Agreement') is entered into by and between Alpine Industries\nInc. (the 'Client') and TechServe Global Partners (the 'Provider'). This agreement governs the provision\nof managed technology services as descri",
"fields": {
"VendorName": {
"type": "string",
"valueString": "TechServe Global Partners",
"confidence": 0.71
},
"DueDate": {
"type": "date",
"valueDate": "2025-02-15",
"confidence": 0.793
},
"InvoiceDate": {
"type": "date",
"valueDate": "2025-01-15",
"confidence": 0.693
},
"InvoiceId": {
"type": "string",
"valueString": "INV-100",
"confidence": 0.489
},
"AmountDue": {
"type": "object",
"valueObject": {
"Amount": {
"type": "number",
"valueNumber": 610,
"confidence": 0.758
},
"CurrencyCode": {
"type": "string",
"valueString": "USD"
}
}
},
"SubtotalAmount": {
"type": "object",
"valueObject": {
"Amount": {
"type": "number",
"valueNumber": 100,
"confidence": 0.902
},
"CurrencyCode": {
"type": "string",
"valueString": "USD"
}
}
},
"LineItems": {
"type": "array",
"valueArray": [
{
"type": "object",
"valueObject": {
"Description": {
"type": "string",
"valueString": "Consulting Services",
"confidence": 0.664
},
"Quantity": {
"type": "number",
"valueNumber": 2,
"confidence": 0.957
},
"UnitPrice": {
"type": "object",
"valueObject": {
"Amount": {
"type": "number",
"valueNumber": 30,
"confidence": 0.956
},
"CurrencyCode": {
"type": "string",
"valueString": "USD"
}
}
}
}
},
{
"type": "object",
"valueObject": {
"Description": {
"type": "string",
"valueString": "Document Fee",
"confidence": 0.712
},
"Quantity": {
"type": "number",
"valueNumber": 3,
"confidence": 0.939
}
}
}
]
}
},
"kind": "document",
"startPageNumber": 1,
"endPageNumber": 100
}
]
}
@@ -0,0 +1,23 @@
{
"analyzerId": "prebuilt-documentSearch",
"apiVersion": "2025-11-01",
"createdAt": "2026-03-21T22:44:09Z",
"contents": [
{
"path": "input1",
"markdown": "# Contoso Q1 2025 Financial Summary\n\nTotal revenue for Q1 2025 was $42.7 million, an increase of 18% over Q1 2024.\nOperating expenses were $31.2 million. Net profit was $11.5 million. The largest\nrevenue segment was Cloud Services at $19.3 million, followed by Professional\nServices at $14.8 million and Product Licensing at $8.6 million. Headcount at end of\nQ1 was 1,247 employees across 8 offices worldwide.\n\n<!-- PageBreak -->\n\n\n# Contoso Q2 2025 Financial Summary\n\nTotal revenue for Q2 2025 was $48.1 million, an increase of 22% over Q2 2024.\nOperating expenses were $33.9 million. Net profit was $14.2 million. Cloud Services\ngrew to $22.5 million, Professional Services was $15.7 million, and Product Licensing\nwas $9.9 million. The company opened a new office in Tokyo, bringing the total to 9\noffices. Headcount grew to 1,389 employees.\n\n<!-- PageBreak -->\n\n\n## Contoso Product Roadmap 2025\n\nThree major product launches are planned for 2025: (1) Contoso CloudVault - an\nenterprise document storage solution, launching August 2025, with an expected price\nof $29.99/user/month. (2) Contoso DataPulse - a real-time analytics dashboard,\nlaunching October 2025. (3) Contoso SecureLink - a zero-trust networking product,\nlaunching December 2025. Total R&D; budget for 2025 is $18.4 million.\n\n<!-- PageBreak -->\n\n\n# Contoso Employee Satisfaction Survey Results\n\nThe annual employee satisfaction survey was completed in March 2025 with a 87%\nresponse rate. Overall satisfaction score was 4.2 out of 5.0. Work-life balance scored\n3.8/5.0. Career growth opportunities scored 3.9/5.0. Compensation satisfaction\nscored 3.6/5.0. The top requested improvement was 'more flexible remote work\noptions' cited by 62% of respondents. Employee retention rate for the trailing 12\nmonths was 91%.\n\n<!-- PageBreak -->\n\n\n## Contoso Partnership Announcements\n\nContoso announced three strategic partnerships in H1 2025: (1) A joint venture with\nMeridian Technologies for AI-powered document processing, valued at $5.2 million\nover 3 years. (2) A distribution agreement with Pacific Rim Solutions covering 12\ncountries in Asia-Pacific. (3) A technology integration partnership with NovaBridge\nSystems for unified identity management. The Chief Partnership Officer, Helena\nNakagawa, stated the partnerships are expected to generate an additional $15 million\nin revenue by 2027.\n",
"fields": {
"Summary": {
"type": "string",
"valueString": "The document provides a comprehensive overview of Contoso's key business metrics and initiatives for 2025, including financial performance for Q1 and Q2 with revenue, expenses, and profit details; a product roadmap with three major launches and R&D budget; employee satisfaction survey results highlighting scores and retention; and strategic partnership announcements expected to boost future revenue.",
"confidence": 0.46
}
},
"kind": "document",
"startPageNumber": 1,
"endPageNumber": 5,
"mimeType": "application/pdf",
"analyzerId": "prebuilt-documentSearch"
}
]
}
@@ -0,0 +1,51 @@
{
"id": "synthetic-video-001",
"status": "Succeeded",
"analyzer_id": "prebuilt-videoSearch",
"api_version": "2025-05-01-preview",
"created_at": "2026-03-21T10:15:00Z",
"contents": [
{
"kind": "audioVisual",
"startTimeMs": 1000,
"endTimeMs": 14000,
"width": 640,
"height": 480,
"markdown": "# Video: 00:01.000 => 00:14.000\n\nTranscript\n```\nWEBVTT\n\n00:01.000 --> 00:05.000\n<Speaker 1>Welcome to the Contoso Product Demo.\n\n00:05.000 --> 00:14.000\n<Speaker 1>Today we'll be showcasing our latest cloud infrastructure management tool.\n```",
"fields": {
"Summary": {
"type": "string",
"valueString": "Introduction to the Contoso Product Demo showcasing the latest cloud infrastructure management tool."
}
}
},
{
"kind": "audioVisual",
"startTimeMs": 15000,
"endTimeMs": 35000,
"width": 640,
"height": 480,
"markdown": "# Video: 00:15.000 => 00:35.000\n\nTranscript\n```\nWEBVTT\n\n00:15.000 --> 00:25.000\n<Speaker 1>As you can see on the dashboard, the system provides real-time monitoring of all deployed resources.\n\n00:25.000 --> 00:35.000\n<Speaker 1>Key features include automated scaling, cost optimization, and security compliance monitoring.\n```",
"fields": {
"Summary": {
"type": "string",
"valueString": "Dashboard walkthrough covering real-time monitoring, automated scaling, cost optimization, and security compliance."
}
}
},
{
"kind": "audioVisual",
"startTimeMs": 36000,
"endTimeMs": 42000,
"width": 640,
"height": 480,
"markdown": "# Video: 00:36.000 => 00:42.000\n\nTranscript\n```\nWEBVTT\n\n00:36.000 --> 00:42.000\n<Speaker 1>Visit contoso.com/cloud-manager to learn more and start your free trial.\n```",
"fields": {
"Summary": {
"type": "string",
"valueString": "Call to action directing viewers to contoso.com/cloud-manager for more information and a free trial."
}
}
}
]
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,318 @@
# Copyright (c) Microsoft. All rights reserved.
"""Integration tests for ContentUnderstandingContextProvider.
These tests require a live Azure Content Understanding endpoint.
Set AZURE_CONTENTUNDERSTANDING_ENDPOINT to enable them.
To generate fixtures for unit tests, run these tests with --update-fixtures flag
and the resulting JSON files will be written to tests/cu/fixtures/.
"""
from __future__ import annotations
import json
import os
from pathlib import Path
from typing import Any, cast
import pytest
skip_if_cu_integration_tests_disabled = pytest.mark.skipif(
not os.environ.get("AZURE_CONTENTUNDERSTANDING_ENDPOINT"),
reason="CU integration tests disabled (AZURE_CONTENTUNDERSTANDING_ENDPOINT not set)",
)
FIXTURES_DIR = Path(__file__).parent / "fixtures"
# Shared sample asset — same PDF used by samples and integration tests
INVOICE_PDF_PATH = Path(__file__).resolve().parents[2] / "samples" / "shared" / "sample_assets" / "invoice.pdf"
@pytest.mark.flaky
@pytest.mark.integration
@skip_if_cu_integration_tests_disabled
async def test_analyze_pdf_binary() -> None:
"""Analyze a PDF via binary upload and optionally capture fixture."""
from azure.ai.contentunderstanding.aio import ContentUnderstandingClient
from azure.identity.aio import DefaultAzureCredential
endpoint = os.environ["AZURE_CONTENTUNDERSTANDING_ENDPOINT"]
analyzer_id = os.environ.get("AZURE_CONTENTUNDERSTANDING_ANALYZER_ID", "prebuilt-documentSearch")
pdf_path = INVOICE_PDF_PATH
assert pdf_path.exists(), f"Test fixture not found: {pdf_path}"
pdf_bytes = pdf_path.read_bytes()
async with DefaultAzureCredential() as credential, ContentUnderstandingClient(endpoint, credential) as client: # pyrefly: ignore[bad-argument-type]
poller = await client.begin_analyze_binary(
analyzer_id,
binary_input=pdf_bytes,
content_type="application/pdf",
string_encoding="utf-8",
)
result = await poller.result()
assert result.contents
assert result.contents[0].markdown
assert len(result.contents[0].markdown) > 10
assert "CONTOSO LTD." in result.contents[0].markdown
# Optionally capture fixture
if os.environ.get("CU_UPDATE_FIXTURES"):
FIXTURES_DIR.mkdir(exist_ok=True)
fixture_path = FIXTURES_DIR / "analyze_pdf_result.json"
fixture_path.write_text(json.dumps(result.as_dict(), indent=2, default=str))
@pytest.mark.flaky
@pytest.mark.integration
@skip_if_cu_integration_tests_disabled
async def test_before_run_e2e() -> None:
"""End-to-end test: Content.from_data → before_run → state populated."""
from agent_framework import Content, Message, SessionContext
from agent_framework._sessions import AgentSession
from azure.identity.aio import DefaultAzureCredential
from agent_framework_azure_contentunderstanding import ContentUnderstandingContextProvider
endpoint = os.environ["AZURE_CONTENTUNDERSTANDING_ENDPOINT"]
pdf_path = INVOICE_PDF_PATH
assert pdf_path.exists(), f"Test fixture not found: {pdf_path}"
pdf_bytes = pdf_path.read_bytes()
async with DefaultAzureCredential() as credential:
cu = ContentUnderstandingContextProvider(
endpoint=endpoint,
credential=credential, # pyrefly: ignore[bad-argument-type]
max_wait=None, # wait until analysis completes (no background deferral)
)
async with cu:
msg = Message(
role="user",
contents=[
Content.from_text("What's in this document?"),
Content.from_data(
pdf_bytes,
"application/pdf",
additional_properties={"filename": "invoice.pdf"},
),
],
)
context = SessionContext(input_messages=[msg])
state: dict[str, object] = {}
session = AgentSession()
from unittest.mock import MagicMock
await cu.before_run(agent=MagicMock(), session=session, context=context, state=state)
docs = cast("dict[str, Any]", state.get("documents", {}))
assert isinstance(docs, dict)
assert "invoice.pdf" in docs
doc_entry = docs["invoice.pdf"]
assert doc_entry["status"] == "ready"
# ``result`` is now the rendered string from ``to_llm_input``.
rendered = doc_entry["result"]
assert isinstance(rendered, str)
assert len(rendered) > 10
assert "source: invoice.pdf" in rendered
assert "CONTOSO LTD." in rendered
# Raw GitHub URL for a public invoice PDF from the CU samples repo
_INVOICE_PDF_URL = (
"https://raw.githubusercontent.com/Azure-Samples/azure-ai-content-understanding-assets/main/document/invoice.pdf"
)
@pytest.mark.flaky
@pytest.mark.integration
@skip_if_cu_integration_tests_disabled
async def test_before_run_uri_content() -> None:
"""End-to-end test: Content.from_uri with an external URL → before_run → state populated.
Verifies that CU can analyze a file referenced by URL (not base64 data).
Uses a public invoice PDF from the Azure CU samples repository.
"""
from agent_framework import Content, Message, SessionContext
from agent_framework._sessions import AgentSession
from azure.identity.aio import DefaultAzureCredential
from agent_framework_azure_contentunderstanding import ContentUnderstandingContextProvider
endpoint = os.environ["AZURE_CONTENTUNDERSTANDING_ENDPOINT"]
async with DefaultAzureCredential() as credential:
cu = ContentUnderstandingContextProvider(
endpoint=endpoint,
credential=credential, # pyrefly: ignore[bad-argument-type]
max_wait=None, # wait until analysis completes (no background deferral)
)
async with cu:
msg = Message(
role="user",
contents=[
Content.from_text("What's on this invoice?"),
Content.from_uri(
uri=_INVOICE_PDF_URL,
media_type="application/pdf",
additional_properties={"filename": "invoice.pdf"},
),
],
)
context = SessionContext(input_messages=[msg])
state: dict[str, object] = {}
session = AgentSession()
from unittest.mock import MagicMock
await cu.before_run(agent=MagicMock(), session=session, context=context, state=state)
docs = cast("dict[str, Any]", state.get("documents", {}))
assert isinstance(docs, dict)
assert "invoice.pdf" in docs
doc_entry = docs["invoice.pdf"]
assert doc_entry["status"] == "ready"
rendered = doc_entry["result"]
assert isinstance(rendered, str)
assert len(rendered) > 10
assert "source: invoice.pdf" in rendered
assert "CONTOSO LTD." in rendered
@pytest.mark.flaky
@pytest.mark.integration
@skip_if_cu_integration_tests_disabled
async def test_before_run_data_uri_content() -> None:
"""End-to-end test: Content.from_uri with a base64 data URI → before_run → state populated.
Verifies that CU can analyze a file embedded as a data URI (data:application/pdf;base64,...).
This tests the data URI path: from_uri with "data:" prefix → type="data" → begin_analyze_binary.
"""
import base64
from agent_framework import Content, Message, SessionContext
from agent_framework._sessions import AgentSession
from azure.identity.aio import DefaultAzureCredential
from agent_framework_azure_contentunderstanding import ContentUnderstandingContextProvider
endpoint = os.environ["AZURE_CONTENTUNDERSTANDING_ENDPOINT"]
pdf_path = INVOICE_PDF_PATH
assert pdf_path.exists(), f"Test fixture not found: {pdf_path}"
pdf_bytes = pdf_path.read_bytes()
b64 = base64.b64encode(pdf_bytes).decode("ascii")
data_uri = f"data:application/pdf;base64,{b64}"
async with DefaultAzureCredential() as credential:
cu = ContentUnderstandingContextProvider(
endpoint=endpoint,
credential=credential, # pyrefly: ignore[bad-argument-type]
max_wait=None, # wait until analysis completes
)
async with cu:
msg = Message(
role="user",
contents=[
Content.from_text("What's on this invoice?"),
Content.from_uri(
uri=data_uri,
media_type="application/pdf",
additional_properties={"filename": "invoice_b64.pdf"},
),
],
)
context = SessionContext(input_messages=[msg])
state: dict[str, object] = {}
session = AgentSession()
from unittest.mock import MagicMock
await cu.before_run(agent=MagicMock(), session=session, context=context, state=state)
docs = cast("dict[str, Any]", state.get("documents", {}))
assert isinstance(docs, dict)
assert "invoice_b64.pdf" in docs
doc_entry = docs["invoice_b64.pdf"]
assert doc_entry["status"] == "ready"
rendered = doc_entry["result"]
assert isinstance(rendered, str)
assert len(rendered) > 10
assert "source: invoice_b64.pdf" in rendered
assert "CONTOSO LTD." in rendered
@pytest.mark.flaky
@pytest.mark.integration
@skip_if_cu_integration_tests_disabled
async def test_before_run_background_analysis() -> None:
"""End-to-end test: max_wait timeout → background analysis → resolved on next turn.
Uses a short max_wait (0.5s) so CU analysis is deferred to background.
Then waits for analysis to complete and calls before_run again to verify
the background task resolves and the document becomes ready.
"""
import asyncio
from agent_framework import Content, Message, SessionContext
from agent_framework._sessions import AgentSession
from azure.identity.aio import DefaultAzureCredential
from agent_framework_azure_contentunderstanding import ContentUnderstandingContextProvider
endpoint = os.environ["AZURE_CONTENTUNDERSTANDING_ENDPOINT"]
async with DefaultAzureCredential() as credential:
cu = ContentUnderstandingContextProvider(
endpoint=endpoint,
credential=credential, # pyrefly: ignore[bad-argument-type]
max_wait=0.5, # short timeout to force background deferral
)
async with cu:
# Turn 1: upload file — should time out and defer to background
msg = Message(
role="user",
contents=[
Content.from_text("What's on this invoice?"),
Content.from_uri(
uri=_INVOICE_PDF_URL,
media_type="application/pdf",
additional_properties={"filename": "invoice.pdf"},
),
],
)
context = SessionContext(input_messages=[msg])
state: dict[str, object] = {}
session = AgentSession()
from unittest.mock import MagicMock
await cu.before_run(agent=MagicMock(), session=session, context=context, state=state)
docs = cast("dict[str, Any]", state.get("documents", {}))
assert isinstance(docs, dict)
assert "invoice.pdf" in docs
assert docs["invoice.pdf"]["status"] == "analyzing", (
f"Expected 'analyzing' but got '{docs['invoice.pdf']['status']}'"
"CU responded too fast for the 0.5s timeout"
)
assert docs["invoice.pdf"]["result"] is None
# Wait for background analysis to complete
await asyncio.sleep(30)
# Turn 2: no new files — should resolve the background task
msg2 = Message(role="user", contents=[Content.from_text("Is it ready?")])
context2 = SessionContext(input_messages=[msg2])
await cu.before_run(agent=MagicMock(), session=session, context=context2, state=state)
assert docs["invoice.pdf"]["status"] == "ready"
rendered = docs["invoice.pdf"]["result"]
assert isinstance(rendered, str)
assert "CONTOSO LTD." in rendered
@@ -0,0 +1,68 @@
# Copyright (c) Microsoft. All rights reserved.
from __future__ import annotations
from unittest.mock import AsyncMock
from agent_framework_azure_contentunderstanding._models import (
DocumentEntry,
DocumentStatus,
FileSearchConfig,
)
class TestDocumentEntry:
def test_construction(self) -> None:
entry: DocumentEntry = {
"status": DocumentStatus.READY,
"filename": "invoice.pdf",
"media_type": "application/pdf",
"analyzer_id": "prebuilt-documentSearch",
"analyzed_at": "2026-01-01T00:00:00+00:00",
"analysis_duration_s": 1.23,
"upload_duration_s": None,
"result": "---\nsource: invoice.pdf\n---\n# Title",
"error": None,
}
assert entry["status"] == DocumentStatus.READY
assert entry["filename"] == "invoice.pdf"
assert entry["analyzer_id"] == "prebuilt-documentSearch"
assert entry["analysis_duration_s"] == 1.23
assert entry["upload_duration_s"] is None
assert isinstance(entry["result"], str)
def test_failed_entry(self) -> None:
entry: DocumentEntry = {
"status": DocumentStatus.FAILED,
"filename": "bad.pdf",
"media_type": "application/pdf",
"analyzer_id": "prebuilt-documentSearch",
"analyzed_at": "2026-01-01T00:00:00+00:00",
"analysis_duration_s": 0.5,
"upload_duration_s": None,
"result": None,
"error": "Service unavailable",
}
assert entry["status"] == DocumentStatus.FAILED
assert entry["error"] == "Service unavailable"
assert entry["result"] is None
class TestFileSearchConfig:
def test_required_fields(self) -> None:
backend = AsyncMock()
tool = {"type": "file_search", "vector_store_ids": ["vs_123"]}
config = FileSearchConfig(backend=backend, vector_store_id="vs_123", file_search_tool=tool)
assert config.backend is backend
assert config.vector_store_id == "vs_123"
assert config.file_search_tool is tool
def test_from_openai_factory(self) -> None:
from agent_framework_azure_contentunderstanding._file_search import OpenAIFileSearchBackend
client = AsyncMock()
tool = {"type": "file_search", "vector_store_ids": ["vs_abc"]}
config = FileSearchConfig.from_openai(client, vector_store_id="vs_abc", file_search_tool=tool)
assert isinstance(config.backend, OpenAIFileSearchBackend)
assert config.vector_store_id == "vs_abc"
assert config.file_search_tool is tool