466 lines (465 with data), 28.0 kB
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "a954e8f1",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 819
},
"id": "a954e8f1",
"outputId": "439b5e9d-52d3-49ec-ab97-60fdd5ea862d"
},
"outputs": [
{
"data": {
"text/html": [
"<img src=\"https://raw.githubusercontent.com/langchain-ai/langgraph/17f1a05b6b9e32e4e560c270d0a94246b69f1e45/examples/multi_agent/img/supervisor-diagram.png\"/>"
],
"text/plain": [
"<IPython.core.display.Image object>"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Adapted from langchain-ai Agent Supervisor\n",
"# https://github.com/langchain-ai/langgraph/blob/main/examples/multi_agent/agent_supervisor.ipynb\n",
"from IPython.display import Image\n",
"image_url = \"https://raw.githubusercontent.com/langchain-ai/langgraph/17f1a05b6b9e32e4e560c270d0a94246b69f1e45/examples/multi_agent/img/supervisor-diagram.png\"\n",
"Image(url=image_url)"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "0d30b6f7-3bec-4d9f-af50-43dfdc81ae6c",
"metadata": {
"id": "0d30b6f7-3bec-4d9f-af50-43dfdc81ae6c"
},
"outputs": [],
"source": [
"%%capture --no-stderr\n",
"%pip install -U langchain langchain_openai langchain_experimental langsmith pandas langgraph"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "30c2f3de-c730-4aec-85a6-af2c2f058803",
"metadata": {
"id": "30c2f3de-c730-4aec-85a6-af2c2f058803"
},
"outputs": [],
"source": [
"import getpass\n",
"import os\n",
"\n",
"os.environ['OPENAI_API_KEY'] = ''\n",
"os.environ['TAVILY_API_KEY'] = ''\n",
"\n",
"# Optional, add tracing in LangSmith\n",
"os.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\n",
"os.environ['LANGCHAIN_ENDPOINT'] = ''\n",
"os.environ[\"LANGCHAIN_PROJECT\"] = \"Agent Supervisor\"\n",
"os.environ['LANGCHAIN_API_KEY'] = ''"
]
},
{
"cell_type": "markdown",
"id": "1ac25624-4d83-45a4-b9ef-a10589aacfb7",
"metadata": {
"id": "1ac25624-4d83-45a4-b9ef-a10589aacfb7"
},
"source": [
"## Create tools\n",
"\n",
"For this example, you will make an agent to do web research with a search engine, and one agent to create plots. Define the tools they'll use below:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "f04c6778-403b-4b49-9b93-678e910d5cec",
"metadata": {
"id": "f04c6778-403b-4b49-9b93-678e910d5cec"
},
"outputs": [],
"source": [
"from typing import Annotated, List, Tuple, Union\n",
"\n",
"from langchain_community.tools.tavily_search import TavilySearchResults\n",
"from langchain_core.tools import tool\n",
"from langchain_experimental.tools import PythonREPLTool\n",
"\n",
"tavily_tool = TavilySearchResults(max_results=5)\n",
"\n",
"# This executes code locally, which can be unsafe\n",
"python_repl_tool = PythonREPLTool()"
]
},
{
"cell_type": "markdown",
"id": "d58d1e85-22d4-4c22-9062-72a346a0d709",
"metadata": {
"id": "d58d1e85-22d4-4c22-9062-72a346a0d709"
},
"source": [
"## Helper Utilities\n",
"\n",
"Define a helper function below, which make it easier to add new agent worker nodes."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "c4823dd9-26bd-4e1a-8117-b97b2860211a",
"metadata": {
"id": "c4823dd9-26bd-4e1a-8117-b97b2860211a"
},
"outputs": [],
"source": [
"from langchain.agents import AgentExecutor, create_openai_tools_agent\n",
"from langchain_core.messages import BaseMessage, HumanMessage\n",
"from langchain_openai import ChatOpenAI\n",
"\n",
"\n",
"def create_agent(llm: ChatOpenAI, tools: list, system_prompt: str):\n",
" # Each worker node will be given a name and some tools.\n",
" prompt = ChatPromptTemplate.from_messages(\n",
" [\n",
" (\n",
" \"system\",\n",
" system_prompt,\n",
" ),\n",
" MessagesPlaceholder(variable_name=\"messages\"),\n",
" MessagesPlaceholder(variable_name=\"agent_scratchpad\"),\n",
" ]\n",
" )\n",
" agent = create_openai_tools_agent(llm, tools, prompt)\n",
" executor = AgentExecutor(agent=agent, tools=tools)\n",
" return executor"
]
},
{
"cell_type": "markdown",
"id": "b7c302b0-cd57-4913-986f-5dc7d6d77386",
"metadata": {
"id": "b7c302b0-cd57-4913-986f-5dc7d6d77386"
},
"source": [
"We can also define a function that we will use to be the nodes in the graph - it takes care of converting the agent response to a human message. This is important because that is how we will add it the global state of the graph"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "80862241-a1a7-4726-bce5-f867b233832e",
"metadata": {
"id": "80862241-a1a7-4726-bce5-f867b233832e"
},
"outputs": [],
"source": [
"def agent_node(state, agent, name):\n",
" result = agent.invoke(state)\n",
" return {\"messages\": [HumanMessage(content=result[\"output\"], name=name)]}"
]
},
{
"cell_type": "markdown",
"id": "d32962d2-5487-496d-aefc-2a3b0d194985",
"metadata": {
"id": "d32962d2-5487-496d-aefc-2a3b0d194985"
},
"source": [
"### Create Agent Supervisor\n",
"\n",
"It will use function calling to choose the next worker node OR finish processing."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "311f0a58-b425-4496-adac-dc4cd8ffb912",
"metadata": {
"id": "311f0a58-b425-4496-adac-dc4cd8ffb912"
},
"outputs": [],
"source": [
"from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n",
"from langchain_core.output_parsers.openai_functions import JsonOutputFunctionsParser\n",
"\n",
"members = [\"Researcher\", \"Coder\"]\n",
"system_prompt = (\n",
" \"You are a supervisor tasked with managing a conversation between the\"\n",
" \" following workers: {members}. Given the following user request,\"\n",
" \" respond with the worker to act next. Each worker will perform a\"\n",
" \" task and respond with their results and status. When finished,\"\n",
" \" respond with FINISH.\"\n",
")\n",
"# Our team supervisor is an LLM node. It just picks the next agent to process\n",
"# and decides when the work is completed\n",
"options = [\"FINISH\"] + members\n",
"# Using openai function calling can make output parsing easier for us\n",
"function_def = {\n",
" \"name\": \"route\",\n",
" \"description\": \"Select the next role.\",\n",
" \"parameters\": {\n",
" \"title\": \"routeSchema\",\n",
" \"type\": \"object\",\n",
" \"properties\": {\n",
" \"next\": {\n",
" \"title\": \"Next\",\n",
" \"anyOf\": [\n",
" {\"enum\": options},\n",
" ],\n",
" }\n",
" },\n",
" \"required\": [\"next\"],\n",
" },\n",
"}\n",
"prompt = ChatPromptTemplate.from_messages(\n",
" [\n",
" (\"system\", system_prompt),\n",
" MessagesPlaceholder(variable_name=\"messages\"),\n",
" (\n",
" \"system\",\n",
" \"Given the conversation above, who should act next?\"\n",
" \" Or should we FINISH? Select one of: {options}\",\n",
" ),\n",
" ]\n",
").partial(options=str(options), members=\", \".join(members))\n",
"\n",
"llm = ChatOpenAI(model=\"gpt-4o-2024-05-13\")\n",
"\n",
"supervisor_chain = (\n",
" prompt\n",
" | llm.bind_functions(functions=[function_def], function_call=\"route\")\n",
" | JsonOutputFunctionsParser()\n",
")"
]
},
{
"cell_type": "markdown",
"id": "a07d507f-34d1-4f1b-8dde-5e58d17b2166",
"metadata": {
"id": "a07d507f-34d1-4f1b-8dde-5e58d17b2166"
},
"source": [
"## Construct Graph\n",
"\n",
"We're ready to start building the graph. Below, define the state and worker nodes using the function we just defined."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "6a430af7-8fce-4e66-ba9e-d940c1bc48e8",
"metadata": {
"id": "6a430af7-8fce-4e66-ba9e-d940c1bc48e8"
},
"outputs": [],
"source": [
"import operator\n",
"from typing import Annotated, Any, Dict, List, Optional, Sequence, TypedDict\n",
"import functools\n",
"\n",
"from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n",
"from langgraph.graph import StateGraph, END\n",
"\n",
"\n",
"# The agent state is the input to each node in the graph\n",
"class AgentState(TypedDict):\n",
" # The annotation tells the graph that new messages will always\n",
" # be added to the current states\n",
" messages: Annotated[Sequence[BaseMessage], operator.add]\n",
" # The 'next' field indicates where to route to next\n",
" next: str\n",
"\n",
"\n",
"research_agent = create_agent(llm, [tavily_tool], \"You are a web researcher.\")\n",
"research_node = functools.partial(agent_node, agent=research_agent, name=\"Researcher\")\n",
"\n",
"# NOTE: THIS PERFORMS ARBITRARY CODE EXECUTION. PROCEED WITH CAUTION\n",
"code_agent = create_agent(\n",
" llm,\n",
" [python_repl_tool],\n",
" \"You may generate safe python code to analyze data and generate charts using matplotlib.\",\n",
")\n",
"code_node = functools.partial(agent_node, agent=code_agent, name=\"Coder\")\n",
"\n",
"workflow = StateGraph(AgentState)\n",
"workflow.add_node(\"Researcher\", research_node)\n",
"workflow.add_node(\"Coder\", code_node)\n",
"workflow.add_node(\"supervisor\", supervisor_chain)"
]
},
{
"cell_type": "markdown",
"id": "2c1593d5-39f7-4819-96d2-4ad7d7991d72",
"metadata": {
"id": "2c1593d5-39f7-4819-96d2-4ad7d7991d72"
},
"source": [
"Now connect all the edges in the graph."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "14778e86-077b-4e6a-893c-400e59b0cdbf",
"metadata": {
"id": "14778e86-077b-4e6a-893c-400e59b0cdbf"
},
"outputs": [],
"source": [
"for member in members:\n",
" # We want our workers to ALWAYS \"report back\" to the supervisor when done\n",
" workflow.add_edge(member, \"supervisor\")\n",
"# The supervisor populates the \"next\" field in the graph state\n",
"# which routes to a node or finishes\n",
"conditional_map = {k: k for k in members}\n",
"conditional_map[\"FINISH\"] = END\n",
"workflow.add_conditional_edges(\"supervisor\", lambda x: x[\"next\"], conditional_map)\n",
"# Finally, add entrypoint\n",
"workflow.set_entry_point(\"supervisor\")\n",
"\n",
"graph = workflow.compile()"
]
},
{
"cell_type": "markdown",
"id": "d36496de-7121-4c49-8cb6-58c943c66628",
"metadata": {
"id": "d36496de-7121-4c49-8cb6-58c943c66628"
},
"source": [
"## Invoke the team\n",
"\n",
"With the graph created, we can now invoke it and see how it performs!"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "56ba78e9-d9c1-457c-a073-d606d5d3e013",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 0
},
"id": "56ba78e9-d9c1-457c-a073-d606d5d3e013",
"outputId": "f3a8046a-7ffc-42ca-f191-5cbb2be2a63b"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'supervisor': {'next': 'Researcher'}}\n",
"----\n",
"{'Researcher': {'messages': [HumanMessage(content='Here are some key resources and information on the use of generative AI in drug discovery, particularly for cancer research:\\n\\n1. **Nature Review on AI in Cancer Research**:\\n - A comprehensive review focusing on AI applications in cancer research, including image analysis, NLP, and drug discovery.\\n - [Link to article](https://www.nature.com/articles/s41568-024-00694-7)\\n\\n2. **Generative Artificial Intelligence in Drug Discovery**:\\n - Discusses the basic framework, recent advances, challenges, and opportunities of generative AI in drug discovery.\\n - [Link to article](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC10879372/)\\n\\n3. **AI-Driven Generative Models in Drug Discovery**:\\n - Highlights the use of AI-driven generative models like RNNs, GANs, and VAEs in creating innovative compounds and exploring chemical space.\\n - [Link to article](https://www.tandfonline.com/doi/full/10.1080/17460441.2024.2367014)\\n\\n4. **Quantum-Enhanced Generative AI for Cancer Drug Discovery**:\\n - Demonstrates a breakthrough in applying quantum-enhanced generative AI to cancer drug discovery using quantum devices.\\n - [Link to article](https://zapata.ai/news/for-the-first-time-quantum-enhanced-generative-ai-generates-viable-cancer-drug-candidates/)\\n\\n5. **Drug Discovery Using Machine Learning**:\\n - A resource on using machine learning for discovering new candidate drugs, including trending ML papers, research developments, and datasets.\\n - [Link to article](https://paperswithcode.com/task/drug-discovery)\\n \\nFor a practical overview and code examples, you can refer to the following:\\n\\n**Basic Framework for Generative AI in Drug Discovery**:\\n```python\\nimport torch\\nimport torch.nn as nn\\nimport torch.optim as optim\\n\\n# Example of a simple generative model using PyTorch\\nclass GenerativeModel(nn.Module):\\n def __init__(self, input_size, hidden_size, output_size):\\n super(GenerativeModel, self).__init__()\\n self.fc1 = nn.Linear(input_size, hidden_size)\\n self.fc2 = nn.Linear(hidden_size, output_size)\\n \\n def forward(self, x):\\n x = torch.relu(self.fc1(x))\\n x = torch.sigmoid(self.fc2(x))\\n return x\\n\\n# Hyperparameters\\ninput_size = 100\\nhidden_size = 50\\noutput_size = 1\\nlearning_rate = 0.001\\nepochs = 1000\\n\\n# Model, Loss Function, Optimizer\\nmodel = GenerativeModel(input_size, hidden_size, output_size)\\ncriterion = nn.BCELoss()\\noptimizer = optim.Adam(model.parameters(), lr=learning_rate)\\n\\n# Dummy Data for Training (replace with actual data)\\ndata = torch.randn(100, input_size)\\nlabels = torch.randint(0, 2, (100, 1)).float()\\n\\n# Training Loop\\nfor epoch in range(epochs):\\n model.train()\\n optimizer.zero_grad()\\n outputs = model(data)\\n loss = criterion(outputs, labels)\\n loss.backward()\\n optimizer.step()\\n\\n if (epoch + 1) % 100 == 0:\\n print(f\\'Epoch [{epoch+1}/{epochs}], Loss: {loss.item():.4f}\\')\\n\\nprint(\"Model training complete.\")\\n```\\n\\nThis is a simple example of a generative model in PyTorch. In actual drug discovery research, the models and datasets would be significantly more complex, often involving domain-specific features and large-scale datasets. For more detailed and complex implementations, refer to the provided articles and resources.', name='Researcher')]}}\n",
"----\n",
"{'supervisor': {'next': 'Coder'}}\n",
"----\n",
"{'Coder': {'messages': [HumanMessage(content='The information on generative AI in drug discovery for cancer research has been printed to the terminal. The code provided is a basic framework for a generative model using PyTorch. This example demonstrates the structure of such a model and how it might be trained using dummy data. For more detailed implementations and research, please refer to the linked articles.', name='Coder')]}}\n",
"----\n",
"{'supervisor': {'next': 'FINISH'}}\n",
"----\n"
]
}
],
"source": [
"for s in graph.stream(\n",
" {\n",
" \"messages\": [\n",
" HumanMessage(content=\"Code for drug discovery generative ai cancer research and print it to the terminal\")\n",
" ]\n",
" }\n",
"):\n",
" if \"__end__\" not in s:\n",
" print(s)\n",
" print(\"----\")"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "45a92dfd-0e11-47f5-aad4-b68d24990e34",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 0
},
"id": "45a92dfd-0e11-47f5-aad4-b68d24990e34",
"outputId": "73cd81aa-7962-47af-c945-e20b00941837"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'supervisor': {'next': 'Researcher'}}\n",
"----\n",
"{'Researcher': {'messages': [HumanMessage(content=\"## Research Report: ChemicalQDevice\\n\\n### Overview\\nChemicalQDevice is a technology company focused on leveraging generative artificial intelligence (GenAI) and quantum computing to address some of the world's critical challenges, particularly in the medical and drug discovery sectors. The company integrates advanced AI models and quantum technologies to enhance various applications, including critical care medical devices and drug discovery for diseases like cancer and Alzheimer's.\\n\\n### Key Areas of Focus\\n\\n1. **Generative Artificial Intelligence (GenAI)**\\n - The company emphasizes the use of generative AI to solve complex problems. This includes the development of local generative AI model frameworks compatible with macOS and iOS.\\n - They explore how to develop APIs for GenAI and utilize tools like LangChain for drug discovery.\\n\\n2. **Quantum Computing Technologies**\\n - Quantum Machine Learning Neuroimaging (QMLN) techniques are employed to improve the prediction and diagnosis of diseases such as Alzheimer's by enhancing image sensitivity, signal strength, and resolution.\\n - Their mission includes advancing the application of quantum technologies in medical imaging to provide better diagnostic tools.\\n\\n3. **Drug Discovery**\\n - ChemicalQDevice focuses on using generative AI for drug discovery, particularly in cancer research. Their software repository for cancer drug discovery is publicly available on platforms like GitHub.\\n\\n### Recent Developments\\n\\n- **Speed and Control in GenAI**: The company has made strides in improving the speed and control of generative AI models, particularly those developed in C++.\\n- **On-Device AI for Apple Products**: They are working on generative AI models that operate locally on Apple devices, including MacOS and iOS, enhancing the performance and privacy of AI applications.\\n\\n### Online Presence\\n\\n- **Website**: [ChemicalQDevice](https://www.chemicalqdevice.com/)\\n - The website provides detailed information on their projects, recent results, and insights into the integration of new quantum frameworks.\\n- **Social Media**: They maintain an active presence on platforms like Twitter and LinkedIn, sharing updates and engaging with the tech community.\\n - [Twitter](https://twitter.com/chemicalqdevice): Updates on quantum computing technologies for critical care medical devices.\\n - [LinkedIn](https://jm.linkedin.com/company/chemicalqdevice): Information on their mission and advancements in Alzheimer’s disease prediction using quantum machine learning.\\n- **YouTube**: The company also shares research summaries and future outlooks on platforms such as YouTube, focusing on their public repositories and advancements in cancer drug discovery.\\n\\n### Conclusion\\n\\nChemicalQDevice is at the forefront of integrating generative AI and quantum computing technologies to tackle significant medical challenges. Their work in drug discovery and medical imaging holds promise for improving diagnostic and treatment methods for diseases like cancer and Alzheimer's. Through their innovative use of AI and quantum technologies, they aim to make substantial contributions to critical care and medical research.\", name='Researcher')]}}\n",
"----\n",
"{'supervisor': {'next': 'Coder'}}\n",
"----\n",
"{'Coder': {'messages': [HumanMessage(content=\"### Detailed Analysis: ChemicalQDevice\\n\\n#### 1. **Generative Artificial Intelligence (GenAI)**\\n\\nChemicalQDevice's approach to GenAI is multi-faceted, targeting both the development of AI models and the creation of supportive frameworks and APIs to facilitate their deployment. Here are some key points:\\n\\n- **Local GenAI Models**: The company focuses on developing generative AI models that run locally on macOS and iOS devices. This not only enhances user privacy but also improves the performance of AI applications by reducing latency associated with cloud-based models.\\n \\n- **APIs for GenAI**: By creating APIs for generative AI, ChemicalQDevice aims to make these advanced models more accessible to developers. This includes APIs for specific applications like drug discovery, which can streamline the development process and enhance the functionality of AI-driven solutions.\\n\\n- **LangChain Integration**: LangChain, a framework for developing applications powered by language models, is used by ChemicalQDevice to facilitate drug discovery. This integration allows for more sophisticated data analysis and model training, ultimately leading to better results in identifying potential drug candidates.\\n\\n#### 2. **Quantum Computing Technologies**\\n\\nQuantum computing is a core component of ChemicalQDevice's strategy, particularly in the realm of medical imaging and diagnostics:\\n\\n- **Quantum Machine Learning Neuroimaging (QMLN)**: This technology is utilized to improve the accuracy and sensitivity of neuroimaging techniques. By leveraging quantum algorithms, QMLN can enhance image resolution and signal strength, providing clearer and more detailed images for diagnosing diseases like Alzheimer's.\\n\\n- **Mission and Vision**: ChemicalQDevice is dedicated to pushing the boundaries of what's possible with quantum technologies in medical imaging. Their goal is to develop tools that provide more reliable and early diagnoses, which are crucial for effective treatment planning.\\n\\n#### 3. **Drug Discovery**\\n\\nThe company's use of generative AI in drug discovery is particularly noteworthy:\\n\\n- **Cancer Research**: One of the primary applications of their technology is in the discovery of new cancer treatments. By using generative models, ChemicalQDevice can simulate and predict the efficacy of potential drug compounds, speeding up the research process.\\n\\n- **Public Repositories**: To foster collaboration and transparency, ChemicalQDevice makes its software repositories for cancer drug discovery publicly available. This allows researchers worldwide to access their tools and contribute to the development of new treatments.\\n\\n### Recent Developments\\n\\n- **Performance Enhancements in GenAI**: Recent improvements in the speed and control of generative AI models, particularly those developed in C++, have been a significant focus. These enhancements make the models more efficient and easier to deploy in real-world applications.\\n\\n- **On-Device AI for Apple Products**: By developing AI models that run locally on Apple devices, ChemicalQDevice is addressing key concerns around data privacy and security while also enhancing the responsiveness of AI applications.\\n\\n### Online Presence and Community Engagement\\n\\nChemicalQDevice actively engages with the tech and research communities through various online platforms:\\n\\n- **Website**: Their website serves as a comprehensive resource for information on their projects, research findings, and technological advancements.\\n \\n- **Social Media**: Platforms like Twitter and LinkedIn are used to share updates, engage with followers, and highlight significant achievements. These channels provide a way for the broader community to stay informed about their progress and initiatives.\\n \\n- **YouTube**: Videos on YouTube offer deeper insights into their research, including summaries of recent results and future outlooks. These videos are valuable for both academic and industry professionals interested in their work.\\n\\n### Conclusion\\n\\nChemicalQDevice is pioneering the integration of generative AI and quantum computing to address some of the most challenging problems in medical research and diagnostics. Their innovative approach to drug discovery and medical imaging has the potential to revolutionize the field, offering new tools and methods for early diagnosis and effective treatment of diseases like cancer and Alzheimer's. Through their commitment to transparency and community engagement, they are fostering a collaborative environment that could lead to significant advancements in healthcare technology.\\n\\nOverall, ChemicalQDevice exemplifies the transformative potential of combining cutting-edge technologies with a mission-driven approach to solving critical global challenges.\", name='Coder')]}}\n",
"----\n",
"{'supervisor': {'next': 'FINISH'}}\n",
"----\n"
]
}
],
"source": [
"for s in graph.stream(\n",
" {\"messages\": [HumanMessage(content=\"Write a research report on this website https://www.chemicalqdevice.com/.\")]},\n",
" {\"recursion_limit\": 100},\n",
"):\n",
" if \"__end__\" not in s:\n",
" print(s)\n",
" print(\"----\")"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "1d363d2c-e0da-4cce-ba47-ad2aa9df0fef",
"metadata": {
"id": "1d363d2c-e0da-4cce-ba47-ad2aa9df0fef"
},
"outputs": [],
"source": []
}
],
"metadata": {
"colab": {
"machine_shape": "hm",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"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.1"
}
},
"nbformat": 4,
"nbformat_minor": 5
}