{
  "name": "AI Meeting Summary Workflow",
  "nodes": [
    {
      "id": "trigger",
      "name": "Audio Input Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        240,
        300
      ],
      "parameters": {}
    },
    {
      "id": "webhook",
      "name": "Webhook Input",
      "type": "n8n-nodes-base.webhook",
      "position": [
        240,
        300
      ],
      "parameters": {
        "httpMethod": "POST",
        "path": "meeting-audio-upload"
      },
      "webhookId": "meeting-audio-webhook"
    },
    {
      "id": "validate-input",
      "name": "Validate Audio Input",
      "type": "n8n-nodes-base.function",
      "position": [
        520,
        300
      ],
      "parameters": {
        "functionCode": "const audioFile = $input.first().json;\n\n// Validate file type\nconst allowedTypes = ['.mp3', '.m4a'];\nconst fileExt = audioFile.name ? audioFile.name.slice((Math.max(0, audioFile.name.lastIndexOf('.')) || Infinity) + 1).toLowerCase() : '';\n\nif (!allowedTypes.includes('.' + fileExt)) {\n  throw new Error(`Invalid file type: ${fileExt}. Allowed types: ${allowedTypes.join(', ')}`);\n}\n\nreturn { validatedAudio: audioFile };"
      }
    },
    {
      "id": "upload-to-whisper",
      "name": "Upload to Whisper API",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        780,
        300
      ],
      "parameters": {
        "requestMethod": "POST",
        "url": "https://api.openai.com/v1/audio/transcriptions",
        "authentication": "apiKey",
        "sendHeaders": true,
        "headers": {
          "Content-Type": "multipart/form-data"
        },
        "body": {
          "file": "={{ $input.first().json.validatedAudio }}",
          "model": "whisper-1"
        },
        "options": {}
      }
    },
    {
      "id": "parse-transcription",
      "name": "Parse Transcription",
      "type": "n8n-nodes-base.function",
      "position": [
        1040,
        300
      ],
      "parameters": {
        "functionCode": "// Parse transcription response\nconst transcription = $input.first().json.text;\n\nreturn { transcription };"
      }
    },
    {
      "id": "summarize-with-claude",
      "name": "Summarize with Claude",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1300,
        300
      ],
      "parameters": {
        "requestMethod": "POST",
        "url": "https://api.anthropic.com/v1/messages",
        "authentication": "genericCredentialType",
        "credentials": {
          "generic": "anthropicApi"
        },
        "sendHeaders": true,
        "headers": {
          "content-type": "application/json",
          "x-api-key": "={{ $credentials.apiKey }}",
          "anthropic-version": "2023-06-01"
        },
        "body": {
          "model": "claude-3-5-sonnet-20240620",
          "max_tokens": 1024,
          "messages": [
            {
              "role": "user",
              "content": "请帮我整理以下会议纪要，提取关键信息。请按以下格式输出：\n\n## 会议主题\n[在这里填写会议主题]\n\n## 关键要点\n- [要点1]\n- [要点2]\n- [要点3]\n\n## 行动项 (Action Items)\n- [任务描述] - [负责人] - [截止日期]\n- [任务描述] - [负责人] - [截止日期]\n\n## 参会人员\n- [姓名] - [职位/部门]\n\n以下是会议内容：\n\n{{ $json.transcription }}"
            }
          ]
        }
      }
    },
    {
      "id": "extract-action-items",
      "name": "Extract Action Items",
      "type": "n8n-nodes-base.function",
      "position": [
        1560,
        300
      ],
      "parameters": {
        "functionCode": "// Extract action items from summary\nconst summary = $input.first().json.content[0].text;\n\n// Simple regex to extract action items\nconst actionItemRegex = /-\\s*(.*?)\\s*-\\s*([^\\-\\n]+?)\\s*-\\s*(\\d{4}-\\d{2}-\\d{2}|[^\\-\\n]+)/g;\nlet match;\nconst actionItems = [];\n\nwhile ((match = actionItemRegex.exec(summary)) !== null) {\n  actionItems.push({\n    task: match[1].trim(),\n    assignee: match[2].trim(),\n    deadline: match[3].trim()\n  });\n}\n\nreturn {\n  summary: summary,\n  actionItems: actionItems\n};"
      }
    },
    {
      "id": "feishu-card-message",
      "name": "Feishu Card Message",
      "type": "n8n-nodes-base.function",
      "position": [
        1820,
        300
      ],
      "parameters": {
        "functionCode": "const { summary, actionItems } = $input.first().json;\n\n// Construct Feishu card message\nconst feishuCard = {\n  \"msg_type\": \"interactive\",\n  \"card\": {\n    \"config\": {\n      \"wide_screen_mode\": true\n    },\n    \"elements\": [\n      {\n        \"tag\": \"div\",\n        \"text\": {\n          \"tag\": \"plain_text\",\n          \"content\": \"会议纪要已整理完成，请查阅。\"\n        }\n      },\n      {\n        \"tag\": \"hr\"\n      },\n      {\n        \"tag\": \"div\",\n        \"text\": {\n          \"tag\": \"lark_md\",\n          \"content\": summary\n        }\n      },\n      {\n        \"tag\": \"hr\"\n      },\n      {\n        \"tag\": \"div\",\n        \"text\": {\n          \"tag\": \"lark_md\",\n          \"content\": \"**行动项清单**\\n\" + actionItems.map(item => `• ${item.task} (${item.assignee} - ${item.deadline})`).join('\\n')\n        }\n      }\n    ],\n    \"header\": {\n      \"template\": \"blue\",\n      \"title\": {\n        \"content\": \"📋 新会议纪要\",\n        \"tag\": \"plain_text\"\n      }\n    }\n  }\n};\n\nreturn { feishuCard };"
      }
    },
    {
      "id": "send-to-feishu",
      "name": "Send to Feishu",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2080,
        300
      ],
      "parameters": {
        "requestMethod": "POST",
        "url": "={{ $credentials.feishuWebhookUrl }}",
        "sendHeaders": true,
        "headers": {
          "Content-Type": "application/json"
        },
        "body": {
          "msg_type": "interactive",
          "card": "={{ $input.first().json.feishuCard.card }}"
        }
      }
    }
  ],
  "connections": {
    "trigger": {
      "main": [
        [
          {
            "node": "validate-input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "validate-input": {
      "main": [
        [
          {
            "node": "upload-to-whisper",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "upload-to-whisper": {
      "main": [
        [
          {
            "node": "parse-transcription",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "parse-transcription": {
      "main": [
        [
          {
            "node": "summarize-with-claude",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "summarize-with-claude": {
      "main": [
        [
          {
            "node": "extract-action-items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "extract-action-items": {
      "main": [
        [
          {
            "node": "feishu-card-message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "feishu-card-message": {
      "main": [
        [
          {
            "node": "send-to-feishu",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "saveManualExecutions": false,
    "callerPolicy": "any",
    "errorWorkflow": "",
    "executionTimeout": -1,
    "maxExecutionTimeout": 7200000,
    "saveDataErrorExecution": "all",
    "saveDataSuccessExecution": "all",
    "saveExecutionProgress": false,
    "timezone": "Asia/Shanghai"
  },
  "staticData": null,
  "pinData": {},
  "tags": [
    "AI",
    "Meeting",
    "Summary",
    "Feishu",
    "Automation"
  ],
  "versionId": "2",
  "id": "ai-meeting-summary-workflow",
  "meta": {
    "templateCredsSetupCompleted": true,
    "instanceId": "n8n-instance-id-placeholder"
  },
  "credentials": [
    {
      "name": "openaiApi",
      "type": "openai",
      "displayName": "OpenAI API"
    },
    {
      "name": "anthropicApi",
      "type": "anthropic",
      "displayName": "Anthropic API"
    },
    {
      "name": "feishuWebhook",
      "type": "webhook",
      "displayName": "Feishu Webhook"
    }
  ]
}