Escáner de libros n8n
Este es unContent Creation, Multimodal AIflujo de automatización del dominio deautomatización que contiene 16 nodos.Utiliza principalmente nodos como Set, Code, Webhook, HttpRequest, OpenAi. Usar GPT-4o y Google Books para extraer y verificar los títulos de libros a partir de fotos de estanterías
- •Punto final de HTTP Webhook (n8n generará automáticamente)
- •Pueden requerirse credenciales de autenticación para la API de destino
- •Clave de API de OpenAI
Nodos utilizados (16)
Categoría
{
"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": "Responder a 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": "Analizar imagen",
"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": "Nota adhesiva",
"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": "Nota adhesiva1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-736,
1520
],
"parameters": {
"height": 80,
"content": "Input is normalized"
},
"typeVersion": 1
},
{
"id": "2c44a9af-f395-45ff-bf4f-91a55c829d3e",
"name": "Nota adhesiva2",
"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": "Nota adhesiva3",
"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": "Nota adhesiva4",
"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": "Nota adhesiva5",
"type": "n8n-nodes-base.stickyNote",
"position": [
112,
1536
],
"parameters": {
"height": 80,
"content": "Normalizes data"
},
"typeVersion": 1
},
{
"id": "62b507e0-5b7d-48a3-9e44-aa4ccf339331",
"name": "Nota adhesiva6",
"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": "Nota adhesiva7",
"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": "Entrada normalizada",
"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": "División de lista de elementos",
"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": "Validación de título",
"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": "Datos normalizados",
"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": "Reagrupar lista",
"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
}
]
]
}
}
}¿Cómo usar este flujo de trabajo?
Copie el código de configuración JSON de arriba, cree un nuevo flujo de trabajo en su instancia de n8n y seleccione "Importar desde JSON", pegue la configuración y luego modifique la configuración de credenciales según sea necesario.
¿En qué escenarios es adecuado este flujo de trabajo?
Avanzado - Creación de contenido, IA Multimodal
¿Es de pago?
Este flujo de trabajo es completamente gratuito, puede importarlo y usarlo directamente. Sin embargo, tenga en cuenta que los servicios de terceros utilizados en el flujo de trabajo (como la API de OpenAI) pueden requerir un pago por su cuenta.
Flujos de trabajo relacionados recomendados
Arlene Martin
@arlenemartinCompartir este flujo de trabajo