0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GPT4.1 と Logic Apps で簡単OCR

Posted at

背景

GPT4.1 使うと、OCR 出来そうだったんで Logic Apps で やってみた

OCR の精度自体は満足できるもので、Teams チャット用にできたら便利そうだった。

概要

Teams チャットに貼り付けた画像は、取得権限なさそうだったので、
Microsoft Lists へ Forms UI から投稿させて使うことにしてみた

  1. Forms UI で画像投稿
  2. 添付ファイル(画像も添付ファイル扱い)を取得
  3. 添付ファイルを、OpenAPI Action へ渡して テキスト抽出
  4. 投稿者に、チャットで通知

image.png

取得画像から、API 用 param の作成

以下の観点から、本当なら type: image_url に URL で渡す方が良い。

  • Token 消費量

Storage を用意する必要があるので、今回は base64 にして渡すことにした。

ファイルサイズが大きい場合の対処も本来なら必要

image.png

content を複数ファイルで作っているので、そのまま渡す

type: text がもしあれば、変数の初期化時に設定しておく

image.png

あとがき

Teams チャットでできればもうちょい便利なんですけどね・・
最近 Graph API が制約厳しいので、添付ファイル取得 API とか出してくれないと、会社じゃ無理かな。
※HostedContents, Attachements を取得すればいいだけなので、
 適切に権限設定出来るならオススメ

Code 例

{
    "definition": {
        "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
        "contentVersion": "1.0.0.0",
        "triggers": {
            "項目が作成されたとき": {
                "type": "ApiConnection",
                "inputs": {
                    "host": {
                        "connection": {
                            "name": "@parameters('$connections')['sharepointonline']['connectionId']"
                        }
                    },
                    "method": "get",
                    "path": "/datasets/@{encodeURIComponent(encodeURIComponent('https://{tenant.sharepoint.com}/personal/{username}'))}/tables/@{encodeURIComponent(encodeURIComponent('{list-id}'))}/onnewitems"
                },
                "recurrence": {
                    "interval": 3,
                    "frequency": "Minute"
                },
                "splitOn": "@triggerBody()?['value']"
            }
        },
        "actions": {
            "For_each": {
                "type": "Foreach",
                "foreach": "@body('添付ファイルの取得')",
                "actions": {
                    "Append_to_array_variable": {
                        "type": "AppendToArrayVariable",
                        "inputs": {
                            "name": "Base64Images",
                            "value": {
                                "type": "image_url",
                                "image_url": {
                                    "url": "data:@{body('添付ファイルのコンテンツの取得')['$Content-Type']};base64,@{body('添付ファイルのコンテンツの取得')['$Content']}"
                                }
                            }
                        },
                        "runAfter": {
                            "添付ファイルのコンテンツの取得": [
                                "SUCCEEDED"
                            ]
                        }
                    },
                    "添付ファイルのコンテンツの取得": {
                        "type": "ApiConnection",
                        "inputs": {
                            "host": {
                                "connection": {
                                    "name": "@parameters('$connections')['sharepointonline']['connectionId']"
                                }
                            },
                            "method": "get",
                            "path": "/datasets/@{encodeURIComponent(encodeURIComponent('https://{tenant.sharepoint.com}/personal/{username}'))}/tables/@{encodeURIComponent(encodeURIComponent('{list-id}'))}/items/@{encodeURIComponent(encodeURIComponent(triggerBody()?['ID']))}/attachments/@{encodeURIComponent(item()?['Id'])}/$value"
                        }
                    }
                },
                "runAfter": {
                    "Compose_Prompt": [
                        "Succeeded"
                    ],
                    "添付ファイルの取得": [
                        "SUCCEEDED"
                    ]
                }
            },
            "項目の取得": {
                "type": "ApiConnection",
                "inputs": {
                    "host": {
                        "connection": {
                            "name": "@parameters('$connections')['sharepointonline']['connectionId']"
                        }
                    },
                    "method": "get",
                    "path": "/datasets/@{encodeURIComponent(encodeURIComponent('https://{tenant.sharepoint.com}/personal/{username}'))}/tables/@{encodeURIComponent(encodeURIComponent('{list-id}'))}/items/@{encodeURIComponent(triggerBody()?['ID'])}"
                },
                "runAfter": {
                    "Initialize_variables_Messages": [
                        "Succeeded"
                    ]
                }
            },
            "Initialize_variables_Messages": {
                "type": "InitializeVariable",
                "inputs": {
                    "variables": [
                        {
                            "name": "Base64Images",
                            "type": "array",
                            "value": [
                                {
                                    "type": "text",
                                    "text": "what's in this image?"
                                }
                            ]
                        }
                    ]
                },
                "runAfter": {}
            },
            "Creates_a_completion_for_the_chat_message-copy": {
                "type": "ApiConnection",
                "inputs": {
                    "host": {
                        "connection": {
                            "name": "@parameters('$connections')['azureopenai']['connectionId']"
                        }
                    },
                    "method": "post",
                    "body": {
                        "messages": [
                            {
                                "role": "system",
                                "content": "@{outputs('Compose_Prompt')}"
                            },
                            {
                                "role": "user",
                                "content": "@variables('Base64Images')"
                            }
                        ],
                        "temperature": 1,
                        "top_p": 1,
                        "stream": false,
                        "stop": null,
                        "max_tokens": 15000,
                        "presence_penalty": 0,
                        "frequency_penalty": 0,
                        "n": 1,
                        "seed": 0,
                        "logprobs": false,
                        "response_format": {
                            "type": "text"
                        }
                    },
                    "path": "/2024-02-15-preview/deployments/@{encodeURIComponent('gpt-4.1-mini')}/chat/completions",
                    "queries": {
                        "api-version": "2025-04-01-preview"
                    }
                },
                "runAfter": {
                    "For_each": [
                        "Succeeded"
                    ]
                }
            },
            "For_each_いつも_[0]_とはいえ、面倒なのでこのまま_": {
                "type": "Foreach",
                "foreach": "@body('Creates_a_completion_for_the_chat_message-copy')['choices']",
                "actions": {
                    "チャットまたはチャネルでメッセージを投稿する": {
                        "type": "ApiConnection",
                        "inputs": {
                            "host": {
                                "connection": {
                                    "name": "@parameters('$connections')['teams']['connectionId']"
                                }
                            },
                            "method": "post",
                            "body": {
                                "recipient": "@triggerBody()?['Author']?['Email']",
                                "messageBody": "<p class=\"editor-paragraph\">@{items('For_each_いつも_[0]_とはいえ、面倒なのでこのまま_')?['message']?['content']}</p>"
                            },
                            "path": "/beta/teams/conversation/message/poster/Flow bot/location/@{encodeURIComponent('Chat with Flow bot')}"
                        }
                    },
                    "項目の更新": {
                        "type": "ApiConnection",
                        "inputs": {
                            "host": {
                                "connection": {
                                    "name": "@parameters('$connections')['sharepointonline']['connectionId']"
                                }
                            },
                            "method": "patch",
                            "body": {
                                "Done": true
                            },
                            "path": "/datasets/@{encodeURIComponent(encodeURIComponent('https://{tenant.sharepoint.com}/personal/{username}'))}/tables/@{encodeURIComponent(encodeURIComponent('{list-id}'))}/items/@{encodeURIComponent(triggerBody()?['ID'])}"
                        },
                        "runAfter": {
                            "チャットまたはチャネルでメッセージを投稿する": [
                                "SUCCEEDED"
                            ]
                        }
                    }
                },
                "runAfter": {
                    "Creates_a_completion_for_the_chat_message-copy": [
                        "Succeeded"
                    ]
                }
            },
            "Compose_Prompt": {
                "type": "Compose",
                "description": "抽出した文字をHTML構造で返してください(```html などは不要)。1.画像解析の基本\\n画像を解析する際は、走査線をイメージして解析してください。左上から右へ、走査線のように移動しつつ、右下まで解析を行います。\\n2.色の再現\\n画像内の色彩を正確に再現するために、使用されている色のパレットやトーンを明確に記述してください。具体的な色使いの説明を加え、色の変化や影響を考慮します。\\n3.構図の再現\\n画像の構図を意識し、要素の配置やバランスを考慮してください。視線の流れを意識し、重要な情報や要素を効",
                "inputs": "@if(equals(triggerBody()?['Prompt'],null), '抽出した文字をHTML構造で返してください(```html などは不要)。1.画像解析の基本\n画像を解析する際は、走査線をイメージして解析してください。左上から右へ、走査線のように移動しつつ、右下まで解析を行います。\n2.色の再現\n画像内の色彩を正確に再現するために、使用されている色のパレットやトーンを明確に記述してください。具体的な色使いの説明を加え、色の変化や影響を考慮します。\n3.構図の再現\n画像の構図を意識し、要素の配置やバランスを考慮してください。視線の流れを意識し、重要な情報や要素を効果的に配置することで、視覚的なインパクトを高めます。\n4.表の再現\nデータを整理して視覚的にわかりやすくするために、表形式で情報を提示します。見出しやデータの配置、色使いに注意を払い、視認性を高めることを心がけます。\n', triggerBody()?['Prompt'])",
                "runAfter": {
                    "項目の取得": [
                        "Succeeded"
                    ]
                }
            },
            "添付ファイルの取得": {
                "type": "ApiConnection",
                "inputs": {
                    "host": {
                        "connection": {
                            "name": "@parameters('$connections')['sharepointonline']['connectionId']"
                        }
                    },
                    "method": "get",
                    "path": "/datasets/@{encodeURIComponent(encodeURIComponent('https://{tenant.sharepoint.com}/personal/{username}'))}/tables/@{encodeURIComponent(encodeURIComponent('{list-id}'))}/items/@{encodeURIComponent(encodeURIComponent(triggerBody()?['ID']))}/attachments"
                },
                "runAfter": {
                    "Initialize_variables_Messages": [
                        "SUCCEEDED"
                    ]
                }
            }
        },
        "outputs": {},
        "parameters": {
            "$connections": {
                "type": "Object",
                "defaultValue": {}
            }
        }
    },
    "parameters": {
        "$connections": {
            "type": "Object",
            "value": {
                "sharepointonline": {
                    "id": "/subscriptions/{subscription-id}/providers/Microsoft.Web/locations/northcentralus/managedApis/sharepointonline",
                    "connectionId": "/subscriptions/{subscription-id}/resourceGroups/chatbot_choji/providers/Microsoft.Web/connections/sharepointonline",
                    "connectionName": "sharepointonline"
                },
                "azureopenai": {
                    "id": "/subscriptions/{subscription-id}/providers/Microsoft.Web/locations/northcentralus/managedApis/azureopenai",
                    "connectionId": "/subscriptions/{subscription-id}/resourceGroups/chatbot_choji/providers/Microsoft.Web/connections/azureopenai-4",
                    "connectionName": "azureopenai-4"
                },
                "teams": {
                    "id": "/subscriptions/{subscription-id}/providers/Microsoft.Web/locations/northcentralus/managedApis/teams",
                    "connectionId": "/subscriptions/{subscription-id}/resourceGroups/chatbot_choji/providers/Microsoft.Web/connections/teams",
                    "connectionName": "teams"
                }
            }
        }
    }
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?