823 lines
38 KiB
JSON
823 lines
38 KiB
JSON
|
|
{
|
|||
|
|
"name": "v1.6 Test",
|
|||
|
|
"nodes": [
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"formTitle": "Form input data",
|
|||
|
|
"formFields": {
|
|||
|
|
"values": [
|
|||
|
|
{
|
|||
|
|
"fieldLabel": "image",
|
|||
|
|
"fieldType": "file"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"options": {}
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.formTrigger",
|
|||
|
|
"typeVersion": 2.5,
|
|||
|
|
"position": [
|
|||
|
|
-1200,
|
|||
|
|
160
|
|||
|
|
],
|
|||
|
|
"id": "bc08484e-ccbe-4ccf-b6dc-9f8bd59d1197",
|
|||
|
|
"name": "Form input data",
|
|||
|
|
"webhookId": "afa8943e-cab2-4554-b64d-2c888ecfd9c3"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"method": "POST",
|
|||
|
|
"url": "=http://{{ $json.LLaVA }}/llava-api/v1/get-object-types",
|
|||
|
|
"sendHeaders": true,
|
|||
|
|
"headerParameters": {
|
|||
|
|
"parameters": [
|
|||
|
|
{
|
|||
|
|
"name": "accept",
|
|||
|
|
"value": "application/json"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"name": "Authorization",
|
|||
|
|
"value": "=Bearer {{ $json.Token }}"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"sendBody": true,
|
|||
|
|
"contentType": "multipart-form-data",
|
|||
|
|
"bodyParameters": {
|
|||
|
|
"parameters": [
|
|||
|
|
{
|
|||
|
|
"name": "temperature",
|
|||
|
|
"value": "0.2"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"name": "top_p",
|
|||
|
|
"value": "0.9"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameterType": "formBinaryData",
|
|||
|
|
"name": "image",
|
|||
|
|
"inputDataFieldName": "=image"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"options": {}
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.httpRequest",
|
|||
|
|
"typeVersion": 4.3,
|
|||
|
|
"position": [
|
|||
|
|
64,
|
|||
|
|
-240
|
|||
|
|
],
|
|||
|
|
"id": "fa89e8ca-2669-48f2-bdcf-e4d2aeee1311",
|
|||
|
|
"name": "LLaVA-based object types extractor",
|
|||
|
|
"onError": "continueRegularOutput"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"method": "POST",
|
|||
|
|
"url": "=http://{{ $json.Grounding_DINO }}/grounding-dino-api/v1/get-objects-bboxes ",
|
|||
|
|
"sendHeaders": true,
|
|||
|
|
"headerParameters": {
|
|||
|
|
"parameters": [
|
|||
|
|
{
|
|||
|
|
"name": "accept",
|
|||
|
|
"value": "application/json"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"name": "Authorization",
|
|||
|
|
"value": "=Bearer {{ $json.Token }}"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"sendBody": true,
|
|||
|
|
"contentType": "multipart-form-data",
|
|||
|
|
"bodyParameters": {
|
|||
|
|
"parameters": [
|
|||
|
|
{
|
|||
|
|
"name": "object_types",
|
|||
|
|
"value": "={{ $json.labels_string }}"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"name": "max_objects",
|
|||
|
|
"value": "50"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"name": "base64",
|
|||
|
|
"value": "false"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameterType": "formBinaryData",
|
|||
|
|
"name": "image",
|
|||
|
|
"inputDataFieldName": "image"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"options": {}
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.httpRequest",
|
|||
|
|
"typeVersion": 4.3,
|
|||
|
|
"position": [
|
|||
|
|
800,
|
|||
|
|
-16
|
|||
|
|
],
|
|||
|
|
"id": "6cfd2993-30d9-4905-a643-48a73273c60c",
|
|||
|
|
"name": "Grounding DINO"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"operation": "binaryToPropery",
|
|||
|
|
"binaryPropertyName": "image",
|
|||
|
|
"destinationKey": "image_input",
|
|||
|
|
"options": {}
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.extractFromFile",
|
|||
|
|
"typeVersion": 1.1,
|
|||
|
|
"position": [
|
|||
|
|
-384,
|
|||
|
|
560
|
|||
|
|
],
|
|||
|
|
"id": "eb0dc17a-cedb-4ea2-a28e-c9aac74f188e",
|
|||
|
|
"name": "base64"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"method": "POST",
|
|||
|
|
"url": "=http://{{ $json.DeepGaze }}/v1/predict-heatmap ",
|
|||
|
|
"sendHeaders": true,
|
|||
|
|
"headerParameters": {
|
|||
|
|
"parameters": [
|
|||
|
|
{
|
|||
|
|
"name": "accept",
|
|||
|
|
"value": "application/json"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"name": "Authorization",
|
|||
|
|
"value": "=Bearer {{ $json.Token }}"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"sendBody": true,
|
|||
|
|
"contentType": "multipart-form-data",
|
|||
|
|
"bodyParameters": {
|
|||
|
|
"parameters": [
|
|||
|
|
{
|
|||
|
|
"parameterType": "formBinaryData",
|
|||
|
|
"name": "image",
|
|||
|
|
"inputDataFieldName": "image"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"options": {}
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.httpRequest",
|
|||
|
|
"typeVersion": 4.3,
|
|||
|
|
"position": [
|
|||
|
|
96,
|
|||
|
|
352
|
|||
|
|
],
|
|||
|
|
"id": "4e3419b0-dae9-4bba-8729-8798d4d5f289",
|
|||
|
|
"name": "DeepGaze",
|
|||
|
|
"onError": "continueRegularOutput"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"jsCode": "const item = $input.first().json;\n\nconst binaryData = Buffer.from(item.heatmap_b64, 'base64');\n\nreturn [{\n json: item,\n binary: {\n image: await this.helpers.prepareBinaryData(\n binaryData,\n 'heatmap.png',\n 'image/png'\n )\n }\n}];"
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.code",
|
|||
|
|
"typeVersion": 2,
|
|||
|
|
"position": [
|
|||
|
|
1120,
|
|||
|
|
352
|
|||
|
|
],
|
|||
|
|
"id": "456beac3-734b-4cc2-9006-3b671462b9ed",
|
|||
|
|
"name": "Image"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {},
|
|||
|
|
"type": "n8n-nodes-base.merge",
|
|||
|
|
"typeVersion": 3.2,
|
|||
|
|
"position": [
|
|||
|
|
1120,
|
|||
|
|
576
|
|||
|
|
],
|
|||
|
|
"id": "e3ea6d0e-cc9e-491b-9a52-e83f733d59ed",
|
|||
|
|
"name": "Merge"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"content": "## Inverted heatmap - DeepGaze\nPrezentacja heatmap nałożonej na grafikę źródłową",
|
|||
|
|
"height": 112,
|
|||
|
|
"width": 464,
|
|||
|
|
"color": 4
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.stickyNote",
|
|||
|
|
"typeVersion": 1,
|
|||
|
|
"position": [
|
|||
|
|
1424,
|
|||
|
|
720
|
|||
|
|
],
|
|||
|
|
"id": "d4207e63-5241-4b70-a01a-bb4d52e1641e",
|
|||
|
|
"name": "Sticky Note"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {},
|
|||
|
|
"type": "n8n-nodes-base.merge",
|
|||
|
|
"typeVersion": 3.2,
|
|||
|
|
"position": [
|
|||
|
|
1120,
|
|||
|
|
144
|
|||
|
|
],
|
|||
|
|
"id": "b8dec319-2fa6-4655-afbb-87ab03a7d167",
|
|||
|
|
"name": "Merge1"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"content": "## Object Detection\nObiekty nałożone na grafikę źródłową",
|
|||
|
|
"height": 112,
|
|||
|
|
"width": 464,
|
|||
|
|
"color": 4
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.stickyNote",
|
|||
|
|
"typeVersion": 1,
|
|||
|
|
"position": [
|
|||
|
|
1424,
|
|||
|
|
288
|
|||
|
|
],
|
|||
|
|
"id": "02ee310f-191b-4e74-b562-1ee1b030560e",
|
|||
|
|
"name": "Sticky Note1"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"content": "## Object Listing\nLista obiektów wraz z opisem grafiki",
|
|||
|
|
"height": 112,
|
|||
|
|
"width": 464,
|
|||
|
|
"color": 4
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.stickyNote",
|
|||
|
|
"typeVersion": 1,
|
|||
|
|
"position": [
|
|||
|
|
-96,
|
|||
|
|
-384
|
|||
|
|
],
|
|||
|
|
"id": "426c4aca-e358-4aeb-8de1-182eaff75a44",
|
|||
|
|
"name": "Sticky Note2"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"mode": "combine",
|
|||
|
|
"combineBy": "combineAll",
|
|||
|
|
"options": {}
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.merge",
|
|||
|
|
"typeVersion": 3.2,
|
|||
|
|
"position": [
|
|||
|
|
-384,
|
|||
|
|
-16
|
|||
|
|
],
|
|||
|
|
"id": "7cd356f2-501a-418a-b809-67f520433273",
|
|||
|
|
"name": "Merge2"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"operation": "get",
|
|||
|
|
"dataTableId": {
|
|||
|
|
"__rl": true,
|
|||
|
|
"value": "vNV6H2oqepIaXaDj",
|
|||
|
|
"mode": "list",
|
|||
|
|
"cachedResultName": "Credentials",
|
|||
|
|
"cachedResultUrl": "/projects/OZaIb3cfHKXhndDW/datatables/vNV6H2oqepIaXaDj"
|
|||
|
|
},
|
|||
|
|
"limit": 1
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.dataTable",
|
|||
|
|
"typeVersion": 1.1,
|
|||
|
|
"position": [
|
|||
|
|
-848,
|
|||
|
|
-32
|
|||
|
|
],
|
|||
|
|
"id": "7c2ee8f0-8eab-4c80-bca8-818e5335feff",
|
|||
|
|
"name": "Credentials"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"mode": "combine",
|
|||
|
|
"combineBy": "combineAll",
|
|||
|
|
"options": {}
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.merge",
|
|||
|
|
"typeVersion": 3.2,
|
|||
|
|
"position": [
|
|||
|
|
560,
|
|||
|
|
-16
|
|||
|
|
],
|
|||
|
|
"id": "9298bcb8-d2f6-4d42-8e03-13b556495cab",
|
|||
|
|
"name": "Merge5"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"content": "## Heatmap\n",
|
|||
|
|
"height": 112,
|
|||
|
|
"width": 464
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.stickyNote",
|
|||
|
|
"typeVersion": 1,
|
|||
|
|
"position": [
|
|||
|
|
1424,
|
|||
|
|
1632
|
|||
|
|
],
|
|||
|
|
"id": "786650ff-5fd8-4a83-9ad1-9fb22041789c",
|
|||
|
|
"name": "Sticky Note3"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"content": "## Interwały\n30 sek, 6 obrazów\n",
|
|||
|
|
"height": 112,
|
|||
|
|
"width": 464
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.stickyNote",
|
|||
|
|
"typeVersion": 1,
|
|||
|
|
"position": [
|
|||
|
|
1904,
|
|||
|
|
720
|
|||
|
|
],
|
|||
|
|
"id": "f5e0761f-b4df-4b27-910d-d7cecf3110c2",
|
|||
|
|
"name": "Sticky Note4"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"content": "## Interwały\n30 sek, 6 obrazów\n20 sek. do 0,5 sekundy",
|
|||
|
|
"height": 112,
|
|||
|
|
"width": 464
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.stickyNote",
|
|||
|
|
"typeVersion": 1,
|
|||
|
|
"position": [
|
|||
|
|
1904,
|
|||
|
|
1632
|
|||
|
|
],
|
|||
|
|
"id": "05d80ebd-4a8d-435f-b125-96d61162b1e1",
|
|||
|
|
"name": "Sticky Note5"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"content": "## Ścieżki fiksacji\n",
|
|||
|
|
"height": 112,
|
|||
|
|
"width": 464
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.stickyNote",
|
|||
|
|
"typeVersion": 1,
|
|||
|
|
"position": [
|
|||
|
|
1424,
|
|||
|
|
1920
|
|||
|
|
],
|
|||
|
|
"id": "8671e093-3278-4d7d-b028-7066a634aa10",
|
|||
|
|
"name": "Sticky Note6"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"content": "## Interwały\n???\n",
|
|||
|
|
"height": 112,
|
|||
|
|
"width": 464
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.stickyNote",
|
|||
|
|
"typeVersion": 1,
|
|||
|
|
"position": [
|
|||
|
|
1904,
|
|||
|
|
1920
|
|||
|
|
],
|
|||
|
|
"id": "3d9a385e-377a-494d-be51-57c02eb6bbc6",
|
|||
|
|
"name": "Sticky Note7"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"content": "## Mapa emocji\n",
|
|||
|
|
"height": 112,
|
|||
|
|
"width": 464
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.stickyNote",
|
|||
|
|
"typeVersion": 1,
|
|||
|
|
"position": [
|
|||
|
|
1424,
|
|||
|
|
2176
|
|||
|
|
],
|
|||
|
|
"id": "be6a9c40-a7d9-489a-8452-b1dd79efaf01",
|
|||
|
|
"name": "Sticky Note8"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"jsCode": "const labels = $input.first().json.labels;\nreturn [{ json: { labels_string: labels.join(\", \") } }];"
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.code",
|
|||
|
|
"typeVersion": 2,
|
|||
|
|
"position": [
|
|||
|
|
256,
|
|||
|
|
-240
|
|||
|
|
],
|
|||
|
|
"id": "040cb049-68ca-46ca-b46f-06ecce243387",
|
|||
|
|
"name": "Labels string"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"jsCode": "const items = $input.all();\n\nconst originalB64 = items[0].json.image_input;\nconst heatmapB64 = items[1].json.heatmap_b64;\nconst heatmapMime = items[1].json.heatmap_mime;\nconst width = items[1].json.width;\nconst height = items[1].json.height;\n\nconst html = `<!DOCTYPE html>\n<html lang=\"pl\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Heatmap Overlay Viewer</title>\n<style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n background: #1a1a2e;\n color: #e0e0e0;\n font-family: 'Segoe UI', system-ui, sans-serif;\n display: flex;\n flex-direction: column;\n align-items: center;\n min-height: 100vh;\n padding: 24px;\n }\n h1 {\n font-size: 1.4rem;\n font-weight: 600;\n margin-bottom: 20px;\n color: #fff;\n letter-spacing: 0.5px;\n }\n .viewer {\n position: relative;\n width: ${width}px;\n max-width: 95vw;\n aspect-ratio: ${width} / ${height};\n border-radius: 12px;\n overflow: hidden;\n box-shadow: 0 8px 32px rgba(0,0,0,0.5);\n }\n .viewer img {\n position: absolute;\n top: 0; left: 0;\n width: 100%;\n height: 100%;\n object-fit: contain;\n }\n #heatmap {\n opacity: 0.5;\n transition: opacity 0.05s ease;\n }\n .controls {\n margin-top: 24px;\n background: #16213e;\n padding: 20px 32px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n gap: 16px;\n box-shadow: 0 4px 16px rgba(0,0,0,0.3);\n max-width: 95vw;\n }\n .controls label {\n font-size: 0.95rem;\n white-space: nowrap;\n }\n input[type=\"range\"] {\n -webkit-appearance: none;\n width: 300px;\n height: 6px;\n border-radius: 3px;\n background: linear-gradient(90deg, #0f3460, #e94560);\n outline: none;\n cursor: pointer;\n }\n input[type=\"range\"]::-webkit-slider-thumb {\n -webkit-appearance: none;\n width: 20px; height: 20px;\n border-radius: 50%;\n background: #fff;\n box-shadow: 0 2px 6px rgba(0,0,0,0.4);\n cursor: grab;\n }\n input[type=\"range\"]::-moz-range-thumb {\n width: 20px; height: 20px;\n border-radius: 50%;\n background: #fff;\n border: none;\n box-shadow: 0 2px 6px rgba(0,0,0,0.4);\n cursor: grab;\n }\n #opacityValue {\n font-weight: 700;\n font-size: 1.1rem;\n min-width: 48px;\n text-align: center;\n color: #e94560;\n }\n .hint {\n margin-top: 12px;\n font-size: 0.8rem;\n color: #666;\n }\n</style>\n</head>\n<body>\n\n<h1>Heatmap overlay viewer</h1>\n\n<div class=\"viewer\">\n <img id=\"original\" src=\"data:image/png;base64,${originalB64}\" alt=\"Original\" />\n <img id=\"heatmap\" src=\"data:${heatmapMime};base64,${heatmapB64}\" alt=\"Heatmap\" />\n</div>\n\n<div class=\"controls\">\n <label for=\"slider\">Przezroczystość heatmapy:</label>\n <input type=\"range\" id=\"slider\" min=\"0\" max=\"100\" value=\"50\" />\n <span id=\"opacityValue\">50%</span>\n</div>\n\n<p class=\"hint\">Przesuń suwak w lewo, aby zobaczyć oryginał · w prawo, aby zobaczyć heatmapę</p>\n\n<script>\n const slider = document.getElementById('slider');\n const heatmap = document.getElementById('heatmap');\n const display = document.getElementById('opacityValue');\n\n slider.addEventListener('input', () => {\n const val = slider.value;\n heatmap.style.opacity = val / 100;\n display.textContent = val + '%';\n });\n</script>\n</body>\n</html>`;\n\nconst binaryData = await this.helpers.prepareBinaryData(\n Buffer.from(html, 'utf-8'),\n 'heatmap_viewer.html',\n 'text/html'\n);\n\nreturn [{\n json: {\n filename: 'heatmap_viewer.html',\n width,\n height,\n model: items[1].json.model\n },\n binary: { file: binaryData }\n}];"
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.code",
|
|||
|
|
"typeVersion": 2,
|
|||
|
|
"position": [
|
|||
|
|
1424,
|
|||
|
|
576
|
|||
|
|
],
|
|||
|
|
"id": "fbc15b23-9640-48da-b79f-33328a1c92dd",
|
|||
|
|
"name": "Inverted heatmap"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"method": "POST",
|
|||
|
|
"url": "http://1.208.108.242:58951/unisal/process-image",
|
|||
|
|
"sendQuery": true,
|
|||
|
|
"queryParameters": {
|
|||
|
|
"parameters": [
|
|||
|
|
{
|
|||
|
|
"name": "as_base64",
|
|||
|
|
"value": "true"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"sendHeaders": true,
|
|||
|
|
"headerParameters": {
|
|||
|
|
"parameters": [
|
|||
|
|
{
|
|||
|
|
"name": "accept",
|
|||
|
|
"value": "application/json"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"name": "X-API-Key",
|
|||
|
|
"value": "={{ $json.Token }}"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"sendBody": true,
|
|||
|
|
"contentType": "multipart-form-data",
|
|||
|
|
"bodyParameters": {
|
|||
|
|
"parameters": [
|
|||
|
|
{
|
|||
|
|
"parameterType": "formBinaryData",
|
|||
|
|
"name": "file",
|
|||
|
|
"inputDataFieldName": "image"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"options": {}
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.httpRequest",
|
|||
|
|
"typeVersion": 4.4,
|
|||
|
|
"position": [
|
|||
|
|
96,
|
|||
|
|
832
|
|||
|
|
],
|
|||
|
|
"id": "edd412d8-cbc2-48ab-8df7-2ef047ee9f5e",
|
|||
|
|
"name": "unisal - inverted heatmap",
|
|||
|
|
"onError": "continueRegularOutput"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"method": "POST",
|
|||
|
|
"url": "http://1.208.108.242:58951/asmModel/process-image",
|
|||
|
|
"sendQuery": true,
|
|||
|
|
"queryParameters": {
|
|||
|
|
"parameters": [
|
|||
|
|
{
|
|||
|
|
"name": "prompt",
|
|||
|
|
"value": "Describe the image in the style of a polished marketing ad."
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"name": "as_raw_output",
|
|||
|
|
"value": "false"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"name": "max_new_tokens",
|
|||
|
|
"value": "100"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"sendHeaders": true,
|
|||
|
|
"headerParameters": {
|
|||
|
|
"parameters": [
|
|||
|
|
{
|
|||
|
|
"name": "accept",
|
|||
|
|
"value": "application/json"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"name": "X-API-Key",
|
|||
|
|
"value": "={{ $json.Token }}"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"sendBody": true,
|
|||
|
|
"contentType": "multipart-form-data",
|
|||
|
|
"bodyParameters": {
|
|||
|
|
"parameters": [
|
|||
|
|
{
|
|||
|
|
"parameterType": "formBinaryData",
|
|||
|
|
"name": "file",
|
|||
|
|
"inputDataFieldName": "image"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"options": {}
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.httpRequest",
|
|||
|
|
"typeVersion": 4.4,
|
|||
|
|
"position": [
|
|||
|
|
96,
|
|||
|
|
1040
|
|||
|
|
],
|
|||
|
|
"id": "91aabc80-b814-4c31-9796-e9acdad65192",
|
|||
|
|
"name": "asmModel - inverted heatmap",
|
|||
|
|
"onError": "continueRegularOutput"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"numberInputs": 4
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.merge",
|
|||
|
|
"typeVersion": 3.2,
|
|||
|
|
"position": [
|
|||
|
|
1120,
|
|||
|
|
944
|
|||
|
|
],
|
|||
|
|
"id": "2abef155-3c6f-4c64-9aaa-a5bc12ef2c43",
|
|||
|
|
"name": "Merge6"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"content": "## Inverted heatmap - Compare\nPrezentacja heatmap nałożonej na grafikę źródłową",
|
|||
|
|
"height": 112,
|
|||
|
|
"width": 464,
|
|||
|
|
"color": 4
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.stickyNote",
|
|||
|
|
"typeVersion": 1,
|
|||
|
|
"position": [
|
|||
|
|
1424,
|
|||
|
|
1120
|
|||
|
|
],
|
|||
|
|
"id": "b3a754d2-c3ff-4dfd-a8a0-71c8a37d3bb5",
|
|||
|
|
"name": "Sticky Note9"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"jsCode": "// n8n Code Node – Generate Inverted Heatmap HTML (Canvas pixel-blend)\n// Input items (4):\n// [0] image_input – original image (base64 PNG)\n// [1] heatmap_b64 – DeepGaze heatmap (base64 PNG), heatmap_mime\n// [2] data – unisal heatmap (base64 JPEG), mimetype\n// [3] image_detailed – asmModel detailed (base64), image_general – asmModel general, mimetype\n\nconst imgInput = items[0].json.image_input;\nconst deepGazeB64 = items[1].json.heatmap_b64;\nconst deepGazeMime = items[1].json.heatmap_mime || 'image/png';\nconst unisalB64 = items[2].json.data;\nconst unisalMime = items[2].json.mimetype || 'image/jpeg';\nconst detailedB64 = items[3].json.image_detailed;\nconst generalB64 = items[3].json.image_general;\nconst asmMime = items[3].json.mimetype || 'image/jpeg';\n\nconst origMime = imgInput.startsWith('/9j/') ? 'image/jpeg' : 'image/png';\n\nconst html = `<!DOCTYPE html>\n<html lang=\"pl\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Inverted Heatmap</title>\n<style>\n * { box-sizing: border-box; margin: 0; padding: 0; }\n body {\n font-family: 'Segoe UI', Arial, sans-serif;\n background: #1a1a2e;\n color: #e0e0e0;\n min-height: 100vh;\n padding: 24px;\n }\n h1 {\n text-align: center;\n font-size: 2rem;\n letter-spacing: 2px;\n margin-bottom: 24px;\n color: #a0c4ff;\n text-shadow: 0 0 12px #3a7bd560;\n }\n .slider-container {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 16px;\n margin-bottom: 32px;\n }\n .slider-container label {\n font-size: 1rem;\n color: #a0c4ff;\n white-space: nowrap;\n }\n #opacitySlider {\n -webkit-appearance: none;\n appearance: none;\n width: 320px;\n height: 6px;\n border-radius: 3px;\n background: linear-gradient(to right, #3a7bd5, #a0c4ff);\n outline: none;\n cursor: pointer;\n }\n #opacitySlider::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: #a0c4ff;\n box-shadow: 0 0 6px #3a7bd5;\n cursor: pointer;\n }\n #opacityValue {\n font-size: 1rem;\n color: #fff;\n min-width: 40px;\n text-align: left;\n }\n #status {\n text-align: center;\n color: #a0c4ff88;\n font-size: 0.9rem;\n margin-bottom: 16px;\n min-height: 1.2em;\n }\n .grid {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 20px;\n max-width: 1400px;\n margin: 0 auto;\n }\n .card {\n background: #16213e;\n border-radius: 12px;\n overflow: hidden;\n box-shadow: 0 4px 24px #0008;\n display: flex;\n flex-direction: column;\n }\n .card-title {\n text-align: center;\n padding: 10px 0 8px;\n font-size: 1.05rem;\n font-weight: 600;\n letter-spacing: 1px;\n color: #a0c4ff;\n background: #0f3460;\n }\n canvas {\n display: block;\n width: 100%;\n height: auto;\n }\n @media (max-width: 700px) {\n .grid { grid-template-columns: 1fr; }\n }\n</style>\n</head>\n<body>\n<h1>Inverted Heatmap</h1>\n\n<div class=\"slider-container\">\n <label for=\"opacitySlider\">Przezroczystość heatmapy:</label>\n <input type=\"range\" id=\"opacitySlider\" min=\"0\" max=\"100\" value=\"70\">\n <span id=\"opacityValue\">70%</span>\n</div>\n<div id=\"status\">Ładowanie obrazów…</div>\n\n<div class=\"grid\">\n <div class=\"card\">\n <div class=\"card-title\">DeepGaze</div>\n <canvas id=\"c0\"></canvas>\n </div>\n <div class=\"card\">\n <div class=\"card-title\">unisal</div>\n <canvas id=\"c1\"></canvas>\n </div>\n <div class=\"card\">\n <div class=\"card-title\">asmModel detailed</div>\n <canvas id=\"c2\"></canvas>\n </div>\n <div class=\"card\">\n <div class=\"card-title\">asmModel general</div>\n <canvas id=\"c3\"></canvas>\n </div>\n</div>\n\n<script>\n // ── Embedded image data ───────────<E29480>
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.code",
|
|||
|
|
"typeVersion": 2,
|
|||
|
|
"position": [
|
|||
|
|
1424,
|
|||
|
|
976
|
|||
|
|
],
|
|||
|
|
"id": "fe201da2-822e-4433-973d-d14d3e72421e",
|
|||
|
|
"name": "Inverted heatmap - Compare"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"parameters": {
|
|||
|
|
"jsCode": "const items = $input.all();\n\nconst imageB64 = items[0].json.image_input;\nconst detections = items[1].json.objects_bboxes || [];\n\n// --- Odczyt rzeczywistych wymiarów obrazu z nagłówka binarnego (base64) ---\n// Eliminuje zależność od pól width/height, których może nie być w danych\nconst imgBuffer = Buffer.from(imageB64, 'base64');\n\nlet imgWidth, imgHeight, mimeType;\n\nif (\n imgBuffer[0] === 0x89 && imgBuffer[1] === 0x50 &&\n imgBuffer[2] === 0x4E && imgBuffer[3] === 0x47\n) {\n // PNG — wymiary w bajtach 16-23 (big-endian uint32)\n mimeType = 'image/png';\n imgWidth = imgBuffer.readUInt32BE(16);\n imgHeight = imgBuffer.readUInt32BE(20);\n} else if (imgBuffer[0] === 0xFF && imgBuffer[1] === 0xD8) {\n // JPEG — szukamy markera SOF0 (0xC0) lub SOF2 (0xC2)\n mimeType = 'image/jpeg';\n let offset = 2;\n let found = false;\n while (offset + 3 < imgBuffer.length) {\n if (imgBuffer[offset] !== 0xFF) break;\n const marker = imgBuffer[offset + 1];\n if (marker === 0xC0 || marker === 0xC2) {\n imgHeight = imgBuffer.readUInt16BE(offset + 5);\n imgWidth = imgBuffer.readUInt16BE(offset + 7);\n found = true;\n break;\n }\n // Przejdź do następnego markera\n const segLen = imgBuffer.readUInt16BE(offset + 2);\n offset += 2 + segLen;\n }\n if (!found) {\n imgWidth = items[1].json.width || 839;\n imgHeight = items[1].json.height || 1190;\n }\n} else {\n // Nieznany format — fallback na dane z JSON lub wartości domyślne\n mimeType = 'image/png';\n imgWidth = items[1].json.width || 839;\n imgHeight = items[1].json.height || 1190;\n}\n\n// --- Dynamiczna paleta kolorów ---\nconst palette = [\n '#00e5ff', '#ff4081', '#ffea00', '#76ff03', '#d500f9',\n '#ff6d00', '#00bfa5', '#304ffe', '#ff1744', '#64ffda',\n '#f50057', '#00b0ff', '#ffc400', '#69f0ae', '#e040fb',\n '#ff9100', '#18ffff', '#7c4dff', '#ff3d00', '#b2ff59',\n];\n\nconst uniqueTypes = [...new Set(detections.map(d => d.object_type))];\nconst colors = {};\nuniqueTypes.forEach((type, i) => {\n colors[type] = palette[i % palette.length];\n});\n\n// --- Generowanie boksów z pozycjonowaniem procentowym ---\n// Kluczowa poprawka: używamy % zamiast px, dzięki czemu boxy\n// skalują się razem z obrazem przy każdej rozdzielczości ekranu.\nconst boxesHtml = detections.map(det => {\n const [x1, y1, x2, y2] = det.bbox_coords_xyxy;\n const color = colors[det.object_type];\n const score = (det.score * 100).toFixed(1);\n\n const left = ((x1 / imgWidth) * 100).toFixed(4);\n const top = ((y1 / imgHeight) * 100).toFixed(4);\n const width = (((x2 - x1) / imgWidth) * 100).toFixed(4);\n const height = (((y2 - y1) / imgHeight)* 100).toFixed(4);\n\n return `\n <div class=\"bbox\" data-type=\"${det.object_type}\" style=\"\n left:${left}%; top:${top}%;\n width:${width}%; height:${height}%;\n border-color:${color};\n \">\n <span class=\"label\" style=\"background:${color};\">${det.object_type} ${score}%</span>\n </div>`;\n}).join('\\n');\n\n// --- Legenda i filtry ---\nconst legend = uniqueTypes.map(type =>\n `<span class=\"legend-item\"><span class=\"legend-dot\" style=\"background:${colors[type]};\"></span>${type}</span>`\n).join('');\n\nconst filters = uniqueTypes.map(type => {\n const count = detections.filter(d => d.object_type === type).length;\n return `<button class=\"filter-btn active\" data-filter=\"${type}\" style=\"--c:${colors[type]};\">${type} <small>(${count})</small></button>`;\n}).join('\\n');\n\nconst html = `<!DOCTYPE html>\n<html lang=\"pl\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Object Detection Viewer</title>\n<style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n background: #0d1117;\n color: #e6edf3;\n font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;\n
|
|||
|
|
},
|
|||
|
|
"type": "n8n-nodes-base.code",
|
|||
|
|
"typeVersion": 2,
|
|||
|
|
"position": [
|
|||
|
|
1424,
|
|||
|
|
144
|
|||
|
|
],
|
|||
|
|
"id": "fa626aa0-64a4-4818-83b3-ac1f88228694",
|
|||
|
|
"name": "Object Detection"
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"pinData": {},
|
|||
|
|
"connections": {
|
|||
|
|
"Form input data": {
|
|||
|
|
"main": [
|
|||
|
|
[
|
|||
|
|
{
|
|||
|
|
"node": "base64",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 0
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"node": "Merge2",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 1
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"node": "Credentials",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 0
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"DeepGaze": {
|
|||
|
|
"main": [
|
|||
|
|
[
|
|||
|
|
{
|
|||
|
|
"node": "Image",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 0
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"node": "Merge",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 1
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"node": "Merge6",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 1
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"Image": {
|
|||
|
|
"main": [
|
|||
|
|
[]
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"Merge": {
|
|||
|
|
"main": [
|
|||
|
|
[
|
|||
|
|
{
|
|||
|
|
"node": "Inverted heatmap",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 0
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"base64": {
|
|||
|
|
"main": [
|
|||
|
|
[
|
|||
|
|
{
|
|||
|
|
"node": "Merge",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 0
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"node": "Merge1",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 0
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"node": "Merge6",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 0
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"Grounding DINO": {
|
|||
|
|
"main": [
|
|||
|
|
[
|
|||
|
|
{
|
|||
|
|
"node": "Merge1",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 1
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"Merge1": {
|
|||
|
|
"main": [
|
|||
|
|
[
|
|||
|
|
{
|
|||
|
|
"node": "Object Detection",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 0
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"Merge2": {
|
|||
|
|
"main": [
|
|||
|
|
[
|
|||
|
|
{
|
|||
|
|
"node": "LLaVA-based object types extractor",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 0
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"node": "unisal - inverted heatmap",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 0
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"node": "Merge5",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 1
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"node": "DeepGaze",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 0
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"node": "asmModel - inverted heatmap",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 0
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"Credentials": {
|
|||
|
|
"main": [
|
|||
|
|
[
|
|||
|
|
{
|
|||
|
|
"node": "Merge2",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 0
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"LLaVA-based object types extractor": {
|
|||
|
|
"main": [
|
|||
|
|
[
|
|||
|
|
{
|
|||
|
|
"node": "Labels string",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 0
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"Merge5": {
|
|||
|
|
"main": [
|
|||
|
|
[
|
|||
|
|
{
|
|||
|
|
"node": "Grounding DINO",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 0
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"Labels string": {
|
|||
|
|
"main": [
|
|||
|
|
[
|
|||
|
|
{
|
|||
|
|
"node": "Merge5",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 0
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"Inverted heatmap": {
|
|||
|
|
"main": [
|
|||
|
|
[]
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"unisal - inverted heatmap": {
|
|||
|
|
"main": [
|
|||
|
|
[
|
|||
|
|
{
|
|||
|
|
"node": "Merge6",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 2
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"asmModel - inverted heatmap": {
|
|||
|
|
"main": [
|
|||
|
|
[
|
|||
|
|
{
|
|||
|
|
"node": "Merge6",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 3
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"Merge6": {
|
|||
|
|
"main": [
|
|||
|
|
[
|
|||
|
|
{
|
|||
|
|
"node": "Inverted heatmap - Compare",
|
|||
|
|
"type": "main",
|
|||
|
|
"index": 0
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
"active": false,
|
|||
|
|
"settings": {
|
|||
|
|
"executionOrder": "v1",
|
|||
|
|
"binaryMode": "separate",
|
|||
|
|
"availableInMCP": false
|
|||
|
|
},
|
|||
|
|
"versionId": "5e97360b-e09b-43a9-962f-91090d292f8c",
|
|||
|
|
"meta": {
|
|||
|
|
"instanceId": "1e4ac0fc2b33692d40da602263ad5f150100624f047385c3b326b30a4678b299"
|
|||
|
|
},
|
|||
|
|
"id": "ByacxQXqRD7pGkWW",
|
|||
|
|
"tags": []
|
|||
|
|
}
|