nisargvp commited on
Commit
063cbd0
2 Parent(s): 293585b 40e4d64

Merge branch 'myrepo' of https://github.com/nisargvp/nisargs_llmops_project into myrepo

Browse files
app/Programatically_Accessing_OpenAI_Endpoints_with_Python.ipynb ADDED
@@ -0,0 +1,334 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {
6
+ "id": "UIuhLOcmCdyR"
7
+ },
8
+ "source": [
9
+ "### Using the OpenAI Library to Programmatically Access GPT-3.5-turbo!\n",
10
+ "\n",
11
+ "This notebook was authored by [Chris Alexiuk](https://www.linkedin.com/in/csalexiuk/)"
12
+ ]
13
+ },
14
+ {
15
+ "cell_type": "code",
16
+ "execution_count": 1,
17
+ "metadata": {
18
+ "colab": {
19
+ "base_uri": "https://localhost:8080/"
20
+ },
21
+ "id": "3qCKaH6vD-jZ",
22
+ "outputId": "b9898a5f-36a7-4d8d-d760-310187cf31fa"
23
+ },
24
+ "outputs": [],
25
+ "source": [
26
+ "# !pip install openai cohere tiktoken -qU"
27
+ ]
28
+ },
29
+ {
30
+ "cell_type": "markdown",
31
+ "metadata": {
32
+ "id": "XxS23_1zpYid"
33
+ },
34
+ "source": [
35
+ "### OpenAI API Key"
36
+ ]
37
+ },
38
+ {
39
+ "cell_type": "code",
40
+ "execution_count": 2,
41
+ "metadata": {
42
+ "colab": {
43
+ "base_uri": "https://localhost:8080/"
44
+ },
45
+ "id": "tpnsDCfEbsqS",
46
+ "outputId": "1011f74e-624b-4800-89ff-c83152d34c1f"
47
+ },
48
+ "outputs": [],
49
+ "source": [
50
+ "import os\n",
51
+ "import openai\n",
52
+ "import getpass\n",
53
+ "\n",
54
+ "# set the OPENAI_API_KEY environment variable\n",
55
+ "openai.api_key = getpass.getpass(\"OpenAI API Key:\")"
56
+ ]
57
+ },
58
+ {
59
+ "cell_type": "markdown",
60
+ "metadata": {
61
+ "id": "YHD49z39pbIS"
62
+ },
63
+ "source": [
64
+ "### Our First Prompt\n",
65
+ "\n",
66
+ "You can reference OpenAI's [documentation](https://platform.openai.com/docs/api-reference/authentication?lang=python) if you get stuck!\n",
67
+ "\n",
68
+ "Let's create a `ChatCompletion` model to kick things off!\n",
69
+ "\n",
70
+ "There are three \"roles\" available to use:\n",
71
+ "\n",
72
+ "- `system`\n",
73
+ "- `assistant`\n",
74
+ "- `user`\n",
75
+ "\n",
76
+ "OpenAI provides some context for these roles [here](https://help.openai.com/en/articles/7042661-chatgpt-api-transition-guide)\n",
77
+ "\n",
78
+ "Let's just stick to the `user` role for now and send our first message to the endpoint!\n",
79
+ "\n",
80
+ "If we check the documentation, we'll see that it expects it in a list of prompt objects - so we'll be sure to do that!"
81
+ ]
82
+ },
83
+ {
84
+ "cell_type": "code",
85
+ "execution_count": 3,
86
+ "metadata": {
87
+ "id": "g0AL4VTwyWLN"
88
+ },
89
+ "outputs": [
90
+ {
91
+ "data": {
92
+ "text/plain": [
93
+ "ChatCompletion(id='chatcmpl-9D4ZMhNvYSJaf3Rx8cDkyW2ypwPog', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='A woodchuck could chuck as much wood as a woodchuck would chuck if a woodchuck could chuck wood.', role='assistant', function_call=None, tool_calls=None))], created=1712902856, model='gpt-3.5-turbo-0125', object='chat.completion', system_fingerprint='fp_c2295e73ad', usage=CompletionUsage(completion_tokens=25, prompt_tokens=25, total_tokens=50))"
94
+ ]
95
+ },
96
+ "execution_count": 3,
97
+ "metadata": {},
98
+ "output_type": "execute_result"
99
+ }
100
+ ],
101
+ "source": [
102
+ "from openai import OpenAI\n",
103
+ "\n",
104
+ "client = OpenAI(api_key=openai.api_key)\n",
105
+ "\n",
106
+ "YOUR_PROMPT = \"How much wood could a woodchuck chuck if a woodchuck could chuck wood?\"\n",
107
+ "\n",
108
+ "client.chat.completions.create(\n",
109
+ " model=\"gpt-3.5-turbo\",\n",
110
+ " messages=[{\"role\" : \"user\", \"content\" : YOUR_PROMPT}]\n",
111
+ ")"
112
+ ]
113
+ },
114
+ {
115
+ "cell_type": "markdown",
116
+ "metadata": {
117
+ "id": "FD_Z64hGy6RV"
118
+ },
119
+ "source": [
120
+ "As you can see, the prompt comes back with a tonne of information that we can use when we're building our applications!\n",
121
+ "\n",
122
+ "Let's focus on extending that a bit, and incorporate a `system` message as well!\n",
123
+ "\n",
124
+ "Also, we'll be building some helper functions to display the prompts with Markdown!\n",
125
+ "\n",
126
+ "We'll also wrap our prompts so we don't have to keep making dictionaries for them!"
127
+ ]
128
+ },
129
+ {
130
+ "cell_type": "code",
131
+ "execution_count": 4,
132
+ "metadata": {
133
+ "id": "QSQMFfWKbsqT"
134
+ },
135
+ "outputs": [],
136
+ "source": [
137
+ "from IPython.display import display, Markdown\n",
138
+ "\n",
139
+ "def get_response(messages: str, model: str = \"gpt-3.5-turbo\") -> str:\n",
140
+ " return client.chat.completions.create(\n",
141
+ " model=model,\n",
142
+ " messages=messages\n",
143
+ " )\n",
144
+ "\n",
145
+ "def wrap_prompt(message: str, role: str) -> dict:\n",
146
+ " return {\"role\": role, \"content\": message}\n",
147
+ "\n",
148
+ "def m_print(message: str) -> str:\n",
149
+ " display(Markdown(message.choices[0].message.content))"
150
+ ]
151
+ },
152
+ {
153
+ "cell_type": "code",
154
+ "execution_count": 5,
155
+ "metadata": {
156
+ "colab": {
157
+ "base_uri": "https://localhost:8080/",
158
+ "height": 348
159
+ },
160
+ "id": "7aEd_p1sbsqT",
161
+ "outputId": "d32cf1ff-d4aa-48a9-ebf5-f670c1750110"
162
+ },
163
+ "outputs": [
164
+ {
165
+ "data": {
166
+ "text/markdown": [
167
+ "Sure! Here's a Python function that calculates the Nth Fibonacci number using recursion:\n",
168
+ "\n",
169
+ "```python\n",
170
+ "def fibonacci(n):\n",
171
+ " if n <= 0:\n",
172
+ " return \"Invalid input. Please enter a positive integer.\"\n",
173
+ " elif n == 1:\n",
174
+ " return 0\n",
175
+ " elif n == 2:\n",
176
+ " return 1\n",
177
+ " else:\n",
178
+ " return fibonacci(n-1) + fibonacci(n-2)\n",
179
+ "\n",
180
+ "n = 10\n",
181
+ "result = fibonacci(n)\n",
182
+ "print(f\"The {n}th Fibonacci number is: {result}\")\n",
183
+ "```\n",
184
+ "\n",
185
+ "You can replace the value of `n` with any positive integer to get the corresponding Fibonacci number."
186
+ ],
187
+ "text/plain": [
188
+ "<IPython.core.display.Markdown object>"
189
+ ]
190
+ },
191
+ "metadata": {},
192
+ "output_type": "display_data"
193
+ }
194
+ ],
195
+ "source": [
196
+ "system_prompt = wrap_prompt(\"You are a Python Programmer.\", \"system\")\n",
197
+ "user_prompt = wrap_prompt(\"Can you write me a function in Python that calculates the Nth Fibonacci number?\", \"user\")\n",
198
+ "\n",
199
+ "openai_response = get_response([system_prompt, user_prompt])\n",
200
+ "m_print(openai_response)"
201
+ ]
202
+ },
203
+ {
204
+ "cell_type": "code",
205
+ "execution_count": 6,
206
+ "metadata": {
207
+ "colab": {
208
+ "base_uri": "https://localhost:8080/"
209
+ },
210
+ "id": "N7EproZ5ztKt",
211
+ "outputId": "a7ca3b15-87cf-4c27-8173-6534d9f70421"
212
+ },
213
+ "outputs": [
214
+ {
215
+ "name": "stdout",
216
+ "output_type": "stream",
217
+ "text": [
218
+ "ChatCompletion(id='chatcmpl-9D4cOPbhi0rrPQGQC1bDUrDBUNTGs', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='Sure! Here\\'s a Python function that calculates the Nth Fibonacci number using recursion:\\n\\n```python\\ndef fibonacci(n):\\n if n <= 0:\\n return \"Invalid input. Please enter a positive integer.\"\\n elif n == 1:\\n return 0\\n elif n == 2:\\n return 1\\n else:\\n return fibonacci(n-1) + fibonacci(n-2)\\n\\nn = 10\\nresult = fibonacci(n)\\nprint(f\"The {n}th Fibonacci number is: {result}\")\\n```\\n\\nYou can replace the value of `n` with any positive integer to get the corresponding Fibonacci number.', role='assistant', function_call=None, tool_calls=None))], created=1712903044, model='gpt-3.5-turbo-0125', object='chat.completion', system_fingerprint='fp_b28b39ffa8', usage=CompletionUsage(completion_tokens=129, prompt_tokens=33, total_tokens=162))\n"
219
+ ]
220
+ }
221
+ ],
222
+ "source": [
223
+ "print(openai_response)"
224
+ ]
225
+ },
226
+ {
227
+ "cell_type": "markdown",
228
+ "metadata": {
229
+ "id": "YdhHoeo5zxbl"
230
+ },
231
+ "source": [
232
+ "You can add the `assistant` role to send messages as-if they're from the model itself - which can help us do \"few-shot\" prompt engineering!\n",
233
+ "\n",
234
+ "That's where we show the LLM a few examples of the output we'd like to see to help guide the model to our desired outputs!\n",
235
+ "\n",
236
+ "Let's see it in action!"
237
+ ]
238
+ },
239
+ {
240
+ "cell_type": "code",
241
+ "execution_count": 7,
242
+ "metadata": {
243
+ "id": "DLCT0o5i0AEw"
244
+ },
245
+ "outputs": [],
246
+ "source": [
247
+ "prompt_list = [\n",
248
+ " wrap_prompt(\"You are an expert food critic, and also a pirate.\", \"system\"),\n",
249
+ " wrap_prompt(\"Hi, are apples any good?\", \"user\"),\n",
250
+ " wrap_prompt(\"Ahoy matey. Apples be the finest of the edible treasures.\", \"assistant\"),\n",
251
+ " wrap_prompt(\"Hello there, is the combination of cheese and plums a good combination?\", \"user\"),\n",
252
+ " wrap_prompt(\"Arrrrrr. That be a dish only land-lubbers could enjoy. If that grub be on my ship, I'd toss it overboard!\", \"assistant\")\n",
253
+ "]"
254
+ ]
255
+ },
256
+ {
257
+ "cell_type": "markdown",
258
+ "metadata": {
259
+ "id": "i1k3xWIP0x5u"
260
+ },
261
+ "source": [
262
+ "Now we can append our *actual* prompt to the list!"
263
+ ]
264
+ },
265
+ {
266
+ "cell_type": "code",
267
+ "execution_count": 8,
268
+ "metadata": {
269
+ "colab": {
270
+ "base_uri": "https://localhost:8080/",
271
+ "height": 64
272
+ },
273
+ "id": "CFeNREBW03G_",
274
+ "outputId": "4ff66e0f-b38d-486d-d125-dcb8b876b150"
275
+ },
276
+ "outputs": [
277
+ {
278
+ "data": {
279
+ "text/markdown": [
280
+ "Aye, pears be a fine addition to a salad, adding a sweet and juicy element to balance the savory and crunchy components. You won't be walkin' the plank for addin' them to your salad, that be for sure!"
281
+ ],
282
+ "text/plain": [
283
+ "<IPython.core.display.Markdown object>"
284
+ ]
285
+ },
286
+ "metadata": {},
287
+ "output_type": "display_data"
288
+ }
289
+ ],
290
+ "source": [
291
+ "prompt_list.append(wrap_prompt(\"Are pears a good choice for a salad?\", \"user\"))\n",
292
+ "\n",
293
+ "openai_response = get_response(prompt_list)\n",
294
+ "m_print(openai_response)"
295
+ ]
296
+ },
297
+ {
298
+ "cell_type": "markdown",
299
+ "metadata": {
300
+ "id": "ZJ2IuNHT1E8r"
301
+ },
302
+ "source": [
303
+ "Feel free to send some prompts and try out different things!\n",
304
+ "\n",
305
+ "Let us know if you find anything interesting!"
306
+ ]
307
+ }
308
+ ],
309
+ "metadata": {
310
+ "colab": {
311
+ "provenance": []
312
+ },
313
+ "kernelspec": {
314
+ "display_name": "open_ai",
315
+ "language": "python",
316
+ "name": "python3"
317
+ },
318
+ "language_info": {
319
+ "codemirror_mode": {
320
+ "name": "ipython",
321
+ "version": 3
322
+ },
323
+ "file_extension": ".py",
324
+ "mimetype": "text/x-python",
325
+ "name": "python",
326
+ "nbconvert_exporter": "python",
327
+ "pygments_lexer": "ipython3",
328
+ "version": "3.11.8"
329
+ },
330
+ "orig_nbformat": 4
331
+ },
332
+ "nbformat": 4,
333
+ "nbformat_minor": 0
334
+ }
app/hello_world.ipynb ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 1,
6
+ "metadata": {},
7
+ "outputs": [],
8
+ "source": [
9
+ "import pandas as pd\n",
10
+ "import numpy as np\n",
11
+ "import matplotlib.pyplot as plt"
12
+ ]
13
+ },
14
+ {
15
+ "cell_type": "code",
16
+ "execution_count": 2,
17
+ "metadata": {},
18
+ "outputs": [
19
+ {
20
+ "data": {
21
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkAAAAGzCAYAAADHdKgcAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAAA5+klEQVR4nO3de3zO9R//8eeO/Jprzm0s1kJ8Q4vUt4VUQ6YDlaj0ZRShfCtKzTehA33LIUnli7b11Vc6kYrRcohyiDIjYox0YSyHDZsdvH9/9HP9XHZgc12uXfs87rfb+5bP+/P+fD6v67Nr7bnP5/255iPJCAAAwEJ8PV0AAADApUYAAgAAlkMAAgAAlkMAAgAAlkMAAgAAlkMAAgAAlkMAAgAAlkMAAgAAlkMAAgAAlkMAAjxs2bJlWrZsmWM5PDxcxhj17dvXrccdPXq0jHH+IPj09HTFx8e79bhS8a8xPj5e2dnZbj+2q1yqc+UK8fHxSk9P93QZbtO3b18ZYxQeHu7pUuBFCECo8M78zy0nJ0f169cvsn7ZsmVKTU31QGWQpJiYGI0ePdrTZRSrItcGwLMIQPAaVatW1QsvvODpMiq1pk2basCAAWXapmvXrhozZkyZttmzZ4+qVq2q//73v2XarqzKUxsAayAAwWv88ssvGjBggOrVq+fW41StWtWt+6/I8vLyVFBQ4Lb9+/n5KSAgQJJ06tQpnT592m3HqqjOPgcAPIcABK8xbtw4+fn5XdBVID8/P7344otKS0tTbm6u0tPT9dprrykwMNBpXHp6ur766it17txZP/30k3JycvT444+rQ4cOMsbogQce0EsvvaQ//vhDWVlZ+vTTTxUcHKzAwEBNnjxZGRkZys7O1gcffFBk37Gxsfruu++UkZGh3NxcbdmyRYMGDSrz646NjZUxRtddd12RdXFxcSooKCj21uDZ2rZtq3Xr1iknJ0dpaWkaOHBgsePOndfi7++vl156Sdu3b1dOTo4yMzO1cuVKdezYUdJfc0uefPJJSZIxxtGk/z/PZ/jw4XrqqaeUlpamU6dO6Zprril1nlNERISSkpJ0/Phx2e12jRo1ymn9ma9Nhw4dnPrP3WdptUmSj4+PnnrqKW3evFk5OTk6cOCA3n//fdWoUaNITf/617+0d+9enThxQkuXLtU111xT6vk+t6bizkFAQIDGjh2r9evX6+jRozp+/Li+//573XrrrSXuY8CAAY739Lp169SmTZsix+zWrZtSU1OVk5Oj1NRUde/evdjaLrvsMk2YMEG///67cnNztW3bNg0fPrzIOGOMpk6dqh49emjLli06efKkfvzxR7Vo0UKSNHDgQO3YsUM5OTlatmzZeefh3H///TLG6JZbbimybuDAgTLGqHnz5pKkli1bKj4+Xjt37lROTo7279+vWbNmqVatWqUe40zdxd3+LG7uVvXq1TV58mTHudixY4dGjBghHx8fp3G9evXS+vXrlZWVpWPHjmnTpk365z//ed5aUDH5e7oA4EKlp6frww8/1IABA/T6669r//79JY6dOXOmYmNj9emnn2rixIn6+9//rpEjR+pvf/ub7rvvPqexTZs21Zw5czR9+nTNmDFDv/32m2NdXFyccnJy9Prrr6tx48YaOnSo8vPzdfr0adWsWVNjxozRTTfdpH79+ik9PV2vvPKKY9vBgwdry5YtWrBggQoKCnT33Xfrvffek6+vr959990Lft2fffaZpk2bpt69e2vjxo1O63r37q3ly5dr3759JW7fokULLVmyRIcOHdKYMWPk7++vsWPHKiMj47zHHjNmjOLi4jRz5kytW7dOwcHBatOmjVq3bq3k5GRNnz5d9evXV+fOnfXII48Uu49+/fqpatWq+s9//qNTp07p8OHD8vUt/ncvPz8/JSUlac2aNRoxYoS6dOmil19+Wf7+/mWey3O+2qZPn67Y2FjFx8fr7bffVkREhJ588km1atVKbdu2dVwJe/nllzVq1Ch98803WrhwoVq3bq0lS5YUCbylKe4cBAcH67HHHtOcOXM0Y8YM2Ww2Pfroo1q8eLFuvPFGpaSkOO3j4Ycfls1m0/Tp02WM0YgRI/TFF1/oqquuctTaqVMnff755/r1118VFxen2rVrKz4+Xn/88UeRmhYsWKDbbrtNs2bN0saNG3XHHXdowoQJCgsL07Bhw5zGtm/fXvfcc4+mTZsm6a/vi6+//lpvvPGGhgwZonfffVc1a9bUiBEj9MEHHyg6OrrEc/HNN98oOztbPXv21Pfff++0rlevXtq8ebO2bNnieD1XXXWV4uPjdeDAATVv3lwDBw5U8+bNddNNN13w+S/N//k//0crVqxQWFiYpk+frt9//10333yzxo8fr3r16umZZ56RJHXs2FEff/yx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ys7O9nQZAACgDGw22wXNkyQAFaN+/fqy2+2eLgMAAJRDWFjYeUMQAagYZ678hIWFcRUIAAAvYbPZZLfbL+hnNwGoFNnZ2QQgAAAqISZBAwAAyyEAAQAAyyEAAQAAyyEAAQAAyyEAAQAAyyEAAQAAyyEAAQAAyyEAAQAAyyEAAQAAyyEAAQAAyyEAAQAAyyEAAQAAyyEAAQAAyyEAAQAAy/H3dAEAcKlNTF3t6RLKbHjLKE+XAFQqXAECAACWQwACAACWQwACAACWQwACAACWQwACAACW49EA1L59ey1YsEB2u13GGHXr1s1pvTGm2Pbss8+WuM/Ro0cXGb9161Z3vxQAAOBFPBqAgoKClJKSoieeeKLY9aGhoU6tX79+On36tD7//PNS97t582an7dq1a+eO8gEAgJfy6OcAJSUlKSkpqcT1GRkZTsvdunXTsmXLlJ6eXup+CwoKimwLAABwhtfMAbr88st15513atasWecd26RJE9ntdu3cuVOzZ89WgwYNSh0fGBgom83m1AAAQOXlNQGob9++ys7O1hdffFHquLVr1yo2NlZdunTR4MGDFRERoZUrV6patWolbhMXF6esrCxHs9vtri4fAABUIF4TgPr376+PPvpIp06dKnVcUlKSPvvsM6WmpmrJkiXq2rWratSooZ49e5a4zfjx4xUcHOxoYWFhri4fAABUIF7xt8DatWunZs2aqVevXmXe9tixY9q+fbsaN25c4pi8vDzl5eVdTIkAAMCLeMUVoEcffVTr16/Xpk2byrxtUFCQGjVqpP3797uhMgAA4I08/hh8ZGSkIiMjJUkRERGKjIx0mrRss9n0wAMPaObMmcXuIzk52ekx+jfffFO33HKLwsPDFRUVpXnz5qmwsFBz5sxx74sBAABew6O3wNq0aaPly5c7lidPnixJSkhIUL9+/SRJDz74oHx8fEoMMI0aNVKdOnUcy1dccYXmzJmj2rVr69ChQ1q1apVuuukmZWZmuu+FAAAAr+IjyXi6iIrGZrMpKytLwcHBys7O9nQ5AFxsYupqT5dQZsNbRnm6BKDCK8vPb6+YAwQAAOBKBCAAAGA5BCAAAGA5XvE5QAAqLm+cTwMAXAECAACWQwACAACWQwACAACWQwACAACWQwACAACWQwACAACWQwACAACWQwACAACWQwACAACWQwACAACWQwACAACWQwACAACWQwACAACWQwACAACWQwACAACWQwACAACWQwACAACWQwACAACW4+/pAgAA5zcxdbWnSyiz4S2jPF0CUCKuAAEAAMshAAEAAMshAAEAAMshAAEAAMshAAEAAMshAAEAAMshAAEAAMshAAEAAMshAAEAAMshAAEAAMshAAEAAMshAAEAAMshAAEAAMshAAEAAMshAAEAAMvxaABq3769FixYILvdLmOMunXr5rQ+Pj5exhintmjRovPud8iQIUpPT1dOTo7WrFmjG264wV0vAQAAeCGPBqCgoCClpKToiSeeKHHMokWLFBoa6mgPPfRQqfvs2bOnJk2apLFjx6p169ZKSUnR4sWLVbduXVeXDwAAvJS/Jw+elJSkpKSkUsecOnVKGRkZF7zPYcOGacaMGUpISJAkDRo0SHfeeaf69++vf//73xdTLgAAqCQq/BygW2+9VRkZGdq2bZveffdd1apVq8SxAQEBuv7665WcnOzoM8YoOTlZUVFRJW4XGBgom83m1AAAQOVVoQNQUlKS+vTpo+joaD3//PPq0KGDFi1aJF/f4suuU6eO/P39i1wxysjIUGhoaInHiYuLU1ZWlqPZ7XaXvg4AAFCxePQW2PnMnTvX8e/Nmzdr06ZN2rVrl2699VYtXbrUZccZP368Jk2a5Fi22WyEIAAAKrEKfQXoXOnp6Tp06JAaN25c7PrMzEwVFBQoJCTEqT8kJEQHDhwocb95eXnKzs52agAAoPLyqgAUFham2rVra//+/cWuz8/P14YNGxQdHe3o8/HxUXR0tFavXn2pygQAABWcxx+Dj4yMVGRkpCQpIiJCkZGRatCggYKCgvTGG2/o73//u8LDw3X77bfryy+/VFpamhYvXuzYR3JystNj9JMmTdKAAQPUp08fNWvWTO+9956CgoIUHx9/yV8fAAComDw6B6hNmzZavny5Y3ny5MmSpISEBA0ePFjXXnut+vbtqxo1amjfvn1asmSJRo0apby8PMc2jRo1Up06dRzLn3zyierWrauXX35ZoaGh2rhxo7p06aKDBw9estcFAAAqNh9JxtNFVDQ2m01ZWVkKDg5mPhBwHhNTub2M4g1vWfLHjwDuUJaf3141BwgAAMAVCEAAAMByCEAAAMByCEAAAMByCEAAAMByCEAAAMByCEAAAMByCEAAAMByCEAAAMByCEAAAMBy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V7VgwQKlpqaqT58+ql+/vrp3717iPocNG6YZM2YoISFBW7du1aBBg3Ty5En179//ousFAACVQ7kC0MSJE/XUU0+5uhYnERERqlevnpKTkx19WVlZWrt2raKioordJiAgQNdff73TNsYYJScnl7iNJAUGBspmszk1AABQeZXrFli7du102223KSYmRlu2bFF+fr7T+vvvv/+iCwsNDZUkZWRkOPVnZGQ41p2rTp068vf3L3abZs2alXisuLg4jRkz5uIKBgAAXqNcAejo0aPFztnxVuPHj9ekSZMcyzabTXa73YMVAQAAdypXALoU82kOHDggSQoJCXH8+8zyxo0bi90mMzNTBQUFCgkJceo/dx/nysvLU15e3sUXDQAAvEK55gBJkp+fn6KjozVw4EBVq1ZNklSvXj0FBQW5pLD09HTt37/f6TOFbDab/v73v2v16tXFbpOfn68NGzY4bePj46Po6OgStwEAANZTritADRs2VFJSkho2bKgqVaro22+/1fHjx/X888+rSpUqGjx48AXtJygoyOlzfSIiIhQZGanDhw9r7969euutt/Tiiy9qx44djsfg9+3b5/TUWHJysubNm6dp06ZJkiZNmqTExEStX79e69at09NPP62goCDFx8eX56UCAIBKqFwBaMqUKVq/fr0iIyP1559/OvrnzZunGTNmXPB+2rRpo+XLlzuWJ0+eLElKSEhQv3799MYbbygoKEj/+c9/VKNGDa1atUpdunRx+gygRo0aqU6dOo7lTz75RHXr1tXLL7+s0NBQbdy4UV26dNHBgwfL81IBAEAl5CPJlHWjzMxM3Xzzzdq+fbuysrIUGRmp9PR0hYeH69dff3XZbTBPsdlsysrKUnBwsLKzsz1dDixkYiq3agFPGt6y5I9MQcVXlp/f5ZoD5OvrKz8/vyL9V1xxBYEBAABUeOUKQEuWLNHTTz/tWDbGKCgoSGPHjtXChQtdVRsAAIBblGsO0PDhw7V48WJt2bJFVatW1f/+9z81adJEmZmZeuihh1xdIwAAgEuVKwDZ7XZFRkbqwQcf1LXXXqtq1app1qxZ+uijj5Sbm+vqGgEAAFyqXAFIkgoLC/XRRx/po48+cmU9AAAAbleuAPSPf/yj1PX//e9/y1UMAADApVDuzwE6W0BAgC677DLl5eXp5MmTBCAAAFChlespsFq1ajk1m82m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717icQIDA1WlShXHss1mc/qvqwX6+rllvwAAeAN3/Xwty34rdACqU6eO/P39lZGR4dSfkZGhZs2aFbtNaGhoseNDQ0NLPE5cXJzGjBlTpN9ut5e9aAAAUKons7Lcun+bzebdV4AulfHjxxe5alSrVi0dPnzYQxV5B5vNJrvdrrCwMLfcKkTxOO+XHufcMzjvl15lOOc2m0379u0777gKHYAyMzNVUFCgkJAQp/6QkBAdOHCg2G0OHDhQpvGSlJeXp7y8PKc+b/3Ce0J2djbnywM475ce59wzOO+Xnjef8wutu0I/BZafn68NGzYoOjra0efj46Po6GitXl38ROLVq1c7jZekTp06lTgeAABYk6nIrWfPniYnJ8f06dPHNGvWzLz//vvm8OHD5vLLLzeSTGJiohk3bpxjfFRUlMnLyzPDhg0zTZs2NaNHjzanTp0yzZs39/hrqWzNZrMZY4yx2Wwer8VKjfPOObdK47xzzt3cPF7AedsTTzxhdu/ebXJzc82aNWvMjTfe6Fi3bNkyEx8f7zS+R48eZtu2bSY3N9ekpqaamJgYj7+GytgCAwPN6NGjTWBgoMdrsVLjvHPOrdI475xzd7YK/zlAAAAArlah5wABAAC4AwEIAABYDgEIAABYDgEIAABYDgEIAABYDgEILhEeHq6ZM2dq165dOnnypNLS0jRmzBgFBAR4urRKbeTIkfrhhx904sQJHTlyxNPlVFpDhgxRenq6cnJytGbNGt1www2eLqlSa9++vRYsWCC73S5jjLp16+bpkiq9F154QevWrVNWVpYyMjI0b948XX311Z4uy60IQHCJZs2aydfXV48//riaN2+uZ555RoMGDdK4ceM8XVqlFhgYqE8//VTvvfeep0uptHr27KlJkyZp7Nixat26tVJSUrR48WLVrVvX06VVWkFBQUpJSdETTzzh6VIso0OHDpo2bZpuuukmderUSQEBAVqyZIkuu+wyT5fmVh7/MCJa5WzPPvus2blzp8frsELr27evOXLkiMfrqIxtzZo1ZurUqY5lHx8f88cff5jnn3/e47VZoRljTLdu3Txeh9VanTp1jDHGtG/f3uO1uKtxBQhuU716dR0+fNjTZQDlFhAQoOuvv17JycmOPmOMkpOTFRUV5cHKAPeqXr26JFXq/4cTgOAWjRo10tChQzV9+nRPlwKUW506deTv76+MjAyn/oyMDIWGhnqoKsC9fHx89NZbb2nVqlXasmWLp8txGwIQSjV+/HgZY0ptTZs2ddqmfv36SkpK0qeffqqZM2d6qHLvVZ5zDgCuMm3aNLVo0UIPPvigp0txK39PF4CKbeLEiUpISCh1zK5duxz/rlevnpYtW6Yff/xRAwcOdHN1lVNZzzncJzMzUwUFBQoJCXHqDwkJ0YEDBzxUFeA+U6dO1V133aVbbrlFdrvd0+W4FQEIpcrMzFRmZuYFja1fv76WLVumDRs2qF+/fjLGuLm6yqks5xzulZ+frw0bNig6OlpffvmlpL9uD0RHR+udd97xcHWAa02dOlX33nuvbr31Vu3evdvT5bgdAQguUb9+fS1fvlx79uzRs88+6/SI8LnzJ+A6DRo0UK1atdSwYUP5+fkpMjJSkpSWlqYTJ054uLrKYdKkSUpMTNT69eu1bt06Pf300woKClJ8fLynS6u0goKC1LhxY8dyRESEIiMjdfjwYe3du9eDlVVe06ZN08MPP6xu3bopOzvbcdXz2LFjys3N9XB17uPxR9Fo3t/69u1rSuLp2ipzi4+PL/acd+jQweO1Vab2xBNPmN27d5vc3FyzZs0ac+ONN3q8psrcOnToUOz7Oj4+3uO1VdZWkr59+3q8Nnc1n//3DwAAAMvgKTAAAGA5BCAAAGA5BCAAAGA5BCAAAGA5BCAAAGA5BCAAAGA5BCAAAGA5BCAAAGA5BCAAAGA5BCAAAGA5BCAAAGA5/xdkG2K4b6jvCwAAAABJRU5ErkJggg==",
22
+ "text/plain": [
23
+ "<Figure size 640x480 with 1 Axes>"
24
+ ]
25
+ },
26
+ "metadata": {},
27
+ "output_type": "display_data"
28
+ }
29
+ ],
30
+ "source": [
31
+ "np.random.seed(0)\n",
32
+ "\n",
33
+ "values = np.random.randn(100) # array of normally distributed random numbers\n",
34
+ "s = pd.Series(values) # generate a pandas series\n",
35
+ "s.plot(kind='hist', title='Normally distributed random values') # hist computes distribution\n",
36
+ "plt.show() "
37
+ ]
38
+ },
39
+ {
40
+ "cell_type": "code",
41
+ "execution_count": null,
42
+ "metadata": {},
43
+ "outputs": [],
44
+ "source": []
45
+ }
46
+ ],
47
+ "metadata": {
48
+ "kernelspec": {
49
+ "display_name": "llmops-course",
50
+ "language": "python",
51
+ "name": "python3"
52
+ },
53
+ "language_info": {
54
+ "codemirror_mode": {
55
+ "name": "ipython",
56
+ "version": 3
57
+ },
58
+ "file_extension": ".py",
59
+ "mimetype": "text/x-python",
60
+ "name": "python",
61
+ "nbconvert_exporter": "python",
62
+ "pygments_lexer": "ipython3",
63
+ "version": "3.11.8"
64
+ }
65
+ },
66
+ "nbformat": 4,
67
+ "nbformat_minor": 2
68
+ }
app/hello_world.py ADDED
@@ -0,0 +1 @@
 
 
1
+ print("hello world! let's do some ml ops!")