{
  "name": "Paiwan to Chinese api",
  "nodes": [
    {
      "parameters": {
        "method": "POST",
        "url": "http://host.docker.internal:8000/translate/paiwan-to-chinese",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"text\": \"{{ $json.token }}\"\n}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "text"
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        400,
        460
      ],
      "id": "8411e95e-af54-4527-a12a-239eb0222026",
      "name": "HTTP Request1"
    },
    {
      "parameters": {
        "jsCode": "// \u932f\u8aa4\u793a\u4f8b\uff1a\u6bcf\u62c6\u4e00\u500b token \u5c31 return \u4e00\u7b46\nconst paiwan = $input.first().json.paiwan_sentences;\nconst rawTokens = paiwan.split(/[\\s,\uff0c\u3001]+/);\nconst tokens = rawTokens.filter(t => t.trim().length > 0);\nconst results = tokens.map(token => ({ json: { token: token } }));\nreturn results;\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        200,
        460
      ],
      "id": "d4570cff-164d-4e00-ab8c-916d27bd5ffe",
      "name": "Code"
    },
    {
      "parameters": {
        "model": "gemma3:1b",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOllama",
      "typeVersion": 1,
      "position": [
        1240,
        800
      ],
      "id": "7e3b6b7f-a37f-416f-a859-3875e28d28a7",
      "name": "Ollama Chat Model1",
      "credentials": {
        "ollamaApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// n8n \u7684 Function \u7bc0\u9ede\u9810\u8a2d\u6703\u50b3\u9032 $input \u8b8a\u6578\u88e1\u9762\u662f\u300c\u4e00\u500b items \u9663\u5217\u300d\uff0c\n// \u9019\u88e1\u5047\u8a2d\u4e0a\u6e38\u53ea\u50b3\u4f86\u4e00\u7b46\u6216\u591a\u7b46\uff0c\u4f46\u6bcf\u7b46\u88e1\u7684 data \u5c6c\u6027\u90fd\u8981\u89e3\u6790\u3002\n\n// \u6211\u5011\u8981\u56de\u50b3\u4e00\u500b Array\uff0c\u5305\u542b\u89e3\u6790\u5f8c\u7684\u7269\u4ef6\nconst newItems = [];\n\n// \u904d\u6b77\u6240\u6709\u8f38\u5165 item\nfor (const item of $input.all()) {\n  // 1. \u53d6\u5f97\u76ee\u524d item \u88e1\u7684 data \u6b04\u4f4d\uff08\u5b83\u662f\u4e00\u500b JSON \u5b57\u4e32\uff09\n  const dataString = item.json[\"data\"];\n\n  let parsed = {};\n  try {\n    // 2. \u505a\u4e00\u6b21 JSON.parse\uff0c\u628a\u5b57\u4e32\u9084\u539f\u6210\u7269\u4ef6\n    parsed = JSON.parse(dataString);\n  } catch (error) {\n    // \u5982\u679c parse \u5931\u6557\uff0c\u53ef\u4ee5\u9078\u64c7\u628a error \u5370\u51fa\u6216\u7e7c\u7e8c\u4fdd\u7559\u539f\u503c\n    parsed = {};\n    console.error(\"JSON.parse error for data:\", dataString, error);\n  }\n\n  // 3. parsed \u9019\u6642\u5019\u61c9\u8a72\u9577\u5f97\u50cf { tokens: \"situ\", result: \"\u5b78\u751f\" }\n  //    \u5982\u679c\u8981\u540c\u6642\u4fdd\u7559\u5176\u4ed6\u6b04\u4f4d\uff0c\u53ef\u5beb\u6210\uff1a\n  // const merged = { ...item.json, ...parsed };\n\n  // 4. \u9019\u88e1\u793a\u7bc4\u53ea\u8f38\u51fa parsed \u7269\u4ef6\uff08\u53ef\u4f9d\u9700\u6c42\u81ea\u884c\u8abf\u6574\uff09\n  newItems.push({ json: parsed });\n}\n\n// 5. \u56de\u50b3\u89e3\u6790\u597d\u7684\u9663\u5217\nreturn newItems;\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        620,
        460
      ],
      "id": "e06a8626-becc-4b78-ac6c-3d34f139ea90",
      "name": "Parse Data Field"
    },
    {
      "parameters": {
        "jsCode": "// \u6b64\u6642 $input.all() \u6703\u662f\u4e00\u500b\u9663\u5217\uff0c\u6bcf\u7b46\u9577\u5f97\u50cf { json: { tokens:\"...\", result:\"...\" } }\nconst allItems = $input.all();\nconst mappingList = [];\n\n// \u9010\u7b46\u628a tokens/result \u7d44\u6210 { token, translation }\uff0c\u63a8\u5230 mappingList\nfor (const item of allItems) {\n  const token = item.json[\"tokens\"] || \"\";\n  const translation = item.json[\"result\"] || \"\";\n  mappingList.push({\n    token: token,\n    translation: translation\n  });\n  \n}\n\n// \u56de\u50b3\u5f8c\u53ea\u5269\u4e0b\u4e00\u7b46\uff0c\u88e1\u9762\u5e36 mappingList \u9663\u5217\nreturn [\n  {\n    json: {\n      mappingList\n    }\n  }\n];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        860,
        460
      ],
      "id": "efdc9d51-9483-45d0-b898-a3024a267cc3",
      "name": "Build Mapping List"
    },
    {
      "parameters": {
        "jsCode": "// \u53d6\u5f97\u6700\u4e0a\u5c64\u300cWhen chat message received\u300d\u7684\u90a3\u4e00\u7b46 item\n// \u7bc0\u9ede\u540d\u7a31\u5982\u679c\u4e0d\u662f\u525b\u597d\u53eb \"When chat message received\"\uff0c\u8acb\u6539\u6210\u4f60\u7684\u5be6\u969b\u540d\u7a31\n\n// \u539f\u59cb\u6392\u7063\u8a9e\u53e5\u5b50\uff0c\u53ef\u80fd\u5b58\u5728 paiwanText\uff0c\u4e5f\u53ef\u80fd\u5b58\u5728 message\nconst paiwanText = $('Loop Over Items').first().json.paiwan_sentences\n\n// \u4e4b\u524d\u4f60\u5df2\u7d93\u6709 mappingList\nconst mappingList = $input.all()[0].json.mappingList || [];\n\n// \u751f\u6210\u591a\u884c\u5c0d\u7167\nconst lines = mappingList.map(e => `- \u6392\u7063\u8a9e\uff1a${e.token} \u2192 \u4e2d\u6587\uff1a${e.translation}`);\nconst formattedText = lines.join(\"\\n\");\n\n// \u6700\u7d42\u56de\u50b3\u6642\uff0c\u628a paiwanText \u4e00\u4f75\u5e36\u51fa\nreturn [\n  {\n    json: {\n      paiwanText,\n      formattedText\n    }\n  }\n];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1120,
        460
      ],
      "id": "7dc15952-32b1-42f5-bf37-471599a06993",
      "name": "Code1"
    },
    {
      "parameters": {
        "model": "deepseek-r1-distill-llama-70b",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGroq",
      "typeVersion": 1,
      "position": [
        1400,
        800
      ],
      "id": "f35e8ee0-5eea-490c-9e07-6746cecbd092",
      "name": "Groq Chat Model",
      "credentials": {
        "groqApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "modelName": "models/gemma-3-27b-it",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "typeVersion": 1,
      "position": [
        1140,
        720
      ],
      "id": "ccd8148c-35c4-4774-ad72-d5ecef6aa5c5",
      "name": "Google Gemini Chat Model",
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        -700,
        300
      ],
      "id": "ece55585-2961-4dbf-8165-bb88fae2e6b3",
      "name": "When clicking \u2018Execute workflow\u2019"
    },
    {
      "parameters": {
        "url": "http://host.docker.internal:8001/paiwan-sentences",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -440,
        300
      ],
      "id": "9130d8b7-b4d1-4aab-aef2-e3b0c6cc494b",
      "name": "InputJson"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=\u4f60\u64c1\u6709\u975e\u51e1\u7684\u601d\u8003\u80fd\u529b\u3002\u9019\u610f\u5473\u8457\u4f60\u6703\u5728\u69cb\u601d\u6700\u7d42\u7b54\u6848\u4e4b\u524d\uff0c\u4ed4\u7d30\u601d\u8003\u6bcf\u500b\u6b65\u9a5f\u3002\u9019\u500b\u601d\u8003\u904e\u7a0b\u4ee5<thinking>\u958b\u59cb\uff0c\u4ee5</thinking>\u7d50\u675f\u3002\n\n\u4f60\u662f\u4e00\u500b\u6392\u7063\u8a9e\u7684\u7ffb\u8b6f\u5c08\u5bb6\u4ee5\u4e0b\u6709\u4e00\u500b\u6392\u7063\u8a9e\u7247\u6bb5\u7684\u300c\u8a5e\u5f59\u5c0d\u7167\u300d\u5217\u8868\uff0c\u8acb\u4f60\u6839\u64da\u6bcf\u500b\u300c\u6392\u7063\u8a9e\u8a5e \u2192 \u5c0d\u61c9\u4e2d\u6587\u300d\u7684 mapping\uff0c\u7d44\u6210\u4e00\u500b\u5b8c\u6574\u4e14\u6700\u901a\u9806\u7684\u4e2d\u6587\u53e5\u5b50(\u4e0d\u4e00\u5b9a\u662f\u53e5\u5b50\uff0c\u53ef\u80fd\u662f\u55ae\u5b57)\uff0c\u4e26\u5fe0\u5be6\u8868\u9054\u539f\u6587\u542b\u7fa9\uff0c\u5982\u679c\u4f60\u89ba\u5f97\u6539\u8b8a\u8a5e\u8a9e\u9806\u5e8f\u80fd\u66f4\u901a\u66a2\uff0c\u90a3\u4f60\u53ef\u4ee5\u6539\u8b8a\u3002\u4f60\u4e5f\u53ef\u4ee5\u53c3\u8003\u6a19\u9ede\u7b26\u865f\u53bb\u505a\u63a8\u6e2c\u3002\u53ef\u80fd\u4e00\u500b\u8a5e\u5f59\u6709\u591a\u500b\u610f\u601d\uff0c\u4ed6\u6703\u4ee5,\u505a\u5340\u9694\u3002\n\n\u8a5e\u5f59\u5c0d\u7167\uff1a\n{{ $json.formattedText }}\n\u539f\u6587:\n{{ $json.paiwanText }}\n\u6700\u5f8c\uff0c\u8acb\u8f38\u51fa\u6700\u7d42\u5b8c\u6574\u8b6f\u6587\uff0c\u4e26\u5c07\u7b54\u6848\u4ee5<ans>\u958b\u59cb\uff0c\u4ee5</ans>\u7d50\u675f\u3002\u3002\n\n\u6392\u7063\u65cf\u7684\u6587\u6cd5\u88dc\u5145(\u5728\u63a5\u4e0b\u4f86\u7684\u7ffb\u8b6f\u4efb\u52d9\u4e0d\u4e00\u5b9a\u6703\u7528\u5230):\n\u6392\u7063\u65cf\u5b58\u5728\u8907\u5408\u8a5e\n\u8907\u5408\u8a5e\u70ba\u5177\u6709\u610f\u7fa9\u7684\u5169\u500b\u8a5e\u7d20\u7dca\u5bc6\u7d50\u5408\u6210\u4e00\u500b\u65b0\u8a5e\u3002\u5169\u500b\u8a5e\u7d44\u5408\u6210\u70ba\u65b0\u8a5e,\u4e2d\u9593\u6703\u6709\u4e00\u500b\u6a19\u8a18,\u53ef\u80fd\u662fa\u6216\u662fna\n\u5982:\nvavayan\u300c\u5973\u6027\u300d+ a + vatu\u300c\u72d7\u300d=\u300c\u6bcd\u72d7\u300d\nuqaljay\u300c\u7537\u6027\u300d+ a + vatu\u300c\u72d7\u300d=\u300c\u516c\u72d7\u300d\n\nalju\u300c\u7cd6\u300d+ na + hana\u300c\u82b1\u300d=\u300c\u82b1\u871c\u300d\nalju\u300c\u7cd6\u300d+ na + tjainan\u300c\u871c\u8702\u300d=\u300c\u8702\u871c\u300d",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 2,
      "position": [
        1360,
        460
      ],
      "id": "622269ba-2207-4b5c-b832-cb1ba0150efd",
      "name": "Restructure"
    },
    {
      "parameters": {
        "fieldToSplitOut": "paiwan_sentences",
        "include": "=",
        "options": {}
      },
      "type": "n8n-nodes-base.splitOut",
      "typeVersion": 1,
      "position": [
        -220,
        300
      ],
      "id": "f5218b14-b1ab-4295-bb7b-34291a40e9ba",
      "name": "Split Out"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        20,
        300
      ],
      "id": "2fef72a7-424c-4e03-9306-b6aad8d287dc",
      "name": "Loop Over Items"
    },
    {
      "parameters": {
        "jsCode": "// 1. \u53d6\u51fa LLM \u56de\u50b3\u7684\u539f\u59cb\u5167\u5bb9\uff08\u4f9d\u4f60\u7684\u6b04\u4f4d\u540d\u7a31\u8abf\u6574\uff09\nconst raw = $input.first().json.output ?? '';   // \u4f8b\u5982 $json.text\n\n// 2. \u6293 <ans> ... </ans> \u4e2d\u9593\u7684\u5b57\nconst match = raw.match(/<ans>([\\s\\S]*?)<\\/ans>/);\nconst answer = match ? match[1].trim() : raw;   // \u82e5\u6c92\u627e\u5230\u5c31\u56de\u6574\u4e32\n\n// 3. \u53ea\u8f38\u51fa\u60f3\u8981\u7684\u6b04\u4f4d\nreturn [{\n  json: { answer }\n}];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1740,
        460
      ],
      "id": "5ef0b316-882f-4c19-9ad5-a211e36b4d0b",
      "name": "Code2"
    },
    {
      "parameters": {
        "jsCode": "\nconst raw = $input.first().json.answer          // \u770b\u4f60\u7684\u6b04\u4f4d\u540d\u7a31\nconst match = raw.match(/<ans>([\\s\\S]*?)<\\/ans>/);\nconst answer = match ? match[1].trim() : raw;          // \u6293\u4e0d\u5230\u5c31\u6574\u4e32\u8fd4\u56de\n\n// ===== \u8f38\u51fa\u683c\u5f0f\uff1a\u53ea\u4fdd\u7559\u53e5\u5b50\uff0b\u7b54\u6848 =====\nreturn [{\n  json: {\n    answer\n  }\n}];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2040,
        260
      ],
      "id": "3c6b68b1-9ac7-44e2-8ab2-7e853c564e88",
      "name": "build result"
    },
    {
      "parameters": {
        "aggregate": "aggregateAllItemData",
        "destinationFieldName": "results",
        "options": {}
      },
      "type": "n8n-nodes-base.aggregate",
      "typeVersion": 1,
      "position": [
        240,
        200
      ],
      "id": "12d2d6db-29b0-4d38-a53a-b72346a05b70",
      "name": "Aggregate"
    }
  ],
  "connections": {
    "HTTP Request1": {
      "main": [
        [
          {
            "node": "Parse Data Field",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code": {
      "main": [
        [
          {
            "node": "HTTP Request1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Data Field": {
      "main": [
        [
          {
            "node": "Build Mapping List",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Mapping List": {
      "main": [
        [
          {
            "node": "Code1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code1": {
      "main": [
        [
          {
            "node": "Restructure",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Restructure",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "When clicking \u2018Execute workflow\u2019": {
      "main": [
        [
          {
            "node": "InputJson",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "InputJson": {
      "main": [
        [
          {
            "node": "Split Out",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Restructure": {
      "main": [
        [
          {
            "node": "Code2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Items": {
      "main": [
        [
          {
            "node": "Aggregate",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code2": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "build result": {
      "main": [
        []
      ]
    },
    "Aggregate": {
      "main": [
        []
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "f51b7031-c9b4-433e-a9f9-4c3ea9abe07b",
  "id": "eunhLs0f6JEx3R1I",
  "tags": []
}