{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This notebook demos how to make prompt functions -- that is, python functions that \n",
    "are defined by prompt templates."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Pre-defined prompt functions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We have a few pre-defined prompt functions that come with the `oa` package. \n",
    "We'll start looking at those, and then see how to make them..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['prompt_template_improver',\n",
       " 'user_story_to_code_for_dag',\n",
       " 'prompt_template_starter',\n",
       " 'make_synopsis',\n",
       " 'description_to_software_specs',\n",
       " 'define_jargon',\n",
       " 'simple_tests_for_code',\n",
       " 'suggest_names',\n",
       " 'specs_to_code_for_dag']"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from oa import ask\n",
    "from inspect import signature\n",
    "\n",
    "print_signature = lambda func: print(signature(func))\n",
    "\n",
    "list(ask.ai)[:10]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## prompt_template_starter"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Of particular interest to use here is an AI-enabled function that will help us make AI-enabled functions...\n",
    "\n",
    "It has two inputs:\n",
    "- a `task`, which is a specification of what we want a prompt template for\n",
    "- `inputs`, which is a specification of what \"variables\" this prompt template should have, that is, what kinds of inputs we're going to ask the user"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(task, *, inputs=' ')\n"
     ]
    }
   ],
   "source": [
    "print_signature(ask.ai.prompt_template_starter)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First we go through a bit of experimentation, trying out different ways of expressing what we want. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "You are a language teacher. Teach me how to say {this} in the new language.\n"
     ]
    }
   ],
   "source": [
    "template = ask.ai.prompt_template_starter(\n",
    "    task=\"\"\"\n",
    "    Help me learn a new language\n",
    "    \"\"\",\n",
    "    inputs = \"\"\n",
    ")\n",
    "print(template)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "You are a language learning expert. Translate the following sentences into {language} using the vocabulary words: {vocabulary_words}. Translate {number_of_sentences} sentences.\n"
     ]
    }
   ],
   "source": [
    "template = ask.ai.prompt_template_starter(\n",
    "    task=\"\"\"\n",
    "    Help me learn new vocabulary words of a language that I'm learning\n",
    "    by giving me some sentences that I should translate into the language I am learning.\n",
    "    \"\"\",\n",
    "    inputs = \"language, vocabulary_words, number_of_sentences\"\n",
    ")\n",
    "print(template)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then we settle on some template, possibly editing it a bit, and make a prompt function out of it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(vocabulary_words, *, language='Japanese', number_of_sentences='3')\n"
     ]
    }
   ],
   "source": [
    "from oa import prompt_function\n",
    "\n",
    "template = \"\"\"\n",
    "You are a language learning expert. Translate the following sentences into {language:Japanese} \n",
    "using the vocabulary words: {vocabulary_words}. \n",
    "Give me a list of {number_of_sentences:3} to translate followed with an ANSWERS section where \n",
    "you'll list the actual translations.\n",
    "\"\"\"\n",
    "practice_vocab = prompt_function(template)\n",
    "print_signature(practice_vocab)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's try this function out:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1. Hello, please give me some tasty sushi.\n",
      "2. Thank you for the tasty sushi.\n",
      "3. Hello, may I please have some more tasty sushi?\n",
      "\n",
      "ANSWERS:\n",
      "1. こんにちは、美味しい寿司をください。\n",
      "2. 美味しい寿司をありがとうございます。\n",
      "3. こんにちは、美味しい寿司をもう少しいただけますか。\n"
     ]
    }
   ],
   "source": [
    "print(practice_vocab(\"tasty, sushi, hello, please, thank you\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's have a look at what the underlying template looks like."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "```\n",
      "You are an expert prompt engineer.\n",
      "I will give you a task below and would like you to write a “prompt template” to perform this task.\n",
      "This task will be parametrized by some inputs, which should appear in the prompt template as placeholders, marked by braces {like} {this} (here, both “like” and “this” are names of inputs that would parametrize the prompt template). \n",
      "I might give you an explicit list of inputs, which will be a comma or space separated list of strings (to be more precise, python identifier strings (so only alphanumerics and underscores).\n",
      "If I do give you this list of inputs (names), you should use them (all) in the prompt template, using the {braces} to show where these should be injected when making a prompt (I have code for that). \n",
      "You should use them all.\n",
      "If I don’t give you this list of inputs (that is, my list of inputs is empty), you should come up with your own. Remember; I’m going to use this template to make a form to get inputs from the user, so I need this form to contain input fields, so I need my prompt template to have named placeholders to inject the inputs in and make a prompt. \n",
      "Also, your output should ONLY be the prompt template, with no explanation, before or after\n",
      "\n",
      "Here’s two examples: \n",
      "\n",
      "###\n",
      "\n",
      "My input:\n",
      "Task: Generate jokes\n",
      "Inputs:\n",
      "\n",
      "Your output:\n",
      "You are an expert comedy writer. Write me a joke about {this}.\n",
      "\n",
      "###\n",
      "\n",
      "My input:\n",
      "Task: Generate jokes\n",
      "Inputs: subject_of_joke, approx_number_of_words\n",
      "\n",
      "Your output:\n",
      "You are an expert comedy writer. Write me a joke about {subject_of_joke} with about {approx_number_of_words}\n",
      "```\n",
      "\n",
      "###\n",
      "\n",
      "Here’s my first actual input:\n",
      "Task: {task}\n",
      "Inputs: {inputs: }\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(ask.ai.prompt_template_starter.template_original)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## prompt_template_improver"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "So now we have a template that works. How can we improve it?\n",
    "\n",
    "Let's use another (prompt-based) function for that"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "template = \"\"\"\n",
    "You are a language learning expert. Translate the following sentences into {language:Japanese} \n",
    "using the vocabulary words: {vocabulary_words}. \n",
    "Give me a list of {number_of_sentences:3} to translate followed with an ANSWERS section where \n",
    "you'll list the actual translations.\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(prompt_template, *, specific_goals=' ', number_of_alternatives='3', include_additional_explanations='false', prompt_engineering_tips='false')\n"
     ]
    }
   ],
   "source": [
    "print_signature(ask.ai.prompt_template_improver)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "**Prompt Alternatives:**\n",
      "1. You are a language learning expert. Translate the following sentences into {language:Japanese} using the vocabulary words: {vocabulary_words}. Give me a list of {number_of_sentences:3} to translate followed with an ANSWERS section where you'll list the actual translations.\n",
      "  \n",
      "2. As a language learning expert, I need you to translate the following sentences into {language:Japanese} with the provided vocabulary words: {vocabulary_words}. Provide a list of {number_of_sentences:3} to translate, followed by an ANSWERS section where the actual translations will be listed.\n",
      "\n",
      "3. Calling all language learning experts! Your task is to translate the following sentences into {language:Japanese} using the vocabulary words: {vocabulary_words}. I need a list of {number_of_sentences:3} translations, followed by an ANSWERS section detailing the actual translations.\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "alternative_template_1 = ask.ai.prompt_template_improver(template)\n",
    "print(alternative_template_1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Alternative 1:\n",
      "You are a language learning expert. Translate the following sentences into {language:Japanese} \n",
      "using the vocabulary words: {vocabulary_words}. \n",
      "Give me a list of {number_of_sentences:3} to translate followed with an ANSWERS section where \n",
      "you'll list the actual translations.\n",
      "\n",
      "Alternative 2:\n",
      "As a language learning expert, translate the sentences below into {language:Japanese} \n",
      "with the given vocabulary words: {vocabulary_words}. \n",
      "Provide {number_of_sentences:3} translations and list them in the ANSWERS section.\n",
      "\n",
      "ADDITIONAL EXPLANATIONS:\n",
      "In these alternatives, the focus is on the vocabulary words provided, ensuring that the translations stick closely to them. By structuring the prompt in a specific format, it can help guide the expert towards using the vocabulary effectively in the translations.\n",
      "\n",
      "PROMPT ENGINEERING TIPS:\n",
      "1. Encourage the expert to utilize the vocabulary words creatively by providing a variety of sentence structures to translate.\n",
      "2. Remind the expert to pay attention to nuances and context when translating to ensure accuracy while staying focused on the vocabulary words.\n"
     ]
    }
   ],
   "source": [
    "alternative_template_2 = ask.ai.prompt_template_improver(\n",
    "    template,\n",
    "    specific_goals='To stay more focused on the vocabulary words, departing from them as little as possible', \n",
    "    number_of_alternatives=2, \n",
    "    include_additional_explanations=True, \n",
    "    prompt_engineering_tips=True\n",
    ")\n",
    "print(alternative_template_2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## changing the chat model"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Not good enough?\n",
    "\n",
    "Perhaps the prompt is good enough, but not the ai?\n",
    "\n",
    "Let's try to change the model we're using!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['whisper-1',\n",
       " 'davinci-002',\n",
       " 'dall-e-2',\n",
       " 'tts-1-hd-1106',\n",
       " 'tts-1-hd',\n",
       " 'gpt-3.5-turbo',\n",
       " 'gpt-3.5-turbo-0125',\n",
       " 'gpt-3.5-turbo-instruct-0914',\n",
       " 'gpt-3.5-turbo-16k-0613',\n",
       " 'gpt-3.5-turbo-16k',\n",
       " 'gpt-3.5-turbo-instruct',\n",
       " 'gpt-3.5-turbo-0301',\n",
       " 'gpt-3.5-turbo-0613',\n",
       " 'tts-1',\n",
       " 'dall-e-3',\n",
       " 'gpt-3.5-turbo-1106',\n",
       " 'babbage-002',\n",
       " 'gpt-4-0125-preview',\n",
       " 'gpt-4-turbo-preview',\n",
       " 'tts-1-1106',\n",
       " 'text-embedding-3-large',\n",
       " 'gpt-4-turbo-2024-04-09',\n",
       " 'gpt-4-vision-preview',\n",
       " 'text-embedding-3-small',\n",
       " 'gpt-4',\n",
       " 'text-embedding-ada-002',\n",
       " 'gpt-4-1106-vision-preview',\n",
       " 'gpt-4-1106-preview',\n",
       " 'gpt-4-0613',\n",
       " 'gpt-4-turbo']"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from oa.base import list_engine_ids\n",
    "\n",
    "list_engine_ids()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "from oa import prompt_function, chat\n",
    "from functools import partial\n",
    "\n",
    "smarter_chat = partial(chat, model='gpt-4')\n",
    "smarter_prompt_function = partial(prompt_function, prompt_func=smarter_chat)\n",
    "# and now let's make a smarter prompt_template_improver\n",
    "# Since prompt_template_improver was already made with the default chat model,\n",
    "# we need to go back to the template, and make a new function with the new model\n",
    "smarter_prompt_template_improver = smarter_prompt_function(\n",
    "    ask.ai.prompt_template_improver.template_original\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Alternative 1:\n",
      "For our language mastery exercise today, you are to translate the following phrases into {language:Japanese}. You will be utilizing these key phrases: {vocabulary_words}. Provide an index of {number_of_sentences:3} notions to translate and follow it with a SOLUTIONS segment where you catalog the accurate translations.\n",
      "\n",
      "Alternative 2:\n",
      "You are recognized for your proficiency in languages. The task here requires you to translate the subsequent sentences into {language:Japanese}, with a focus on these keywords: {vocabulary_words}. Try to construct and translate {number_of_sentences:3} original lines, followed by an ANSWERS segment displaying the correct translations.\n",
      "\n",
      "ADDITIONAL EXPLANATIONS:\n",
      "\n",
      "Alternative 1 slightly modifies the tone and language of the original template. In this alternative, the wording is a bit more formal. 'mastery exercise' is used instead of 'learning', which might help the AI take a more scholarly approach to the task. Also, by renaming the 'ANSWERS' to 'SOLUTIONS', it can make the AI generate answers in a more solution-providing way. These slight tweaks are done keeping the specific goal in mind that we want the AI to stick to the vocabulary words as closely as possible.\n",
      "\n",
      "Alternative 2 basically keeps the original structure of the prompt but enhances it by adding expressions such as 'recognized for your proficiency' and 'construct and translate original lines'. These add-ins are used to inspire the AI to stay more focused on utilizing the specified vocabulary words.\n",
      "\n",
      "PROMPT ENGINEERING TIPS:\n",
      "\n",
      "1. Always keep the end task in mind. The alterations in the template should be driven by what you want out of the task. In this case, to keep the focus on the vocabulary words. \n",
      "\n",
      "2. The tone of the prompt can significantly affect the output. If you want an output that is more formal or professional, consider using language that sounds more academic or professional.\n",
      "\n",
      "3. Consider the way you frame your instructions. Providing clear, specific instructions can help produce a response that more closely matches what you're looking for. \n",
      "\n",
      "4. Don't be afraid to experiment with your prompt. The slight alterations may cause the AI to approach the task in a way that you hadn't thought of.\n",
      "  \n",
      "5. Lastly, prompt engineering is more art than science. It requires understanding how the AI generates responses and using this knowledge to craft an effective prompt. Keep practicing, and you'll get better at it!\n"
     ]
    }
   ],
   "source": [
    "template = \"\"\"\n",
    "You are a language learning expert. Translate the following sentences into {language:Japanese} \n",
    "using the vocabulary words: {vocabulary_words}. \n",
    "Give me a list of {number_of_sentences:3} to translate followed with an ANSWERS section where \n",
    "you'll list the actual translations.\n",
    "\"\"\"\n",
    "alternative_template_3 = smarter_prompt_template_improver(\n",
    "    template,\n",
    "    specific_goals='To stay more focused on the vocabulary words, departing from them as little as possible', \n",
    "    number_of_alternatives=2, \n",
    "    include_additional_explanations=True, \n",
    "    prompt_engineering_tips=True\n",
    ")\n",
    "print(alternative_template_3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Your own templates"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "I mean, really we've already gone through the motions now, perhaps unknowlingly.\n",
    "\n",
    "We took a pre existing ai-based function as our point of departure, but have seen how it itself was \n",
    "made from a prompt template string. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Using `response_format` to get json"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "With some newer models (example, \"gpt4o-mini\") you can request that only valid \n",
    "json be given as a response, or even more: A json obeying a specific schema. \n",
    "You control this via the `response_format` argument. \n",
    "\n",
    "Let's first use AI to get a json schema for characteristics of a programming language.\n",
    "That's a json, so why not use the `response_format` with `{\"type\": \"json_object\"}` to \n",
    "get that schema!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To make sure we get a json schema that is openAI compliant, we'll use an example of \n",
    "one in our prompt to AI to give us one..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "    \"name\": \"math_response\",\n",
      "    \"strict\": false,\n",
      "    \"schema\": {\n",
      "      \"type\": \"object\",\n",
      "      \"properties\": {\n",
      "        \"steps\": {\n",
      "          \"type\": \"array\",\n",
      "          \"items\": {\n",
      "            \"type\": \"object\",\n",
      "            \"properties\": {\n",
      "              \"explanation\": {\n",
      "                \"type\": \"string\"\n",
      "              },\n",
      "              \"output\": {\n",
      "                \"type\": \"string\"\n",
      "              }\n",
      "            },\n",
      "            \"required\": [\n",
      "              \"explanation\",\n",
      "              \"output\"\n",
      "            ],\n",
      "            \"additionalProperties\": false\n",
      "          }\n",
      "        },\n",
      "        \"final_answer\": {\n",
      "          \"type\": \"string\"\n",
      "        }\n",
      "      },\n",
      "      \"additionalProperties\": false,\n",
      "      \"required\": [\n",
      "        \"steps\",\n",
      "        \"final_answer\"\n",
      "      ]\n",
      "    }\n",
      "  }\n"
     ]
    }
   ],
   "source": [
    "from oa.util import data_files\n",
    "\n",
    "example_of_a_openai_json_schema = data_files.joinpath('json_schema_example.json').read_text()\n",
    "\n",
    "print(example_of_a_openai_json_schema)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "  \"name\": \"programming_language_characteristics\",\n",
      "  \"strict\": false,\n",
      "  \"schema\": {\n",
      "    \"type\": \"object\",\n",
      "    \"properties\": {\n",
      "      \"name\": {\n",
      "        \"type\": \"string\",\n",
      "        \"description\": \"The name of the programming language.\"\n",
      "      },\n",
      "      \"paradigm\": {\n",
      "        \"type\": \"array\",\n",
      "        \"items\": {\n",
      "          \"type\": \"string\",\n",
      "          \"description\": \"Programming paradigms the language follows, e.g., 'object-oriented', 'functional', etc.\"\n",
      "        }\n",
      "      },\n",
      "      \"designed_by\": {\n",
      "        \"t...\n"
     ]
    }
   ],
   "source": [
    "from oa import chat\n",
    "\n",
    "json_schema_str = chat(\n",
    "    \"Give me the json of a json_schema I can use different characteristics of \"\n",
    "    \"programming languages. This schema should be a valid schema to use as a \"\n",
    "    \"response_format in the OpenAI API. \"\n",
    "    f\"Here's an example:\\n{example_of_a_openai_json_schema}\", \n",
    "    model='gpt-4o-mini',\n",
    "    response_format={'type': 'json_object'}\n",
    ")\n",
    "print(json_schema_str[:500] + '...')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can use this schema to make an AI-enabled python function that will give \n",
    "us characteristics of a language, but always using that fixed format.\n",
    "This also means we'll be able to stick an `egress` to our prompt function, so \n",
    "that we always get our output in the form of an already decoded json (a `dict`)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "type(info)=<class 'dict'>\n",
      "\n",
      "{'designed_by': ['Guido van Rossum'],\n",
      " 'first_appeared': 1991,\n",
      " 'influenced_by': ['ABC', 'C', 'C++', 'Java', 'Modula-3', 'Lisp'],\n",
      " 'influences': ['Ruby', 'Swift', 'Matlab', 'Go'],\n",
      " 'latest_release': '3.11.5',\n",
      " 'name': 'Python',\n",
      " 'paradigm': ['object-oriented', 'imperative', 'functional', 'procedural'],\n",
      " 'typing_discipline': 'dynamic',\n",
      " 'website': 'https://www.python.org'}\n"
     ]
    }
   ],
   "source": [
    "import json\n",
    "from oa import prompt_function\n",
    "\n",
    "\n",
    "properties_of_language = prompt_function(\n",
    "    \"Give me a json that describes characteristics of the programming language: {language}.\",\n",
    "    prompt_func=chat, \n",
    "    prompt_func_kwargs=dict(\n",
    "        model='gpt-4o-mini', \n",
    "        response_format={\n",
    "            'type': 'json_schema',\n",
    "            'json_schema': json.loads(json_schema_str)\n",
    "        }\n",
    "    ),\n",
    "    egress=json.loads\n",
    ")\n",
    "\n",
    "info = properties_of_language('Python')\n",
    "print(f\"{type(info)=}\\n\")\n",
    "\n",
    "from pprint import pprint\n",
    "pprint(info)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "p10",
   "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.10.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
