Gmail vers embeddings vectoriels avec PGVector et Ollama

Avancé

Ceci est unSupport, IT Opsworkflow d'automatisation du domainecontenant 20 nœuds.Utilise principalement des nœuds comme If, Set, Code, Gmail, Postgres. Incorporation vectorielle Gmail avec PGVector et Ollama

Prérequis
  • Compte Google et informations d'identification Gmail API
  • Informations de connexion à la base de données PostgreSQL
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": "ZiIoKEClTk83g1Jt",
  "meta": {
    "instanceId": "8a3ba313628b26e4e4cf0504ff23322f235d6b433d92e59bcf8762764730ed80",
    "templateCredsSetupCompleted": true
  },
  "name": "Gmail to Vector Embeddings with PGVector and Ollama",
  "tags": [],
  "nodes": [
    {
      "id": "162b1a8b-2471-4880-9fcb-7f2dcfe175a8",
      "name": "Embeddings Ollama",
      "type": "@n8n/n8n-nodes-langchain.embeddingsOllama",
      "position": [
        1920,
        -100
      ],
      "parameters": {
        "model": "nomic-embed-text:latest"
      },
      "credentials": {},
      "typeVersion": 1
    },
    {
      "id": "49eb04b0-3b54-499c-ba46-3251102a4017",
      "name": "Chargeur de données par défaut",
      "type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
      "position": [
        2040,
        -97.5
      ],
      "parameters": {
        "options": {
          "metadata": {
            "metadataValues": [
              {
                "name": "emails_metadata.id",
                "value": "={{ $('Extract email fields').item.json.email_id }}"
              },
              {
                "name": "emails_metadata.thread_id",
                "value": "={{ $('Extract email fields').item.json.thread_id }}"
              }
            ]
          }
        },
        "jsonData": "={{ $('Extract email fields').item.json.email_text }}",
        "jsonMode": "expressionData"
      },
      "typeVersion": 1
    },
    {
      "id": "b4853472-6ac7-4da5-97b3-b22950ddff06",
      "name": "Séparateur de texte récursif par caractères",
      "type": "@n8n/n8n-nodes-langchain.textSplitterRecursiveCharacterTextSplitter",
      "position": [
        2128,
        100
      ],
      "parameters": {
        "options": {},
        "chunkSize": 2000,
        "chunkOverlap": 50
      },
      "typeVersion": 1
    },
    {
      "id": "b189f134-f78e-438f-9189-2f2b276b487d",
      "name": "Gmail Trigger",
      "type": "n8n-nodes-base.gmailTrigger",
      "position": [
        1260,
        280
      ],
      "parameters": {
        "simple": false,
        "filters": {
          "labelIds": [
            "INBOX"
          ]
        },
        "options": {
          "downloadAttachments": true
        },
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        }
      },
      "credentials": {},
      "typeVersion": 1.2
    },
    {
      "id": "81cba4c5-7762-483d-a076-3fa8799f70ce",
      "name": "Boucle sur les éléments",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        840,
        40
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "f82243ad-6efd-4be2-bf4e-5001870ae854",
      "name": "Séparation",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        640,
        40
      ],
      "parameters": {
        "options": {
          "destinationFieldName": "after"
        },
        "fieldToSplitOut": "weeks"
      },
      "typeVersion": 1
    },
    {
      "id": "2163d5ec-416f-4299-8a9d-10c26eaef32f",
      "name": "Déclenchement manuel ?",
      "type": "n8n-nodes-base.if",
      "position": [
        2416,
        -145
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "3cbc77e7-1796-4e1b-bbff-6391dd131336",
              "operator": {
                "type": "boolean",
                "operation": "false",
                "singleValue": true
              },
              "leftValue": "={{ $('Manual Trigger').isExecuted }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "76557325-c94e-47a9-9384-e6cbea94f67e",
      "name": "Déclencheur manuel",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        0,
        40
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "b9400906-a458-4305-8805-bb6bea17396b",
      "name": "Aucune opération, ne rien faire",
      "type": "n8n-nodes-base.noOp",
      "position": [
        2636,
        -145
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "5f0aa7c2-85b3-4585-8c8c-727af27de61c",
      "name": "Note adhésive",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -60,
        -540
      ],
      "parameters": {
        "color": 6,
        "width": 1440,
        "height": 780,
        "content": "## Bulk e-mail import\n\nPress the `Test workflow` button to run this once, and bulk import of all your e-mail\n\n### IMPORTANT\nSpecify your Gmail account creation date by editing the code node"
      },
      "typeVersion": 1
    },
    {
      "id": "2b85d362-d40d-49c0-b3a7-27fdbee8e90b",
      "name": "Note adhésive 1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        360,
        -100
      ],
      "parameters": {
        "width": 220,
        "height": 300,
        "content": "## Edit this ⬇️\nAnd specify your Gmail account creation date"
      },
      "typeVersion": 1
    },
    {
      "id": "05a9dd25-ae36-4e3c-a249-787ee1047bff",
      "name": "Note adhésive 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        740,
        260
      ],
      "parameters": {
        "color": 4,
        "width": 640,
        "height": 180,
        "content": "## Activate the workflow\nAnd this trigger will check for new mail, every minute"
      },
      "typeVersion": 1
    },
    {
      "id": "3f19abc5-a165-49e8-b97e-233c47949e68",
      "name": "Définir les dates avant et après",
      "type": "n8n-nodes-base.set",
      "position": [
        1040,
        -320
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "48e8d703-e52a-46cc-bd72-9b0d3352091b",
              "name": "after",
              "type": "string",
              "value": "={{ $json.after }}"
            },
            {
              "id": "a515cf56-9bc6-4724-a0ef-01a6159606f7",
              "name": "before",
              "type": "string",
              "value": "={{ DateTime.fromISO($json.after).plus(1, 'week').toISODate() }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "af742b17-2086-4698-af3a-32cb7260f380",
      "name": "Extraire les champs d'email",
      "type": "n8n-nodes-base.set",
      "position": [
        1480,
        -320
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "f818bad8-b000-499c-b137-de22dff4a343",
              "name": "email_text",
              "type": "string",
              "value": "={{ $json.text }}"
            },
            {
              "id": "68c16520-4a26-4ea9-95f7-ee89b9f53c4f",
              "name": "email_from",
              "type": "string",
              "value": "={{ $json.from?.text ?? '' }}"
            },
            {
              "id": "981f1f5b-ba2f-4153-966c-45bb6b535794",
              "name": "email_to",
              "type": "string",
              "value": "={{ $json.to?.text ?? '' }}"
            },
            {
              "id": "b528dd23-a743-4a55-98df-e1ae823b29b3",
              "name": "date",
              "type": "string",
              "value": "={{ DateTime.fromISO($json.date).toISO() }}"
            },
            {
              "id": "39081032-e503-470b-8d83-b5064238d037",
              "name": "email_id",
              "type": "string",
              "value": "={{ $json.id }}"
            },
            {
              "id": "146e8e72-3c2c-4320-b93a-b109d2e46139",
              "name": "thread_id",
              "type": "string",
              "value": "={{ $json.threadId }}"
            },
            {
              "id": "a49333a5-c565-4d46-8398-d423072b1e4d",
              "name": "email_subject",
              "type": "string",
              "value": "={{ $json.subject }}"
            },
            {
              "id": "806cf930-450e-4221-8061-a71ec8bf9bbe",
              "name": "attachments",
              "type": "array",
              "value": "={{ Object.keys($binary).map(item => $binary[item].fileName).filter(item => !!item) }}"
            },
            {
              "id": "30a38aaf-04c2-4286-99c9-8bb60ae8b317",
              "name": "email_cc",
              "type": "string",
              "value": "={{ $json.cc?.text ?? ''}}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "a51f5d5f-69c7-4153-be7f-492a8694629a",
      "name": "Note adhésive 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1640,
        -540
      ],
      "parameters": {
        "width": 720,
        "height": 780,
        "content": "## Magic here 🪄\n#### (not really, just statistics)\nE-mail is stored in a `emails_metadata` structured table, and also fed to the [`nomic-embed-text`](https://ollama.com/library/nomic-embed-text) model to be stored in a `emails_embeddings` table as [vector embeddings](https://www.pinecone.io/learn/vector-embeddings/) so similarity searches are possible.\n\nThe `email_id` field can be used to make the relation between the structured records and the vector embeddings, as it's stored in their metadata as `emails_metadata.id`.\nThis is also the case for `thread_id`."
      },
      "typeVersion": 1
    },
    {
      "id": "809e9269-1275-4c87-8c7f-1840c76f5b22",
      "name": "Stockage structuré",
      "type": "n8n-nodes-base.postgres",
      "onError": "continueErrorOutput",
      "position": [
        1700,
        -320
      ],
      "parameters": {
        "table": {
          "__rl": true,
          "mode": "name",
          "value": "emails_metadata"
        },
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "columns": {
          "value": {},
          "schema": [
            {
              "id": "email_id",
              "type": "string",
              "display": true,
              "removed": false,
              "required": true,
              "displayName": "email_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "thread_id",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "thread_id",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "email_from",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "email_from",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "email_to",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "email_to",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "email_cc",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "email_cc",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "date",
              "type": "dateTime",
              "display": true,
              "removed": false,
              "required": true,
              "displayName": "date",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "email_subject",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "email_subject",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "attachments",
              "type": "array",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "attachments",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "email_text",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "email_text",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            }
          ],
          "mappingMode": "autoMapInputData",
          "matchingColumns": [
            "email_id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {
          "outputColumns": [
            "*"
          ]
        },
        "operation": "upsert"
      },
      "credentials": {},
      "typeVersion": 2.6
    },
    {
      "id": "1c3dca79-381c-411b-8727-baa297e1ceda",
      "name": "Stockage vectorisé",
      "type": "@n8n/n8n-nodes-langchain.vectorStorePGVector",
      "onError": "continueRegularOutput",
      "position": [
        1936,
        -320
      ],
      "parameters": {
        "mode": "insert",
        "options": {},
        "tableName": "emails_embeddings"
      },
      "credentials": {},
      "typeVersion": 1.1
    },
    {
      "id": "3b7e13b2-73e9-42e7-900c-59611fe5af32",
      "name": "Créer la table",
      "type": "n8n-nodes-base.postgres",
      "position": [
        200,
        40
      ],
      "parameters": {
        "query": "CREATE TABLE IF NOT EXISTS public.emails_metadata (\n    email_id character varying(64) NOT NULL,\n    thread_id character varying(64),\n    email_from text,\n    email_to text,\n    email_cc text,\n    date timestamp with time zone NOT NULL,\n    email_subject text,\n    email_text text,\n    attachments text[]\n);\n",
        "options": {},
        "operation": "executeQuery"
      },
      "credentials": {},
      "typeVersion": 2.6
    },
    {
      "id": "19c55312-d1da-4d1e-8637-c5b08a9c1a2d",
      "name": "Décomposer l'intervalle en semaines",
      "type": "n8n-nodes-base.code",
      "position": [
        420,
        40
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Edit this\nlet whenDidICreateMyGmailAccount = DateTime.fromISO('2013-11-01')\n\n// (don't edit further down)\nwhenDidICreateMyGmailAccount = whenDidICreateMyGmailAccount.set({day: 1})\nlet now = $now.set({day: 1})\nconst weeks = []\nwhile (Math.floor(Interval.fromDateTimes(whenDidICreateMyGmailAccount, now).length('weeks')) > -1) {\n  weeks.push(now.toISODate())\n  now = now.minus({weeks: 1})\n}\n\nreturn {json: { weeks }};"
      },
      "typeVersion": 2
    },
    {
      "id": "aed43a77-6d58-41ba-b0b0-fdd3e9fe777a",
      "name": "Obtenir un lot de messages",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1260,
        -320
      ],
      "webhookId": "bace3678-df5b-4a9c-a1ef-1c219e3fd07b",
      "parameters": {
        "simple": false,
        "filters": {
          "receivedAfter": "={{ $json.after }}",
          "receivedBefore": "={{ $json.before }}"
        },
        "options": {
          "downloadAttachments": true
        },
        "operation": "getAll",
        "returnAll": true
      },
      "credentials": {},
      "typeVersion": 2.1
    }
  ],
  "active": false,
  "pinData": {
    "Manual Trigger": [
      {
        "json": {}
      }
    ]
  },
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "3c337d42-a3bb-4b71-ac36-deaf0cdf6019",
  "connections": {
    "f82243ad-6efd-4be2-bf4e-5001870ae854": {
      "main": [
        [
          {
            "node": "81cba4c5-7762-483d-a076-3fa8799f70ce",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "b189f134-f78e-438f-9189-2f2b276b487d": {
      "main": [
        [
          {
            "node": "af742b17-2086-4698-af3a-32cb7260f380",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "76557325-c94e-47a9-9384-e6cbea94f67e": {
      "main": [
        [
          {
            "node": "3b7e13b2-73e9-42e7-900c-59611fe5af32",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "81cba4c5-7762-483d-a076-3fa8799f70ce": {
      "main": [
        [],
        [
          {
            "node": "3f19abc5-a165-49e8-b97e-233c47949e68",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3b7e13b2-73e9-42e7-900c-59611fe5af32": {
      "main": [
        [
          {
            "node": "19c55312-d1da-4d1e-8637-c5b08a9c1a2d",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "809e9269-1275-4c87-8c7f-1840c76f5b22": {
      "main": [
        [
          {
            "node": "1c3dca79-381c-411b-8727-baa297e1ceda",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "81cba4c5-7762-483d-a076-3fa8799f70ce",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1c3dca79-381c-411b-8727-baa297e1ceda": {
      "main": [
        [
          {
            "node": "2163d5ec-416f-4299-8a9d-10c26eaef32f",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "162b1a8b-2471-4880-9fcb-7f2dcfe175a8": {
      "ai_embedding": [
        [
          {
            "node": "1c3dca79-381c-411b-8727-baa297e1ceda",
            "type": "ai_embedding",
            "index": 0
          }
        ]
      ]
    },
    "49eb04b0-3b54-499c-ba46-3251102a4017": {
      "ai_document": [
        [
          {
            "node": "1c3dca79-381c-411b-8727-baa297e1ceda",
            "type": "ai_document",
            "index": 0
          }
        ]
      ]
    },
    "af742b17-2086-4698-af3a-32cb7260f380": {
      "main": [
        [
          {
            "node": "809e9269-1275-4c87-8c7f-1840c76f5b22",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "aed43a77-6d58-41ba-b0b0-fdd3e9fe777a": {
      "main": [
        [
          {
            "node": "af742b17-2086-4698-af3a-32cb7260f380",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2163d5ec-416f-4299-8a9d-10c26eaef32f": {
      "main": [
        [
          {
            "node": "b9400906-a458-4305-8805-bb6bea17396b",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "81cba4c5-7762-483d-a076-3fa8799f70ce",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3f19abc5-a165-49e8-b97e-233c47949e68": {
      "main": [
        [
          {
            "node": "aed43a77-6d58-41ba-b0b0-fdd3e9fe777a",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "19c55312-d1da-4d1e-8637-c5b08a9c1a2d": {
      "main": [
        [
          {
            "node": "f82243ad-6efd-4be2-bf4e-5001870ae854",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "b4853472-6ac7-4da5-97b3-b22950ddff06": {
      "ai_textSplitter": [
        [
          {
            "node": "49eb04b0-3b54-499c-ba46-3251102a4017",
            "type": "ai_textSplitter",
            "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é - Support, Opérations IT

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œuds20
Catégorie2
Types de nœuds15
Description de la difficulté

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

Auteur
Alfonso Corretti

Alfonso Corretti

@acorretti

Software Engineering | Die-hard maker

Liens externes
Voir sur n8n.io

Partager ce workflow

Catégories

Catégories: 34