{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Harden and deploy your app\n",
    "\n",
    "Finally, it's time to deploy your model. But before that, you have to make sure you follow AI deployment [best practices](https://se-ml.github.io/). In the past, this step was too often either the source of unexpected struggle, or worse, simply ignored.\n",
    "\n",
    "GreatAI's decorators add tracing and API scaffolding with a few lines of code. This brings the service nearly to production readiness, but does not establish the model's accuracy, fairness, or trustworthiness. Evaluate the model for its intended use, configure a production-suitable tracing database and storage, and review the remaining deployment best practices. The local TinyDB backend used below is for development, as the output warns."
   ],
   "id": "cell-0"
  },
  {
   "id": "94c0cd76",
   "cell_type": "markdown",
   "source": [
    "## Local setup\n",
    "\n",
    "Use Python 3.12 or 3.13 and install this checkout with `uv pip install --editable '.[notebooks]'`.\n",
    "See **Run notebooks locally** in the repository README for the kernel, execution order,\n",
    "and full-data options. Run related notebooks from the same working directory\n",
    "to share the default `.cache/` model store and `tracing_database.json` database.\n"
   ],
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-28T22:47:27.038586Z",
     "iopub.status.busy": "2026-10-28T22:47:27.038390Z",
     "iopub.status.idle": "2026-10-28T22:47:28.222141Z",
     "shell.execute_reply": "2026-10-28T22:47:28.221742Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;226mEnvironment variable ENVIRONMENT is not set, defaulting to development mode ‼️\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;226mCannot find credentials files, defaulting to using ParallelTinyDbDriver\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;226mThe selected tracing database (ParallelTinyDbDriver) is not recommended for production\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;226mCannot find credentials files, defaulting to using LargeFileLocal\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;39mGreatAI (v0.1.11): configured ✅\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;39m  🔩 tracing_database: ParallelTinyDbDriver\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;39m  🔩 large_file_implementation: LargeFileLocal\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;39m  🔩 is_production: False\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;39m  🔩 should_log_exception_stack: True\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;39m  🔩 prediction_cache_size: 512\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;39m  🔩 dashboard_table_size: 50\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;226mYou still need to check whether you follow all best practices before trusting your deployment.\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;226m> Find out more at https://se-ml.github.io/practices\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;39mFetching cached versions of my-domain-predictor\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;39mLatest version of my-domain-predictor is 0 (from versions: 0)\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;39mFile my-domain-predictor-0 found in cache\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[38;5;39mFile my-domain-predictor-0 found in cache\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "from great_ai import GreatAI, use_model\n",
    "from great_ai.utilities import clean\n",
    "\n",
    "\n",
    "@GreatAI.create\n",
    "@use_model(\"my-domain-predictor\")\n",
    "def predict_domain(sentence, model):\n",
    "    inputs = [clean(sentence)]\n",
    "    return str(model.predict(inputs)[0])"
   ],
   "id": "cell-3"
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-28T22:47:28.223068Z",
     "iopub.status.busy": "2026-10-28T22:47:28.222987Z",
     "iopub.status.idle": "2026-10-28T22:47:28.234820Z",
     "shell.execute_reply": "2026-10-28T22:47:28.234515Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Trace[str]({'created': '2026-10-28T22:47:28.223376',\n",
       "  'exception': None,\n",
       "  'feedback': None,\n",
       "  'logged_values': { 'arg:sentence:length': 29,\n",
       "                     'arg:sentence:value': 'Mountains are just big rocks.'},\n",
       "  'models': [{'key': 'my-domain-predictor', 'version': 0}],\n",
       "  'original_execution_time_ms': 7.958,\n",
       "  'output': 'sociology',\n",
       "  'tags': ['predict_domain', 'online', 'development'],\n",
       "  'trace_id': 'b48540f9-3162-47de-b035-bf11cc4d1581'})"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "predict_domain(\"Mountains are just big rocks.\")"
   ],
   "id": "cell-4"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Notice how the original return value is under the `.output` key, alongside\n",
    "tracing metadata. Run `train.ipynb` first, using the same local/full mode.\n",
    "\n",
    "Start the development server in a separate terminal from the checkout root:\n",
    "\n",
    "```sh\n",
    "source .venv/bin/activate\n",
    "great-ai docs/tutorial/deploy.ipynb\n",
    "```\n",
    "\n",
    "Open http://127.0.0.1:6060/dashboard. Stop the server with Ctrl+C.\n",
    "The next cell tests the HTTP API in-process so that **Run All** can finish."
   ],
   "id": "cell-5"
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-28T22:47:28.235605Z",
     "iopub.status.busy": "2026-10-28T22:47:28.235548Z",
     "iopub.status.idle": "2026-10-28T22:47:28.266237Z",
     "shell.execute_reply": "2026-10-28T22:47:28.265852Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sociology\n"
     ]
    }
   ],
   "source": [
    "from fastapi.testclient import TestClient\n",
    "\n",
    "with TestClient(predict_domain.app) as client:\n",
    "    response = client.post(\n",
    "        \"/predict\", json={\"sentence\": \"Mountains are just big rocks.\"}\n",
    "    )\n",
    "    response.raise_for_status()\n",
    "    assert isinstance(response.json()[\"output\"], str)\n",
    "    print(response.json()[\"output\"])"
   ],
   "id": "cell-6"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Congrats, you've just created your first GreatAI service! 🎉\n",
    "\n",
    "Your service now has tracing and API scaffolding. Before deploying, replace the default local TinyDB tracing backend, configure storage and infrastructure, evaluate the model for its intended use, and review the remaining best practices. Model trustworthiness requires evidence and ongoing oversight beyond wrapping the inference function. You (or your organisation) remain responsible for deploying and operating the service.\n",
    "\n",
    "There are three main approaches to deploy a GreatAI service: For more info about them, check out [the deployment how-to](https://great-ai.schmelczer.dev/how-to-guides/use-service).\n",
    "\n",
    "For more thorough examples, see the [examples page](https://great-ai.schmelczer.dev/examples/simple/data).\n",
    "\n",
    "### [Go back to the summary](https://great-ai.schmelczer.dev/tutorial/#summary)"
   ],
   "id": "cell-7"
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "GreatAI (local)",
   "language": "python",
   "name": "great-ai-local"
  },
  "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.13.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
