{
  "name": "Multi Language Translator",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "translate",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "b99c378f-e2b2-4a0f-ac9a-2198c9159c6b",
      "name": "\u7ffb\u8bd1\u8bf7\u6c42",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [
        720,
        120
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://host.docker.internal:8000/v1/chat/completions",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"model\": \"gemini-2.5-pro\",\n  \"messages\": [\n    {\n      \"role\": \"system\",\n      \"content\": \"\u4f60\u662f\u4e13\u4e1a\u7684\u7ffb\u8bd1\u52a9\u624b\u3002\u8bf7\u5c06\u7528\u6237\u63d0\u4f9b\u7684\u6587\u672c\u7ffb\u8bd1\u6210\u5e38\u7528\u8bed\u8a00\u3002\u8bf7\u7528JSON\u683c\u5f0f\u8fd4\u56de\u7ffb\u8bd1\u7ed3\u679c\u3002\"\n    },\n    {\n      \"role\": \"user\",\n      \"content\": \"\u8bf7\u5c06 {{ $('\u7ffb\u8bd1\u8bf7\u6c42').item.json.body.text }}\uff0c\u7ffb\u8bd1\u6210 {{ $('\u7ffb\u8bd1\u8bf7\u6c42').item.json.body.target_languages.join(',') }}\"\n    }\n  ],\n  \"project_id\": \"{{ $json.project_id }}\"\n}",
        "options": {
          "timeout": 30000
        }
      },
      "id": "abb91ddd-a096-4248-9ac5-f3e55839de50",
      "name": "Gemini \u7ffb\u8bd1",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.1,
      "position": [
        1220,
        120
      ]
    },
    {
      "parameters": {
        "jsCode": "// \u83b7\u53d6\u6570\u636e\nconst geminiResponse = $input.all()[0].json;\nconst translationText = geminiResponse.choices[0].message.content;\nconst webhookData = $('\u7ffb\u8bd1\u8bf7\u6c42').all()[0].json;\n\n// \u5904\u7406\u6362\u884c\u7b26\nconst cleanText = translationText.replace(/\\\\n/g, '\\n');\n\n// \u4fee\u590d\uff1a\u6570\u636e\u5728 body \u91cc\u9762\uff01\nconst requestBody = webhookData.body || webhookData;\nconst originalText = requestBody.text;\nconst originalLanguages = requestBody.target_languages || [];\n\nconsole.log(\"=== \u4fee\u590d\u540e\u7684\u6570\u636e\u83b7\u53d6 ===\");\nconsole.log(\"requestBody:\", requestBody);\nconsole.log(\"originalLanguages:\", originalLanguages);\n\n// \u8bed\u8a00\u6620\u5c04\nconst languageMapping = {\n  \"\u4e2d\u6587\": \"Chinese\", \"Chinese\": \"Chinese\",\n  \"\u65e5\u8bed\": \"Japanese\", \"\u65e5\u6587\": \"Japanese\", \"Japanese\": \"Japanese\", \"\u65e5\u672c\u8a9e\": \"Japanese\",\n  \"\u97e9\u8bed\": \"Korean\", \"\u97e9\u6587\": \"Korean\", \"Korean\": \"Korean\", \"\ud55c\uad6d\uc5b4\": \"Korean\", \n  \"\u6cd5\u8bed\": \"French\", \"\u6cd5\u6587\": \"French\", \"French\": \"French\", \"Fran\u00e7ais\": \"French\",\n  \"\u5fb7\u8bed\": \"German\", \"\u5fb7\u6587\": \"German\", \"German\": \"German\", \"Deutsch\": \"German\",\n  \"\u82f1\u8bed\": \"English\", \"\u82f1\u6587\": \"English\", \"English\": \"English\"\n};\n\n// \u8bed\u8a00\u68c0\u6d4b\u6a21\u5f0f\nconst languagePatterns = {\n  \"Chinese\": [\"\u4e2d\u6587\", \"Chinese\"],\n  \"Japanese\": [\"\u65e5\u8bed\", \"\u65e5\u6587\", \"Japanese\", \"\u65e5\u672c\u8a9e\"],\n  \"Korean\": [\"\u97e9\u8bed\", \"\u97e9\u6587\", \"Korean\", \"\ud55c\uad6d\uc5b4\"],\n  \"French\": [\"\u6cd5\u8bed\", \"\u6cd5\u6587\", \"French\", \"Fran\u00e7ais\"], \n  \"German\": [\"\u5fb7\u8bed\", \"\u5fb7\u6587\", \"German\", \"Deutsch\"],\n  \"English\": [\"\u82f1\u8bed\", \"\u82f1\u6587\", \"English\"]\n};\n\n// \u6807\u51c6\u5316\u8bed\u8a00\u540d\u79f0\nfunction normalizeLanguages(inputLanguages) {\n  return inputLanguages.map(lang => {\n    return languageMapping[lang] || languageMapping[lang.toLowerCase()] || lang;\n  });\n}\n\n// \u52a8\u6001\u63d0\u53d6\u7ffb\u8bd1\nfunction extractTranslationsDynamically(text, normalizedLanguages) {\n  const translations = {};\n  const lines = text.split('\\n');\n  \n  normalizedLanguages.forEach(targetLang => {\n    const patterns = languagePatterns[targetLang] || [targetLang];\n    \n    lines.forEach(line => {\n      const trimmedLine = line.trim();\n      \n      if (trimmedLine.includes(':**') && !translations[targetLang]) {\n        const hasLanguage = patterns.some(pattern => \n          trimmedLine.toLowerCase().includes(pattern.toLowerCase())\n        );\n        \n        if (hasLanguage) {\n          const afterColon = trimmedLine.split(':**')[1];\n          if (afterColon) {\n            translations[targetLang] = afterColon.trim();\n          }\n        }\n      }\n    });\n  });\n  \n  return translations;\n}\n\n// \u5904\u7406\u8bed\u8a00\u6807\u51c6\u5316\nconst normalizedLanguages = normalizeLanguages(originalLanguages);\n\n// \u63d0\u53d6\u7ffb\u8bd1\nlet translations = extractTranslationsDynamically(cleanText, normalizedLanguages);\n\n// \u6784\u5efa\u8fd4\u56de\u7ed3\u679c\nconst result = {\n  success: true,\n  original_text: originalText,\n  requested_languages: normalizedLanguages,\n  translations: translations,\n  extracted_count: Object.keys(translations).length,\n  timestamp: new Date().toISOString(),\n  model_used: geminiResponse.model,\n  request_id: geminiResponse.id\n};\n\nreturn {\n  json: result\n};"
      },
      "id": "40492fc4-2a4b-40fb-934b-d31e94607d30",
      "name": "\u683c\u5f0f\u5316\u7ffb\u8bd1\u7ed3\u679c",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1460,
        120
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ $json }}",
        "options": {}
      },
      "id": "1c53fdd1-55e1-4dc7-a156-1fa597b357ee",
      "name": "\u8fd4\u56de\u7ffb\u8bd1\u7ed3\u679c",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        1680,
        120
      ]
    },
    {
      "parameters": {},
      "id": "69b49d3c-1e17-4385-b179-8db11608153b",
      "name": "\u9519\u8bef\u5904\u7406",
      "type": "n8n-nodes-base.errorTrigger",
      "typeVersion": 1,
      "position": [
        1040,
        320
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={\n  \"success\": false,\n  \"error\": \"{{ $json.error?.message || 'Unknown error' }}\",\n  \"timestamp\": \"{{ new Date().toISOString() }}\",\n  \"details\": \"Gemini CLI \u670d\u52a1\u53ef\u80fd\u6682\u65f6\u4e0d\u53ef\u7528\uff0c\u8bf7\u7a0d\u540e\u91cd\u8bd5\"\n}",
        "options": {}
      },
      "id": "5a96dd26-ddc9-43ca-a4d8-9e8afb5ad08a",
      "name": "\u9519\u8bef\u54cd\u5e94",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        1300,
        320
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "eb469860-ec95-44aa-864d-4725ce567a65",
              "name": "project_id",
              "value": "YOUR_GOOGLE_CLOUD_PROJECT",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        980,
        120
      ],
      "id": "6ce4924a-f945-42ae-b289-5aad3d0713b8",
      "name": "\u8bbe\u7f6e Google Cloud \u9879\u76eeID"
    },
    {
      "parameters": {
        "content": "# \ud83c\udf0d n8n + Gemini \u667a\u80fd\u7ffb\u8bd1\u670d\u52a1\n\n## \ud83d\udccb \u57fa\u672c\u4fe1\u606f\n- **\u5de5\u4f5c\u6d41\u540d\u79f0**: Smart Translate API \n- **\u7248\u672c**: v0.0.1\n- **\u521b\u5efa\u8005**: LQ\n- **\u5fae\u4fe1**\uff1acloud-native-101\n- **\u516c\u4f17\u53f7**: \u6797\u6708\u534a\u5b50\u7684AI\u7b14\u8bb0\n\n## \ud83c\udfaf \u529f\u80fd\u6982\u8ff0\n\u57fa\u4e8e Google Gemini API \u6784\u5efa\u7684\u591a\u8bed\u8a00\u7ffb\u8bd1\u670d\u52a1\uff0c\u901a\u8fc7 Webhook \u63a5\u53e3\u63d0\u4f9b\u5b9e\u65f6\u7ffb\u8bd1\u529f\u80fd\u3002\u652f\u6301\u4e2d\u6587\u3001\u82f1\u8bed\u3001\u65e5\u8bed\u3001\u97e9\u8bed\u3001\u6cd5\u8bed\u3001\u5fb7\u8bed\u7b49\u591a\u79cd\u8bed\u8a00\u4e92\u8bd1\uff0c\u8fd4\u56de\u7ed3\u6784\u5316JSON\u683c\u5f0f\u7684\u7ffb\u8bd1\u7ed3\u679c\u3002\n\n## \ud83d\udcca \u914d\u7f6e\u8bf4\u660e\n### 1. \u90e8\u7f72 Gemini CLI API\n```\npython main.py\n```\n### 2. \u914d\u7f6e\u5de5\u4f5c\u6d41\n- \u66ff\u6362 Google Cloud \u9879\u76eeID\n- \u76ee\u6807\u8bed\u8a00\u53ef\u5728\u201c\u683c\u5f0f\u5316\u7ffb\u8bd1\u7ed3\u679c\u201d\u8282\u70b9\u81ea\u884c\u6269\u5c55\n\n",
        "height": 880,
        "width": 1820,
        "color": 5
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        140,
        -380
      ],
      "id": "38d5df8a-c18d-401e-acb9-a4792cc5dd70",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "content": "## API\u8c03\u7528\u793a\u4f8b\n```bash\ncurl -X POST http://localhost:5678/webhook/translate \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"text\": \"Hello, how are you today?\",\n    \"target_languages\": [\"\u4e2d\u6587\", \"\u65e5\u8bed\", \"\u6cd5\u8bed\"]\n  }'\n```\n\n## \u54cd\u5e94\u683c\u5f0f\n\n```json\n{\n  \"success\": true,\n  \"original_text\": \"Hello, how are you today?\",\n  \"requested_languages\": [\"Chinese\", \"Japanese\", \"French\"],\n  \"translations\": {\n    \"Chinese\": \"\u4f60\u597d\uff0c\u4f60\u4eca\u5929\u600e\u4e48\u6837\uff1f\",\n    \"Japanese\": \"\u3053\u3093\u306b\u3061\u306f\u3001\u4eca\u65e5\u306f\u3044\u304b\u304c\u3067\u3059\u304b\uff1f\",\n    \"French\": \"Bonjour, comment allez-vous aujourd'hui ?\"\n  },\n  \"extracted_count\": 3,\n  \"timestamp\": \"2024-01-15T10:30:00.000Z\",\n  \"model_used\": \"gemini-2.5-pro\",\n  \"request_id\": \"req_123456789\"\n}\n```",
        "height": 880,
        "width": 920,
        "color": 4
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        2000,
        -380
      ],
      "id": "a29073e0-2eed-4cfb-a737-c3f8ccb8d976",
      "name": "Sticky Note1"
    }
  ],
  "connections": {
    "\u7ffb\u8bd1\u8bf7\u6c42": {
      "main": [
        [
          {
            "node": "\u8bbe\u7f6e Google Cloud \u9879\u76eeID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gemini \u7ffb\u8bd1": {
      "main": [
        [
          {
            "node": "\u683c\u5f0f\u5316\u7ffb\u8bd1\u7ed3\u679c",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u683c\u5f0f\u5316\u7ffb\u8bd1\u7ed3\u679c": {
      "main": [
        [
          {
            "node": "\u8fd4\u56de\u7ffb\u8bd1\u7ed3\u679c",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u9519\u8bef\u5904\u7406": {
      "main": [
        [
          {
            "node": "\u9519\u8bef\u54cd\u5e94",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u8bbe\u7f6e Google Cloud \u9879\u76eeID": {
      "main": [
        [
          {
            "node": "Gemini \u7ffb\u8bd1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "a67ff76a-0ab2-4105-8a80-72c65183d6cd",
  "id": "v8BWCDdLu9WpPZAq",
  "tags": []
}