Skip to content

Latest commit

 

History

History
847 lines (668 loc) · 22.2 KB

File metadata and controls

847 lines (668 loc) · 22.2 KB

Azure Implementation Guide

Author: Ranjith Kumar Neela
Last Updated: October 2025


Prerequisites

  • Azure subscription with Owner or Contributor role
  • Access to create Azure OpenAI resources (requires application approval)
  • Power Platform environment (Premium license)

Part 1: Azure OpenAI Setup

Step 1: Create Azure OpenAI Resource

  1. Go to Azure Portal
  2. Click Create a resource
  3. Search for Azure OpenAI
  4. Click Create

Configuration:

  • Subscription: Select your subscription
  • Resource Group: Create new or use existing (e.g., rg-document-summarizer)
  • Region: East US (recommended for GPT-4o availability)
  • Name: openai-doc-summarizer (must be globally unique)
  • Pricing Tier: Standard S0
  1. Click Review + CreateCreate
  2. Wait for deployment (2-3 minutes)

Step 2: Deploy GPT-4o Model

  1. Navigate to your Azure OpenAI resource
  2. Click Go to Azure OpenAI Studio (or visit oai.azure.com)
  3. Click Deployments in left menu
  4. Click + Create new deployment

Deployment Settings:

  • Model: gpt-4o
  • Model version: 2024-08-06 (or latest available)
  • Deployment name: gpt-4o (use this exact name for consistency)
  • Deployment type: Standard
  • Tokens per Minute Rate Limit: 30K (adjust based on needs)
  • Content filter: Default
  1. Click Create
  2. Wait for deployment (30 seconds)

Step 3: Get Connection Details

  1. In Azure OpenAI Studio, click Deployments
  2. Click on your gpt-4o deployment
  3. Note the Endpoint URL (format: https://{your-resource}.openai.azure.com/)
  4. Go back to Azure Portal → Your OpenAI resource
  5. Click Keys and Endpoint in left menu
  6. Copy KEY 1 (save securely)
  7. Copy Endpoint (same as above)

Save these values:

Endpoint: https://openai-doc-summarizer.openai.azure.com/
Key: [your-api-key-here]
Deployment Name: gpt-4o
API Version: 2024-10-01-preview

Part 2: Azure Active Directory Authentication (Recommended)

Step 4: Create Service Principal

  1. Go to Azure Active Directory in Azure Portal
  2. Click App registrationsNew registration

Registration:

  • Name: PowerAutomate-OpenAI-Connector
  • Supported account types: Accounts in this organizational directory only
  • Redirect URI: Leave blank
  1. Click Register
  2. Copy Application (client) ID
  3. Copy Directory (tenant) ID

Step 5: Create Client Secret

  1. In your app registration, click Certificates & secrets
  2. Click New client secret
  • Description: Power Automate Access
  • Expires: 24 months
  1. Click Add
  2. Copy the secret VALUE immediately (you can't see it again)

Save these values:

Client ID: [your-client-id]
Tenant ID: [your-tenant-id]
Client Secret: [your-client-secret]

Step 6: Assign Permissions

  1. Go back to your Azure OpenAI resource
  2. Click Access control (IAM)
  3. Click + AddAdd role assignment
  4. Select Cognitive Services OpenAI User role
  5. Click Next
  6. Click + Select members
  7. Search for PowerAutomate-OpenAI-Connector
  8. Select it → Click Select
  9. Click Review + assign

Part 3: Dataverse Setup

Step 7: Create Dataverse Tables

  1. Go to Power Apps
  2. Select your environment
  3. Click TablesNew tableSet advanced properties

Table 1: Documents

Table Properties:

  • Display name: Documents
  • Plural name: Documents
  • Primary column: Document Name
  • Enable attachments: Yes

Columns to Add:

Display Name Name Data Type Required Notes
Document Name cr_documentname Text Yes Primary
File Content cr_filecontent File Yes Max 32 MB
File Type cr_filetype Choice Yes Options: PDF, DOCX
Upload Date cr_uploaddate Date and Time Yes Auto-set
Processing Status cr_processingstatus Choice Yes Options: Pending, Processing, Completed, Error
Error Message cr_errormessage Text No Max 2000 chars
Token Count cr_tokencount Whole Number No -
Uploaded By cr_uploadedby Lookup Yes To System User

Create Choices:

For File Type:

  • Label: PDF, Value: 1
  • Label: DOCX, Value: 2

For Processing Status:

  • Label: Pending, Value: 1
  • Label: Processing, Value: 2
  • Label: Completed, Value: 3
  • Label: Error, Value: 4

Table 2: Summaries

Table Properties:

  • Display name: Summaries
  • Plural name: Summaries
  • Primary column: Summary ID

Columns to Add:

Display Name Name Data Type Required Notes
Summary ID cr_summaryid Text Yes Primary (auto-generated)
Document cr_documentid Lookup Yes To Documents table
Summary Text cr_summarytext Multiline Text Yes Max 100K chars
Processing Time cr_processingtime Decimal No In seconds
Tokens Used cr_tokensused Whole Number No -
Estimated Cost cr_estimatedcost Currency No In USD
Created Date cr_createddate Date and Time Yes Auto-set
Quality Rating cr_qualityrating Whole Number No 1-5 scale
Model Version cr_modelversion Text No e.g., "gpt-4o"

Step 8: Configure Security

  1. Go to TablesDocuments
  2. Click PropertiesAdvanced options
  3. Enable Audit changes
  4. Set Ownership: User or team owned
  5. Save

Repeat for Summaries table.


Part 4: Power Automate Flow

Step 9: Create Cloud Flow

  1. Go to Power Automate
  2. Click + CreateAutomated cloud flow
  3. Name: Process Document Summarization
  4. Trigger: When a row is added, modified or deleted (Dataverse)
  5. Click Create

Step 10: Configure Trigger

Trigger Settings:

  • Change type: Added
  • Table name: Documents
  • Scope: Organization
  • Run as: Flow owner

Step 11: Add Condition - Check Status

  1. Click + New step
  2. Search for Condition
  3. Choose: Processing Status equals Pending

Step 12: In "If yes" branch - Update Status to Processing

  1. Click Add an action
  2. Search for Update a row (Dataverse)
  3. Table name: Documents
  4. Row ID: Documents (from trigger)
  5. Processing Status: Processing

Step 13: Get Document Content

  1. Click Add an action
  2. Search for Get a row by ID (Dataverse)
  3. Table name: Documents
  4. Row ID: Documents (from trigger)

Step 14: Convert Document to Text

For DOCX files:

  1. Add Condition: File Type equals DOCX
  2. In "If yes":
    • Add Create file (OneDrive or SharePoint)
    • File name: temp_@{triggerOutputs()?['body/cr_documentname']}
    • File content: File Content (from Get row)
    • Add Convert Word Document to Text (Word Online)
    • File: Output from Create file
    • Add Delete file (clean up temp file)

For PDF files:

  1. In "If no":
    • Add Analyze document (AI Builder)
    • Document: File Content
    • Model: Use pre-built document processing

Step 15: Calculate Token Count

  1. Add Compose action
  2. Name: Calculate Tokens
  3. Formula:
div(add(div(length(outputs('Convert_to_Text')?['body']), 4), div(length(split(outputs('Convert_to_Text')?['body'], ' ')), 0.75)), 1)

Step 16: Add Condition - Single Pass vs Chunking

  1. Add Condition
  2. Choose: Calculate Tokens is less than or equal to 1000

Step 17: Single Pass Processing (If yes - Token count ≤ 1000)

  1. Add HTTP action
  2. Method: POST
  3. URI:
https://openai-doc-summarizer.openai.azure.com/openai/deployments/gpt-4o/chat/completions?api-version=2024-10-01-preview
  1. Headers:
{
  "Content-Type": "application/json",
  "api-key": "[YOUR-API-KEY]"
}
  1. Body:
{
  "messages": [
    {
      "role": "system",
      "content": "You are an expert document summarization assistant specializing in business and technical content. Your summaries are concise, accurate, and preserve critical information. You maintain an objective, professional tone and never add information not present in the source document."
    },
    {
      "role": "user",
      "content": "Summarize the following document. Focus on: Main objectives and key findings, Important decisions and recommendations, Critical data points and metrics, Action items and next steps. Target length: 200 words.\n\nDocument:\n@{outputs('Convert_to_Text')?['body']}\n\nProvide a well-structured summary:"
    }
  ],
  "max_tokens": 800,
  "temperature": 0.5,
  "top_p": 0.95,
  "frequency_penalty": 0.3,
  "presence_penalty": 0.1
}

Step 17B: Chunking Processing (If no - Token count > 1000)

In the "If no" branch of Step 16:

Step 17B.1: Initialize Variables

  1. Add Initialize variable action

    • Name: ChunkSize
    • Type: Integer
    • Value: 1000
  2. Add Initialize variable action

    • Name: ChunkOverlap
    • Type: Integer
    • Value: 100
  3. Add Initialize variable action

    • Name: ChunkSummaries
    • Type: Array
    • Value: []
  4. Add Initialize variable action

    • Name: CurrentPosition
    • Type: Integer
    • Value: 0
  5. Add Initialize variable action

    • Name: DocumentText
    • Type: String
    • Value: outputs('Convert_to_Text')?['body']

Step 17B.2: Split Text into Chunks

  1. Add Compose action
  2. Name: Calculate Chunk Count
  3. Formula:
div(sub(length(variables('DocumentText')), variables('ChunkOverlap')), sub(variables('ChunkSize'), variables('ChunkOverlap')))
  1. Add Compose action
  2. Name: Create Chunks Array
  3. Formula:
range(0, int(outputs('Calculate_Chunk_Count')))

Step 17B.3: Process Each Chunk in Parallel

  1. Add Apply to each action
  2. Select an output from previous steps: outputs('Create_Chunks_Array')
  3. Click ...Settings
  4. Concurrency Control: On
  5. Degree of Parallelism: 10

Inside the loop:

A. Calculate Chunk Position

Add Compose action

  • Name: Chunk Start Position
  • Formula:
mul(item(), sub(variables('ChunkSize'), variables('ChunkOverlap')))

Add Compose action

  • Name: Chunk End Position
  • Formula:
min(add(outputs('Chunk_Start_Position'), variables('ChunkSize')), length(variables('DocumentText')))

B. Extract Chunk Text

Add Compose action

  • Name: Chunk Text
  • Formula:
substring(variables('DocumentText'), outputs('Chunk_Start_Position'), sub(outputs('Chunk_End_Position'), outputs('Chunk_Start_Position')))

C. Summarize Chunk

Add HTTP action

  • Method: POST
  • URI:
https://openai-doc-summarizer.openai.azure.com/openai/deployments/gpt-4o/chat/completions?api-version=2024-10-01-preview
  • Headers:
{
  "Content-Type": "application/json",
  "api-key": "[YOUR-API-KEY]"
}
  • Body:
{
  "messages": [
    {
      "role": "system",
      "content": "You are an expert at summarizing document sections. Create concise summaries that capture key points while maintaining context."
    },
    {
      "role": "user",
      "content": "Summarize this section of a larger document. Focus on main points and key information. Target length: 100 words.\n\nSection @{add(item(), 1)} of @{length(outputs('Create_Chunks_Array'))}:\n@{outputs('Chunk_Text')}\n\nSummary:"
    }
  ],
  "max_tokens": 500,
  "temperature": 0.5,
  "top_p": 0.95,
  "frequency_penalty": 0.3,
  "presence_penalty": 0.1
}

D. Parse Chunk Response

Add Parse JSON action

  • Content: Body (from HTTP)
  • Schema: (same as Step 18 below)

E. Append to Chunk Summaries

Add Append to array variable action

  • Name: ChunkSummaries
  • Value:
{
  "chunk_number": @{add(item(), 1)},
  "summary": "@{body('Parse_JSON_Chunk')?['choices'][0]?['message']?['content']}",
  "tokens": @{body('Parse_JSON_Chunk')?['usage']?['total_tokens']}
}

Step 17B.4: Combine Chunk Summaries

After the Apply to each loop:

  1. Add Compose action
    • Name: Combined Chunk Summaries
    • Formula:
join(
  select(variables('ChunkSummaries'), concat('Section ', string(item()?['chunk_number']), ': ', item()?['summary'])),
  '\n\n'
)

Step 17B.5: Second-Level Summarization

  1. Add Condition
  2. Check if: length(variables('ChunkSummaries')) is greater than 5

If yes (many chunks - need final synthesis):

Add HTTP action

  • Method: POST
  • URI:
https://openai-doc-summarizer.openai.azure.com/openai/deployments/gpt-4o/chat/completions?api-version=2024-10-01-preview
  • Headers:
{
  "Content-Type": "application/json",
  "api-key": "[YOUR-API-KEY]"
}
  • Body:
{
  "messages": [
    {
      "role": "system",
      "content": "You are an expert at synthesizing multiple summaries into a cohesive final summary. Create a unified summary that captures the overall document's key points."
    },
    {
      "role": "user",
      "content": "The following are summaries of different sections of a document. Create a final, cohesive summary that captures the main points of the entire document. Target length: 300 words.\n\nSection Summaries:\n@{outputs('Combined_Chunk_Summaries')}\n\nFinal Summary:"
    }
  ],
  "max_tokens": 800,
  "temperature": 0.5,
  "top_p": 0.95,
  "frequency_penalty": 0.3,
  "presence_penalty": 0.1
}

If no (few chunks - use combined summaries directly):

Add Compose action

  • Name: Final Summary
  • Value: outputs('Combined_Chunk_Summaries')

Step 17B.6: Calculate Total Tokens and Cost

  1. Add Compose action
    • Name: Total Tokens Used
    • Formula:
add(
  sum(select(variables('ChunkSummaries'), item()?['tokens'])),
  if(greater(length(variables('ChunkSummaries')), 5), body('Parse_JSON_Final')?['usage']?['total_tokens'], 0)
)
  1. Add Compose action
    • Name: Total Cost
    • Formula:
mul(div(outputs('Total_Tokens_Used'), 1000), 0.005)

Step 18: Parse JSON Response (Single-Pass Only)

Note: For chunked processing, parsing happens inside the loop (Step 17B.3.D). This step is only for single-pass processing.

  1. Add Parse JSON action (in the "If yes" branch from Step 16)
  2. Content: Body (from HTTP action in Step 17)
  3. Schema:
{
  "type": "object",
  "properties": {
    "choices": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "message": {
            "type": "object",
            "properties": {
              "content": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "usage": {
      "type": "object",
      "properties": {
        "prompt_tokens": {
          "type": "integer"
        },
        "completion_tokens": {
          "type": "integer"
        },
        "total_tokens": {
          "type": "integer"
        }
      }
    }
  }
}

Step 19: Calculate Cost (Single-Pass)

In the "If yes" branch (single-pass):

  1. Add Compose action
  2. Name: Calculate Cost
  3. Formula:
add(mul(div(body('Parse_JSON')?['usage']?['prompt_tokens'], 1000), 0.0025), mul(div(body('Parse_JSON')?['usage']?['completion_tokens'], 1000), 0.01))

Note: For chunking, cost is calculated in Step 17B.6.

Step 20: Merge Both Paths

After both "If yes" and "If no" branches complete, add actions outside the condition:

This ensures both single-pass and chunked processing converge to the same final steps.

  1. Add Initialize variable action (before the condition in Step 16)

    • Name: FinalSummary
    • Type: String
    • Value: ""
  2. Add Initialize variable action (before the condition in Step 16)

    • Name: TotalTokens
    • Type: Integer
    • Value: 0
  3. Add Initialize variable action (before the condition in Step 16)

    • Name: TotalCost
    • Type: Float
    • Value: 0.0

In the "If yes" branch (single-pass), add at the end:

  1. Set variable FinalSummary

    • Value: body('Parse_JSON')?['choices'][0]?['message']?['content']
  2. Set variable TotalTokens

    • Value: body('Parse_JSON')?['usage']?['total_tokens']
  3. Set variable TotalCost

    • Value: outputs('Calculate_Cost')

In the "If no" branch (chunking), add at the end:

  1. Set variable FinalSummary

    • Value: if(greater(length(variables('ChunkSummaries')), 5), body('Parse_JSON_Final')?['choices'][0]?['message']?['content'], outputs('Combined_Chunk_Summaries'))
  2. Set variable TotalTokens

    • Value: outputs('Total_Tokens_Used')
  3. Set variable TotalCost

    • Value: outputs('Total_Cost')

Step 21: Create Summary Record (Both Paths)

After the condition (outside both branches):

  1. Add Add a new row (Dataverse)
  2. Table name: Summaries
  3. Document: Documents (from trigger)
  4. Summary Text: variables('FinalSummary')
  5. Processing Time: div(sub(ticks(utcNow()), ticks(triggerOutputs()?['body/createdon'])), 10000000)
  6. Tokens Used: variables('TotalTokens')
  7. Estimated Cost: variables('TotalCost')
  8. Model Version: gpt-4o

Step 22: Update Document Status to Completed

  1. Add Update a row (Dataverse)
  2. Table name: Documents
  3. Row ID: Documents (from trigger)
  4. Processing Status: Completed
  5. Token Count: variables('TotalTokens')

Step 23: Add Error Handling

  1. Click ... on the main scope → Configure run after
  2. Add parallel branch for has failed
  3. Add Update a row (Dataverse)
  4. Processing Status: Error
  5. Error Message: @{body('HTTP')?['error']?['message']}

Step 24: Save and Test

  1. Click Save
  2. Click TestManually
  3. Upload a test document via Power App
  4. Monitor flow execution

Part 5: Power Apps Setup

Step 25: Create Canvas App

  1. Go to Power Apps
  2. Click + CreateCanvas app from blank
  3. App name: Document Summarizer
  4. Format: Tablet
  5. Click Create

Step 26: Connect to Dataverse

  1. Click Data (left panel)
  2. Click + Add data
  3. Search for Dataverse
  4. Select Documents table
  5. Select Summaries table
  6. Click Connect

Step 27: Build Upload Screen

  1. Add Label (Title):

    • Text: "AI Document Summarizer"
    • Font size: 24
    • Position: Top center
  2. Add File Upload control:

    • Insert → Input → Add picture
    • Rename to: FileUpload
    • Position: Center
  3. Add Button (Upload):

    • Text: "Upload Document"
    • OnSelect:
Patch(
    Documents,
    Defaults(Documents),
    {
        'Document Name': FileUpload.FileName,
        'File Content': FileUpload.Image,
        'File Type': If(
            EndsWith(FileUpload.FileName, ".pdf"),
            'File Type (Documents)'.PDF,
            'File Type (Documents)'.DOCX
        ),
        'Upload Date': Now(),
        'Processing Status': 'Processing Status (Documents)'.Pending,
        'Uploaded By': User()
    }
);
Notify("Document uploaded successfully!", NotificationType.Success);
Reset(FileUpload)

Step 28: Build Gallery Screen

  1. Add Gallery (Vertical):

    • Insert → Gallery → Vertical
    • Data source: Filter(Documents, 'Uploaded By'.'Primary Email' = User().Email)
    • Fields: Document Name, Upload Date, Processing Status
  2. Add Search box:

    • Insert → Input → Text input
    • Update Gallery Items:
Filter(
    Documents,
    'Uploaded By'.'Primary Email' = User().Email &&
    (IsBlank(SearchBox.Text) || StartsWith('Document Name', SearchBox.Text))
)

Step 29: Build Detail Screen

  1. Add Form (Display):

    • Insert → Forms → Display form
    • Data source: Summaries
    • Item: LookUp(Summaries, Document = Gallery.Selected)
  2. Add Labels:

    • Document Name
    • Processing Status
    • Summary Text (multiline)
    • Processing Time
    • Estimated Cost
  3. Add Rating control:

    • Insert → Input → Rating
    • Default: ThisItem.'Quality Rating'
    • OnChange: Update Summaries table

Step 30: Publish App

  1. Click FileSave
  2. Click Publish
  3. Click Publish this version
  4. Share with users

Part 6: Testing & Validation

Step 31: Test End-to-End

  1. Upload a test PDF document
  2. Verify flow triggers
  3. Check document status updates
  4. Verify summary is created
  5. Check cost calculation

Step 32: Monitor Performance

  1. Go to Power AutomateMy flows
  2. Click on your flow → Analytics
  3. Monitor:
    • Success rate
    • Average duration
    • Error rate

Step 33: Monitor Costs

  1. Go to Azure PortalCost Management
  2. Filter by Azure OpenAI resource
  3. Set up budget alerts:
    • Budget: $100/month
    • Alert at: 80%, 100%

Configuration Summary

Azure OpenAI:

Resource Name: openai-doc-summarizer
Region: East US
Deployment: gpt-4o
API Version: 2024-10-01-preview
Endpoint: https://openai-doc-summarizer.openai.azure.com/

Dataverse Tables:

  • Documents (cr_documents)
  • Summaries (cr_summaries)

Power Automate Flow:

  • Trigger: Dataverse row added
  • Actions: Convert → Summarize → Store

Power Apps:

  • Upload Screen
  • Gallery Screen
  • Detail Screen

Troubleshooting

Issue: Flow fails with 401 Unauthorized

  • Check API key is correct
  • Verify service principal has Cognitive Services OpenAI User role

Issue: Flow times out

  • Reduce chunk size
  • Increase flow timeout settings
  • Check document size limits

Issue: High costs

  • Implement caching for duplicate documents
  • Reduce max_tokens parameter
  • Monitor token usage in flow

Issue: Poor summary quality

  • Adjust temperature (lower = more focused)
  • Refine system prompt
  • Increase max_tokens for longer summaries

Next Steps

  1. ✅ Deploy to production environment
  2. ✅ Train users on the application
  3. ✅ Set up monitoring dashboards
  4. ✅ Configure backup and disaster recovery
  5. ✅ Document operational procedures

Support: contact@rkneela.com
Repository: https://github.com/rkneela0912/AI-Powered-Document-Summarizer