Skip to content

Commit a70b07c

Browse files
Groenbech96Magnus Hartvig GrønbechJose Antonio Garcia Garciaencimita
authored
Azure Document Intelligence Module (#2834)
Azure Document Intelligence support - OnPrem for now. Uptake available for 1p apps. - Move capabilities to Capabilities Impl Codeunit. - Introduce Azure AI Service Enum. - Hide Azure Doc Int. capabilities on the copilot pages based on PM feedback. [AB#563692](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/563692) --------- Co-authored-by: Magnus Hartvig Grønbech <[email protected]> Co-authored-by: Jose Antonio Garcia Garcia <[email protected]> Co-authored-by: encimita <[email protected]>
1 parent 7ec065f commit a70b07c

15 files changed

+661
-206
lines changed

src/System Application/App/AI/app.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@
9090
"idRanges": [
9191
{
9292
"from": 7757,
93-
"to": 7778
93+
"to": 7780
9494
}
9595
],
9696
"target": "OnPrem",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// ------------------------------------------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All rights reserved.
3+
// Licensed under the MIT License. See License.txt in the project root for license information.
4+
// ------------------------------------------------------------------------------------------------
5+
namespace System.AI.DocumentIntelligence;
6+
7+
/// <summary>
8+
/// The supported model types for Azure Document Intelligence.
9+
/// </summary>
10+
enum 7779 "ADI Model Type"
11+
{
12+
Access = Public;
13+
Extensible = false;
14+
15+
/// <summary>
16+
/// Invoice model type.
17+
/// </summary>
18+
value(0; Invoice)
19+
{
20+
}
21+
22+
/// <summary>
23+
/// Receipt model type.
24+
/// </summary>
25+
value(1; Receipt)
26+
{
27+
}
28+
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
// ------------------------------------------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All rights reserved.
3+
// Licensed under the MIT License. See License.txt in the project root for license information.
4+
// ------------------------------------------------------------------------------------------------
5+
namespace System.AI.DocumentIntelligence;
6+
7+
using System.Telemetry;
8+
using System;
9+
using System.AI;
10+
11+
/// <summary>
12+
/// Azure Document Intelligence implementation.
13+
/// </summary>
14+
codeunit 7779 "Azure DI Impl." implements "AI Service Name"
15+
{
16+
Access = Internal;
17+
InherentEntitlements = X;
18+
InherentPermissions = X;
19+
20+
var
21+
CopilotCapabilityImpl: Codeunit "Copilot Capability Impl";
22+
FeatureTelemetry: Codeunit "Feature Telemetry";
23+
AzureDocumentIntelligenceCapabilityTok: Label 'ADI', Locked = true;
24+
TelemetryAnalyzeInvoiceFailureLbl: Label 'Analyze invoice failed.', Locked = true;
25+
TelemetryAnalyzeInvoiceCompletedLbl: Label 'Analyze invoice completed.', Locked = true;
26+
TelemetryAnalyzeReceiptFailureLbl: Label 'Analyze receipt failed.', Locked = true;
27+
TelemetryAnalyzeReceiptCompletedLbl: Label 'Analyze receipt completed.', Locked = true;
28+
GenerateRequestFailedErr: Label 'The request did not return a success status code.';
29+
AzureAiDocumentIntelligenceTxt: Label 'Azure AI Document Intelligence', Locked = true;
30+
CapabilityNotEnabledErr: Label 'Copilot capability ''%1'' has not been enabled. Please contact your system administrator.', Comment = '%1 is the name of the Copilot Capability';
31+
32+
procedure SetCopilotCapability(Capability: Enum "Copilot Capability"; CallerModuleInfo: ModuleInfo)
33+
begin
34+
CopilotCapabilityImpl.SetCopilotCapability(Capability, CallerModuleInfo, Enum::"Azure AI Service Type"::"Azure Document Intelligence");
35+
end;
36+
37+
procedure RegisterCopilotCapability(CopilotCapability: Enum "Copilot Capability"; CopilotAvailability: Enum "Copilot Availability"; LearnMoreUrl: Text[2048]; CallerModuleInfo: ModuleInfo)
38+
begin
39+
CopilotCapabilityImpl.RegisterCapability(CopilotCapability, CopilotAvailability, Enum::"Azure AI Service Type"::"Azure Document Intelligence", LearnMoreUrl, CallerModuleInfo);
40+
end;
41+
42+
/// <summary>
43+
/// Analyze a single invoice.
44+
/// </summary>
45+
/// <param name="Base64Data">Data to analyze.</param>
46+
/// <param name="CallerModuleInfo">The module info of the caller.</param>
47+
/// <returns>The analyzed result.</returns>
48+
procedure AnalyzeInvoice(Base64Data: Text; CallerModuleInfo: ModuleInfo) Result: Text
49+
var
50+
CustomDimensions: Dictionary of [Text, Text];
51+
begin
52+
CopilotCapabilityImpl.CheckCapabilitySet();
53+
if not CopilotCapabilityImpl.IsCapabilityActive(CallerModuleInfo) then
54+
Error(CapabilityNotEnabledErr, CopilotCapabilityImpl.GetCapabilityName());
55+
56+
CopilotCapabilityImpl.CheckCapabilityServiceType(Enum::"Azure AI Service Type"::"Azure Document Intelligence");
57+
CopilotCapabilityImpl.AddTelemetryCustomDimensions(CustomDimensions, CallerModuleInfo);
58+
59+
if not SendRequest(Base64Data, Enum::"ADI Model Type"::Invoice, CallerModuleInfo, Result) then begin
60+
FeatureTelemetry.LogError('0000OLK', AzureDocumentIntelligenceCapabilityTok, TelemetryAnalyzeInvoiceFailureLbl, GetLastErrorText(), '', Enum::"AL Telemetry Scope"::All, CustomDimensions);
61+
exit;
62+
end;
63+
64+
FeatureTelemetry.LogUsage('0000OLM', AzureDocumentIntelligenceCapabilityTok, TelemetryAnalyzeInvoiceCompletedLbl, Enum::"AL Telemetry Scope"::All, CustomDimensions);
65+
end;
66+
67+
/// <summary>
68+
/// Analyze a single receipt.
69+
/// </summary>
70+
/// <param name="Base64Data">Data to analyze.</param>
71+
/// <param name="CallerModuleInfo">The module info of the caller.</param>
72+
/// <returns>The analyzed result.</returns>
73+
procedure AnalyzeReceipt(Base64Data: Text; CallerModuleInfo: ModuleInfo) Result: Text
74+
var
75+
CustomDimensions: Dictionary of [Text, Text];
76+
begin
77+
CopilotCapabilityImpl.CheckCapabilitySet();
78+
if not CopilotCapabilityImpl.IsCapabilityActive(CallerModuleInfo) then
79+
Error(CapabilityNotEnabledErr, CopilotCapabilityImpl.GetCapabilityName());
80+
81+
CopilotCapabilityImpl.AddTelemetryCustomDimensions(CustomDimensions, CallerModuleInfo);
82+
83+
if not SendRequest(Base64Data, Enum::"ADI Model Type"::Receipt, CallerModuleInfo, Result) then begin
84+
FeatureTelemetry.LogError('0000OLL', AzureDocumentIntelligenceCapabilityTok, TelemetryAnalyzeReceiptFailureLbl, GetLastErrorText(), '', Enum::"AL Telemetry Scope"::All, CustomDimensions);
85+
exit;
86+
end;
87+
88+
FeatureTelemetry.LogUsage('0000OLN', AzureDocumentIntelligenceCapabilityTok, TelemetryAnalyzeReceiptCompletedLbl, Enum::"AL Telemetry Scope"::All, CustomDimensions);
89+
end;
90+
91+
[TryFunction]
92+
[NonDebuggable]
93+
local procedure SendRequest(Base64Data: Text; ModelType: Enum "ADI Model Type"; CallerModuleInfo: ModuleInfo; var Result: Text)
94+
var
95+
ALCopilotFunctions: DotNet ALCopilotFunctions;
96+
ALCopilotCapability: DotNet ALCopilotCapability;
97+
ALCopilotResponse: DotNet ALCopilotOperationResponse;
98+
ErrorMsg: Text;
99+
begin
100+
ClearLastError();
101+
ALCopilotCapability := ALCopilotCapability.ALCopilotCapability(CallerModuleInfo.Publisher(), CallerModuleInfo.Id(), Format(CallerModuleInfo.AppVersion()), AzureDocumentIntelligenceCapabilityTok);
102+
case ModelType of
103+
Enum::"ADI Model Type"::Invoice:
104+
ALCopilotResponse := ALCopilotFunctions.GenerateInvoiceIntelligence(GenerateJsonForSingleInput(Base64Data), ALCopilotCapability);
105+
Enum::"ADI Model Type"::Receipt:
106+
ALCopilotResponse := ALCopilotFunctions.GenerateReceiptIntelligence(GenerateJsonForSingleInput(Base64Data), ALCopilotCapability);
107+
end;
108+
ErrorMsg := ALCopilotResponse.ErrorText();
109+
if ErrorMsg <> '' then
110+
Error(ErrorMsg);
111+
112+
if not ALCopilotResponse.IsSuccess() then
113+
Error(GenerateRequestFailedErr);
114+
115+
Result := ALCopilotResponse.Result();
116+
end;
117+
118+
local procedure GenerateJsonForSingleInput(Base64: Text): Text
119+
var
120+
JsonObject: JsonObject;
121+
InputsObject: JsonObject;
122+
InnerObject: JsonObject;
123+
JsonText: Text;
124+
begin
125+
// Create the inner object with the base64Encoded property
126+
InnerObject.Add('base64_encoded', Base64);
127+
// Create the inputs object and add the inner object to it
128+
InputsObject.Add('1', InnerObject);
129+
// Create the main JSON object and add the inputs object to it
130+
JsonObject.Add('inputs', InputsObject);
131+
// Convert the JSON object to text
132+
JsonObject.WriteTo(JsonText);
133+
// Return the JSON text
134+
exit(JsonText);
135+
end;
136+
137+
procedure GetServiceName(): Text[250]
138+
begin
139+
exit(AzureAiDocumentIntelligenceTxt);
140+
end;
141+
142+
procedure GetServiceId(): Code[50];
143+
begin
144+
exit(AzureAiDocumentIntelligenceTxt);
145+
end;
146+
147+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// ------------------------------------------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All rights reserved.
3+
// Licensed under the MIT License. See License.txt in the project root for license information.
4+
// ------------------------------------------------------------------------------------------------
5+
namespace System.AI.DocumentIntelligence;
6+
7+
using System.AI;
8+
9+
/// <summary>
10+
/// Provides functionality to invoke Azure Document Intelligence services.
11+
/// </summary>
12+
codeunit 7780 "Azure Document Intelligence"
13+
{
14+
Access = Public;
15+
InherentEntitlements = X;
16+
InherentPermissions = X;
17+
18+
var
19+
AzureDIImpl: Codeunit "Azure DI Impl.";
20+
21+
/// <summary>
22+
/// Analyze the invoice.
23+
/// </summary>
24+
/// <param name="Base64Data">Data to analyze.</param>
25+
/// <returns>The analyzed result.</returns>
26+
[Scope('OnPrem')]
27+
procedure AnalyzeInvoice(Base64Data: Text): Text
28+
var
29+
CallerModuleInfo: ModuleInfo;
30+
begin
31+
NavApp.GetCallerModuleInfo(CallerModuleInfo);
32+
exit(AzureDIImpl.AnalyzeInvoice(Base64Data, CallerModuleInfo));
33+
end;
34+
35+
/// <summary>
36+
/// Analyze the Receipt.
37+
/// </summary>
38+
/// <param name="Base64Data">Data to analyze.</param>
39+
/// <returns>The analyzed result.</returns>
40+
[Scope('OnPrem')]
41+
procedure AnalyzeReceipt(Base64Data: Text): Text
42+
var
43+
CallerModuleInfo: ModuleInfo;
44+
begin
45+
NavApp.GetCallerModuleInfo(CallerModuleInfo);
46+
exit(AzureDIImpl.AnalyzeReceipt(Base64Data, CallerModuleInfo));
47+
end;
48+
49+
/// <summary>
50+
/// Register a capability for Azure Document Intelligence.
51+
/// </summary>
52+
/// <param name="CopilotCapability">The capability.</param>
53+
/// <param name="CopilotAvailability">The availability.</param>
54+
/// <param name="LearnMoreUrl">The learn more url.</param>
55+
procedure RegisterCopilotCapability(CopilotCapability: Enum "Copilot Capability"; CopilotAvailability: Enum "Copilot Availability"; LearnMoreUrl: Text[2048])
56+
var
57+
CallerModuleInfo: ModuleInfo;
58+
begin
59+
NavApp.GetCallerModuleInfo(CallerModuleInfo);
60+
AzureDIImpl.RegisterCopilotCapability(CopilotCapability, CopilotAvailability, LearnMoreUrl, CallerModuleInfo);
61+
end;
62+
63+
/// <summary>
64+
/// Sets the copilot capability that the API is running for.
65+
/// </summary>
66+
/// <param name="CopilotCapability">The copilot capability to set.</param>
67+
procedure SetCopilotCapability(CopilotCapability: Enum "Copilot Capability")
68+
var
69+
CallerModuleInfo: ModuleInfo;
70+
begin
71+
NavApp.GetCallerModuleInfo(CallerModuleInfo);
72+
AzureDIImpl.SetCopilotCapability(CopilotCapability, CallerModuleInfo);
73+
end;
74+
75+
}

src/System Application/App/AI/src/Azure OpenAI/AzureOpenAI.Codeunit.al

+1
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ codeunit 7771 "Azure OpenAI"
270270
NavApp.GetCallerModuleInfo(CallerModuleInfo);
271271
AzureOpenAIImpl.SetCopilotCapability(CopilotCapability, CallerModuleInfo);
272272
end;
273+
273274
#if not CLEAN24
274275
/// <summary>
275276
/// Gets the approximate token count for the input.

0 commit comments

Comments
 (0)