Jofthomas HF staff commited on
Commit
c187244
·
verified ·
1 Parent(s): bee59ac

Upload agent.ipynb

Browse files
Files changed (1) hide show
  1. unit2/langgraph/agent.ipynb +560 -0
unit2/langgraph/agent.ipynb ADDED
@@ -0,0 +1,560 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "98f5e36a-da49-4ae2-8c74-b910a2f992fc",
6
+ "metadata": {},
7
+ "source": [
8
+ "# Agent\n",
9
+ "\n",
10
+ "In this notebook, **we're going to build a simple agent using using LangGraph**.\n",
11
+ "\n",
12
+ "This notebook is part of the <a href=\"https://www.hf.co/learn/agents-course\">Hugging Face Agents Course</a>, a free course from beginner to expert, where you learn to build Agents.\n",
13
+ "\n",
14
+ "![Agents course share](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/communication/share.png)\n",
15
+ "\n",
16
+ "As seen in the Unit 1, an agent needs 3 steps as introduced in the ReAct architecture :\n",
17
+ "[ReAct](https://react-lm.github.io/), a general agent architecture.\n",
18
+ " \n",
19
+ "* `act` - let the model call specific tools \n",
20
+ "* `observe` - pass the tool output back to the model \n",
21
+ "* `reason` - let the model reason about the tool output to decide what to do next (e.g., call another tool or just respond directly)\n",
22
+ "\n",
23
+ "\n",
24
+ "![Agent](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/LangGraph/Agent.png)"
25
+ ]
26
+ },
27
+ {
28
+ "cell_type": "code",
29
+ "execution_count": 1,
30
+ "id": "63edff5a-724b-474d-9db8-37f0ae936c76",
31
+ "metadata": {
32
+ "tags": []
33
+ },
34
+ "outputs": [
35
+ {
36
+ "name": "stdout",
37
+ "output_type": "stream",
38
+ "text": [
39
+ "Note: you may need to restart the kernel to use updated packages.\n"
40
+ ]
41
+ }
42
+ ],
43
+ "source": [
44
+ "%pip install -q -U langchain_openai langchain_core langgraph"
45
+ ]
46
+ },
47
+ {
48
+ "cell_type": "code",
49
+ "execution_count": 2,
50
+ "id": "356a6482",
51
+ "metadata": {
52
+ "tags": []
53
+ },
54
+ "outputs": [],
55
+ "source": [
56
+ "import os\n",
57
+ "\n",
58
+ "# Please setp your own key.\n",
59
+ "os.environ[\"OPENAI_API_KEY\"]=\"sk-xxxxxx\""
60
+ ]
61
+ },
62
+ {
63
+ "cell_type": "code",
64
+ "execution_count": 65,
65
+ "id": "71795ff1-d6a7-448d-8b55-88bbd1ed3dbe",
66
+ "metadata": {
67
+ "tags": []
68
+ },
69
+ "outputs": [],
70
+ "source": [
71
+ "import base64\n",
72
+ "from typing import List\n",
73
+ "from langchain.schema import HumanMessage\n",
74
+ "from langchain_openai import ChatOpenAI\n",
75
+ "\n",
76
+ "\n",
77
+ "vision_llm = ChatOpenAI(model=\"gpt-4o\")\n",
78
+ "\n",
79
+ "def extract_text(img_path: str) -> str:\n",
80
+ " \"\"\"\n",
81
+ " Extract text from an image file using a multimodal model.\n",
82
+ "\n",
83
+ " Args:\n",
84
+ " img_path: A local image file path (strings).\n",
85
+ "\n",
86
+ " Returns:\n",
87
+ " A single string containing the concatenated text extracted from each image.\n",
88
+ " \"\"\"\n",
89
+ " all_text = \"\"\n",
90
+ " try:\n",
91
+ " \n",
92
+ " # Read image and encode as base64\n",
93
+ " with open(img_path, \"rb\") as image_file:\n",
94
+ " image_bytes = image_file.read()\n",
95
+ "\n",
96
+ " image_base64 = base64.b64encode(image_bytes).decode(\"utf-8\")\n",
97
+ "\n",
98
+ " # Prepare the prompt including the base64 image data\n",
99
+ " message = [\n",
100
+ " HumanMessage(\n",
101
+ " content=[\n",
102
+ " {\n",
103
+ " \"type\": \"text\",\n",
104
+ " \"text\": (\n",
105
+ " \"Extract all the text from this image. \"\n",
106
+ " \"Return only the extracted text, no explanations.\"\n",
107
+ " ),\n",
108
+ " },\n",
109
+ " {\n",
110
+ " \"type\": \"image_url\",\n",
111
+ " \"image_url\": {\n",
112
+ " \"url\": f\"data:image/png;base64,{image_base64}\"\n",
113
+ " },\n",
114
+ " },\n",
115
+ " ]\n",
116
+ " )\n",
117
+ " ]\n",
118
+ "\n",
119
+ " # Call the vision-capable model\n",
120
+ " response = vision_llm.invoke(message)\n",
121
+ "\n",
122
+ " # Append extracted text\n",
123
+ " all_text += response.content + \"\\n\\n\"\n",
124
+ "\n",
125
+ " return all_text.strip()\n",
126
+ " except Exception as e:\n",
127
+ " # You can choose whether to raise or just return an empty string / error message\n",
128
+ " error_msg = f\"Error extracting text: {str(e)}\"\n",
129
+ " print(error_msg)\n",
130
+ " return \"\"\n",
131
+ "\n",
132
+ "llm = ChatOpenAI(model=\"gpt-4o\")\n",
133
+ "\n",
134
+ "def divide(a: int, b: int) -> float:\n",
135
+ " \"\"\"Divide a and b.\"\"\"\n",
136
+ " return a / b\n",
137
+ "\n",
138
+ "tools = [\n",
139
+ " divide,\n",
140
+ " extract_text\n",
141
+ "]\n",
142
+ "llm_with_tools = llm.bind_tools(tools, parallel_tool_calls=False)"
143
+ ]
144
+ },
145
+ {
146
+ "cell_type": "markdown",
147
+ "id": "a2cec014-3023-405c-be79-de8fc7adb346",
148
+ "metadata": {},
149
+ "source": [
150
+ "Let's create our LLM and prompt it with the overall desired agent behavior."
151
+ ]
152
+ },
153
+ {
154
+ "cell_type": "code",
155
+ "execution_count": 66,
156
+ "id": "deb674bc-49b2-485a-b0c3-4d7b05a0bfac",
157
+ "metadata": {
158
+ "tags": []
159
+ },
160
+ "outputs": [],
161
+ "source": [
162
+ "from typing import TypedDict, Annotated, List, Any, Optional\n",
163
+ "from langchain_core.messages import AnyMessage\n",
164
+ "from langgraph.graph.message import add_messages\n",
165
+ "class AgentState(TypedDict):\n",
166
+ " # The input document\n",
167
+ " input_file: Optional[str] # Contains file path, type (PNG)\n",
168
+ " messages: Annotated[list[AnyMessage], add_messages]"
169
+ ]
170
+ },
171
+ {
172
+ "cell_type": "code",
173
+ "execution_count": 76,
174
+ "id": "d061813f-ebc0-432c-91ec-3b42b15c30b6",
175
+ "metadata": {
176
+ "tags": []
177
+ },
178
+ "outputs": [],
179
+ "source": [
180
+ "from langchain_core.messages import HumanMessage, SystemMessage\n",
181
+ "from langchain_core.utils.function_calling import convert_to_openai_tool\n",
182
+ "\n",
183
+ "\n",
184
+ "# AgentState\n",
185
+ "def assistant(state: AgentState):\n",
186
+ " # System message\n",
187
+ " textual_description_of_tool=\"\"\"\n",
188
+ "extract_text(img_path: str) -> str:\n",
189
+ " Extract text from an image file using a multimodal model.\n",
190
+ "\n",
191
+ " Args:\n",
192
+ " img_path: A local image file path (strings).\n",
193
+ "\n",
194
+ " Returns:\n",
195
+ " A single string containing the concatenated text extracted from each image.\n",
196
+ "divide(a: int, b: int) -> float:\n",
197
+ " Divide a and b\n",
198
+ "\"\"\"\n",
199
+ " image=state[\"input_file\"]\n",
200
+ " sys_msg = SystemMessage(content=f\"You are an helpful agent that can analyse some images and run some computatio without provided tools :\\n{textual_description_of_tool} \\n You have access to some otpional images. Currently the loaded images is : {image}\")\n",
201
+ "\n",
202
+ "\n",
203
+ " return {\"messages\": [llm_with_tools.invoke([sys_msg] + state[\"messages\"])],\"input_file\":state[\"input_file\"]}"
204
+ ]
205
+ },
206
+ {
207
+ "cell_type": "markdown",
208
+ "id": "4eb43343-9a6f-42cb-86e6-4380f928633c",
209
+ "metadata": {},
210
+ "source": [
211
+ "We define a `Tools` node with our list of tools.\n",
212
+ "\n",
213
+ "The `Assistant` node is just our model with bound tools.\n",
214
+ "\n",
215
+ "We create a graph with `Assistant` and `Tools` nodes.\n",
216
+ "\n",
217
+ "We add `tools_condition` edge, which routes to `End` or to `Tools` based on whether the `Assistant` calls a tool.\n",
218
+ "\n",
219
+ "Now, we add one new step:\n",
220
+ "\n",
221
+ "We connect the `Tools` node *back* to the `Assistant`, forming a loop.\n",
222
+ "\n",
223
+ "* After the `assistant` node executes, `tools_condition` checks if the model's output is a tool call.\n",
224
+ "* If it is a tool call, the flow is directed to the `tools` node.\n",
225
+ "* The `tools` node connects back to `assistant`.\n",
226
+ "* This loop continues as long as the model decides to call tools.\n",
227
+ "* If the model response is not a tool call, the flow is directed to END, terminating the process."
228
+ ]
229
+ },
230
+ {
231
+ "cell_type": "code",
232
+ "execution_count": 77,
233
+ "id": "aef13cd4-05a6-4084-a620-2e7b91d9a72f",
234
+ "metadata": {
235
+ "tags": []
236
+ },
237
+ "outputs": [
238
+ {
239
+ "data": {
240
+ "image/png": "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",
241
+ "text/plain": [
242
+ "<IPython.core.display.Image object>"
243
+ ]
244
+ },
245
+ "metadata": {},
246
+ "output_type": "display_data"
247
+ }
248
+ ],
249
+ "source": [
250
+ "from langgraph.graph import START, StateGraph\n",
251
+ "from langgraph.prebuilt import tools_condition\n",
252
+ "from langgraph.prebuilt import ToolNode\n",
253
+ "from IPython.display import Image, display\n",
254
+ "\n",
255
+ "# Graph\n",
256
+ "builder = StateGraph(AgentState)\n",
257
+ "\n",
258
+ "# Define nodes: these do the work\n",
259
+ "builder.add_node(\"assistant\", assistant)\n",
260
+ "builder.add_node(\"tools\", ToolNode(tools))\n",
261
+ "\n",
262
+ "# Define edges: these determine how the control flow moves\n",
263
+ "builder.add_edge(START, \"assistant\")\n",
264
+ "builder.add_conditional_edges(\n",
265
+ " \"assistant\",\n",
266
+ " # If the latest message (result) from assistant is a tool call -> tools_condition routes to tools\n",
267
+ " # If the latest message (result) from assistant is a not a tool call -> tools_condition routes to END\n",
268
+ " tools_condition,\n",
269
+ ")\n",
270
+ "builder.add_edge(\"tools\", \"assistant\")\n",
271
+ "react_graph = builder.compile()\n",
272
+ "\n",
273
+ "# Show\n",
274
+ "display(Image(react_graph.get_graph(xray=True).draw_mermaid_png()))"
275
+ ]
276
+ },
277
+ {
278
+ "cell_type": "code",
279
+ "execution_count": 78,
280
+ "id": "75602459-d8ca-47b4-9518-3f38343ebfe4",
281
+ "metadata": {
282
+ "tags": []
283
+ },
284
+ "outputs": [],
285
+ "source": [
286
+ "messages = [HumanMessage(content=\"Divide 6790 by 5\")]\n",
287
+ "\n",
288
+ "messages = react_graph.invoke({\"messages\": messages,\"input_file\":None})"
289
+ ]
290
+ },
291
+ {
292
+ "cell_type": "code",
293
+ "execution_count": 79,
294
+ "id": "b517142d-c40c-48bf-a5b8-c8409427aa79",
295
+ "metadata": {
296
+ "tags": []
297
+ },
298
+ "outputs": [
299
+ {
300
+ "name": "stdout",
301
+ "output_type": "stream",
302
+ "text": [
303
+ "================================\u001b[1m Human Message \u001b[0m=================================\n",
304
+ "\n",
305
+ "Divide 6790 by 5\n",
306
+ "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
307
+ "Tool Calls:\n",
308
+ " divide (call_s0G5ewtIQyHUCOv0fClsCpgh)\n",
309
+ " Call ID: call_s0G5ewtIQyHUCOv0fClsCpgh\n",
310
+ " Args:\n",
311
+ " a: 6790\n",
312
+ " b: 5\n",
313
+ "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
314
+ "Name: divide\n",
315
+ "\n",
316
+ "1358.0\n",
317
+ "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
318
+ "\n",
319
+ "The result of dividing 6790 by 5 is 1358.0.\n"
320
+ ]
321
+ }
322
+ ],
323
+ "source": [
324
+ "for m in messages['messages']:\n",
325
+ " m.pretty_print()"
326
+ ]
327
+ },
328
+ {
329
+ "cell_type": "markdown",
330
+ "id": "08386393-c270-43a5-bde2-2b4075238971",
331
+ "metadata": {},
332
+ "source": [
333
+ "## Training program\n",
334
+ "MR Wayne left a note with his training program for the week. I came up with a recipe for dinner leaft in a note.\n",
335
+ "\n",
336
+ "you can find the document [HERE](https://huggingface.co/datasets/agents-course/course-images/blob/main/en/unit2/LangGraph/Batman_training_and_meals.png), so download it and upload it in the local folder.\n",
337
+ "\n",
338
+ "![Training](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/LangGraph/Batman_training_and_meals.png)"
339
+ ]
340
+ },
341
+ {
342
+ "cell_type": "code",
343
+ "execution_count": 82,
344
+ "id": "f6e97e84-3b05-4aaf-a38f-1de9b73cd37f",
345
+ "metadata": {
346
+ "tags": []
347
+ },
348
+ "outputs": [],
349
+ "source": [
350
+ "messages = [HumanMessage(content=\"According the note provided by MR wayne in the provided images. What's the list of items I should buy for the dinner menu ?\")]\n",
351
+ "\n",
352
+ "messages = react_graph.invoke({\"messages\": messages,\"input_file\":\"Batman_training_and_meals.png\"})"
353
+ ]
354
+ },
355
+ {
356
+ "cell_type": "code",
357
+ "execution_count": 83,
358
+ "id": "17686d52-c7ba-407b-a13f-f6c37668e5b0",
359
+ "metadata": {
360
+ "tags": []
361
+ },
362
+ "outputs": [
363
+ {
364
+ "name": "stdout",
365
+ "output_type": "stream",
366
+ "text": [
367
+ "================================\u001b[1m Human Message \u001b[0m=================================\n",
368
+ "\n",
369
+ "According the note provided by MR wayne in the provided images. What's the list of tiems I should buy for the dinner menu ?\n",
370
+ "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
371
+ "Tool Calls:\n",
372
+ " extract_text (call_JalVBOR82hwRknFcplnLoTtG)\n",
373
+ " Call ID: call_JalVBOR82hwRknFcplnLoTtG\n",
374
+ " Args:\n",
375
+ " img_path: Batman_training_and_meals.png\n",
376
+ "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
377
+ "Name: extract_text\n",
378
+ "\n",
379
+ "TRAINING SCHEDULE\n",
380
+ "For the week of 2/20-2/26\n",
381
+ "\n",
382
+ "SUNDAY 2/20\n",
383
+ "MORNING\n",
384
+ "30 minute jog\n",
385
+ "30 minute meditation\n",
386
+ "\n",
387
+ "EVENING\n",
388
+ "clean and jerk lifts—3 reps/8 sets. 262 lbs.\n",
389
+ "5 sets metabolic conditioning:\n",
390
+ "10 mile run\n",
391
+ "12 kettlebell swings\n",
392
+ "12 pull-ups\n",
393
+ "30 minutes flexibility\n",
394
+ "30 minutes sparring\n",
395
+ "\n",
396
+ "MONDAY 2/21\n",
397
+ "MORNING\n",
398
+ "30 minute jog\n",
399
+ "30 minutes traditional kata (focus on Japanese forms)\n",
400
+ "\n",
401
+ "EVENING\n",
402
+ "5 sets 20 foot rope climb\n",
403
+ "30 minutes gymnastics (work on muscle ups in\n",
404
+ "particular)\n",
405
+ "high bar jumps—12 reps/8 sets\n",
406
+ "crunches—50 reps/5 sets\n",
407
+ "30 minutes heavy bag\n",
408
+ "30 minutes flexibility\n",
409
+ "20 minutes target practice\n",
410
+ "\n",
411
+ "TUESDAY 2/22\n",
412
+ "MORNING\n",
413
+ "30 minute jog\n",
414
+ "30 minutes yoga\n",
415
+ "\n",
416
+ "EVENING\n",
417
+ "off day\n",
418
+ "leg heavy dead lift—5 reps/7 sets. 600 lbs.\n",
419
+ "clean and jerk lift—3 reps/10 sets\n",
420
+ "30 minutes sparring\n",
421
+ "\n",
422
+ "WEDNESDAY 2/23\n",
423
+ "OFF DAY\n",
424
+ "\n",
425
+ "MORNING\n",
426
+ "20-mile run—last week’s time was 4:50 per mile.\n",
427
+ "Need to better that time by a half a minute.\n",
428
+ "\n",
429
+ "EVENING\n",
430
+ "skill training only\n",
431
+ "30 minutes yoga\n",
432
+ "30 minutes meditation\n",
433
+ "30 minutes body basics\n",
434
+ "30 minutes bow basics\n",
435
+ "30 minutes sword basics\n",
436
+ "30 minutes observational\n",
437
+ "exercise\n",
438
+ "30 minutes kata\n",
439
+ "30 minutes pressure points\n",
440
+ "30 minutes modus and pressure points\n",
441
+ "\n",
442
+ "THURSDAY 2/24\n",
443
+ "MORNING\n",
444
+ "30 minute jog\n",
445
+ "30 minute meditation\n",
446
+ "30 minutes traditional kata\n",
447
+ "(focus on Japanese forms)\n",
448
+ "\n",
449
+ "EVENING\n",
450
+ "squats—10 reps/5 sets. 525 lbs.\n",
451
+ "30 minutes flexibility\n",
452
+ "crunches—50 reps/5 sets\n",
453
+ "20 minutes target practice\n",
454
+ "30 minutes heavy bag\n",
455
+ "\n",
456
+ "FRIDAY 2/25\n",
457
+ "MORNING\n",
458
+ "30 minute jog\n",
459
+ "30 minute meditation\n",
460
+ "\n",
461
+ "EVENING\n",
462
+ "clean and jerk lifts—3 reps/8 sets. 262 lbs.\n",
463
+ "5 sets metabolic conditioning:\n",
464
+ "10 mile run\n",
465
+ "12 kettlebell swings\n",
466
+ "12 pull-ups\n",
467
+ "30 minutes flexibility\n",
468
+ "30 minutes sparring\n",
469
+ "\n",
470
+ "SATURDAY 2/26)\n",
471
+ "MORNING\n",
472
+ "30 minute jog\n",
473
+ "30 minutes yoga\n",
474
+ "\n",
475
+ "EVENING\n",
476
+ "crunches—50 reps/5 sets\n",
477
+ "squats—(5 reps/10 sets. 525 lbs.\n",
478
+ "push-ups—60 reps/sets\n",
479
+ "30 minutes monkey bars\n",
480
+ "30 minute pommel horse\n",
481
+ "30 minutes heavy bag\n",
482
+ "2 mile swim\n",
483
+ "\n",
484
+ "In an effort to inspire the all- important Dark Knight to take time out of his busy schedule and actually consume a reasonable amount of sustenance, I have taken the liberty of composing a menu for today's scheduled natal to its my hope that these elegantly prepared courses will not share the fate of their predecessors -mated cold and untouched on a computer console.\n",
485
+ "-A\n",
486
+ "\n",
487
+ "W A Y N E M A N O R\n",
488
+ "\n",
489
+ "Tuesday's Menu\n",
490
+ "\n",
491
+ "Breakfast\n",
492
+ "six poached eggs laid over artichoke bottoms with a sage pesto sauce\n",
493
+ "thinly sliced baked ham\n",
494
+ "mixed organic fresh fruit bowl\n",
495
+ "freshly squeezed orange juice\n",
496
+ "organic, grass-fed milk\n",
497
+ "4 grams branched-chain amino acid\n",
498
+ "2 grams fish oil\n",
499
+ "\n",
500
+ "Lunch\n",
501
+ "local salmon with a ginger glaze\n",
502
+ "organic asparagus with lemon garlic dusting\n",
503
+ "Asian yam soup with diced onions\n",
504
+ "2 grams fish oil\n",
505
+ "\n",
506
+ "Dinner\n",
507
+ "grass-fed local sirloin steak\n",
508
+ "bed of organic spinach and piquillo peppers\n",
509
+ "oven-baked golden herb potato\n",
510
+ "2 grams fish oil\n",
511
+ "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
512
+ "\n",
513
+ "For the dinner menu, you should buy the following items:\n",
514
+ "\n",
515
+ "1. Grass-fed local sirloin steak\n",
516
+ "2. Organic spinach\n",
517
+ "3. Piquillo peppers\n",
518
+ "4. Potatoes (for oven-baked golden herb potato)\n",
519
+ "5. Fish oil (2 grams)\n",
520
+ "\n",
521
+ "Ensure the steak is grass-fed and the spinach and peppers are organic for the best quality meal.\n"
522
+ ]
523
+ }
524
+ ],
525
+ "source": [
526
+ "for m in messages['messages']:\n",
527
+ " m.pretty_print()"
528
+ ]
529
+ },
530
+ {
531
+ "cell_type": "code",
532
+ "execution_count": null,
533
+ "id": "b96c8456-4093-4cd6-bc5a-f611967ab709",
534
+ "metadata": {},
535
+ "outputs": [],
536
+ "source": []
537
+ }
538
+ ],
539
+ "metadata": {
540
+ "kernelspec": {
541
+ "display_name": "Python 3 (ipykernel)",
542
+ "language": "python",
543
+ "name": "python3"
544
+ },
545
+ "language_info": {
546
+ "codemirror_mode": {
547
+ "name": "ipython",
548
+ "version": 3
549
+ },
550
+ "file_extension": ".py",
551
+ "mimetype": "text/x-python",
552
+ "name": "python",
553
+ "nbconvert_exporter": "python",
554
+ "pygments_lexer": "ipython3",
555
+ "version": "3.9.5"
556
+ }
557
+ },
558
+ "nbformat": 4,
559
+ "nbformat_minor": 5
560
+ }