我正在经历一生中最糟糕的时光,试图让这个电源自动流程发挥作用。
我制作了一个 Power Automate 流程,用于从发票中提取采购订单。收件箱中的每封新电子邮件都会触发它。我正在循环浏览 pdf 附件,调用 AI 构建器从发票中提取信息,并获取采购订单。
我需要更准确的选项来查找采购订单,因此我将提取采购订单的逻辑移至 API 调用。现在,流程只需将 pdf 发送到端点,我就可以处理 C# 中的所有功能,并返回必要的详细信息,以便流程可以继续。
此 API 调用在 Postman 中大约需要 20 秒。 当我尝试在流程中调用它时,它超时了。
我在 API 上附加了一个调试器,我发现当我等待 AI 客户端的响应时,Flow 正在重新发送请求。这会导致无限循环。 我知道对端点的调用正在工作,因为我可以在 AI 调用之前返回 OK 响应,并且它可以工作。
如何让我的 HTTP 请求等待这个结果? 或者是客户端 AI 调用的异步性问题? 我注意到,当我调试时,我的断点总是在第一次调用 aiClient 时丢失,这是调用中的第一个异步操作。
这是 Power Automate 中 HTTP 调用的代码视图
"inputs": {
"method": "POST",
"uri": "REDACTED",
"headers": {
"Connection": "keep-alive",
"Accept": "*/*",
"Host": "REDACTED",
"Accept-Encoding": "gzip, deflate, br"
},
"body": {
"$content-type": "multipart/form-data",
"$multipart": [
{
"headers": {
"Content-Disposition": "form-data; name=\"invoicePdf\"; filename=\"invoicePdf.pdf\""
},
"body": "@outputs('Get_file_content')"
}
]
},
"authentication": {
"type": "Basic",
"username": "REDACTED",
"password": "REDACTED"
}
},
"operationOptions": "DisableAsyncPattern",
"metadata": {
"operationMetadataId": "38dae010-f79b-4c3e-ae7c-22a6047b4151"
}
}
这是我的带有 ai 调用的 C# 方法:
{
// Check if a file was uploaded
if (invoicePdf == null || invoicePdf.Length == 0)
{
return BadRequest("No file uploaded.");
}
// Check if the file is a PDF
if (!invoicePdf.FileName.EndsWith(".pdf"))
{
return BadRequest("Only PDF files are allowed.");
}
AzureKeyCredential credential = new AzureKeyCredential(AppSettings.AzureAiServiceKey);
DocumentAnalysisClient aiClient = new DocumentAnalysisClient(new Uri(AppSettings.AzureAiServiceEndpoint), credential);
//var operation = await aiClient.AnalyzeDocumentAsync(WaitUntil.Completed, "prebuilt-invoice", invoicePdf.OpenReadStream());
var invoiceOperation = aiClient.AnalyzeDocumentAsync(WaitUntil.Completed, "prebuilt-invoice",
invoicePdf.OpenReadStream(), new AnalyzeDocumentOptions
{
Pages = { "1-2" }
}).Result;
var invoiceResult = invoiceOperation.Value;
//check default area
for (int i = 0; i < invoiceResult.Documents.Count; i++)
{
var document = invoiceResult.Documents[i];
//try to find the purchase order from the default area
if (document.Fields.ContainsKey("PurchaseOrder"))
{
document.Fields.TryGetValue("PurchaseOrder", out var purchaseOrderObject);
var purchaseOrderValue = purchaseOrderObject.Content;
var purchaseOrderConfidence = purchaseOrderObject.Confidence;
var sanitizedPurchaseOrderValue = SanitizePurchaseOrder(purchaseOrderValue);
return Ok(new
{
Found = true,
PurchaseOrderValue = sanitizedPurchaseOrderValue,
PurchaseOrderConfidence = purchaseOrderConfidence,
FoundIn = "Default Location"
});
}
}
var layoutOperation = aiClient.AnalyzeDocumentAsync(WaitUntil.Completed, "prebuilt-document",
invoicePdf.OpenReadStream(), new AnalyzeDocumentOptions
{
Pages = { "1-2" }
}).Result;
var layoutResult = layoutOperation.Value;
DocumentKeyValuePair? poKeyValuePair;
poKeyValuePair = layoutResult.KeyValuePairs.FirstOrDefault(x => firstPriorityKeys.Contains(x.Key.Content));
if (poKeyValuePair == null)
{
poKeyValuePair = layoutResult.KeyValuePairs.FirstOrDefault(x => secondPriorityKeys.Contains(x.Key.Content));
if (poKeyValuePair == null)
{
poKeyValuePair = layoutResult.KeyValuePairs.FirstOrDefault(x => thirdPriorityKeys.Contains(x.Key.Content));
if (poKeyValuePair == null)
{
poKeyValuePair = layoutResult.KeyValuePairs.FirstOrDefault(x => fourthPriorityKeys.Contains(x.Key.Content));
if (poKeyValuePair == null)
{
poKeyValuePair = layoutResult.KeyValuePairs.FirstOrDefault(x => fifthPriorityKeys.Contains(x.Key.Content));
}
}
}
}
if (poKeyValuePair != null)
{
var sanitizedPurchaseOrderValue = SanitizePurchaseOrder(poKeyValuePair.Value.Content);
return Ok(new
{
Found = true,
PurchaseOrderValue = sanitizedPurchaseOrderValue,
PurchaseOrderConfidence = poKeyValuePair.Confidence,
FoundIn = $"{poKeyValuePair.Key.Content} (KVP)"
});
}
//check plain text with regex
Regex regex =
new Regex(@"([Pp][Oo]|[Pp][Uu][Rr][Cc][Hh][Aa][Ss][Ee]\s?[Oo][Rr][Dd][Ee][Rr]).{0,3}(\d{7})");
Match match = regex.Match(layoutResult.Content);
if (match.Success)
{
var foundPo = match.Value;
var sanitizedPurchaseOrderValue = SanitizePurchaseOrder(foundPo);
return Ok(new
{
Found = true,
PurchaseOrderValue = sanitizedPurchaseOrderValue,
PurchaseOrderConfidence = 0.5,
FoundIn = "Plain Text Regex Parse"
});
}
return Ok(new
{
Found = false
});
}
总结
多么令人沮丧……我找到了解决方法。
我已更新我的端点以接收 Base64 编码的字符串。
我已更新到 Power Automate 流程以使用获取附件 (V2) 调用,而不是使用新电子邮件触发器的附件。
出于某种原因,它现在可以工作了...我不知道触发器中的附件和呼叫中的附件之间有什么不同,但切换它已经起作用了。
我相当有信心问题是从触发器获取附件,而不是获取附件(V2)调用