From 35761c35f86774b9bad4987afe4dfe31de220d58 Mon Sep 17 00:00:00 2001 From: Ary Date: Tue, 26 Mar 2024 02:15:08 +0800 Subject: [PATCH 1/8] add solar model --- agent/language_models.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/agent/language_models.py b/agent/language_models.py index d47608f..52d3eea 100644 --- a/agent/language_models.py +++ b/agent/language_models.py @@ -23,6 +23,10 @@ def get_async_client(provider: str) -> AsyncOpenAI: return AsyncOpenAI( base_url="https://api.mistral.ai/v1/", api_key=os.getenv("MISTRAL_API_KEY") ) + if provider == "solar": + return AsyncOpenAI( + base_url="https://api.upstage.ai/v1/solar", api_key=os.getenv("SOLAR_API_KEY") + ) if provider == "ollama": return AsyncOpenAI(base_url="http://localhost:11434/v1/") raise NotImplementedError(f"Provider {provider} is not supported.") @@ -35,6 +39,10 @@ def get_sync_client(provider: str) -> OpenAI: return OpenAI( base_url="https://api.mistral.ai/v1/", api_key=os.getenv("MISTRAL_API_KEY") ) + if provider == "solar": + return OpenAI( + base_url="https://api.upstage.ai/v1/solar", api_key=os.getenv("SOLAR_API_KEY") + ) if provider == "ollama": return OpenAI(base_url="http://localhost:11434/v1/") if provider == "groq": From 52197fcb576d2d1f34e138fadda4949005e807c5 Mon Sep 17 00:00:00 2001 From: Ary Date: Tue, 2 Apr 2024 21:55:03 +0800 Subject: [PATCH 2/8] add solar --- agent/actions.py | 1 + agent/config.py | 15 +++++++++------ agent/language_models.py | 1 + eval/game.py | 26 ++++++++++++++++---------- script.py | 2 +- 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/agent/actions.py b/agent/actions.py index d0e31e6..8b24ab0 100644 --- a/agent/actions.py +++ b/agent/actions.py @@ -32,6 +32,7 @@ def call_llm( """ # Get the correct provider, default is mistral provider_name, model_name = get_provider_and_model(model) + print("Provider", provider_name, model_name) client = get_sync_client(provider_name) # Generate the prompts diff --git a/agent/config.py b/agent/config.py index 1fc65d2..86ce8d8 100644 --- a/agent/config.py +++ b/agent/config.py @@ -1,15 +1,18 @@ MODELS = { "OPENAI": { - "openai:gpt-4-0125-preview", - "openai:gpt-4", + # "openai:gpt-4-0125-preview", + # "openai:gpt-4", "openai:gpt-3.5-turbo-0125", # "openai:gpt-3.5-turbo-instruct", # not a chat model }, "MISTRAL": { - "mistral:mistral-small-latest", - "mistral:mistral-medium-latest", - "mistral:mistral-large-latest", - # "groq:mistral-8x6b-32768", + # "mistral:mistral-small-latest", + # "mistral:mistral-medium-latest", + # "mistral:mistral-large-latest", + "mistral:open-mistral-7b", + }, + "Solar": { + "solar:solar-1-mini-chat", }, } diff --git a/agent/language_models.py b/agent/language_models.py index 52d3eea..2dcf8f7 100644 --- a/agent/language_models.py +++ b/agent/language_models.py @@ -40,6 +40,7 @@ def get_sync_client(provider: str) -> OpenAI: base_url="https://api.mistral.ai/v1/", api_key=os.getenv("MISTRAL_API_KEY") ) if provider == "solar": + print("solar key", os.getenv("SOLAR_API_KEY")) return OpenAI( base_url="https://api.upstage.ai/v1/solar", api_key=os.getenv("SOLAR_API_KEY") ) diff --git a/eval/game.py b/eval/game.py index c36004f..bf70f53 100644 --- a/eval/game.py +++ b/eval/game.py @@ -18,7 +18,7 @@ from agent.config import MODELS -def generate_model(openai: bool = False, mistral: bool = True): +def generate_model(openai: bool = False, mistral: bool = True, solar: bool = False): models_available = [] for model, models in MODELS.items(): @@ -26,7 +26,9 @@ def generate_model(openai: bool = False, mistral: bool = True): models_available.extend(models) if mistral and model == "MISTRAL": models_available.extend(models) - + if solar and model == "Solar": + models_available.extend(models) + print('models:', models_available) random.seed() # Generate a pair of random two models random_model = random.choice(models_available) @@ -49,14 +51,15 @@ def __init__( model: Optional[str] = None, openai: bool = False, mistral: bool = True, + solar: bool = False, ): self.nickname = nickname - self.model = model or generate_model(openai=openai, mistral=mistral) + self.model = model or generate_model(openai=False, mistral=True, solar=False) self.openai = False self.mistral = True self.robot = Robot( action_space=None, - character="Ken", + character="Mistral", side=0, character_color=KEN_RED, ennemy_color=KEN_GREEN, @@ -74,12 +77,13 @@ def __init__( model: Optional[str] = None, openai: bool = False, mistral: bool = True, + solar: bool = False, ): self.nickname = nickname - self.model = model or generate_model(openai=openai, mistral=mistral) + self.model = model or generate_model(openai=False, mistral=False, solar=solar) self.robot = Robot( action_space=None, - character="Ken", + character="Solar", side=1, character_color=KEN_GREEN, ennemy_color=KEN_RED, @@ -120,7 +124,7 @@ class Game: render: Optional[bool] = False splash_screen: Optional[bool] = False save_game: Optional[bool] = False - characters: Optional[List[str]] = ["Ken", "Ken"] + characters: Optional[List[str]] = ["Makoto", "Sean"] outfits: Optional[List[int]] = [1, 3] frame_shape: Optional[List[int]] = [0, 0, 0] seed: Optional[int] = 42 @@ -136,7 +140,7 @@ def __init__( render: bool = False, save_game: bool = False, splash_screen: bool = False, - characters: List[str] = ["Ken", "Ken"], + characters: List[str] = ["Makoto", "Sean"], super_arts: List[int] = [3,3], outfits: List[int] = [1, 3], frame_shape: List[int] = [0, 0, 0], @@ -145,6 +149,7 @@ def __init__( player_2: Player2 = None, openai: bool = False, mistral: bool = True, + solar: bool = False, ): """_summary_ @@ -169,17 +174,18 @@ def __init__( self.observation, self.info = self.env.reset(seed=self.seed) self.openai = openai self.mistral = mistral + self.solar = solar self.player_1 = ( player_1 if player_1 - else Player1(nickname="Player 1", openai=self.openai, mistral=self.mistral) + else Player1(nickname="Player 1", openai=self.openai, mistral=self.mistral, solar=self.solar) # else Player1(nickname="Player 1", model="grok:mixtral-8x7b-32768") ) self.player_2 = ( player_2 if player_2 # else Player2(nickname="Player 2", model="openai:gpt-4-turbo-preview") - else Player2(nickname="Player 2", openai=self.openai, mistral=self.mistral) + else Player2(nickname="Player 2", openai=self.openai, mistral=self.mistral, solar=self.solar) ) def _init_settings(self) -> EnvironmentSettingsMultiAgent: diff --git a/script.py b/script.py index 5b653dd..a21c95a 100644 --- a/script.py +++ b/script.py @@ -15,7 +15,7 @@ def main(): # Environment Settings # Environment Settings while True: - game = Game(render=True, save_game=True, openai=True) + game = Game(render=True, save_game=True, openai=True, solar=True, mistral=False) game.run() From 92910cf9027954ae8903be94c1086a6056a9a8a8 Mon Sep 17 00:00:00 2001 From: Ary Date: Wed, 3 Apr 2024 03:32:11 +0800 Subject: [PATCH 3/8] add solar --- agent/config.py | 5 +++-- agent/language_models.py | 1 - eval/game.py | 15 +++++++++------ 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/agent/config.py b/agent/config.py index 86ce8d8..fc5a1e8 100644 --- a/agent/config.py +++ b/agent/config.py @@ -6,10 +6,11 @@ # "openai:gpt-3.5-turbo-instruct", # not a chat model }, "MISTRAL": { - # "mistral:mistral-small-latest", + "mistral:mistral-small-latest", # "mistral:mistral-medium-latest", # "mistral:mistral-large-latest", - "mistral:open-mistral-7b", + # "mistral:open-mistral-7b", + # "mistral:open-mixtral-8x7b", }, "Solar": { "solar:solar-1-mini-chat", diff --git a/agent/language_models.py b/agent/language_models.py index 2dcf8f7..52d3eea 100644 --- a/agent/language_models.py +++ b/agent/language_models.py @@ -40,7 +40,6 @@ def get_sync_client(provider: str) -> OpenAI: base_url="https://api.mistral.ai/v1/", api_key=os.getenv("MISTRAL_API_KEY") ) if provider == "solar": - print("solar key", os.getenv("SOLAR_API_KEY")) return OpenAI( base_url="https://api.upstage.ai/v1/solar", api_key=os.getenv("SOLAR_API_KEY") ) diff --git a/eval/game.py b/eval/game.py index bf70f53..2a8907d 100644 --- a/eval/game.py +++ b/eval/game.py @@ -54,7 +54,7 @@ def __init__( solar: bool = False, ): self.nickname = nickname - self.model = model or generate_model(openai=False, mistral=True, solar=False) + self.model = model or generate_model(openai=openai, mistral=mistral, solar=solar) self.openai = False self.mistral = True self.robot = Robot( @@ -80,7 +80,7 @@ def __init__( solar: bool = False, ): self.nickname = nickname - self.model = model or generate_model(openai=False, mistral=False, solar=solar) + self.model = model or generate_model(openai=openai, mistral=mistral, solar=solar) self.robot = Robot( action_space=None, character="Solar", @@ -124,7 +124,8 @@ class Game: render: Optional[bool] = False splash_screen: Optional[bool] = False save_game: Optional[bool] = False - characters: Optional[List[str]] = ["Makoto", "Sean"] + # characters: Optional[List[str]] = ["Makoto", "Sean"] + characters: Optional[List[str]] = ["Ken", "Ken"] outfits: Optional[List[int]] = [1, 3] frame_shape: Optional[List[int]] = [0, 0, 0] seed: Optional[int] = 42 @@ -140,7 +141,8 @@ def __init__( render: bool = False, save_game: bool = False, splash_screen: bool = False, - characters: List[str] = ["Makoto", "Sean"], + characters: List[str] = ["Ken", "Ken"], + # characters: List[str] = ["Makoto", "Sean"], super_arts: List[int] = [3,3], outfits: List[int] = [1, 3], frame_shape: List[int] = [0, 0, 0], @@ -175,17 +177,18 @@ def __init__( self.openai = openai self.mistral = mistral self.solar = solar + print("GAME", openai, mistral, solar, player_1, player_2) self.player_1 = ( player_1 if player_1 - else Player1(nickname="Player 1", openai=self.openai, mistral=self.mistral, solar=self.solar) + else Player1(nickname="Player 1", openai=False, mistral=False, solar=True) # else Player1(nickname="Player 1", model="grok:mixtral-8x7b-32768") ) self.player_2 = ( player_2 if player_2 # else Player2(nickname="Player 2", model="openai:gpt-4-turbo-preview") - else Player2(nickname="Player 2", openai=self.openai, mistral=self.mistral, solar=self.solar) + else Player2(nickname="Player 2", openai=False, mistral=True, solar=False) ) def _init_settings(self) -> EnvironmentSettingsMultiAgent: From 02f071756f52f1a24c58cda0efc3d69be53d17bd Mon Sep 17 00:00:00 2001 From: Ary Date: Tue, 9 Apr 2024 01:30:44 +0800 Subject: [PATCH 4/8] add video --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 52701d8..b26169c 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,12 @@ https://github.com/OpenGenerativeAI/llm-colosseum/assets/19614572/79b58e26-7902- https://github.com/OpenGenerativeAI/llm-colosseum/assets/19614572/5d3d386b-150a-48a5-8f68-7e2954ec18db +1 VS 1: Mistral 7B vs Solar +* mistral-small-latest vs solar-1-mini-chat +* mistral-medium-latest vs solar-1-mini-chat + +* mistral-large-latest vs solar-1-mini-chat ## A new kind of benchmark ? From 5b6ebbfb5152c4a89bdbfcaaf8e2737304e2fa63 Mon Sep 17 00:00:00 2001 From: Ary Date: Tue, 9 Apr 2024 01:31:11 +0800 Subject: [PATCH 5/8] add video --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b26169c..a597ead 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ https://github.com/OpenGenerativeAI/llm-colosseum/assets/19614572/79b58e26-7902- https://github.com/OpenGenerativeAI/llm-colosseum/assets/19614572/5d3d386b-150a-48a5-8f68-7e2954ec18db -1 VS 1: Mistral 7B vs Solar +### 1 VS 1: Mistral 7B vs Solar * mistral-small-latest vs solar-1-mini-chat * mistral-medium-latest vs solar-1-mini-chat From c67f21e9d00236799a023eb69a1d9c6ecaee4e8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E7=92=9F=E7=90=A6?= Date: Tue, 9 Apr 2024 01:32:52 +0800 Subject: [PATCH 6/8] Update README.md --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a597ead..0082e53 100644 --- a/README.md +++ b/README.md @@ -35,11 +35,12 @@ https://github.com/OpenGenerativeAI/llm-colosseum/assets/19614572/79b58e26-7902- https://github.com/OpenGenerativeAI/llm-colosseum/assets/19614572/5d3d386b-150a-48a5-8f68-7e2954ec18db ### 1 VS 1: Mistral 7B vs Solar -* mistral-small-latest vs solar-1-mini-chat - -* mistral-medium-latest vs solar-1-mini-chat - -* mistral-large-latest vs solar-1-mini-chat +#### mistral-small-latest vs solar-1-mini-chat +https://github.com/Tokkiu/llm-colosseum/assets/13414571/2a7e681d-d022-486c-9250-68fedff4b069 +#### mistral-medium-latest vs solar-1-mini-chat +https://github.com/Tokkiu/llm-colosseum/assets/13414571/d0532e43-11e2-447e-b2b3-6023b9760f11 +#### mistral-large-latest vs solar-1-mini-chat +https://github.com/Tokkiu/llm-colosseum/assets/13414571/4757d562-f800-40ef-8f1a-675b0e23b8ed ## A new kind of benchmark ? From 6f9065f0ea25cbb593560edac65f18ae2442ed52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E7=92=9F=E7=90=A6?= Date: Tue, 9 Apr 2024 01:33:58 +0800 Subject: [PATCH 7/8] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0082e53..2cf0010 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ https://github.com/OpenGenerativeAI/llm-colosseum/assets/19614572/79b58e26-7902- https://github.com/OpenGenerativeAI/llm-colosseum/assets/19614572/5d3d386b-150a-48a5-8f68-7e2954ec18db -### 1 VS 1: Mistral 7B vs Solar +### 1 VS 1: Mistral vs Solar #### mistral-small-latest vs solar-1-mini-chat https://github.com/Tokkiu/llm-colosseum/assets/13414571/2a7e681d-d022-486c-9250-68fedff4b069 #### mistral-medium-latest vs solar-1-mini-chat From 32c90556a7fe7b718d7a7cb0ad8b201d76d84391 Mon Sep 17 00:00:00 2001 From: Ary Date: Thu, 11 Apr 2024 10:12:14 +0800 Subject: [PATCH 8/8] fix conflict --- .env.example | 1 - .gitignore | 3 +- LICENCE | 21 + Makefile | 7 +- Pipfile | 20 - Pipfile.lock | 1328 ------------------------------------ README.md | 146 +++- agent/config.py | 5 + agent/observer.py | 6 +- agent/prompts.py | 39 -- agent/robot.py | 153 +++-- demo.py | 34 + eval/game.py | 195 +++--- mistral.py | 38 -- elo.md => notebooks/elo.md | 0 ollama.py | 36 + requirements.txt | 5 +- script.py | 24 +- 18 files changed, 460 insertions(+), 1601 deletions(-) create mode 100644 LICENCE delete mode 100644 Pipfile delete mode 100644 Pipfile.lock delete mode 100644 agent/prompts.py create mode 100644 demo.py delete mode 100644 mistral.py rename elo.md => notebooks/elo.md (100%) create mode 100644 ollama.py diff --git a/.env.example b/.env.example index 86fe919..fe7f314 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,4 @@ MISTRAL_API_KEY="" OPENAI_API_KEY="" GROK_API_KEY="" -MODEL_PROVIDER="openai" # Options: ["openai", "mistral"] DISABLE_LLM="False" diff --git a/.gitignore b/.gitignore index bc116dd..327b809 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ eval/diambra results.csv results/ -.DS_Store \ No newline at end of file +.DS_Store +.idea \ No newline at end of file diff --git a/LICENCE b/LICENCE new file mode 100644 index 0000000..5ac648d --- /dev/null +++ b/LICENCE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Open GenerativeAI Junior Research LLM Colosseum + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile index e5b88a8..e452b98 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,11 @@ run: - diambra -r ~/.diambra/roms run python3 script.py + diambra -r ~/.diambra/roms run -l python3 script.py demo: - diambra -r ~/.diambra/roms run python3 mistral.py && python3 result.py + diambra -r ~/.diambra/roms run -l python3 demo.py && python3 result.py + +local: + diambra -r ~/.diambra/roms run -l python3 ollama.py install: pip3 install -r requirements.txt diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 9b69a10..0000000 --- a/Pipfile +++ /dev/null @@ -1,20 +0,0 @@ -[[source]] -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - -[packages] -diambra = "==0.0.17" -diambra-arena = "==2.2.6" -openai = "==1.14.2" -python-dotenv = "==1.0.1" -loguru = "==0.7.2" -pandas = "*" -matplotlib = "*" -tkinter = "*" - -[dev-packages] -ipykernel = "*" - -[requires] -python_version = "3.12" diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 816c2e7..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,1328 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "939893546ce9e67d2bf3de58a9111f1af07767f82ac2d83469eb984ccd1577f1" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.12" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "annotated-types": { - "hashes": [ - "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43", - "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d" - ], - "markers": "python_version >= '3.8'", - "version": "==0.6.0" - }, - "anyio": { - "hashes": [ - "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8", - "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6" - ], - "markers": "python_version >= '3.8'", - "version": "==4.3.0" - }, - "certifi": { - "hashes": [ - "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", - "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" - ], - "markers": "python_version >= '3.6'", - "version": "==2024.2.2" - }, - "cloudpickle": { - "hashes": [ - "sha256:246ee7d0c295602a036e86369c77fecda4ab17b506496730f2f576d9016fd9c7", - "sha256:996d9a482c6fb4f33c1a35335cf8afd065d2a56e973270364840712d9131a882" - ], - "markers": "python_version >= '3.8'", - "version": "==3.0.0" - }, - "contourpy": { - "hashes": [ - "sha256:0274c1cb63625972c0c007ab14dd9ba9e199c36ae1a231ce45d725cbcbfd10a8", - "sha256:0d7e03c0f9a4f90dc18d4e77e9ef4ec7b7bbb437f7f675be8e530d65ae6ef956", - "sha256:11f8d2554e52f459918f7b8e6aa20ec2a3bce35ce95c1f0ef4ba36fbda306df5", - "sha256:139d8d2e1c1dd52d78682f505e980f592ba53c9f73bd6be102233e358b401063", - "sha256:16a7380e943a6d52472096cb7ad5264ecee36ed60888e2a3d3814991a0107286", - "sha256:171f311cb758de7da13fc53af221ae47a5877be5a0843a9fe150818c51ed276a", - "sha256:18fc2b4ed8e4a8fe849d18dce4bd3c7ea637758c6343a1f2bae1e9bd4c9f4686", - "sha256:1c203f617abc0dde5792beb586f827021069fb6d403d7f4d5c2b543d87edceb9", - "sha256:1c2559d6cffc94890b0529ea7eeecc20d6fadc1539273aa27faf503eb4656d8f", - "sha256:1c88dfb9e0c77612febebb6ac69d44a8d81e3dc60f993215425b62c1161353f4", - "sha256:1e9dc350fb4c58adc64df3e0703ab076f60aac06e67d48b3848c23647ae4310e", - "sha256:247b9d16535acaa766d03037d8e8fb20866d054d3c7fbf6fd1f993f11fc60ca0", - "sha256:266270c6f6608340f6c9836a0fb9b367be61dde0c9a9a18d5ece97774105ff3e", - "sha256:34b9071c040d6fe45d9826cbbe3727d20d83f1b6110d219b83eb0e2a01d79488", - "sha256:3d7d1f8871998cdff5d2ff6a087e5e1780139abe2838e85b0b46b7ae6cc25399", - "sha256:461e3ae84cd90b30f8d533f07d87c00379644205b1d33a5ea03381edc4b69431", - "sha256:464b423bc2a009088f19bdf1f232299e8b6917963e2b7e1d277da5041f33a779", - "sha256:491b1917afdd8638a05b611a56d46587d5a632cabead889a5440f7c638bc6ed9", - "sha256:4a1b1208102be6e851f20066bf0e7a96b7d48a07c9b0cfe6d0d4545c2f6cadab", - "sha256:575bcaf957a25d1194903a10bc9f316c136c19f24e0985a2b9b5608bdf5dbfe0", - "sha256:5c6b28956b7b232ae801406e529ad7b350d3f09a4fde958dfdf3c0520cdde0dd", - "sha256:5d16edfc3fc09968e09ddffada434b3bf989bf4911535e04eada58469873e28e", - "sha256:5fd1810973a375ca0e097dee059c407913ba35723b111df75671a1976efa04bc", - "sha256:67b7f17679fa62ec82b7e3e611c43a016b887bd64fb933b3ae8638583006c6d6", - "sha256:68ce4788b7d93e47f84edd3f1f95acdcd142ae60bc0e5493bfd120683d2d4316", - "sha256:6d3364b999c62f539cd403f8123ae426da946e142312a514162adb2addd8d808", - "sha256:6e739530c662a8d6d42c37c2ed52a6f0932c2d4a3e8c1f90692ad0ce1274abe0", - "sha256:6fdd887f17c2f4572ce548461e4f96396681212d858cae7bd52ba3310bc6f00f", - "sha256:78e6ad33cf2e2e80c5dfaaa0beec3d61face0fb650557100ee36db808bfa6843", - "sha256:884c3f9d42d7218304bc74a8a7693d172685c84bd7ab2bab1ee567b769696df9", - "sha256:8d8faf05be5ec8e02a4d86f616fc2a0322ff4a4ce26c0f09d9f7fb5330a35c95", - "sha256:999c71939aad2780f003979b25ac5b8f2df651dac7b38fb8ce6c46ba5abe6ae9", - "sha256:99ad97258985328b4f207a5e777c1b44a83bfe7cf1f87b99f9c11d4ee477c4de", - "sha256:9e6c93b5b2dbcedad20a2f18ec22cae47da0d705d454308063421a3b290d9ea4", - "sha256:ab459a1cbbf18e8698399c595a01f6dcc5c138220ca3ea9e7e6126232d102bb4", - "sha256:b69303ceb2e4d4f146bf82fda78891ef7bcd80c41bf16bfca3d0d7eb545448aa", - "sha256:b7caf9b241464c404613512d5594a6e2ff0cc9cb5615c9475cc1d9b514218ae8", - "sha256:b95a225d4948b26a28c08307a60ac00fb8671b14f2047fc5476613252a129776", - "sha256:bd2f1ae63998da104f16a8b788f685e55d65760cd1929518fd94cd682bf03e41", - "sha256:be16975d94c320432657ad2402f6760990cb640c161ae6da1363051805fa8108", - "sha256:ce96dd400486e80ac7d195b2d800b03e3e6a787e2a522bfb83755938465a819e", - "sha256:dbd50d0a0539ae2e96e537553aff6d02c10ed165ef40c65b0e27e744a0f10af8", - "sha256:dd10c26b4eadae44783c45ad6655220426f971c61d9b239e6f7b16d5cdaaa727", - "sha256:ebeac59e9e1eb4b84940d076d9f9a6cec0064e241818bcb6e32124cc5c3e377a" - ], - "markers": "python_version >= '3.9'", - "version": "==1.2.0" - }, - "cycler": { - "hashes": [ - "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", - "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c" - ], - "markers": "python_version >= '3.8'", - "version": "==0.12.1" - }, - "cython": { - "hashes": [ - "sha256:000af6deb7412eb7ac0c635ff5e637fb8725dd0a7b88cc58dfc2b3de14e701c4", - "sha256:00b105b5d050645dd59e6767bc0f18b48a4aa11c85f42ec7dd8181606f4059e3", - "sha256:02c6e809f060bed073dc7cba1648077fe3b68208863d517c8b39f3920eecf9dd", - "sha256:09c44501d476d16aaa4cbc29c87f8c0f54fc20e69b650d59cbfa4863426fc70c", - "sha256:1315aee506506e8d69cf6631d8769e6b10131fdcc0eb66df2698f2a3ddaeeff2", - "sha256:1365d5f76bf4d19df3d19ce932584c9bb76e9fb096185168918ef9b36e06bfa4", - "sha256:157973807c2796addbed5fbc4d9c882ab34bbc60dc297ca729504901479d5df7", - "sha256:158c38360bbc5063341b1e78d3737f1251050f89f58a3df0d10fb171c44262be", - "sha256:15c7f5c2d35bed9aa5f2a51eaac0df23ae72f2dbacf62fc672dd6bfaa75d2d6f", - "sha256:1dc320a9905ab95414013f6de805efbff9e17bb5fb3b90bbac533f017bec8136", - "sha256:22b8fae756c5c0d8968691bed520876de452f216c28ec896a00739a12dba3bd9", - "sha256:296bd30d4445ac61b66c9d766567f6e81a6e262835d261e903c60c891a6729d3", - "sha256:2cc92504b5d22ac66031ffb827bd3a967fc75a5f0f76ab48bce62df19be6fdfd", - "sha256:2fd198c1a7f8e9382904d622cc0efa3c184605881fd5262c64cbb7168c4c1ec5", - "sha256:33b6ac376538a7fc8c567b85d3c71504308a9318702ec0485dd66c059f3165cb", - "sha256:357e2fad46a25030b0c0496487e01a9dc0fdd0c09df0897f554d8ba3c1bc4872", - "sha256:35e6665a20d6b8a152d72b7fd87dbb2af6bb6b18a235b71add68122d594dbd41", - "sha256:36f5a2dfc724bea1f710b649f02d802d80fc18320c8e6396684ba4a48412445a", - "sha256:38df37d0e732fbd9a2fef898788492e82b770c33d1e4ed12444bbc8a3b3f89c0", - "sha256:44457279da56e0f829bb1fc5a5dc0836e5d498dbcf9b2324f32f7cc9d2ec6569", - "sha256:4558814fa025b193058d42eeee498a53d6b04b2980d01339fc2444b23fd98e58", - "sha256:4ae349960ebe0da0d33724eaa7f1eb866688fe5434cc67ce4dbc06d6a719fbfc", - "sha256:4cf0ed273bf60e97922fcbbdd380c39693922a597760160b4b4355e6078ca188", - "sha256:4f836192140f033b2319a0128936367c295c2b32e23df05b03b672a6015757ea", - "sha256:5055988b007c92256b6e9896441c3055556038c3497fcbf8c921a6c1fce90719", - "sha256:530c01c4aebba709c0ec9c7ecefe07177d0b9fd7ffee29450a118d92192ccbdf", - "sha256:539cd1d74fd61f6cfc310fa6bbbad5adc144627f2b7486a07075d4e002fd6aad", - "sha256:56f3b643dbe14449248bbeb9a63fe3878a24256664bc8c8ef6efd45d102596d8", - "sha256:5eb9bd4ae12ebb2bc79a193d95aacf090fbd8d7013e11ed5412711650cb34934", - "sha256:63d2537bf688247f76ded6dee28ebd26274f019309aef1eb4f2f9c5c482fde2d", - "sha256:757ca93bdd80702546df4d610d2494ef2e74249cac4d5ba9464589fb464bd8a3", - "sha256:858c3766b9aa3ab8a413392c72bbab1c144a9766b7c7bfdef64e2e414363fa0c", - "sha256:8bf30b045f7deda0014b042c1b41c1d272facc762ab657529e3b05505888e878", - "sha256:8edd59d22950b400b03ca78d27dc694d2836a92ef0cac4f64cb4b2ff902f7e25", - "sha256:95ed792c966f969cea7489c32ff90150b415c1f3567db8d5a9d489c7c1602dac", - "sha256:976c8d2bedc91ff6493fc973d38b2dc01020324039e2af0e049704a8e1b22936", - "sha256:9a001fd95c140c94d934078544ff60a3c46aca2dc86e75a76e4121d3cd1f4b33", - "sha256:9cda0d92a09f3520f29bd91009f1194ba9600777c02c30c6d2d4ac65fb63e40d", - "sha256:a274fe9ca5c53fafbcf5c8f262f8ad6896206a466f0eeb40aaf36a7951e957c0", - "sha256:a2d354f059d1f055d34cfaa62c5b68bc78ac2ceab6407148d47fb508cf3ba4f3", - "sha256:a30d96938c633e3ec37000ac3796525da71254ef109e66bdfd78f29891af6454", - "sha256:ac5536d09bef240cae0416d5a703d298b74c7bbc397da803ac9d344e732d4369", - "sha256:ad7fd88ebaeaf2e76fd729a8919fae80dab3d6ac0005e28494261d52ff347a8f", - "sha256:bf96417714353c5454c2e3238fca9338599330cf51625cdc1ca698684465646f", - "sha256:c0eb1e6ef036028a52525fd9a012a556f6dd4788a0e8755fe864ba0e70cde2ff", - "sha256:c232e7f279388ac9625c3e5a5a9f0078a9334959c5d6458052c65bbbba895e1e", - "sha256:c3232926cd406ee02eabb732206f6e882c3aed9d58f0fea764013d9240405bcf", - "sha256:c4b419a1adc2af43f4660e2f6eaf1e4fac2dbac59490771eb8ac3d6063f22356", - "sha256:c8191941073ea5896321de3c8c958fd66e5f304b0cd1f22c59edd0b86c4dd90d", - "sha256:cc9c3b9f20d8e298618e5ccd32083ca386e785b08f9893fbec4c50b6b85be772", - "sha256:d6f3ff1cd6123973fe03e0fb8ee936622f976c0c41138969975824d08886572b", - "sha256:d9360606d964c2d0492a866464efcf9d0a92715644eede3f6a2aa696de54a137", - "sha256:deaf4197d4b0bcd5714a497158ea96a2bd6d0f9636095437448f7e06453cc83d", - "sha256:e32b016030bc72a8a22a1f21f470a2f57573761a4f00fbfe8347263f4fbdb9f1", - "sha256:ec612418490941ed16c50c8d3784c7bdc4c4b2a10c361259871790b02ec8c1db", - "sha256:f496b52845cb45568a69d6359a2c335135233003e708ea02155c10ce3548aa89", - "sha256:f49aa4970cd3bec66ac22e701def16dca2a49c59cceba519898dd7526e0be2c0", - "sha256:f92f4960c40ad027bd8c364c50db11104eadc59ffeb9e5b7f605ca2f05946e20" - ], - "markers": "sys_platform == 'darwin'", - "version": "==3.0.9" - }, - "dacite": { - "hashes": [ - "sha256:cc31ad6fdea1f49962ea42db9421772afe01ac5442380d9a99fcf3d188c61afe" - ], - "markers": "python_version >= '3.6'", - "version": "==1.8.1" - }, - "diambra": { - "hashes": [ - "sha256:19363e2406b0e6a2e1e73563faa4d6a2e8dba3dcebaf139e042b1af9cd180d13", - "sha256:531ca0dfb396839d6e50823a8cbef5a2672abbc6e1bebdbafdb4ab6a9096c659", - "sha256:9c0cf47a6018035b603ec594753573bd336396cfb8592fdc0e15353d9c46f7f2", - "sha256:a63fd1fce45b5664b6bb5fc603fe45e029af40e0459370f00768244c71632af2", - "sha256:d77d7679b6645634a0197658b209532625566fbbcd69bb500fd3bc9061004624" - ], - "index": "pypi", - "version": "==0.0.17" - }, - "diambra-arena": { - "hashes": [ - "sha256:1e1df67283ccbd36df252a33f8255bb6be0395acfef620dbe2798ee42b785c94", - "sha256:a7b3a01b0f365180c821a049d4912149cdbf29f57586e07000abdff583ed4ec8" - ], - "index": "pypi", - "version": "==2.2.6" - }, - "diambra-engine": { - "hashes": [ - "sha256:02059b8be1415e90741de37c58030e6f70d864902c7081caab165bc8552e75b3", - "sha256:c080f30ea394c28ef6ba8c371a5859cf242827059d2b95c4c2cbe7145a1dcdf5" - ], - "markers": "python_version >= '3.6'", - "version": "==2.2.1" - }, - "distro": { - "hashes": [ - "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", - "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2" - ], - "markers": "python_version >= '3.6'", - "version": "==1.9.0" - }, - "farama-notifications": { - "hashes": [ - "sha256:13fceff2d14314cf80703c8266462ebf3733c7d165336eee998fc58e545efd18", - "sha256:14de931035a41961f7c056361dc7f980762a143d05791ef5794a751a2caf05ae" - ], - "version": "==0.0.4" - }, - "fonttools": { - "hashes": [ - "sha256:0743fd2191ad7ab43d78cd747215b12033ddee24fa1e088605a3efe80d6984de", - "sha256:074841375e2e3d559aecc86e1224caf78e8b8417bb391e7d2506412538f21adc", - "sha256:0ccc85fd96373ab73c59833b824d7a73846670a0cb1f3afbaee2b2c426a8f931", - "sha256:2c673ab40d15a442a4e6eb09bf007c1dda47c84ac1e2eecbdf359adacb799c24", - "sha256:34692850dfd64ba06af61e5791a441f664cb7d21e7b544e8f385718430e8f8e4", - "sha256:3566bfb8c55ed9100afe1ba6f0f12265cd63a1387b9661eb6031a1578a28bad1", - "sha256:35e10ddbc129cf61775d58a14f2d44121178d89874d32cae1eac722e687d9019", - "sha256:39293ff231b36b035575e81c14626dfc14407a20de5262f9596c2cbb199c3625", - "sha256:3d7080cce7be5ed65bee3496f09f79a82865a514863197ff4d4d177389e981b0", - "sha256:3dfb102e7f63b78c832e4539969167ffcc0375b013080e6472350965a5fe8048", - "sha256:47abd6669195abe87c22750dbcd366dc3a0648f1b7c93c2baa97429c4dc1506e", - "sha256:48fa36da06247aa8282766cfd63efff1bb24e55f020f29a335939ed3844d20d3", - "sha256:4f2ce7b0b295fe64ac0a85aef46a0f2614995774bd7bc643b85679c0283287f9", - "sha256:678dd95f26a67e02c50dcb5bf250f95231d455642afbc65a3b0bcdacd4e4dd38", - "sha256:77844e2f1b0889120b6c222fc49b2b75c3d88b930615e98893b899b9352a27ea", - "sha256:778c5f43e7e654ef7fe0605e80894930bc3a7772e2f496238e57218610140f54", - "sha256:7913992ab836f621d06aabac118fc258b9947a775a607e1a737eb3a91c360335", - "sha256:8639be40d583e5d9da67795aa3eeeda0488fb577a1d42ae11a5036f18fb16d93", - "sha256:8844e7a2c5f7ecf977e82eb6b3014f025c8b454e046d941ece05b768be5847ae", - "sha256:8e0a1c5bd2f63da4043b63888534b52c5a1fd7ae187c8ffc64cbb7ae475b9dab", - "sha256:9b3ac35cdcd1a4c90c23a5200212c1bb74fa05833cc7c14291d7043a52ca2aaa", - "sha256:9e58fe34cb379ba3d01d5d319d67dd3ce7ca9a47ad044ea2b22635cd2d1247fc", - "sha256:9fff65fbb7afe137bac3113827855e0204482727bddd00a806034ab0d3951d0d", - "sha256:a0493dd97ac8977e48ffc1476b932b37c847cbb87fd68673dee5182004906828", - "sha256:a4062cc7e8de26f1603323ef3ae2171c9d29c8a9f5e067d555a2813cd5c7a7e0", - "sha256:a467ba4e2eadc1d5cc1a11d355abb945f680473fbe30d15617e104c81f483045", - "sha256:a51eeaf52ba3afd70bf489be20e52fdfafe6c03d652b02477c6ce23c995222f4", - "sha256:ac2463de667233372e9e1c7e9de3d914b708437ef52a3199fdbf5a60184f190c", - "sha256:b1aeae3dd2ee719074a9372c89ad94f7c581903306d76befdaca2a559f802472", - "sha256:b2ca1837bfbe5eafa11313dbc7edada79052709a1fffa10cea691210af4aa1fa", - "sha256:b4a886a6dbe60100ba1cd24de962f8cd18139bd32808da80de1fa9f9f27bf1dc", - "sha256:b6245eafd553c4e9a0708e93be51392bd2288c773523892fbd616d33fd2fda59", - "sha256:c33d5023523b44d3481624f840c8646656a1def7630ca562f222eb3ead16c438", - "sha256:cc8140baf9fa8f9b903f2b393a6c413a220fa990264b215bf48484f3d0bf8710", - "sha256:d346f4dc2221bfb7ab652d1e37d327578434ce559baf7113b0f55768437fe6a0", - "sha256:d40fc98540fa5360e7ecf2c56ddf3c6e7dd04929543618fd7b5cc76e66390562", - "sha256:e270a406219af37581d96c810172001ec536e29e5593aa40d4c01cca3e145aa6", - "sha256:e9623afa319405da33b43c85cceb0585a6f5d3a1d7c604daf4f7e1dd55c03d1f", - "sha256:effd303fb422f8ce06543a36ca69148471144c534cc25f30e5be752bc4f46736", - "sha256:f77e048f805e00870659d6318fd89ef28ca4ee16a22b4c5e1905b735495fc422", - "sha256:f849bd3c5c2249b49c98eca5aaebb920d2bfd92b3c69e84ca9bddf133e9f83f0", - "sha256:fa5cf61058c7dbb104c2ac4e782bf1b2016a8cf2f69de6e4dd6a865d2c969bb5" - ], - "markers": "python_version >= '3.8'", - "version": "==4.50.0" - }, - "grpcio": { - "hashes": [ - "sha256:12859468e8918d3bd243d213cd6fd6ab07208195dc140763c00dfe901ce1e1b4", - "sha256:1714e7bc935780bc3de1b3fcbc7674209adf5208ff825799d579ffd6cd0bd505", - "sha256:179bee6f5ed7b5f618844f760b6acf7e910988de77a4f75b95bbfaa8106f3c1e", - "sha256:1f1e7b36bdff50103af95a80923bf1853f6823dd62f2d2a2524b66ed74103e49", - "sha256:1faa02530b6c7426404372515fe5ddf66e199c2ee613f88f025c6f3bd816450c", - "sha256:22bccdd7b23c420a27fd28540fb5dcbc97dc6be105f7698cb0e7d7a420d0e362", - "sha256:23e2e04b83f347d0aadde0c9b616f4726c3d76db04b438fd3904b289a725267f", - "sha256:3227c667dccbe38f2c4d943238b887bac588d97c104815aecc62d2fd976e014b", - "sha256:359f821d4578f80f41909b9ee9b76fb249a21035a061a327f91c953493782c31", - "sha256:3952b581eb121324853ce2b191dae08badb75cd493cb4e0243368aa9e61cfd41", - "sha256:407b26b7f7bbd4f4751dbc9767a1f0716f9fe72d3d7e96bb3ccfc4aace07c8de", - "sha256:4187201a53f8561c015bc745b81a1b2d278967b8de35f3399b84b0695e281d5f", - "sha256:482ae2ae78679ba9ed5752099b32e5fe580443b4f798e1b71df412abf43375db", - "sha256:48611e4fa010e823ba2de8fd3f77c1322dd60cb0d180dc6630a7e157b205f7ea", - "sha256:48f7135c3de2f298b833be8b4ae20cafe37091634e91f61f5a7eb3d61ec6f660", - "sha256:4b49fd8fe9f9ac23b78437da94c54aa7e9996fbb220bac024a67469ce5d0825f", - "sha256:58f6c693d446964e3292425e1d16e21a97a48ba9172f2d0df9d7b640acb99243", - "sha256:5bd90b8c395f39bc82a5fb32a0173e220e3f401ff697840f4003e15b96d1befc", - "sha256:60dcd824df166ba266ee0cfaf35a31406cd16ef602b49f5d4dfb21f014b0dedd", - "sha256:6696ffe440333a19d8d128e88d440f91fb92c75a80ce4b44d55800e656a3ef1d", - "sha256:6c455e008fa86d9e9a9d85bb76da4277c0d7d9668a3bfa70dbe86e9f3c759947", - "sha256:71f11fd63365ade276c9d4a7b7df5c136f9030e3457107e1791b3737a9b9ed6a", - "sha256:73db2dc1b201d20ab7083e7041946910bb991e7e9761a0394bbc3c2632326483", - "sha256:77c339403db5a20ef4fed02e4d1a9a3d9866bf9c0afc77a42234677313ea22f3", - "sha256:833379943d1728a005e44103f17ecd73d058d37d95783eb8f0b28ddc1f54d7b2", - "sha256:83a17b303425104d6329c10eb34bba186ffa67161e63fa6cdae7776ff76df73f", - "sha256:83e7ccb85a74beaeae2634f10eb858a0ed1a63081172649ff4261f929bacfd22", - "sha256:844d1f3fb11bd1ed362d3fdc495d0770cfab75761836193af166fee113421d66", - "sha256:882020c87999d54667a284c7ddf065b359bd00251fcd70279ac486776dbf84ec", - "sha256:8999bf1b57172dbc7c3e4bb3c732658e918f5c333b2942243f10d0d653953ba9", - "sha256:9084086190cc6d628f282e5615f987288b95457292e969b9205e45b442276407", - "sha256:960edebedc6b9ada1ef58e1c71156f28689978188cd8cff3b646b57288a927d9", - "sha256:973c49086cabab773525f6077f95e5a993bfc03ba8fc32e32f2c279497780585", - "sha256:978121758711916d34fe57c1f75b79cdfc73952f1481bb9583399331682d36f7", - "sha256:9bd5c8a1af40ec305d001c60236308a67e25419003e9bb3ebfab5695a8d0b369", - "sha256:a10383035e864f386fe096fed5c47d27a2bf7173c56a6e26cffaaa5a361addb1", - "sha256:a485f0c2010c696be269184bdb5ae72781344cb4e60db976c59d84dd6354fac9", - "sha256:a7f615270fe534548112a74e790cd9d4f5509d744dd718cd442bf016626c22e4", - "sha256:b134d5d71b4e0837fff574c00e49176051a1c532d26c052a1e43231f252d813b", - "sha256:b2a0e71b0a2158aa4bce48be9f8f9eb45cbd17c78c7443616d00abbe2a509f6d", - "sha256:b50b09b4dc01767163d67e1532f948264167cd27f49e9377e3556c3cba1268e1", - "sha256:b5a4ea906db7dec694098435d84bf2854fe158eb3cd51e1107e571246d4d1d70", - "sha256:b7209117bbeebdfa5d898205cc55153a51285757902dd73c47de498ad4d11332", - "sha256:bba97b8e8883a8038606480d6b6772289f4c907f6ba780fa1f7b7da7dfd76f06", - "sha256:be0477cb31da67846a33b1a75c611f88bfbcd427fe17701b6317aefceee1b96f", - "sha256:c7fcc6a32e7b7b58f5a7d27530669337a5d587d4066060bcb9dee7a8c833dfb7", - "sha256:c8842ccbd8c0e253c1f189088228f9b433f7a93b7196b9e5b6f87dba393f5d5d", - "sha256:d1f6c96573dc09d50dbcbd91dbf71d5cf97640c9427c32584010fbbd4c0e0037", - "sha256:d9e52558b8b8c2f4ac05ac86344a7417ccdd2b460a59616de49eb6933b07a0bd", - "sha256:e3393b0823f938253370ebef033c9fd23d27f3eae8eb9a8f6264900c7ea3fb5a", - "sha256:e6c8c8693df718c5ecbc7babb12c69a4e3677fd11de8886f05ab22d4e6b1c43b", - "sha256:f8de7c8cef9261a2d0a62edf2ccea3d741a523c6b8a6477a340a1f2e417658de", - "sha256:fa7d28eb4d50b7cbe75bb8b45ed0da9a1dc5b219a0af59449676a29c2eed9698", - "sha256:fbe80577c7880911d3ad65e5ecc997416c98f354efeba2f8d0f9112a67ed65a5" - ], - "markers": "python_version >= '3.7'", - "version": "==1.62.1" - }, - "gymnasium": { - "hashes": [ - "sha256:1a532752efcb7590478b1cc7aa04f608eb7a2fdad5570cd217b66b6a35274bb1", - "sha256:61c3384b5575985bb7f85e43213bcb40f36fcdff388cae6bc229304c71f2843e" - ], - "markers": "python_version >= '3.8'", - "version": "==0.29.1" - }, - "h11": { - "hashes": [ - "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", - "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761" - ], - "markers": "python_version >= '3.7'", - "version": "==0.14.0" - }, - "httpcore": { - "hashes": [ - "sha256:ac418c1db41bade2ad53ae2f3834a3a0f5ae76b56cf5aa497d2d033384fc7d73", - "sha256:cb2839ccfcba0d2d3c1131d3c3e26dfc327326fbe7a5dc0dbfe9f6c9151bb022" - ], - "markers": "python_version >= '3.8'", - "version": "==1.0.4" - }, - "httpx": { - "hashes": [ - "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5", - "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5" - ], - "markers": "python_version >= '3.8'", - "version": "==0.27.0" - }, - "idna": { - "hashes": [ - "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", - "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" - ], - "markers": "python_version >= '3.5'", - "version": "==3.6" - }, - "inputs": { - "hashes": [ - "sha256:13f894564e52134cf1e3862b1811da034875eb1f2b62e6021e3776e9669a96ec", - "sha256:a31d5b96a3525f1232f326be9e7ce8ccaf873c6b1fb84d9f3c9bc3d79b23eae4" - ], - "version": "==0.5" - }, - "kiwisolver": { - "hashes": [ - "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf", - "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e", - "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af", - "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f", - "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046", - "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3", - "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5", - "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71", - "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee", - "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3", - "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9", - "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b", - "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985", - "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea", - "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16", - "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89", - "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c", - "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9", - "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712", - "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342", - "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a", - "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958", - "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d", - "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a", - "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130", - "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff", - "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898", - "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b", - "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f", - "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265", - "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93", - "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929", - "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635", - "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709", - "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b", - "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb", - "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a", - "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920", - "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e", - "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544", - "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45", - "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390", - "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77", - "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355", - "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff", - "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4", - "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7", - "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20", - "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c", - "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162", - "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228", - "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437", - "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc", - "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a", - "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901", - "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4", - "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770", - "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525", - "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad", - "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a", - "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29", - "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90", - "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250", - "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d", - "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3", - "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54", - "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f", - "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1", - "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da", - "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238", - "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa", - "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523", - "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0", - "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205", - "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3", - "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4", - "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac", - "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9", - "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb", - "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced", - "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd", - "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0", - "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da", - "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18", - "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9", - "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276", - "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333", - "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b", - "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db", - "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126", - "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9", - "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09", - "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0", - "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec", - "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7", - "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff", - "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9", - "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192", - "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8", - "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d", - "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6", - "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797", - "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892", - "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f" - ], - "markers": "python_version >= '3.7'", - "version": "==1.4.5" - }, - "loguru": { - "hashes": [ - "sha256:003d71e3d3ed35f0f8984898359d65b79e5b21943f78af86aa5491210429b8eb", - "sha256:e671a53522515f34fd406340ee968cb9ecafbc4b36c679da03c18fd8d0bd51ac" - ], - "index": "pypi", - "markers": "python_version >= '3.5'", - "version": "==0.7.2" - }, - "matplotlib": { - "hashes": [ - "sha256:04b36ad07eac9740fc76c2aa16edf94e50b297d6eb4c081e3add863de4bb19a7", - "sha256:09074f8057917d17ab52c242fdf4916f30e99959c1908958b1fc6032e2d0f6d4", - "sha256:1c5c8290074ba31a41db1dc332dc2b62def469ff33766cbe325d32a3ee291aea", - "sha256:242489efdb75b690c9c2e70bb5c6550727058c8a614e4c7716f363c27e10bba1", - "sha256:40321634e3a05ed02abf7c7b47a50be50b53ef3eaa3a573847431a545585b407", - "sha256:4c6e00a65d017d26009bac6808f637b75ceade3e1ff91a138576f6b3065eeeba", - "sha256:5184e07c7e1d6d1481862ee361905b7059f7fe065fc837f7c3dc11eeb3f2f900", - "sha256:5745f6d0fb5acfabbb2790318db03809a253096e98c91b9a31969df28ee604aa", - "sha256:5e431a09e6fab4012b01fc155db0ce6dccacdbabe8198197f523a4ef4805eb26", - "sha256:5f557156f7116be3340cdeef7f128fa99b0d5d287d5f41a16e169819dcf22357", - "sha256:6728dde0a3997396b053602dbd907a9bd64ec7d5cf99e728b404083698d3ca01", - "sha256:7b416239e9ae38be54b028abbf9048aff5054a9aba5416bef0bd17f9162ce161", - "sha256:7c42dae72a62f14982f1474f7e5c9959fc4bc70c9de11cc5244c6e766200ba65", - "sha256:813925d08fb86aba139f2d31864928d67511f64e5945ca909ad5bc09a96189bb", - "sha256:83c0653c64b73926730bd9ea14aa0f50f202ba187c307a881673bad4985967b7", - "sha256:83e0f72e2c116ca7e571c57aa29b0fe697d4c6425c4e87c6e994159e0c008635", - "sha256:b3c5f96f57b0369c288bf6f9b5274ba45787f7e0589a34d24bdbaf6d3344632f", - "sha256:b97653d869a71721b639714b42d87cda4cfee0ee74b47c569e4874c7590c55c5", - "sha256:bf5932eee0d428192c40b7eac1399d608f5d995f975cdb9d1e6b48539a5ad8d0", - "sha256:c4af3f7317f8a1009bbb2d0bf23dfaba859eb7dd4ccbd604eba146dccaaaf0a4", - "sha256:cd3a0c2be76f4e7be03d34a14d49ded6acf22ef61f88da600a18a5cd8b3c5f3c", - "sha256:cf60138ccc8004f117ab2a2bad513cc4d122e55864b4fe7adf4db20ca68a078f", - "sha256:d7e7e0993d0758933b1a241a432b42c2db22dfa37d4108342ab4afb9557cbe3e", - "sha256:e7b49ab49a3bea17802df6872f8d44f664ba8f9be0632a60c99b20b6db2165b7", - "sha256:e9764df0e8778f06414b9d281a75235c1e85071f64bb5d71564b97c1306a2afc", - "sha256:ef6c1025a570354297d6c15f7d0f296d95f88bd3850066b7f1e7b4f2f4c13a39", - "sha256:f386cf162b059809ecfac3bcc491a9ea17da69fa35c8ded8ad154cd4b933d5ec", - "sha256:fa93695d5c08544f4a0dfd0965f378e7afc410d8672816aff1e81be1f45dbf2e" - ], - "index": "pypi", - "markers": "python_version >= '3.9'", - "version": "==3.8.3" - }, - "numpy": { - "hashes": [ - "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b", - "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818", - "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20", - "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0", - "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", - "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a", - "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea", - "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c", - "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71", - "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110", - "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be", - "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a", - "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a", - "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5", - "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed", - "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd", - "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c", - "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e", - "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0", - "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c", - "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a", - "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b", - "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", - "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6", - "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2", - "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a", - "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30", - "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218", - "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5", - "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07", - "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2", - "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4", - "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764", - "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef", - "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3", - "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f" - ], - "markers": "python_version >= '3.9'", - "version": "==1.26.4" - }, - "openai": { - "hashes": [ - "sha256:a48b3c4d635b603952189ac5a0c0c9b06c025b80eb2900396939f02bb2104ac3", - "sha256:e5642f7c02cf21994b08477d7bb2c1e46d8f335d72c26f0396c5f89b15b5b153" - ], - "index": "pypi", - "markers": "python_full_version >= '3.7.1'", - "version": "==1.14.2" - }, - "opencv-python": { - "hashes": [ - "sha256:1a9f0e6267de3a1a1db0c54213d022c7c8b5b9ca4b580e80bdc58516c922c9e1", - "sha256:3f16f08e02b2a2da44259c7cc712e779eff1dd8b55fdb0323e8cab09548086c0", - "sha256:71dfb9555ccccdd77305fc3dcca5897fbf0cf28b297c51ee55e079c065d812a3", - "sha256:7b34a52e9da36dda8c151c6394aed602e4b17fa041df0b9f5b93ae10b0fcca2a", - "sha256:7e5f7aa4486651a6ebfa8ed4b594b65bd2d2f41beeb4241a3e4b1b85acbbbadb", - "sha256:dcf000c36dd1651118a2462257e3a9e76db789a78432e1f303c7bac54f63ef6c", - "sha256:e4088cab82b66a3b37ffc452976b14a3c599269c247895ae9ceb4066d8188a57" - ], - "markers": "python_version >= '3.6'", - "version": "==4.9.0.80" - }, - "packaging": { - "hashes": [ - "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", - "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9" - ], - "markers": "python_version >= '3.7'", - "version": "==24.0" - }, - "pandas": { - "hashes": [ - "sha256:04f6ec3baec203c13e3f8b139fb0f9f86cd8c0b94603ae3ae8ce9a422e9f5bee", - "sha256:06cf591dbaefb6da9de8472535b185cba556d0ce2e6ed28e21d919704fef1a9e", - "sha256:0ab90f87093c13f3e8fa45b48ba9f39181046e8f3317d3aadb2fffbb1b978572", - "sha256:0f573ab277252ed9aaf38240f3b54cfc90fff8e5cab70411ee1d03f5d51f3944", - "sha256:101d0eb9c5361aa0146f500773395a03839a5e6ecde4d4b6ced88b7e5a1a6403", - "sha256:11940e9e3056576ac3244baef2fedade891977bcc1cb7e5cc8f8cc7d603edc89", - "sha256:1ba21b1d5c0e43416218db63037dbe1a01fc101dc6e6024bcad08123e48004ab", - "sha256:4aa1d8707812a658debf03824016bf5ea0d516afdea29b7dc14cf687bc4d4ec6", - "sha256:4acf681325ee1c7f950d058b05a820441075b0dd9a2adf5c4835b9bc056bf4fb", - "sha256:53680dc9b2519cbf609c62db3ed7c0b499077c7fefda564e330286e619ff0dd9", - "sha256:739cc70eaf17d57608639e74d63387b0d8594ce02f69e7a0b046f117974b3019", - "sha256:76f27a809cda87e07f192f001d11adc2b930e93a2b0c4a236fde5429527423be", - "sha256:7d2ed41c319c9fb4fd454fe25372028dfa417aacb9790f68171b2e3f06eae8cd", - "sha256:88ecb5c01bb9ca927ebc4098136038519aa5d66b44671861ffab754cae75102c", - "sha256:8df8612be9cd1c7797c93e1c5df861b2ddda0b48b08f2c3eaa0702cf88fb5f88", - "sha256:94e714a1cca63e4f5939cdce5f29ba8d415d85166be3441165edd427dc9f6bc0", - "sha256:9bd8a40f47080825af4317d0340c656744f2bfdb6819f818e6ba3cd24c0e1397", - "sha256:9d1265545f579edf3f8f0cb6f89f234f5e44ba725a34d86535b1a1d38decbccc", - "sha256:a935a90a76c44fe170d01e90a3594beef9e9a6220021acfb26053d01426f7dc2", - "sha256:af5d3c00557d657c8773ef9ee702c61dd13b9d7426794c9dfeb1dc4a0bf0ebc7", - "sha256:c2ce852e1cf2509a69e98358e8458775f89599566ac3775e70419b98615f4b06", - "sha256:c38ce92cb22a4bea4e3929429aa1067a454dcc9c335799af93ba9be21b6beb51", - "sha256:c391f594aae2fd9f679d419e9a4d5ba4bce5bb13f6a989195656e7dc4b95c8f0", - "sha256:c70e00c2d894cb230e5c15e4b1e1e6b2b478e09cf27cc593a11ef955b9ecc81a", - "sha256:df0c37ebd19e11d089ceba66eba59a168242fc6b7155cba4ffffa6eccdfb8f16", - "sha256:e97fbb5387c69209f134893abc788a6486dbf2f9e511070ca05eed4b930b1b02", - "sha256:f02a3a6c83df4026e55b63c1f06476c9aa3ed6af3d89b4f04ea656ccdaaaa359", - "sha256:f821213d48f4ab353d20ebc24e4faf94ba40d76680642fb7ce2ea31a3ad94f9b", - "sha256:f9d3558d263073ed95e46f4650becff0c5e1ffe0fc3a015de3c79283dfbdb3df" - ], - "index": "pypi", - "markers": "python_version >= '3.9'", - "version": "==2.2.1" - }, - "pillow": { - "hashes": [ - "sha256:0304004f8067386b477d20a518b50f3fa658a28d44e4116970abfcd94fac34a8", - "sha256:0689b5a8c5288bc0504d9fcee48f61a6a586b9b98514d7d29b840143d6734f39", - "sha256:0eae2073305f451d8ecacb5474997c08569fb4eb4ac231ffa4ad7d342fdc25ac", - "sha256:0fb3e7fc88a14eacd303e90481ad983fd5b69c761e9e6ef94c983f91025da869", - "sha256:11fa2e5984b949b0dd6d7a94d967743d87c577ff0b83392f17cb3990d0d2fd6e", - "sha256:127cee571038f252a552760076407f9cff79761c3d436a12af6000cd182a9d04", - "sha256:154e939c5f0053a383de4fd3d3da48d9427a7e985f58af8e94d0b3c9fcfcf4f9", - "sha256:15587643b9e5eb26c48e49a7b33659790d28f190fc514a322d55da2fb5c2950e", - "sha256:170aeb00224ab3dc54230c797f8404507240dd868cf52066f66a41b33169bdbe", - "sha256:1b5e1b74d1bd1b78bc3477528919414874748dd363e6272efd5abf7654e68bef", - "sha256:1da3b2703afd040cf65ec97efea81cfba59cdbed9c11d8efc5ab09df9509fc56", - "sha256:1e23412b5c41e58cec602f1135c57dfcf15482013ce6e5f093a86db69646a5aa", - "sha256:2247178effb34a77c11c0e8ac355c7a741ceca0a732b27bf11e747bbc950722f", - "sha256:257d8788df5ca62c980314053197f4d46eefedf4e6175bc9412f14412ec4ea2f", - "sha256:3031709084b6e7852d00479fd1d310b07d0ba82765f973b543c8af5061cf990e", - "sha256:322209c642aabdd6207517e9739c704dc9f9db943015535783239022002f054a", - "sha256:322bdf3c9b556e9ffb18f93462e5f749d3444ce081290352c6070d014c93feb2", - "sha256:33870dc4653c5017bf4c8873e5488d8f8d5f8935e2f1fb9a2208c47cdd66efd2", - "sha256:35bb52c37f256f662abdfa49d2dfa6ce5d93281d323a9af377a120e89a9eafb5", - "sha256:3c31822339516fb3c82d03f30e22b1d038da87ef27b6a78c9549888f8ceda39a", - "sha256:3eedd52442c0a5ff4f887fab0c1c0bb164d8635b32c894bc1faf4c618dd89df2", - "sha256:3ff074fc97dd4e80543a3e91f69d58889baf2002b6be64347ea8cf5533188213", - "sha256:47c0995fc4e7f79b5cfcab1fc437ff2890b770440f7696a3ba065ee0fd496563", - "sha256:49d9ba1ed0ef3e061088cd1e7538a0759aab559e2e0a80a36f9fd9d8c0c21591", - "sha256:51f1a1bffc50e2e9492e87d8e09a17c5eea8409cda8d3f277eb6edc82813c17c", - "sha256:52a50aa3fb3acb9cf7213573ef55d31d6eca37f5709c69e6858fe3bc04a5c2a2", - "sha256:54f1852cd531aa981bc0965b7d609f5f6cc8ce8c41b1139f6ed6b3c54ab82bfb", - "sha256:609448742444d9290fd687940ac0b57fb35e6fd92bdb65386e08e99af60bf757", - "sha256:69ffdd6120a4737710a9eee73e1d2e37db89b620f702754b8f6e62594471dee0", - "sha256:6fad5ff2f13d69b7e74ce5b4ecd12cc0ec530fcee76356cac6742785ff71c452", - "sha256:7049e301399273a0136ff39b84c3678e314f2158f50f517bc50285fb5ec847ad", - "sha256:70c61d4c475835a19b3a5aa42492409878bbca7438554a1f89d20d58a7c75c01", - "sha256:716d30ed977be8b37d3ef185fecb9e5a1d62d110dfbdcd1e2a122ab46fddb03f", - "sha256:753cd8f2086b2b80180d9b3010dd4ed147efc167c90d3bf593fe2af21265e5a5", - "sha256:773efe0603db30c281521a7c0214cad7836c03b8ccff897beae9b47c0b657d61", - "sha256:7823bdd049099efa16e4246bdf15e5a13dbb18a51b68fa06d6c1d4d8b99a796e", - "sha256:7c8f97e8e7a9009bcacbe3766a36175056c12f9a44e6e6f2d5caad06dcfbf03b", - "sha256:823ef7a27cf86df6597fa0671066c1b596f69eba53efa3d1e1cb8b30f3533068", - "sha256:8373c6c251f7ef8bda6675dd6d2b3a0fcc31edf1201266b5cf608b62a37407f9", - "sha256:83b2021f2ade7d1ed556bc50a399127d7fb245e725aa0113ebd05cfe88aaf588", - "sha256:870ea1ada0899fd0b79643990809323b389d4d1d46c192f97342eeb6ee0b8483", - "sha256:8d12251f02d69d8310b046e82572ed486685c38f02176bd08baf216746eb947f", - "sha256:9c23f307202661071d94b5e384e1e1dc7dfb972a28a2310e4ee16103e66ddb67", - "sha256:9d189550615b4948f45252d7f005e53c2040cea1af5b60d6f79491a6e147eef7", - "sha256:a086c2af425c5f62a65e12fbf385f7c9fcb8f107d0849dba5839461a129cf311", - "sha256:a2b56ba36e05f973d450582fb015594aaa78834fefe8dfb8fcd79b93e64ba4c6", - "sha256:aebb6044806f2e16ecc07b2a2637ee1ef67a11840a66752751714a0d924adf72", - "sha256:b1b3020d90c2d8e1dae29cf3ce54f8094f7938460fb5ce8bc5c01450b01fbaf6", - "sha256:b4b6b1e20608493548b1f32bce8cca185bf0480983890403d3b8753e44077129", - "sha256:b6f491cdf80ae540738859d9766783e3b3c8e5bd37f5dfa0b76abdecc5081f13", - "sha256:b792a349405fbc0163190fde0dc7b3fef3c9268292586cf5645598b48e63dc67", - "sha256:b7c2286c23cd350b80d2fc9d424fc797575fb16f854b831d16fd47ceec078f2c", - "sha256:babf5acfede515f176833ed6028754cbcd0d206f7f614ea3447d67c33be12516", - "sha256:c365fd1703040de1ec284b176d6af5abe21b427cb3a5ff68e0759e1e313a5e7e", - "sha256:c4225f5220f46b2fde568c74fca27ae9771536c2e29d7c04f4fb62c83275ac4e", - "sha256:c570f24be1e468e3f0ce7ef56a89a60f0e05b30a3669a459e419c6eac2c35364", - "sha256:c6dafac9e0f2b3c78df97e79af707cdc5ef8e88208d686a4847bab8266870023", - "sha256:c8de2789052ed501dd829e9cae8d3dcce7acb4777ea4a479c14521c942d395b1", - "sha256:cb28c753fd5eb3dd859b4ee95de66cc62af91bcff5db5f2571d32a520baf1f04", - "sha256:cb4c38abeef13c61d6916f264d4845fab99d7b711be96c326b84df9e3e0ff62d", - "sha256:d1b35bcd6c5543b9cb547dee3150c93008f8dd0f1fef78fc0cd2b141c5baf58a", - "sha256:d8e6aeb9201e655354b3ad049cb77d19813ad4ece0df1249d3c793de3774f8c7", - "sha256:d8ecd059fdaf60c1963c58ceb8997b32e9dc1b911f5da5307aab614f1ce5c2fb", - "sha256:da2b52b37dad6d9ec64e653637a096905b258d2fc2b984c41ae7d08b938a67e4", - "sha256:e87f0b2c78157e12d7686b27d63c070fd65d994e8ddae6f328e0dcf4a0cd007e", - "sha256:edca80cbfb2b68d7b56930b84a0e45ae1694aeba0541f798e908a49d66b837f1", - "sha256:f379abd2f1e3dddb2b61bc67977a6b5a0a3f7485538bcc6f39ec76163891ee48", - "sha256:fe4c15f6c9285dc54ce6553a3ce908ed37c8f3825b5a51a15c91442bb955b868" - ], - "markers": "python_version >= '3.8'", - "version": "==10.2.0" - }, - "pip": { - "hashes": [ - "sha256:ba0d021a166865d2265246961bec0152ff124de910c5cc39f1156ce3fa7c69dc", - "sha256:ea9bd1a847e8c5774a5777bb398c19e80bcd4e2aa16a4b301b718fe6f593aba2" - ], - "markers": "python_version >= '3.7'", - "version": "==24.0" - }, - "protobuf": { - "hashes": [ - "sha256:03038ac1cfbc41aa21f6afcbcd357281d7521b4157926f30ebecc8d4ea59dcb7", - "sha256:28545383d61f55b57cf4df63eebd9827754fd2dc25f80c5253f9184235db242c", - "sha256:2e3427429c9cffebf259491be0af70189607f365c2f41c7c3764af6f337105f2", - "sha256:398a9e0c3eaceb34ec1aee71894ca3299605fa8e761544934378bbc6c97de23b", - "sha256:44246bab5dd4b7fbd3c0c80b6f16686808fab0e4aca819ade6e8d294a29c7050", - "sha256:447d43819997825d4e71bf5769d869b968ce96848b6479397e29fc24c4a5dfe9", - "sha256:67a3598f0a2dcbc58d02dd1928544e7d88f764b47d4a286202913f0b2801c2e7", - "sha256:74480f79a023f90dc6e18febbf7b8bac7508420f2006fabd512013c0c238f454", - "sha256:819559cafa1a373b7096a482b504ae8a857c89593cf3a25af743ac9ecbd23480", - "sha256:899dc660cd599d7352d6f10d83c95df430a38b410c1b66b407a6b29265d66469", - "sha256:8c0c984a1b8fef4086329ff8dd19ac77576b384079247c770f29cc8ce3afa06c", - "sha256:9aae4406ea63d825636cc11ffb34ad3379335803216ee3a856787bcf5ccc751e", - "sha256:a7ca6d488aa8ff7f329d4c545b2dbad8ac31464f1d8b1c87ad1346717731e4db", - "sha256:b6cc7ba72a8850621bfec987cb72623e703b7fe2b9127a161ce61e61558ad905", - "sha256:bf01b5720be110540be4286e791db73f84a2b721072a3711efff6c324cdf074b", - "sha256:c02ce36ec760252242a33967d51c289fd0e1c0e6e5cc9397e2279177716add86", - "sha256:d9e4432ff660d67d775c66ac42a67cf2453c27cb4d738fc22cb53b5d84c135d4", - "sha256:daa564862dd0d39c00f8086f88700fdbe8bc717e993a21e90711acfed02f2402", - "sha256:de78575669dddf6099a8a0f46a27e82a1783c557ccc38ee620ed8cc96d3be7d7", - "sha256:e64857f395505ebf3d2569935506ae0dfc4a15cb80dc25261176c784662cdcc4", - "sha256:f4bd856d702e5b0d96a00ec6b307b0f51c1982c2bf9c0052cf9019e9a544ba99", - "sha256:f4c42102bc82a51108e449cbb32b19b180022941c727bac0cfd50170341f16ee" - ], - "markers": "python_version >= '3.7'", - "version": "==3.20.3" - }, - "pydantic": { - "hashes": [ - "sha256:b1704e0847db01817624a6b86766967f552dd9dbf3afba4004409f908dcc84e6", - "sha256:cc46fce86607580867bdc3361ad462bab9c222ef042d3da86f2fb333e1d916c5" - ], - "markers": "python_version >= '3.8'", - "version": "==2.6.4" - }, - "pydantic-core": { - "hashes": [ - "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a", - "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed", - "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979", - "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff", - "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5", - "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45", - "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340", - "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad", - "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23", - "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6", - "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7", - "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241", - "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda", - "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187", - "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba", - "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c", - "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2", - "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c", - "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132", - "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf", - "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972", - "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db", - "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade", - "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4", - "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8", - "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f", - "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9", - "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48", - "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec", - "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d", - "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9", - "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb", - "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4", - "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89", - "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c", - "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9", - "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da", - "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac", - "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b", - "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf", - "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e", - "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137", - "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1", - "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b", - "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8", - "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e", - "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053", - "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01", - "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe", - "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd", - "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805", - "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183", - "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8", - "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99", - "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820", - "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074", - "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256", - "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8", - "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975", - "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad", - "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e", - "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca", - "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df", - "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b", - "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a", - "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a", - "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721", - "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a", - "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f", - "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2", - "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97", - "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6", - "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed", - "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc", - "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1", - "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe", - "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120", - "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f", - "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a" - ], - "markers": "python_version >= '3.8'", - "version": "==2.16.3" - }, - "pyobjc-core": { - "hashes": [ - "sha256:0153206e15d0e0d7abd53ee8a7fbaf5606602a032e177a028fc8589516a8771c", - "sha256:a70546246177c23acb323c9324330e37638f1a0a3d13664abcba3bb75e43012c", - "sha256:a9b5a215080d13bd7526031d21d5eb27a410780878d863f486053a0eba7ca9a5", - "sha256:b8eab50ce7f17017a0f1d68c3b7e88bb1bb033415fdff62b8e0a9ee4ab72f242", - "sha256:c9a7163aff9c47d654f835f80361c1b112886ec754800d34e75d1e02ff52c3d7", - "sha256:eb1ab700a44bcc4ceb125091dfaae0b998b767b49990df5fdc83eb58158d8e3f", - "sha256:f2115971463073426ab926416e17e5c16de5b90d1a1f2a2d8724637eb1c21308" - ], - "markers": "python_version >= '3.8'", - "version": "==10.2" - }, - "pyobjc-framework-cocoa": { - "hashes": [ - "sha256:0def036a7b24e3ae37a244c77bec96b7c9c8384bf6bb4d33369f0a0c8807a70d", - "sha256:18886d5013cd7dc7ecd6e0df5134c767569b5247fc10a5e293c72ee3937b217b", - "sha256:1ecf01400ee698d2e0ff4c907bcf9608d9d710e97203fbb97b37d208507a9362", - "sha256:5f47ecc393bc1019c4b47e8653207188df784ac006ad54d8c2eb528906ff7013", - "sha256:6383141379636b13855dca1b39c032752862b829f93a49d7ddb35046abfdc035", - "sha256:6a6042b7703bdc33b7491959c715c1e810a3f8c7a560c94b36e00ef321480797", - "sha256:f9227b4f271fda2250f5a88cbc686ff30ae02c0f923bb7854bb47972397496b2" - ], - "markers": "sys_platform == 'darwin'", - "version": "==10.2" - }, - "pyparsing": { - "hashes": [ - "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad", - "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742" - ], - "markers": "python_full_version >= '3.6.8'", - "version": "==3.1.2" - }, - "python-dateutil": { - "hashes": [ - "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", - "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.9.0.post0" - }, - "python-dotenv": { - "hashes": [ - "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", - "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==1.0.1" - }, - "pytz": { - "hashes": [ - "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812", - "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319" - ], - "version": "==2024.1" - }, - "screeninfo": { - "hashes": [ - "sha256:9983076bcc7e34402a1a9e4d7dabf3729411fd2abb3f3b4be7eba73519cd2ed1", - "sha256:e97d6b173856edcfa3bd282f81deb528188aff14b11ec3e195584e7641be733c" - ], - "markers": "python_full_version >= '3.6.2' and python_full_version < '4.0.0'", - "version": "==0.8.1" - }, - "setuptools": { - "hashes": [ - "sha256:0ff4183f8f42cd8fa3acea16c45205521a4ef28f73c6391d8a25e92893134f2e", - "sha256:c21c49fb1042386df081cb5d86759792ab89efca84cf114889191cd09aacc80c" - ], - "markers": "python_version >= '3.8'", - "version": "==69.2.0" - }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.16.0" - }, - "sniffio": { - "hashes": [ - "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", - "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" - ], - "markers": "python_version >= '3.7'", - "version": "==1.3.1" - }, - "tk": { - "hashes": [ - "sha256:60bc8923d5d35f67f5c6bd93d4f0c49d2048114ec077768f959aef36d4ed97f8", - "sha256:703a69ff0d5ba2bd2f7440582ad10160e4a6561595d33457dc6caa79b9bf4930" - ], - "version": "==0.1.0" - }, - "tqdm": { - "hashes": [ - "sha256:1ee4f8a893eb9bef51c6e35730cebf234d5d0b6bd112b0271e10ed7c24a02bd9", - "sha256:6cd52cdf0fef0e0f543299cfc96fec90d7b8a7e88745f411ec33eb44d5ed3531" - ], - "markers": "python_version >= '3.7'", - "version": "==4.66.2" - }, - "typing-extensions": { - "hashes": [ - "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", - "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb" - ], - "markers": "python_version >= '3.8'", - "version": "==4.10.0" - }, - "tzdata": { - "hashes": [ - "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd", - "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252" - ], - "markers": "python_version >= '2'", - "version": "==2024.1" - } - }, - "develop": { - "appnope": { - "hashes": [ - "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", - "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c" - ], - "markers": "platform_system == 'Darwin'", - "version": "==0.1.4" - }, - "asttokens": { - "hashes": [ - "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24", - "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0" - ], - "version": "==2.4.1" - }, - "comm": { - "hashes": [ - "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e", - "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3" - ], - "markers": "python_version >= '3.8'", - "version": "==0.2.2" - }, - "debugpy": { - "hashes": [ - "sha256:016a9fcfc2c6b57f939673c874310d8581d51a0fe0858e7fac4e240c5eb743cb", - "sha256:0de56aba8249c28a300bdb0672a9b94785074eb82eb672db66c8144fff673146", - "sha256:1a9fe0829c2b854757b4fd0a338d93bc17249a3bf69ecf765c61d4c522bb92a8", - "sha256:28acbe2241222b87e255260c76741e1fbf04fdc3b6d094fcf57b6c6f75ce1242", - "sha256:3a79c6f62adef994b2dbe9fc2cc9cc3864a23575b6e387339ab739873bea53d0", - "sha256:3bda0f1e943d386cc7a0e71bfa59f4137909e2ed947fb3946c506e113000f741", - "sha256:3ebb70ba1a6524d19fa7bb122f44b74170c447d5746a503e36adc244a20ac539", - "sha256:58911e8521ca0c785ac7a0539f1e77e0ce2df753f786188f382229278b4cdf23", - "sha256:6df9aa9599eb05ca179fb0b810282255202a66835c6efb1d112d21ecb830ddd3", - "sha256:7a3afa222f6fd3d9dfecd52729bc2e12c93e22a7491405a0ecbf9e1d32d45b39", - "sha256:7eb7bd2b56ea3bedb009616d9e2f64aab8fc7000d481faec3cd26c98a964bcdd", - "sha256:92116039b5500633cc8d44ecc187abe2dfa9b90f7a82bbf81d079fcdd506bae9", - "sha256:a2e658a9630f27534e63922ebf655a6ab60c370f4d2fc5c02a5b19baf4410ace", - "sha256:bfb20cb57486c8e4793d41996652e5a6a885b4d9175dd369045dad59eaacea42", - "sha256:caad2846e21188797a1f17fc09c31b84c7c3c23baf2516fed5b40b378515bbf0", - "sha256:d915a18f0597ef685e88bb35e5d7ab968964b7befefe1aaea1eb5b2640b586c7", - "sha256:dda73bf69ea479c8577a0448f8c707691152e6c4de7f0c4dec5a4bc11dee516e", - "sha256:e38beb7992b5afd9d5244e96ad5fa9135e94993b0c551ceebf3fe1a5d9beb234", - "sha256:edcc9f58ec0fd121a25bc950d4578df47428d72e1a0d66c07403b04eb93bcf98", - "sha256:efd3fdd3f67a7e576dd869c184c5dd71d9aaa36ded271939da352880c012e703", - "sha256:f696d6be15be87aef621917585f9bb94b1dc9e8aced570db1b8a6fc14e8f9b42", - "sha256:fd97ed11a4c7f6d042d320ce03d83b20c3fb40da892f994bc041bbc415d7a099" - ], - "markers": "python_version >= '3.8'", - "version": "==1.8.1" - }, - "decorator": { - "hashes": [ - "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330", - "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186" - ], - "markers": "python_version >= '3.5'", - "version": "==5.1.1" - }, - "executing": { - "hashes": [ - "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147", - "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc" - ], - "markers": "python_version >= '3.5'", - "version": "==2.0.1" - }, - "ipykernel": { - "hashes": [ - "sha256:5aa086a4175b0229d4eca211e181fb473ea78ffd9869af36ba7694c947302a21", - "sha256:e14c250d1f9ea3989490225cc1a542781b095a18a19447fcf2b5eaf7d0ac5bd2" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==6.29.3" - }, - "ipython": { - "hashes": [ - "sha256:2dcaad9049f9056f1fef63514f176c7d41f930daa78d05b82a176202818f2c14", - "sha256:3c86f284c8f3d8f2b6c662f885c4889a91df7cd52056fd02b7d8d6195d7f56e9" - ], - "markers": "python_version >= '3.10'", - "version": "==8.22.2" - }, - "jedi": { - "hashes": [ - "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd", - "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0" - ], - "markers": "python_version >= '3.6'", - "version": "==0.19.1" - }, - "jupyter-client": { - "hashes": [ - "sha256:3b7bd22f058434e3b9a7ea4b1500ed47de2713872288c0d511d19926f99b459f", - "sha256:e842515e2bab8e19186d89fdfea7abd15e39dd581f94e399f00e2af5a1652d3f" - ], - "markers": "python_version >= '3.8'", - "version": "==8.6.1" - }, - "jupyter-core": { - "hashes": [ - "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409", - "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9" - ], - "markers": "python_version >= '3.8'", - "version": "==5.7.2" - }, - "matplotlib-inline": { - "hashes": [ - "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311", - "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304" - ], - "markers": "python_version >= '3.5'", - "version": "==0.1.6" - }, - "nest-asyncio": { - "hashes": [ - "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", - "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c" - ], - "markers": "python_version >= '3.5'", - "version": "==1.6.0" - }, - "packaging": { - "hashes": [ - "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", - "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9" - ], - "markers": "python_version >= '3.7'", - "version": "==24.0" - }, - "parso": { - "hashes": [ - "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0", - "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75" - ], - "markers": "python_version >= '3.6'", - "version": "==0.8.3" - }, - "pexpect": { - "hashes": [ - "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", - "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f" - ], - "markers": "sys_platform != 'win32' and sys_platform != 'emscripten'", - "version": "==4.9.0" - }, - "platformdirs": { - "hashes": [ - "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068", - "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768" - ], - "markers": "python_version >= '3.8'", - "version": "==4.2.0" - }, - "prompt-toolkit": { - "hashes": [ - "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d", - "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6" - ], - "markers": "python_full_version >= '3.7.0'", - "version": "==3.0.43" - }, - "psutil": { - "hashes": [ - "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d", - "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73", - "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8", - "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2", - "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e", - "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36", - "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7", - "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c", - "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee", - "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421", - "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf", - "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81", - "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0", - "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631", - "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4", - "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==5.9.8" - }, - "ptyprocess": { - "hashes": [ - "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", - "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220" - ], - "version": "==0.7.0" - }, - "pure-eval": { - "hashes": [ - "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350", - "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3" - ], - "version": "==0.2.2" - }, - "pygments": { - "hashes": [ - "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c", - "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367" - ], - "markers": "python_version >= '3.7'", - "version": "==2.17.2" - }, - "python-dateutil": { - "hashes": [ - "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", - "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.9.0.post0" - }, - "pyzmq": { - "hashes": [ - "sha256:004ff469d21e86f0ef0369717351073e0e577428e514c47c8480770d5e24a565", - "sha256:00a06faa7165634f0cac1abb27e54d7a0b3b44eb9994530b8ec73cf52e15353b", - "sha256:00c48ae2fd81e2a50c3485de1b9d5c7c57cd85dc8ec55683eac16846e57ac979", - "sha256:01171fc48542348cd1a360a4b6c3e7d8f46cdcf53a8d40f84db6707a6768acc1", - "sha256:019744b99da30330798bb37df33549d59d380c78e516e3bab9c9b84f87a9592f", - "sha256:02bbc1a87b76e04fd780b45e7f695471ae6de747769e540da909173d50ff8e2d", - "sha256:02c9087b109070c5ab0b383079fa1b5f797f8d43e9a66c07a4b8b8bdecfd88ee", - "sha256:07cd61a20a535524906595e09344505a9bd46f1da7a07e504b315d41cd42eb07", - "sha256:0806175f2ae5ad4b835ecd87f5f85583316b69f17e97786f7443baaf54b9bb98", - "sha256:09dfe949e83087da88c4a76767df04b22304a682d6154de2c572625c62ad6886", - "sha256:0dabfb10ef897f3b7e101cacba1437bd3a5032ee667b7ead32bbcdd1a8422fe7", - "sha256:0ddd6d71d4ef17ba5a87becf7ddf01b371eaba553c603477679ae817a8d84d75", - "sha256:0f513130c4c361201da9bc69df25a086487250e16b5571ead521b31ff6b02220", - "sha256:0f97bc2f1f13cb16905a5f3e1fbdf100e712d841482b2237484360f8bc4cb3d7", - "sha256:11e70516688190e9c2db14fcf93c04192b02d457b582a1f6190b154691b4c93a", - "sha256:146b9b1f29ead41255387fb07be56dc29639262c0f7344f570eecdcd8d683314", - "sha256:16b726c1f6c2e7625706549f9dbe9b06004dfbec30dbed4bf50cbdfc73e5b32a", - "sha256:1b3cbba2f47062b85fe0ef9de5b987612140a9ba3a9c6d2543c6dec9f7c2ab27", - "sha256:1b9b1f2ad6498445a941d9a4fee096d387fee436e45cc660e72e768d3d8ee611", - "sha256:1ec23bd7b3a893ae676d0e54ad47d18064e6c5ae1fadc2f195143fb27373f7f6", - "sha256:246747b88917e4867e2367b005fc8eefbb4a54b7db363d6c92f89d69abfff4b6", - "sha256:25c2dbb97d38b5ac9fd15586e048ec5eb1e38f3d47fe7d92167b0c77bb3584e9", - "sha256:2c6441e0398c2baacfe5ba30c937d274cfc2dc5b55e82e3749e333aabffde561", - "sha256:2c9a79f1d2495b167119d02be7448bfba57fad2a4207c4f68abc0bab4b92925b", - "sha256:2e2713ef44be5d52dd8b8e2023d706bf66cb22072e97fc71b168e01d25192755", - "sha256:313c3794d650d1fccaaab2df942af9f2c01d6217c846177cfcbc693c7410839e", - "sha256:3516e0b6224cf6e43e341d56da15fd33bdc37fa0c06af4f029f7d7dfceceabbc", - "sha256:359f7f74b5d3c65dae137f33eb2bcfa7ad9ebefd1cab85c935f063f1dbb245cc", - "sha256:39b1067f13aba39d794a24761e385e2eddc26295826530a8c7b6c6c341584289", - "sha256:3c00c9b7d1ca8165c610437ca0c92e7b5607b2f9076f4eb4b095c85d6e680a1d", - "sha256:3c53687dde4d9d473c587ae80cc328e5b102b517447456184b485587ebd18b62", - "sha256:3e124e6b1dd3dfbeb695435dff0e383256655bb18082e094a8dd1f6293114642", - "sha256:4345c9a27f4310afbb9c01750e9461ff33d6fb74cd2456b107525bbeebcb5be3", - "sha256:45999e7f7ed5c390f2e87ece7f6c56bf979fb213550229e711e45ecc7d42ccb8", - "sha256:49151b0efece79f6a79d41a461d78535356136ee70084a1c22532fc6383f4ad0", - "sha256:4cb8fc1f8d69b411b8ec0b5f1ffbcaf14c1db95b6bccea21d83610987435f1a4", - "sha256:4e5837af3e5aaa99a091302df5ee001149baff06ad22b722d34e30df5f0d9097", - "sha256:4e6f689880d5ad87918430957297c975203a082d9a036cc426648fcbedae769b", - "sha256:5074adeacede5f810b7ef39607ee59d94e948b4fd954495bdb072f8c54558181", - "sha256:518efd91c3d8ac9f9b4f7dd0e2b7b8bf1a4fe82a308009016b07eaa48681af82", - "sha256:55875492f820d0eb3417b51d96fea549cde77893ae3790fd25491c5754ea2f68", - "sha256:5a68d491fc20762b630e5db2191dd07ff89834086740f70e978bb2ef2668be08", - "sha256:5dde6751e857910c1339890f3524de74007958557593b9e7e8c5f01cd919f8a7", - "sha256:5e319ed7d6b8f5fad9b76daa0a68497bc6f129858ad956331a5835785761e003", - "sha256:5edac3f57c7ddaacdb4d40f6ef2f9e299471fc38d112f4bc6d60ab9365445fb0", - "sha256:6cc0020b74b2e410287e5942e1e10886ff81ac77789eb20bec13f7ae681f0fdd", - "sha256:6dd0d50bbf9dca1d0bdea219ae6b40f713a3fb477c06ca3714f208fd69e16fd8", - "sha256:7598d2ba821caa37a0f9d54c25164a4fa351ce019d64d0b44b45540950458840", - "sha256:759cfd391a0996345ba94b6a5110fca9c557ad4166d86a6e81ea526c376a01e8", - "sha256:7ae8f354b895cbd85212da245f1a5ad8159e7840e37d78b476bb4f4c3f32a9fe", - "sha256:7b6d09a8962a91151f0976008eb7b29b433a560fde056ec7a3db9ec8f1075438", - "sha256:7c61e346ac34b74028ede1c6b4bcecf649d69b707b3ff9dc0fab453821b04d1e", - "sha256:7f51a7b4ead28d3fca8dda53216314a553b0f7a91ee8fc46a72b402a78c3e43d", - "sha256:82544e0e2d0c1811482d37eef297020a040c32e0687c1f6fc23a75b75db8062c", - "sha256:8807c87fa893527ae8a524c15fc505d9950d5e856f03dae5921b5e9aa3b8783b", - "sha256:889370d5174a741a62566c003ee8ddba4b04c3f09a97b8000092b7ca83ec9c49", - "sha256:8b14c75979ce932c53b79976a395cb2a8cd3aaf14aef75e8c2cb55a330b9b49d", - "sha256:8c5f80e578427d4695adac6fdf4370c14a2feafdc8cb35549c219b90652536ae", - "sha256:8e9f3fabc445d0ce320ea2c59a75fe3ea591fdbdeebec5db6de530dd4b09412e", - "sha256:93f1aa311e8bb912e34f004cf186407a4e90eec4f0ecc0efd26056bf7eda0226", - "sha256:94504ff66f278ab4b7e03e4cba7e7e400cb73bfa9d3d71f58d8972a8dc67e7a6", - "sha256:967668420f36878a3c9ecb5ab33c9d0ff8d054f9c0233d995a6d25b0e95e1b6b", - "sha256:9880078f683466b7f567b8624bfc16cad65077be046b6e8abb53bed4eeb82dd3", - "sha256:99a6b36f95c98839ad98f8c553d8507644c880cf1e0a57fe5e3a3f3969040882", - "sha256:9a18fff090441a40ffda8a7f4f18f03dc56ae73f148f1832e109f9bffa85df15", - "sha256:9add2e5b33d2cd765ad96d5eb734a5e795a0755f7fc49aa04f76d7ddda73fd70", - "sha256:a793ac733e3d895d96f865f1806f160696422554e46d30105807fdc9841b9f7d", - "sha256:a86c2dd76ef71a773e70551a07318b8e52379f58dafa7ae1e0a4be78efd1ff16", - "sha256:a8c1d566344aee826b74e472e16edae0a02e2a044f14f7c24e123002dcff1c05", - "sha256:ac170e9e048b40c605358667aca3d94e98f604a18c44bdb4c102e67070f3ac9b", - "sha256:b264bf2cc96b5bc43ce0e852be995e400376bd87ceb363822e2cb1964fcdc737", - "sha256:b8c8a419dfb02e91b453615c69568442e897aaf77561ee0064d789705ff37a92", - "sha256:bc69c96735ab501419c432110016329bf0dea8898ce16fab97c6d9106dc0b348", - "sha256:bef02cfcbded83473bdd86dd8d3729cd82b2e569b75844fb4ea08fee3c26ae41", - "sha256:c0b5ca88a8928147b7b1e2dfa09f3b6c256bc1135a1338536cbc9ea13d3b7add", - "sha256:cc69949484171cc961e6ecd4a8911b9ce7a0d1f738fcae717177c231bf77437b", - "sha256:ced111c2e81506abd1dc142e6cd7b68dd53747b3b7ae5edbea4578c5eeff96b7", - "sha256:d1299d7e964c13607efd148ca1f07dcbf27c3ab9e125d1d0ae1d580a1682399d", - "sha256:d1b604734bec94f05f81b360a272fc824334267426ae9905ff32dc2be433ab96", - "sha256:d9a5f194cf730f2b24d6af1f833c14c10f41023da46a7f736f48b6d35061e76e", - "sha256:db36c27baed588a5a8346b971477b718fdc66cf5b80cbfbd914b4d6d355e44e2", - "sha256:df0c7a16ebb94452d2909b9a7b3337940e9a87a824c4fc1c7c36bb4404cb0cde", - "sha256:e10a4b5a4b1192d74853cc71a5e9fd022594573926c2a3a4802020360aa719d8", - "sha256:e624c789359f1a16f83f35e2c705d07663ff2b4d4479bad35621178d8f0f6ea4", - "sha256:e690145a8c0c273c28d3b89d6fb32c45e0d9605b2293c10e650265bf5c11cfec", - "sha256:ea1608dd169da230a0ad602d5b1ebd39807ac96cae1845c3ceed39af08a5c6df", - "sha256:ea253b368eb41116011add00f8d5726762320b1bda892f744c91997b65754d73", - "sha256:eb7e49a17fb8c77d3119d41a4523e432eb0c6932187c37deb6fbb00cc3028088", - "sha256:ef12e259e7bc317c7597d4f6ef59b97b913e162d83b421dd0db3d6410f17a244", - "sha256:f8429b17cbb746c3e043cb986328da023657e79d5ed258b711c06a70c2ea7537", - "sha256:fa99973d2ed20417744fca0073390ad65ce225b546febb0580358e36aa90dba6", - "sha256:faf79a302f834d9e8304fafdc11d0d042266667ac45209afa57e5efc998e3872", - "sha256:fc31baa0c32a2ca660784d5af3b9487e13b61b3032cb01a115fce6588e1bed30" - ], - "markers": "python_version >= '3.6'", - "version": "==25.1.2" - }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.16.0" - }, - "stack-data": { - "hashes": [ - "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", - "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695" - ], - "version": "==0.6.3" - }, - "tornado": { - "hashes": [ - "sha256:02ccefc7d8211e5a7f9e8bc3f9e5b0ad6262ba2fbb683a6443ecc804e5224ce0", - "sha256:10aeaa8006333433da48dec9fe417877f8bcc21f48dda8d661ae79da357b2a63", - "sha256:27787de946a9cffd63ce5814c33f734c627a87072ec7eed71f7fc4417bb16263", - "sha256:6f8a6c77900f5ae93d8b4ae1196472d0ccc2775cc1dfdc9e7727889145c45052", - "sha256:71ddfc23a0e03ef2df1c1397d859868d158c8276a0603b96cf86892bff58149f", - "sha256:72291fa6e6bc84e626589f1c29d90a5a6d593ef5ae68052ee2ef000dfd273dee", - "sha256:88b84956273fbd73420e6d4b8d5ccbe913c65d31351b4c004ae362eba06e1f78", - "sha256:e43bc2e5370a6a8e413e1e1cd0c91bedc5bd62a74a532371042a18ef19e10579", - "sha256:f0251554cdd50b4b44362f73ad5ba7126fc5b2c2895cc62b14a1c2d7ea32f212", - "sha256:f7894c581ecdcf91666a0912f18ce5e757213999e183ebfc2c3fdbf4d5bd764e", - "sha256:fd03192e287fbd0899dd8f81c6fb9cbbc69194d2074b38f384cb6fa72b80e9c2" - ], - "markers": "python_version >= '3.8'", - "version": "==6.4" - }, - "traitlets": { - "hashes": [ - "sha256:8cdd83c040dab7d1dee822678e5f5d100b514f7b72b01615b26fc5718916fdf9", - "sha256:fcdf85684a772ddeba87db2f398ce00b40ff550d1528c03c14dbf6a02003cd80" - ], - "markers": "python_version >= '3.8'", - "version": "==5.14.2" - }, - "wcwidth": { - "hashes": [ - "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", - "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5" - ], - "version": "==0.2.13" - } - } -} diff --git a/README.md b/README.md index 2cf0010..782344f 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Which LLM will be the best fighter ? ## Our criterias 🔥 They need to be: + - **Fast**: It is a real time game, fast decisions are key - **Smart**: A good fighter thinks 50 moves ahead - **Out of the box thinking**: Outsmart your opponent with unexpected moves @@ -21,17 +22,10 @@ They need to be: ### 1 VS 1: Mistral 7B vs Mistral 7B - - https://github.com/OpenGenerativeAI/llm-colosseum/assets/19614572/79b58e26-7902-4687-af5d-0e1e845ecaf8 - - - ### 1 VS 1 X 6 : Mistral 7B vs Mistral 7B - - https://github.com/OpenGenerativeAI/llm-colosseum/assets/19614572/5d3d386b-150a-48a5-8f68-7e2954ec18db ### 1 VS 1: Mistral vs Solar @@ -48,35 +42,34 @@ https://github.com/Tokkiu/llm-colosseum/assets/13414571/4757d562-f800-40ef-8f1a- Street Fighter III assesses the ability of LLMs to understand their environment and take actions based on a specific context. As opposed to RL models, which blindly take actions based on the reward function, LLMs are fully aware of the context and act accordingly. -# Results +# Results -Our experimentations (342 fights so far) led to the following leader board. -Each LLM has an ELO score based on its results +Our experimentations (342 fights so far) led to the following leader board. +Each LLM has an ELO score based on its results ## Ranking ### ELO ranking -| Model | Rating | -| ---------------------------- | ------: | -| 🥇openai:gpt-3.5-turbo-0125 | 1776.11 | -| 🥈mistral:mistral-small-latest | 1586.16 | -| 🥉openai:gpt-4-1106-preview | 1584.78 | -| openai:gpt-4 | 1517.2 | -| openai:gpt-4-turbo-preview | 1509.28 | -| openai:gpt-4-0125-preview | 1438.92 | -| mistral:mistral-medium-latest | 1356.19 | -| mistral:mistral-large-latest | 1231.36 | +| Model | Rating | +| ------------------------------ | ------: | +| 🥇openai:gpt-3.5-turbo-0125 | 1776.11 | +| 🥈mistral:mistral-small-latest | 1586.16 | +| 🥉openai:gpt-4-1106-preview | 1584.78 | +| openai:gpt-4 | 1517.2 | +| openai:gpt-4-turbo-preview | 1509.28 | +| openai:gpt-4-0125-preview | 1438.92 | +| mistral:mistral-medium-latest | 1356.19 | +| mistral:mistral-large-latest | 1231.36 | ### Win rate matrix ![Win rate matrix](notebooks/win_rate_matrix.png) - # Explanation -Each player is controlled by an LLM. -We send to the LLM a text description of the screen. The LLM decide on the next moves its character will make. The next moves depends on its previous moves, the moves of its opponents, its power and health bars. +Each player is controlled by an LLM. +We send to the LLM a text description of the screen. The LLM decide on the next moves its character will make. The next moves depends on its previous moves, the moves of its opponents, its power and health bars. - Agent based - Multithreading @@ -84,31 +77,118 @@ We send to the LLM a text description of the screen. The LLM decide on the next ![fight3 drawio](https://github.com/OpenGenerativeAI/llm-colosseum/assets/78322686/3a212601-f54c-490d-aeb9-6f7c2401ebe6) - # Installation - Follow instructions in https://docs.diambra.ai/#installation - Download the ROM and put it in `~/.diambra/roms` -- Install with `pip3 install -r requirements` +- (Optional) Create and activate a [new python venv](https://docs.python.org/3/library/venv.html) +- Install dependencies with `make install` or `pip install -r requirements.txt` - Create a `.env` file and fill it with the content like in the `.env.example` file - Run with `make run` ## Test mode To disable the LLM calls, set `DISABLE_LLM` to `True` in the `.env` file. -It will choose the action randomly. - -## Positions - -- x is between 0 and 384 -- y is between 0 and 224 +It will choose the actions randomly. ## Logging Change the logging level in the `script.py` file. - +## Local model + +You can run the arena with local models using [Ollama](https://ollama.com/). + +1. Make sure you have ollama installed, running, and with a model downloaded (run `ollama serve mistral` in the terminal for example) + +2. Run `make local` to start the fight. + +By default, it runs mistral against mistral. To use other models, you need to change the parameter model in `ollama.py`. + +```python +from eval.game import Game, Player1, Player2 + +def main(): + game = Game( + render=True, + save_game=True, + player_1=Player1( + nickname="Baby", + model="ollama:mistral", # change this + ), + player_2=Player2( + nickname="Daddy", + model="ollama:mistral", # change this + ), + ) + game.run() + return 0 +``` + +The convention we use is `model_provider:model_name`. If you want to use another local model than Mistral, you can do `ollama:some_other_model` + +## How to make my own LLM model play? Can I improve the prompts? + +The LLM is called in `Robot.call_llm()` method of the `agent/robot.py` file. + +```python + def call_llm( + self, + temperature: float = 0.7, + max_tokens: int = 50, + top_p: float = 1.0, + ) -> str: + """ + Make an API call to the language model. + + Edit this method to change the behavior of the robot! + """ + # self.model is a slug like mistral:mistral-small-latest or ollama:mistral + provider_name, model_name = get_provider_and_model(self.model) + client = get_sync_client(provider_name) # OpenAI client + + # Generate the prompts + move_list = "- " + "\n - ".join([move for move in META_INSTRUCTIONS]) + system_prompt = f"""You are the best and most aggressive Street Fighter III 3rd strike player in the world. +Your character is {self.character}. Your goal is to beat the other opponent. You respond with a bullet point list of moves. +{self.context_prompt()} +The moves you can use are: +{move_list} +---- +Reply with a bullet point list of moves. The format should be: `- ` separated by a new line. +Example if the opponent is close: +- Move closer +- Medium Punch + +Example if the opponent is far: +- Fireball +- Move closer""" + + # Call the LLM + completion = client.chat.completions.create( + model=model_name, + messages=[ + {"role": "system", "content": system_prompt}, + {"role": "user", "content": "Your next moves are:"}, + ], + temperature=temperature, + max_tokens=max_tokens, + top_p=top_p, + ) + + # Return the string to be parsed with regex + llm_response = completion.choices[0].message.content.strip() + return llm_response +``` + +To use another model or other prompts, make a call to another client in this function, change the system prompt, or make any fancy stuff. + +### Submit your model + +Create a new class herited from `Robot` that has the changes you want to make and open a PR. + +We'll do our best to add it to the ranking! # Credits -Made with ❤️ by the OpenGenerativeAI team @oulianov @Pierre-LouisBJT @Platinn @StanGirard during Mistral Hackathon 2024 in San Francisco +Made with ❤️ by the OpenGenerativeAI team from [phospho](https://phospho.ai) (@oulianov @Pierre-LouisBJT @Platinn) and [Quivr](https://www.quivr.app) (@StanGirard) during Mistral Hackathon 2024 in San Francisco diff --git a/agent/config.py b/agent/config.py index fc5a1e8..b98f9f2 100644 --- a/agent/config.py +++ b/agent/config.py @@ -1,3 +1,7 @@ +import dotenv + +dotenv.load_dotenv() + MODELS = { "OPENAI": { # "openai:gpt-4-0125-preview", @@ -143,6 +147,7 @@ if "Punch" in move_name or "Kick" in move_name }, "Jump Closer": {"right": [4, 4, 4, 4], "left": [2, 2, 2, 2]}, + "Jump Away": {"right": [2, 2, 2, 2], "left": [4, 4, 4, 4]}, } META_INSTRUCTIONS_WITH_LOWER = { **META_INSTRUCTIONS, diff --git a/agent/observer.py b/agent/observer.py index 64ad97d..0b4cdb3 100644 --- a/agent/observer.py +++ b/agent/observer.py @@ -1,7 +1,6 @@ import numpy as np KEN_RED = [248, 0, 0] -# KEN_GREEN = [48, 88, 152] KEN_GREEN = [88, 176, 40] @@ -14,13 +13,14 @@ def detect_position_from_color( It works by finding the first pixel that matches the color. Returns a tuple of (x, y) coordinates. + - x is between 0 and 384 + - y is between 0 and 224 """ frame = observation["frame"] # the screen is a np.array of RGB colors (3 channels) # Select the frames where the characters play: between 80 vertical and 200 vertical - # dump the observation to a file - + # dump the observation to a file for debugging if save_frame: np.save("observation.npy", frame) diff --git a/agent/prompts.py b/agent/prompts.py deleted file mode 100644 index 06a08bb..0000000 --- a/agent/prompts.py +++ /dev/null @@ -1,39 +0,0 @@ -from typing import Optional -from .config import META_INSTRUCTIONS -import random -from typing import List - - -def build_system_prompt(character: str, context_prompt: str) -> str: - move_list = "- " + "\n - ".join([move for move in META_INSTRUCTIONS]) - # Generate a random float to avoid caching - random_seed = random.random() - - system_prompt = f"""You are the best and most aggressive Street Fighter III 3rd strike player in the world. -Your character is {character}. Your goal it to beat the other opponent. You respond with a bullet point list of moves. -{context_prompt} -The moves you can use are: ----- -{move_list} ----- -Reply with a bullet point list of moves. The format should be: `- ` separated by a new line. -Example if the opponent is close: -- Move closer -- Medium Punch - -Example if the opponent is far: -- Fireball -- Move closer -""" - return system_prompt - - -def build_main_prompt() -> str: - """ - TODO: Takes as argument an observation of the world and returns a prompt for the language model - wrong_answer: str, the wrong answer, to inject in the prompt to ask for a regenrated answer - """ - - prompt = "Your next moves are:" - - return prompt diff --git a/agent/robot.py b/agent/robot.py index b84621e..80a04a9 100644 --- a/agent/robot.py +++ b/agent/robot.py @@ -1,23 +1,26 @@ -import abc +import os +import random +import re +import time from collections import defaultdict +from typing import Dict, List, Literal, Optional + import numpy as np -from typing import Dict, List, Optional, Literal from gymnasium import spaces from loguru import logger - -from .observer import detect_position_from_color, KEN_RED, KEN_GREEN -from .actions import get_actions_from_llm +from phospho.lab import get_provider_and_model, get_sync_client +from rich import print from .config import ( - MOVES, INDEX_TO_MOVE, - X_SIZE, - Y_SIZE, - NB_FRAME_WAIT, - COMBOS, META_INSTRUCTIONS, META_INSTRUCTIONS_WITH_LOWER, + MOVES, + NB_FRAME_WAIT, + X_SIZE, + Y_SIZE, ) +from .observer import detect_position_from_color class Robot: @@ -122,43 +125,22 @@ def plan(self) -> None: https://www.eventhubs.com/guides/2008/may/09/ryu-street-fighter-3-third-strike-character-guide/ """ - # Detect own position - own_position = self.observations[-1]["character_position"] - ennemy_position = self.observations[-1]["ennemy_position"] - - # Note: at the beginning of the game, the position is None - # If we already have a next step, we don't need to plan if len(self.next_steps) > 0: return - # Get the context - context = self.context_prompt() - - logger.debug(f"Context: {context}") - # Call the LLM to get the next steps - next_steps_from_llm = get_actions_from_llm( - context, - self.character, - model=self.model, - temperature=0.7, - player_nb=self.player_nb, - ) - - next_button_press = [ + next_steps_from_llm = self.get_moves_from_llm() + next_buttons_to_press = [ button for combo in next_steps_from_llm for button in META_INSTRUCTIONS_WITH_LOWER[combo][ self.current_direction.lower() ] + # We add a wait time after each button press + [0] * NB_FRAME_WAIT ] - - # Add some steps where we just wait - # next_button_press.extend([0] * NB_FRAME_WAIT) - - self.next_steps.extend(next_button_press) + self.next_steps.extend(next_buttons_to_press) def observe(self, observation: dict, actions: dict, reward: float): """ @@ -205,12 +187,8 @@ def observe(self, observation: dict, actions: dict, reward: float): self.current_direction = "Right" else: self.current_direction = "Left" - # print( - # f"Character X: {character_position[0]} vs Ennemy X: {ennemy_position[0]}" - # ) - # print(f"Current direction: {self.current_direction}") - def context_prompt(self): + def context_prompt(self) -> str: """ Return a str of the context @@ -292,3 +270,98 @@ def context_prompt(self): """ return context + + def get_moves_from_llm( + self, + ) -> List[str]: + """ + Get a list of moves from the language model. + """ + + # Filter the moves that are not in the list of moves + invalid_moves = [] + valid_moves = [] + + # If we are in the test environment, we don't want to call the LLM + if os.getenv("DISABLE_LLM", "False") == "True": + # Choose a random int from the list of moves + logger.debug("DISABLE_LLM is True, returning a random move") + return [random.choice(list(MOVES.values()))] + + while len(valid_moves) == 0: + llm_response = self.call_llm() + + # The response is a bullet point list of moves. Use regex + matches = re.findall(r"- ([\w ]+)", llm_response) + moves = ["".join(match) for match in matches] + invalid_moves = [] + valid_moves = [] + for move in moves: + cleaned_move_name = move.strip().lower() + if cleaned_move_name in META_INSTRUCTIONS_WITH_LOWER.keys(): + if self.player_nb == 1: + print( + f"[red] Player {self.player_nb} move: {cleaned_move_name}" + ) + elif self.player_nb == 2: + print( + f"[green] Player {self.player_nb} move: {cleaned_move_name}" + ) + valid_moves.append(cleaned_move_name) + else: + logger.debug(f"Invalid completion: {move}") + logger.debug(f"Cleaned move name: {cleaned_move_name}") + invalid_moves.append(move) + + if len(invalid_moves) > 1: + logger.warning(f"Many invalid moves: {invalid_moves}") + + logger.debug(f"Next moves: {valid_moves}") + return valid_moves + + def call_llm( + self, + temperature: float = 0.7, + max_tokens: int = 50, + top_p: float = 1.0, + ) -> str: + """ + Make an API call to the language model. + + Edit this method to change the behavior of the robot! + """ + provider_name, model_name = get_provider_and_model(self.model) + client = get_sync_client(provider_name) + + # Generate the prompts + move_list = "- " + "\n - ".join([move for move in META_INSTRUCTIONS]) + system_prompt = f"""You are the best and most aggressive Street Fighter III 3rd strike player in the world. +Your character is {self.character}. Your goal is to beat the other opponent. You respond with a bullet point list of moves. +{self.context_prompt()} +The moves you can use are: +{move_list} +---- +Reply with a bullet point list of moves. The format should be: `- ` separated by a new line. +Example if the opponent is close: +- Move closer +- Medium Punch + +Example if the opponent is far: +- Fireball +- Move closer""" + + start_time = time.time() + completion = client.chat.completions.create( + model=model_name, + messages=[ + {"role": "system", "content": system_prompt}, + {"role": "user", "content": "Your next moves are:"}, + ], + temperature=temperature, + max_tokens=max_tokens, + top_p=top_p, + ) + logger.debug(f"LLM call to {self.model}: {system_prompt}") + logger.debug(f"LLM call to {self.model}: {time.time() - start_time}s") + llm_response = completion.choices[0].message.content.strip() + return llm_response diff --git a/demo.py b/demo.py new file mode 100644 index 0000000..065d803 --- /dev/null +++ b/demo.py @@ -0,0 +1,34 @@ +import sys + +from dotenv import load_dotenv +from eval.game import Game, Player1, Player2 +from loguru import logger + +logger.remove() +logger.add(sys.stdout, level="INFO") + +load_dotenv() + + +def main(): + # Environment Settings + + game = Game( + render=True, + save_game=True, + player_1=Player1( + nickname="Baby", + model="mistral:mistral-small-latest", + ), + player_2=Player2( + nickname="Daddy", + model="mistral:mistral-small-latest", + ), + ) + + game.run() + return 0 + + +if __name__ == "__main__": + main() diff --git a/eval/game.py b/eval/game.py index 2a8907d..04e6f00 100644 --- a/eval/game.py +++ b/eval/game.py @@ -1,24 +1,22 @@ -from typing import List, Optional, Union +import datetime +import os +import random +import traceback +from threading import Thread +from typing import List, Optional + +from agent import KEN_GREEN, KEN_RED, Robot +from agent.config import MODELS from diambra.arena import ( - SpaceTypes, EnvironmentSettingsMultiAgent, - make, RecordingSettings, + SpaceTypes, + make, ) -import os -import datetime - -from agent import Robot, KEN_RED, KEN_GREEN -from threading import Thread from rich import print -import time -import random - -from agent.config import MODELS - -def generate_model(openai: bool = False, mistral: bool = True, solar: bool = False): +def generate_random_model(openai: bool = False, mistral: bool = True): models_available = [] for model, models in MODELS.items(): @@ -26,40 +24,42 @@ def generate_model(openai: bool = False, mistral: bool = True, solar: bool = Fal models_available.extend(models) if mistral and model == "MISTRAL": models_available.extend(models) - if solar and model == "Solar": - models_available.extend(models) - print('models:', models_available) + random.seed() # Generate a pair of random two models random_model = random.choice(models_available) return random_model + class Player: nickname: str model: str robot: Optional[Robot] = None temperature: Optional[float] = 0.0 - openai: Optional[bool] = False - mistral: Optional[bool] = True + + def verify_provider_name(self): + if self.model.startswith("openai"): + assert ( + os.environ.get("OPENAI_API_KEY") is not None + ), "OpenAI API key not set" + if self.model.startswith("mistral"): + assert ( + os.environ.get("MISTRAL_API_KEY") is not None + ), "Mistral API key not set" class Player1(Player): def __init__( self, nickname: str, - model: Optional[str] = None, - openai: bool = False, - mistral: bool = True, - solar: bool = False, + model: str, ): self.nickname = nickname - self.model = model or generate_model(openai=openai, mistral=mistral, solar=solar) - self.openai = False - self.mistral = True + self.model = model self.robot = Robot( action_space=None, - character="Mistral", + character="Ken", side=0, character_color=KEN_RED, ennemy_color=KEN_GREEN, @@ -68,22 +68,20 @@ def __init__( player_nb=1, ) print(f"[red] Player 1 using: {self.model}") + self.verify_provider_name() class Player2(Player): def __init__( self, nickname: str, - model: Optional[str] = None, - openai: bool = False, - mistral: bool = True, - solar: bool = False, + model: str, ): self.nickname = nickname - self.model = model or generate_model(openai=openai, mistral=mistral, solar=solar) + self.model = model self.robot = Robot( action_space=None, - character="Solar", + character="Ken", side=1, character_color=KEN_GREEN, ennemy_color=KEN_RED, @@ -92,18 +90,24 @@ def __init__( player_nb=2, ) print(f"[green] Player 2 using: {self.model}") + self.verify_provider_name() class Episode: - player_1: Player1 + player_1: Optional[Player1] player_2: Player2 player_1_won: Optional[bool] = None - def __init__(self, player_1: Player1, player_2: Player2): + def __init__(self, player_1: Optional[Player1], player_2: Player2): self.player_1 = player_1 self.player_2 = player_2 def save(self): + if self.player_1 is None: + # Playing with the controller + # Results are not saved + return + # Write the results to an existing csv with headers "player_1", "player_2", "winner" timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S") @@ -111,47 +115,42 @@ def save(self): if not os.path.exists("results.csv"): with open("results.csv", "w") as f: f.write( - "id, player_1_model, player_1_temperature, player_2_model, player_2_temperature, player_1_won\n" + "id,player_1_model,player_1_temperature,player_2_model,player_2_temperature,player_1_won\n" ) with open("results.csv", "a") as f: f.write( - f"{timestamp}, {self.player_1.model}, {self.player_1.temperature}, {self.player_2.model}, {self.player_2.temperature}, {self.player_1_won}\n" + f"{timestamp},{self.player_1.model},{self.player_1.temperature}," + + f"{self.player_2.model},{self.player_2.temperature},{self.player_1_won}\n" ) class Game: + player_1: Optional[Player1] = None # First player. None if Human + player_2: Player2 + render: Optional[bool] = False splash_screen: Optional[bool] = False save_game: Optional[bool] = False - # characters: Optional[List[str]] = ["Makoto", "Sean"] characters: Optional[List[str]] = ["Ken", "Ken"] outfits: Optional[List[int]] = [1, 3] frame_shape: Optional[List[int]] = [0, 0, 0] seed: Optional[int] = 42 settings: EnvironmentSettingsMultiAgent = None # Settings of the game env = None # Environment of the game - player_1: Player1 = None # First player - player_2: Player2 = None # Second player - openai: Optional[bool] = False - mistral: Optional[bool] = True def __init__( self, + player_1: Optional[Player1], + player_2: Player2, render: bool = False, save_game: bool = False, splash_screen: bool = False, characters: List[str] = ["Ken", "Ken"], - # characters: List[str] = ["Makoto", "Sean"], - super_arts: List[int] = [3,3], + super_arts: List[int] = [3, 3], outfits: List[int] = [1, 3], frame_shape: List[int] = [0, 0, 0], seed: int = 42, - player_1: Player1 = None, - player_2: Player2 = None, - openai: bool = False, - mistral: bool = True, - solar: bool = False, ): """_summary_ @@ -174,22 +173,20 @@ def __init__( self.settings = self._init_settings() self.env = self._init_env(self.settings) self.observation, self.info = self.env.reset(seed=self.seed) - self.openai = openai - self.mistral = mistral - self.solar = solar - print("GAME", openai, mistral, solar, player_1, player_2) - self.player_1 = ( - player_1 - if player_1 - else Player1(nickname="Player 1", openai=False, mistral=False, solar=True) - # else Player1(nickname="Player 1", model="grok:mixtral-8x7b-32768") - ) - self.player_2 = ( - player_2 - if player_2 - # else Player2(nickname="Player 2", model="openai:gpt-4-turbo-preview") - else Player2(nickname="Player 2", openai=False, mistral=True, solar=False) - ) + if player_1 is not None: + self.player_1 = player_1 + else: + # If player 1 is not provided, we will use the controller + # The human player will be able to play with the controller + from diambra.arena.utils.controller import get_diambra_controller + + self.player_1 = None + self.controller = get_diambra_controller( + self.env.unwrapped.get_actions_tuples(), + # force_configure=True, + ) + self.controller.start() + self.player_2 = player_2 def _init_settings(self) -> EnvironmentSettingsMultiAgent: """ @@ -201,13 +198,9 @@ def _init_settings(self) -> EnvironmentSettingsMultiAgent: ) settings.action_space = (SpaceTypes.DISCRETE, SpaceTypes.DISCRETE) - settings.characters = self.characters - settings.outfits = self.outfits - settings.frame_shape = self.frame_shape - settings.super_art = self.super_arts return settings @@ -266,23 +259,23 @@ def run(self): Runs the game with the given settings. """ try: - self.player_1.robot.observe(self.observation, {}, 0.0) - self.player_2.robot.observe(self.observation, {}, 0.0) - # Initialize the episode - - episode = Episode(player_1=self.player_1, player_2=self.player_2) self.actions = { "agent_0": 0, "agent_1": 0, } - self.reward = 0.0 - # Start the thread - player1_thread = PlanAndActPlayer1(game=self, episode=episode) - player2_thread = PlanAndActPlayer2(game=self, episode=episode) + if self.player_1 is not None: + self.player_1.robot.observe(self.observation, {}, 0.0) - player1_thread.start() + self.player_2.robot.observe(self.observation, {}, 0.0) + # Initialize the episode + episode = Episode(player_1=self.player_1, player_2=self.player_2) + # Start the threads that make API calls + if self.player_1 is not None: + player1_thread = PlanAndActPlayer1(game=self, episode=episode) + player1_thread.start() + player2_thread = PlanAndActPlayer2(game=self, episode=episode) player2_thread.start() while True: @@ -291,6 +284,21 @@ def run(self): self.env.render() actions = self.actions + + if self.player_1 is None: + # If player 1 is not provided, we use the controller + try: + # On MacOS we need to install pyobjc + # pip install pyobjc + # https://stackoverflow.com/questions/76434535/attributeerror-super-object-has-no-attribute-init + + controller_actions = self.controller.get_actions() + actions["agent_1"] = ( + controller_actions[0] + controller_actions[1] + ) + except Exception as e: + print(e) + if "agent_0" not in actions: actions["agent_0"] = 0 if "agent_1" not in actions: @@ -311,16 +319,36 @@ def run(self): p2_wins = observation["P2"]["wins"][0] if p1_wins == 1 or p2_wins == 1: - player1_thread.running = False + if self.player_1 is not None: + player1_thread.running = False player2_thread.running = False - episode.player_1_won = p1_wins == 1 + if episode.player_1_won: + print( + f"[red] Player1 {self.player_1.robot.model} '{self.player_1.nickname}' won!" + ) + else: + print( + f"[green] Player2 {self.player_2.robot.model} {self.player_2.nickname} won!" + ) episode.save() self.env.close() break - except Exception: + except Exception as e: + # self.env.close() + print(f"Exception: {e}") + traceback.print_exception(limit=10) + traceback.print_tb(limit=40) + if self.player_1 is None: + self.controller.stop() + self.env.close() + try: + if self.player_1 is None: + self.controller.stop() self.env.close() - print("Game Finished") + except Exception as e: + pass # Ignore the exception + return 0 class PlanAndAct(Thread): @@ -359,4 +387,3 @@ def run(self) -> None: self.game.player_2.robot.observe( self.game.observation, self.game.actions, -self.game.reward ) - time.sleep(0.1) diff --git a/mistral.py b/mistral.py deleted file mode 100644 index 144aa27..0000000 --- a/mistral.py +++ /dev/null @@ -1,38 +0,0 @@ -from dotenv import load_dotenv -from eval.game import Game, Player1, Player2 - -import sys - -from loguru import logger - -logger.remove() # remove the old handler. Else, the old one will work along with the new one you've added below' -logger.add(sys.stdout, level="INFO") - -load_dotenv() - - -def main(): - # Environment Settings - # Environment Settings - - player1 = Player1( - nickname="Baby", - model="mistral:mistral-small-latest", - ) - player2 = Player2( - nickname="Daddy", - model="mistral:mistral-small-latest", - ) - - game = Game( - render=True, - save_game=True, - player_1=player1, - player_2=player2, - ) - - game.run() - - -if __name__ == "__main__": - main() diff --git a/elo.md b/notebooks/elo.md similarity index 100% rename from elo.md rename to notebooks/elo.md diff --git a/ollama.py b/ollama.py new file mode 100644 index 0000000..3cf383f --- /dev/null +++ b/ollama.py @@ -0,0 +1,36 @@ +import sys + +from dotenv import load_dotenv +from eval.game import Game, Player1, Player2 +from loguru import logger + +logger.remove() +logger.add(sys.stdout, level="INFO") + +load_dotenv() + + +def main(): + # Environment Settings + + game = Game( + render=True, + save_game=True, + player_1=Player1( + nickname="Baby", + model="ollama:qwen:14b-chat-v1.5-fp16", + # model="ollama:mistral", + ), + player_2=Player2( + nickname="Daddy", + model="ollama:qwen:14b-chat-v1.5-fp16", + # model="ollama:mistral", + ), + ) + + game.run() + return 0 + + +if __name__ == "__main__": + main() diff --git a/requirements.txt b/requirements.txt index df1f328..cf401ff 100644 --- a/requirements.txt +++ b/requirements.txt @@ -30,11 +30,10 @@ packaging==24.0; python_version >= '3.7' pandas==2.2.1; python_version >= '3.9' pillow==10.2.0; python_version >= '3.8' pip==24.0; python_version >= '3.7' +phospho>=0.3.14; python_version >= '3.8' protobuf==3.20.3; python_version >= '3.7' pydantic==2.6.4; python_version >= '3.8' pydantic-core==2.16.3; python_version >= '3.8' -pyobjc-core==10.2; python_version >= '3.8' -pyobjc-framework-cocoa==10.2; sys_platform == 'darwin' pyparsing==3.1.2; python_full_version >= '3.6.8' python-dateutil==2.9.0.post0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' python-dotenv==1.0.1; python_version >= '3.8' @@ -47,4 +46,4 @@ tk==0.1.0 tqdm==4.66.2; python_version >= '3.7' typing-extensions==4.10.0; python_version >= '3.8' tzdata==2024.1; python_version >= '2' -rich==13.7.1 \ No newline at end of file +rich==13.7.1 diff --git a/script.py b/script.py index a21c95a..0525a3a 100644 --- a/script.py +++ b/script.py @@ -1,11 +1,10 @@ -from dotenv import load_dotenv -from eval.game import Game - import sys +from dotenv import load_dotenv +from eval.game import Game, Player1, Player2, generate_random_model from loguru import logger -logger.remove() # remove the old handler. Else, the old one will work along with the new one you've added below' +logger.remove() logger.add(sys.stdout, level="INFO") load_dotenv() @@ -13,11 +12,18 @@ def main(): # Environment Settings - # Environment Settings - while True: - game = Game(render=True, save_game=True, openai=True, solar=True, mistral=False) - - game.run() + game = Game( + render=True, + player_1=Player1( + nickname="Daddy", + model=generate_random_model(mistral=True), + ), + player_2=Player2( + nickname="Baby", + model=generate_random_model(openai=True), + ), + ) + return game.run() if __name__ == "__main__":