{
  "name": "Lumos",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "start",
        "responseMode": "responseNode",
        "options": {
          "allowedOrigins": "*",
          "binaryPropertyName": "audio"
        }
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        0,
        0
      ],
      "id": "ca0b83a3-67fc-468d-bb60-a054e36df584",
      "name": "Webhook",
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "{\"status\": \"error\", \"code\": \"INVALID_REQUEST\", \"message\": \"Requ\u00eate invalide ou fichier audio manquant\"}",
        "options": {
          "responseCode": 400
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        0,
        240
      ],
      "id": "a1b2c3d4-0001-0001-0001-000000000001",
      "name": "Webhook Error"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://host.docker.internal:8000/transcribe",
        "sendBody": true,
        "contentType": "multipart-form-data",
        "bodyParameters": {
          "parameters": [
            {
              "parameterType": "formBinaryData",
              "name": "audio",
              "inputDataFieldName": "audio"
            }
          ]
        },
        "options": {
          "timeout": 30000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        280,
        0
      ],
      "id": "88ae1dd3-9852-4bb6-811e-6c50ceb791fe",
      "name": "Whisper Transcription",
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "{\"status\": \"error\", \"code\": \"WHISPER_OFFLINE\", \"message\": \"Service de transcription indisponible. V\u00e9rifiez que le serveur Whisper tourne sur le port 8000.\"}",
        "options": {
          "responseCode": 503
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        280,
        240
      ],
      "id": "a1b2c3d4-0001-0001-0001-000000000002",
      "name": "Whisper Error"
    },
    {
      "parameters": {
        "modelId": {
          "__rl": true,
          "value": "models/gemini-2.5-flash",
          "mode": "list",
          "cachedResultName": "models/gemini-2.5-flash"
        },
        "messages": {
          "values": [
            {
              "content": "=Tu es un assistant domotique. Analyse cette commande vocale et retourne UNIQUEMENT un tableau JSON valide, sans markdown, sans explication, sans backticks.\n\nPi\u00e8ces disponibles :\n- salon (pin 2)\n- cuisine (pin 6)\n- chambre_paul (pin 8)\n- chambre_principale (pin 13)\n\nActions possibles : on, off\n\nR\u00e8gle importante : retourne TOUJOURS un tableau, m\u00eame pour une seule action.\n\nExemples de r\u00e9ponses attendues :\n\"allume le salon\" -> [{\"room\": \"salon\", \"action\": \"on\", \"pin\": 2}]\n\"\u00e9teins tout\" -> [{\"room\": \"salon\", \"action\": \"off\", \"pin\": 2}, {\"room\": \"cuisine\", \"action\": \"off\", \"pin\": 6}, {\"room\": \"chambre_paul\", \"action\": \"off\", \"pin\": 8}, {\"room\": \"chambre_principale\", \"action\": \"off\", \"pin\": 13}]\n\"allume la chambre de paul et le salon\" -> [{\"room\": \"chambre_paul\", \"action\": \"on\", \"pin\": 8}, {\"room\": \"salon\", \"action\": \"on\", \"pin\": 2}]\n\nSi la commande est incompr\u00e9hensible ou ne concerne pas une lumi\u00e8re :\n[{\"error\": \"commande non reconnue\"}]\n\nCommande vocale : {{ $json.text }}"
            }
          ]
        },
        "jsonOutput": true,
        "builtInTools": {},
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.googleGemini",
      "typeVersion": 1.1,
      "position": [
        560,
        0
      ],
      "id": "d9e04136-7e58-4b8b-91f9-293d0abdeacc",
      "name": "Gemini LLM",
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "{\"status\": \"error\", \"code\": \"LLM_ERROR\", \"message\": \"Erreur lors de l'interpr\u00e9tation de la commande. V\u00e9rifiez votre cl\u00e9 API Gemini.\"}",
        "options": {
          "responseCode": 502
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        560,
        240
      ],
      "id": "a1b2c3d4-0001-0001-0001-000000000003",
      "name": "Gemini Error"
    },
    {
      "parameters": {
        "jsCode": "const data = $input.first().json;\n\n// Gemini jsonOutput:true retourne directement l'objet/tableau\n// mais on g\u00e8re aussi le cas string au cas o\u00f9\nlet parsed;\nif (typeof data === 'string') {\n  const cleaned = data\n    .replace(/```json/g, '')\n    .replace(/```/g, '')\n    .replace(/`/g, '')\n    .trim();\n  parsed = JSON.parse(cleaned);\n} else {\n  parsed = data;\n}\n\n// Normaliser en tableau\nconst commands = Array.isArray(parsed) ? parsed : [parsed];\n\n// R\u00e9cup\u00e9rer la transcription depuis le node Whisper\nconst transcription = $('Whisper Transcription').first().json.text || '';\n\n// V\u00e9rifier si Gemini a retourn\u00e9 une erreur\nif (commands.length === 1 && commands[0].error) {\n  return [{\n    json: {\n      status: 'error',\n      code: 'COMMAND_NOT_RECOGNIZED',\n      message: 'Commande non reconnue : ' + commands[0].error,\n      transcription: transcription\n    }\n  }];\n}\n\n// Succ\u00e8s\nreturn [{\n  json: {\n    status: 'success',\n    transcription: transcription,\n    commands: commands\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        840,
        0
      ],
      "id": "3b6b0210-857a-4cf0-8cbe-f2176e8b38a9",
      "name": "Parse Commands",
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "{\"status\": \"error\", \"code\": \"PARSE_ERROR\", \"message\": \"Impossible de parser la r\u00e9ponse du LLM.\"}",
        "options": {
          "responseCode": 500
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        840,
        240
      ],
      "id": "a1b2c3d4-0001-0001-0001-000000000004",
      "name": "Parse Error"
    },
    {
      "parameters": {
        "respondWith": "firstIncomingItem",
        "options": {
          "responseCode": 200
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        1120,
        0
      ],
      "id": "a1b2c3d4-0001-0001-0001-000000000005",
      "name": "Success Response"
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Whisper Transcription",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Webhook Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Whisper Transcription": {
      "main": [
        [
          {
            "node": "Gemini LLM",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Whisper Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gemini LLM": {
      "main": [
        [
          {
            "node": "Parse Commands",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Gemini Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Commands": {
      "main": [
        [
          {
            "node": "Success Response",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Parse Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate"
  },
  "versionId": "68f73fc4-9760-4e7b-b5e6-07eff4c43d78",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "id": "Fl2dg3L5i5Ip1YLZ",
  "tags": []
}