From d57d98fc6e39ddce15f598f70c8cd0a597ea1027 Mon Sep 17 00:00:00 2001 From: nusquama Date: Tue, 10 Mar 2026 12:13:26 +0800 Subject: [PATCH] creation --- ...p-it-tenders-and-score-them-with-gpt-4o-mini-to-supabase.webp | 1 + 1 file changed, 1 insertion(+) create mode 100644 workflows/Monitor BOAMP IT tenders and score them with GPT-4o Mini to Supabase-13765/13765-monitor-boamp-it-tenders-and-score-them-with-gpt-4o-mini-to-supabase.webp diff --git a/workflows/Monitor BOAMP IT tenders and score them with GPT-4o Mini to Supabase-13765/13765-monitor-boamp-it-tenders-and-score-them-with-gpt-4o-mini-to-supabase.webp b/workflows/Monitor BOAMP IT tenders and score them with GPT-4o Mini to Supabase-13765/13765-monitor-boamp-it-tenders-and-score-them-with-gpt-4o-mini-to-supabase.webp new file mode 100644 index 000000000..63b272400 --- /dev/null +++ b/workflows/Monitor BOAMP IT tenders and score them with GPT-4o Mini to Supabase-13765/13765-monitor-boamp-it-tenders-and-score-them-with-gpt-4o-mini-to-supabase.webp @@ -0,0 +1 @@ +{"id":"w69l72uRokyiUp7g","meta":{"instanceId":"4fb03e8a794c9a4ffa717f54989f44bb958e64f57e605ef61bad499ca54d20f3","templateCredsSetupCompleted":true},"name":"Monitor BOAMP IT tenders with AI scoring to Supabase","tags":[],"nodes":[{"id":"61d56904-218d-4d62-87fb-7f21a2b1ba5c","name":"Overview","type":"n8n-nodes-base.stickyNote","position":[640,976],"parameters":{"color":5,"width":520,"height":380,"content":"## Monitor BOAMP IT Tenders with AI Scoring\n\n**Who it's for:** ESN, IT consultancies, and agencies monitoring French public tenders (BOAMP) for IT and DevOps opportunities.\n\n**What it does:** Fetches IT-related tenders from the BOAMP API, scores each with OpenAI (pertinence, budget, stack), and routes to Supabase as hot (≥75) or archived.\n\n**Setup:** Run the SQL in the \"Supabase Schema\" sticky (right) in Supabase SQL Editor. Add OpenAI and Supabase credentials."},"typeVersion":1},{"id":"f8747f21-c023-4cbe-aa68-f89613c8952e","name":"Sticky Note 1","type":"n8n-nodes-base.stickyNote","position":[1216,880],"parameters":{"color":7,"width":220,"height":140,"content":"**Step 1 - Triggers**\n\n• Schedule: every 4 hours\n• Manual: for testing\n• Webhook: external trigger"},"typeVersion":1},{"id":"5e40fc30-1cfe-4be0-bc8d-7f705885e759","name":"Sticky Note 2","type":"n8n-nodes-base.stickyNote","position":[1552,1104],"parameters":{"color":7,"height":120,"content":"**Step 2 - Fetch & Normalize**\n\nBOAMP API (filter: informatique)"},"typeVersion":1},{"id":"87efc239-7d64-47c8-91e0-95a2767faa6f","name":"Sticky Note 3","type":"n8n-nodes-base.stickyNote","position":[2032,1056],"parameters":{"color":7,"width":360,"height":120,"content":"**Step 3–5 - AI & Route**\n\nScore → Parse → Hot (≥75) or Archive → Supabase"},"typeVersion":1},{"id":"9fd12931-3b53-4fb0-b294-7fdfdc72eacd","name":"Supabase Schema","type":"n8n-nodes-base.stickyNote","position":[640,1376],"parameters":{"color":6,"width":360,"height":400,"content":"**Supabase Schema** — Run in Supabase SQL Editor before use:\n\n```sql\nCREATE TABLE IF NOT EXISTS opportunities (\n id UUID DEFAULT gen_random_uuid() PRIMARY KEY,\n source TEXT NOT NULL,\n external_id TEXT NOT NULL,\n title TEXT,\n raw_data JSONB,\n stack_keywords TEXT[],\n budget_estimated TEXT,\n score INT DEFAULT 0,\n summary TEXT,\n status TEXT DEFAULT 'new' CHECK (status IN ('new','notified','archived')),\n created_at TIMESTAMPTZ DEFAULT NOW(),\n UNIQUE(source, external_id)\n);\nCREATE INDEX IF NOT EXISTS idx_opportunities_status ON opportunities(status);\nCREATE INDEX IF NOT EXISTS idx_opportunities_score ON opportunities(score DESC);\nCREATE INDEX IF NOT EXISTS idx_opportunities_created ON opportunities(created_at DESC);\n```"},"typeVersion":1},{"id":"62dc5076-fe50-4d04-9292-b2da274dbd69","name":"Config","type":"n8n-nodes-base.set","position":[1264,1408],"parameters":{"options":{},"assignments":{"assignments":[{"id":"1","name":"SCORE_THRESHOLD","type":"number","value":75}]}},"typeVersion":3.4},{"id":"aa8a2ee0-b377-492d-b516-0a02f93faa4e","name":"Schedule Every 4 Hours","type":"n8n-nodes-base.scheduleTrigger","position":[1264,1200],"parameters":{"rule":{"interval":[{"field":"hours","hoursInterval":4}]}},"typeVersion":1.2},{"id":"c9bb673d-b573-422a-8b0c-2944cff3ce90","name":"Manual Trigger","type":"n8n-nodes-base.manualTrigger","position":[1248,1568],"parameters":{},"typeVersion":1},{"id":"bd4f9a7a-8bba-4ef7-acd8-7b5ac25a7625","name":"Webhook Trigger","type":"n8n-nodes-base.webhook","position":[1264,1056],"webhookId":"5a72bfd2-7d39-4c7c-b8bf-8a0e79ff5ef3","parameters":{"path":"devops-radar-fetch","options":{},"httpMethod":"POST","responseMode":"lastNode"},"typeVersion":2.1},{"id":"bad3b741-ad9e-48ee-86cd-3c6ffb4c106f","name":"Fetch BOAMP IT Tenders","type":"n8n-nodes-base.httpRequest","position":[1552,1296],"parameters":{"url":"https://boamp-datadila.opendatasoft.com/api/explore/v2.1/catalog/datasets/boamp/records?limit=10&refine=objet:informatique","options":{}},"typeVersion":4.2},{"id":"80fb7470-fd15-4248-9d95-1d63f0001a83","name":"Normalize Tender Data","type":"n8n-nodes-base.code","position":[1776,1296],"parameters":{"jsCode":"const config = $('Config').first()?.json ?? {};\nconst results = $input.first().json?.results ?? [];\nreturn results.map(r => ({\n json: {\n ...config,\n source: 'BOAMP',\n external_id: r.idweb ?? r.id ?? '',\n title: r.objet ?? 'Sans titre',\n raw_data: r,\n body: (r.objet ?? '') + ' ' + (r.descripteur_libelle?.join(' ') ?? '') + ' ' + (r.type_marche_facette?.join(' ') ?? '')\n }\n}));"},"typeVersion":2},{"id":"c98315e9-0fd9-4b55-9ed5-2dfff75c020e","name":"AI Score Tender","type":"n8n-nodes-base.httpRequest","position":[1984,1296],"parameters":{"url":"https://api.openai.com/v1/chat/completions","method":"POST","options":{},"jsonBody":"={\n \"model\": \"gpt-4o-mini\",\n \"messages\": [{\n \"role\": \"user\",\n \"content\": \"Analyse cette opportunité B2B IT. Réponds en JSON uniquement: {\\\"pertinence\\\":0-100,\\\"budget_estimated\\\":\\\"string\\\",\\\"stack_keywords\\\":[\\\"k1\\\",\\\"k2\\\"],\\\"summary\\\":\\\"5 lignes\\\",\\\"recommendation\\\":\\\"GO|NO_GO\\\"}\\n\\nTitre: {{ $json.title }}\\nCorps: {{ $json.body }}\"\n }],\n \"temperature\": 0.2,\n \"max_tokens\": 500\n}","sendBody":true,"specifyBody":"json","authentication":"predefinedCredentialType","nodeCredentialType":"openAiApi"},"credentials":{"openAiApi":{"id":"rbmrvKOb9pdiLhSW","name":"n8n free OpenAI API credits"}},"typeVersion":4.2},{"id":"86c3a6fa-f09a-4d5f-b297-ea773a11415c","name":"Parse AI Response","type":"n8n-nodes-base.code","position":[2208,1296],"parameters":{"jsCode":"const resp = $input.first().json;\nconst content = resp.choices?.[0]?.message?.content ?? resp.message?.content ?? '{}';\nlet parsed = {};\ntry { parsed = JSON.parse(content.replace(/```json?/g,'').replace(/```/g,'').trim()); } catch(e) { parsed = { pertinence: 50 }; }\nconst allNorm = $('Normalize Tender Data').all();\nconst idx = $itemIndex ?? 0;\nconst opp = allNorm[idx]?.json ?? allNorm[0]?.json ?? {};\nconst score = Math.min(100, Math.max(0, parsed.pertinence ?? 50));\nconst threshold = opp.SCORE_THRESHOLD ?? 75;\nreturn { json: { ...opp, ...parsed, score, status: score >= threshold ? 'notified' : 'archived' } };"},"typeVersion":2},{"id":"f9d7080e-3e14-4c7d-a896-6fdcc5b4a0e5","name":"Is Hot Opportunity?","type":"n8n-nodes-base.if","position":[2432,1296],"parameters":{"options":{},"conditions":{"options":{"caseSensitive":true},"combinator":"and","conditions":[{"id":"1","operator":{"type":"number","operation":"gte"},"leftValue":"={{ $json.score }}","rightValue":"={{ $json.SCORE_THRESHOLD ?? 75 }}"}]}},"typeVersion":2},{"id":"3eefceaa-1b87-4f13-be55-a47bf144a977","name":"Supabase Insert Hot","type":"n8n-nodes-base.supabase","position":[2656,1200],"parameters":{"tableId":"opportunities","dataToSend":"autoMapInputData","inputsToIgnore":"SCORE_THRESHOLD"},"typeVersion":1},{"id":"f5c96ac0-e63c-49b9-b4ba-926a4cd13f88","name":"Supabase Insert Archived","type":"n8n-nodes-base.supabase","position":[2656,1392],"parameters":{"tableId":"opportunities","dataToSend":"autoMapInputData","inputsToIgnore":"SCORE_THRESHOLD"},"typeVersion":1}],"active":false,"pinData":{},"settings":{"binaryMode":"separate","availableInMCP":false,"executionOrder":"v1"},"versionId":"b29813be-1c90-4f0a-ba87-a99ab488edbd","connections":{"Config":{"main":[[{"node":"Fetch BOAMP IT Tenders","type":"main","index":0}]]},"Manual Trigger":{"main":[[{"node":"Config","type":"main","index":0}]]},"AI Score Tender":{"main":[[{"node":"Parse AI Response","type":"main","index":0}]]},"Webhook Trigger":{"main":[[{"node":"Config","type":"main","index":0}]]},"Parse AI Response":{"main":[[{"node":"Is Hot Opportunity?","type":"main","index":0}]]},"Is Hot Opportunity?":{"main":[[{"node":"Supabase Insert Hot","type":"main","index":0}],[{"node":"Supabase Insert Archived","type":"main","index":0}]]},"Normalize Tender Data":{"main":[[{"node":"AI Score Tender","type":"main","index":0}]]},"Fetch BOAMP IT Tenders":{"main":[[{"node":"Normalize Tender Data","type":"main","index":0}]]},"Schedule Every 4 Hours":{"main":[[{"node":"Config","type":"main","index":0}]]}}} \ No newline at end of file