{
  "name": "AI Pulse \u2014 Deep Analysis (Pass 2)",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 4
            }
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        0,
        -32
      ],
      "id": "9accff48-f95c-479c-a3fa-9cfcd7c174df",
      "name": "Schedule Trigger"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://host.docker.internal:11434/api/generate",
        "sendBody": true,
        "contentType": "raw",
        "rawContentType": "application/json",
        "body": "{\"model\": \"mistral\", \"prompt\": \"\", \"stream\": false, \"keep_alive\": 0}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        224,
        96
      ],
      "id": "74d62c6d-70bf-4e32-9a99-6785478e316b",
      "name": "Unload Mistral",
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "language": "pythonNative",
        "pythonCode": "import sqlite3\n\ndb_path = \"/data/ai-pulse/ai-pulse.db\"\nconn = sqlite3.connect(db_path)\nconn.row_factory = sqlite3.Row\ncursor = conn.cursor()\n\ncursor.execute(\"\"\"\n    SELECT id, title, url, source_name, source_type, category, raw_content, relevance_score\n    FROM articles\n    WHERE relevance_score >= 60\n    AND importance IS NULL\n    ORDER BY relevance_score DESC\n    LIMIT 100\n\"\"\")\nrows = cursor.fetchall()\nconn.close()\n\nreturn [{\"json\": dict(row)} for row in rows]"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        448,
        96
      ],
      "id": "f5ed13fc-0e76-432d-aa26-788085000208",
      "name": "Fetch Promoted Articles"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        672,
        96
      ],
      "id": "5d0df582-17e8-47d8-9305-47aa3a2a3b57",
      "name": "Loop Promoted Articles"
    },
    {
      "parameters": {
        "language": "pythonNative",
        "pythonCode": "import json as json_lib\n\nitems = _items\nresult = []\n\nfor item in items:\n    data = item['json'] if 'json' in item else item\n\n    title = str(data.get('title', 'Untitled'))[:300]\n    source_name = str(data.get('source_name', 'Unknown'))\n    category = str(data.get('category', 'general'))\n    raw = str(data.get('raw_content', ''))[:3000]\n\n    prompt = (\n        \"You are an AI analyst writing for a Software Engineer who works on\\n\"\n        \"AI-powered dev tooling, agentic workflows, context engineering,\\n\"\n        \"prompt engineering, and workflow automation. He cares about practical,\\n\"\n        \"engineering-focused insights he can apply immediately.\\n\\n\"\n        f\"Analyze this article:\\nTitle: {title}\\nSource: {source_name}\\n\"\n        f\"Category: {category}\\nContent: {raw}\\n\\n\"\n        \"Return ONLY valid JSON, no other text:\\n\"\n        \"{\\\"summary\\\": \\\"<2-3 sentence plain-language summary>\\\", \"\n        \"\\\"importance\\\": <1-5>, \"\n        \"\\\"importance_reasoning\\\": \\\"<why this rating>\\\", \"\n        \"\\\"why_it_matters\\\": \\\"<one sentence connecting this to the reader's work>\\\", \"\n        \"\\\"tags\\\": [\\\"<tag1>\\\", \\\"<tag2>\\\", \\\"<tag3>\\\"]}\"\n    )\n\n    body = json_lib.dumps({\n        \"model\": \"llama3:8b\",\n        \"prompt\": prompt,\n        \"stream\": False,\n        \"keep_alive\": \"10m\"\n    })\n\n    result.append({\"json\": {\n        \"id\": data.get('id', 0),\n        \"title\": title,\n        \"source_name\": source_name,\n        \"request_body\": body\n    }})\n\nreturn result"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        896,
        96
      ],
      "id": "90d7e742-7721-4a9b-9ea8-7eeee4c3083d",
      "name": "Prepare Pass 2 Prompt"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://host.docker.internal:11434/api/generate",
        "sendBody": true,
        "contentType": "raw",
        "rawContentType": "application/json",
        "body": "={{ $json.request_body }}",
        "options": {
          "timeout": 300000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        1120,
        96
      ],
      "id": "f6b5c175-e50f-44f8-b061-5a6ad22e1e9a",
      "name": "Ollama Deep Analysis",
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "56c1f084-fc18-4100-9d55-d47d0a8f94d1",
              "name": "article_id",
              "value": "={{ $('Prepare Pass 2 Prompt').item.json.id }}",
              "type": "string"
            }
          ]
        },
        "includeOtherFields": true,
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1344,
        96
      ],
      "id": "8541caef-7577-4170-b250-f1e0793f24de",
      "name": "Add Article ID"
    },
    {
      "parameters": {
        "language": "pythonNative",
        "pythonCode": "import sqlite3\n\ndb_path = \"/data/ai-pulse/ai-pulse.db\"\nconn = sqlite3.connect(db_path)\ncursor = conn.cursor()\n\ncursor.execute(\"SELECT COUNT(*) FROM articles WHERE relevance_score >= 60 AND importance IS NULL\")\nremaining = cursor.fetchone()[0]\n\ncursor.execute(\"SELECT COUNT(*) FROM articles WHERE importance IS NOT NULL\")\nenriched = cursor.fetchone()[0]\n\ncursor.execute(\"SELECT importance, COUNT(*) FROM articles WHERE importance IS NOT NULL GROUP BY importance ORDER BY importance DESC\")\nratings = cursor.fetchall()\n\nconn.close()\n\nrating_summary = \", \".join([f\"{row[0]} stars: {row[1]}\" for row in ratings])\n\nreturn [{\"json\": {\"enriched_total\": enriched, \"remaining_to_enrich\": remaining, \"importance_distribution\": rating_summary}}]"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        896,
        -96
      ],
      "id": "1f8581da-dc6d-4441-9cca-0ef8efcefbd2",
      "name": "Batch Summary"
    },
    {
      "parameters": {
        "language": "pythonNative",
        "pythonCode": "import sqlite3\nimport json as json_lib\n\ndb_path = \"/data/ai-pulse/ai-pulse.db\"\n\nitems = _items\narticle_id = 0\nimportance = 0\nsummary = \"\"\nwhy_it_matters = \"\"\ntags = \"\"\nstatus = \"failed\"\n\nfor item in items:\n    data = item['json'] if 'json' in item else item\n    article_id = int(data.get('article_id', 0))\n    response_text = str(data.get('response', ''))\n\n    try:\n        clean = response_text.strip()\n        start = clean.find('{')\n        end = clean.rfind('}') + 1\n        if start >= 0 and end > start:\n            parsed = json_lib.loads(clean[start:end])\n            importance = int(parsed.get('importance', 0))\n            summary = str(parsed.get('summary', ''))\n            why_it_matters = str(parsed.get('why_it_matters', ''))\n            tags_list = parsed.get('tags', [])\n            tags = json_lib.dumps(tags_list)\n            status = \"success\"\n    except:\n        importance = 1\n        summary = \"Parse error\"\n        status = \"parse_error\"\n\n    if article_id > 0:\n        conn = sqlite3.connect(db_path)\n        cursor = conn.cursor()\n        cursor.execute(\"\"\"\n            UPDATE articles \n            SET importance = ?, summary = ?, why_it_matters = ?, tags = ?\n            WHERE id = ?\n        \"\"\", (importance, summary, why_it_matters, tags, article_id))\n        conn.commit()\n        conn.close()\n\nreturn [{\"json\": {\"article_id\": article_id, \"importance\": importance, \"summary\": summary, \"status\": status}}]"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1568,
        176
      ],
      "id": "ccdfc1ae-d8b7-4f6b-8415-ce0ed7ba2a84",
      "name": "Update Deep Analysis",
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        0,
        176
      ],
      "id": "7b9c01ef-5b07-4b8d-a9ff-93aaf257532a",
      "name": "When clicking \u2018Execute workflow\u2019"
    }
  ],
  "connections": {
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Unload Mistral",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Unload Mistral": {
      "main": [
        [
          {
            "node": "Fetch Promoted Articles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Promoted Articles": {
      "main": [
        [
          {
            "node": "Loop Promoted Articles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Promoted Articles": {
      "main": [
        [
          {
            "node": "Batch Summary",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Prepare Pass 2 Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Pass 2 Prompt": {
      "main": [
        [
          {
            "node": "Ollama Deep Analysis",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Ollama Deep Analysis": {
      "main": [
        [
          {
            "node": "Add Article ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Article ID": {
      "main": [
        [
          {
            "node": "Update Deep Analysis",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Deep Analysis": {
      "main": [
        [
          {
            "node": "Loop Promoted Articles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking \u2018Execute workflow\u2019": {
      "main": [
        [
          {
            "node": "Unload Mistral",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate",
    "availableInMCP": false
  },
  "versionId": "37bf3b51-d5d4-48b8-9ba4-eb2389cc43f1",
  "id": "2A6T3P7q3W4GKhxA",
  "tags": []
}