SpyFox commited on
Commit
613a6ac
·
verified ·
1 Parent(s): c1d7434

Upload simple_agent.ipynb

Browse files
Files changed (1) hide show
  1. simple_agent.ipynb +497 -0
simple_agent.ipynb ADDED
@@ -0,0 +1,497 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 1,
6
+ "id": "94c8b42c",
7
+ "metadata": {},
8
+ "outputs": [],
9
+ "source": [
10
+ "import getpass\n",
11
+ "import os\n",
12
+ "from langchain.chat_models import init_chat_model\n",
13
+ "\n",
14
+ "if not os.environ.get(\"GOOGLE_API_KEY\"):\n",
15
+ " os.environ[\"GOOGLE_API_KEY\"] = getpass.getpass(\"Enter API key for Google Gemini: \")\n",
16
+ "llm = init_chat_model(\"gemini-2.5-flash-preview-04-17\", model_provider=\"google_genai\", temperature=0)"
17
+ ]
18
+ },
19
+ {
20
+ "cell_type": "code",
21
+ "execution_count": 18,
22
+ "id": "ce83aa2a",
23
+ "metadata": {},
24
+ "outputs": [],
25
+ "source": [
26
+ "import re\n",
27
+ "from langchain.document_loaders import WebBaseLoader\n",
28
+ "from langchain_community.tools import DuckDuckGoSearchResults\n",
29
+ "def download_web_pages(query: str) -> str:\n",
30
+ " \"\"\"\n",
31
+ " Performs a web search using the given query, downloads the content of two relevant web pages,\n",
32
+ " and returns their combined content as a raw string.\n",
33
+ "\n",
34
+ " This is useful when the task requires analysis of web page content, such as retrieving poems, \n",
35
+ " changelogs, or other textual resources.\n",
36
+ "\n",
37
+ " Args:\n",
38
+ " query (str): The search query.\n",
39
+ "\n",
40
+ " Returns:\n",
41
+ " str: The combined raw text content of the two retrieved web pages.\n",
42
+ " \"\"\"\n",
43
+ " search_engine = DuckDuckGoSearchResults(output_format=\"list\", num_results=2)\n",
44
+ " page_urls = [url[\"link\"] for url in search_engine(query)]\n",
45
+ "\n",
46
+ " loader = WebBaseLoader(web_paths=(page_urls))\n",
47
+ " docs = loader.load()\n",
48
+ "\n",
49
+ " combined_text = \"\\n\\n\".join(doc.page_content[:15000] for doc in docs)\n",
50
+ "\n",
51
+ " # Clean up excessive newlines, spaces and strip leading/trailing whitespace\n",
52
+ " cleaned_text = re.sub(r'\\n{3,}', '\\n\\n', combined_text).strip()\n",
53
+ " cleaned_text = re.sub(r'[ \\t]{6,}', ' ', cleaned_text)\n",
54
+ "\n",
55
+ " # Strip leading/trailing whitespace\n",
56
+ " cleaned_text = cleaned_text.strip()\n",
57
+ " return cleaned_text"
58
+ ]
59
+ },
60
+ {
61
+ "cell_type": "code",
62
+ "execution_count": 24,
63
+ "id": "586df437",
64
+ "metadata": {},
65
+ "outputs": [],
66
+ "source": [
67
+ "from langchain_community.retrievers import WikipediaRetriever\n",
68
+ "\n",
69
+ "def wikipedia_search(query: str) -> str:\n",
70
+ " \"\"\"\n",
71
+ " Searches for a Wikipedia articles using the provided query and returns the content of the corresponding Wikipedia pages.\n",
72
+ "\n",
73
+ " Args:\n",
74
+ " query (str): The search term to look up on Wikipedia.\n",
75
+ "\n",
76
+ " Returns:\n",
77
+ " str: The text content of the Wikipedia articles related to the query.\n",
78
+ " \"\"\"\n",
79
+ " retriever = WikipediaRetriever()\n",
80
+ " docs = retriever.invoke(query)\n",
81
+ " combined_text = \"\\n\\n\".join(doc.page_content for doc in docs)\n",
82
+ " return combined_text"
83
+ ]
84
+ },
85
+ {
86
+ "cell_type": "code",
87
+ "execution_count": 25,
88
+ "id": "fac2cb01",
89
+ "metadata": {},
90
+ "outputs": [],
91
+ "source": [
92
+ "from google import genai\n",
93
+ "from google.genai import types\n",
94
+ "\n",
95
+ "def youtube_viewer(youtube_url: str, question: str) -> str:\n",
96
+ " \"\"\"\n",
97
+ " Analyzes a YouTube video from the provided URL and returns an answer \n",
98
+ " to the given question based on the analysis results.\n",
99
+ "\n",
100
+ " Args:\n",
101
+ " youtube_url (str): The URL of the YouTube video, in the format \n",
102
+ " \"https://www.youtube.com/...\".\n",
103
+ " question (str): A question related to the content of the video.\n",
104
+ "\n",
105
+ " Returns:\n",
106
+ " str: An answer to the question based on the video's content.\n",
107
+ " \"\"\"\n",
108
+ " client = genai.Client()\n",
109
+ " response = client.models.generate_content(\n",
110
+ " model='models/gemini-2.5-flash-preview-04-17',\n",
111
+ " contents=types.Content(\n",
112
+ " parts=[\n",
113
+ " types.Part(\n",
114
+ " file_data=types.FileData(file_uri=youtube_url)\n",
115
+ " ),\n",
116
+ " types.Part(text=question)\n",
117
+ " ]\n",
118
+ " )\n",
119
+ " )\n",
120
+ " return response.text"
121
+ ]
122
+ },
123
+ {
124
+ "cell_type": "code",
125
+ "execution_count": 26,
126
+ "id": "4c498a3d",
127
+ "metadata": {},
128
+ "outputs": [
129
+ {
130
+ "name": "stderr",
131
+ "output_type": "stream",
132
+ "text": [
133
+ "Key 'title' is not supported in schema, ignoring\n",
134
+ "Key 'title' is not supported in schema, ignoring\n",
135
+ "Key 'title' is not supported in schema, ignoring\n"
136
+ ]
137
+ }
138
+ ],
139
+ "source": [
140
+ "tools = [download_web_pages, wikipedia_search, youtube_viewer]\n",
141
+ "\n",
142
+ "# Bind the tools to the agent\n",
143
+ "llm_with_tools = llm.bind_tools(tools)"
144
+ ]
145
+ },
146
+ {
147
+ "cell_type": "code",
148
+ "execution_count": 27,
149
+ "id": "10628e0f",
150
+ "metadata": {},
151
+ "outputs": [],
152
+ "source": [
153
+ "from typing import TypedDict, Annotated, Optional\n",
154
+ "from langchain_core.messages import AnyMessage\n",
155
+ "from langgraph.graph.message import add_messages\n",
156
+ "\n",
157
+ "class AgentState(TypedDict):\n",
158
+ " \"\"\"Agent state for the graph.\"\"\"\n",
159
+ " input_file: Optional[str]\n",
160
+ " messages: Annotated[list[AnyMessage], add_messages]"
161
+ ]
162
+ },
163
+ {
164
+ "cell_type": "code",
165
+ "execution_count": 28,
166
+ "id": "f1594fb9",
167
+ "metadata": {},
168
+ "outputs": [],
169
+ "source": [
170
+ "from langchain_core.messages import SystemMessage, HumanMessage\n",
171
+ "\n",
172
+ "def assistant(state: AgentState):\n",
173
+ " sys_msg = SystemMessage(\n",
174
+ " content=\n",
175
+ " \"\"\"\n",
176
+ "You are a helpful assistant tasked with answering questions using a set of tools. When given a question, follow these steps:\n",
177
+ "1. Create a clear, step-by-step plan to solve the question.\n",
178
+ "2. If a tool is necessary, select the most appropriate tool based on its functionality. If one tool isn't working, use another with similar functionality.\n",
179
+ "3. Execute your plan and provide the response in the following format:\n",
180
+ "\n",
181
+ "FINAL ANSWER: [YOUR FINAL ANSWER]\n",
182
+ "\n",
183
+ "Your final answer should be:\n",
184
+ "\n",
185
+ "- A number (without commas or units unless explicitly requested),\n",
186
+ "- A short string (avoid articles, abbreviations, and use plain text for digits unless otherwise specified),\n",
187
+ "- A comma-separated list (apply the formatting rules above for each element, with exactly one space after each comma).\n",
188
+ "\n",
189
+ "Ensure that your answer is concise and follows the task instructions strictly. If the answer is more complex, break it down in a way that follows the format.\n",
190
+ "Begin your response with \"FINAL ANSWER: \" followed by the answer, and nothing else.\n",
191
+ " \"\"\"\n",
192
+ " )\n",
193
+ "\n",
194
+ " return {\n",
195
+ " \"messages\": [llm_with_tools.invoke([sys_msg] + state[\"messages\"])],\n",
196
+ " \"input_file\": state[\"input_file\"]\n",
197
+ " }"
198
+ ]
199
+ },
200
+ {
201
+ "cell_type": "code",
202
+ "execution_count": 29,
203
+ "id": "b36bc36c",
204
+ "metadata": {},
205
+ "outputs": [
206
+ {
207
+ "data": {
208
+ "image/png": "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",
209
+ "text/plain": [
210
+ "<IPython.core.display.Image object>"
211
+ ]
212
+ },
213
+ "metadata": {},
214
+ "output_type": "display_data"
215
+ }
216
+ ],
217
+ "source": [
218
+ "from langgraph.prebuilt import ToolNode, tools_condition\n",
219
+ "from IPython.display import Image, display\n",
220
+ "from langgraph.graph import StateGraph, START\n",
221
+ "\n",
222
+ "# Build the state graph\n",
223
+ "# The graph\n",
224
+ "builder = StateGraph(AgentState)\n",
225
+ "\n",
226
+ "# Define nodes: these do the work\n",
227
+ "builder.add_node(\"assistant\", assistant)\n",
228
+ "builder.add_node(\"tools\", ToolNode(tools))\n",
229
+ "# Define edges: these determine how the control flow moves\n",
230
+ "builder.add_edge(START, \"assistant\")\n",
231
+ "builder.add_conditional_edges(\n",
232
+ " \"assistant\",\n",
233
+ " tools_condition,\n",
234
+ ")\n",
235
+ "builder.add_edge(\"tools\", \"assistant\")\n",
236
+ "react_graph = builder.compile()\n",
237
+ "# Show the butler's thought process\n",
238
+ "display(Image(react_graph.get_graph(xray=True).draw_mermaid_png()))"
239
+ ]
240
+ },
241
+ {
242
+ "cell_type": "code",
243
+ "execution_count": 13,
244
+ "id": "ead8e45f",
245
+ "metadata": {},
246
+ "outputs": [
247
+ {
248
+ "data": {
249
+ "application/vnd.jupyter.widget-view+json": {
250
+ "model_id": "ed21ed00ada141289cbee25b93029435",
251
+ "version_major": 2,
252
+ "version_minor": 0
253
+ },
254
+ "text/plain": [
255
+ "VBox(children=(HTML(value='<center> <img\\nsrc=https://huggingface.co/front/assets/huggingface_logo-noborder.sv…"
256
+ ]
257
+ },
258
+ "metadata": {},
259
+ "output_type": "display_data"
260
+ }
261
+ ],
262
+ "source": [
263
+ "from huggingface_hub import login\n",
264
+ "\n",
265
+ "# This will prompt you for your token\n",
266
+ "login()"
267
+ ]
268
+ },
269
+ {
270
+ "cell_type": "code",
271
+ "execution_count": 12,
272
+ "id": "b4b1299d",
273
+ "metadata": {},
274
+ "outputs": [
275
+ {
276
+ "name": "stdout",
277
+ "output_type": "stream",
278
+ "text": [
279
+ "Logged in as: SpyFox\n"
280
+ ]
281
+ }
282
+ ],
283
+ "source": [
284
+ "from huggingface_hub import whoami\n",
285
+ "\n",
286
+ "info = whoami()\n",
287
+ "username = info[\"name\"]\n",
288
+ "\n",
289
+ "print(f\"Logged in as: {username}\")"
290
+ ]
291
+ },
292
+ {
293
+ "cell_type": "code",
294
+ "execution_count": 13,
295
+ "id": "45e5f7ca",
296
+ "metadata": {},
297
+ "outputs": [],
298
+ "source": [
299
+ "DEFAULT_API_URL = \"https://agents-course-unit4-scoring.hf.space\" \n",
300
+ "api_url = DEFAULT_API_URL\n",
301
+ "questions_url = f\"{api_url}/questions\"\n",
302
+ "submit_url = f\"{api_url}/submit\"\n",
303
+ "files_url = f\"{api_url}/files\""
304
+ ]
305
+ },
306
+ {
307
+ "cell_type": "code",
308
+ "execution_count": 14,
309
+ "id": "af2e50c9",
310
+ "metadata": {},
311
+ "outputs": [
312
+ {
313
+ "name": "stdout",
314
+ "output_type": "stream",
315
+ "text": [
316
+ "Fetching questions from: https://agents-course-unit4-scoring.hf.space/questions\n",
317
+ "Fetched 20 questions.\n",
318
+ "{'task_id': 'cabe07ed-9eca-40ea-8ead-410ef5e83f91', 'question': \"What is the surname of the equine veterinarian mentioned in 1.E Exercises from the chemistry materials licensed by Marisa Alviar-Agnew & Henry Agnew under the CK-12 license in LibreText's Introductory Chemistry materials as compiled 08/21/2023?\", 'Level': '1', 'file_name': ''}\n"
319
+ ]
320
+ }
321
+ ],
322
+ "source": [
323
+ "import requests\n",
324
+ "print(f\"Fetching questions from: {questions_url}\")\n",
325
+ "try:\n",
326
+ " response = requests.get(questions_url, timeout=15)\n",
327
+ " response.raise_for_status()\n",
328
+ " questions_data = response.json()\n",
329
+ " if not questions_data:\n",
330
+ " print(\"Fetched questions list is empty.\")\n",
331
+ " print(f\"Fetched {len(questions_data)} questions.\")\n",
332
+ "except requests.exceptions.RequestException as e:\n",
333
+ " print(f\"Error fetching questions: {e}\")\n",
334
+ "except requests.exceptions.JSONDecodeError as e:\n",
335
+ " print(f\"Error decoding JSON response from questions endpoint: {e}\")\n",
336
+ " print(f\"Response text: {response.text[:500]}\")\n",
337
+ "except Exception as e:\n",
338
+ " print(f\"An unexpected error occurred fetching questions: {e}\")\n",
339
+ "\n",
340
+ "print(questions_data[7])"
341
+ ]
342
+ },
343
+ {
344
+ "cell_type": "code",
345
+ "execution_count": 30,
346
+ "id": "3c6996e6",
347
+ "metadata": {},
348
+ "outputs": [
349
+ {
350
+ "name": "stdout",
351
+ "output_type": "stream",
352
+ "text": [
353
+ "Running agent on 20 questions...\n",
354
+ "Question: How many studio albums were published by Mercedes Sosa between 2000 and 2009 (included)? You can use the latest 2022 version of english wikipedia.\n"
355
+ ]
356
+ },
357
+ {
358
+ "name": "stderr",
359
+ "output_type": "stream",
360
+ "text": [
361
+ "C:\\Users\\wasyl\\AppData\\Local\\Temp\\ipykernel_22488\\81366616.py:19: LangChainDeprecationWarning: The method `BaseTool.__call__` was deprecated in langchain-core 0.1.47 and will be removed in 1.0. Use :meth:`~invoke` instead.\n",
362
+ " page_urls = [url[\"link\"] for url in search_engine(query)]\n"
363
+ ]
364
+ },
365
+ {
366
+ "name": "stdout",
367
+ "output_type": "stream",
368
+ "text": [
369
+ "Answer: 3\n",
370
+ "Question: In the video https://www.youtube.com/watch?v=L1vXCYZAYYM, what is the highest number of bird species to be on camera simultaneously?\n",
371
+ "Answer: 3\n"
372
+ ]
373
+ },
374
+ {
375
+ "ename": "KeyboardInterrupt",
376
+ "evalue": "",
377
+ "output_type": "error",
378
+ "traceback": [
379
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
380
+ "\u001b[1;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)",
381
+ "Cell \u001b[1;32mIn[30], line 28\u001b[0m\n\u001b[0;32m 26\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mAnswer: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00msubmitted_answer\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 27\u001b[0m answers_payload\u001b[38;5;241m.\u001b[39mappend({\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtask_id\u001b[39m\u001b[38;5;124m\"\u001b[39m: task_id, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msubmitted_answer\u001b[39m\u001b[38;5;124m\"\u001b[39m: submitted_answer})\n\u001b[1;32m---> 28\u001b[0m time\u001b[38;5;241m.\u001b[39msleep(\u001b[38;5;241m10\u001b[39m) \u001b[38;5;66;03m# Sleep for 10 seconds to avoid rate limiting\u001b[39;00m\n\u001b[0;32m 29\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[0;32m 30\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mError running agent on task \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtask_id\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00me\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n",
382
+ "\u001b[1;31mKeyboardInterrupt\u001b[0m: "
383
+ ]
384
+ }
385
+ ],
386
+ "source": [
387
+ "import time\n",
388
+ "\n",
389
+ "def extract_after_final_answer(text):\n",
390
+ " keyword = \"FINAL ANSWER: \"\n",
391
+ " index = text.find(keyword)\n",
392
+ " if index != -1:\n",
393
+ " return text[index + len(keyword):]\n",
394
+ " else:\n",
395
+ " return \"\"\n",
396
+ "\n",
397
+ "answers_payload = []\n",
398
+ "\n",
399
+ "print(f\"Running agent on {len(questions_data)} questions...\")\n",
400
+ "for item in questions_data:\n",
401
+ " task_id = item.get(\"task_id\")\n",
402
+ " question_text = item.get(\"question\")\n",
403
+ " print(f\"Question: {question_text}\")\n",
404
+ " messages = [HumanMessage(content=question_text)]\n",
405
+ "\n",
406
+ " if not task_id or question_text is None:\n",
407
+ " print(f\"Skipping item with missing task_id or question: {item}\")\n",
408
+ " continue\n",
409
+ " try:\n",
410
+ " submitted_answer = react_graph.invoke({\"messages\": messages, \"input_file\": None})\n",
411
+ " submitted_answer = extract_after_final_answer(submitted_answer['messages'][-1].content)\n",
412
+ " print(f\"Answer: {submitted_answer}\")\n",
413
+ " answers_payload.append({\"task_id\": task_id, \"submitted_answer\": submitted_answer})\n",
414
+ " time.sleep(10) # Sleep for 10 seconds to avoid rate limiting\n",
415
+ " except Exception as e:\n",
416
+ " print(f\"Error running agent on task {task_id}: {e}\")\n"
417
+ ]
418
+ },
419
+ {
420
+ "cell_type": "code",
421
+ "execution_count": 27,
422
+ "id": "8e47414a",
423
+ "metadata": {},
424
+ "outputs": [
425
+ {
426
+ "name": "stdout",
427
+ "output_type": "stream",
428
+ "text": [
429
+ "Agent finished. Submitting 20 answers for user 'SpyFox'...\n"
430
+ ]
431
+ }
432
+ ],
433
+ "source": [
434
+ "submission_data = {\"username\": username.strip(), \"agent_code\": \"https://huggingface.co/spaces/SpyFox/agents_final_test/tree/main\", \"answers\": answers_payload}\n",
435
+ "status_update = f\"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'...\"\n",
436
+ "print(status_update)"
437
+ ]
438
+ },
439
+ {
440
+ "cell_type": "code",
441
+ "execution_count": 28,
442
+ "id": "a086f73f",
443
+ "metadata": {},
444
+ "outputs": [
445
+ {
446
+ "name": "stdout",
447
+ "output_type": "stream",
448
+ "text": [
449
+ "Submitting 20 answers to: https://agents-course-unit4-scoring.hf.space/submit\n",
450
+ "Submission successful.\n",
451
+ "Submission Successful!\n",
452
+ "User: SpyFox\n",
453
+ "Overall Score: 45.0% (9/20 correct)\n",
454
+ "Message: Score calculated successfully: 9/20 total questions answered correctly (20 valid tasks attempted). High score updated on leaderboard.\n"
455
+ ]
456
+ }
457
+ ],
458
+ "source": [
459
+ "print(f\"Submitting {len(answers_payload)} answers to: {submit_url}\")\n",
460
+ "\n",
461
+ "response = requests.post(submit_url, json=submission_data, timeout=60)\n",
462
+ "response.raise_for_status()\n",
463
+ "result_data = response.json()\n",
464
+ "final_status = (\n",
465
+ " f\"Submission Successful!\\n\"\n",
466
+ " f\"User: {result_data.get('username')}\\n\"\n",
467
+ " f\"Overall Score: {result_data.get('score', 'N/A')}% \"\n",
468
+ " f\"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\\n\"\n",
469
+ " f\"Message: {result_data.get('message', 'No message received.')}\"\n",
470
+ ")\n",
471
+ "print(\"Submission successful.\")\n",
472
+ "print(final_status)"
473
+ ]
474
+ }
475
+ ],
476
+ "metadata": {
477
+ "kernelspec": {
478
+ "display_name": "base",
479
+ "language": "python",
480
+ "name": "python3"
481
+ },
482
+ "language_info": {
483
+ "codemirror_mode": {
484
+ "name": "ipython",
485
+ "version": 3
486
+ },
487
+ "file_extension": ".py",
488
+ "mimetype": "text/x-python",
489
+ "name": "python",
490
+ "nbconvert_exporter": "python",
491
+ "pygments_lexer": "ipython3",
492
+ "version": "3.11.4"
493
+ }
494
+ },
495
+ "nbformat": 4,
496
+ "nbformat_minor": 5
497
+ }