Spaces:
Runtime error
Runtime error
Eric Michael Martinez
commited on
Commit
•
a05d6e8
1
Parent(s):
c22fd38
update
Browse files- 02_prototyping_a_basic_chatbot_ui.ipynb +36 -9
- 03_using_the_openai_api.ipynb +244 -76
- 04_creating_a_functional_conversational_chatbot.ipynb +1 -9
- 05_deploying_a_chatbot_to_the_web.ipynb +472 -45
- 06_designing_effective_prompts.ipynb +334 -47
- 07_software_engineering_applied_to_llms.ipynb +402 -93
- images/access-tokens.png +0 -0
- images/add-secret.png +0 -0
- images/copy-token.png +0 -0
- images/dropdown.png +0 -0
- images/new-access-token.png +0 -0
- images/profile-settings.png +0 -0
- images/repo.png +0 -0
- images/restart.png +0 -0
- images/secrets.png +0 -0
- images/signup.png +0 -0
- images/space-settings.png +0 -0
02_prototyping_a_basic_chatbot_ui.ipynb
CHANGED
@@ -87,14 +87,37 @@
|
|
87 |
},
|
88 |
{
|
89 |
"cell_type": "code",
|
90 |
-
"execution_count":
|
91 |
"id": "0b28a4e7",
|
92 |
"metadata": {
|
93 |
"slideshow": {
|
94 |
"slide_type": "fragment"
|
95 |
}
|
96 |
},
|
97 |
-
"outputs": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
"source": [
|
99 |
"import gradio as gr\n",
|
100 |
" \n",
|
@@ -102,11 +125,11 @@
|
|
102 |
" return f\"{first_name} {last_name} is so cool\"\n",
|
103 |
" \n",
|
104 |
"with gr.Blocks() as app:\n",
|
105 |
-
"
|
106 |
-
"
|
107 |
-
"
|
108 |
-
"
|
109 |
-
"
|
110 |
" app.launch(share=True)\n"
|
111 |
]
|
112 |
},
|
@@ -227,14 +250,18 @@
|
|
227 |
{
|
228 |
"cell_type": "markdown",
|
229 |
"id": "3b660170",
|
230 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
231 |
"source": [
|
232 |
"Sweet! That wasn't too bad, not much code to make a cool little UI!"
|
233 |
]
|
234 |
}
|
235 |
],
|
236 |
"metadata": {
|
237 |
-
"celltoolbar": "
|
238 |
"kernelspec": {
|
239 |
"display_name": "Python 3 (ipykernel)",
|
240 |
"language": "python",
|
|
|
87 |
},
|
88 |
{
|
89 |
"cell_type": "code",
|
90 |
+
"execution_count": 3,
|
91 |
"id": "0b28a4e7",
|
92 |
"metadata": {
|
93 |
"slideshow": {
|
94 |
"slide_type": "fragment"
|
95 |
}
|
96 |
},
|
97 |
+
"outputs": [
|
98 |
+
{
|
99 |
+
"name": "stdout",
|
100 |
+
"output_type": "stream",
|
101 |
+
"text": [
|
102 |
+
"Running on local URL: http://127.0.0.1:7882\n",
|
103 |
+
"Running on public URL: https://d807b00726b10425a4.gradio.live\n",
|
104 |
+
"\n",
|
105 |
+
"This share link expires in 72 hours. For free permanent hosting and GPU upgrades (NEW!), check out Spaces: https://huggingface.co/spaces\n"
|
106 |
+
]
|
107 |
+
},
|
108 |
+
{
|
109 |
+
"data": {
|
110 |
+
"text/html": [
|
111 |
+
"<div><iframe src=\"https://d807b00726b10425a4.gradio.live\" width=\"100%\" height=\"500\" allow=\"autoplay; camera; microphone; clipboard-read; clipboard-write;\" frameborder=\"0\" allowfullscreen></iframe></div>"
|
112 |
+
],
|
113 |
+
"text/plain": [
|
114 |
+
"<IPython.core.display.HTML object>"
|
115 |
+
]
|
116 |
+
},
|
117 |
+
"metadata": {},
|
118 |
+
"output_type": "display_data"
|
119 |
+
}
|
120 |
+
],
|
121 |
"source": [
|
122 |
"import gradio as gr\n",
|
123 |
" \n",
|
|
|
125 |
" return f\"{first_name} {last_name} is so cool\"\n",
|
126 |
" \n",
|
127 |
"with gr.Blocks() as app:\n",
|
128 |
+
" first_name_box = gr.Textbox(label=\"First Name\")\n",
|
129 |
+
" last_name_box = gr.Textbox(label=\"Last Name\")\n",
|
130 |
+
" output_box = gr.Textbox(label=\"Output\", interactive=False)\n",
|
131 |
+
" btn = gr.Button(value =\"Send\")\n",
|
132 |
+
" btn.click(do_something_cool, inputs = [first_name_box, last_name_box], outputs = [output_box])\n",
|
133 |
" app.launch(share=True)\n"
|
134 |
]
|
135 |
},
|
|
|
250 |
{
|
251 |
"cell_type": "markdown",
|
252 |
"id": "3b660170",
|
253 |
+
"metadata": {
|
254 |
+
"slideshow": {
|
255 |
+
"slide_type": "slide"
|
256 |
+
}
|
257 |
+
},
|
258 |
"source": [
|
259 |
"Sweet! That wasn't too bad, not much code to make a cool little UI!"
|
260 |
]
|
261 |
}
|
262 |
],
|
263 |
"metadata": {
|
264 |
+
"celltoolbar": "Slideshow",
|
265 |
"kernelspec": {
|
266 |
"display_name": "Python 3 (ipykernel)",
|
267 |
"language": "python",
|
03_using_the_openai_api.ipynb
CHANGED
@@ -44,32 +44,56 @@
|
|
44 |
}
|
45 |
},
|
46 |
"source": [
|
47 |
-
"## Managing Application Secrets"
|
|
|
|
|
|
|
|
|
48 |
]
|
49 |
},
|
50 |
{
|
51 |
"cell_type": "markdown",
|
52 |
-
"id": "
|
53 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
54 |
"source": [
|
55 |
-
"
|
56 |
-
"\n",
|
57 |
-
"In software development, secrets are often used to authenticate users, grant access to resources, or encrypt/decrypt data. Mismanaging or exposing secrets can lead to severe security breaches and data leaks.\n",
|
58 |
-
"\n",
|
59 |
-
"Common examples of secrets\n",
|
60 |
"* API keys\n",
|
61 |
"* Database credentials\n",
|
62 |
"* SSH keys\n",
|
63 |
"* OAuth access tokens\n",
|
64 |
-
"* Encryption/decryption keys
|
65 |
-
|
66 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
"* Storing secrets in plain text\n",
|
68 |
"* Hardcoding secrets in source code\n",
|
69 |
"* Sharing secrets through unsecured channels (e.g., email or messaging apps)\n",
|
70 |
"* Using the same secret for multiple purposes\n",
|
71 |
-
"* Not rotating or updating secrets regularly
|
72 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
"How attackers might obtain secrets\n",
|
74 |
"* Exploiting vulnerabilities in software or infrastructure\n",
|
75 |
"* Intercepting unencrypted communications\n",
|
@@ -91,7 +115,7 @@
|
|
91 |
"* Limit access to secrets on a need-to-know basis\n",
|
92 |
"* Implement proper auditing and monitoring of secret usage\n",
|
93 |
"\n",
|
94 |
-
"
|
95 |
"* Many cloud providers offer secret management services (e.g., AWS Secrets Manager, Azure Key Vault, Google Cloud Secret Manager) that securely store, manage, and rotate secrets.\n",
|
96 |
"* These services often provide access control, encryption, and auditing capabilities.\n",
|
97 |
"* Integrating cloud secret management services with your application can help secure sensitive information and reduce the risk of exposure.\n",
|
@@ -106,7 +130,11 @@
|
|
106 |
{
|
107 |
"cell_type": "markdown",
|
108 |
"id": "ef366b65",
|
109 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
110 |
"source": [
|
111 |
"#### Using `.dotenv` library to protect secrets in Python"
|
112 |
]
|
@@ -114,27 +142,23 @@
|
|
114 |
{
|
115 |
"cell_type": "markdown",
|
116 |
"id": "dc39df10",
|
117 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
118 |
"source": [
|
119 |
" `.dotenv` is a Python library that allows developers to load environment variables from a `.env` file. It helps keep secrets out of source code and makes it easier to manage and update them."
|
120 |
]
|
121 |
},
|
122 |
-
{
|
123 |
-
"cell_type": "code",
|
124 |
-
"execution_count": null,
|
125 |
-
"id": "88252d32",
|
126 |
-
"metadata": {},
|
127 |
-
"outputs": [],
|
128 |
-
"source": [
|
129 |
-
" 3. Add secrets as key-value pairs in the `.env` file\n",
|
130 |
-
" 4. Load secrets in your Python code using the `load_dotenv()` function\n",
|
131 |
-
" 5. Access secrets using `os.environ`"
|
132 |
-
]
|
133 |
-
},
|
134 |
{
|
135 |
"cell_type": "markdown",
|
136 |
"id": "ae0500ea",
|
137 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
138 |
"source": [
|
139 |
"Install the `python-dotenv` library"
|
140 |
]
|
@@ -143,7 +167,11 @@
|
|
143 |
"cell_type": "code",
|
144 |
"execution_count": 45,
|
145 |
"id": "1212333f",
|
146 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
147 |
"outputs": [],
|
148 |
"source": [
|
149 |
"!pip -q install --upgrade python-dotenv"
|
@@ -152,7 +180,11 @@
|
|
152 |
{
|
153 |
"cell_type": "markdown",
|
154 |
"id": "faecedf0",
|
155 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
156 |
"source": [
|
157 |
"Create a `.env` file in this folder using any editor."
|
158 |
]
|
@@ -160,7 +192,11 @@
|
|
160 |
{
|
161 |
"cell_type": "markdown",
|
162 |
"id": "a880382a",
|
163 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
164 |
"source": [
|
165 |
"Add secrets as key-value pairs in the `.env` file"
|
166 |
]
|
@@ -168,15 +204,25 @@
|
|
168 |
{
|
169 |
"cell_type": "markdown",
|
170 |
"id": "04f00703",
|
171 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
172 |
"source": [
|
173 |
"If you are using my OpenAI service use the following format:"
|
174 |
]
|
175 |
},
|
176 |
{
|
177 |
-
"cell_type": "
|
178 |
-
"
|
179 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
180 |
"source": [
|
181 |
"OPENAI_API_BASE=<my API base>\n",
|
182 |
"OPENAI_API_KEY=<your API key to my service>"
|
@@ -185,7 +231,11 @@
|
|
185 |
{
|
186 |
"cell_type": "markdown",
|
187 |
"id": "a952b103",
|
188 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
189 |
"source": [
|
190 |
"If you are not using my OpenAI service then use the following format:"
|
191 |
]
|
@@ -194,7 +244,11 @@
|
|
194 |
"cell_type": "code",
|
195 |
"execution_count": null,
|
196 |
"id": "7cf6ed7b",
|
197 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
198 |
"outputs": [],
|
199 |
"source": [
|
200 |
"OPENAI_API_KEY=<your OpenAI API key>"
|
@@ -203,7 +257,11 @@
|
|
203 |
{
|
204 |
"cell_type": "markdown",
|
205 |
"id": "955963ed",
|
206 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
207 |
"source": [
|
208 |
"Then, use the following code to load those secrets into this notebook:"
|
209 |
]
|
@@ -212,7 +270,11 @@
|
|
212 |
"cell_type": "code",
|
213 |
"execution_count": 47,
|
214 |
"id": "fcadf45e",
|
215 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
216 |
"outputs": [
|
217 |
{
|
218 |
"data": {
|
@@ -234,7 +296,11 @@
|
|
234 |
{
|
235 |
"cell_type": "markdown",
|
236 |
"id": "d3b6c394",
|
237 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
238 |
"source": [
|
239 |
"#### Install Dependencies"
|
240 |
]
|
@@ -256,7 +322,11 @@
|
|
256 |
{
|
257 |
"cell_type": "markdown",
|
258 |
"id": "f2ed966d",
|
259 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
260 |
"source": [
|
261 |
"#### Let's make a function to wrap OpenAI functionality and write some basic tests"
|
262 |
]
|
@@ -264,7 +334,11 @@
|
|
264 |
{
|
265 |
"cell_type": "markdown",
|
266 |
"id": "c1b09026",
|
267 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
268 |
"source": [
|
269 |
"Start by simply seeing if we can make an API call"
|
270 |
]
|
@@ -273,7 +347,11 @@
|
|
273 |
"cell_type": "code",
|
274 |
"execution_count": 2,
|
275 |
"id": "0abdd4e9",
|
276 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
277 |
"outputs": [
|
278 |
{
|
279 |
"name": "stdout",
|
@@ -300,7 +378,11 @@
|
|
300 |
{
|
301 |
"cell_type": "markdown",
|
302 |
"id": "3f5d1530",
|
303 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
304 |
"source": [
|
305 |
"Great! Now let's wrap that in a function"
|
306 |
]
|
@@ -340,7 +422,11 @@
|
|
340 |
{
|
341 |
"cell_type": "markdown",
|
342 |
"id": "f4506fe8",
|
343 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
344 |
"source": [
|
345 |
"Let's add some tests!\n",
|
346 |
"\n",
|
@@ -381,7 +467,11 @@
|
|
381 |
{
|
382 |
"cell_type": "markdown",
|
383 |
"id": "ed166c5b",
|
384 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
385 |
"source": [
|
386 |
"But what if we do what to test the output of the LLM?\n",
|
387 |
"\n",
|
@@ -402,7 +492,11 @@
|
|
402 |
"cell_type": "code",
|
403 |
"execution_count": 31,
|
404 |
"id": "9c03b774",
|
405 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
406 |
"outputs": [],
|
407 |
"source": [
|
408 |
"import openai\n",
|
@@ -421,11 +515,29 @@
|
|
421 |
"assert isinstance(get_ai_reply(\"hello\", model=\"gpt-3.5-turbo\"), str)"
|
422 |
]
|
423 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
424 |
{
|
425 |
"cell_type": "code",
|
426 |
"execution_count": 33,
|
427 |
"id": "f5ed24da",
|
428 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
429 |
"outputs": [
|
430 |
{
|
431 |
"name": "stdout",
|
@@ -444,7 +556,11 @@
|
|
444 |
{
|
445 |
"cell_type": "markdown",
|
446 |
"id": "ee320648",
|
447 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
448 |
"source": [
|
449 |
"Ok great! Now, an LLM is no good to us if we can't _steer_ it.\n",
|
450 |
"\n",
|
@@ -455,7 +571,11 @@
|
|
455 |
"cell_type": "code",
|
456 |
"execution_count": 37,
|
457 |
"id": "295839a5",
|
458 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
459 |
"outputs": [],
|
460 |
"source": [
|
461 |
"import openai\n",
|
@@ -493,7 +613,11 @@
|
|
493 |
{
|
494 |
"cell_type": "markdown",
|
495 |
"id": "fc9763d6",
|
496 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
497 |
"source": [
|
498 |
"Let's see if we can get the LLM to follow instructions by adding instructions to the prompt.\n",
|
499 |
"\n",
|
@@ -504,7 +628,11 @@
|
|
504 |
"cell_type": "code",
|
505 |
"execution_count": 36,
|
506 |
"id": "c5e2a8b3",
|
507 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
508 |
"outputs": [
|
509 |
{
|
510 |
"name": "stdout",
|
@@ -521,32 +649,32 @@
|
|
521 |
{
|
522 |
"cell_type": "markdown",
|
523 |
"id": "e59d3275",
|
524 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
525 |
"source": [
|
526 |
"While the output is more or less controlled, the LLM responds with 'world.' or 'world'. While the word 'world' being in the string is pretty consistent, the punctuation is not.\n",
|
527 |
"\n",
|
528 |
-
"
|
529 |
-
"\n",
|
530 |
-
"For now let's assume this is the best we can do.\n",
|
531 |
-
"\n",
|
532 |
-
"How do we write tests against this?\n",
|
533 |
-
"\n",
|
534 |
-
"Well, what do have high confidence won't change in the LLM output?\n",
|
535 |
"\n",
|
536 |
"What is a test that we could write that:\n",
|
537 |
"* would pass if the LLM outputs in a manner that is consistent with our expectations (and consistent with its own output)?\n",
|
538 |
"* _we want to be true_ about our LLM system, and if it does not then we would want to know immediately and adjust our system?\n",
|
539 |
"* if the prompt does not change, that our expectation holds true?\n",
|
540 |
-
"* someone changes the prompt in a way that would break the rest of the system, that we would want to prevent that from being merged without fixing the downstream effects
|
541 |
-
"\n",
|
542 |
-
"That might be a bunch of ways of saying the same thing but I hope you get the point."
|
543 |
]
|
544 |
},
|
545 |
{
|
546 |
"cell_type": "code",
|
547 |
"execution_count": 38,
|
548 |
"id": "d2b2bc15",
|
549 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
550 |
"outputs": [],
|
551 |
"source": [
|
552 |
"# non-deterministic tests\n",
|
@@ -559,7 +687,11 @@
|
|
559 |
{
|
560 |
"cell_type": "markdown",
|
561 |
"id": "5e17eefe",
|
562 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
563 |
"source": [
|
564 |
"Alright that worked!\n",
|
565 |
"\n",
|
@@ -570,7 +702,11 @@
|
|
570 |
"cell_type": "code",
|
571 |
"execution_count": 39,
|
572 |
"id": "4fd88c05",
|
573 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
574 |
"outputs": [],
|
575 |
"source": [
|
576 |
"import openai\n",
|
@@ -615,7 +751,11 @@
|
|
615 |
{
|
616 |
"cell_type": "markdown",
|
617 |
"id": "e0a00cda",
|
618 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
619 |
"source": [
|
620 |
"Now let's check that it works"
|
621 |
]
|
@@ -624,7 +764,11 @@
|
|
624 |
"cell_type": "code",
|
625 |
"execution_count": 42,
|
626 |
"id": "977f99bd",
|
627 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
628 |
"outputs": [
|
629 |
{
|
630 |
"name": "stdout",
|
@@ -647,7 +791,11 @@
|
|
647 |
{
|
648 |
"cell_type": "markdown",
|
649 |
"id": "2ad45888",
|
650 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
651 |
"source": [
|
652 |
"Great! Now let's turn that into a test!"
|
653 |
]
|
@@ -656,7 +804,11 @@
|
|
656 |
"cell_type": "code",
|
657 |
"execution_count": 43,
|
658 |
"id": "83aa7546",
|
659 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
660 |
"outputs": [],
|
661 |
"source": [
|
662 |
"system_message=\"The user will tell you their name. When asked, repeat their name back to them.\"\n",
|
@@ -672,7 +824,11 @@
|
|
672 |
{
|
673 |
"cell_type": "markdown",
|
674 |
"id": "25e498c8",
|
675 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
676 |
"source": [
|
677 |
"Alright here is our final function for integrating with OpenAI!"
|
678 |
]
|
@@ -681,7 +837,11 @@
|
|
681 |
"cell_type": "code",
|
682 |
"execution_count": null,
|
683 |
"id": "bfc5cd86",
|
684 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
685 |
"outputs": [],
|
686 |
"source": [
|
687 |
"import openai\n",
|
@@ -736,7 +896,11 @@
|
|
736 |
"cell_type": "code",
|
737 |
"execution_count": 44,
|
738 |
"id": "159eea8a",
|
739 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
740 |
"outputs": [
|
741 |
{
|
742 |
"name": "stdout",
|
@@ -753,14 +917,18 @@
|
|
753 |
{
|
754 |
"cell_type": "markdown",
|
755 |
"id": "9de8f5da",
|
756 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
757 |
"source": [
|
758 |
"In the next few lessons, we will be building a graphical user interface around this functionality so we can have a real conversational experience."
|
759 |
]
|
760 |
}
|
761 |
],
|
762 |
"metadata": {
|
763 |
-
"celltoolbar": "
|
764 |
"kernelspec": {
|
765 |
"display_name": "Python 3 (ipykernel)",
|
766 |
"language": "python",
|
|
|
44 |
}
|
45 |
},
|
46 |
"source": [
|
47 |
+
"## Managing Application Secrets\n",
|
48 |
+
"\n",
|
49 |
+
"Secrets are sensitive information, such as API keys, passwords, or cryptographic keys, that must be protected to ensure the security and integrity of a system.\n",
|
50 |
+
"\n",
|
51 |
+
"In software development, secrets are often used to authenticate users, grant access to resources, or encrypt/decrypt data. Mismanaging or exposing secrets can lead to severe security breaches and data leaks."
|
52 |
]
|
53 |
},
|
54 |
{
|
55 |
"cell_type": "markdown",
|
56 |
+
"id": "2059552f",
|
57 |
+
"metadata": {
|
58 |
+
"slideshow": {
|
59 |
+
"slide_type": "slide"
|
60 |
+
}
|
61 |
+
},
|
62 |
"source": [
|
63 |
+
"#### Common examples of secrets\n",
|
|
|
|
|
|
|
|
|
64 |
"* API keys\n",
|
65 |
"* Database credentials\n",
|
66 |
"* SSH keys\n",
|
67 |
"* OAuth access tokens\n",
|
68 |
+
"* Encryption/decryption keys"
|
69 |
+
]
|
70 |
+
},
|
71 |
+
{
|
72 |
+
"cell_type": "markdown",
|
73 |
+
"id": "a1e650f8",
|
74 |
+
"metadata": {
|
75 |
+
"slideshow": {
|
76 |
+
"slide_type": "slide"
|
77 |
+
}
|
78 |
+
},
|
79 |
+
"source": [
|
80 |
+
"#### Common mistakes when handling secrets\n",
|
81 |
"* Storing secrets in plain text\n",
|
82 |
"* Hardcoding secrets in source code\n",
|
83 |
"* Sharing secrets through unsecured channels (e.g., email or messaging apps)\n",
|
84 |
"* Using the same secret for multiple purposes\n",
|
85 |
+
"* Not rotating or updating secrets regularly"
|
86 |
+
]
|
87 |
+
},
|
88 |
+
{
|
89 |
+
"cell_type": "markdown",
|
90 |
+
"id": "66de4ac1",
|
91 |
+
"metadata": {
|
92 |
+
"slideshow": {
|
93 |
+
"slide_type": "skip"
|
94 |
+
}
|
95 |
+
},
|
96 |
+
"source": [
|
97 |
"How attackers might obtain secrets\n",
|
98 |
"* Exploiting vulnerabilities in software or infrastructure\n",
|
99 |
"* Intercepting unencrypted communications\n",
|
|
|
115 |
"* Limit access to secrets on a need-to-know basis\n",
|
116 |
"* Implement proper auditing and monitoring of secret usage\n",
|
117 |
"\n",
|
118 |
+
"Cloud services and secret management\n",
|
119 |
"* Many cloud providers offer secret management services (e.g., AWS Secrets Manager, Azure Key Vault, Google Cloud Secret Manager) that securely store, manage, and rotate secrets.\n",
|
120 |
"* These services often provide access control, encryption, and auditing capabilities.\n",
|
121 |
"* Integrating cloud secret management services with your application can help secure sensitive information and reduce the risk of exposure.\n",
|
|
|
130 |
{
|
131 |
"cell_type": "markdown",
|
132 |
"id": "ef366b65",
|
133 |
+
"metadata": {
|
134 |
+
"slideshow": {
|
135 |
+
"slide_type": "slide"
|
136 |
+
}
|
137 |
+
},
|
138 |
"source": [
|
139 |
"#### Using `.dotenv` library to protect secrets in Python"
|
140 |
]
|
|
|
142 |
{
|
143 |
"cell_type": "markdown",
|
144 |
"id": "dc39df10",
|
145 |
+
"metadata": {
|
146 |
+
"slideshow": {
|
147 |
+
"slide_type": "fragment"
|
148 |
+
}
|
149 |
+
},
|
150 |
"source": [
|
151 |
" `.dotenv` is a Python library that allows developers to load environment variables from a `.env` file. It helps keep secrets out of source code and makes it easier to manage and update them."
|
152 |
]
|
153 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
154 |
{
|
155 |
"cell_type": "markdown",
|
156 |
"id": "ae0500ea",
|
157 |
+
"metadata": {
|
158 |
+
"slideshow": {
|
159 |
+
"slide_type": "slide"
|
160 |
+
}
|
161 |
+
},
|
162 |
"source": [
|
163 |
"Install the `python-dotenv` library"
|
164 |
]
|
|
|
167 |
"cell_type": "code",
|
168 |
"execution_count": 45,
|
169 |
"id": "1212333f",
|
170 |
+
"metadata": {
|
171 |
+
"slideshow": {
|
172 |
+
"slide_type": "fragment"
|
173 |
+
}
|
174 |
+
},
|
175 |
"outputs": [],
|
176 |
"source": [
|
177 |
"!pip -q install --upgrade python-dotenv"
|
|
|
180 |
{
|
181 |
"cell_type": "markdown",
|
182 |
"id": "faecedf0",
|
183 |
+
"metadata": {
|
184 |
+
"slideshow": {
|
185 |
+
"slide_type": "slide"
|
186 |
+
}
|
187 |
+
},
|
188 |
"source": [
|
189 |
"Create a `.env` file in this folder using any editor."
|
190 |
]
|
|
|
192 |
{
|
193 |
"cell_type": "markdown",
|
194 |
"id": "a880382a",
|
195 |
+
"metadata": {
|
196 |
+
"slideshow": {
|
197 |
+
"slide_type": "fragment"
|
198 |
+
}
|
199 |
+
},
|
200 |
"source": [
|
201 |
"Add secrets as key-value pairs in the `.env` file"
|
202 |
]
|
|
|
204 |
{
|
205 |
"cell_type": "markdown",
|
206 |
"id": "04f00703",
|
207 |
+
"metadata": {
|
208 |
+
"slideshow": {
|
209 |
+
"slide_type": "slide"
|
210 |
+
}
|
211 |
+
},
|
212 |
"source": [
|
213 |
"If you are using my OpenAI service use the following format:"
|
214 |
]
|
215 |
},
|
216 |
{
|
217 |
+
"cell_type": "code",
|
218 |
+
"execution_count": null,
|
219 |
+
"id": "33c7bf87",
|
220 |
+
"metadata": {
|
221 |
+
"slideshow": {
|
222 |
+
"slide_type": "fragment"
|
223 |
+
}
|
224 |
+
},
|
225 |
+
"outputs": [],
|
226 |
"source": [
|
227 |
"OPENAI_API_BASE=<my API base>\n",
|
228 |
"OPENAI_API_KEY=<your API key to my service>"
|
|
|
231 |
{
|
232 |
"cell_type": "markdown",
|
233 |
"id": "a952b103",
|
234 |
+
"metadata": {
|
235 |
+
"slideshow": {
|
236 |
+
"slide_type": "slide"
|
237 |
+
}
|
238 |
+
},
|
239 |
"source": [
|
240 |
"If you are not using my OpenAI service then use the following format:"
|
241 |
]
|
|
|
244 |
"cell_type": "code",
|
245 |
"execution_count": null,
|
246 |
"id": "7cf6ed7b",
|
247 |
+
"metadata": {
|
248 |
+
"slideshow": {
|
249 |
+
"slide_type": "fragment"
|
250 |
+
}
|
251 |
+
},
|
252 |
"outputs": [],
|
253 |
"source": [
|
254 |
"OPENAI_API_KEY=<your OpenAI API key>"
|
|
|
257 |
{
|
258 |
"cell_type": "markdown",
|
259 |
"id": "955963ed",
|
260 |
+
"metadata": {
|
261 |
+
"slideshow": {
|
262 |
+
"slide_type": "slide"
|
263 |
+
}
|
264 |
+
},
|
265 |
"source": [
|
266 |
"Then, use the following code to load those secrets into this notebook:"
|
267 |
]
|
|
|
270 |
"cell_type": "code",
|
271 |
"execution_count": 47,
|
272 |
"id": "fcadf45e",
|
273 |
+
"metadata": {
|
274 |
+
"slideshow": {
|
275 |
+
"slide_type": "fragment"
|
276 |
+
}
|
277 |
+
},
|
278 |
"outputs": [
|
279 |
{
|
280 |
"data": {
|
|
|
296 |
{
|
297 |
"cell_type": "markdown",
|
298 |
"id": "d3b6c394",
|
299 |
+
"metadata": {
|
300 |
+
"slideshow": {
|
301 |
+
"slide_type": "slide"
|
302 |
+
}
|
303 |
+
},
|
304 |
"source": [
|
305 |
"#### Install Dependencies"
|
306 |
]
|
|
|
322 |
{
|
323 |
"cell_type": "markdown",
|
324 |
"id": "f2ed966d",
|
325 |
+
"metadata": {
|
326 |
+
"slideshow": {
|
327 |
+
"slide_type": "slide"
|
328 |
+
}
|
329 |
+
},
|
330 |
"source": [
|
331 |
"#### Let's make a function to wrap OpenAI functionality and write some basic tests"
|
332 |
]
|
|
|
334 |
{
|
335 |
"cell_type": "markdown",
|
336 |
"id": "c1b09026",
|
337 |
+
"metadata": {
|
338 |
+
"slideshow": {
|
339 |
+
"slide_type": "fragment"
|
340 |
+
}
|
341 |
+
},
|
342 |
"source": [
|
343 |
"Start by simply seeing if we can make an API call"
|
344 |
]
|
|
|
347 |
"cell_type": "code",
|
348 |
"execution_count": 2,
|
349 |
"id": "0abdd4e9",
|
350 |
+
"metadata": {
|
351 |
+
"slideshow": {
|
352 |
+
"slide_type": "fragment"
|
353 |
+
}
|
354 |
+
},
|
355 |
"outputs": [
|
356 |
{
|
357 |
"name": "stdout",
|
|
|
378 |
{
|
379 |
"cell_type": "markdown",
|
380 |
"id": "3f5d1530",
|
381 |
+
"metadata": {
|
382 |
+
"slideshow": {
|
383 |
+
"slide_type": "slide"
|
384 |
+
}
|
385 |
+
},
|
386 |
"source": [
|
387 |
"Great! Now let's wrap that in a function"
|
388 |
]
|
|
|
422 |
{
|
423 |
"cell_type": "markdown",
|
424 |
"id": "f4506fe8",
|
425 |
+
"metadata": {
|
426 |
+
"slideshow": {
|
427 |
+
"slide_type": "slide"
|
428 |
+
}
|
429 |
+
},
|
430 |
"source": [
|
431 |
"Let's add some tests!\n",
|
432 |
"\n",
|
|
|
467 |
{
|
468 |
"cell_type": "markdown",
|
469 |
"id": "ed166c5b",
|
470 |
+
"metadata": {
|
471 |
+
"slideshow": {
|
472 |
+
"slide_type": "slide"
|
473 |
+
}
|
474 |
+
},
|
475 |
"source": [
|
476 |
"But what if we do what to test the output of the LLM?\n",
|
477 |
"\n",
|
|
|
492 |
"cell_type": "code",
|
493 |
"execution_count": 31,
|
494 |
"id": "9c03b774",
|
495 |
+
"metadata": {
|
496 |
+
"slideshow": {
|
497 |
+
"slide_type": "slide"
|
498 |
+
}
|
499 |
+
},
|
500 |
"outputs": [],
|
501 |
"source": [
|
502 |
"import openai\n",
|
|
|
515 |
"assert isinstance(get_ai_reply(\"hello\", model=\"gpt-3.5-turbo\"), str)"
|
516 |
]
|
517 |
},
|
518 |
+
{
|
519 |
+
"cell_type": "code",
|
520 |
+
"execution_count": null,
|
521 |
+
"id": "15e09750",
|
522 |
+
"metadata": {
|
523 |
+
"slideshow": {
|
524 |
+
"slide_type": "slide"
|
525 |
+
}
|
526 |
+
},
|
527 |
+
"outputs": [],
|
528 |
+
"source": [
|
529 |
+
"If we run this enough times we should see that the output for the bottom run is more inconsistent."
|
530 |
+
]
|
531 |
+
},
|
532 |
{
|
533 |
"cell_type": "code",
|
534 |
"execution_count": 33,
|
535 |
"id": "f5ed24da",
|
536 |
+
"metadata": {
|
537 |
+
"slideshow": {
|
538 |
+
"slide_type": "fragment"
|
539 |
+
}
|
540 |
+
},
|
541 |
"outputs": [
|
542 |
{
|
543 |
"name": "stdout",
|
|
|
556 |
{
|
557 |
"cell_type": "markdown",
|
558 |
"id": "ee320648",
|
559 |
+
"metadata": {
|
560 |
+
"slideshow": {
|
561 |
+
"slide_type": "slide"
|
562 |
+
}
|
563 |
+
},
|
564 |
"source": [
|
565 |
"Ok great! Now, an LLM is no good to us if we can't _steer_ it.\n",
|
566 |
"\n",
|
|
|
571 |
"cell_type": "code",
|
572 |
"execution_count": 37,
|
573 |
"id": "295839a5",
|
574 |
+
"metadata": {
|
575 |
+
"slideshow": {
|
576 |
+
"slide_type": "slide"
|
577 |
+
}
|
578 |
+
},
|
579 |
"outputs": [],
|
580 |
"source": [
|
581 |
"import openai\n",
|
|
|
613 |
{
|
614 |
"cell_type": "markdown",
|
615 |
"id": "fc9763d6",
|
616 |
+
"metadata": {
|
617 |
+
"slideshow": {
|
618 |
+
"slide_type": "slide"
|
619 |
+
}
|
620 |
+
},
|
621 |
"source": [
|
622 |
"Let's see if we can get the LLM to follow instructions by adding instructions to the prompt.\n",
|
623 |
"\n",
|
|
|
628 |
"cell_type": "code",
|
629 |
"execution_count": 36,
|
630 |
"id": "c5e2a8b3",
|
631 |
+
"metadata": {
|
632 |
+
"slideshow": {
|
633 |
+
"slide_type": "fragment"
|
634 |
+
}
|
635 |
+
},
|
636 |
"outputs": [
|
637 |
{
|
638 |
"name": "stdout",
|
|
|
649 |
{
|
650 |
"cell_type": "markdown",
|
651 |
"id": "e59d3275",
|
652 |
+
"metadata": {
|
653 |
+
"slideshow": {
|
654 |
+
"slide_type": "slide"
|
655 |
+
}
|
656 |
+
},
|
657 |
"source": [
|
658 |
"While the output is more or less controlled, the LLM responds with 'world.' or 'world'. While the word 'world' being in the string is pretty consistent, the punctuation is not.\n",
|
659 |
"\n",
|
660 |
+
"How do we write tests against this or have confidence with non-determinism?\n",
|
|
|
|
|
|
|
|
|
|
|
|
|
661 |
"\n",
|
662 |
"What is a test that we could write that:\n",
|
663 |
"* would pass if the LLM outputs in a manner that is consistent with our expectations (and consistent with its own output)?\n",
|
664 |
"* _we want to be true_ about our LLM system, and if it does not then we would want to know immediately and adjust our system?\n",
|
665 |
"* if the prompt does not change, that our expectation holds true?\n",
|
666 |
+
"* someone changes the prompt in a way that would break the rest of the system, that we would want to prevent that from being merged without fixing the downstream effects?"
|
|
|
|
|
667 |
]
|
668 |
},
|
669 |
{
|
670 |
"cell_type": "code",
|
671 |
"execution_count": 38,
|
672 |
"id": "d2b2bc15",
|
673 |
+
"metadata": {
|
674 |
+
"slideshow": {
|
675 |
+
"slide_type": "slide"
|
676 |
+
}
|
677 |
+
},
|
678 |
"outputs": [],
|
679 |
"source": [
|
680 |
"# non-deterministic tests\n",
|
|
|
687 |
{
|
688 |
"cell_type": "markdown",
|
689 |
"id": "5e17eefe",
|
690 |
+
"metadata": {
|
691 |
+
"slideshow": {
|
692 |
+
"slide_type": "slide"
|
693 |
+
}
|
694 |
+
},
|
695 |
"source": [
|
696 |
"Alright that worked!\n",
|
697 |
"\n",
|
|
|
702 |
"cell_type": "code",
|
703 |
"execution_count": 39,
|
704 |
"id": "4fd88c05",
|
705 |
+
"metadata": {
|
706 |
+
"slideshow": {
|
707 |
+
"slide_type": "slide"
|
708 |
+
}
|
709 |
+
},
|
710 |
"outputs": [],
|
711 |
"source": [
|
712 |
"import openai\n",
|
|
|
751 |
{
|
752 |
"cell_type": "markdown",
|
753 |
"id": "e0a00cda",
|
754 |
+
"metadata": {
|
755 |
+
"slideshow": {
|
756 |
+
"slide_type": "slide"
|
757 |
+
}
|
758 |
+
},
|
759 |
"source": [
|
760 |
"Now let's check that it works"
|
761 |
]
|
|
|
764 |
"cell_type": "code",
|
765 |
"execution_count": 42,
|
766 |
"id": "977f99bd",
|
767 |
+
"metadata": {
|
768 |
+
"slideshow": {
|
769 |
+
"slide_type": "fragment"
|
770 |
+
}
|
771 |
+
},
|
772 |
"outputs": [
|
773 |
{
|
774 |
"name": "stdout",
|
|
|
791 |
{
|
792 |
"cell_type": "markdown",
|
793 |
"id": "2ad45888",
|
794 |
+
"metadata": {
|
795 |
+
"slideshow": {
|
796 |
+
"slide_type": "slide"
|
797 |
+
}
|
798 |
+
},
|
799 |
"source": [
|
800 |
"Great! Now let's turn that into a test!"
|
801 |
]
|
|
|
804 |
"cell_type": "code",
|
805 |
"execution_count": 43,
|
806 |
"id": "83aa7546",
|
807 |
+
"metadata": {
|
808 |
+
"slideshow": {
|
809 |
+
"slide_type": "fragment"
|
810 |
+
}
|
811 |
+
},
|
812 |
"outputs": [],
|
813 |
"source": [
|
814 |
"system_message=\"The user will tell you their name. When asked, repeat their name back to them.\"\n",
|
|
|
824 |
{
|
825 |
"cell_type": "markdown",
|
826 |
"id": "25e498c8",
|
827 |
+
"metadata": {
|
828 |
+
"slideshow": {
|
829 |
+
"slide_type": "slide"
|
830 |
+
}
|
831 |
+
},
|
832 |
"source": [
|
833 |
"Alright here is our final function for integrating with OpenAI!"
|
834 |
]
|
|
|
837 |
"cell_type": "code",
|
838 |
"execution_count": null,
|
839 |
"id": "bfc5cd86",
|
840 |
+
"metadata": {
|
841 |
+
"slideshow": {
|
842 |
+
"slide_type": "slide"
|
843 |
+
}
|
844 |
+
},
|
845 |
"outputs": [],
|
846 |
"source": [
|
847 |
"import openai\n",
|
|
|
896 |
"cell_type": "code",
|
897 |
"execution_count": 44,
|
898 |
"id": "159eea8a",
|
899 |
+
"metadata": {
|
900 |
+
"slideshow": {
|
901 |
+
"slide_type": "slide"
|
902 |
+
}
|
903 |
+
},
|
904 |
"outputs": [
|
905 |
{
|
906 |
"name": "stdout",
|
|
|
917 |
{
|
918 |
"cell_type": "markdown",
|
919 |
"id": "9de8f5da",
|
920 |
+
"metadata": {
|
921 |
+
"slideshow": {
|
922 |
+
"slide_type": "fragment"
|
923 |
+
}
|
924 |
+
},
|
925 |
"source": [
|
926 |
"In the next few lessons, we will be building a graphical user interface around this functionality so we can have a real conversational experience."
|
927 |
]
|
928 |
}
|
929 |
],
|
930 |
"metadata": {
|
931 |
+
"celltoolbar": "Slideshow",
|
932 |
"kernelspec": {
|
933 |
"display_name": "Python 3 (ipykernel)",
|
934 |
"language": "python",
|
04_creating_a_functional_conversational_chatbot.ipynb
CHANGED
@@ -345,18 +345,10 @@
|
|
345 |
"# Set the share parameter to False, meaning the interface will not be publicly accessible\n",
|
346 |
"get_chatbot_app().launch()"
|
347 |
]
|
348 |
-
},
|
349 |
-
{
|
350 |
-
"cell_type": "code",
|
351 |
-
"execution_count": null,
|
352 |
-
"id": "ae24e591",
|
353 |
-
"metadata": {},
|
354 |
-
"outputs": [],
|
355 |
-
"source": []
|
356 |
}
|
357 |
],
|
358 |
"metadata": {
|
359 |
-
"celltoolbar": "
|
360 |
"kernelspec": {
|
361 |
"display_name": "Python 3 (ipykernel)",
|
362 |
"language": "python",
|
|
|
345 |
"# Set the share parameter to False, meaning the interface will not be publicly accessible\n",
|
346 |
"get_chatbot_app().launch()"
|
347 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
348 |
}
|
349 |
],
|
350 |
"metadata": {
|
351 |
+
"celltoolbar": "Slideshow",
|
352 |
"kernelspec": {
|
353 |
"display_name": "Python 3 (ipykernel)",
|
354 |
"language": "python",
|
05_deploying_a_chatbot_to_the_web.ipynb
CHANGED
@@ -43,24 +43,36 @@
|
|
43 |
},
|
44 |
{
|
45 |
"cell_type": "markdown",
|
46 |
-
"id": "
|
47 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
48 |
"source": [
|
49 |
-
"
|
50 |
]
|
51 |
},
|
52 |
{
|
53 |
"cell_type": "markdown",
|
54 |
-
"id": "
|
55 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
56 |
"source": [
|
57 |
-
"
|
58 |
]
|
59 |
},
|
60 |
{
|
61 |
"cell_type": "markdown",
|
62 |
"id": "54de0ddc",
|
63 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
64 |
"source": [
|
65 |
"Add a username and password for your app to your `.env` file. This will ensure that unauthorized users are not able to access LLM features. Use the following format:"
|
66 |
]
|
@@ -69,7 +81,11 @@
|
|
69 |
"cell_type": "code",
|
70 |
"execution_count": null,
|
71 |
"id": "95dec7cf",
|
72 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
73 |
"outputs": [],
|
74 |
"source": [
|
75 |
"APP_USERNAME=<whatever username you want>\n",
|
@@ -79,24 +95,48 @@
|
|
79 |
{
|
80 |
"cell_type": "markdown",
|
81 |
"id": "5072dc21",
|
82 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
83 |
"source": [
|
84 |
-
"Let's start by taking all of our necessary chatbot code into one file which we will name `app.py`.
|
85 |
]
|
86 |
},
|
87 |
{
|
88 |
"cell_type": "markdown",
|
89 |
"id": "aacdcaaf",
|
90 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
91 |
"source": [
|
92 |
"Take note that this code has been altered a little bit from the last chatbot example in order to add authentication."
|
93 |
]
|
94 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
{
|
96 |
"cell_type": "code",
|
97 |
-
"execution_count":
|
98 |
"id": "710b66f7",
|
99 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
100 |
"outputs": [
|
101 |
{
|
102 |
"name": "stdout",
|
@@ -242,7 +282,11 @@
|
|
242 |
{
|
243 |
"cell_type": "markdown",
|
244 |
"id": "6d75af66",
|
245 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
246 |
"source": [
|
247 |
"We will also need a `requirements.txt` file to store the list of the packages that HuggingFace needs to install to run our chatbot."
|
248 |
]
|
@@ -251,7 +295,11 @@
|
|
251 |
"cell_type": "code",
|
252 |
"execution_count": 13,
|
253 |
"id": "14d0e434",
|
254 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
255 |
"outputs": [
|
256 |
{
|
257 |
"name": "stdout",
|
@@ -271,7 +319,11 @@
|
|
271 |
{
|
272 |
"cell_type": "markdown",
|
273 |
"id": "4debec45",
|
274 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
275 |
"source": [
|
276 |
"Now let's go ahead and commit our changes"
|
277 |
]
|
@@ -280,7 +332,11 @@
|
|
280 |
"cell_type": "code",
|
281 |
"execution_count": 9,
|
282 |
"id": "14d42a96",
|
283 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
284 |
"outputs": [],
|
285 |
"source": [
|
286 |
"!git add app.py"
|
@@ -290,7 +346,11 @@
|
|
290 |
"cell_type": "code",
|
291 |
"execution_count": 8,
|
292 |
"id": "d7c5b127",
|
293 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
294 |
"outputs": [],
|
295 |
"source": [
|
296 |
"!git add requirements.txt"
|
@@ -300,7 +360,11 @@
|
|
300 |
"cell_type": "code",
|
301 |
"execution_count": 11,
|
302 |
"id": "18960d9f",
|
303 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
304 |
"outputs": [
|
305 |
{
|
306 |
"name": "stdout",
|
@@ -320,7 +384,11 @@
|
|
320 |
{
|
321 |
"cell_type": "markdown",
|
322 |
"id": "09221ee0",
|
323 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
324 |
"source": [
|
325 |
"#### Using HuggingFace Spaces"
|
326 |
]
|
@@ -328,7 +396,11 @@
|
|
328 |
{
|
329 |
"cell_type": "markdown",
|
330 |
"id": "db789c94",
|
331 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
332 |
"source": [
|
333 |
"As mentioned before, HuggingFace is a free-to-use platform for hosting AI demos and apps. We will need to make a HuggingFace _Space_ for our chatbot."
|
334 |
]
|
@@ -336,31 +408,235 @@
|
|
336 |
{
|
337 |
"cell_type": "markdown",
|
338 |
"id": "d9eedd10",
|
339 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
340 |
"source": [
|
341 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
342 |
]
|
343 |
},
|
344 |
{
|
345 |
"cell_type": "markdown",
|
346 |
"id": "3e042d24",
|
347 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
348 |
"source": [
|
349 |
"#### Generate a HuggingFace Access Token"
|
350 |
]
|
351 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
352 |
{
|
353 |
"cell_type": "markdown",
|
354 |
"id": "a7d0781d",
|
355 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
356 |
"source": [
|
357 |
"#### Login to HuggingFace Hub"
|
358 |
]
|
359 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
360 |
{
|
361 |
"cell_type": "markdown",
|
362 |
"id": "eba83252",
|
363 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
364 |
"source": [
|
365 |
"Install `huggingface_hub`"
|
366 |
]
|
@@ -369,7 +645,11 @@
|
|
369 |
"cell_type": "code",
|
370 |
"execution_count": 40,
|
371 |
"id": "266bf481",
|
372 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
373 |
"outputs": [],
|
374 |
"source": [
|
375 |
"!pip -q install --upgrade huggingface_hub"
|
@@ -378,7 +658,11 @@
|
|
378 |
{
|
379 |
"cell_type": "markdown",
|
380 |
"id": "d50cd84b",
|
381 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
382 |
"source": [
|
383 |
"Login to HuggingFace"
|
384 |
]
|
@@ -387,7 +671,11 @@
|
|
387 |
"cell_type": "code",
|
388 |
"execution_count": 6,
|
389 |
"id": "53fd5037",
|
390 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
391 |
"outputs": [
|
392 |
{
|
393 |
"name": "stdout",
|
@@ -408,7 +696,11 @@
|
|
408 |
{
|
409 |
"cell_type": "markdown",
|
410 |
"id": "90f9bd4d",
|
411 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
412 |
"source": [
|
413 |
"#### Now lets setup git and HuggingFace Spaces to work together and deploy"
|
414 |
]
|
@@ -416,7 +708,11 @@
|
|
416 |
{
|
417 |
"cell_type": "markdown",
|
418 |
"id": "66468481",
|
419 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
420 |
"source": [
|
421 |
"<span style=\"color:red\">REPLACE MY URL WITH YOURS</span>"
|
422 |
]
|
@@ -425,7 +721,11 @@
|
|
425 |
"cell_type": "code",
|
426 |
"execution_count": null,
|
427 |
"id": "827a201d",
|
428 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
429 |
"outputs": [],
|
430 |
"source": [
|
431 |
"!git remote add huggingface https://huggingface.co/spaces/ericmichael/gradio-chatbot-demo"
|
@@ -434,7 +734,11 @@
|
|
434 |
{
|
435 |
"cell_type": "markdown",
|
436 |
"id": "f8b3bb3d",
|
437 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
438 |
"source": [
|
439 |
"Then force push to sync everything for the first time."
|
440 |
]
|
@@ -443,7 +747,11 @@
|
|
443 |
"cell_type": "code",
|
444 |
"execution_count": 12,
|
445 |
"id": "86c9ee4e",
|
446 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
447 |
"outputs": [
|
448 |
{
|
449 |
"name": "stdout",
|
@@ -461,39 +769,158 @@
|
|
461 |
},
|
462 |
{
|
463 |
"cell_type": "markdown",
|
464 |
-
"id": "
|
465 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
466 |
"source": [
|
467 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
468 |
]
|
469 |
},
|
470 |
{
|
471 |
"cell_type": "markdown",
|
472 |
-
"id": "
|
473 |
"metadata": {
|
474 |
"slideshow": {
|
475 |
"slide_type": "slide"
|
476 |
}
|
477 |
},
|
478 |
"source": [
|
479 |
-
"
|
480 |
]
|
481 |
},
|
482 |
{
|
483 |
-
"cell_type": "
|
484 |
-
"
|
485 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
486 |
"metadata": {
|
487 |
"slideshow": {
|
488 |
"slide_type": "slide"
|
489 |
}
|
490 |
},
|
491 |
-
"
|
492 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
493 |
}
|
494 |
],
|
495 |
"metadata": {
|
496 |
-
"celltoolbar": "
|
497 |
"kernelspec": {
|
498 |
"display_name": "Python 3 (ipykernel)",
|
499 |
"language": "python",
|
|
|
43 |
},
|
44 |
{
|
45 |
"cell_type": "markdown",
|
46 |
+
"id": "60c8e7f6",
|
47 |
+
"metadata": {
|
48 |
+
"slideshow": {
|
49 |
+
"slide_type": "-"
|
50 |
+
}
|
51 |
+
},
|
52 |
"source": [
|
53 |
+
"Let's face it! Once we start building cool stuff we are going to want to show it off. It can take us < 10 minutes to deploy our chatbots and LLM applications when using Gradio!"
|
54 |
]
|
55 |
},
|
56 |
{
|
57 |
"cell_type": "markdown",
|
58 |
+
"id": "7804a8ce",
|
59 |
+
"metadata": {
|
60 |
+
"slideshow": {
|
61 |
+
"slide_type": "slide"
|
62 |
+
}
|
63 |
+
},
|
64 |
"source": [
|
65 |
+
"#### Configuring the files required"
|
66 |
]
|
67 |
},
|
68 |
{
|
69 |
"cell_type": "markdown",
|
70 |
"id": "54de0ddc",
|
71 |
+
"metadata": {
|
72 |
+
"slideshow": {
|
73 |
+
"slide_type": "-"
|
74 |
+
}
|
75 |
+
},
|
76 |
"source": [
|
77 |
"Add a username and password for your app to your `.env` file. This will ensure that unauthorized users are not able to access LLM features. Use the following format:"
|
78 |
]
|
|
|
81 |
"cell_type": "code",
|
82 |
"execution_count": null,
|
83 |
"id": "95dec7cf",
|
84 |
+
"metadata": {
|
85 |
+
"slideshow": {
|
86 |
+
"slide_type": "fragment"
|
87 |
+
}
|
88 |
+
},
|
89 |
"outputs": [],
|
90 |
"source": [
|
91 |
"APP_USERNAME=<whatever username you want>\n",
|
|
|
95 |
{
|
96 |
"cell_type": "markdown",
|
97 |
"id": "5072dc21",
|
98 |
+
"metadata": {
|
99 |
+
"slideshow": {
|
100 |
+
"slide_type": "slide"
|
101 |
+
}
|
102 |
+
},
|
103 |
"source": [
|
104 |
+
"Let's start by taking all of our necessary chatbot code into one file which we will name `app.py`. Which I'll show you how to do in a second."
|
105 |
]
|
106 |
},
|
107 |
{
|
108 |
"cell_type": "markdown",
|
109 |
"id": "aacdcaaf",
|
110 |
+
"metadata": {
|
111 |
+
"slideshow": {
|
112 |
+
"slide_type": "fragment"
|
113 |
+
}
|
114 |
+
},
|
115 |
"source": [
|
116 |
"Take note that this code has been altered a little bit from the last chatbot example in order to add authentication."
|
117 |
]
|
118 |
},
|
119 |
+
{
|
120 |
+
"cell_type": "markdown",
|
121 |
+
"id": "78815586",
|
122 |
+
"metadata": {
|
123 |
+
"slideshow": {
|
124 |
+
"slide_type": "slide"
|
125 |
+
}
|
126 |
+
},
|
127 |
+
"source": [
|
128 |
+
"In a Jupyter notebook, `%%writefile` is a magic command that tells the notebook to write the contents of the cell to a file. When you run the following cell, it will create (or overwrite) the specified file `app.py` in the current working directory and save the cell's content to that file. It won't actually run the code, just save it. This is useful when you want to save your code directly from a Jupyter notebook cell to a separate Python script file."
|
129 |
+
]
|
130 |
+
},
|
131 |
{
|
132 |
"cell_type": "code",
|
133 |
+
"execution_count": 14,
|
134 |
"id": "710b66f7",
|
135 |
+
"metadata": {
|
136 |
+
"slideshow": {
|
137 |
+
"slide_type": "slide"
|
138 |
+
}
|
139 |
+
},
|
140 |
"outputs": [
|
141 |
{
|
142 |
"name": "stdout",
|
|
|
282 |
{
|
283 |
"cell_type": "markdown",
|
284 |
"id": "6d75af66",
|
285 |
+
"metadata": {
|
286 |
+
"slideshow": {
|
287 |
+
"slide_type": "slide"
|
288 |
+
}
|
289 |
+
},
|
290 |
"source": [
|
291 |
"We will also need a `requirements.txt` file to store the list of the packages that HuggingFace needs to install to run our chatbot."
|
292 |
]
|
|
|
295 |
"cell_type": "code",
|
296 |
"execution_count": 13,
|
297 |
"id": "14d0e434",
|
298 |
+
"metadata": {
|
299 |
+
"slideshow": {
|
300 |
+
"slide_type": "fragment"
|
301 |
+
}
|
302 |
+
},
|
303 |
"outputs": [
|
304 |
{
|
305 |
"name": "stdout",
|
|
|
319 |
{
|
320 |
"cell_type": "markdown",
|
321 |
"id": "4debec45",
|
322 |
+
"metadata": {
|
323 |
+
"slideshow": {
|
324 |
+
"slide_type": "slide"
|
325 |
+
}
|
326 |
+
},
|
327 |
"source": [
|
328 |
"Now let's go ahead and commit our changes"
|
329 |
]
|
|
|
332 |
"cell_type": "code",
|
333 |
"execution_count": 9,
|
334 |
"id": "14d42a96",
|
335 |
+
"metadata": {
|
336 |
+
"slideshow": {
|
337 |
+
"slide_type": "fragment"
|
338 |
+
}
|
339 |
+
},
|
340 |
"outputs": [],
|
341 |
"source": [
|
342 |
"!git add app.py"
|
|
|
346 |
"cell_type": "code",
|
347 |
"execution_count": 8,
|
348 |
"id": "d7c5b127",
|
349 |
+
"metadata": {
|
350 |
+
"slideshow": {
|
351 |
+
"slide_type": "fragment"
|
352 |
+
}
|
353 |
+
},
|
354 |
"outputs": [],
|
355 |
"source": [
|
356 |
"!git add requirements.txt"
|
|
|
360 |
"cell_type": "code",
|
361 |
"execution_count": 11,
|
362 |
"id": "18960d9f",
|
363 |
+
"metadata": {
|
364 |
+
"slideshow": {
|
365 |
+
"slide_type": "fragment"
|
366 |
+
}
|
367 |
+
},
|
368 |
"outputs": [
|
369 |
{
|
370 |
"name": "stdout",
|
|
|
384 |
{
|
385 |
"cell_type": "markdown",
|
386 |
"id": "09221ee0",
|
387 |
+
"metadata": {
|
388 |
+
"slideshow": {
|
389 |
+
"slide_type": "slide"
|
390 |
+
}
|
391 |
+
},
|
392 |
"source": [
|
393 |
"#### Using HuggingFace Spaces"
|
394 |
]
|
|
|
396 |
{
|
397 |
"cell_type": "markdown",
|
398 |
"id": "db789c94",
|
399 |
+
"metadata": {
|
400 |
+
"slideshow": {
|
401 |
+
"slide_type": "-"
|
402 |
+
}
|
403 |
+
},
|
404 |
"source": [
|
405 |
"As mentioned before, HuggingFace is a free-to-use platform for hosting AI demos and apps. We will need to make a HuggingFace _Space_ for our chatbot."
|
406 |
]
|
|
|
408 |
{
|
409 |
"cell_type": "markdown",
|
410 |
"id": "d9eedd10",
|
411 |
+
"metadata": {
|
412 |
+
"slideshow": {
|
413 |
+
"slide_type": "slide"
|
414 |
+
}
|
415 |
+
},
|
416 |
+
"source": [
|
417 |
+
"First sign up for a free HuggingFace account [here](https://huggingface.co/join). "
|
418 |
+
]
|
419 |
+
},
|
420 |
+
{
|
421 |
+
"cell_type": "markdown",
|
422 |
+
"id": "00f537d9",
|
423 |
+
"metadata": {
|
424 |
+
"slideshow": {
|
425 |
+
"slide_type": "-"
|
426 |
+
}
|
427 |
+
},
|
428 |
"source": [
|
429 |
+
"<img src=\"images/signup.png\">"
|
430 |
+
]
|
431 |
+
},
|
432 |
+
{
|
433 |
+
"cell_type": "markdown",
|
434 |
+
"id": "f5fc871f",
|
435 |
+
"metadata": {
|
436 |
+
"slideshow": {
|
437 |
+
"slide_type": "slide"
|
438 |
+
}
|
439 |
+
},
|
440 |
+
"source": [
|
441 |
+
"After you sign up, create a new Space by clicking \"New Space\" on the navigation menu (press on your profile image)."
|
442 |
+
]
|
443 |
+
},
|
444 |
+
{
|
445 |
+
"cell_type": "markdown",
|
446 |
+
"id": "f84e8451",
|
447 |
+
"metadata": {
|
448 |
+
"slideshow": {
|
449 |
+
"slide_type": "-"
|
450 |
+
}
|
451 |
+
},
|
452 |
+
"source": [
|
453 |
+
"<img src=\"images/dropdown.png\">"
|
454 |
+
]
|
455 |
+
},
|
456 |
+
{
|
457 |
+
"cell_type": "markdown",
|
458 |
+
"id": "85684a7b",
|
459 |
+
"metadata": {
|
460 |
+
"slideshow": {
|
461 |
+
"slide_type": "slide"
|
462 |
+
}
|
463 |
+
},
|
464 |
+
"source": [
|
465 |
+
"Create a new space with the following settings"
|
466 |
+
]
|
467 |
+
},
|
468 |
+
{
|
469 |
+
"cell_type": "markdown",
|
470 |
+
"id": "e6130b5d",
|
471 |
+
"metadata": {
|
472 |
+
"slideshow": {
|
473 |
+
"slide_type": "-"
|
474 |
+
}
|
475 |
+
},
|
476 |
+
"source": [
|
477 |
+
"<img src=\"images/space-settings.png\">"
|
478 |
+
]
|
479 |
+
},
|
480 |
+
{
|
481 |
+
"cell_type": "markdown",
|
482 |
+
"id": "897729d3",
|
483 |
+
"metadata": {
|
484 |
+
"slideshow": {
|
485 |
+
"slide_type": "slide"
|
486 |
+
}
|
487 |
+
},
|
488 |
+
"source": [
|
489 |
+
"Take note of your HuggingFace Space URL"
|
490 |
]
|
491 |
},
|
492 |
{
|
493 |
"cell_type": "markdown",
|
494 |
"id": "3e042d24",
|
495 |
+
"metadata": {
|
496 |
+
"slideshow": {
|
497 |
+
"slide_type": "slide"
|
498 |
+
}
|
499 |
+
},
|
500 |
"source": [
|
501 |
"#### Generate a HuggingFace Access Token"
|
502 |
]
|
503 |
},
|
504 |
+
{
|
505 |
+
"cell_type": "code",
|
506 |
+
"execution_count": null,
|
507 |
+
"id": "67273b1a",
|
508 |
+
"metadata": {
|
509 |
+
"slideshow": {
|
510 |
+
"slide_type": "fragment"
|
511 |
+
}
|
512 |
+
},
|
513 |
+
"outputs": [],
|
514 |
+
"source": [
|
515 |
+
"In order to push our code to HuggingFace, we will need to authenticate with HuggingFace via an access token on Git.\n",
|
516 |
+
"\n",
|
517 |
+
"HuggingFace uses git to push a copy of your code to their servers for deployment."
|
518 |
+
]
|
519 |
+
},
|
520 |
+
{
|
521 |
+
"cell_type": "markdown",
|
522 |
+
"id": "909216d4",
|
523 |
+
"metadata": {
|
524 |
+
"slideshow": {
|
525 |
+
"slide_type": "slide"
|
526 |
+
}
|
527 |
+
},
|
528 |
+
"source": [
|
529 |
+
"Visit your Profile Settings and click 'Access Tokens'"
|
530 |
+
]
|
531 |
+
},
|
532 |
+
{
|
533 |
+
"cell_type": "markdown",
|
534 |
+
"id": "fc1c1bec",
|
535 |
+
"metadata": {
|
536 |
+
"slideshow": {
|
537 |
+
"slide_type": "-"
|
538 |
+
}
|
539 |
+
},
|
540 |
+
"source": [
|
541 |
+
"<img src=\"images/profile-settings.png\">"
|
542 |
+
]
|
543 |
+
},
|
544 |
+
{
|
545 |
+
"cell_type": "markdown",
|
546 |
+
"id": "4af1eb8e",
|
547 |
+
"metadata": {
|
548 |
+
"slideshow": {
|
549 |
+
"slide_type": "slide"
|
550 |
+
}
|
551 |
+
},
|
552 |
+
"source": [
|
553 |
+
"Create a new access token for your app with 'write' permissions."
|
554 |
+
]
|
555 |
+
},
|
556 |
+
{
|
557 |
+
"cell_type": "markdown",
|
558 |
+
"id": "e4958b80",
|
559 |
+
"metadata": {
|
560 |
+
"slideshow": {
|
561 |
+
"slide_type": "-"
|
562 |
+
}
|
563 |
+
},
|
564 |
+
"source": [
|
565 |
+
"<img src=\"images/access-tokens.png\">"
|
566 |
+
]
|
567 |
+
},
|
568 |
+
{
|
569 |
+
"cell_type": "markdown",
|
570 |
+
"id": "230d1a32",
|
571 |
+
"metadata": {
|
572 |
+
"slideshow": {
|
573 |
+
"slide_type": "slide"
|
574 |
+
}
|
575 |
+
},
|
576 |
+
"source": [
|
577 |
+
"<img src=\"images/new-access-token.png\">"
|
578 |
+
]
|
579 |
+
},
|
580 |
+
{
|
581 |
+
"cell_type": "markdown",
|
582 |
+
"id": "f050684c",
|
583 |
+
"metadata": {
|
584 |
+
"slideshow": {
|
585 |
+
"slide_type": "slide"
|
586 |
+
}
|
587 |
+
},
|
588 |
+
"source": [
|
589 |
+
"Copy the token to your clipboard!"
|
590 |
+
]
|
591 |
+
},
|
592 |
+
{
|
593 |
+
"cell_type": "markdown",
|
594 |
+
"id": "aa776b02",
|
595 |
+
"metadata": {
|
596 |
+
"slideshow": {
|
597 |
+
"slide_type": "-"
|
598 |
+
}
|
599 |
+
},
|
600 |
+
"source": [
|
601 |
+
"<img src=\"images/copy-token.png\">"
|
602 |
+
]
|
603 |
+
},
|
604 |
{
|
605 |
"cell_type": "markdown",
|
606 |
"id": "a7d0781d",
|
607 |
+
"metadata": {
|
608 |
+
"slideshow": {
|
609 |
+
"slide_type": "slide"
|
610 |
+
}
|
611 |
+
},
|
612 |
"source": [
|
613 |
"#### Login to HuggingFace Hub"
|
614 |
]
|
615 |
},
|
616 |
+
{
|
617 |
+
"cell_type": "markdown",
|
618 |
+
"id": "74518b91",
|
619 |
+
"metadata": {
|
620 |
+
"slideshow": {
|
621 |
+
"slide_type": "-"
|
622 |
+
}
|
623 |
+
},
|
624 |
+
"source": [
|
625 |
+
"If you have ever used Heroku, HuggingFace is similar. The way you deploy is by pushing them a copy of your git repository.\n",
|
626 |
+
"\n",
|
627 |
+
"In order for us to do this, our local git will need to be able to authenticate with HuggingFace.\n",
|
628 |
+
"\n",
|
629 |
+
"Fortunately, theres an easy way we can authenticate and we can do it from inside this notebook."
|
630 |
+
]
|
631 |
+
},
|
632 |
{
|
633 |
"cell_type": "markdown",
|
634 |
"id": "eba83252",
|
635 |
+
"metadata": {
|
636 |
+
"slideshow": {
|
637 |
+
"slide_type": "slide"
|
638 |
+
}
|
639 |
+
},
|
640 |
"source": [
|
641 |
"Install `huggingface_hub`"
|
642 |
]
|
|
|
645 |
"cell_type": "code",
|
646 |
"execution_count": 40,
|
647 |
"id": "266bf481",
|
648 |
+
"metadata": {
|
649 |
+
"slideshow": {
|
650 |
+
"slide_type": "-"
|
651 |
+
}
|
652 |
+
},
|
653 |
"outputs": [],
|
654 |
"source": [
|
655 |
"!pip -q install --upgrade huggingface_hub"
|
|
|
658 |
{
|
659 |
"cell_type": "markdown",
|
660 |
"id": "d50cd84b",
|
661 |
+
"metadata": {
|
662 |
+
"slideshow": {
|
663 |
+
"slide_type": "slide"
|
664 |
+
}
|
665 |
+
},
|
666 |
"source": [
|
667 |
"Login to HuggingFace"
|
668 |
]
|
|
|
671 |
"cell_type": "code",
|
672 |
"execution_count": 6,
|
673 |
"id": "53fd5037",
|
674 |
+
"metadata": {
|
675 |
+
"slideshow": {
|
676 |
+
"slide_type": "-"
|
677 |
+
}
|
678 |
+
},
|
679 |
"outputs": [
|
680 |
{
|
681 |
"name": "stdout",
|
|
|
696 |
{
|
697 |
"cell_type": "markdown",
|
698 |
"id": "90f9bd4d",
|
699 |
+
"metadata": {
|
700 |
+
"slideshow": {
|
701 |
+
"slide_type": "slide"
|
702 |
+
}
|
703 |
+
},
|
704 |
"source": [
|
705 |
"#### Now lets setup git and HuggingFace Spaces to work together and deploy"
|
706 |
]
|
|
|
708 |
{
|
709 |
"cell_type": "markdown",
|
710 |
"id": "66468481",
|
711 |
+
"metadata": {
|
712 |
+
"slideshow": {
|
713 |
+
"slide_type": "fragment"
|
714 |
+
}
|
715 |
+
},
|
716 |
"source": [
|
717 |
"<span style=\"color:red\">REPLACE MY URL WITH YOURS</span>"
|
718 |
]
|
|
|
721 |
"cell_type": "code",
|
722 |
"execution_count": null,
|
723 |
"id": "827a201d",
|
724 |
+
"metadata": {
|
725 |
+
"slideshow": {
|
726 |
+
"slide_type": "fragment"
|
727 |
+
}
|
728 |
+
},
|
729 |
"outputs": [],
|
730 |
"source": [
|
731 |
"!git remote add huggingface https://huggingface.co/spaces/ericmichael/gradio-chatbot-demo"
|
|
|
734 |
{
|
735 |
"cell_type": "markdown",
|
736 |
"id": "f8b3bb3d",
|
737 |
+
"metadata": {
|
738 |
+
"slideshow": {
|
739 |
+
"slide_type": "fragment"
|
740 |
+
}
|
741 |
+
},
|
742 |
"source": [
|
743 |
"Then force push to sync everything for the first time."
|
744 |
]
|
|
|
747 |
"cell_type": "code",
|
748 |
"execution_count": 12,
|
749 |
"id": "86c9ee4e",
|
750 |
+
"metadata": {
|
751 |
+
"slideshow": {
|
752 |
+
"slide_type": "fragment"
|
753 |
+
}
|
754 |
+
},
|
755 |
"outputs": [
|
756 |
{
|
757 |
"name": "stdout",
|
|
|
769 |
},
|
770 |
{
|
771 |
"cell_type": "markdown",
|
772 |
+
"id": "48510bba",
|
773 |
+
"metadata": {
|
774 |
+
"slideshow": {
|
775 |
+
"slide_type": "slide"
|
776 |
+
}
|
777 |
+
},
|
778 |
"source": [
|
779 |
+
"#### Now lets setup our secrets on our HuggingFace Space"
|
780 |
+
]
|
781 |
+
},
|
782 |
+
{
|
783 |
+
"cell_type": "markdown",
|
784 |
+
"id": "4ab2d59b",
|
785 |
+
"metadata": {
|
786 |
+
"slideshow": {
|
787 |
+
"slide_type": "fragment"
|
788 |
+
}
|
789 |
+
},
|
790 |
+
"source": [
|
791 |
+
"We're so close, HuggingFace now has our app but it doesn't have any of our secrets! This means users can't authenticate with our HuggingFace app and our app can't authenticate with OpenAI!\n",
|
792 |
+
"\n",
|
793 |
+
"We will need to set our secrets manually on HuggingFace, which is a common practice so they don't end up accidentally leaked in version control."
|
794 |
]
|
795 |
},
|
796 |
{
|
797 |
"cell_type": "markdown",
|
798 |
+
"id": "fec397c8",
|
799 |
"metadata": {
|
800 |
"slideshow": {
|
801 |
"slide_type": "slide"
|
802 |
}
|
803 |
},
|
804 |
"source": [
|
805 |
+
"Go to your HuggingFace Space and click 'Settings'"
|
806 |
]
|
807 |
},
|
808 |
{
|
809 |
+
"cell_type": "markdown",
|
810 |
+
"id": "a7016df7",
|
811 |
+
"metadata": {
|
812 |
+
"slideshow": {
|
813 |
+
"slide_type": "-"
|
814 |
+
}
|
815 |
+
},
|
816 |
+
"source": [
|
817 |
+
"<img src=\"images/repo.png\">"
|
818 |
+
]
|
819 |
+
},
|
820 |
+
{
|
821 |
+
"cell_type": "markdown",
|
822 |
+
"id": "1e10cf24",
|
823 |
"metadata": {
|
824 |
"slideshow": {
|
825 |
"slide_type": "slide"
|
826 |
}
|
827 |
},
|
828 |
+
"source": [
|
829 |
+
"Scroll to 'Repository Secrets', yours will be empty for now but you will need to fill it in."
|
830 |
+
]
|
831 |
+
},
|
832 |
+
{
|
833 |
+
"cell_type": "markdown",
|
834 |
+
"id": "d70ec1aa",
|
835 |
+
"metadata": {
|
836 |
+
"slideshow": {
|
837 |
+
"slide_type": "-"
|
838 |
+
}
|
839 |
+
},
|
840 |
+
"source": [
|
841 |
+
"<img src=\"images/secrets.png\">"
|
842 |
+
]
|
843 |
+
},
|
844 |
+
{
|
845 |
+
"cell_type": "markdown",
|
846 |
+
"id": "8c931425",
|
847 |
+
"metadata": {
|
848 |
+
"slideshow": {
|
849 |
+
"slide_type": "slide"
|
850 |
+
}
|
851 |
+
},
|
852 |
+
"source": [
|
853 |
+
"We will need to provide:\n",
|
854 |
+
"\n",
|
855 |
+
"* `OPENAI_API_BASE` - if you are using my OpenAI service, don't add this one if you are paying for OpenAI yourself\n",
|
856 |
+
"* `OPENAI_API_KEY` - either the key from my service or from OpenAI directly\n",
|
857 |
+
"* `APP_USERNAME` - the username you want people to sign in with\n",
|
858 |
+
"* `APP_PASSWORD` - the username you want people to sign in with"
|
859 |
+
]
|
860 |
+
},
|
861 |
+
{
|
862 |
+
"cell_type": "markdown",
|
863 |
+
"id": "17a2e7c5",
|
864 |
+
"metadata": {
|
865 |
+
"slideshow": {
|
866 |
+
"slide_type": "slide"
|
867 |
+
}
|
868 |
+
},
|
869 |
+
"source": [
|
870 |
+
"Example"
|
871 |
+
]
|
872 |
+
},
|
873 |
+
{
|
874 |
+
"cell_type": "markdown",
|
875 |
+
"id": "7132a08f",
|
876 |
+
"metadata": {
|
877 |
+
"slideshow": {
|
878 |
+
"slide_type": "-"
|
879 |
+
}
|
880 |
+
},
|
881 |
+
"source": [
|
882 |
+
"<img src=\"images/add-secret.png\">"
|
883 |
+
]
|
884 |
+
},
|
885 |
+
{
|
886 |
+
"cell_type": "markdown",
|
887 |
+
"id": "4405e200",
|
888 |
+
"metadata": {
|
889 |
+
"slideshow": {
|
890 |
+
"slide_type": "slide"
|
891 |
+
}
|
892 |
+
},
|
893 |
+
"source": [
|
894 |
+
"Restart your HuggingFace Space"
|
895 |
+
]
|
896 |
+
},
|
897 |
+
{
|
898 |
+
"cell_type": "markdown",
|
899 |
+
"id": "0718c510",
|
900 |
+
"metadata": {
|
901 |
+
"slideshow": {
|
902 |
+
"slide_type": "-"
|
903 |
+
}
|
904 |
+
},
|
905 |
+
"source": [
|
906 |
+
"<img src=\"images/restart.png\">"
|
907 |
+
]
|
908 |
+
},
|
909 |
+
{
|
910 |
+
"cell_type": "markdown",
|
911 |
+
"id": "3a353ebf",
|
912 |
+
"metadata": {
|
913 |
+
"slideshow": {
|
914 |
+
"slide_type": "-"
|
915 |
+
}
|
916 |
+
},
|
917 |
+
"source": [
|
918 |
+
"That's it! 🎉 Check your HuggingFace Space URL to access your chatbot!"
|
919 |
+
]
|
920 |
}
|
921 |
],
|
922 |
"metadata": {
|
923 |
+
"celltoolbar": "Slideshow",
|
924 |
"kernelspec": {
|
925 |
"display_name": "Python 3 (ipykernel)",
|
926 |
"language": "python",
|
06_designing_effective_prompts.ipynb
CHANGED
@@ -41,7 +41,7 @@
|
|
41 |
},
|
42 |
{
|
43 |
"cell_type": "code",
|
44 |
-
"execution_count":
|
45 |
"id": "895d5bf1",
|
46 |
"metadata": {
|
47 |
"hideCode": false,
|
@@ -1484,90 +1484,377 @@
|
|
1484 |
}
|
1485 |
},
|
1486 |
"source": [
|
1487 |
-
"##
|
1488 |
]
|
1489 |
},
|
1490 |
{
|
1491 |
"cell_type": "code",
|
1492 |
-
"execution_count":
|
1493 |
-
"id": "
|
1494 |
-
"metadata": {
|
1495 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1496 |
"source": [
|
1497 |
-
"
|
|
|
1498 |
"\n",
|
1499 |
-
"
|
1500 |
-
"
|
1501 |
-
"
|
1502 |
-
"
|
1503 |
-
"
|
1504 |
-
"
|
1505 |
-
" messages += [{\"role\": \"user\", \"content\": message}]\n",
|
1506 |
-
" \n",
|
1507 |
-
" # Make an API call to the OpenAI ChatCompletion endpoint with the model and messages\n",
|
1508 |
-
" completion = openai.ChatCompletion.create(\n",
|
1509 |
-
" model=\"gpt-3.5-turbo\",\n",
|
1510 |
-
" messages=messages\n",
|
1511 |
-
" )\n",
|
1512 |
-
" \n",
|
1513 |
-
" # Extract and return the AI's response from the API response\n",
|
1514 |
-
" return completion.choices[0].message.content"
|
1515 |
-
]
|
1516 |
-
},
|
1517 |
-
{
|
1518 |
-
"cell_type": "markdown",
|
1519 |
-
"id": "1a2e4dbb",
|
1520 |
-
"metadata": {},
|
1521 |
-
"source": [
|
1522 |
-
"#### Idea: Entrepreneur AI Prompt"
|
1523 |
]
|
1524 |
},
|
1525 |
{
|
1526 |
-
"cell_type": "
|
1527 |
-
"
|
1528 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1529 |
"source": [
|
1530 |
-
"
|
|
|
|
|
|
|
1531 |
"\n",
|
1532 |
-
"
|
1533 |
-
"
|
|
|
|
|
|
|
|
|
1534 |
]
|
1535 |
},
|
1536 |
{
|
1537 |
-
"cell_type": "
|
1538 |
-
"
|
|
|
1539 |
"metadata": {
|
|
|
1540 |
"slideshow": {
|
1541 |
"slide_type": "slide"
|
1542 |
}
|
1543 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1544 |
"source": [
|
1545 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1546 |
]
|
1547 |
},
|
1548 |
{
|
1549 |
-
"cell_type": "
|
1550 |
-
"
|
|
|
1551 |
"metadata": {
|
|
|
1552 |
"slideshow": {
|
1553 |
"slide_type": "slide"
|
1554 |
}
|
1555 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1556 |
"source": [
|
1557 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1558 |
]
|
1559 |
},
|
1560 |
{
|
1561 |
"cell_type": "code",
|
1562 |
-
"execution_count":
|
1563 |
-
"id": "
|
1564 |
"metadata": {
|
|
|
1565 |
"slideshow": {
|
1566 |
"slide_type": "slide"
|
1567 |
}
|
1568 |
},
|
1569 |
-
"outputs": [
|
1570 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1571 |
}
|
1572 |
],
|
1573 |
"metadata": {
|
|
|
41 |
},
|
42 |
{
|
43 |
"cell_type": "code",
|
44 |
+
"execution_count": 2,
|
45 |
"id": "895d5bf1",
|
46 |
"metadata": {
|
47 |
"hideCode": false,
|
|
|
1484 |
}
|
1485 |
},
|
1486 |
"source": [
|
1487 |
+
"## Additional Examples"
|
1488 |
]
|
1489 |
},
|
1490 |
{
|
1491 |
"cell_type": "code",
|
1492 |
+
"execution_count": 13,
|
1493 |
+
"id": "8e09db5c",
|
1494 |
+
"metadata": {
|
1495 |
+
"hideCode": true,
|
1496 |
+
"slideshow": {
|
1497 |
+
"slide_type": "slide"
|
1498 |
+
}
|
1499 |
+
},
|
1500 |
+
"outputs": [
|
1501 |
+
{
|
1502 |
+
"data": {
|
1503 |
+
"text/html": [
|
1504 |
+
"\n",
|
1505 |
+
" <table style=\"font-size: 100%;\">\n",
|
1506 |
+
" <tr style=\"background: none;\">\n",
|
1507 |
+
" <td style=\"vertical-align: top;text-align:left;\" width=\"45%\">\n",
|
1508 |
+
" <h4>Prompt</h4><div style='color:red;padding-top:10px;font-weight:300;font-style: italic;'>Bad, ambigous without context</div>\n",
|
1509 |
+
" <div style=\"line-height:1.5;border:1px solid #e9ecef;margin-top:9px;color:#495057;background-color:#ffe69c;padding: 12px;border-radius: 8px;\">\n",
|
1510 |
+
" You are an AI assistant that can provide translations for words and sentences.<br/><br/>Translate that word or sentence to Spanish, do not provide unnecessary commentary or punctuation.\n",
|
1511 |
+
" </div>\n",
|
1512 |
+
" </td>\n",
|
1513 |
+
" <td width=\"10%\"></td>\n",
|
1514 |
+
" <td style=\"vertical-align: top;text-align:right;\" width=\"45%\">\n",
|
1515 |
+
" <h4>User Input</h4>\n",
|
1516 |
+
" <div style=\"line-height:1.5;margin-top:9px;color:white;background-color:#0b93f6;padding: 12px;border-radius: 8px;\">\n",
|
1517 |
+
" I saw the bat.\n",
|
1518 |
+
" </div>\n",
|
1519 |
+
" <h4>LLM Output</h4>\n",
|
1520 |
+
" <div style=\"line-height:1.5;margin-top:9px;color:black;background-color:#e5e5ea;padding: 12px;border-radius: 8px;\">\n",
|
1521 |
+
" Vi el murciélago.\n",
|
1522 |
+
" </div>\n",
|
1523 |
+
" </td>\n",
|
1524 |
+
" </tr>\n",
|
1525 |
+
" </table>\n",
|
1526 |
+
" "
|
1527 |
+
],
|
1528 |
+
"text/plain": [
|
1529 |
+
"<IPython.core.display.HTML object>"
|
1530 |
+
]
|
1531 |
+
},
|
1532 |
+
"metadata": {},
|
1533 |
+
"output_type": "display_data"
|
1534 |
+
}
|
1535 |
+
],
|
1536 |
"source": [
|
1537 |
+
"prompt = \"\"\"\n",
|
1538 |
+
"You are an AI assistant that can provide translations for words and sentences.\n",
|
1539 |
"\n",
|
1540 |
+
"Translate that word or sentence to Spanish, do not provide unnecessary commentary or punctuation.\n",
|
1541 |
+
"\"\"\"\n",
|
1542 |
+
"\n",
|
1543 |
+
"user_message = \"I saw the bat.\"\n",
|
1544 |
+
"\n",
|
1545 |
+
"display_chat(prompt, user_message, label=\"Bad, ambigous without context\")"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1546 |
]
|
1547 |
},
|
1548 |
{
|
1549 |
+
"cell_type": "code",
|
1550 |
+
"execution_count": 15,
|
1551 |
+
"id": "cee637d0",
|
1552 |
+
"metadata": {
|
1553 |
+
"hideCode": true,
|
1554 |
+
"slideshow": {
|
1555 |
+
"slide_type": "slide"
|
1556 |
+
}
|
1557 |
+
},
|
1558 |
+
"outputs": [
|
1559 |
+
{
|
1560 |
+
"data": {
|
1561 |
+
"text/html": [
|
1562 |
+
"\n",
|
1563 |
+
" <table style=\"font-size: 100%;\">\n",
|
1564 |
+
" <tr style=\"background: none;\">\n",
|
1565 |
+
" <td style=\"vertical-align: top;text-align:left;\" width=\"45%\">\n",
|
1566 |
+
" <h4>Prompt</h4><div style='color:green;padding-top:10px;font-weight:300;font-style: italic;'>Good, provides the context needed for translation</div>\n",
|
1567 |
+
" <div style=\"line-height:1.5;border:1px solid #e9ecef;margin-top:9px;color:#495057;background-color:#ffe69c;padding: 12px;border-radius: 8px;\">\n",
|
1568 |
+
" You are an AI assistant that can provide translations for words and sentences.<br/><br/>Context: A detective is looking for a murder weapon and is speaking to a witness.<br/><br/>Translate that word or sentence to Spanish, do not provide unnecessary commentary or punctuation.\n",
|
1569 |
+
" </div>\n",
|
1570 |
+
" </td>\n",
|
1571 |
+
" <td width=\"10%\"></td>\n",
|
1572 |
+
" <td style=\"vertical-align: top;text-align:right;\" width=\"45%\">\n",
|
1573 |
+
" <h4>User Input</h4>\n",
|
1574 |
+
" <div style=\"line-height:1.5;margin-top:9px;color:white;background-color:#0b93f6;padding: 12px;border-radius: 8px;\">\n",
|
1575 |
+
" I saw the bat.\n",
|
1576 |
+
" </div>\n",
|
1577 |
+
" <h4>LLM Output</h4>\n",
|
1578 |
+
" <div style=\"line-height:1.5;margin-top:9px;color:black;background-color:#e5e5ea;padding: 12px;border-radius: 8px;\">\n",
|
1579 |
+
" Vi el bate.\n",
|
1580 |
+
" </div>\n",
|
1581 |
+
" </td>\n",
|
1582 |
+
" </tr>\n",
|
1583 |
+
" </table>\n",
|
1584 |
+
" "
|
1585 |
+
],
|
1586 |
+
"text/plain": [
|
1587 |
+
"<IPython.core.display.HTML object>"
|
1588 |
+
]
|
1589 |
+
},
|
1590 |
+
"metadata": {},
|
1591 |
+
"output_type": "display_data"
|
1592 |
+
}
|
1593 |
+
],
|
1594 |
"source": [
|
1595 |
+
"prompt = \"\"\"\n",
|
1596 |
+
"You are an AI assistant that can provide translations for words and sentences.\n",
|
1597 |
+
"\n",
|
1598 |
+
"Context: A detective is looking for a murder weapon and is speaking to a witness.\n",
|
1599 |
"\n",
|
1600 |
+
"Translate that word or sentence to Spanish, do not provide unnecessary commentary or punctuation.\n",
|
1601 |
+
"\"\"\"\n",
|
1602 |
+
"\n",
|
1603 |
+
"user_message = \"I saw the bat.\"\n",
|
1604 |
+
"\n",
|
1605 |
+
"display_chat(prompt, user_message, label=\"Good, provides the context needed for translation\")"
|
1606 |
]
|
1607 |
},
|
1608 |
{
|
1609 |
+
"cell_type": "code",
|
1610 |
+
"execution_count": 17,
|
1611 |
+
"id": "5b59cc98",
|
1612 |
"metadata": {
|
1613 |
+
"hideCode": true,
|
1614 |
"slideshow": {
|
1615 |
"slide_type": "slide"
|
1616 |
}
|
1617 |
},
|
1618 |
+
"outputs": [
|
1619 |
+
{
|
1620 |
+
"data": {
|
1621 |
+
"text/html": [
|
1622 |
+
"\n",
|
1623 |
+
" <table style=\"font-size: 100%;\">\n",
|
1624 |
+
" <tr style=\"background: none;\">\n",
|
1625 |
+
" <td style=\"vertical-align: top;text-align:left;\" width=\"45%\">\n",
|
1626 |
+
" <h4>Prompt</h4><div style='color:red;padding-top:10px;font-weight:300;font-style: italic;'>Bad</div>\n",
|
1627 |
+
" <div style=\"line-height:1.5;border:1px solid #e9ecef;margin-top:9px;color:#495057;background-color:#ffe69c;padding: 12px;border-radius: 8px;\">\n",
|
1628 |
+
" You are an AI assistant that can clean up auto-generated text transcriptions from YouTube videos.<br/><br/>When the user submits text.<br/><br/>Reply only with the cleaned up version of the text.\n",
|
1629 |
+
" </div>\n",
|
1630 |
+
" </td>\n",
|
1631 |
+
" <td width=\"10%\"></td>\n",
|
1632 |
+
" <td style=\"vertical-align: top;text-align:right;\" width=\"45%\">\n",
|
1633 |
+
" <h4>User Input</h4>\n",
|
1634 |
+
" <div style=\"line-height:1.5;margin-top:9px;color:white;background-color:#0b93f6;padding: 12px;border-radius: 8px;\">\n",
|
1635 |
+
" so i have a new series coming out<br/>on kgard which is my favorite way to<br/>approach<br/>guard against an opponent who is<br/>kneeling for open guard okay this is<br/>going to be part of<br/>three releases i have coming out on open<br/>guard there's keyguard<br/>there's de la hever and wader and then<br/>there's leg entanglements and reverse<br/>telehebera<br/>okay so for keigar if i've got jorge<br/>here<br/>usually usually against someone who's on<br/>their knees the first entry point<br/>for me is to look for keigar\n",
|
1636 |
+
" </div>\n",
|
1637 |
+
" <h4>LLM Output</h4>\n",
|
1638 |
+
" <div style=\"line-height:1.5;margin-top:9px;color:black;background-color:#e5e5ea;padding: 12px;border-radius: 8px;\">\n",
|
1639 |
+
" "I have a new series coming out on Keigar, my favorite way to guard against an opponent who is kneeling for open guard. This is part of three releases I have coming out on open guard, which include De La Hever and Wader, and leg entanglements and reverse telehebera. When using Keigar, my first entry point against someone on their knees is to look for Keigar."\n",
|
1640 |
+
" </div>\n",
|
1641 |
+
" </td>\n",
|
1642 |
+
" </tr>\n",
|
1643 |
+
" </table>\n",
|
1644 |
+
" "
|
1645 |
+
],
|
1646 |
+
"text/plain": [
|
1647 |
+
"<IPython.core.display.HTML object>"
|
1648 |
+
]
|
1649 |
+
},
|
1650 |
+
"metadata": {},
|
1651 |
+
"output_type": "display_data"
|
1652 |
+
}
|
1653 |
+
],
|
1654 |
"source": [
|
1655 |
+
"prompt = \"\"\"\n",
|
1656 |
+
"You are an AI assistant that can clean up auto-generated text transcriptions from YouTube videos.\n",
|
1657 |
+
"\n",
|
1658 |
+
"When the user submits text.\n",
|
1659 |
+
"\n",
|
1660 |
+
"Reply only with the cleaned up version of the text.\n",
|
1661 |
+
"\"\"\"\n",
|
1662 |
+
"\n",
|
1663 |
+
"user_message = \"\"\"\n",
|
1664 |
+
"so i have a new series coming out\n",
|
1665 |
+
"on kgard which is my favorite way to\n",
|
1666 |
+
"approach\n",
|
1667 |
+
"guard against an opponent who is\n",
|
1668 |
+
"kneeling for open guard okay this is\n",
|
1669 |
+
"going to be part of\n",
|
1670 |
+
"three releases i have coming out on open\n",
|
1671 |
+
"guard there's keyguard\n",
|
1672 |
+
"there's de la hever and wader and then\n",
|
1673 |
+
"there's leg entanglements and reverse\n",
|
1674 |
+
"telehebera\n",
|
1675 |
+
"okay so for keigar if i've got jorge\n",
|
1676 |
+
"here\n",
|
1677 |
+
"usually usually against someone who's on\n",
|
1678 |
+
"their knees the first entry point\n",
|
1679 |
+
"for me is to look for keigar\n",
|
1680 |
+
"\"\"\"\n",
|
1681 |
+
"\n",
|
1682 |
+
"display_chat(prompt, user_message, label=\"Bad\")"
|
1683 |
]
|
1684 |
},
|
1685 |
{
|
1686 |
+
"cell_type": "code",
|
1687 |
+
"execution_count": 30,
|
1688 |
+
"id": "dc452072",
|
1689 |
"metadata": {
|
1690 |
+
"hideCode": true,
|
1691 |
"slideshow": {
|
1692 |
"slide_type": "slide"
|
1693 |
}
|
1694 |
},
|
1695 |
+
"outputs": [
|
1696 |
+
{
|
1697 |
+
"data": {
|
1698 |
+
"text/html": [
|
1699 |
+
"\n",
|
1700 |
+
" <table style=\"font-size: 100%;\">\n",
|
1701 |
+
" <tr style=\"background: none;\">\n",
|
1702 |
+
" <td style=\"vertical-align: top;text-align:left;\" width=\"45%\">\n",
|
1703 |
+
" <h4>Prompt</h4><div style='color:green;padding-top:10px;font-weight:300;font-style: italic;'>Good, this can be used as a subroutine for LLM chains.</div>\n",
|
1704 |
+
" <div style=\"line-height:1.5;border:1px solid #e9ecef;margin-top:9px;color:#495057;background-color:#ffe69c;padding: 12px;border-radius: 8px;\">\n",
|
1705 |
+
" You are an AI assistant that can aid humans in assist in cleaning auto-generated text transcriptions from YouTube videos.<br/><br/>When the user submits the title of the YouTube video.<br/><br/>Reply with unique vocabulary words or short phrases that relate to that topic that an auto-generated transcription is likely to misspell due to the words or phrases being unique nomenclature to that topic.<br/><br/>Reply only with the vocabulary list.<br/><br/>You must provide 50 words or phrases.<br/><br/>Use the following format:<br/>- <word or phrase><br/>- <word or phrase><br/>- <word or phrase><br/>- <word or phrase><br/>- <word or phrase><br/>- <word or phrase><br/>- <word or phrase><br/>...<br/>- <word or phrase>\n",
|
1706 |
+
" </div>\n",
|
1707 |
+
" </td>\n",
|
1708 |
+
" <td width=\"10%\"></td>\n",
|
1709 |
+
" <td style=\"vertical-align: top;text-align:right;\" width=\"45%\">\n",
|
1710 |
+
" <h4>User Input</h4>\n",
|
1711 |
+
" <div style=\"line-height:1.5;margin-top:9px;color:white;background-color:#0b93f6;padding: 12px;border-radius: 8px;\">\n",
|
1712 |
+
" How To Do The Perfect BJJ K Guard by Lachlan Giles\n",
|
1713 |
+
" </div>\n",
|
1714 |
+
" <h4>LLM Output</h4>\n",
|
1715 |
+
" <div style=\"line-height:1.5;margin-top:9px;color:black;background-color:#e5e5ea;padding: 12px;border-radius: 8px;\">\n",
|
1716 |
+
" - BJJ <br/>- K Guard<br/>- Lachlan Giles<br/>- Brazilian Jiu-Jitsu<br/>- Grappling<br/>- Submission<br/>- Martial arts<br/>- Gi <br/>- No Gi<br/>- Ground Game<br/>- Sweep<br/>- Choke<br/>- Armbar<br/>- Triangle<br/>- Kimura<br/>- Omoplata<br/>- Guard Pass<br/>- Open Guard<br/>- Closed Guard<br/>- Half Guard<br/>- Full Guard<br/>- Mount<br/>- Back Control<br/>- Side Control<br/>- Knee-on-Belly <br/>- Spider Guard<br/>- De La Riva Guard<br/>- X Guard<br/>- Butterfly Guard<br/>- Sprawl<br/>- Hip Escape<br/>- Scissor Sweep<br/>- Butterfly Sweep<br/>- Single Leg Takedown<br/>- Double Leg Takedown<br/>- Shoulder Pressure<br/>- Guard Retention<br/>- Guard Recovery<br/>- Submission Defense<br/>- Positional Control<br/>- Joint Lock<br/>- Wrist Lock<br/>- Rear Naked Choke<br/>- Guillotine Choke<br/>- Arm Triangle Choke<br/>- Baseball Bat Choke<br/>- Bow and Arrow Choke<br/>- Triangle Choke Defense<br/>- Mount Escape<br/>- Collar Drag<br/>- Foot Sweep<br/>- Balloon Sweep.\n",
|
1717 |
+
" </div>\n",
|
1718 |
+
" </td>\n",
|
1719 |
+
" </tr>\n",
|
1720 |
+
" </table>\n",
|
1721 |
+
" "
|
1722 |
+
],
|
1723 |
+
"text/plain": [
|
1724 |
+
"<IPython.core.display.HTML object>"
|
1725 |
+
]
|
1726 |
+
},
|
1727 |
+
"metadata": {},
|
1728 |
+
"output_type": "display_data"
|
1729 |
+
}
|
1730 |
+
],
|
1731 |
"source": [
|
1732 |
+
"prompt = \"\"\"\n",
|
1733 |
+
"You are an AI assistant that can aid humans in assist in cleaning auto-generated text transcriptions from YouTube videos.\n",
|
1734 |
+
"\n",
|
1735 |
+
"When the user submits the title of the YouTube video.\n",
|
1736 |
+
"\n",
|
1737 |
+
"Reply with unique vocabulary words or short phrases that relate to that topic that an auto-generated transcription is likely to misspell due to the words or phrases being unique nomenclature to that topic.\n",
|
1738 |
+
"\n",
|
1739 |
+
"Reply only with the vocabulary list.\n",
|
1740 |
+
"\n",
|
1741 |
+
"You must provide 50 words or phrases.\n",
|
1742 |
+
"\n",
|
1743 |
+
"Use the following format:\n",
|
1744 |
+
"- <word or phrase>\n",
|
1745 |
+
"- <word or phrase>\n",
|
1746 |
+
"- <word or phrase>\n",
|
1747 |
+
"- <word or phrase>\n",
|
1748 |
+
"- <word or phrase>\n",
|
1749 |
+
"- <word or phrase>\n",
|
1750 |
+
"- <word or phrase>\n",
|
1751 |
+
"...\n",
|
1752 |
+
"- <word or phrase>\n",
|
1753 |
+
"\"\"\"\n",
|
1754 |
+
"\n",
|
1755 |
+
"user_message = \"\"\"\n",
|
1756 |
+
"How To Do The Perfect BJJ K Guard by Lachlan Giles\n",
|
1757 |
+
"\"\"\"\n",
|
1758 |
+
"\n",
|
1759 |
+
"display_chat(prompt, user_message, label=\"Good, this can be used as a subroutine for LLM chains.\")"
|
1760 |
]
|
1761 |
},
|
1762 |
{
|
1763 |
"cell_type": "code",
|
1764 |
+
"execution_count": 29,
|
1765 |
+
"id": "90d9439a",
|
1766 |
"metadata": {
|
1767 |
+
"hideCode": true,
|
1768 |
"slideshow": {
|
1769 |
"slide_type": "slide"
|
1770 |
}
|
1771 |
},
|
1772 |
+
"outputs": [
|
1773 |
+
{
|
1774 |
+
"data": {
|
1775 |
+
"text/html": [
|
1776 |
+
"\n",
|
1777 |
+
" <table style=\"font-size: 100%;\">\n",
|
1778 |
+
" <tr style=\"background: none;\">\n",
|
1779 |
+
" <td style=\"vertical-align: top;text-align:left;\" width=\"45%\">\n",
|
1780 |
+
" <h4>Prompt</h4><div style='color:green;padding-top:10px;font-weight:300;font-style: italic;'>Good, includes context about the topic and a known list of vocabulary words. Can the LLM come up with those words though?</div>\n",
|
1781 |
+
" <div style=\"line-height:1.5;border:1px solid #e9ecef;margin-top:9px;color:#495057;background-color:#ffe69c;padding: 12px;border-radius: 8px;\">\n",
|
1782 |
+
" You are an AI assistant that can clean up auto-generated text transcriptions from YouTube videos.<br/><br/>When the user submits text.<br/><br/>Reply only with the cleaned up version of the text.<br/><br/>If you are about to output something that looks like it is misspelled check first against the list of unique vocabulary<br/>and also think about the context you know about the topic.<br/><br/>If you output a word or phrase it should be because you have context that associates it with the topic.<br/><br/>Topic: Brazilian Jiu-Jitsu<br/>Unique Vocabulary:<br/>- K-Guard<br/>- Half-Guard<br/>- Single Leg X<br/>- Single Leg<br/>- Z-Guard<br/>- De La Riva<br/>- Reverse De Riva<br/>- Mount<br/>- Back Control<br/>- Ezekiel<br/>- Kimura<br/>- Waiter\n",
|
1783 |
+
" </div>\n",
|
1784 |
+
" </td>\n",
|
1785 |
+
" <td width=\"10%\"></td>\n",
|
1786 |
+
" <td style=\"vertical-align: top;text-align:right;\" width=\"45%\">\n",
|
1787 |
+
" <h4>User Input</h4>\n",
|
1788 |
+
" <div style=\"line-height:1.5;margin-top:9px;color:white;background-color:#0b93f6;padding: 12px;border-radius: 8px;\">\n",
|
1789 |
+
" so i have a new series coming out<br/>on kgard which is my favorite way to<br/>approach<br/>guard against an opponent who is<br/>kneeling for open guard okay this is<br/>going to be part of<br/>three releases i have coming out on open<br/>guard there's keyguard<br/>there's de la hever and wader and then<br/>there's leg entanglements and reverse<br/>telehebera<br/>okay so for keigar if i've got jorge<br/>here<br/>usually usually against someone who's on<br/>their knees the first entry point<br/>for me is to look for keigar\n",
|
1790 |
+
" </div>\n",
|
1791 |
+
" <h4>LLM Output</h4>\n",
|
1792 |
+
" <div style=\"line-height:1.5;margin-top:9px;color:black;background-color:#e5e5ea;padding: 12px;border-radius: 8px;\">\n",
|
1793 |
+
" "I have a new series coming out on K-Guard, which is my favorite way to approach open guard against an opponent who is kneeling. This is going to be part of three releases I have coming out on open guard. There are K-Guard, De La Riva, and Waiter, and then there's leg entanglements and reverse De La Riva. For K-Guard, if I've got Jorge here, usually against someone who's on their knees, the first entry point for me is to look for K-Guard."\n",
|
1794 |
+
" </div>\n",
|
1795 |
+
" </td>\n",
|
1796 |
+
" </tr>\n",
|
1797 |
+
" </table>\n",
|
1798 |
+
" "
|
1799 |
+
],
|
1800 |
+
"text/plain": [
|
1801 |
+
"<IPython.core.display.HTML object>"
|
1802 |
+
]
|
1803 |
+
},
|
1804 |
+
"metadata": {},
|
1805 |
+
"output_type": "display_data"
|
1806 |
+
}
|
1807 |
+
],
|
1808 |
+
"source": [
|
1809 |
+
"prompt = \"\"\"\n",
|
1810 |
+
"You are an AI assistant that can clean up auto-generated text transcriptions from YouTube videos.\n",
|
1811 |
+
"\n",
|
1812 |
+
"When the user submits text.\n",
|
1813 |
+
"\n",
|
1814 |
+
"Reply only with the cleaned up version of the text.\n",
|
1815 |
+
"\n",
|
1816 |
+
"If you are about to output something that looks like it is misspelled check first against the list of unique vocabulary\n",
|
1817 |
+
"and also think about the context you know about the topic.\n",
|
1818 |
+
"\n",
|
1819 |
+
"If you output a word or phrase it should be because you have context that associates it with the topic.\n",
|
1820 |
+
"\n",
|
1821 |
+
"Topic: Brazilian Jiu-Jitsu\n",
|
1822 |
+
"Unique Vocabulary:\n",
|
1823 |
+
"- K-Guard\n",
|
1824 |
+
"- Half-Guard\n",
|
1825 |
+
"- Single Leg X\n",
|
1826 |
+
"- Single Leg\n",
|
1827 |
+
"- Z-Guard\n",
|
1828 |
+
"- De La Riva\n",
|
1829 |
+
"- Reverse De Riva\n",
|
1830 |
+
"- Mount\n",
|
1831 |
+
"- Back Control\n",
|
1832 |
+
"- Ezekiel\n",
|
1833 |
+
"- Kimura\n",
|
1834 |
+
"- Waiter\n",
|
1835 |
+
"\"\"\"\n",
|
1836 |
+
"\n",
|
1837 |
+
"user_message = \"\"\"\n",
|
1838 |
+
"so i have a new series coming out\n",
|
1839 |
+
"on kgard which is my favorite way to\n",
|
1840 |
+
"approach\n",
|
1841 |
+
"guard against an opponent who is\n",
|
1842 |
+
"kneeling for open guard okay this is\n",
|
1843 |
+
"going to be part of\n",
|
1844 |
+
"three releases i have coming out on open\n",
|
1845 |
+
"guard there's keyguard\n",
|
1846 |
+
"there's de la hever and wader and then\n",
|
1847 |
+
"there's leg entanglements and reverse\n",
|
1848 |
+
"telehebera\n",
|
1849 |
+
"okay so for keigar if i've got jorge\n",
|
1850 |
+
"here\n",
|
1851 |
+
"usually usually against someone who's on\n",
|
1852 |
+
"their knees the first entry point\n",
|
1853 |
+
"for me is to look for keigar\n",
|
1854 |
+
"\"\"\"\n",
|
1855 |
+
"\n",
|
1856 |
+
"display_chat(prompt, user_message, label=\"Good, includes context about the topic and a known list of vocabulary words. Can the LLM come up with those words though?\")"
|
1857 |
+
]
|
1858 |
}
|
1859 |
],
|
1860 |
"metadata": {
|
07_software_engineering_applied_to_llms.ipynb
CHANGED
@@ -18,217 +18,526 @@
|
|
18 |
{
|
19 |
"cell_type": "markdown",
|
20 |
"id": "02d71e5e",
|
21 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
22 |
"source": [
|
23 |
-
"
|
24 |
]
|
25 |
},
|
26 |
{
|
27 |
"cell_type": "markdown",
|
28 |
-
"id": "
|
29 |
"metadata": {
|
30 |
"slideshow": {
|
31 |
-
"slide_type": "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
}
|
33 |
},
|
34 |
"source": [
|
35 |
-
"
|
36 |
-
"* Responses may not be correct or accurate, how do we increase confidence in result?\n",
|
37 |
-
"* Responses may be biased or unethical or unwanted output, how do we stop this type of output?\n",
|
38 |
-
"* User requests could be unethical or unwanted input, how do we filter this type of input?\n"
|
39 |
]
|
40 |
},
|
41 |
{
|
42 |
"cell_type": "markdown",
|
43 |
"id": "5ef5865b",
|
44 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
45 |
"source": [
|
46 |
"## Lessons from Software Engineering Applied to LLMS:"
|
47 |
]
|
48 |
},
|
49 |
{
|
50 |
"cell_type": "markdown",
|
51 |
-
"id": "
|
52 |
"metadata": {
|
53 |
"slideshow": {
|
54 |
"slide_type": "slide"
|
55 |
}
|
56 |
},
|
57 |
"source": [
|
58 |
-
"
|
59 |
-
|
60 |
-
|
61 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
]
|
63 |
},
|
64 |
{
|
65 |
"cell_type": "markdown",
|
66 |
-
"id": "
|
67 |
"metadata": {
|
68 |
"slideshow": {
|
69 |
"slide_type": "slide"
|
70 |
}
|
71 |
},
|
72 |
"source": [
|
73 |
-
"
|
74 |
-
"* Unit test prompts using traditional methods to increase confidence.\n",
|
75 |
-
"* Unit test your prompts using LLMs to increase confidence.\n",
|
76 |
-
"* Write tests that handle API errors or bad output (malformed, incorrect, unethical).\n",
|
77 |
-
"* Use 'mocking' in integration tests to avoid unnecessary calls to APIs, flakiness, and unwanted charges."
|
78 |
]
|
79 |
},
|
80 |
{
|
81 |
"cell_type": "markdown",
|
82 |
-
"id": "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
83 |
"metadata": {
|
84 |
"slideshow": {
|
85 |
"slide_type": "slide"
|
86 |
}
|
87 |
},
|
88 |
"source": [
|
89 |
-
"
|
90 |
-
|
91 |
-
|
92 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
93 |
]
|
94 |
},
|
95 |
{
|
96 |
"cell_type": "markdown",
|
97 |
-
"id": "
|
98 |
"metadata": {
|
99 |
"slideshow": {
|
100 |
"slide_type": "slide"
|
101 |
}
|
102 |
},
|
103 |
"source": [
|
104 |
-
"
|
105 |
-
|
106 |
-
|
107 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
108 |
]
|
109 |
},
|
110 |
{
|
111 |
"cell_type": "markdown",
|
112 |
-
"id": "
|
113 |
"metadata": {
|
114 |
"slideshow": {
|
115 |
"slide_type": "slide"
|
116 |
}
|
117 |
},
|
118 |
"source": [
|
119 |
-
"
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
]
|
125 |
},
|
126 |
{
|
127 |
"cell_type": "markdown",
|
128 |
-
"id": "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
129 |
"metadata": {
|
130 |
"slideshow": {
|
131 |
"slide_type": "slide"
|
132 |
}
|
133 |
},
|
134 |
"source": [
|
135 |
-
"
|
136 |
-
"* **Do not:** store API keys in application code as strings, encrypted or not.\n",
|
137 |
-
"* **Do not:** store API keys in compiled binaries distributed to users.\n",
|
138 |
-
"* **Do not:** store API keys in metadeta files bundled with your application.\n",
|
139 |
-
"* **Do:** store API keys in environment variables or cloud secrets.\n",
|
140 |
-
"* **Do:** store API keys in a `.env` file that is blocked from version control. (Ideally these are encrypted with a secret that is not in version control, but that is beyond the scope of today's discussion.)\n",
|
141 |
-
"* **Do:** create an intermediate web app (or API) with authentication/authorization that delegates requests to LLMs at run-time for use in front-end applications.\n",
|
142 |
-
"* **Do:** if your front-end application does not have user accounts, consider implementing guest or anonymous accounts and expiring or rotating keys.\n",
|
143 |
-
"* **Do:** when allowing LLMs to use tools, consider designing systems to pass-through user ids to tools so that they tools operate at the same level of access as the end-user."
|
144 |
]
|
145 |
},
|
146 |
{
|
147 |
"cell_type": "markdown",
|
148 |
-
"id": "
|
149 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
150 |
"source": [
|
151 |
-
"
|
152 |
]
|
153 |
},
|
154 |
{
|
155 |
"cell_type": "markdown",
|
156 |
-
"id": "
|
157 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
158 |
"source": [
|
159 |
-
"
|
160 |
-
" - For example: Django, Flask, FastAPI, Express.js, Sinatra, Ruby on Rails"
|
161 |
]
|
162 |
},
|
163 |
{
|
164 |
"cell_type": "markdown",
|
165 |
-
"id": "
|
166 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
167 |
"source": [
|
168 |
-
"
|
169 |
-
" - Regulation may require specific data handling and storage practices.\n",
|
170 |
-
" - Cloud providers may offer compliance certifications and assessment tools.\n",
|
171 |
-
" - On-prem deployments can provide more control of data storage and processing, but might require more resources (hardware, people, software) for management and maintenance\n",
|
172 |
-
" - Cloud providers like Azure have great tools like Azure Defender for Cloud and Microsoft Purview for managing compliance"
|
173 |
]
|
174 |
},
|
175 |
{
|
176 |
"cell_type": "markdown",
|
177 |
-
"id": "
|
178 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
179 |
"source": [
|
180 |
-
"
|
181 |
-
" - Cloud services offer many advantages such as scalability, flexibilitiy, cost-effectiveness, and ease of management.\n",
|
182 |
-
" - Easy to spin up resources and scale based on demand, without worrying about infrastructure or maintenance.\n",
|
183 |
-
" - Wide range of tools: performance optimization, monitoring, security, reliability."
|
184 |
]
|
185 |
},
|
186 |
{
|
187 |
"cell_type": "markdown",
|
188 |
-
"id": "
|
189 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
190 |
"source": [
|
191 |
-
"
|
192 |
-
" - Containerization is a lightweight virtualization method that packages an application and its dependencies into a single, portable unit called a container.\n",
|
193 |
-
" - Containers can run consistently across different environments, making it easier to develop, test, and deploy applications. \n",
|
194 |
-
" - Containerization is useful when you need to ensure consistent behavior across various platforms, simplify deployment and scaling, and improve resource utilization.\n",
|
195 |
-
" - Common tools for deploying container-based architecture are Docker and Kubernetes."
|
196 |
]
|
197 |
},
|
198 |
{
|
199 |
"cell_type": "markdown",
|
200 |
-
"id": "
|
201 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
202 |
"source": [
|
203 |
-
"
|
204 |
-
"
|
205 |
-
"
|
206 |
-
"
|
207 |
-
"
|
208 |
]
|
209 |
},
|
210 |
{
|
211 |
"cell_type": "markdown",
|
212 |
-
"id": "
|
213 |
-
"metadata": {
|
|
|
|
|
|
|
|
|
214 |
"source": [
|
215 |
-
"-
|
216 |
-
"
|
217 |
-
"
|
218 |
-
"
|
219 |
]
|
220 |
},
|
221 |
{
|
222 |
-
"cell_type": "
|
223 |
-
"
|
224 |
-
"
|
225 |
-
|
226 |
-
|
227 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
228 |
}
|
229 |
],
|
230 |
"metadata": {
|
231 |
-
"celltoolbar": "
|
232 |
"kernelspec": {
|
233 |
"display_name": "Python 3 (ipykernel)",
|
234 |
"language": "python",
|
|
|
18 |
{
|
19 |
"cell_type": "markdown",
|
20 |
"id": "02d71e5e",
|
21 |
+
"metadata": {
|
22 |
+
"slideshow": {
|
23 |
+
"slide_type": "slide"
|
24 |
+
}
|
25 |
+
},
|
26 |
"source": [
|
27 |
+
"#### 🔍 Concerns with Quality and Performance Issues of LLM Integrated Apps"
|
28 |
]
|
29 |
},
|
30 |
{
|
31 |
"cell_type": "markdown",
|
32 |
+
"id": "449db7d4",
|
33 |
"metadata": {
|
34 |
"slideshow": {
|
35 |
+
"slide_type": "fragment"
|
36 |
+
}
|
37 |
+
},
|
38 |
+
"source": [
|
39 |
+
"❓ **Accuracy** - How do we boost confidence, correctness, and quality in outputs?"
|
40 |
+
]
|
41 |
+
},
|
42 |
+
{
|
43 |
+
"cell_type": "markdown",
|
44 |
+
"id": "d86252a4",
|
45 |
+
"metadata": {
|
46 |
+
"slideshow": {
|
47 |
+
"slide_type": "fragment"
|
48 |
+
}
|
49 |
+
},
|
50 |
+
"source": [
|
51 |
+
"❓ **Validation & Verification** - How do we know we built the right thing? How do we know we built the thing right?"
|
52 |
+
]
|
53 |
+
},
|
54 |
+
{
|
55 |
+
"cell_type": "markdown",
|
56 |
+
"id": "681ffe8e",
|
57 |
+
"metadata": {
|
58 |
+
"slideshow": {
|
59 |
+
"slide_type": "fragment"
|
60 |
+
}
|
61 |
+
},
|
62 |
+
"source": [
|
63 |
+
"❓ **Bias and Ethics** - How do we minimize harmful output?"
|
64 |
+
]
|
65 |
+
},
|
66 |
+
{
|
67 |
+
"cell_type": "markdown",
|
68 |
+
"id": "441d106d",
|
69 |
+
"metadata": {
|
70 |
+
"slideshow": {
|
71 |
+
"slide_type": "fragment"
|
72 |
}
|
73 |
},
|
74 |
"source": [
|
75 |
+
"❓ **How** does traditional software engineering practices relate to LLM prompts and systems?"
|
|
|
|
|
|
|
76 |
]
|
77 |
},
|
78 |
{
|
79 |
"cell_type": "markdown",
|
80 |
"id": "5ef5865b",
|
81 |
+
"metadata": {
|
82 |
+
"slideshow": {
|
83 |
+
"slide_type": "slide"
|
84 |
+
}
|
85 |
+
},
|
86 |
"source": [
|
87 |
"## Lessons from Software Engineering Applied to LLMS:"
|
88 |
]
|
89 |
},
|
90 |
{
|
91 |
"cell_type": "markdown",
|
92 |
+
"id": "651ed117",
|
93 |
"metadata": {
|
94 |
"slideshow": {
|
95 |
"slide_type": "slide"
|
96 |
}
|
97 |
},
|
98 |
"source": [
|
99 |
+
"### 🎯 Agile & Iterative Design:"
|
100 |
+
]
|
101 |
+
},
|
102 |
+
{
|
103 |
+
"cell_type": "markdown",
|
104 |
+
"id": "d784a289",
|
105 |
+
"metadata": {
|
106 |
+
"slideshow": {
|
107 |
+
"slide_type": "fragment"
|
108 |
+
}
|
109 |
+
},
|
110 |
+
"source": [
|
111 |
+
"🔸 **Rapid prompt prototyping** - Engage customers/stakeholders early on validate you are building the right prompts"
|
112 |
+
]
|
113 |
+
},
|
114 |
+
{
|
115 |
+
"cell_type": "markdown",
|
116 |
+
"id": "907c5e83",
|
117 |
+
"metadata": {
|
118 |
+
"slideshow": {
|
119 |
+
"slide_type": "fragment"
|
120 |
+
}
|
121 |
+
},
|
122 |
+
"source": [
|
123 |
+
"🔸 **Real-world examples** - Test and iterate quickly against examples that simulate real-world inputs from users. Consider edge-cases early"
|
124 |
+
]
|
125 |
+
},
|
126 |
+
{
|
127 |
+
"cell_type": "markdown",
|
128 |
+
"id": "3392caa7",
|
129 |
+
"metadata": {
|
130 |
+
"slideshow": {
|
131 |
+
"slide_type": "fragment"
|
132 |
+
}
|
133 |
+
},
|
134 |
+
"source": [
|
135 |
+
"🔸 **Collaborate** - Discuss and plan ahead how you might get access to external data sources or integrate into other systems"
|
136 |
]
|
137 |
},
|
138 |
{
|
139 |
"cell_type": "markdown",
|
140 |
+
"id": "4aa1c373",
|
141 |
"metadata": {
|
142 |
"slideshow": {
|
143 |
"slide_type": "slide"
|
144 |
}
|
145 |
},
|
146 |
"source": [
|
147 |
+
"### 📏 Testing:"
|
|
|
|
|
|
|
|
|
148 |
]
|
149 |
},
|
150 |
{
|
151 |
"cell_type": "markdown",
|
152 |
+
"id": "d40f58cf",
|
153 |
+
"metadata": {
|
154 |
+
"slideshow": {
|
155 |
+
"slide_type": "fragment"
|
156 |
+
}
|
157 |
+
},
|
158 |
+
"source": [
|
159 |
+
"✅ Unit test your prompts with traditional test frameworks"
|
160 |
+
]
|
161 |
+
},
|
162 |
+
{
|
163 |
+
"cell_type": "markdown",
|
164 |
+
"id": "1e0c1912",
|
165 |
+
"metadata": {
|
166 |
+
"slideshow": {
|
167 |
+
"slide_type": "fragment"
|
168 |
+
}
|
169 |
+
},
|
170 |
+
"source": [
|
171 |
+
"✅ Leverage LLMs for non-deterministic unit testing and generating example data"
|
172 |
+
]
|
173 |
+
},
|
174 |
+
{
|
175 |
+
"cell_type": "markdown",
|
176 |
+
"id": "98b83f99",
|
177 |
+
"metadata": {
|
178 |
+
"slideshow": {
|
179 |
+
"slide_type": "fragment"
|
180 |
+
}
|
181 |
+
},
|
182 |
+
"source": [
|
183 |
+
"✅ Handle API errors, bad output, and harmful output as part of your testing suite, CI practices, and team workflow"
|
184 |
+
]
|
185 |
+
},
|
186 |
+
{
|
187 |
+
"cell_type": "markdown",
|
188 |
+
"id": "be00ab2a",
|
189 |
+
"metadata": {
|
190 |
+
"slideshow": {
|
191 |
+
"slide_type": "fragment"
|
192 |
+
}
|
193 |
+
},
|
194 |
+
"source": [
|
195 |
+
"✅ Use mocking to prevent unwanted API calls in integration tests (and save money!)"
|
196 |
+
]
|
197 |
+
},
|
198 |
+
{
|
199 |
+
"cell_type": "markdown",
|
200 |
+
"id": "adb5e77a",
|
201 |
"metadata": {
|
202 |
"slideshow": {
|
203 |
"slide_type": "slide"
|
204 |
}
|
205 |
},
|
206 |
"source": [
|
207 |
+
"### 🔄 Handling Bad Output:"
|
208 |
+
]
|
209 |
+
},
|
210 |
+
{
|
211 |
+
"cell_type": "markdown",
|
212 |
+
"id": "aceb00b5",
|
213 |
+
"metadata": {
|
214 |
+
"slideshow": {
|
215 |
+
"slide_type": "fragment"
|
216 |
+
}
|
217 |
+
},
|
218 |
+
"source": [
|
219 |
+
"💡 **Error handing** - Recover from unwanted output or incorrect output with robust retry mechanisms"
|
220 |
+
]
|
221 |
+
},
|
222 |
+
{
|
223 |
+
"cell_type": "markdown",
|
224 |
+
"id": "252c7d5b",
|
225 |
+
"metadata": {
|
226 |
+
"slideshow": {
|
227 |
+
"slide_type": "fragment"
|
228 |
+
}
|
229 |
+
},
|
230 |
+
"source": [
|
231 |
+
"💡 **Customized retry prompts** - Guide the LLM with custom prompts that include the desired goal, the output, and the error."
|
232 |
+
]
|
233 |
+
},
|
234 |
+
{
|
235 |
+
"cell_type": "markdown",
|
236 |
+
"id": "374eb0be",
|
237 |
+
"metadata": {
|
238 |
+
"slideshow": {
|
239 |
+
"slide_type": "fragment"
|
240 |
+
}
|
241 |
+
},
|
242 |
+
"source": [
|
243 |
+
"💡 **Logging and Monitoring** - Track output quality, malicious input, and harmful output."
|
244 |
+
]
|
245 |
+
},
|
246 |
+
{
|
247 |
+
"cell_type": "markdown",
|
248 |
+
"id": "95af337f",
|
249 |
+
"metadata": {
|
250 |
+
"slideshow": {
|
251 |
+
"slide_type": "slide"
|
252 |
+
}
|
253 |
+
},
|
254 |
+
"source": [
|
255 |
+
"### 📚 Template Languages & Version Control:"
|
256 |
+
]
|
257 |
+
},
|
258 |
+
{
|
259 |
+
"cell_type": "markdown",
|
260 |
+
"id": "2972ba3f",
|
261 |
+
"metadata": {
|
262 |
+
"slideshow": {
|
263 |
+
"slide_type": "fragment"
|
264 |
+
}
|
265 |
+
},
|
266 |
+
"source": [
|
267 |
+
"📝 **Dynamic template languages** - Use templating engines like ERB, Handlebars, etc for dynamically building prompts and leveraging existing testing tools"
|
268 |
+
]
|
269 |
+
},
|
270 |
+
{
|
271 |
+
"cell_type": "markdown",
|
272 |
+
"id": "4f44c1c4",
|
273 |
+
"metadata": {
|
274 |
+
"slideshow": {
|
275 |
+
"slide_type": "fragment"
|
276 |
+
}
|
277 |
+
},
|
278 |
+
"source": [
|
279 |
+
"📝 **Version control** - Manage prompt templates in the app's repo"
|
280 |
+
]
|
281 |
+
},
|
282 |
+
{
|
283 |
+
"cell_type": "markdown",
|
284 |
+
"id": "642bd8ae",
|
285 |
+
"metadata": {
|
286 |
+
"slideshow": {
|
287 |
+
"slide_type": "fragment"
|
288 |
+
}
|
289 |
+
},
|
290 |
+
"source": [
|
291 |
+
"📝 **Team Policy / Code Review** - Develop expectations and team practices around managing changes to prompts"
|
292 |
]
|
293 |
},
|
294 |
{
|
295 |
"cell_type": "markdown",
|
296 |
+
"id": "e91111a4",
|
297 |
"metadata": {
|
298 |
"slideshow": {
|
299 |
"slide_type": "slide"
|
300 |
}
|
301 |
},
|
302 |
"source": [
|
303 |
+
"### 💉 Prompt Injection/Leakage:"
|
304 |
+
]
|
305 |
+
},
|
306 |
+
{
|
307 |
+
"cell_type": "markdown",
|
308 |
+
"id": "db84eff5",
|
309 |
+
"metadata": {
|
310 |
+
"slideshow": {
|
311 |
+
"slide_type": "fragment"
|
312 |
+
}
|
313 |
+
},
|
314 |
+
"source": [
|
315 |
+
"🔐 Test for prompt injection attacks"
|
316 |
+
]
|
317 |
+
},
|
318 |
+
{
|
319 |
+
"cell_type": "markdown",
|
320 |
+
"id": "99a6f711",
|
321 |
+
"metadata": {
|
322 |
+
"slideshow": {
|
323 |
+
"slide_type": "fragment"
|
324 |
+
}
|
325 |
+
},
|
326 |
+
"source": [
|
327 |
+
"🔐 Validate input at UI and LLM level"
|
328 |
+
]
|
329 |
+
},
|
330 |
+
{
|
331 |
+
"cell_type": "markdown",
|
332 |
+
"id": "df148645",
|
333 |
+
"metadata": {
|
334 |
+
"slideshow": {
|
335 |
+
"slide_type": "fragment"
|
336 |
+
}
|
337 |
+
},
|
338 |
+
"source": [
|
339 |
+
"🔐 Use LLMs to analyze input/output similarity to known prompt injection attacks and/or the prompt itself"
|
340 |
+
]
|
341 |
+
},
|
342 |
+
{
|
343 |
+
"cell_type": "markdown",
|
344 |
+
"id": "d6885dd4",
|
345 |
+
"metadata": {
|
346 |
+
"slideshow": {
|
347 |
+
"slide_type": "fragment"
|
348 |
+
}
|
349 |
+
},
|
350 |
+
"source": [
|
351 |
+
"🔐 Implement anomaly detection & incident response"
|
352 |
]
|
353 |
},
|
354 |
{
|
355 |
"cell_type": "markdown",
|
356 |
+
"id": "e6b3ef98",
|
357 |
"metadata": {
|
358 |
"slideshow": {
|
359 |
"slide_type": "slide"
|
360 |
}
|
361 |
},
|
362 |
"source": [
|
363 |
+
"### 🔒 Security (Do Not):"
|
364 |
+
]
|
365 |
+
},
|
366 |
+
{
|
367 |
+
"cell_type": "markdown",
|
368 |
+
"id": "2b79206c",
|
369 |
+
"metadata": {
|
370 |
+
"slideshow": {
|
371 |
+
"slide_type": "fragment"
|
372 |
+
}
|
373 |
+
},
|
374 |
+
"source": [
|
375 |
+
"🚫 Avoid storing API keys in app code, binaries, or metadata files"
|
376 |
]
|
377 |
},
|
378 |
{
|
379 |
"cell_type": "markdown",
|
380 |
+
"id": "2b33263f",
|
381 |
+
"metadata": {
|
382 |
+
"slideshow": {
|
383 |
+
"slide_type": "fragment"
|
384 |
+
}
|
385 |
+
},
|
386 |
+
"source": [
|
387 |
+
"🚫 Give LLM access to tools with higher privileges than the users themselves!"
|
388 |
+
]
|
389 |
+
},
|
390 |
+
{
|
391 |
+
"cell_type": "markdown",
|
392 |
+
"id": "1b4e2040",
|
393 |
"metadata": {
|
394 |
"slideshow": {
|
395 |
"slide_type": "slide"
|
396 |
}
|
397 |
},
|
398 |
"source": [
|
399 |
+
"### 🔒 Security (Do):"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
400 |
]
|
401 |
},
|
402 |
{
|
403 |
"cell_type": "markdown",
|
404 |
+
"id": "5cdf282f",
|
405 |
+
"metadata": {
|
406 |
+
"slideshow": {
|
407 |
+
"slide_type": "fragment"
|
408 |
+
}
|
409 |
+
},
|
410 |
"source": [
|
411 |
+
"✅ Store API keys in environment variables or cloud secrets"
|
412 |
]
|
413 |
},
|
414 |
{
|
415 |
"cell_type": "markdown",
|
416 |
+
"id": "8093990a",
|
417 |
+
"metadata": {
|
418 |
+
"slideshow": {
|
419 |
+
"slide_type": "fragment"
|
420 |
+
}
|
421 |
+
},
|
422 |
"source": [
|
423 |
+
"✅ Block files containing secrets from entering version control by adding them to `.gitignore`"
|
|
|
424 |
]
|
425 |
},
|
426 |
{
|
427 |
"cell_type": "markdown",
|
428 |
+
"id": "8b19f8e4",
|
429 |
+
"metadata": {
|
430 |
+
"slideshow": {
|
431 |
+
"slide_type": "fragment"
|
432 |
+
}
|
433 |
+
},
|
434 |
"source": [
|
435 |
+
"✅ Use intermediate web apps/APIs with authentication/authorization for accessing LLM features"
|
|
|
|
|
|
|
|
|
436 |
]
|
437 |
},
|
438 |
{
|
439 |
"cell_type": "markdown",
|
440 |
+
"id": "5ce316c7",
|
441 |
+
"metadata": {
|
442 |
+
"slideshow": {
|
443 |
+
"slide_type": "fragment"
|
444 |
+
}
|
445 |
+
},
|
446 |
"source": [
|
447 |
+
"✅ Implement transparent guest/anonymous accounts & key rotation when apps don't require authentication to use LLM features"
|
|
|
|
|
|
|
448 |
]
|
449 |
},
|
450 |
{
|
451 |
"cell_type": "markdown",
|
452 |
+
"id": "9d3ef132",
|
453 |
+
"metadata": {
|
454 |
+
"slideshow": {
|
455 |
+
"slide_type": "skip"
|
456 |
+
}
|
457 |
+
},
|
458 |
"source": [
|
459 |
+
"## Production Deployment Considerations"
|
|
|
|
|
|
|
|
|
460 |
]
|
461 |
},
|
462 |
{
|
463 |
"cell_type": "markdown",
|
464 |
+
"id": "a480904f",
|
465 |
+
"metadata": {
|
466 |
+
"slideshow": {
|
467 |
+
"slide_type": "skip"
|
468 |
+
}
|
469 |
+
},
|
470 |
+
"source": [
|
471 |
+
"#### Wrap LLM features as web service or API. Don't give out your OpenAI keys directly in distributed software.\n",
|
472 |
+
"* For example: Django, Flask, FastAPI, Express.js, Sinatra, Ruby on Rails"
|
473 |
+
]
|
474 |
+
},
|
475 |
+
{
|
476 |
+
"cell_type": "markdown",
|
477 |
+
"id": "e6274d71",
|
478 |
+
"metadata": {
|
479 |
+
"slideshow": {
|
480 |
+
"slide_type": "skip"
|
481 |
+
}
|
482 |
+
},
|
483 |
"source": [
|
484 |
+
"#### Consider whether there are any regulations that might impact how you handle data, such as GDPR and HIPAA.\n",
|
485 |
+
"- Regulation may require specific data handling and storage practices.\n",
|
486 |
+
"- Cloud providers may offer compliance certifications and assessment tools.\n",
|
487 |
+
"- On-prem deployments can provide more control of data storage and processing, but might require more resources (hardware, people, software) for management and maintenance\n",
|
488 |
+
"- Cloud providers like Azure have great tools like Azure Defender for Cloud and Microsoft Purview for managing compliance"
|
489 |
]
|
490 |
},
|
491 |
{
|
492 |
"cell_type": "markdown",
|
493 |
+
"id": "2f9b5cf9",
|
494 |
+
"metadata": {
|
495 |
+
"slideshow": {
|
496 |
+
"slide_type": "skip"
|
497 |
+
}
|
498 |
+
},
|
499 |
"source": [
|
500 |
+
"#### Using Cloud Services vs On-Prem\n",
|
501 |
+
"- Cloud services offer many advantages such as scalability, flexibilitiy, cost-effectiveness, and ease of management.\n",
|
502 |
+
"- Easy to spin up resources and scale based on demand, without worrying about infrastructure or maintenance.\n",
|
503 |
+
"- Wide range of tools: performance optimization, monitoring, security, reliability."
|
504 |
]
|
505 |
},
|
506 |
{
|
507 |
+
"cell_type": "markdown",
|
508 |
+
"id": "17111661",
|
509 |
+
"metadata": {
|
510 |
+
"slideshow": {
|
511 |
+
"slide_type": "skip"
|
512 |
+
}
|
513 |
+
},
|
514 |
+
"source": [
|
515 |
+
"#### Container-based Architecture\n",
|
516 |
+
"- Containerization is a lightweight virtualization method that packages an application and its dependencies into a single, portable unit called a container.\n",
|
517 |
+
"- Containers can run consistently across different environments, making it easier to develop, test, and deploy applications. \n",
|
518 |
+
"- Containerization is useful when you need to ensure consistent behavior across various platforms, simplify deployment and scaling, and improve resource utilization.\n",
|
519 |
+
"- Common tools for deploying container-based architecture are Docker and Kubernetes."
|
520 |
+
]
|
521 |
+
},
|
522 |
+
{
|
523 |
+
"cell_type": "markdown",
|
524 |
+
"id": "56890eec",
|
525 |
+
"metadata": {
|
526 |
+
"slideshow": {
|
527 |
+
"slide_type": "skip"
|
528 |
+
}
|
529 |
+
},
|
530 |
+
"source": [
|
531 |
+
"#### Serverless Architectures\n",
|
532 |
+
"- Serverless architectures are a cloud computing model where the cloud provider manages the infrastructure and automatically allocates resources based on the application's needs.\n",
|
533 |
+
"- Developers only need to focus on writing code, and the provider takes care of scaling, patching, and maintaining the underlying infrastructure. \n",
|
534 |
+
"- Serverless architectures can be useful when you want to reduce operational overhead, build event-driven applications, and optimize costs by paying only for the resources you actually use.\n",
|
535 |
+
"- Common tools to build serverless applications and APIs include Azure Functions, AWS Lambda, and Google Cloud Functions."
|
536 |
+
]
|
537 |
}
|
538 |
],
|
539 |
"metadata": {
|
540 |
+
"celltoolbar": "Slideshow",
|
541 |
"kernelspec": {
|
542 |
"display_name": "Python 3 (ipykernel)",
|
543 |
"language": "python",
|
images/access-tokens.png
ADDED
images/add-secret.png
ADDED
images/copy-token.png
ADDED
images/dropdown.png
ADDED
images/new-access-token.png
ADDED
images/profile-settings.png
ADDED
images/repo.png
ADDED
images/restart.png
ADDED
images/secrets.png
ADDED
images/signup.png
ADDED
images/space-settings.png
ADDED