{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "51f4cea0",
   "metadata": {},
   "source": [
    "# Build anomaly detection for a subsystem/asset\n",
    "\n",
    "This notebook provides a step-by-step guide to set up, test, and deploy anomaly models using Falkonry APIs. Follow each section to create a workspace, define rules, evaluate them, set up assessments, and monitor live outputs.\n",
    "\n",
    "### 6 Steps to go live with your anomaly models for the asset signals\n",
    "1. Set Up Falkonry API Access\n",
    "2. Create Workspace\n",
    "3. Get the list of signals for an asset (node in a tree)\n",
    "4. Create an anomaly model for each signal\n",
    "5. Run ANOMALYEVAL for testing (Optional)\n",
    "6. Create live assessments for each signal"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bc03641d",
   "metadata": {},
   "source": [
    "COPYRIGHT (c) 2026 FALKONRY, INC. ALL RIGHTS RESERVED.\n",
    "\n",
    "FOR FALKONRY's CUSTOMER USE ONLY.\n",
    "\n",
    "THIS SAMPLE CODE FROM FALKONRY IS PROVIDED \"AS IS\" AND WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FALKONRY INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) SUSTAINED BY YOU OR A THIRD PARTY, HOWEVER CAUSED AND UNDER ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ARISING IN ANY WAY OUT OF THE USE OF OR INABILITY TO USE THIS SAMPLE CODE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b81b7701",
   "metadata": {},
   "source": [
    "## 1. Set Up Falkonry API Access\n",
    "\n",
    "Configure authentication and base URL for Falkonry API requests. Set your API key, account_id, and other required variables."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9e917122",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Testing API connection...\n",
      "https://app3.falkonry.ai/api/1.3/accounts/1356886815915696128\n",
      "Status code: 200\n",
      "API connection successful!\n",
      "Proceed with the rest of the notebook...\n"
     ]
    }
   ],
   "source": [
    "# Set up Falkonry API access\n",
    "import requests\n",
    "\n",
    "# Set your API connection and account ID here\n",
    "BASE_SERVER = \"\" # e.g., app3.falkonry.ai\n",
    "API_TOKEN   = \"\" # <YOUR_API_TOKEN>\n",
    "ACCOUNT_ID  = \"\" # <YOUR_ACCOUNT_ID>\n",
    "BASE_URL    = f\"https://{BASE_SERVER}/api/1.3\"\n",
    "HEADERS     = {\n",
    "    \"Authorization\": f\"Bearer {API_TOKEN}\",\n",
    "    \"Content-Type\": \"application/json\"\n",
    "}\n",
    "\n",
    "# Set your workspace, anomaly model and assessment parameters here\n",
    "WORKSPACE_ID = \"\" # e.g., \"1356886815915696129\"\n",
    "WORKSPACE_NAME = \"\" # e.g., \"Machine 2 Model Development\"\n",
    "TREE_NAME = \"\"\n",
    "NODE_NAME = \"\"\n",
    "MODEL_NAME_SUFFIX = \"01\" # e.g., \"1\"\n",
    "LEARN_TIME_RANGE = [\n",
    "    {\n",
    "        \"startTime\": \"\", # e.g., \"2024-07-22T00:00:00.00Z\",\n",
    "        \"endTime\": \"\" # e.g., \"2024-10-10T23:59:59.00Z\"\n",
    "    }\n",
    "]\n",
    "EVAL_TIME_RANGE = [\n",
    "    {\n",
    "        \"startTime\": \"\", # e.g., \"2024-07-22T23:01:09.000Z\", \n",
    "        \"endTime\": \"\" # e.g., \"2024-08-01T23:01:09.000Z\"\n",
    "    }\n",
    "]\n",
    "OUTPUT_PREFIX = \"\" # e.g., \"test01/\"\n",
    "\n",
    "# Test the API connection before proceeding with the rest of the notebook\n",
    "print(\"Testing API connection...\")\n",
    "try:\n",
    "    test_url = f\"{BASE_URL}/accounts/{ACCOUNT_ID}\"\n",
    "    print (test_url)\n",
    "    response = requests.get(test_url, headers=HEADERS, timeout=10)\n",
    "    print(f\"Status code: {response.status_code}\")\n",
    "    if response.status_code == 200:\n",
    "        print(\"API connection successful!\")\n",
    "        print(\"Proceed with the rest of the notebook...\")\n",
    "    else:\n",
    "        print(f\"API error: {response.text[:100]}\")\n",
    "        print(\"STOP! Check your API connection parameters and try again.\")\n",
    "except Exception as e:\n",
    "    print(f\"Connection error: {str(e)}\")\n",
    "    print(\"STOP! Check your API connection parameters and try again.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "65708c32",
   "metadata": {},
   "source": [
    "## 2. Create Workspace\n",
    "\n",
    "Send a POST request to `/api/1.3/accounts/{{account_id}}/workspace` to create a new workspace for development. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "940bb9af",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Using existing workspace with ID: 1511839170830970880\n",
      "Using the Existing Workspace ID: 1511839170830970880\n"
     ]
    }
   ],
   "source": [
    "if WORKSPACE_ID:\n",
    "    workspace_id = WORKSPACE_ID\n",
    "    print(\"Using the Existing Workspace ID:\", workspace_id)\n",
    "else:\n",
    "    # Create a new workspace if you don't have one already, or if you want to create a separate workspace for this exercise. You can also reuse an existing workspace by setting WORKSPACE_ID above and skipping this step.\n",
    "    workspace_payload = {\n",
    "        \"name\": WORKSPACE_NAME,\n",
    "        \"description\": \"Created by notebook\"\n",
    "    }\n",
    "\n",
    "    response = requests.post(\n",
    "        f\"{BASE_URL}/accounts/{ACCOUNT_ID}/workspace\",\n",
    "        headers=HEADERS,\n",
    "        json=workspace_payload\n",
    "    )\n",
    "\n",
    "    print(\"Status:\", response.status_code)\n",
    "    print(\"Response:\", response.json())\n",
    "\n",
    "    workspace_id = response.json().get(\"id\")\n",
    "    print(\"Created Workspace ID:\", workspace_id)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2f2a9752",
   "metadata": {},
   "source": [
    "## 3. Get the list of signals for a node in a tree\n",
    "\n",
    "To start anomaly detection, we first need to identify which signals are available for a specific node (such as a machine or subsystem) within a signal tree. This step retrieves all signals associated with the selected node, so they can be used as inputs for anomaly detection models.\n",
    "\n",
    "The process involves:\n",
    "- Selecting the tree and node of interest (e.g., a specific machine in a plant).\n",
    "- Querying the API to fetch all signals linked to that node.\n",
    "- Preparing the list of signals in the required format for downstream anomaly detection workflows."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e7e88991",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[{'signal': '1387690531524554752', 'name': 'plant1/line2/machine2/torque2'}, {'signal': '1387690531629412352', 'name': 'plant1/line2/machine2/current2'}, {'signal': '1387690531860099072', 'name': 'plant1/line2/machine2/temperature3'}, {'signal': '1387690532308889600', 'name': 'plant1/line2/machine2/rate1'}, {'signal': '1387690532409552896', 'name': 'plant1/line2/machine2/pressure3'}, {'signal': '1387690532526993408', 'name': 'plant1/line2/machine2/torque3'}, {'signal': '1387690532740902912', 'name': 'plant1/line2/machine2/pressure2'}, {'signal': '1387690533126778880', 'name': 'plant1/line2/machine2/temperature2'}, {'signal': '1387690533214859264', 'name': 'plant1/line2/machine2/rate3'}, {'signal': '1387690534045331456', 'name': 'plant1/line2/machine2/current1'}, {'signal': '1387690534313766912', 'name': 'plant1/line2/machine2/rate2'}, {'signal': '1387690534502510592', 'name': 'plant1/line2/machine2/temperature1'}, {'signal': '1387690534695448576', 'name': 'plant1/line2/machine2/current3'}, {'signal': '1387690535580446720', 'name': 'plant1/line2/machine2/torque1'}, {'signal': '1387690535664332800', 'name': 'plant1/line2/machine2/pressure1'}]\n"
     ]
    }
   ],
   "source": [
    "# Get layout ID for the tree name\n",
    "layout = requests.get(f'{BASE_URL}/accounts/{ACCOUNT_ID}/layouts?name=\"{TREE_NAME}\"&limit=1', headers=HEADERS).json()\n",
    "layoutID = layout[0][\"id\"]\n",
    "\n",
    "# Get layout node id for the tree name\n",
    "layoutnodes_count = requests.get(f'{BASE_URL}/accounts/{ACCOUNT_ID}/layouts/{layoutID}/layoutnodes', headers=HEADERS).json()[0][\"count\"]\n",
    "layoutnodes = requests.get(f'{BASE_URL}/accounts/{ACCOUNT_ID}/layouts/{layoutID}/layoutnodes?limit={layoutnodes_count}', headers=HEADERS).json()\n",
    "\n",
    "layoutNodeID = \"\"\n",
    "for node in layoutnodes:\n",
    "    if node[\"name\"] == NODE_NAME:\n",
    "        layoutNodeID = node[\"id\"]\n",
    "        break\n",
    "        \n",
    "# Get the signal count for the layout ID\n",
    "data = {\"complexQuery\":{\"operands\":[{\"-valueType\":[\"events\"],\"layout-and\":[layoutID],\"layoutinfopath\":[layoutNodeID], \"valueType\":[\"Numeric\"]}],\"operator\":\"and\"}}\n",
    "signalCount = requests.post(f'{BASE_URL}/accounts/{ACCOUNT_ID}/connectedsources/query', json=data, headers=HEADERS).json()[0][\"count\"]\n",
    "\n",
    "offset = 0\n",
    "while (offset < signalCount):\n",
    "    data = {\"complexQuery\":{\"operands\":[{\"-valueType\":[\"events\"],\"layout-and\":[layoutID],\"layoutinfopath\":[layoutNodeID], \"valueType\":[\"Numeric\"]}],\"operator\":\"and\"},\"limit\":50,\"offset\":offset}\n",
    "    signals = requests.post(f'{BASE_URL}/accounts/{ACCOUNT_ID}/connectedsources/query', json=data, headers=HEADERS).json()\n",
    "    offset += 50\n",
    "\n",
    "signal_list = [{\"signal\": s[\"id\"], \"name\": s[\"sourceName\"]} for s in signals]\n",
    "\n",
    "print(signal_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "af5b9f78",
   "metadata": {},
   "source": [
    "## 4. Create an anomaly model for each signal\n",
    "\n",
    "Once the relevant signals for a node have been identified, the next step is to create an anomaly detection model. This model will learn the normal behavior of the selected signals over a specified time range.\n",
    "\n",
    "This step results in the creation of one anomaly model for each signal."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "07fbb6ec",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ANOMALYLEARN Flow created for signal plant1/line2/machine2/torque2 with ID: 1511958966390140928\n",
      "ANOMALYLEARN Flow created for signal plant1/line2/machine2/current2 with ID: 1511958969259044864\n",
      "ANOMALYLEARN Flow created for signal plant1/line2/machine2/temperature3 with ID: 1511958971444277248\n",
      "ANOMALYLEARN Flow created for signal plant1/line2/machine2/rate1 with ID: 1511958973725638656\n",
      "ANOMALYLEARN Flow created for signal plant1/line2/machine2/pressure3 with ID: 1511958976569716736\n",
      "ANOMALYLEARN Flow created for signal plant1/line2/machine2/torque3 with ID: 1511958978867855360\n",
      "ANOMALYLEARN Flow created for signal plant1/line2/machine2/pressure2 with ID: 1511958981401214976\n",
      "ANOMALYLEARN Flow created for signal plant1/line2/machine2/temperature2 with ID: 1511958984304013312\n",
      "ANOMALYLEARN Flow created for signal plant1/line2/machine2/rate3 with ID: 1511958987105468416\n",
      "ANOMALYLEARN Flow created for signal plant1/line2/machine2/current1 with ID: 1511958990046015488\n",
      "ANOMALYLEARN Flow created for signal plant1/line2/machine2/rate2 with ID: 1511958993019437056\n",
      "ANOMALYLEARN Flow created for signal plant1/line2/machine2/temperature1 with ID: 1511958995817377792\n",
      "ANOMALYLEARN Flow created for signal plant1/line2/machine2/current3 with ID: 1511958998514315264\n",
      "ANOMALYLEARN Flow created for signal plant1/line2/machine2/torque1 with ID: 1511959001349664768\n",
      "ANOMALYLEARN Flow created for signal plant1/line2/machine2/pressure1 with ID: 1511959003647803392\n"
     ]
    }
   ],
   "source": [
    "flow_info_list = []\n",
    "\n",
    "for signal in signal_list:\n",
    "  anomaly_payload = {\n",
    "    \"name\": f\"signal - {signal['name']}\",\n",
    "    \"flowType\": \"ANOMALYLEARN\",\n",
    "    \"description\": f\"Flow to learn anomalies for signal - {signal['name']}\",\n",
    "    \"spec\": {\n",
    "      \"workspace\": workspace_id,\n",
    "      \"modelName\": f\"{signal['name']/{MODEL_NAME_SUFFIX}}\",\n",
    "      \"dataspec\": {\n",
    "        \"name\": f\"Dataspec for signal - {signal['name']}\",\n",
    "        \"specs\": [\n",
    "          { \n",
    "            \"timeRanges\": LEARN_TIME_RANGE, # e.g., {\"startTime\": \"2024-01-01T00:00:00.00Z\", \"endTime\": \"2024-10-10T23:59:59.00Z\"}\n",
    "            \"signals\": [signal]\n",
    "          }\n",
    "        ]\n",
    "      }\n",
    "    }\n",
    "  }\n",
    "  response = requests.post(\n",
    "      f\"{BASE_URL}/accounts/{ACCOUNT_ID}/flows\",\n",
    "      headers=HEADERS,\n",
    "      json=anomaly_payload\n",
    "  )\n",
    "  \n",
    "  flow_id = response.json().get(\"id\")\n",
    "  print(f\"ANOMALYLEARN Flow created for signal {signal['name']} with ID: {flow_id}\")\n",
    "  \n",
    "  # Save flow_id and signal name for later use\n",
    "  flow_info_list.append({\"flow_id\": flow_id, \"signal_name\": signal[\"name\"], \"signal_id\": signal[\"signal\"]})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f72eb22f",
   "metadata": {},
   "source": [
    "## 5. Run ANOMALYEVAL for testing\n",
    "\n",
    "After creating anomaly detection models, the next step is to evaluate their performance using historical or test data. This process, called anomaly evaluation (ANOMALYEVAL), helps verify that the models correctly identify anomalies and behave as expected before deploying them in production.\n",
    "\n",
    "This step ensures that only well-performing models are used for real-time anomaly detection improving reliability."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "32bae765",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ANOMALYEVAL Flow created for signal plant1/line2/machine2/torque2 with ID: 1511979707022094336\n",
      "ANOMALYEVAL Flow created for signal plant1/line2/machine2/current2 with ID: 1511979709982932992\n",
      "ANOMALYEVAL Flow created for signal plant1/line2/machine2/temperature3 with ID: 1511979712889585664\n",
      "ANOMALYEVAL Flow created for signal plant1/line2/machine2/rate1 with ID: None\n",
      "ANOMALYEVAL Flow created for signal plant1/line2/machine2/pressure3 with ID: 1511979718648365056\n",
      "ANOMALYEVAL Flow created for signal plant1/line2/machine2/torque3 with ID: 1511979721110761472\n",
      "ANOMALYEVAL Flow created for signal plant1/line2/machine2/pressure2 with ID: 1511979723258245120\n",
      "ANOMALYEVAL Flow created for signal plant1/line2/machine2/temperature2 with ID: 1511979725472837632\n",
      "ANOMALYEVAL Flow created for signal plant1/line2/machine2/rate3 with ID: 1511979728224301056\n",
      "ANOMALYEVAL Flow created for signal plant1/line2/machine2/current1 with ID: 1511979731038679040\n",
      "ANOMALYEVAL Flow created for signal plant1/line2/machine2/rate2 with ID: None\n",
      "ANOMALYEVAL Flow created for signal plant1/line2/machine2/temperature1 with ID: 1511979735119396864\n",
      "ANOMALYEVAL Flow created for signal plant1/line2/machine2/current3 with ID: 1511979738168995840\n",
      "ANOMALYEVAL Flow created for signal plant1/line2/machine2/torque1 with ID: 1511979740492300288\n",
      "ANOMALYEVAL Flow created for signal plant1/line2/machine2/pressure1 with ID: 1511979742954356736\n"
     ]
    }
   ],
   "source": [
    "for item in flow_info_list:\n",
    "    anomalyeval_payload = {\n",
    "        \"name\": \"Eval for signal - \" + item[\"signal_name\"],\n",
    "        \"flowType\": \"ANOMALYEVAL\",\n",
    "        \"description\": \"try eval on anomaly model \" + OUTPUT_PREFIX,\n",
    "        \"spec\": {\n",
    "            \"model\": item[\"flow_id\"],\n",
    "            \"workspace\": workspace_id,\n",
    "            \"dataspec\": {\n",
    "                \"name\": \"anomaly eval range 1\",\n",
    "                \"specs\": [\n",
    "                    { \n",
    "                        \"timeRanges\": EVAL_TIME_RANGE, # e.g., {\"startTime\": \"2024-07-22T23:01:09.000Z\", \"endTime\": \"2024-08-01T23:01:09.000Z\"}\n",
    "                        \"signals\": [{\"signal\": item[\"signal_id\"], \"name\": item[\"signal_name\"]}]\n",
    "                    }\n",
    "                ]\n",
    "            },\n",
    "            \"outputsignalPrefix\": OUTPUT_PREFIX + item[\"signal_name\"]\n",
    "        }\n",
    "    }\n",
    "\n",
    "    response = requests.post(\n",
    "        f\"{BASE_URL}/accounts/{ACCOUNT_ID}/flows\",\n",
    "        headers=HEADERS,\n",
    "        json=anomalyeval_payload\n",
    "    )\n",
    "    flow_id = response.json().get(\"id\")\n",
    "    print(f\"ANOMALYEVAL Flow created for signal {item['signal_name']} with ID: {flow_id}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d2d87034",
   "metadata": {},
   "source": [
    "## 6. Create live assessments for each signal\n",
    "\n",
    "After evaluating the anomaly detection models, the next steps are to make an assessment for each signal and deploy the selected model for monitoring.\n",
    "\n",
    "The process involves:\n",
    "- Reviewing the results of the anomaly evaluation for each signal to determine model performance and suitability.\n",
    "- Creating an assessment for each signal and deploying the approved anomaly models to start real-time monitoring\n",
    "\n",
    "This ensures that only validated and high-performing models are deployed, providing reliable anomaly detection and actionable insights for each monitored signal.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "40f73f46",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Response: {'id': '1511992678838349824', 'type': 'entities.flow', 'tenant': '1356886815915696128', 'flowType': 'ASSESSMENTSETUP', 'status': 'CREATED', 'name': 'create assessment for plant1/line2/machine2/torque2', 'description': 'Created from notebook', 'spec': {'assessmentName': 'plant1/line2/machine2/torque2', 'model': '1511958966390140928', 'assessmentRate': None, 'clockSignals': [], 'assessmentState': 'MONITORING', 'inputsignals': [{'signal': '1387690531524554752', 'name': 'plant1/line2/machine2/torque2'}], 'outputsignals': [], 'config': {}}, 'outputs': [], 'messages': [], 'createTime': 1780557546100, 'updateTime': 1780557546100, 'createdBy': '596582102439518208', 'updatedBy': '596582102439518208', 'archived': False, 'transitions': [{'id': '1', 'status': 'CREATED', 'createTime': '2026-06-04T07:19:06.100000Z'}], 'links': []}\n",
      "Created Assessment: plant1/line2/machine2/torque2\n",
      "Response: {'id': '1511992682051186688', 'type': 'entities.flow', 'tenant': '1356886815915696128', 'flowType': 'ASSESSMENTSETUP', 'status': 'CREATED', 'name': 'create assessment for plant1/line2/machine2/current2', 'description': 'Created from notebook', 'spec': {'assessmentName': 'plant1/line2/machine2/current2', 'model': '1511958969259044864', 'assessmentRate': None, 'clockSignals': [], 'assessmentState': 'MONITORING', 'inputsignals': [{'signal': '1387690531629412352', 'name': 'plant1/line2/machine2/current2'}], 'outputsignals': [], 'config': {}}, 'outputs': [], 'messages': [], 'createTime': 1780557546866, 'updateTime': 1780557546866, 'createdBy': '596582102439518208', 'updatedBy': '596582102439518208', 'archived': False, 'transitions': [{'id': '1', 'status': 'CREATED', 'createTime': '2026-06-04T07:19:06.866000Z'}], 'links': []}\n",
      "Created Assessment: plant1/line2/machine2/current2\n",
      "Response: {'id': '1511992684509048832', 'type': 'entities.flow', 'tenant': '1356886815915696128', 'flowType': 'ASSESSMENTSETUP', 'status': 'CREATED', 'name': 'create assessment for plant1/line2/machine2/temperature3', 'description': 'Created from notebook', 'spec': {'assessmentName': 'plant1/line2/machine2/temperature3', 'model': '1511958971444277248', 'assessmentRate': None, 'clockSignals': [], 'assessmentState': 'MONITORING', 'inputsignals': [{'signal': '1387690531860099072', 'name': 'plant1/line2/machine2/temperature3'}], 'outputsignals': [], 'config': {}}, 'outputs': [], 'messages': [], 'createTime': 1780557547452, 'updateTime': 1780557547452, 'createdBy': '596582102439518208', 'updatedBy': '596582102439518208', 'archived': False, 'transitions': [{'id': '1', 'status': 'CREATED', 'createTime': '2026-06-04T07:19:07.452000Z'}], 'links': []}\n",
      "Created Assessment: plant1/line2/machine2/temperature3\n",
      "Response: {'message': 'loadModelById.tenant=1356886815915696128 loadModelById.model=1511958973725638656 not found'}\n"
     ]
    },
    {
     "ename": "KeyError",
     "evalue": "'spec'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mKeyError\u001b[0m                                  Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[9], line 24\u001b[0m\n\u001b[1;32m     17\u001b[0m response \u001b[38;5;241m=\u001b[39m requests\u001b[38;5;241m.\u001b[39mpost(\n\u001b[1;32m     18\u001b[0m     \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mBASE_URL\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m/accounts/\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mACCOUNT_ID\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m/flows\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m     19\u001b[0m     headers\u001b[38;5;241m=\u001b[39mHEADERS,\n\u001b[1;32m     20\u001b[0m     json\u001b[38;5;241m=\u001b[39massessment_payload\n\u001b[1;32m     21\u001b[0m )\n\u001b[1;32m     23\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mResponse:\u001b[39m\u001b[38;5;124m\"\u001b[39m, response\u001b[38;5;241m.\u001b[39mjson())\n\u001b[0;32m---> 24\u001b[0m assessment_name \u001b[38;5;241m=\u001b[39m \u001b[43mresponse\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mjson\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mspec\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124massessmentName\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n\u001b[1;32m     25\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mCreated Assessment:\u001b[39m\u001b[38;5;124m\"\u001b[39m, assessment_name)\n",
      "\u001b[0;31mKeyError\u001b[0m: 'spec'"
     ]
    }
   ],
   "source": [
    "for item in flow_info_list:\n",
    "\n",
    "    assessment_payload = {\n",
    "        \"description\": \"Created from notebook\",\n",
    "        \"flowType\": \"ASSESSMENTSETUP\",\n",
    "        \"name\": \"create assessment for \" + item[\"signal_name\"],\n",
    "        \"spec\": {\n",
    "            \"assessmentName\": f'{item[\"signal_name\"]}',\n",
    "            \"assessmentState\": \"MONITORING\",\n",
    "            \"inputsignals\": [\n",
    "                {\"signal\": item[\"signal_id\"],\"name\": item[\"signal_name\"]}\n",
    "            ],\n",
    "            \"model\": item[\"flow_id\"] \n",
    "        }\n",
    "    }\n",
    "\n",
    "    response = requests.post(\n",
    "        f\"{BASE_URL}/accounts/{ACCOUNT_ID}/flows\",\n",
    "        headers=HEADERS,\n",
    "        json=assessment_payload\n",
    "    )\n",
    "\n",
    "    print(\"Response:\", response.json())\n",
    "    assessment_name = response.json()[\"spec\"][\"assessmentName\"]\n",
    "    print(\"Created Assessment:\", assessment_name)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
