Scanner de livres n8n

Avancé

Ceci est unContent Creation, Multimodal AIworkflow d'automatisation du domainecontenant 16 nœuds.Utilise principalement des nœuds comme Set, Code, Webhook, HttpRequest, OpenAi. Extraire et vérifier les titres de livres à partir de photos d'étagère de livres avec GPT-4o et Google Books

Prérequis
  • Point de terminaison HTTP Webhook (généré automatiquement par n8n)
  • Peut nécessiter les informations d'identification d'authentification de l'API cible
  • Clé API OpenAI
Aperçu du workflow
Visualisation des connexions entre les nœuds, avec support du zoom et du déplacement
Exporter le workflow
Copiez la configuration JSON suivante dans n8n pour importer et utiliser ce workflow
{
  "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": "Répondre à 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": "Analyser l'image",
      "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": "Note adhésive",
      "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": "Note adhésive1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -736,
        1520
      ],
      "parameters": {
        "height": 80,
        "content": "Input is normalized"
      },
      "typeVersion": 1
    },
    {
      "id": "2c44a9af-f395-45ff-bf4f-91a55c829d3e",
      "name": "Note adhésive2",
      "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": "Note adhésive3",
      "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": "Note adhésive4",
      "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": "Note adhésive5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        112,
        1536
      ],
      "parameters": {
        "height": 80,
        "content": "Normalizes data"
      },
      "typeVersion": 1
    },
    {
      "id": "62b507e0-5b7d-48a3-9e44-aa4ccf339331",
      "name": "Note adhésive6",
      "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": "Note adhésive7",
      "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": "Entrée normalisée",
      "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": "Division de la liste d'éléments",
      "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": "Validation du titre",
      "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": "Données normalisées",
      "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": "Réagrégation de la liste",
      "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
          }
        ]
      ]
    }
  }
}
Foire aux questions

Comment utiliser ce workflow ?

Copiez le code de configuration JSON ci-dessus, créez un nouveau workflow dans votre instance n8n et sélectionnez "Importer depuis le JSON", collez la configuration et modifiez les paramètres d'authentification selon vos besoins.

Dans quelles scénarios ce workflow est-il adapté ?

Avancé - Création de contenu, IA Multimodale

Est-ce payant ?

Ce workflow est entièrement gratuit et peut être utilisé directement. Veuillez noter que les services tiers utilisés dans le workflow (comme l'API OpenAI) peuvent nécessiter un paiement de votre part.

Informations sur le workflow
Niveau de difficulté
Avancé
Nombre de nœuds16
Catégorie2
Types de nœuds7
Description de la difficulté

Adapté aux utilisateurs avancés, avec des workflows complexes contenant 16+ nœuds

Liens externes
Voir sur n8n.io

Partager ce workflow

Catégories

Catégories: 34