n8n書籍スキャナー
上級
これはContent Creation, Multimodal AI分野の自動化ワークフローで、16個のノードを含みます。主にSet, Code, Webhook, HttpRequest, OpenAiなどのノードを使用。 GPT-4oとGoogle Booksを使用して書架から撮影した写真から書籍タイトルを抽出し、検証
前提条件
- •HTTP Webhookエンドポイント(n8nが自動生成)
- •ターゲットAPIの認証情報が必要な場合あり
- •OpenAI API Key
ワークフロープレビュー
ノード接続関係を可視化、ズームとパンをサポート
ワークフローをエクスポート
以下のJSON設定をn8nにインポートして、このワークフローを使用できます
{
"id": "n1UbcJnl7I5rMDIe",
"meta": {
"instanceId": "7d302cb44fba0420b6a4deb04edff9d7c47e83ef1f3f66f89fe519337b882186",
"templateCredsSetupCompleted": true
},
"name": "n8n submission book scanner",
"tags": [],
"nodes": [
{
"id": "8fc53cb4-d7bc-4fcb-8c6d-1ee90b4ad5b4",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
-896,
1376
],
"webhookId": "365ea003-fe66-4211-ae03-69f1456d768e",
"parameters": {
"path": "365ea003-fe66-4211-ae03-69f1456d768e",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2.1
},
{
"id": "a140d496-9098-43b2-97df-089a811a909d",
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
592,
1376
],
"parameters": {
"options": {
"responseCode": 200,
"responseHeaders": {
"entries": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"respondWith": "json",
"responseBody": "={{$json}}"
},
"typeVersion": 1.4
},
{
"id": "050a5432-4d7e-4855-b09f-5ca40a9e0999",
"name": "画像解析",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
-448,
1376
],
"parameters": {
"text": "=You are a STRICT transformer. Analyze the image of book spines and return only clearly readable titles and authors. \nDo NOT guess. If the author isn't clearly visible, set \"author\": null.\nNormalize capitalization. Deduplicate by title. \nOutput STRICT JSON only:\n{\"books\":[{\"title\":\"string\",\"author\":\"string|null\"}]}\n",
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini",
"cachedResultName": "GPT-4O-MINI"
},
"options": {},
"resource": "image",
"imageUrls": "={{$json.image}}\n",
"operation": "analyze"
},
"credentials": {
"openAiApi": {
"id": "iJ4uczBur5RBMvV4",
"name": "OpenAi account"
}
},
"typeVersion": 1.8
},
{
"id": "50c4d4b8-b164-47fb-b9c6-2234f3cb5952",
"name": "付箋",
"type": "n8n-nodes-base.stickyNote",
"position": [
-992,
1280
],
"parameters": {
"height": 80,
"content": "Webhook connects to front end that passes on JSON with imageURL (string)"
},
"typeVersion": 1
},
{
"id": "d245e1df-a5a2-487c-bd8f-41601be2f05c",
"name": "付箋1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-736,
1520
],
"parameters": {
"height": 80,
"content": "Input is normalized"
},
"typeVersion": 1
},
{
"id": "2c44a9af-f395-45ff-bf4f-91a55c829d3e",
"name": "付箋2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-512,
1280
],
"parameters": {
"height": 80,
"content": "Image is analyzed and transformed."
},
"typeVersion": 1
},
{
"id": "1ec82294-d70b-4ff6-ab34-c7ef156a41b2",
"name": "付箋3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-288,
1520
],
"parameters": {
"content": "Splits the output (in this case, books) into individual items in preparation for the next step which is to verify the book against a known source to confirm the title and author."
},
"typeVersion": 1
},
{
"id": "44f65fae-f829-4b6b-976b-001d071b82ee",
"name": "付箋4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-96,
1280
],
"parameters": {
"height": 80,
"content": "Confirms each title against Google Books"
},
"typeVersion": 1
},
{
"id": "917a2da3-3691-4904-8cbc-4c00ee4ed72e",
"name": "付箋5",
"type": "n8n-nodes-base.stickyNote",
"position": [
112,
1536
],
"parameters": {
"height": 80,
"content": "Normalizes data"
},
"typeVersion": 1
},
{
"id": "62b507e0-5b7d-48a3-9e44-aa4ccf339331",
"name": "付箋6",
"type": "n8n-nodes-base.stickyNote",
"position": [
304,
1280
],
"parameters": {
"height": 80,
"content": "Reaggregates book list and dedupes"
},
"typeVersion": 1
},
{
"id": "94b96cbc-3bd4-4db8-83ff-eb57b4e516c3",
"name": "付箋7",
"type": "n8n-nodes-base.stickyNote",
"position": [
544,
1520
],
"parameters": {
"height": 80,
"content": "Returns list back to frontend."
},
"typeVersion": 1
},
{
"id": "c4796062-4c64-474a-85b9-8306585c18b1",
"name": "入力正規化",
"type": "n8n-nodes-base.set",
"position": [
-672,
1376
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "94b88376-fed9-46cf-882f-d4c0d7670350",
"name": "image",
"type": "string",
"value": "={{ ($json.body?.imageUrl || $json.body?.image || $json.imageUrl || $json.image || '').trim() }}\n"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "dbe25007-44da-403b-89bf-bcbf57591d58",
"name": "アイテムリスト分割",
"type": "n8n-nodes-base.code",
"position": [
-240,
1376
],
"parameters": {
"jsCode": "const items = await $input.all();\nconst out = [];\n\nfunction stripCodeFence(s) {\n return String(s || '')\n .replace(/^```json\\s*/i, '')\n .replace(/^```\\s*/i, '')\n .replace(/```$/, '')\n .trim();\n}\n\nfunction firstAuthor(a) {\n if (!a) return null;\n // keep a single name for better \"inauthor:\" matching\n const s = String(a);\n const parts = s.split(/\\s*(?:,| and |&)\\s*/i);\n return (parts[0] || '').trim() || null;\n}\n\nfor (const item of items) {\n let books = null;\n\n // Case 1: you already have an object with books[]\n if (Array.isArray(item.json?.books)) {\n books = item.json.books;\n }\n\n // Case 2: you have a string in `content` with ```json ... ```\n if (!books && typeof item.json?.content === 'string') {\n const cleaned = stripCodeFence(item.json.content);\n try {\n const parsed = JSON.parse(cleaned);\n if (Array.isArray(parsed.books)) books = parsed.books;\n } catch (e) {\n // ignore; we'll fall back\n }\n }\n\n if (!books) continue;\n\n for (const b of books) {\n out.push({\n json: {\n title: b.title,\n author: b.author ?? null,\n // helper field only for the search query:\n searchAuthor: firstAuthor(b.author)\n }\n });\n }\n}\n\nreturn out;\n"
},
"typeVersion": 2
},
{
"id": "2017d011-6d85-4844-a08a-0a7e88ae052d",
"name": "書名検証",
"type": "n8n-nodes-base.httpRequest",
"position": [
-32,
1376
],
"parameters": {
"url": "https://www.googleapis.com/books/v1/volumes",
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
},
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "=q",
"value": "={{ \n 'intitle:\"' + $json.title.replace(/\"/g,'') + '\"' +\n ($json.searchAuthor ? ' inauthor:\"' + $json.searchAuthor.replace(/\"/g,'') + '\"' : '')\n}}\n"
},
{
"name": "maxResults",
"value": "5"
},
{
"name": "printType",
"value": "books"
},
{
"name": "orderBy",
"value": "relevance"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "7d94ce36-fc7c-44cb-8df6-6f13293160a4",
"name": "データ正規化",
"type": "n8n-nodes-base.set",
"position": [
176,
1376
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "67464bb0-8615-41a5-8408-11a95708d200",
"name": "=title",
"type": "string",
"value": "={{ $json.items?.[0]?.volumeInfo?.title || $prevNode('Code').json.title }}\n"
},
{
"id": "8db9c2f0-3193-428e-adab-2745f397233c",
"name": "author",
"type": "string",
"value": "={{ $json.items?.[0]?.volumeInfo?.authors?.[0] || $prevNode('Code').json.author || null }}\n"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "99d74571-f35d-4086-93ce-f7f67768a8f0",
"name": "リスト再集約",
"type": "n8n-nodes-base.code",
"position": [
384,
1376
],
"parameters": {
"jsCode": "const items = await $input.all();\nconst seen = new Set();\nconst books = [];\n\nfor (const it of items) {\n const t = (it.json.title || '').toLowerCase().trim();\n if (t && !seen.has(t)) {\n seen.add(t);\n books.push({ title: it.json.title, author: it.json.author ?? null });\n }\n}\n\nreturn [{ json: { books } }];\n"
},
"typeVersion": 2
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "5f454fe8-f8b7-4302-820e-ec24a00f13bd",
"connections": {
"8fc53cb4-d7bc-4fcb-8c6d-1ee90b4ad5b4": {
"main": [
[
{
"node": "c4796062-4c64-474a-85b9-8306585c18b1",
"type": "main",
"index": 0
}
]
]
},
"050a5432-4d7e-4855-b09f-5ca40a9e0999": {
"main": [
[
{
"node": "dbe25007-44da-403b-89bf-bcbf57591d58",
"type": "main",
"index": 0
}
]
]
},
"7d94ce36-fc7c-44cb-8df6-6f13293160a4": {
"main": [
[
{
"node": "99d74571-f35d-4086-93ce-f7f67768a8f0",
"type": "main",
"index": 0
}
]
]
},
"dbe25007-44da-403b-89bf-bcbf57591d58": {
"main": [
[
{
"node": "2017d011-6d85-4844-a08a-0a7e88ae052d",
"type": "main",
"index": 0
}
]
]
},
"c4796062-4c64-474a-85b9-8306585c18b1": {
"main": [
[
{
"node": "050a5432-4d7e-4855-b09f-5ca40a9e0999",
"type": "main",
"index": 0
}
]
]
},
"2017d011-6d85-4844-a08a-0a7e88ae052d": {
"main": [
[
{
"node": "7d94ce36-fc7c-44cb-8df6-6f13293160a4",
"type": "main",
"index": 0
}
]
]
},
"99d74571-f35d-4086-93ce-f7f67768a8f0": {
"main": [
[
{
"node": "a140d496-9098-43b2-97df-089a811a909d",
"type": "main",
"index": 0
}
]
]
}
}
}よくある質問
このワークフローの使い方は?
上記のJSON設定コードをコピーし、n8nインスタンスで新しいワークフローを作成して「JSONからインポート」を選択、設定を貼り付けて認証情報を必要に応じて変更してください。
このワークフローはどんな場面に適していますか?
上級 - コンテンツ作成, マルチモーダルAI
有料ですか?
このワークフローは完全無料です。ただし、ワークフローで使用するサードパーティサービス(OpenAI APIなど)は別途料金が発生する場合があります。
関連ワークフロー
会議議事録とアクションアイテムトラッカー
AIベースの会議議事録:GPT-4の活用、タスク割り当て、マルチチャネル配信
If
Set
Code
+
If
Set
Code
38 ノードJitesh Dugar
コンテンツ作成
コンテンツジェネレーター
GPT-4 モデルの戦略の方法を採用した AI によるソーシャルメディアコンテンツ生成ツール
Set
Code
Webhook
+
Set
Code
Webhook
22 ノードinderjeet Bhambra
コンテンツ作成
リード呼出を自動化:VAPI、Googleスheetsへの記録、カレンダー予約
リード呼出の自動化:VAPI、Googleスプレッドシートへの記録とカレンダー予約
Set
Code
Webhook
+
Set
Code
Webhook
13 ノードMeak
コンテンツ作成
AIを使ってWordPress記事を書く(キーワードいくつかから始める)
GPT-4、DALL-E、Wikipediaを基にした自動ブログ記事生成ツール(WordPress向け)
If
Set
Code
+
If
Set
Code
37 ノードPunit
コンテンツ作成
OpenAI・LangChain・アピ業間連携によるワークフレーム自動化入門ガイド
OpenAI、LangChain、API を使用したワークフロー自動化の初心者ガイド
If
Set
Code
+
If
Set
Code
33 ノードMeelioo
コンテンツ作成
Zonosを使ったAPIによるテキスト読み上げ音声クローン(ローカルストレージ)
Zyphra Zonos APIを使ってテキストから音声にボイストリーンク
If
Set
Code
+
If
Set
Code
18 ノードTiartyos
コンテンツ作成