Document Intelligence with Azure Functions: A Practical Implementation
Recently, I wrote about a system I created that automatically classifies SharePoint documents, but only briefly touched on the most important part—the Azure Function that does all the heavy lifting.
This post walks through the technical part of this document processing engine and demos how to build an Azure Function that extracts text from documents, analyzes content with cognitive services, and outputs clean, structured data.
Why document intelligence matters for automation engineers
Automation engineers are often skeptical about AI's usefulness in their workflows, and I get it but document processing is a genuinely a good use case.
Think about what happens when a user uploads a legal contract to a law firm's intranet. How would you programmatically figure out:
- Is this a legal contract or an NDA?
- Who are the parties involved?
- What's the effective date?
- Which jurisdiction applies?
The classic approach would, first of all, not be really possible unless they followed a template, and otherwise, would require complex regex patterns or custom parsers that break if someone adds an extra space. Custom parsers are often brittle, maintenance-heavy, and a pain to keep working.
Models like gpt-4o and gpt-4o-mini can handle this variability naturally, but you have to ensure you get structured data back instead of walls of text.
Structured output: The secret to practical AI integration
In my post about asking tiny questions, I showed how to get clean true/false responses from local LLMs. Then in asking bigger questions, I expanded this to handle larger contexts and complex command outputs. Now, we're applying those same principles to structure and analyze entire documents.
Instead of getting paragraphs of conversational text, we can get JSON that fits a schema we define:
1{
2 "document_type": "Non-Disclosure Agreement",
3 "parties": ["Acme Corp", "XYZ Consulting"],
4 "effective_date": "2025-01-15",
5 "jurisdiction": "Delaware"
6}
This document processor is a perfect real-world application of the "bigger questions" approach - taking unstructured content (in this case, documents rather than command outputs) and morphing it into clean, structured data using cloud-based models with larger context windows.
Structured data changes how we use AI in automation because it's predictable with fields always having the same names, easily parseable without requiring regex to extract values from text, can be validated by enforcing types and required fields, and is directly usable as it's ready to insert into databases or update properties.
Ultimately, with structured output, AI becomes way more useful because it returns structured data instead of freeform text.
What we're building: An AI document processor in Azure Functions
Microsoft's Power Platform doesn't have a free or native way to read the actual content of Office/PDF files. You can get the binary file, though. To extract that binary and read the text to provide to the AI API for categorization, we need an Azure Function.
If you've been following my blog series, you've probably noticed that structured output is a recurring theme. Nearly every post I've written—from local LLMs to GitHub Models to SharePoint integration—builds on this core concept. That's because structured data is the foundation that makes AI actually useful for automation.
I've built an Azure Function that:
- Takes in documents (PDF, Word, etc.)
- Extracts the text content
- Uses gpt-4o-mini to analyze the text and extract structured data
- Returns clean JSON that matches our schema
This isn't just a demo—it's a production-ready service you can integrate with SharePoint, document management systems, or any pipeline that processes documents.
Best of all, it works with multiple AI providers like OpenAI's API, Azure OpenAI Service, GitHub Models and any other API-compatible endpoint. Note that your schema structure may have to change slightly for non-OpenAI models. Check out my post Asking Tiny Questions for alternative schema templates.
Setting up the Azure Function
First, let's set up our Azure Function environment:
- Create a new Function App in Azure
- Configure environment variables:
API_KEY
: Your OpenAI API keyAPI_BASE
: API base URL (leave empty for OpenAI, or use Azure OpenAI/GitHub URLs)Model
: Specify "gpt-4o" or "gpt-4o-mini"AZURE_FUNCTION_KEY
: A key to secure your function
Instead of setting up from scratch, I've created a ready-to-use GitHub repository with all the code. You can find it here.
Function endpoints and their roles
Our function app has two key HTTP endpoints:
1. Text extraction endpoint (/api/extract)
This endpoint takes a document and extracts plain text:
1# Test text extraction only
2$params = @{
3 Uri = "https://your-function-app.azurewebsites.net/api/extract"
4 Method = "Post"
5 Headers = @{
6 'x-functions-key' = $functionKey
7 }
8 InFile = "C:\path\to\your\document.pdf"
9 ContentType = "application/octet-stream"
10}
11Invoke-RestMethod @params
This returns just the raw text from your document - useful for debugging or when you want to process the text yourself.
2. Document processing endpoint (/api/process)
This is where the real work happens. It extracts text and then uses GPT-4o-mini to analyze it:
1# Process document with AI
2$params = @{
3 Uri = "https://your-function-app.azurewebsites.net/api/process"
4 Method = "Post"
5 Headers = @{
6 'x-functions-key' = $functionKey
7 'x-openai-model' = 'gpt-4o-mini'
8 }
9 ContentType = "application/octet-stream"
10 InFile = "C:\path\to\your\document.pdf"
11}
12Invoke-RestMethod @params
Defining your schema for structured data
The key to getting consistent results is defining exactly what you want from the AI using a JSON schema.
In the code below, I create my schema in PowerShell because it's easier to read, then I convert it to JSON and send it in the header. I used the header because the body is taken up entirely by the binary of the Office document or PDF.
1# Define your schema
2$schema = @{
3 name = "legal_document_categorizer"
4 strict = $true
5 additionalProperties = $false
6 schema = @{
7 type = "object"
8 properties = @{
9 area_of_law = @{
10 type = "string"
11 enum = @("Criminal Law", "Civil Law", "Contract Law")
12 }
13 document_type = @{
14 type = "string"
15 enum = @("Case Brief", "Legal Opinion", "Contract")
16 }
17 parties_involved = @{
18 type = "array"
19 items = @{ type = "string" }
20 }
21 }
22 required = @("area_of_law", "document_type", "parties_involved")
23 }
24}
25
26# Process the document
27$params = @{
28 Uri = "https://your-function-app.azurewebsites.net/api/process"
29 Method = "Post"
30 Headers = @{
31 'x-functions-key' = $functionKey
32 'x-custom-schema' = ($schema | ConvertTo-Json -Depth 20 -Compress)
33 'x-openai-model' = 'gpt-4o-mini'
34 }
35 InFile = "C:\path\to\your\document.pdf"
36 ContentType = "application/octet-stream"
37}
38Invoke-RestMethod @params | ConvertTo-Json -Depth 20
The schema approach gives you several advantages like allowing only specific values using enum
, specifying required fields, and even defining complex data types like arrays.
Understanding the results
The function returns clean, structured JSON that maps directly to your schema:
1{
2 "status": "success",
3 "message": "Document processed successfully",
4 "results": {
5 "fileName": "contract.pdf",
6 "data": {
7 "area_of_law": "Contract Law",
8 "document_type": "Contract",
9 "parties_involved": ["Acme Corp", "XYZ Ltd"]
10 }
11 }
12}
This structured format is perfect for integrating with systems like SharePoint, since each field can map directly to a SharePoint column.
Customizing the AI instructions
Need more control over how the AI analyzes your documents? You can provide custom instructions:
1$params = @{
2 Uri = "https://your-function-app.azurewebsites.net/api/process"
3 Method = "Post"
4 Headers = @{
5 'x-functions-key' = $functionKey
6 'x-custom-schema' = ($schema | ConvertTo-Json -Depth 20 -Compress)
7 'x-openai-instructions' = "if any field is missing (like court jurisdiction), just write N/A"
8 'x-openai-model' = 'gpt-4o-mini'
9 }
10 InFile = "C:\path\to\your\document.pdf"
11 ContentType = "application/octet-stream"
12}
13Invoke-RestMethod @params
These custom instructions help guide the AI's analysis, which is particularly useful for domain-specific documents or unusual formats.
Integrating with Power Automate
To connect this Azure Function to Power Automate, update the HTTP action to call our process endpoint:
1Method: POST
2URI: https://your-function-app.azurewebsites.net/api/process
3Headers:
4 x-functions-key: your-function-key
5 x-custom-schema: {"name":"sharepoint_document","schema":{"type":"object","properties":{"case_number":{"type":"string"},"document_type":{"type":"string","enum":["Case Brief","Legal Opinion","Contract"]},"jurisdiction":{"type":"string"},"keywords":{"type":"array","items":{"type":"string"}},"parties_involved":{"type":"array","items":{"type":"string"}},"area_of_law":{"type":"string","enum":["Criminal Law","Civil Law","Contract Law"]}},"required":["document_type","area_of_law"]}}
6 Content-Type: application/octet-stream
7Body: [File content from previous step]
The output includes a results.data
object that maps directly to your SharePoint columns - no additional transformation needed.
Speed check
For those wondering about performance, here's what you can expect:
- Text extraction: 1-2 seconds
- GPT-4o analysis: 3-5 seconds
- GPT-4o-mini analysis: 1-2 seconds
If you're batch processing, the function can handle multiple concurrent requests. For large volumes, consider deploying to a premium Azure Function plan.
Why this matters
This Azure Function is the worker bee of our automatic document classification system. By combining it with SharePoint and Power Automate, we've created a workflow that:
- Takes documents uploaded by users
- Extracts text and identifies key metadata
- Updates SharePoint properties automatically
The result is a system where users just upload files like normal, but behind the scenes, everything gets properly classified and organized.
This post is part of my AI Integration for Automation Engineers series. If you enjoyed it, check out these other posts:
- AI Automation with AI Toolkit for VS Code and GitHub Models: A visual guide
- Getting Started with AI for PowerShell Developers: PSOpenAI and GitHub Models
- Asking Tiny Questions: Local LLMs for PowerShell Devs
- Local Models Mildly Demystified
- Asking Bigger Questions: Remote LLMs for Automation Engineers
- PDF Text to SQL Data: Using OpenAI's Structured Output with PSOpenAI
- Automating Document Classification in SharePoint with Power Platform and AI
- Document Intelligence with Azure Functions: A Practical Implementation
And as always, if you're interested in diving deeper into these topics, my upcoming AI book covers everything from local models to advanced automation techniques. Use code gaipbl45 for 45% off.