{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "07f5174c",
   "metadata": {
    "tags": []
   },
   "source": [
    "## Inserting Data Lab Content into Organizer Topics"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dea57e0f",
   "metadata": {},
   "source": [
    "Data Lab Functions can be used to insert Data Lab content directly into Organizer Topic.  Data Lab Functions use the cells in a Jupyter Notebook as an API endpoint. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "838d9aad",
   "metadata": {},
   "source": [
    "## How To Define A Data Lab Functions Notebook\n",
    "### Notebook Cells\n",
    "#### Context Cell\n",
    "\n",
    "- A notebook cell that is not decorated with a top-line comment resembling a RESTful endpoint. Context cells appear sequentially at the beginning of a Jupyter notebook and are executed only once in a new kernel.\n",
    "\n",
    "#### Endpoint Cell\n",
    "\n",
    "- A notebook cell that is decorated with a top-line comment resembling a RESTful endpoint. For example:\n",
    "\n",
    "```\n",
    "# GET /items\n",
    "items = spy.search({\n",
    "    'Path': 'Example >> Cooling Tower 1 >> Area A',\n",
    "    'Name': 'Compressor'\n",
    "})\n",
    "items.to_json()\n",
    "```\n",
    "\n",
    "- Endpoint cells must appear after context cells in a Jupyter notebook\n",
    "\n",
    "- Allowed HTTP methods are GET, POST, PATCH, PUT, DELETE\n",
    "\n",
    "- Endpoints can include nested paths. For example, # GET /items/area-a/compressor\n",
    "\n",
    "- Endpoints do not support path parameters. Instead, both query parameters and a request body are available in the REQUEST object which is instantiated in the kernel for every Data Lab Functions request.\n",
    "\n",
    "- Endpoint cells must be unique. That is, they cannot duplicate HTTP method + endpoint name\n",
    "\n",
    "- Endpoint cell response content-types\n",
    "\n",
    "    - application/json (default)\n",
    "\n",
    "        - Cell response should be Python objects or literals. Data Lab Functions responses performs json.dumps() on endpoint cell output.\n",
    "\n",
    "    - image/*\n",
    "\n",
    "    - text/plain\n",
    "\n",
    "    - text/html\n",
    "`\n",
    "### Reserved Variables\n",
    "#### REQUEST\n",
    "\n",
    "On each request, Data Lab Functions injects a REQUEST variable of type Dict directly into the kernel. The REQUEST dictionary contains all the relevant HTTP Request information, namely:\n",
    "\n",
    "| REQUEST Variable | Type | Description |\n",
    "| --- | --- ||\n",
    "|info | Dict||\n",
    "|id|str| Unique ID of the request|\n",
    "|user_id|str| The Seeq user UUID invoking the request|\n",
    "|notebook |str| The path and name of the API notebook|\n",
    "|method| str |HTTP method|\n",
    "|endpoint|str| Endpoint name|\n",
    "|body|str/Dict|Parsed from JSON or Form-Encoded name-value pairs|\n",
    "|args|Dict|Parsed query string name-value pairs |\n",
    "|headers|Dict|HTTP Header name-value pairs |\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c9b165cc",
   "metadata": {},
   "source": [
    "An example url for an endpoint in this notebook would look like this."
   ]
  },
  {
   "cell_type": "raw",
   "id": "a44dc9ce-8e38-41c0-af45-4428f06e2c28",
   "metadata": {},
   "source": [
    "data-lab/<project GUID>/functions/notebooks/<notebook name>/endpoints/static_image"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cb525589-2ac3-431f-8223-8ef3a67b2cb8",
   "metadata": {},
   "source": [
    "### An optional common definition that could be called by various endpoints"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "48d8bf93-204b-45c9-912f-f4d5673f9d39",
   "metadata": {},
   "outputs": [],
   "source": [
    "from io import StringIO\n",
    "import plotly.express as px\n",
    "\n",
    "#def get_query_params(*names):\n",
    "#    args = REQUEST['args']\n",
    "#    return {name: args.get(name, None) for name in names}\n",
    "\n",
    "def fig_to_html(fig):\n",
    "    buffer = StringIO()\n",
    "    fig.write_html(buffer, full_html=True, include_plotlyjs=True)\n",
    "    return {'headers': {'Content-Type': 'text/html'}, 'data': buffer.getvalue()}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e687fac",
   "metadata": {},
   "source": [
    "## Insert Static Content"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "93f97003",
   "metadata": {},
   "outputs": [],
   "source": [
    "# GET /static_image\n",
    "# data-lab/<GUID>/functions/notebooks/example/endpoints/static_image\n",
    "import plotly.graph_objects as go\n",
    "\n",
    "fig = go.Figure(go.Indicator(\n",
    "    mode = \"gauge+number\",\n",
    "    value = 450,\n",
    "    title = {'text': \"Speed\"},\n",
    "    domain = {'x': [0, 1], 'y': [0, 1]}\n",
    "))\n",
    "\n",
    "#{'headers': {'Content-Type': 'text/html'}, 'data': fig.to_html()}\n",
    "fig_to_html(fig)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3a80a2f7",
   "metadata": {},
   "source": [
    "## Insert Dynamic Content to update with Asset Selection and Date Range"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "b5ea7f96-70d2-4ab2-81ab-c096cfdcee07",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\u001b[0;31mNameError: \u001b[0mname 'REQUEST' is not defined\n",
      "\n",
      "Error found at \u001b[0;36mline 7\u001b[0m in \u001b[0;32mcell 3\u001b[0m.\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "4946de30465946b6a8dd13442494c61f",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Button(description='Click to show stack trace', layout=Layout(height='auto', width='auto'), style=ButtonStyle(…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# GET /TBL2\n",
    "# data-lab/<GUID>/functions/notebooks/example/endpoints/TBL2\n",
    "\n",
    "from seeq import spy\n",
    "from datetime import datetime\n",
    "\n",
    "asset=REQUEST['args']['asset']\n",
    "#our epoch timestamps come back in milliseconds, so we have to convert them\n",
    "startdate=datetime.fromtimestamp(int(REQUEST['args']['start'])//1000)\n",
    "enddate=datetime.fromtimestamp(int(REQUEST['args']['end'])//1000)\n",
    "\n",
    "#get item\n",
    "#search for Temperature signal\n",
    "item = spy.search({\n",
    "    'Asset': asset,\n",
    "    'Name': 'Temperature'\n",
    "})\n",
    "\n",
    "#pull for date range\n",
    "data = spy.pull(item, start=(startdate), end=(enddate),header='Name') #later return start and end from request parameters\n",
    "{'headers': {'Content-Type': 'text/html'}, 'data': data}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c17f7eca-42be-4d60-af58-9923e4869f6d",
   "metadata": {},
   "source": [
    "## Insert Dynamic Text that displays recent signal value"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1de0ccaa-e9d8-4f2f-9a1a-7050db27f3c4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# GET /text_string\n",
    "# Update the URL from this project into the partial link below, then use that \n",
    "#  in the URL entry field in Organizer (excluding the #)\n",
    "#  data-lab/<GUID>/functions/notebooks/example/endpoints/text_string\n",
    "\n",
    "import rich\n",
    "from seeq import spy\n",
    "from rich.console import Console\n",
    "from rich.text import Text\n",
    "from datetime import datetime, timedelta\n",
    "\n",
    "console = Console()\n",
    "\n",
    "#Current time - weird timezone stuff so I am shifting \"now\" to have data not NAN at the end of the df\n",
    "current_datetime=datetime.now()-timedelta(hours=8)\n",
    "#1 hr earlier\n",
    "hour_prior=current_datetime - timedelta(hours=10)\n",
    "#find string signal you want to display in Organizer\n",
    "signal=spy.search({'Name':'Area A_Compressor Stage','Datasource Name':'Example Data'})\n",
    "#pull data for representative time frame\n",
    "data=spy.pull(signal,start=hour_prior, end=current_datetime,grid='1h',tz_convert='UTC')\n",
    "\n",
    "# Get the dataframe's last row of text for the signal displayed\n",
    "last_row_text = Text(data['Area A_Compressor Stage'].iloc[-1])\n",
    "\n",
    "# Print that strig with bold formatting\n",
    "console.print(last_row_text, style=\"bold\" )"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.8.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
