Skip to content

Instantly share code, notes, and snippets.

@snowch
Created March 10, 2025 10:04
Show Gist options
  • Save snowch/95146268d671bd4464c0870189f6bdf9 to your computer and use it in GitHub Desktop.
Save snowch/95146268d671bd4464c0870189f6bdf9 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"id": "0c9e547f",
"metadata": {
"id": "0c9e547f"
},
"source": [
"[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langchain-ai/langchain-academy/blob/main/module-3/streaming-interruption.ipynb) [![Open in LangChain Academy](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66e9eba12c7b7688aa3dbb5e_LCA-badge-green.svg)](https://academy.langchain.com/courses/take/intro-to-langgraph/lessons/58239464-lesson-1-streaming)"
]
},
{
"cell_type": "markdown",
"id": "319adfec-2d0a-49f2-87f9-275c4a32add2",
"metadata": {
"id": "319adfec-2d0a-49f2-87f9-275c4a32add2"
},
"source": [
"# Streaming\n",
"\n",
"## Review\n",
"\n",
"In module 2, covered a few ways to customize graph state and memory.\n",
"\n",
"We built up to a Chatbot with external memory that can sustain long-running conversations.\n",
"\n",
"## Goals\n",
"\n",
"This module will dive into `human-in-the-loop`, which builds on memory and allows users to interact directly with graphs in various ways.\n",
"\n",
"To set the stage for `human-in-the-loop`, we'll first dive into streaming, which provides several ways to visualize graph output (e.g., node state or chat model tokens) over the course of execution."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "db024d1f-feb3-45a0-a55c-e7712a1feefa",
"metadata": {
"id": "db024d1f-feb3-45a0-a55c-e7712a1feefa"
},
"outputs": [],
"source": [
"%%capture --no-stderr\n",
"%pip install --quiet -U langgraph langchain_openai langgraph_sdk"
]
},
{
"cell_type": "markdown",
"id": "70d7e41b-c6ba-4e47-b645-6c110bede549",
"metadata": {
"id": "70d7e41b-c6ba-4e47-b645-6c110bede549"
},
"source": [
"## Streaming\n",
"\n",
"LangGraph is built with [first class support for streaming](https://langchain-ai.github.io/langgraph/concepts/low_level/#streaming).\n",
"\n",
"Let's set up our Chatbot from Module 2, and show various way to stream outputs from the graph during execution."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "5b430d92-f595-4322-a56e-06de7485daa8",
"metadata": {
"id": "5b430d92-f595-4322-a56e-06de7485daa8",
"outputId": "b3664fb5-a33d-4007-93a9-c15acc5afba0",
"colab": {
"base_uri": "https://localhost:8080/"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"OPENAI_API_KEY: ··········\n"
]
}
],
"source": [
"import os, getpass\n",
"\n",
"def _set_env(var: str):\n",
" if not os.environ.get(var):\n",
" os.environ[var] = getpass.getpass(f\"{var}: \")\n",
"\n",
"_set_env(\"OPENAI_API_KEY\")"
]
},
{
"cell_type": "markdown",
"id": "4d0682fc",
"metadata": {
"id": "4d0682fc"
},
"source": [
"Note that we use `RunnableConfig` with `call_model` to enable token-wise streaming. This is [only needed with python < 3.11](https://langchain-ai.github.io/langgraph/how-tos/streaming-tokens/). We include in case you are running this notebook in CoLab, which will use python 3.x."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "2d7321e0-0d99-4efe-a67b-74c12271859b",
"metadata": {
"id": "2d7321e0-0d99-4efe-a67b-74c12271859b",
"outputId": "7de676ef-a812-4bb7-a148-2b932b91abe4",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 350
}
},
"outputs": [
{
"output_type": "display_data",
"data": {
"image/png": "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\n",
"text/plain": [
"<IPython.core.display.Image object>"
]
},
"metadata": {}
}
],
"source": [
"from IPython.display import Image, display\n",
"\n",
"from langchain_openai import ChatOpenAI\n",
"from langchain_core.messages import SystemMessage, HumanMessage, RemoveMessage\n",
"from langchain_core.runnables import RunnableConfig\n",
"\n",
"from langgraph.checkpoint.memory import MemorySaver\n",
"from langgraph.graph import StateGraph, START, END\n",
"from langgraph.graph import MessagesState\n",
"\n",
"# LLM\n",
"model = ChatOpenAI(model=\"gpt-4o\", temperature=0)\n",
"\n",
"# State\n",
"class State(MessagesState):\n",
" summary: str\n",
"\n",
"# Define the logic to call the model\n",
"def call_model(state: State, config: RunnableConfig):\n",
"\n",
" # Get summary if it exists\n",
" summary = state.get(\"summary\", \"\")\n",
"\n",
" # If there is summary, then we add it\n",
" if summary:\n",
"\n",
" # Add summary to system message\n",
" system_message = f\"Summary of conversation earlier: {summary}\"\n",
"\n",
" # Append summary to any newer messages\n",
" messages = [SystemMessage(content=system_message)] + state[\"messages\"]\n",
"\n",
" else:\n",
" messages = state[\"messages\"]\n",
"\n",
" response = model.invoke(messages, config)\n",
" return {\"messages\": response}\n",
"\n",
"def summarize_conversation(state: State):\n",
"\n",
" # First, we get any existing summary\n",
" summary = state.get(\"summary\", \"\")\n",
"\n",
" # Create our summarization prompt\n",
" if summary:\n",
"\n",
" # A summary already exists\n",
" summary_message = (\n",
" f\"This is summary of the conversation to date: {summary}\\n\\n\"\n",
" \"Extend the summary by taking into account the new messages above:\"\n",
" )\n",
"\n",
" else:\n",
" summary_message = \"Create a summary of the conversation above:\"\n",
"\n",
" # Add prompt to our history\n",
" messages = state[\"messages\"] + [HumanMessage(content=summary_message)]\n",
" response = model.invoke(messages)\n",
"\n",
" # Delete all but the 2 most recent messages\n",
" delete_messages = [RemoveMessage(id=m.id) for m in state[\"messages\"][:-2]]\n",
" return {\"summary\": response.content, \"messages\": delete_messages}\n",
"\n",
"# Determine whether to end or summarize the conversation\n",
"def should_continue(state: State):\n",
"\n",
" \"\"\"Return the next node to execute.\"\"\"\n",
"\n",
" messages = state[\"messages\"]\n",
"\n",
" # If there are more than six messages, then we summarize the conversation\n",
" if len(messages) > 6:\n",
" return \"summarize_conversation\"\n",
"\n",
" # Otherwise we can just end\n",
" return END\n",
"\n",
"# Define a new graph\n",
"workflow = StateGraph(State)\n",
"workflow.add_node(\"conversation\", call_model)\n",
"workflow.add_node(summarize_conversation)\n",
"\n",
"# Set the entrypoint as conversation\n",
"workflow.add_edge(START, \"conversation\")\n",
"workflow.add_conditional_edges(\"conversation\", should_continue)\n",
"workflow.add_edge(\"summarize_conversation\", END)\n",
"\n",
"# Compile\n",
"memory = MemorySaver()\n",
"graph = workflow.compile(checkpointer=memory)\n",
"display(Image(graph.get_graph().draw_mermaid_png()))"
]
},
{
"cell_type": "markdown",
"id": "f847a787-b301-488c-9b58-cba9f389f55d",
"metadata": {
"id": "f847a787-b301-488c-9b58-cba9f389f55d"
},
"source": [
"### Streaming full state\n",
"\n",
"Now, let's talk about ways to [stream our graph state](https://langchain-ai.github.io/langgraph/concepts/low_level/#streaming).\n",
"\n",
"`.stream` and `.astream` are sync and async methods for streaming back results.\n",
"\n",
"LangGraph supports a few [different streaming modes](https://langchain-ai.github.io/langgraph/how-tos/stream-values/) for [graph state](https://langchain-ai.github.io/langgraph/how-tos/stream-values/):\n",
"\n",
"* `values`: This streams the full state of the graph after each node is called.\n",
"* `updates`: This streams updates to the state of the graph after each node is called.\n",
"\n",
"![values_vs_updates.png](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66dbaf892d24625a201744e5_streaming1.png)\n",
"\n",
"Let's look at `stream_mode=\"updates\"`.\n",
"\n",
"Because we stream with `updates`, we only see updates to the state after node in the graph is run.\n",
"\n",
"Each `chunk` is a dict with `node_name` as the key and the updated state as the value."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "9a6f8ae9-f244-40c5-a2da-618b72631b22",
"metadata": {
"id": "9a6f8ae9-f244-40c5-a2da-618b72631b22",
"outputId": "a729229c-9367-4ae5-8b92-c99842a60ec5",
"colab": {
"base_uri": "https://localhost:8080/"
}
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"{'conversation': {'messages': AIMessage(content='Hello Lance! How can I assist you today?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 11, 'prompt_tokens': 11, 'total_tokens': 22, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_eb9dce56a8', 'finish_reason': 'stop', 'logprobs': None}, id='run-831c8413-e24f-4600-938a-2517fa27e161-0', usage_metadata={'input_tokens': 11, 'output_tokens': 11, 'total_tokens': 22, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})}}\n"
]
}
],
"source": [
"# Create a thread\n",
"config = {\"configurable\": {\"thread_id\": \"1\"}}\n",
"\n",
"# Start conversation\n",
"for chunk in graph.stream({\"messages\": [HumanMessage(content=\"hi! I'm Lance\")]}, config, stream_mode=\"updates\"):\n",
" print(chunk)"
]
},
{
"cell_type": "markdown",
"id": "0c4882e9-07dd-4d70-866b-dfc530418cad",
"metadata": {
"id": "0c4882e9-07dd-4d70-866b-dfc530418cad"
},
"source": [
"Let's now just print the state update."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "c859c777-cb12-4682-9108-6b367e597b81",
"metadata": {
"id": "c859c777-cb12-4682-9108-6b367e597b81",
"outputId": "2bd0117d-d3b4-4360-e4a5-20f710a6fed3",
"colab": {
"base_uri": "https://localhost:8080/"
}
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"\n",
"Hi Lance! How's it going? What can I do for you today?\n"
]
}
],
"source": [
"# Start conversation\n",
"for chunk in graph.stream({\"messages\": [HumanMessage(content=\"hi! I'm Lance\")]}, config, stream_mode=\"updates\"):\n",
" chunk['conversation'][\"messages\"].pretty_print()"
]
},
{
"cell_type": "markdown",
"id": "583bf219-6358-4d06-ae99-c40f43569fda",
"metadata": {
"id": "583bf219-6358-4d06-ae99-c40f43569fda"
},
"source": [
"Now, we can see `stream_mode=\"values\"`.\n",
"\n",
"This is the `full state` of the graph after the `conversation` node is called."
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "6ee763f8-6d1f-491e-8050-fb1439e116df",
"metadata": {
"id": "6ee763f8-6d1f-491e-8050-fb1439e116df",
"outputId": "fcff48a6-7cfc-4575-bb9e-a0805b07dcbf",
"colab": {
"base_uri": "https://localhost:8080/"
}
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"================================\u001b[1m Human Message \u001b[0m=================================\n",
"\n",
"hi! I'm Lance\n",
"---------------------------------------------------------------------------\n",
"================================\u001b[1m Human Message \u001b[0m=================================\n",
"\n",
"hi! I'm Lance\n",
"==================================\u001b[1m Ai Message \u001b[0m==================================\n",
"\n",
"Hello Lance! How can I assist you today?\n",
"---------------------------------------------------------------------------\n"
]
}
],
"source": [
"# Start conversation, again\n",
"config = {\"configurable\": {\"thread_id\": \"2\"}}\n",
"\n",
"# Start conversation\n",
"input_message = HumanMessage(content=\"hi! I'm Lance\")\n",
"for event in graph.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n",
" for m in event['messages']:\n",
" m.pretty_print()\n",
" print(\"---\"*25)"
]
},
{
"cell_type": "markdown",
"id": "563c198a-d1a4-4700-b7a7-ff5b8e0b25d7",
"metadata": {
"id": "563c198a-d1a4-4700-b7a7-ff5b8e0b25d7"
},
"source": [
"### Streaming tokens\n",
"\n",
"We often want to stream more than graph state.\n",
"\n",
"In particular, with chat model calls it is common to stream the tokens as they are generated.\n",
"\n",
"We can do this [using the `.astream_events` method](https://langchain-ai.github.io/langgraph/how-tos/streaming-from-final-node/#stream-outputs-from-the-final-node), which streams back events as they happen inside nodes!\n",
"\n",
"Each event is a dict with a few keys:\n",
"\n",
"* `event`: This is the type of event that is being emitted.\n",
"* `name`: This is the name of event.\n",
"* `data`: This is the data associated with the event.\n",
"* `metadata`: Contains`langgraph_node`, the node emitting the event.\n",
"\n",
"Let's have a look."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "6ae8c7a6-c6e7-4cef-ac9f-190d2f4dd763",
"metadata": {
"id": "6ae8c7a6-c6e7-4cef-ac9f-190d2f4dd763",
"outputId": "e0ea9383-b129-42e5-b2fe-174c6f4f1aa0",
"colab": {
"base_uri": "https://localhost:8080/"
}
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Node: . Type: on_chain_start. Name: LangGraph\n",
"Node: __start__. Type: on_chain_start. Name: __start__\n",
"Node: __start__. Type: on_chain_start. Name: _write\n",
"Node: __start__. Type: on_chain_end. Name: _write\n",
"Node: __start__. Type: on_chain_start. Name: _write\n",
"Node: __start__. Type: on_chain_end. Name: _write\n",
"Node: __start__. Type: on_chain_stream. Name: __start__\n",
"Node: __start__. Type: on_chain_end. Name: __start__\n",
"Node: conversation. Type: on_chain_start. Name: conversation\n",
"Node: . Type: on_chain_stream. Name: LangGraph\n",
"Node: . Type: on_chain_end. Name: LangGraph\n"
]
}
],
"source": [
"config = {\"configurable\": {\"thread_id\": \"3\"}}\n",
"input_message = HumanMessage(content=\"Tell me about the 49ers NFL team\")\n",
"output_count = 0\n",
"\n",
"async for event in graph.astream_events({\"messages\": [input_message]}, config, version=\"v2\"):\n",
" if event['metadata'].get('langgraph_node','') != 'conversation':\n",
" print(f\"Node: {event['metadata'].get('langgraph_node','')}. Type: {event['event']}. Name: {event['name']}\")\n",
" else:\n",
" if output_count == 0:\n",
" print(f\"Node: {event['metadata'].get('langgraph_node','')}. Type: {event['event']}. Name: {event['name']}\")\n",
" output_count += 1"
]
},
{
"cell_type": "markdown",
"id": "0b63490f-3d24-4f68-95ca-5320ccb61d2d",
"metadata": {
"id": "0b63490f-3d24-4f68-95ca-5320ccb61d2d"
},
"source": [
"The central point is that tokens from chat models within your graph have the `on_chat_model_stream` type.\n",
"\n",
"We can use `event['metadata']['langgraph_node']` to select the node to stream from.\n",
"\n",
"And we can use `event['data']` to get the actual data for each event, which in this case is an `AIMessageChunk`."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "cc3529f8-3960-4d41-9ed6-373f93183950",
"metadata": {
"id": "cc3529f8-3960-4d41-9ed6-373f93183950",
"outputId": "fa870a5d-96b8-4a75-894c-31ed0f196741",
"colab": {
"base_uri": "https://localhost:8080/"
}
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"{'chunk': AIMessageChunk(content='', additional_kwargs={}, response_metadata={}, id='run-6d5fda99-8641-4f6f-85e7-cdc119f3b4d2')}\n",
"{'chunk': AIMessageChunk(content='The', additional_kwargs={}, response_metadata={}, id='run-6d5fda99-8641-4f6f-85e7-cdc119f3b4d2')}\n",
"{'chunk': AIMessageChunk(content=' San', additional_kwargs={}, response_metadata={}, id='run-6d5fda99-8641-4f6f-85e7-cdc119f3b4d2')}\n",
"{'chunk': AIMessageChunk(content=' Francisco', additional_kwargs={}, response_metadata={}, id='run-6d5fda99-8641-4f6f-85e7-cdc119f3b4d2')}\n",
"{'chunk': AIMessageChunk(content=' ', additional_kwargs={}, response_metadata={}, id='run-6d5fda99-8641-4f6f-85e7-cdc119f3b4d2')}\n",
"{'chunk': AIMessageChunk(content='49', additional_kwargs={}, response_metadata={}, id='run-6d5fda99-8641-4f6f-85e7-cdc119f3b4d2')}\n",
"{'chunk': AIMessageChunk(content='ers', additional_kwargs={}, response_metadata={}, id='run-6d5fda99-8641-4f6f-85e7-cdc119f3b4d2')}\n",
"{'chunk': AIMessageChunk(content=' are', additional_kwargs={}, response_metadata={}, id='run-6d5fda99-8641-4f6f-85e7-cdc119f3b4d2')}\n",
"{'chunk': AIMessageChunk(content=' a', additional_kwargs={}, response_metadata={}, id='run-6d5fda99-8641-4f6f-85e7-cdc119f3b4d2')}\n",
"{'chunk': AIMessageChunk(content=' stor', additional_kwargs={}, response_metadata={}, id='run-6d5fda99-8641-4f6f-85e7-cdc119f3b4d2')}\n"
]
}
],
"source": [
"node_to_stream = 'conversation'\n",
"config = {\"configurable\": {\"thread_id\": \"4\"}}\n",
"input_message = HumanMessage(content=\"Tell me about the 49ers NFL team\")\n",
"output_count = 0\n",
"async for event in graph.astream_events({\"messages\": [input_message]}, config, version=\"v2\"):\n",
" # Get chat model tokens from a particular node\n",
" if event[\"event\"] == \"on_chat_model_stream\" and event['metadata'].get('langgraph_node','') == node_to_stream:\n",
" if output_count < 10:\n",
" print(event[\"data\"])\n",
" output_count += 1"
]
},
{
"cell_type": "markdown",
"id": "226e569a-76c3-43d8-8f89-3ae687efde1c",
"metadata": {
"id": "226e569a-76c3-43d8-8f89-3ae687efde1c"
},
"source": [
"As you see above, just use the `chunk` key to get the `AIMessageChunk`."
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "3aeae53d-6dcf-40d0-a0c6-c40de492cc83",
"metadata": {
"id": "3aeae53d-6dcf-40d0-a0c6-c40de492cc83",
"outputId": "248df5ec-4ead-44e9-b2d4-634882eca660",
"colab": {
"base_uri": "https://localhost:8080/"
}
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"|The| San| Francisco| |49|ers| are| a| professional| American| football| team| based| in| the| San| Francisco| Bay| Area|.| They| compete| in| the| National| Football| League| (|NFL|)| as| a| member| of| the| league|'s| National| Football| Conference| (|N|FC|)| West| division|.| The| team| was| founded| in| |194|6| as| a| charter| member| of| the| All|-Amer|ica| Football| Conference| (|AA|FC|)| and| joined| the| NFL| in| |194|9| when| the| leagues| merged|.\n",
"\n",
"|###| Key| Points|:\n",
"\n",
"|-| **|Team| Name| and| Colors|**|:| The| team| is| named| after| the| prospect|ors| who| arrived| in| Northern| California| during| the| |184|9| Gold| Rush|.| The| team's| colors| are| red|,| gold|,| and| white|.\n",
"\n",
"|-| **|St|adium|**|:| The| |49|ers| play| their| home| games| at| Levi|'s| Stadium| in| Santa| Clara|,| California|,| which| they| moved| to| in| |201|4|.| Before| that|,| they| played| at| Cand|lestick| Park| in| San| Francisco|.\n",
"\n",
"|-| **|Champ|ionship|s| and| Success|**|:| The| |49|ers| are| one| of| the| most| successful| teams| in| NFL| history|.| They| have| won| five| Super| Bowl| championships| (|Super| Bowl| XVI|,| XIX|,| XX|III|,| XX|IV|,| and| XX|IX|)| and| have| appeared| in| the| Super| Bowl| multiple| times|.| The| team| has| also| won| numerous| division| titles| and| conference| championships|.\n",
"\n",
"|-| **|Not|able| Figures|**|:| The| |49|ers| have| had| several| Hall| of| Fame| players| and| coaches|,| including| Joe| Montana|,| Jerry| Rice|,| Steve| Young|,| Ronnie| L|ott|,| and| coach| Bill| Walsh|.| These| individuals| were| instrumental| in| the| team's| success|,| particularly| during| the| |198|0|s| and| |199|0|s|.\n",
"\n",
"|-| **|R|ival|ries|**|:| The| |49|ers| have| several| notable| rival|ries|,| including| with| the| Dallas| Cowboys|,| Los| Angeles| Rams|,| and| Seattle| Seahawks|.| These| rival|ries| have| often| been| highlighted| by| significant| and| competitive| games|.\n",
"\n",
"|-| **|Recent| Performance|**|:| In| recent| years|,| the| |49|ers| have| experienced| both| ups| and| downs|.| They| reached| the| Super| Bowl| in| the| |201|9| season| but| lost| to| the| Kansas| City| Chiefs|.| The| team| has| been| working| to| maintain| a| competitive| roster| and| return| to| championship| contention|.\n",
"\n",
"|-| **|Community| and| Culture|**|:| The| |49|ers| have| a| strong| fan| base| and| are| known| for| their| community| involvement| and| charitable| activities| in| the| Bay| Area|.| The| team| has| a| rich| history| and| a| tradition| of| excellence| that| continues| to| be| a| source| of| pride| for| its| fans|.\n",
"\n",
"|Overall|,| the| San| Francisco| |49|ers| are| a| stor|ied| franchise| with| a| legacy| of| success| and| a| bright| future| as| they| continue| to| build| on| their| historic| achievements|.||"
]
}
],
"source": [
"config = {\"configurable\": {\"thread_id\": \"5\"}}\n",
"input_message = HumanMessage(content=\"Tell me about the 49ers NFL team\")\n",
"async for event in graph.astream_events({\"messages\": [input_message]}, config, version=\"v2\"):\n",
" # Get chat model tokens from a particular node\n",
" if event[\"event\"] == \"on_chat_model_stream\" and event['metadata'].get('langgraph_node','') == node_to_stream:\n",
" data = event[\"data\"]\n",
" print(data[\"chunk\"].content, end=\"|\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1ae885f8-102f-448a-9d68-8ded8d2bbd18",
"metadata": {
"id": "1ae885f8-102f-448a-9d68-8ded8d2bbd18"
},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.8"
},
"colab": {
"provenance": []
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment