{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "86410054-f81a-44bc-8cfb-54a6ab72014f",
   "metadata": {},
   "source": [
    "## Exploring Code Generation Using DeepSeek Coder\n",
    "\n",
    "AI Models being able to generate code unlocks all sorts of use cases. The [DeepSeek Coder](https://github.com/deepseek-ai/DeepSeek-Coder) models `@hf/thebloke/deepseek-coder-6.7b-base-awq` and `@hf/thebloke/deepseek-coder-6.7b-instruct-awq` are now available on [Workers AI](https://developers.cloudflare.com/workers-ai).\n",
    "\n",
    "Let's explore them using the API!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "7ee34133-5861-4318-9a46-4af53572b6db",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: requests in ./venv/lib/python3.12/site-packages (2.31.0)\n",
      "Requirement already satisfied: python-dotenv in ./venv/lib/python3.12/site-packages (1.0.1)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in ./venv/lib/python3.12/site-packages (from requests) (3.3.2)\n",
      "Requirement already satisfied: idna<4,>=2.5 in ./venv/lib/python3.12/site-packages (from requests) (3.6)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in ./venv/lib/python3.12/site-packages (from requests) (2.1.0)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in ./venv/lib/python3.12/site-packages (from requests) (2023.11.17)\n"
     ]
    }
   ],
   "source": [
    "import sys\n",
    "!{sys.executable} -m pip install requests python-dotenv"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "e10739bd-5b40-4b3a-990d-539bd81a7362",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "from getpass import getpass\n",
    "\n",
    "from IPython.display import display, Image, Markdown, Audio\n",
    "\n",
    "import requests"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "09b9bfb8-aa22-4b5e-a136-86362361689c",
   "metadata": {},
   "outputs": [],
   "source": [
    "%load_ext dotenv\n",
    "%dotenv"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "41090577-b5a5-444b-9670-cccdfee48082",
   "metadata": {},
   "source": [
    "### Configuring your environment\n",
    "\n",
    "To use the API you'll need your [Cloudflare Account ID](https://dash.cloudflare.com) (head to Workers & Pages > Overview > Account details > Account ID) and a [Workers AI enabled API Token](https://dash.cloudflare.com/profile/api-tokens).\n",
    "\n",
    "If you want to add these files to your environment, you can create a new file named `.env`\n",
    "\n",
    "```bash\n",
    "CLOUDFLARE_API_TOKEN=\"YOUR-TOKEN\"\n",
    "CLOUDFLARE_ACCOUNT_ID=\"YOUR-ACCOUNT-ID\"\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "3cdfc295-064a-4cd6-90c5-ea81c4434b31",
   "metadata": {},
   "outputs": [],
   "source": [
    "if \"CLOUDFLARE_API_TOKEN\" in os.environ:\n",
    "    api_token = os.environ[\"CLOUDFLARE_API_TOKEN\"]\n",
    "else:\n",
    "    api_token = getpass(\"Enter you Cloudflare API Token\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "88f40f51-4aa9-41ee-a30c-3d168dfd8d44",
   "metadata": {},
   "outputs": [],
   "source": [
    "if \"CLOUDFLARE_ACCOUNT_ID\" in os.environ:\n",
    "    account_id = os.environ[\"CLOUDFLARE_ACCOUNT_ID\"]\n",
    "else:\n",
    "    account_id = getpass(\"Enter your account id\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cb6f0b33-2850-43dd-ade5-8324922ba398",
   "metadata": {},
   "source": [
    "### Generate code from a comment\n",
    "\n",
    "A common use case is to complete the code for the user after they provide a descriptive comment."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "c4dbffd9-f3c4-42d7-ab76-c9203066b0da",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "\n",
       "```python\n",
       "# A function that checks if a given word is a palindrome\n",
       "def is_palindrome(word):\n",
       "    # Convert the word to lowercase\n",
       "    word = word.lower()\n",
       "\n",
       "    # Reverse the word\n",
       "    reversed_word = word[::-1]\n",
       "\n",
       "    # Check if the reversed word is the same as the original word\n",
       "    if word == reversed_word:\n",
       "        return True\n",
       "    else:\n",
       "        return False\n",
       "\n",
       "# Test the function\n",
       "print(is_palindrome(\"racecar\"))  # Output: True\n",
       "print(is_palindrome(\"hello\"))    # Output: False\n",
       "```\n"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "model = \"@hf/thebloke/deepseek-coder-6.7b-base-awq\"\n",
    "\n",
    "prompt = \"# A function that checks if a given word is a palindrome\"\n",
    "\n",
    "response = requests.post(\n",
    "    f\"https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run/{model}\",\n",
    "    headers={\"Authorization\": f\"Bearer {api_token}\"},\n",
    "    json={\"messages\": [\n",
    "        {\"role\": \"user\", \"content\": prompt}\n",
    "    ]}\n",
    ")\n",
    "inference = response.json()\n",
    "code = inference[\"result\"][\"response\"]\n",
    "\n",
    "display(Markdown(f\"\"\"\n",
    "```python\n",
    "{prompt}\n",
    "{code.strip()}\n",
    "```\n",
    "\"\"\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dbfcf971-fb36-4886-8029-b8c72d7fa29b",
   "metadata": {},
   "source": [
    "### Assist in debugging\n",
    "\n",
    "We've all been there, bugs happen. Sometimes those stacktraces can be very intimidating, and a great use case of using Code Generation is to assist in explaining the problem."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "34a9db99-b799-4c07-8bb4-a7100a44dd02",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "The error in your code is that you are trying to use a variable `name` which is not defined anywhere in your function. The correct variable to use is `first_name`. So, you should change `f\"Hello, {name}!\"` to `f\"Hello, {first_name}!\"`.\n",
       "\n",
       "Here is the corrected code:\n",
       "\n",
       "```python\n",
       "# Welcomes our user\n",
       "def hello_world(first_name=\"World\"):\n",
       "    print(f\"Hello, {first_name}\")\n",
       "```\n",
       "\n",
       "Now, when you call `hello_world()`, it will print \"Hello, World\" by default. If you call `hello_world(\"John\")`, it will print \"Hello, John\".\n"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "model = \"@hf/thebloke/deepseek-coder-6.7b-instruct-awq\"\n",
    "\n",
    "system_message = \"The user is going to give you code that isn't working. Explain to the user what might be wrong\"\n",
    "\n",
    "code = \"\"\"# Welcomes our user\n",
    "def hello_world(first_name=\"World\"):\n",
    "    print(f\"Hello, {name}!\")\n",
    "\"\"\"\n",
    "\n",
    "response = requests.post(\n",
    "    f\"https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run/{model}\",\n",
    "    headers={\"Authorization\": f\"Bearer {api_token}\"},\n",
    "    json={\"messages\": [\n",
    "        {\"role\": \"system\", \"content\": system_message},\n",
    "        {\"role\": \"user\", \"content\": code},\n",
    "    ]}\n",
    ")\n",
    "inference = response.json()\n",
    "response = inference[\"result\"][\"response\"]\n",
    "display(Markdown(response))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6077e477-e3f2-41fe-af09-7b595e1fcc2e",
   "metadata": {},
   "source": [
    "### Write tests!\n",
    "\n",
    "Writing unit tests is a common best practice. With the enough context, it's possible to write unit tests."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "a7a60a34-eade-480f-b4ea-5e3e1a0457a5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "\n",
       "Here is a simple unittest test case for the User class:\n",
       "\n",
       "```python\n",
       "import unittest\n",
       "\n",
       "class TestUser(unittest.TestCase):\n",
       "\n",
       "    def test_full_name(self):\n",
       "        user = User(\"John\", \"Doe\")\n",
       "        self.assertEqual(user.full_name(), \"John Doe\")\n",
       "\n",
       "    def test_default_last_name(self):\n",
       "        user = User(\"Jane\")\n",
       "        self.assertEqual(user.full_name(), \"Jane McJane\")\n",
       "\n",
       "if __name__ == '__main__':\n",
       "    unittest.main()\n",
       "```\n",
       "\n",
       "In this test case, we have two tests:\n",
       "\n",
       "- `test_full_name` tests the `full_name` method when the user has both a first name and a last name.\n",
       "- `test_default_last_name` tests the `full_name` method when the user only has a first name and the last name is set to \"Mc\" + first name.\n",
       "\n",
       "If all these tests pass, it means that the `full_name` method is working as expected. If any of these tests fail, it"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "model = \"@hf/thebloke/deepseek-coder-6.7b-instruct-awq\"\n",
    "\n",
    "system_message = \"The user is going to give you code and would like to have tests written in the Python unittest module.\"\n",
    "\n",
    "code = \"\"\"\n",
    "class User:\n",
    "\n",
    "    def __init__(self, first_name, last_name=None):\n",
    "        self.first_name = first_name\n",
    "        self.last_name = last_name\n",
    "        if last_name is None:\n",
    "            self.last_name = \"Mc\" + self.first_name\n",
    "\n",
    "    def full_name(self):\n",
    "        return self.first_name + \" \" + self.last_name\n",
    "\"\"\"\n",
    "\n",
    "response = requests.post(\n",
    "    f\"https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run/{model}\",\n",
    "    headers={\"Authorization\": f\"Bearer {api_token}\"},\n",
    "    json={\"messages\": [\n",
    "        {\"role\": \"system\", \"content\": system_message},\n",
    "        {\"role\": \"user\", \"content\": code},\n",
    "    ]}\n",
    ")\n",
    "inference = response.json()\n",
    "response = inference[\"result\"][\"response\"]\n",
    "display(Markdown(response))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "21dd5f6d-f46c-4a67-850d-3a9269612976",
   "metadata": {},
   "source": [
    "### Fill-in-the-middle Code Completion\n",
    "\n",
    "A common use case in Developer Tools is to autocomplete based on context. DeepSeek Coder provides the ability to submit existing code with a placeholder, so that the model can complete in context.\n",
    "\n",
    "Warning: The tokens are prefixed with `<｜` and suffixed with `｜>` make sure to copy and paste them."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "9d9fb494-7e2e-4783-ae3b-466f499ea20f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "\n",
       "```python\n",
       "is_valid_email = re.match(r\"[^@]+@[^@]+\\.[^@]+\", email_address)\n",
       "```\n"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "model = \"@hf/thebloke/deepseek-coder-6.7b-base-awq\"\n",
    "\n",
    "code = \"\"\"\n",
    "<｜fim▁begin｜>import re\n",
    "\n",
    "from jklol import email_service\n",
    "\n",
    "def send_email(email_address, body):\n",
    "    <｜fim▁hole｜>\n",
    "    if not is_valid_email:\n",
    "        raise InvalidEmailAddress(email_address)\n",
    "    return email_service.send(email_address, body)<｜fim▁end｜>\n",
    "\"\"\"\n",
    "\n",
    "response = requests.post(\n",
    "    f\"https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run/{model}\",\n",
    "    headers={\"Authorization\": f\"Bearer {api_token}\"},\n",
    "    json={\"messages\": [\n",
    "        {\"role\": \"user\", \"content\": code}\n",
    "    ]}\n",
    ")\n",
    "inference = response.json()\n",
    "response = inference[\"result\"][\"response\"]\n",
    "display(Markdown(f\"\"\"\n",
    "```python\n",
    "{response.strip()}\n",
    "```\n",
    "\"\"\"))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "63bc41c8-0a11-4123-bf17-ff5aa6f9a690",
   "metadata": {},
   "source": [
    "### Experimental: Extract data into JSON\n",
    "\n",
    "No need to threaten the model or bring grandma into the prompt. Get back JSON in the format you want."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "8a6aa203-1e45-40c7-8dfd-cfee4ec9f03d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "\n",
       "```json\n",
       "{\n",
       "  \"firstName\": \"Craig\",\n",
       "  \"lastName\": \"Dennis\",\n",
       "  \"numKids\": 2,\n",
       "  \"interests\": [\"AI\", \"Cloudflare\", \"Tacos\", \"Burritos\"]\n",
       "}\n",
       "```\n"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "model = \"@hf/thebloke/deepseek-coder-6.7b-instruct-awq\"\n",
    "\n",
    "# Learn more at https://json-schema.org/\n",
    "json_schema = \"\"\"\n",
    "{\n",
    "  \"title\": \"User\",\n",
    "  \"description\": \"A user from our example app\",\n",
    "  \"type\": \"object\",\n",
    "  \"properties\": {\n",
    "    \"firstName\": {\n",
    "      \"description\": \"The user's first name\",\n",
    "      \"type\": \"string\"\n",
    "    },\n",
    "    \"lastName\": {\n",
    "      \"description\": \"The user's last name\",\n",
    "      \"type\": \"string\"\n",
    "    },\n",
    "    \"numKids\": {\n",
    "      \"description\": \"Amount of children the user has currently\",\n",
    "      \"type\": \"integer\"\n",
    "    },\n",
    "    \"interests\": {\n",
    "      \"description\": \"A list of what the user has shown interest in\",\n",
    "      \"type\": \"array\",\n",
    "      \"items\": {\n",
    "        \"type\": \"string\"\n",
    "      }\n",
    "    },\n",
    "  },\n",
    "  \"required\": [ \"firstName\" ]\n",
    "}\n",
    "\"\"\"\n",
    "\n",
    "system_prompt = f\"\"\"\n",
    "The user is going to discuss themselves and you should create a JSON object from their description to match the json schema below. \n",
    "\n",
    "<BEGIN JSON SCHEMA>\n",
    "{json_schema}\n",
    "<END JSON SCHEMA>\n",
    "\n",
    "Return JSON only. Do not explain or provide usage examples.\n",
    "\"\"\"\n",
    "\n",
    "prompt = \"\"\"Hey there, I'm Craig Dennis and I'm a Developer Educator at Cloudflare. My email is craig@cloudflare.com. \n",
    "            I am very interested in AI. I've got two kids. I love tacos, burritos, and all things Cloudflare\"\"\"\n",
    "\n",
    "response = requests.post(\n",
    "    f\"https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run/{model}\",\n",
    "    headers={\"Authorization\": f\"Bearer {api_token}\"},\n",
    "    json={\"messages\": [\n",
    "        {\"role\": \"system\", \"content\": system_prompt},\n",
    "        {\"role\": \"user\", \"content\": prompt}\n",
    "    ]}\n",
    ")\n",
    "inference = response.json()\n",
    "response = inference[\"result\"][\"response\"]\n",
    "display(Markdown(f\"\"\"\n",
    "```json\n",
    "{response.strip()}\n",
    "```\n",
    "\"\"\"))"
   ]
  }
 ],
 "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.12.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
