├── .gitignore ├── .python-version ├── .vscode ├── launch.json └── tasks.json ├── Code-of-Conduct.md ├── LICENSE ├── Readme.md ├── extra └── vscode-lovelaice │ ├── .vscode-test.mjs │ ├── .vscodeignore │ ├── CHANGELOG.md │ ├── README.md │ ├── eslint.config.mjs │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── extension.ts │ └── test │ │ └── extension.test.ts │ ├── tsconfig.json │ └── vsc-extension-quickstart.md ├── lovelaice ├── __init__.py ├── __main__.py ├── api.open-meteo.yml ├── api.py ├── cli.py ├── config.py ├── connectors.py ├── core.py ├── models.py └── tools.py ├── pyproject.toml └── uv.lock /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | client/server 4 | .vscode-test 5 | .vscode/settings.json 6 | env 7 | # Created by https://www.toptal.com/developers/gitignore/api/python 8 | # Edit at https://www.toptal.com/developers/gitignore?templates=python 9 | 10 | ### Python ### 11 | # Byte-compiled / optimized / DLL files 12 | __pycache__/ 13 | *.py[cod] 14 | *$py.class 15 | 16 | # C extensions 17 | *.so 18 | 19 | # Distribution / packaging 20 | .Python 21 | build/ 22 | develop-eggs/ 23 | dist/ 24 | downloads/ 25 | eggs/ 26 | .eggs/ 27 | lib/ 28 | lib64/ 29 | parts/ 30 | sdist/ 31 | var/ 32 | wheels/ 33 | share/python-wheels/ 34 | *.egg-info/ 35 | .installed.cfg 36 | *.egg 37 | MANIFEST 38 | 39 | # PyInstaller 40 | # Usually these files are written by a python script from a template 41 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 42 | *.manifest 43 | *.spec 44 | 45 | # Installer logs 46 | pip-log.txt 47 | pip-delete-this-directory.txt 48 | 49 | # Unit test / coverage reports 50 | htmlcov/ 51 | .tox/ 52 | .nox/ 53 | .coverage 54 | .coverage.* 55 | .cache 56 | nosetests.xml 57 | coverage.xml 58 | *.cover 59 | *.py,cover 60 | .hypothesis/ 61 | .pytest_cache/ 62 | cover/ 63 | 64 | # Translations 65 | *.mo 66 | *.pot 67 | 68 | # Django stuff: 69 | *.log 70 | local_settings.py 71 | db.sqlite3 72 | db.sqlite3-journal 73 | 74 | # Flask stuff: 75 | instance/ 76 | .webassets-cache 77 | 78 | # Scrapy stuff: 79 | .scrapy 80 | 81 | # Sphinx documentation 82 | docs/_build/ 83 | 84 | # PyBuilder 85 | .pybuilder/ 86 | target/ 87 | 88 | # Jupyter Notebook 89 | .ipynb_checkpoints 90 | 91 | # IPython 92 | profile_default/ 93 | ipython_config.py 94 | 95 | # pyenv 96 | # For a library or package, you might want to ignore these files since the code is 97 | # intended to run in multiple environments; otherwise, check them in: 98 | # .python-version 99 | 100 | # pipenv 101 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 102 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 103 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 104 | # install all needed dependencies. 105 | #Pipfile.lock 106 | 107 | # poetry 108 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 109 | # This is especially recommended for binary packages to ensure reproducibility, and is more 110 | # commonly ignored for libraries. 111 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 112 | #poetry.lock 113 | 114 | # pdm 115 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 116 | #pdm.lock 117 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 118 | # in version control. 119 | # https://pdm.fming.dev/#use-with-ide 120 | .pdm.toml 121 | 122 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 123 | __pypackages__/ 124 | 125 | # Celery stuff 126 | celerybeat-schedule 127 | celerybeat.pid 128 | 129 | # SageMath parsed files 130 | *.sage.py 131 | 132 | # Environments 133 | .env 134 | .venv 135 | env/ 136 | venv/ 137 | ENV/ 138 | env.bak/ 139 | venv.bak/ 140 | 141 | # Spyder project settings 142 | .spyderproject 143 | .spyproject 144 | 145 | # Rope project settings 146 | .ropeproject 147 | 148 | # mkdocs documentation 149 | /site 150 | 151 | # mypy 152 | .mypy_cache/ 153 | .dmypy.json 154 | dmypy.json 155 | 156 | # Pyre type checker 157 | .pyre/ 158 | 159 | # pytype static type analyzer 160 | .pytype/ 161 | 162 | # Cython debug symbols 163 | cython_debug/ 164 | 165 | # PyCharm 166 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 167 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 168 | # and can be added to the global gitignore or merged into this file. For a more nuclear 169 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 170 | #.idea/ 171 | 172 | ### Python Patch ### 173 | # Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration 174 | poetry.toml 175 | 176 | # ruff 177 | .ruff_cache/ 178 | 179 | # LSP config files 180 | pyrightconfig.json 181 | 182 | # End of https://www.toptal.com/developers/gitignore/api/python 183 | # Created by https://www.toptal.com/developers/gitignore/api/node 184 | # Edit at https://www.toptal.com/developers/gitignore?templates=node 185 | 186 | ### Node ### 187 | # Logs 188 | logs 189 | *.log 190 | npm-debug.log* 191 | yarn-debug.log* 192 | yarn-error.log* 193 | lerna-debug.log* 194 | .pnpm-debug.log* 195 | 196 | # Diagnostic reports (https://nodejs.org/api/report.html) 197 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 198 | 199 | # Runtime data 200 | pids 201 | *.pid 202 | *.seed 203 | *.pid.lock 204 | 205 | # Directory for instrumented libs generated by jscoverage/JSCover 206 | lib-cov 207 | 208 | # Coverage directory used by tools like istanbul 209 | coverage 210 | *.lcov 211 | 212 | # nyc test coverage 213 | .nyc_output 214 | 215 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 216 | .grunt 217 | 218 | # Bower dependency directory (https://bower.io/) 219 | bower_components 220 | 221 | # node-waf configuration 222 | .lock-wscript 223 | 224 | # Compiled binary addons (https://nodejs.org/api/addons.html) 225 | build/Release 226 | 227 | # Dependency directories 228 | node_modules/ 229 | jspm_packages/ 230 | 231 | # Snowpack dependency directory (https://snowpack.dev/) 232 | web_modules/ 233 | 234 | # TypeScript cache 235 | *.tsbuildinfo 236 | 237 | # Optional npm cache directory 238 | .npm 239 | 240 | # Optional eslint cache 241 | .eslintcache 242 | 243 | # Optional stylelint cache 244 | .stylelintcache 245 | 246 | # Microbundle cache 247 | .rpt2_cache/ 248 | .rts2_cache_cjs/ 249 | .rts2_cache_es/ 250 | .rts2_cache_umd/ 251 | 252 | # Optional REPL history 253 | .node_repl_history 254 | 255 | # Output of 'npm pack' 256 | *.tgz 257 | 258 | # Yarn Integrity file 259 | .yarn-integrity 260 | 261 | # dotenv environment variable files 262 | .env 263 | .env.development.local 264 | .env.test.local 265 | .env.production.local 266 | .env.local 267 | 268 | # parcel-bundler cache (https://parceljs.org/) 269 | .cache 270 | .parcel-cache 271 | 272 | # Next.js build output 273 | .next 274 | out 275 | 276 | # Nuxt.js build / generate output 277 | .nuxt 278 | dist 279 | 280 | # Gatsby files 281 | .cache/ 282 | # Comment in the public line in if your project uses Gatsby and not Next.js 283 | # https://nextjs.org/blog/next-9-1#public-directory-support 284 | # public 285 | 286 | # vuepress build output 287 | .vuepress/dist 288 | 289 | # vuepress v2.x temp and cache directory 290 | .temp 291 | 292 | # Docusaurus cache and generated files 293 | .docusaurus 294 | 295 | # Serverless directories 296 | .serverless/ 297 | 298 | # FuseBox cache 299 | .fusebox/ 300 | 301 | # DynamoDB Local files 302 | .dynamodb/ 303 | 304 | # TernJS port file 305 | .tern-port 306 | 307 | # Stores VSCode versions used for testing VSCode extensions 308 | .vscode-test 309 | 310 | # yarn v2 311 | .yarn/cache 312 | .yarn/unplugged 313 | .yarn/build-state.yml 314 | .yarn/install-state.gz 315 | .pnp.* 316 | 317 | ### Node Patch ### 318 | # Serverless Webpack directories 319 | .webpack/ 320 | 321 | # Optional stylelint cache 322 | 323 | # SvelteKit build / generate output 324 | .svelte-kit 325 | 326 | # End of https://www.toptal.com/developers/gitignore/api/node 327 | data/* 328 | app/lovelaice 329 | app/uploads 330 | 331 | .lovelaice.yml -------------------------------------------------------------------------------- /.python-version: -------------------------------------------------------------------------------- 1 | 3.12 2 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "args": [ 13 | "--extensionDevelopmentPath=${workspaceFolder}/extra/vscode-lovelaice" 14 | ], 15 | "outFiles": [ 16 | "${workspaceFolder}/extra/vscode-lovelaice/out/**/*.js" 17 | ], 18 | "preLaunchTask": "${defaultBuildTask}" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "path": "extra/vscode-lovelaice", 10 | "problemMatcher": "$tsc-watch", 11 | "isBackground": true, 12 | "presentation": { 13 | "reveal": "never" 14 | }, 15 | "group": { 16 | "kind": "build", 17 | "isDefault": true 18 | } 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /Code-of-Conduct.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct for Lovelaice 2 | 3 | This code of conduct outlines the expected behavior of all participants in our LLM-based project. Our goal is to foster a respectful, inclusive, and productive environment while ensuring the ethical use of language models. 4 | 5 | ## Principles 6 | 7 | 1. **Fairness** 8 | - Treat all participants with respect and kindness, valuing diverse perspectives and backgrounds. 9 | - Ensure that our project outputs do not perpetuate bias or discrimination and actively work towards equitable outcomes. 10 | 11 | 2. **Reliability and Safety** 12 | - Engage in honest discussions and uphold integrity in all interactions. 13 | - Collaborate to enhance the robustness and safety of our LLM applications, ensuring they operate effectively across various conditions. 14 | 15 | 3. **Privacy and Security** 16 | - Safeguard personal data and respect privacy in all aspects of project work. 17 | - Ensure that any data used complies with ethical standards and does not infringe on the rights of individuals or organizations. 18 | 19 | 4. **Inclusiveness** 20 | - Foster an inclusive environment where everyone feels empowered to contribute, regardless of their expertise. 21 | - Actively seek input from diverse stakeholders to enhance the project's relevance and impact. 22 | 23 | 5. **Transparency** 24 | - Communicate openly about project goals, methodologies, and decision-making processes. 25 | - Provide clear explanations for how our LLM systems generate outputs, fostering trust among users and contributors. 26 | 27 | 6. **Accountability** 28 | - Take responsibility for the impacts of our work, ensuring that we address any unintended consequences promptly. 29 | - If you witness or experience any violations of this code, please report them to the project maintainers promptly. All reports will be treated confidentially and investigated thoroughly. 30 | 31 | 7. **Responsible Use of LLMs** 32 | - Do not use this project or its outputs to create or disseminate misinformation or engage in malicious activities. 33 | - Avoid applications that promote hate speech, harassment, or any form of discrimination. 34 | 35 | ## Conclusion 36 | 37 | By participating in this project, you agree to abide by this code of conduct. Together, we can create a positive impact through responsible use of language models while adhering to ethical standards. 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Alejandro Piad Morffis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Lovelaice: An AI-powered assistant for your terminal and editor 2 | 3 | ![PyPI - Version](https://img.shields.io/pypi/v/lovelaice) 4 | ![GitHub License](https://img.shields.io/github/license/apiad/lovelaice) 5 | ![PyPI - Downloads](https://img.shields.io/pypi/dm/lovelaice) 6 | ![GitHub commit activity](https://img.shields.io/github/commit-activity/m/apiad/lovelaice) 7 | 8 | Lovelaice is an LLM-powered bot that sits in your terminal. 9 | It has access to your files and it can run bash commands for you. 10 | It can also access the Internet and search for answers to general 11 | questions, as well as technical ones. 12 | 13 | ## Installation 14 | 15 | Install with pip: 16 | 17 | pip install lovelaice 18 | 19 | ## Configuring 20 | 21 | Before using Lovelaice, you will need an API key for OpenAI and a model. 22 | Run `lovelaice --config` to set up `lovelaice` for the first time. 23 | 24 | $ lovelaice --config 25 | 26 | The API base URL (in case you're not using OpenAI) 27 | base_url: 28 | 29 | The API key to authenticate with the LLM provider 30 | api_key: 31 | 32 | The concrete LLM model to use 33 | model (gpt-4o): 34 | 35 | You can also define a custom base URL 36 | (if you are using an alternative, OpenAI-compatible 37 | provider such as [Fireworks AI](https://fireworks.ai) or [Mistral AI](https://mistral.ai), or a local LLM server such as LMStudio or vLLM). 38 | Leave it blank if you are using OpenAI's API. 39 | 40 | Once configured, you'll find a `.lovelaice.yml` file in your home directory 41 | (or wherever you ran `lovelaice --config`). These configuration files will stack up, 42 | so you can have a general configuration in your home folder, and a project-specific 43 | configuration in any sub-folder. 44 | 45 | ## Usage 46 | 47 | You can use `lovelaice` from the command line to ask anything. 48 | Lovelaice understands many different types of requests, and will 49 | employ different tools according to the question. 50 | 51 | You can also use Lovelaice in interactive mode just by typing `lovelaice` without a query. 52 | It will launch a conversation loop that you can close at any time with Ctrl+D. 53 | 54 | Remember to run `lovelaice --help` for a full description of all commands. 55 | 56 | ### Basic completion 57 | 58 | You can use `lovelaice` a basic completion model, passing `--complete` or `-c` for short. 59 | 60 | $ lovelaice -c Once upon a time, in a small village 61 | 62 | Once upon a time, in a small village nestled in the rolling hills of Provence, 63 | there was a tiny, exquisite perfume shop. The sign above the door read 64 | "Maison de Rêve" – House of Dreams. The shop was owned by a kind-hearted and 65 | talented perfumer named Colette, who spent her days crafting enchanting fragrances 66 | that transported those who wore them to a world of beauty and wonder. 67 | 68 | [...] 69 | 70 | ### File completion 71 | 72 | You can also run `lovelaice --complete-files [files]` and have `lovelaice` instead run completion on text file. It will scan the file for the first occurrence of the `+++` token and run completion using the previous text as prompt. 73 | 74 | Additionally, you can add `--watch` to leave `lovelaice` running in the background, watching for file changes to all of the arguments to `--complete-files`. Every time a file changes, it will run completion there. 75 | 76 | In conjunction with a sensible text editor (e.g. one that reloads files when changed on disk), this feature allows you to have an almost seamless integration between `lovelaice` and your editor. Just type a `+++` anywhere you want `lovelaice` to complete, hit Ctrl+S, and wait for a few seconds. No need for fancy editor plugins. 77 | 78 | ### Chat 79 | 80 | You can ask a casual question about virtually anything: 81 | 82 | $ lovelaice what is the meaning of life 83 | 84 | The meaning of life is a philosophical and metaphysical question 85 | related to the significance of living or existence in general. 86 | Many different people, cultures, and religions have different 87 | beliefs about the purpose and meaning of life. 88 | 89 | [...] 90 | 91 | ### Bash 92 | 93 | You can also ask `lovelaice` to do something in your terminal: 94 | 95 | $ lovelaice how much free space do i have 96 | :: Using Bash 97 | 98 | Running the following code: 99 | $ df -h | grep '/$' | awk '{ print $4 }' 100 | [y]es / [N]o y 101 | 102 | 5,5G 103 | 104 | You have approximately 5.5 Gigabytes of free space left on your filesystem. 105 | 106 | ### Codegen 107 | 108 | You can ask a general question about programming: 109 | 110 | $ lovelaice how to make an async iterator in python 111 | :: Using Codegen 112 | 113 | In Python, you can create an asynchronous iterator using the `async for` statement and the `async def` syntax. Asynchronous iterators are useful when you want to iterate over a sequence of asynchronous tasks, such as fetching data from a web service. 114 | 115 | Here's a general explanation of how to create an asynchronous iterator in Python: 116 | 117 | 1. Define an asynchronous generator function using the `async def` syntax. 118 | 2. Inside the function, use the `async for` statement to iterate over the asynchronous tasks. 119 | 3. Use the `yield` keyword to return each item from the generator function. 120 | 121 | Here's an example of an asynchronous iterator that generates a sequence of integers: 122 | 123 | ```python 124 | async def async_integer_generator(): 125 | i = 0 126 | while True: 127 | yield i 128 | i += 1 129 | await asyncio.sleep(0.1) 130 | ``` 131 | [...] 132 | 133 | Overall, creating an asynchronous iterator in Python is a powerful way to iterate over a sequence of asynchronous tasks. By using the `async def` syntax, the `async for` statement, and the `yield` keyword, you can create an efficient and flexible iterator that can handle a wide range of use cases. 134 | 135 | ### Interpreter 136 | 137 | And if you ask it something math-related it can generate and run Python for you: 138 | 139 | $ lovelaice throw three d20 dices and return the middle value 140 | :: Using Interpreter 141 | 142 | Will run the following code: 143 | 144 | def solve(): 145 | values = [random.randint(1, 20) for _ in range(3)] 146 | values.sort() 147 | return values[1] 148 | 149 | result = solve() 150 | 151 | [y]es / [N]o y 152 | 153 | Result: 14 154 | 155 | > **NOTE**: Lovelaice will *always* require you to explicitly agree to run any code. 156 | Make sure that you understand what the code will do, otherwise there is no guarantee 157 | your computer won't suddenly grow a hand and slap you in the face, like, literally. 158 | 159 | ## Features 160 | 161 | So far Lovelaice has both general-purpose chat capabilites, and access to bash. 162 | Here is a list of things you can try: 163 | 164 | - Chat with Lovelaice about casual stuff 165 | - Ask Lovelaice questions about your system, distribution, free space, etc. 166 | - Order Lovelaice to create folders, install packages, update apps, etc. 167 | - Order Lovelaice to set settings, turn off the wifi, restart the computer, etc. 168 | - Order Lovelaice to stage, commit, push, show diffs, etc. 169 | - Ask Lovelaice to solve some math equation, generate random numbers, etc. 170 | 171 | In general, you can attempt to ask Lovelaice to do just about anything 172 | that requires bash, and it will try its best. Your imagination is the only limit. 173 | 174 | ### Roadmap 175 | 176 | Here are some features under active development: 177 | 178 | - JSON mode, reply with a JSON object if invoked with `--json`. 179 | - Integrate with `instructor` for robust JSON responses. 180 | - Integrate with `rich` for better CLI experience. 181 | - Keep conversation history in context. 182 | - Separate tools from skills to improve intent detection. 183 | - Read files and answer questions about their content. 184 | - Recover from mistakes and suggest solutions (e.g., installing libraries). 185 | - Create and modify notes, emails, calendar entries, etc. 186 | - Read your emails and send emails on your behalf (with confirmation!). 187 | - Tell you about the weather (https://open-meteo.com/). 188 | - Scaffold coding projects, creating files and running initialization commands. 189 | - Search in Google, crawl webpages, and answer questions using that content. 190 | - VSCode extension. 191 | - Transcribe audio. 192 | - Extract structured information from plain text. 193 | - Understand Excel sheets and draw graphs. 194 | - Call APIs and download data, using the OpenAPI.json specification. 195 | - More powerful planning, e.g., use several tools for a single task. 196 | - Learning mode to add instructions for concrete skills. 197 | 198 | ### Changelog 199 | 200 | - v0.3.6: Basic API (completion only) 201 | - v0.3.5: Structured configuration in YAML 202 | - v0.3.4: Basic functionality and tools 203 | 204 | ## Contributing 205 | 206 | Code is MIT. Just fork, clone, edit, and open a PR. 207 | All suggestions, bug reports, and contributions are welcome. 208 | 209 | ## Star History 210 | 211 | [![Star History Chart](https://api.star-history.com/svg?repos=apiad/lovelaice&type=Date)](https://star-history.com/#apiad/lovelaice&Date) 212 | 213 | ## FAQ 214 | 215 | **What models do you use?** 216 | 217 | Currently, all OpenAI-compatible APIs are supported, which 218 | should cover most use cases, including major commercial LLM providers 219 | as well as local serves. 220 | 221 | If you want to use a custom API that is not OpenAI-compatible, 222 | you can easily setup a proxy with [LiteLLM](https://litellm.ai). 223 | 224 | I do not have specific plans to add any other API, because maintaining 225 | different APIs could become hell, 226 | but you are free to submit a PR for your favorite API and 227 | it might get included. 228 | 229 | **Is this safe?** 230 | 231 | Lovelaice will never run code without your explicit consent. 232 | That being said, LLMs are known for making subtle mistakes, so never 233 | trust that the code does what Lovelaice says it do. Always read 234 | the code and make sure you understand what it does. 235 | 236 | When in doubt, adopt the same stance as if you were copy/pasting code from 237 | a random blog somehwere in the web (because that is exactly what you're doing). 238 | 239 | **Which model(s) shoud I use?** 240 | 241 | I have tested `lovelaice` extensibly using `Llama 3.1 70b`, from [Fireworks AI](https://fireworks.ai). 242 | It is fairly versatile model that is still affordable enough for full-time use. It works well for coding, general chat, bash generation, creative storytelling, and basically anything I use `lovelaice` on a daily basis. 243 | 244 | Thus, probably any model with a similar general performance to Llama 70b will work similarly well. You are unlikely to need, e.g., a 400b model unless you want a pretty complex task. However, using very small models, e.g., 11b or less, may lead to degraded performance, especially because these models may fail to even detect which is the best tool to use. In any case, there is no substitute for experimentation. 245 | -------------------------------------------------------------------------------- /extra/vscode-lovelaice/.vscode-test.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@vscode/test-cli'; 2 | 3 | export default defineConfig({ 4 | files: 'out/test/**/*.test.js', 5 | }); 6 | -------------------------------------------------------------------------------- /extra/vscode-lovelaice/.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | src/** 4 | .gitignore 5 | .yarnrc 6 | vsc-extension-quickstart.md 7 | **/tsconfig.json 8 | **/eslint.config.mjs 9 | **/*.map 10 | **/*.ts 11 | **/.vscode-test.* 12 | -------------------------------------------------------------------------------- /extra/vscode-lovelaice/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "vscode-lovelaice" extension will be documented in this file. 4 | 5 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 6 | 7 | ## [Unreleased] 8 | 9 | - Initial release -------------------------------------------------------------------------------- /extra/vscode-lovelaice/README.md: -------------------------------------------------------------------------------- 1 | # vscode-lovelaice README 2 | 3 | This is the README for your extension "vscode-lovelaice". After writing up a brief description, we recommend including the following sections. 4 | 5 | ## Features 6 | 7 | Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file. 8 | 9 | For example if there is an image subfolder under your extension project workspace: 10 | 11 | \!\[feature X\]\(images/feature-x.png\) 12 | 13 | > Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow. 14 | 15 | ## Requirements 16 | 17 | If you have any requirements or dependencies, add a section describing those and how to install and configure them. 18 | 19 | ## Extension Settings 20 | 21 | Include if your extension adds any VS Code settings through the `contributes.configuration` extension point. 22 | 23 | For example: 24 | 25 | This extension contributes the following settings: 26 | 27 | * `myExtension.enable`: Enable/disable this extension. 28 | * `myExtension.thing`: Set to `blah` to do something. 29 | 30 | ## Known Issues 31 | 32 | Calling out known issues can help limit users opening duplicate issues against your extension. 33 | 34 | ## Release Notes 35 | 36 | Users appreciate release notes as you update your extension. 37 | 38 | ### 1.0.0 39 | 40 | Initial release of ... 41 | 42 | ### 1.0.1 43 | 44 | Fixed issue #. 45 | 46 | ### 1.1.0 47 | 48 | Added features X, Y, and Z. 49 | 50 | --- 51 | 52 | ## Following extension guidelines 53 | 54 | Ensure that you've read through the extensions guidelines and follow the best practices for creating your extension. 55 | 56 | * [Extension Guidelines](https://code.visualstudio.com/api/references/extension-guidelines) 57 | 58 | ## Working with Markdown 59 | 60 | You can author your README using Visual Studio Code. Here are some useful editor keyboard shortcuts: 61 | 62 | * Split the editor (`Cmd+\` on macOS or `Ctrl+\` on Windows and Linux). 63 | * Toggle preview (`Shift+Cmd+V` on macOS or `Shift+Ctrl+V` on Windows and Linux). 64 | * Press `Ctrl+Space` (Windows, Linux, macOS) to see a list of Markdown snippets. 65 | 66 | ## For more information 67 | 68 | * [Visual Studio Code's Markdown Support](http://code.visualstudio.com/docs/languages/markdown) 69 | * [Markdown Syntax Reference](https://help.github.com/articles/markdown-basics/) 70 | 71 | **Enjoy!** 72 | -------------------------------------------------------------------------------- /extra/vscode-lovelaice/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import typescriptEslint from "@typescript-eslint/eslint-plugin"; 2 | import tsParser from "@typescript-eslint/parser"; 3 | 4 | export default [{ 5 | files: ["**/*.ts"], 6 | }, { 7 | plugins: { 8 | "@typescript-eslint": typescriptEslint, 9 | }, 10 | 11 | languageOptions: { 12 | parser: tsParser, 13 | ecmaVersion: 2022, 14 | sourceType: "module", 15 | }, 16 | 17 | rules: { 18 | "@typescript-eslint/naming-convention": ["warn", { 19 | selector: "import", 20 | format: ["camelCase", "PascalCase"], 21 | }], 22 | 23 | curly: "warn", 24 | eqeqeq: "warn", 25 | "no-throw-literal": "warn", 26 | semi: "warn", 27 | }, 28 | }]; -------------------------------------------------------------------------------- /extra/vscode-lovelaice/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-lovelaice", 3 | "displayName": "Lovelaice", 4 | "description": "", 5 | "version": "0.0.1", 6 | "engines": { 7 | "vscode": "^1.96.0" 8 | }, 9 | "categories": [ 10 | "Other" 11 | ], 12 | "activationEvents": [], 13 | "main": "./out/extension.js", 14 | "contributes": { 15 | "commands": [ 16 | { 17 | "command": "vscode-lovelaice.helloWorld", 18 | "title": "Hello World" 19 | } 20 | ] 21 | }, 22 | "scripts": { 23 | "vscode:prepublish": "npm run compile", 24 | "compile": "tsc -p ./", 25 | "watch": "tsc -watch -p ./", 26 | "pretest": "npm run compile && npm run lint", 27 | "lint": "eslint src", 28 | "test": "vscode-test" 29 | }, 30 | "devDependencies": { 31 | "@types/vscode": "^1.96.0", 32 | "@types/mocha": "^10.0.10", 33 | "@types/node": "20.x", 34 | "@typescript-eslint/eslint-plugin": "^8.17.0", 35 | "@typescript-eslint/parser": "^8.17.0", 36 | "eslint": "^9.16.0", 37 | "typescript": "^5.7.2", 38 | "@vscode/test-cli": "^0.0.10", 39 | "@vscode/test-electron": "^2.4.1" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /extra/vscode-lovelaice/src/extension.ts: -------------------------------------------------------------------------------- 1 | // The module 'vscode' contains the VS Code extensibility API 2 | // Import the module and reference it with the alias vscode in your code below 3 | import * as vscode from 'vscode'; 4 | 5 | // This method is called when your extension is activated 6 | // Your extension is activated the very first time the command is executed 7 | export function activate(context: vscode.ExtensionContext) { 8 | 9 | // Use the console to output diagnostic information (console.log) and errors (console.error) 10 | // This line of code will only be executed once when your extension is activated 11 | console.log('Congratulations, your extension "vscode-lovelaice" is now active!'); 12 | 13 | // The command has been defined in the package.json file 14 | // Now provide the implementation of the command with registerCommand 15 | // The commandId parameter must match the command field in package.json 16 | const disposable = vscode.commands.registerCommand('vscode-lovelaice.helloWorld', () => { 17 | // The code you place here will be executed every time your command is executed 18 | // Display a message box to the user 19 | vscode.window.showInformationMessage('Hello World !! from Lovelaice!'); 20 | }); 21 | 22 | context.subscriptions.push(disposable); 23 | } 24 | 25 | // This method is called when your extension is deactivated 26 | export function deactivate() {} 27 | -------------------------------------------------------------------------------- /extra/vscode-lovelaice/src/test/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | 3 | // You can import and use all API from the 'vscode' module 4 | // as well as import your extension to test it 5 | import * as vscode from 'vscode'; 6 | // import * as myExtension from '../../extension'; 7 | 8 | suite('Extension Test Suite', () => { 9 | vscode.window.showInformationMessage('Start all tests.'); 10 | 11 | test('Sample test', () => { 12 | assert.strictEqual(-1, [1, 2, 3].indexOf(5)); 13 | assert.strictEqual(-1, [1, 2, 3].indexOf(0)); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /extra/vscode-lovelaice/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "Node16", 4 | "target": "ES2022", 5 | "outDir": "out", 6 | "lib": [ 7 | "ES2022" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | "strict": true, /* enable all strict type-checking options */ 12 | /* Additional Checks */ 13 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 14 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 15 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /extra/vscode-lovelaice/vsc-extension-quickstart.md: -------------------------------------------------------------------------------- 1 | # Welcome to your VS Code Extension 2 | 3 | ## What's in the folder 4 | 5 | * This folder contains all of the files necessary for your extension. 6 | * `package.json` - this is the manifest file in which you declare your extension and command. 7 | * The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesn’t yet need to load the plugin. 8 | * `src/extension.ts` - this is the main file where you will provide the implementation of your command. 9 | * The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`. 10 | * We pass the function containing the implementation of the command as the second parameter to `registerCommand`. 11 | 12 | ## Get up and running straight away 13 | 14 | * Press `F5` to open a new window with your extension loaded. 15 | * Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`. 16 | * Set breakpoints in your code inside `src/extension.ts` to debug your extension. 17 | * Find output from your extension in the debug console. 18 | 19 | ## Make changes 20 | 21 | * You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`. 22 | * You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. 23 | 24 | ## Explore the API 25 | 26 | * You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`. 27 | 28 | ## Run tests 29 | 30 | * Install the [Extension Test Runner](https://marketplace.visualstudio.com/items?itemName=ms-vscode.extension-test-runner) 31 | * Run the "watch" task via the **Tasks: Run Task** command. Make sure this is running, or tests might not be discovered. 32 | * Open the Testing view from the activity bar and click the Run Test" button, or use the hotkey `Ctrl/Cmd + ; A` 33 | * See the output of the test result in the Test Results view. 34 | * Make changes to `src/test/extension.test.ts` or create new test files inside the `test` folder. 35 | * The provided test runner will only consider files matching the name pattern `**.test.ts`. 36 | * You can create folders inside the `test` folder to structure your tests any way you want. 37 | 38 | ## Go further 39 | 40 | * [Follow UX guidelines](https://code.visualstudio.com/api/ux-guidelines/overview) to create extensions that seamlessly integrate with VS Code's native interface and patterns. 41 | * Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension). 42 | * [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VS Code extension marketplace. 43 | * Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration). 44 | * Integrate to the [report issue](https://code.visualstudio.com/api/get-started/wrapping-up#issue-reporting) flow to get issue and feature requests reported by users. 45 | -------------------------------------------------------------------------------- /lovelaice/__init__.py: -------------------------------------------------------------------------------- 1 | VERSION = "0.3.6" -------------------------------------------------------------------------------- /lovelaice/__main__.py: -------------------------------------------------------------------------------- 1 | from .cli import run 2 | 3 | if __name__ == "__main__": 4 | run() 5 | -------------------------------------------------------------------------------- /lovelaice/api.open-meteo.yml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | title: Open-Meteo APIs 4 | description: 'Open-Meteo offers free weather forecast APIs for open-source developers and non-commercial use. No API key is required.' 5 | version: '1.0' 6 | contact: 7 | name: Open-Meteo 8 | url: https://open-meteo.com 9 | email: info@open-meteo.com 10 | license: 11 | name: Attribution 4.0 International (CC BY 4.0) 12 | url: https://creativecommons.org/licenses/by/4.0/ 13 | termsOfService: https://open-meteo.com/en/features#terms 14 | paths: 15 | /v1/forecast: 16 | servers: 17 | - url: https://api.open-meteo.com 18 | get: 19 | tags: 20 | - Weather Forecast APIs 21 | summary: Weather forecast for coordinates 22 | description: Weather variables in hourly and daily resolution for given WGS84 latitude and longitude coordinates. Available worldwide. Up to 16 days of forecast data can be requested. 23 | parameters: 24 | - name: latitude 25 | in: query 26 | required: true 27 | description: "Geographical WGS84 coordinates of the location. Multiple coordinates can be comma separated. E.g. &latitude=52.52,48.85&longitude=13.41,2.35." 28 | schema: 29 | type: string 30 | - name: longitude 31 | in: query 32 | required: true 33 | description: "Geographical WGS84 coordinates of the location. Multiple coordinates can be comma separated." 34 | schema: 35 | type: string 36 | - name: elevation 37 | in: query 38 | description: "The elevation used for statistical downscaling. Per default, a 90 meter digital elevation model is used. If &elevation=nan is specified, downscaling will be disabled." 39 | schema: 40 | type: number 41 | format: float 42 | - name: hourly 43 | in: query 44 | explode: false 45 | description: "A list of weather variables which should be returned. Values can be comma separated, or multiple &hourly= parameter in the URL can be used." 46 | schema: 47 | type: array 48 | items: 49 | type: string 50 | enum: 51 | - temperature_2m 52 | - relative_humidity_2m 53 | - dew_point_2m 54 | - apparent_temperature 55 | - pressure_msl 56 | - surface_pressure 57 | - cloud_cover 58 | - cloud_cover_low 59 | - cloud_cover_mid 60 | - cloud_cover_high 61 | - wind_speed_10m 62 | - wind_speed_80m 63 | - wind_speed_120m 64 | - wind_speed_180m 65 | - wind_direction_10m 66 | - wind_direction_80m 67 | - wind_direction_120m 68 | - wind_direction_180m 69 | - wind_gusts_10m 70 | - shortwave_radiation 71 | - direct_radiation 72 | - direct_normal_irradiance 73 | - diffuse_radiation 74 | - global_tilted_irradiance 75 | - vapour_pressure_deficit 76 | - cape 77 | - evapotranspiration 78 | - et0_fao_evapotranspiration 79 | - precipitation 80 | - snowfall 81 | - precipitation_probability 82 | - rain 83 | - showers 84 | - weather_code 85 | - snow_depth 86 | - freezing_level_height 87 | - visibility 88 | - soil_temperature_0cm 89 | - soil_temperature_6cm 90 | - soil_temperature_18cm 91 | - soil_temperature_54cm 92 | - soil_moisture_0_to_1cm 93 | - soil_moisture_1_to_3cm 94 | - soil_moisture_3_to_9cm 95 | - soil_moisture_9_to_27cm 96 | - soil_moisture_27_to_81cm 97 | - is_day 98 | - name: daily 99 | in: query 100 | description: "A list of daily weather variable aggregations which should be returned. Values can be comma separated, or multiple &daily= parameter in the URL can be used. If daily weather variables are specified, parameter timezone is required." 101 | schema: 102 | type: array 103 | items: 104 | type: string 105 | enum: 106 | - temperature_2m_max 107 | - temperature_2m_min 108 | - apparent_temperature_max 109 | - apparent_temperature_min 110 | - precipitation_sum 111 | - rain_sum 112 | - showers_sum 113 | - snowfall_sum 114 | - precipitation_hours 115 | - precipitation_probability_max 116 | - precipitation_probability_min 117 | - precipitation_probability_mean 118 | - weather_code 119 | - sunrise 120 | - sunset 121 | - sunshine_duration 122 | - daylight_duration 123 | - wind_speed_10m_max 124 | - wind_gusts_10m_max 125 | - wind_direction_10m_dominant 126 | - shortwave_radiation_sum 127 | - et0_fao_evapotranspiration 128 | - uv_index_max 129 | - uv_index_clear_sky_max 130 | - name: current 131 | in: query 132 | description: "A list of weather variables to get current conditions." 133 | schema: 134 | type: array 135 | items: 136 | items: 137 | type: string 138 | enum: 139 | - temperature_2m 140 | - relative_humidity_2m 141 | - dew_point_2m 142 | - apparent_temperature 143 | - pressure_msl 144 | - surface_pressure 145 | - cloud_cover 146 | - cloud_cover_low 147 | - cloud_cover_mid 148 | - cloud_cover_high 149 | - wind_speed_10m 150 | - wind_speed_80m 151 | - wind_speed_120m 152 | - wind_speed_180m 153 | - wind_direction_10m 154 | - wind_direction_80m 155 | - wind_direction_120m 156 | - wind_direction_180m 157 | - wind_gusts_10m 158 | - shortwave_radiation 159 | - direct_radiation 160 | - direct_normal_irradiance 161 | - diffuse_radiation 162 | - global_tilted_irradiance 163 | - vapour_pressure_deficit 164 | - cape 165 | - evapotranspiration 166 | - et0_fao_evapotranspiration 167 | - precipitation 168 | - snowfall 169 | - precipitation_probability 170 | - rain 171 | - showers 172 | - weather_code 173 | - snow_depth 174 | - freezing_level_height 175 | - visibility 176 | - soil_temperature_0cm 177 | - soil_temperature_6cm 178 | - soil_temperature_18cm 179 | - soil_temperature_54cm 180 | - soil_moisture_0_to_1cm 181 | - soil_moisture_1_to_3cm 182 | - soil_moisture_3_to_9cm 183 | - soil_moisture_9_to_27cm 184 | - soil_moisture_27_to_81cm 185 | - is_day 186 | - name: temperature_unit 187 | in: query 188 | description: "If fahrenheit is set, all temperature values are converted to Fahrenheit." 189 | schema: 190 | type: string 191 | default: celsius 192 | enum: 193 | - celsius 194 | - fahrenheit 195 | - name: wind_speed_unit 196 | in: query 197 | description: "Other wind speed units: ms, mph and kn." 198 | schema: 199 | type: string 200 | default: kmh 201 | enum: 202 | - kmh 203 | - ms 204 | - mph 205 | - kn 206 | - name: precipitation_unit 207 | in: query 208 | description: "Other precipitation amount units: inch." 209 | schema: 210 | type: string 211 | default: mm 212 | enum: 213 | - mm 214 | - inch 215 | - name: timeformat 216 | in: query 217 | description: "If format unixtime is selected, all time values are returned in UNIX epoch time in seconds. Please note that all timestamp are in GMT+0! For daily values with unix timestamps, please apply utc_offset_seconds again to get the correct date." 218 | schema: 219 | type: string 220 | default: iso8601 221 | enum: 222 | - iso8601 223 | - unixtime 224 | - name: timezone 225 | in: query 226 | description: "If timezone is set, all timestamps are returned as local-time and data is returned starting at 00:00 local-time. Any time zone name from the time zone database is supported. If auto is set as a time zone, the coordinates will be automatically resolved to the local time zone." 227 | schema: 228 | type: string 229 | - name: past_days 230 | in: query 231 | description: "If past_days is set, yesterday or the day before yesterday data are also returned." 232 | schema: 233 | type: integer 234 | minimum: 0 235 | maximum: 92 236 | default: 0 237 | - name: forecast_days 238 | in: query 239 | description: "Per default, only 7 days are returned. Up to 16 days of forecast are possible." 240 | schema: 241 | type: integer 242 | minimum: 0 243 | maximum: 16 244 | default: 7 245 | - name: forecast_hours 246 | in: query 247 | description: "Similar to forecast_days, the number of timesteps of hourly data can be controlled. Instead of using the current day as a reference, the current hour is used." 248 | schema: 249 | type: integer 250 | minimum: 0 251 | - name: forecast_minutely_15 252 | in: query 253 | description: "Similar to forecast_days, the number of timesteps of 15-minutely data can be controlled. Instead of using the current day as a reference, the current 15-minute time-step is used." 254 | schema: 255 | type: integer 256 | minimum: 0 257 | - name: past_hours 258 | in: query 259 | description: "Similar to past_days, but for hourly data." 260 | schema: 261 | type: integer 262 | minimum: 0 263 | - name: past_minutely_15 264 | in: query 265 | description: "Similar to past_days, but for 15-minutely data." 266 | schema: 267 | type: integer 268 | minimum: 0 269 | - name: start_date 270 | in: query 271 | description: "The start date for the time interval to get weather data. A day must be specified as an ISO8601 date (e.g. 2022-06-30)." 272 | schema: 273 | type: string 274 | format: date 275 | - name: end_date 276 | in: query 277 | description: "The end date for the time interval to get weather data. A day must be specified as an ISO8601 date (e.g. 2022-06-30)." 278 | schema: 279 | type: string 280 | format: date 281 | - name: start_hour 282 | in: query 283 | description: "The start hour for the time interval to get hourly weather data. Time must be specified as an ISO8601 date-time (e.g. 2022-06-30T12:00)." 284 | schema: 285 | type: string 286 | format: date-time 287 | - name: end_hour 288 | in: query 289 | description: "The end hour for the time interval to get hourly weather data. Time must be specified as an ISO8601 date-time (e.g. 2022-06-30T12:00)." 290 | schema: 291 | type: string 292 | format: date-time 293 | - name: start_minutely_15 294 | in: query 295 | description: "The start 15-minute interval for the time interval to get 15-minutely weather data. Time must be specified as an ISO8601 date-time (e.g. 2022-06-30T12:00)." 296 | schema: 297 | type: string 298 | format: date-time 299 | - name: end_minutely_15 300 | in: query 301 | description: "The end 15-minute interval for the time interval to get 15-minutely weather data. Time must be specified as an ISO8601 date-time (e.g. 2022-06-30T12:00)." 302 | schema: 303 | type: string 304 | format: date-time 305 | - name: models 306 | in: query 307 | description: "Manually select one or more weather models. Per default, the best suitable weather models will be combined." 308 | schema: 309 | type: array 310 | items: 311 | type: string 312 | default: ["auto"] 313 | - name: cell_selection 314 | in: query 315 | description: "Set a preference how grid-cells are selected. The default land finds a suitable grid-cell on land with similar elevation to the requested coordinates using a 90-meter digital elevation model. sea prefers grid-cells on sea. nearest selects the nearest possible grid-cell." 316 | schema: 317 | type: string 318 | default: land 319 | enum: 320 | - land 321 | - sea 322 | - nearest 323 | - name: apikey 324 | in: query 325 | description: "Only required for commercial use to access reserved API resources for customers. The server URL requires the prefix customer-." 326 | schema: 327 | type: string 328 | responses: 329 | 200: 330 | description: OK 331 | content: 332 | application/json: 333 | schema: 334 | type: object 335 | properties: 336 | latitude: 337 | type: number 338 | example: 52.52 339 | description: WGS84 of the center of the weather grid-cell which was used to generate this forecast. This coordinate might be a few kilometers away from the requested coordinate. 340 | longitude: 341 | type: number 342 | example: 13.419 343 | description: WGS84 of the center of the weather grid-cell which was used to generate this forecast. This coordinate might be a few kilometers away from the requested coordinate. 344 | elevation: 345 | type: number 346 | example: 44.812 347 | description: The elevation from a 90 meter digital elevation model. This affects which grid-cell is selected. Statistical downscaling is used to adapt weather conditions for this elevation. 348 | generationtime_ms: 349 | type: number 350 | example: 2.2119 351 | description: Generation time of the weather forecast in milliseconds. This is mainly used for performance monitoring and improvements. 352 | utc_offset_seconds: 353 | type: integer 354 | example: 0 355 | description: Applied timezone offset from the &timezone= parameter. 356 | timezone: 357 | type: string 358 | example: "Europe/Berlin" 359 | description: Timezone identifier (e.g. Europe/Berlin) 360 | timezone_abbreviation: 361 | type: string 362 | example: "CEST" 363 | description: Timezone abbreviation (e.g. CEST) 364 | hourly: 365 | $ref: '#/components/schemas/HourlyResponse' 366 | hourly_units: 367 | type: object 368 | additionalProperties: 369 | type: string 370 | description: For each selected weather variable, the unit will be listed here. 371 | example: 372 | temperature_2m: "°C" 373 | daily: 374 | $ref: '#/components/schemas/DailyResponse' 375 | daily_units: 376 | type: object 377 | additionalProperties: 378 | type: string 379 | description: For each selected daily weather variable, the unit will be listed here. 380 | example: 381 | temperature_2m_max: "°C" 382 | current_weather: 383 | $ref: '#/components/schemas/CurrentWeather' 384 | 400: 385 | description: Bad Request 386 | content: 387 | application/json: 388 | schema: 389 | type: object 390 | properties: 391 | error: 392 | type: boolean 393 | description: Always set true for errors 394 | reason: 395 | type: string 396 | description: Description of the error 397 | example: "Latitude must be in range of -90 to 90°. Given: 300" 398 | components: 399 | schemas: 400 | HourlyResponse: 401 | type: object 402 | required: 403 | - time 404 | properties: 405 | time: 406 | type: array 407 | items: 408 | type: string 409 | description: "Array of ISO8601 timestamps" 410 | example: ["2022-07-01T00:00", "2022-07-01T01:00", "2022-07-01T02:00"] 411 | temperature_2m: 412 | type: array 413 | items: 414 | type: number 415 | description: "Air temperature at 2 meters above ground" 416 | relative_humidity_2m: 417 | type: array 418 | items: 419 | type: number 420 | description: "Relative humidity at 2 meters above ground" 421 | dew_point_2m: 422 | type: array 423 | items: 424 | type: number 425 | description: "Dew point temperature at 2 meters above ground" 426 | apparent_temperature: 427 | type: array 428 | items: 429 | type: number 430 | description: "Apparent temperature is the perceived feels-like temperature combining wind chill factor, relative humidity and solar radiation" 431 | pressure_msl: 432 | type: array 433 | items: 434 | type: number 435 | description: "Atmospheric air pressure reduced to mean sea level (msl)" 436 | surface_pressure: 437 | type: array 438 | items: 439 | type: number 440 | description: "Pressure at surface" 441 | cloud_cover: 442 | type: array 443 | items: 444 | type: number 445 | description: "Total cloud cover as an area fraction" 446 | cloud_cover_low: 447 | type: array 448 | items: 449 | type: number 450 | description: "Low level clouds and fog up to 3 km altitude" 451 | cloud_cover_mid: 452 | type: array 453 | items: 454 | type: number 455 | description: "Mid level clouds from 3 to 8 km altitude" 456 | cloud_cover_high: 457 | type: array 458 | items: 459 | type: number 460 | description: "High level clouds from 8 km altitude" 461 | wind_speed_10m: 462 | type: array 463 | items: 464 | type: number 465 | description: "Wind speed at 10 meters above ground" 466 | wind_speed_80m: 467 | type: array 468 | items: 469 | type: number 470 | description: "Wind speed at 80 meters above ground" 471 | wind_speed_120m: 472 | type: array 473 | items: 474 | type: number 475 | description: "Wind speed at 120 meters above ground" 476 | wind_speed_180m: 477 | type: array 478 | items: 479 | type: number 480 | description: "Wind speed at 180 meters above ground" 481 | wind_direction_10m: 482 | type: array 483 | items: 484 | type: number 485 | description: "Wind direction at 10 meters above ground" 486 | wind_direction_80m: 487 | type: array 488 | items: 489 | type: number 490 | description: "Wind direction at 80 meters above ground" 491 | wind_direction_120m: 492 | type: array 493 | items: 494 | type: number 495 | description: "Wind direction at 120 meters above ground" 496 | wind_direction_180m: 497 | type: array 498 | items: 499 | type: number 500 | description: "Wind direction at 180 meters above ground" 501 | wind_gusts_10m: 502 | type: array 503 | items: 504 | type: number 505 | description: "Gusts at 10 meters above ground as a maximum of the preceding hour" 506 | shortwave_radiation: 507 | type: array 508 | items: 509 | type: number 510 | description: "Shortwave solar radiation as average of the preceding hour" 511 | direct_radiation: 512 | type: array 513 | items: 514 | type: number 515 | description: "Direct solar radiation as average of the preceding hour on the horizontal plane" 516 | direct_normal_irradiance: 517 | type: array 518 | items: 519 | type: number 520 | description: "Direct solar radiation as average of the preceding hour on the normal plane (perpendicular to the sun)" 521 | diffuse_radiation: 522 | type: array 523 | items: 524 | type: number 525 | description: "Diffuse solar radiation as average of the preceding hour" 526 | global_tilted_irradiance: 527 | type: array 528 | items: 529 | type: number 530 | description: "Total radiation received on a tilted pane as average of the preceding hour" 531 | vapour_pressure_deficit: 532 | type: array 533 | items: 534 | type: number 535 | description: "Vapour Pressure Deficit (VPD) in kilopascal (kPa)" 536 | cape: 537 | type: array 538 | items: 539 | type: number 540 | description: "Convective available potential energy" 541 | evapotranspiration: 542 | type: array 543 | items: 544 | type: number 545 | description: "Evapotranspration from land surface and plants" 546 | et0_fao_evapotranspiration: 547 | type: array 548 | items: 549 | type: number 550 | description: "ET₀ Reference Evapotranspiration of a well watered grass field" 551 | precipitation: 552 | type: array 553 | items: 554 | type: number 555 | description: "Total precipitation (rain, showers, snow) sum of the preceding hour" 556 | snowfall: 557 | type: array 558 | items: 559 | type: number 560 | description: "Snowfall amount of the preceding hour in centimeters" 561 | precipitation_probability: 562 | type: array 563 | items: 564 | type: number 565 | description: "Probability of precipitation with more than 0.1 mm of the preceding hour" 566 | rain: 567 | type: array 568 | items: 569 | type: number 570 | description: "Rain from large scale weather systems of the preceding hour" 571 | showers: 572 | type: array 573 | items: 574 | type: number 575 | description: "Showers from convective precipitation in the preceding hour" 576 | weather_code: 577 | type: array 578 | items: 579 | type: number 580 | description: "Weather condition as a numeric code. Follow WMO weather interpretation codes." 581 | snow_depth: 582 | type: array 583 | items: 584 | type: number 585 | description: "Snow depth on the ground" 586 | freezing_level_height: 587 | type: array 588 | items: 589 | type: number 590 | description: "Altitude above sea level of the 0°C level" 591 | visibility: 592 | type: array 593 | items: 594 | type: number 595 | description: "Viewing distance in meters" 596 | soil_temperature_0cm: 597 | type: array 598 | items: 599 | type: number 600 | description: "Temperature in the soil at 0 cm depth (surface temperature)" 601 | soil_temperature_6cm: 602 | type: array 603 | items: 604 | type: number 605 | description: "Temperature in the soil at 6 cm depth" 606 | soil_temperature_18cm: 607 | type: array 608 | items: 609 | type: number 610 | description: "Temperature in the soil at 18 cm depth" 611 | soil_temperature_54cm: 612 | type: array 613 | items: 614 | type: number 615 | description: "Temperature in the soil at 54 cm depth" 616 | soil_moisture_0_to_1cm: 617 | type: array 618 | items: 619 | type: number 620 | description: "Average soil water content as volumetric mixing ratio at 0-1 cm depth" 621 | soil_moisture_1_to_3cm: 622 | type: array 623 | items: 624 | type: number 625 | description: "Average soil water content as volumetric mixing ratio at 1-3 cm depth" 626 | soil_moisture_3_to_9cm: 627 | type: array 628 | items: 629 | type: number 630 | description: "Average soil water content as volumetric mixing ratio at 3-9 cm depth" 631 | soil_moisture_9_to_27cm: 632 | type: array 633 | items: 634 | type: number 635 | description: "Average soil water content as volumetric mixing ratio at 9-27 cm depth" 636 | soil_moisture_27_to_81cm: 637 | type: array 638 | items: 639 | type: number 640 | description: "Average soil water content as volumetric mixing ratio at 27-81 cm depth" 641 | is_day: 642 | type: array 643 | items: 644 | type: integer 645 | description: "1 if the current time step has daylight, 0 at night" 646 | DailyResponse: 647 | type: object 648 | required: 649 | - time 650 | properties: 651 | time: 652 | type: array 653 | items: 654 | type: string 655 | description: "Array of ISO8601 dates" 656 | example: ["2022-07-01", "2022-07-02", "2022-07-03"] 657 | temperature_2m_max: 658 | type: array 659 | items: 660 | type: number 661 | description: "Maximum daily air temperature at 2 meters above ground" 662 | temperature_2m_min: 663 | type: array 664 | items: 665 | type: number 666 | description: "Minimum daily air temperature at 2 meters above ground" 667 | apparent_temperature_max: 668 | type: array 669 | items: 670 | type: number 671 | description: "Maximum daily apparent temperature" 672 | apparent_temperature_min: 673 | type: array 674 | items: 675 | type: number 676 | description: "Minimum daily apparent temperature" 677 | precipitation_sum: 678 | type: array 679 | items: 680 | type: number 681 | description: "Sum of daily precipitation (including rain, showers and snowfall)" 682 | rain_sum: 683 | type: array 684 | items: 685 | type: number 686 | description: "Sum of daily rain" 687 | showers_sum: 688 | type: array 689 | items: 690 | type: number 691 | description: "Sum of daily showers" 692 | snowfall_sum: 693 | type: array 694 | items: 695 | type: number 696 | description: "Sum of daily snowfall" 697 | precipitation_hours: 698 | type: array 699 | items: 700 | type: number 701 | description: "The number of hours with rain" 702 | precipitation_probability_max: 703 | type: array 704 | items: 705 | type: number 706 | description: "Maximum probability of precipitation during the day" 707 | precipitation_probability_min: 708 | type: array 709 | items: 710 | type: number 711 | description: "Minimum probability of precipitation during the day" 712 | precipitation_probability_mean: 713 | type: array 714 | items: 715 | type: number 716 | description: "Mean probability of precipitation during the day" 717 | weather_code: 718 | type: array 719 | items: 720 | type: number 721 | description: "The most severe weather condition on a given day" 722 | sunrise: 723 | type: array 724 | items: 725 | type: string 726 | description: "Sun rise time" 727 | sunset: 728 | type: array 729 | items: 730 | type: string 731 | description: "Sun set time" 732 | sunshine_duration: 733 | type: array 734 | items: 735 | type: number 736 | description: "The number of seconds of sunshine per day" 737 | daylight_duration: 738 | type: array 739 | items: 740 | type: number 741 | description: "Number of seconds of daylight per day" 742 | wind_speed_10m_max: 743 | type: array 744 | items: 745 | type: number 746 | description: "Maximum wind speed on a day" 747 | wind_gusts_10m_max: 748 | type: array 749 | items: 750 | type: number 751 | description: "Maximum wind gusts on a day" 752 | wind_direction_10m_dominant: 753 | type: array 754 | items: 755 | type: number 756 | description: "Dominant wind direction" 757 | shortwave_radiation_sum: 758 | type: array 759 | items: 760 | type: number 761 | description: "The sum of solar radiation on a given day in Megajoules" 762 | et0_fao_evapotranspiration: 763 | type: array 764 | items: 765 | type: number 766 | description: "Daily sum of ET₀ Reference Evapotranspiration of a well watered grass field" 767 | uv_index_max: 768 | type: array 769 | items: 770 | type: number 771 | description: "Daily maximum in UV Index" 772 | uv_index_clear_sky_max: 773 | type: array 774 | items: 775 | type: number 776 | description: "Daily maximum in UV Index assuming cloud free conditions" 777 | CurrentWeather: 778 | type: object 779 | required: 780 | - time 781 | - temperature 782 | - wind_speed 783 | - wind_direction 784 | - weather_code 785 | properties: 786 | time: 787 | type: string 788 | description: "ISO8601 timestamp" 789 | example: "2022-07-01T09:00" 790 | temperature: 791 | type: number 792 | description: "Current temperature" 793 | example: 12.3 794 | wind_speed: 795 | type: number 796 | description: "Current wind speed" 797 | example: 10.5 798 | wind_direction: 799 | type: number 800 | description: "Current wind direction in degrees" 801 | example: 180 802 | weather_code: 803 | type: number 804 | description: "Current weather condition as a WMO code" 805 | example: 3 -------------------------------------------------------------------------------- /lovelaice/api.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | from .core import Agent 3 | from .connectors import OpenAILLM 4 | from .config import LovelaiceConfig 5 | from .tools import * 6 | import uvicorn 7 | 8 | app = FastAPI(title="Lovelaice") 9 | 10 | config = LovelaiceConfig.load() 11 | llm = OpenAILLM(config.model, config.api_key, config.base_url) 12 | agent: Agent = Agent(llm, tools=[Bash(), Chat(), Interpreter(), Codegen()]) 13 | 14 | 15 | @app.post("/complete/") 16 | async def chat(prompt): 17 | completion = await llm.complete(prompt, max_tokens=config.max_tokens) 18 | return dict(completion=prompt + completion) 19 | 20 | 21 | def run_api(debug, host, port): 22 | return uvicorn.run("lovelaice.api:app", host=host, port=port, reload=debug) 23 | -------------------------------------------------------------------------------- /lovelaice/cli.py: -------------------------------------------------------------------------------- 1 | import os 2 | import dotenv 3 | import asyncio 4 | import argparse 5 | from pydantic import BaseModel 6 | from rich.prompt import Prompt, Confirm 7 | from rich import print 8 | from .core import Agent 9 | from .connectors import LLM 10 | from .tools import Bash, Chat, Codegen, Interpreter, Weather 11 | from .config import LovelaiceConfig 12 | 13 | 14 | def run(): 15 | dotenv.load_dotenv() 16 | config = LovelaiceConfig.load() 17 | 18 | parser = argparse.ArgumentParser("lovelaice", usage="lovelaice [options] query ...") 19 | parser.add_argument("--version", action="store_true", help="Print version and exit") 20 | parser.add_argument( 21 | "--config", action="store_true", help="Run configuration and exit" 22 | ) 23 | parser.add_argument( 24 | "-c", 25 | "--complete", 26 | action="store_true", 27 | help="Instead of full chat interaction, simply run completion on the input prompt.", 28 | default=False, 29 | ) 30 | parser.add_argument( 31 | "-cf", "--complete-files", 32 | action="store", 33 | nargs="*", 34 | help="Similar to completion mode, but instead CLI, it will read these files and replace all instances of `+++` with a completion, using the previous content as prompt.", 35 | metavar="FILE", 36 | default=None, 37 | ) 38 | parser.add_argument( 39 | "-w", "--watch", 40 | action="store_true", 41 | help="Used only with --complete-files, keep watching for file changes until stopped with Ctrl+C.", 42 | default=None, 43 | ) 44 | parser.add_argument( 45 | "-f", "--file", action="store", help="Add a file to the context" 46 | ) 47 | parser.add_argument( 48 | "-a", "--audio", action="store", help="Add an audio file to the context" 49 | ) 50 | 51 | parser.add_argument("--api", action="store_true", help="Run an HTTP server instead of CLI.", default=False) 52 | parser.add_argument("--host", action="store", help="Host to bind the API.", default="127.0.0.1") 53 | parser.add_argument("--port", action="store", type=int, help="Port to bind the API.", default=8000) 54 | parser.add_argument("--debug", action="store_true", help="Runs in debug mode, e.g. more verbose.", default=False) 55 | parser.add_argument("query", nargs="*", default=None) 56 | 57 | args = parser.parse_args() 58 | 59 | if args.version: 60 | from lovelaice import VERSION 61 | print(f"version={VERSION}") 62 | return 63 | 64 | if args.config: 65 | configure(config) 66 | return 67 | 68 | llm = LLM(config) 69 | 70 | if args.complete: 71 | asyncio.run(complete(args, config, llm)) 72 | return 73 | 74 | if args.complete_files: 75 | asyncio.run(complete_files(args, config, llm)) 76 | return 77 | 78 | agent = Agent( 79 | llm, 80 | tools=[Bash(), Chat(), Interpreter(), Codegen(), Weather()], 81 | ) 82 | 83 | if args.api: 84 | try: 85 | from .api import run_api 86 | run_api(debug=args.debug, host=args.host, port=args.port) 87 | except ImportError: 88 | print("[red]ERROR[white]: To run the API you need to install lovelaice with the `api` extra.") 89 | 90 | return 91 | 92 | if args.query: 93 | asyncio.run(run_once(args, config, agent)) 94 | else: 95 | asyncio.run(run_forever(args, config, agent)) 96 | 97 | 98 | def _build_config(model: type[BaseModel], old_config, indent=0): 99 | new_config = {} 100 | 101 | for field, info in model.model_fields.items(): 102 | if isinstance(info.annotation, type) and issubclass(info.annotation, BaseModel): 103 | print(f"[purple]{indent * " "}{field}[/purple]: {info.description}\n") 104 | value = _build_config(info.annotation, old_config.get(field, {}), indent+1) 105 | else: 106 | print(f"[yellow]{indent * " "}{info.description}[/yellow]") 107 | value = Prompt.ask(indent * " " + field, default=str(old_config[field])) 108 | print() 109 | 110 | if value is not None: 111 | new_config[field] = value 112 | 113 | return new_config 114 | 115 | 116 | def configure(config: LovelaiceConfig): 117 | old_config = config.model_dump(mode="json") 118 | new_config = _build_config(LovelaiceConfig, old_config) 119 | 120 | new_config = LovelaiceConfig(**new_config) 121 | print(new_config.model_dump(mode="json")) 122 | 123 | if Confirm.ask("Are you happy with this configuration?"): 124 | new_config.save() 125 | 126 | 127 | async def complete(args, config: LovelaiceConfig, llm: LLM): 128 | prompt = " ".join(args.query) 129 | 130 | print(prompt, end="", flush=True) 131 | 132 | while True: 133 | generated = False 134 | 135 | async for chunk in llm.complete_stream(prompt, max_tokens=config.max_tokens): 136 | prompt += chunk 137 | print(chunk, end="", flush=True) 138 | 139 | if chunk: 140 | generated = True 141 | 142 | if not generated or len(prompt.split()) > config.min_words: 143 | break 144 | 145 | print() 146 | 147 | 148 | async def _detect_file_changes(file, interval=1): 149 | last_modified = os.path.getmtime(file) 150 | 151 | while True: 152 | current_modified = os.path.getmtime(file) 153 | 154 | if current_modified != last_modified: 155 | return 156 | 157 | await asyncio.sleep(interval) 158 | 159 | 160 | async def complete_files(args, config, llm: LLM): 161 | for file in args.complete_files: 162 | await _complete_file(file, args, llm) 163 | 164 | 165 | async def _complete_file(file, args, config: LovelaiceConfig, llm: LLM): 166 | while True: 167 | prompt = [] 168 | complete = False 169 | 170 | with open(file) as fp: 171 | for line in fp: 172 | if line.strip().endswith("+++"): 173 | if line.strip() != "+++": 174 | prompt.append(line.replace("+++", "")) 175 | complete = True 176 | break 177 | else: 178 | prompt.append(line) 179 | 180 | prompt = "\n".join(prompt) 181 | 182 | if prompt and complete: 183 | print(f"Running completion on {file}...") 184 | response = await llm.complete(prompt, max_tokens=config.max_tokens) 185 | print(f"Done with completion on {file}.") 186 | 187 | lines = open(file).readlines() 188 | 189 | with open(file, "w") as fp: 190 | for line in lines: 191 | if "+++" in line: 192 | line = line.replace("+++", response) 193 | 194 | fp.write(line) 195 | else: 196 | print(f"Nothing to do in {file}.") 197 | 198 | if args.watch: 199 | print(f"Waiting for changes on {file}.") 200 | await _detect_file_changes(file) 201 | else: 202 | return 203 | 204 | 205 | async def run_once(args, config: LovelaiceConfig, agent: Agent): 206 | prompt = " ".join(args.query) 207 | transcription = "" 208 | 209 | if args.audio: 210 | with open(args.audio, 'rb') as fp: 211 | transcription = await agent.client.transcribe(fp) 212 | 213 | prompt = "\n\n".join([transcription, prompt]) 214 | 215 | async for response in agent.query(prompt, max_tokens=config.max_tokens): 216 | print(response, end="", flush=True) 217 | 218 | print() 219 | 220 | 221 | async def run_forever(args, config: LovelaiceConfig, agent: Agent): 222 | while True: 223 | try: 224 | prompt = input("> ") 225 | 226 | try: 227 | async for response in agent.query(prompt, max_tokens=config.max_tokens): 228 | print(response, end="", flush=True) 229 | except asyncio.exceptions.CancelledError: 230 | print("(!) Cancelled") 231 | 232 | print("\n") 233 | except KeyboardInterrupt: 234 | break 235 | except EOFError: 236 | break 237 | -------------------------------------------------------------------------------- /lovelaice/config.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, AnyUrl, Field 2 | import yaml 3 | import pathlib 4 | 5 | 6 | class ModelConfig(BaseModel): 7 | base_url: str = Field(default="", description="The API base URL (in case you're not using OpenAI)") 8 | api_key: str = Field(default="", description="The API key to authenticate with the LLM provider") 9 | model: str = Field(default="", description="The concrete LLM model to use") 10 | 11 | 12 | class LovelaiceConfig(BaseModel): 13 | chat_model: ModelConfig = Field(default_factory=ModelConfig, description="Configuration for the default chat model.") 14 | audio_model: ModelConfig = Field(default_factory=ModelConfig, description="Configuration for the audio model.") 15 | code_model: ModelConfig = Field(default_factory=ModelConfig, description="Configuration for the code model.") 16 | max_tokens: int = Field(2048, description="Max number of tokens to generate in a single prompt") 17 | min_words: int = Field(0, description="For completion only, min number of words to generate") 18 | 19 | @classmethod 20 | def load(cls, root_path: pathlib.Path = pathlib.Path(".")): 21 | root_path = root_path.absolute() 22 | 23 | if not root_path.is_dir(): 24 | raise ValueError('The root path must a directory.') 25 | 26 | matches: list[pathlib.Path] = [] 27 | 28 | while True: 29 | if (root_path / ".lovelaice.yml").exists(): 30 | matches.append(root_path / ".lovelaice.yml") 31 | 32 | if root_path.parent != root_path: 33 | root_path = root_path.parent 34 | else: 35 | break 36 | 37 | config = {} 38 | 39 | while matches: 40 | path = matches.pop() 41 | 42 | with path.open() as fp: 43 | config.update(yaml.safe_load(fp)) 44 | 45 | return LovelaiceConfig(**config) 46 | 47 | 48 | def save(self, root_path: pathlib.Path = pathlib.Path(".")): 49 | root_path = root_path.absolute() 50 | 51 | if not root_path.is_dir(): 52 | raise ValueError('The root path must a directory.') 53 | 54 | with open(root_path / ".lovelaice.yml", "w") as fp: 55 | yaml.dump(self.model_dump(mode="json"), fp) 56 | -------------------------------------------------------------------------------- /lovelaice/connectors.py: -------------------------------------------------------------------------------- 1 | import abc 2 | from openai import AsyncOpenAI 3 | from openai.types.chat import ChatCompletionChunk 4 | from openai.types.completion import Completion 5 | 6 | from .config import LovelaiceConfig 7 | from .models import Message 8 | 9 | 10 | class LLM(abc.ABC): 11 | def __init__(self, config: LovelaiceConfig) -> None: 12 | self.config = config 13 | 14 | async def chat(self, messages: list[Message], **kwargs): 15 | result = [] 16 | 17 | async for chunk in self.chat_stream(messages, **kwargs): 18 | result.append(chunk) 19 | 20 | return "".join(result) 21 | 22 | async def complete(self, prompt: str, **kwargs): 23 | result = [] 24 | 25 | async for chunk in self.complete_stream(prompt, **kwargs): 26 | result.append(chunk) 27 | 28 | return "".join(result) 29 | 30 | async def chat_stream(self, messages: list[Message], **kwargs): 31 | client = AsyncOpenAI(api_key=self.config.chat_model.api_key, base_url=self.config.chat_model.base_url) 32 | model = self.config.chat_model.model 33 | 34 | stream = await client.chat.completions.create( 35 | messages=[dict(role=m.role, content=m.content) for m in messages], 36 | model=model, 37 | stream=True, 38 | **kwargs, 39 | ) 40 | 41 | async for response in stream: 42 | r: ChatCompletionChunk = response 43 | yield r.choices[0].delta.content or "" 44 | 45 | async def complete_stream(self, prompt: str, **kwargs): 46 | client = AsyncOpenAI(api_key=self.config.chat_model.api_key, base_url=self.config.chat_model.base_url) 47 | model = self.config.chat_model.model 48 | 49 | stream = await client.completions.create( 50 | model=model, prompt=prompt, stream=True, **kwargs 51 | ) 52 | 53 | async for chunk in stream: 54 | r: Completion = chunk 55 | yield r.choices[0].text or "" 56 | 57 | async def transcribe(self, file, **kwargs): 58 | client = AsyncOpenAI(api_key=self.config.audio_model.api_key, base_url=self.config.audio_model.base_url) 59 | model = self.config.audio_model.model 60 | 61 | response = await client.audio.transcriptions.create(file=file, model=model, **kwargs) 62 | return response 63 | -------------------------------------------------------------------------------- /lovelaice/core.py: -------------------------------------------------------------------------------- 1 | from .connectors import LLM 2 | from .models import Message 3 | from .tools import Chat, Tool 4 | 5 | 6 | SYSTEM_PROMPT = """ 7 | You are Lovelaice, a helpful AI agent that runs in the 8 | user terminal. You can do many things, from casual chat 9 | to helping with concrete tasks that require access to the user filesystem. 10 | You can run programs at the request of the user, and write 11 | code for them. 12 | You have access to the Internet and can answer queries that 13 | require searching online. 14 | """ 15 | 16 | TOOLS_PROMPT = """ 17 | These are some of the tools you have access to: 18 | 19 | {tools} 20 | 21 | According to the following query, reply only with the name of the tool that 22 | is most appropriate to solve the problem. Do not reply anything else. 23 | 24 | Query: {query} 25 | Tool: 26 | """ 27 | 28 | 29 | class Agent: 30 | def __init__(self, client: LLM, tools: list[Tool]) -> None: 31 | self.client = client 32 | self.tools = tools 33 | self.tools_dir = {t.name: t for t in tools} 34 | self.tools_line = "\n".join(t.describe() for t in tools) 35 | self.history = [] 36 | 37 | async def query( 38 | self, 39 | prompt: str, 40 | use_tool=None, 41 | **kwargs, 42 | ): 43 | if use_tool is None: 44 | messages = [ 45 | Message(role="system", content=SYSTEM_PROMPT), 46 | Message( 47 | role="user", 48 | content=TOOLS_PROMPT.format(query=prompt, tools=self.tools_line), 49 | ), 50 | ] 51 | 52 | tool_name = await self.client.chat(messages, **kwargs) 53 | tool_name = tool_name.split()[0].strip(",.:") 54 | 55 | async for response in self.query(prompt, use_tool=tool_name, **kwargs): 56 | yield response 57 | 58 | else: 59 | if use_tool not in self.tools_dir: 60 | tool: Tool = Chat() 61 | else: 62 | tool: Tool = self.tools_dir[use_tool] 63 | 64 | if tool.name != "Chat": 65 | yield f":: Using {tool.name}\n\n" 66 | 67 | messages = [Message(role="user", content=tool.prompt(prompt))] 68 | 69 | if tool.skip_use: 70 | async for response in self.client.chat_stream(messages, **kwargs): 71 | yield response 72 | 73 | else: 74 | response = await self.client.chat(messages, **kwargs) 75 | output = [] 76 | 77 | for line in tool.use(prompt, response): 78 | output.append(line) 79 | yield line 80 | 81 | output = "\n".join(output) 82 | conclusion = tool.conclude(prompt, output) 83 | 84 | if conclusion is None: 85 | return 86 | 87 | messages = [Message(role="user", content=conclusion)] 88 | 89 | yield "\n" 90 | 91 | async for response in self.client.chat_stream(messages, **kwargs): 92 | yield response 93 | -------------------------------------------------------------------------------- /lovelaice/models.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class Message(BaseModel): 5 | role:str 6 | content:str 7 | -------------------------------------------------------------------------------- /lovelaice/tools.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import importlib 3 | import requests 4 | from pathlib import Path 5 | 6 | 7 | class Tool: 8 | skip_use = False 9 | 10 | @property 11 | def name(self) -> str: 12 | return self.__class__.__name__ 13 | 14 | @property 15 | def description(self) -> str: 16 | return self.__class__.__doc__ 17 | 18 | def describe(self) -> str: 19 | return f"- {self.name}: {self.description}." 20 | 21 | def prompt(self, query) -> str: 22 | return query 23 | 24 | def use(self, query, response): 25 | pass 26 | 27 | def conclude(self, query, output): 28 | pass 29 | 30 | 31 | class Chat(Tool): 32 | """ 33 | When the user engages in general-purpose or casual conversation. 34 | """ 35 | 36 | def __init__(self) -> None: 37 | self.skip_use = True 38 | 39 | 40 | class Bash(Tool): 41 | """ 42 | When the user requests some action in the filesystem or terminal, 43 | including git commands, or installing new applications or packages. 44 | """ 45 | 46 | def prompt(self, query) -> str: 47 | return f""" 48 | Given the following user query, generate a single bash command line 49 | that performs the indicated functionality. 50 | 51 | Reply only with the corresponding bash line. 52 | Do not add any explanation. 53 | 54 | Query: {query} 55 | Command: 56 | """ 57 | 58 | def use(self, query, response): 59 | response = response.strip("`") 60 | 61 | if response.startswith("bash"): 62 | response = response[4:] 63 | 64 | response = response.split("`")[0] 65 | response = [s.strip() for s in response.split("\n")] 66 | response = [s for s in response if s] 67 | 68 | response = ";".join(s for s in response) 69 | 70 | yield "Running the following code:\n" 71 | yield "$ " 72 | yield response 73 | yes = input("\n[y]es / [N]o ") 74 | 75 | if yes != "y": 76 | yield "(!) Operation cancelled by your request.\n" 77 | return 78 | 79 | yield "\n" 80 | 81 | p = subprocess.run(response, shell=True, stdout=subprocess.PIPE) 82 | yield p.stdout.decode("utf8") 83 | 84 | def conclude(self, query, output): 85 | return f""" 86 | The user issued the following query: 87 | 88 | Query: {query} 89 | 90 | Given that query, you ran the following command which 91 | produced the given output: 92 | 93 | --- 94 | {output} 95 | --- 96 | 97 | If the user query is a question, answer it as succintly 98 | as possible given the output. 99 | 100 | If the user query was a request to do something, 101 | explain briefly the result of the operation. 102 | """ 103 | 104 | 105 | class Interpreter(Tool): 106 | """ 107 | When the user asks a mathematical question that can 108 | be solved with a simple Python function. 109 | """ 110 | 111 | def prompt(self, query) -> str: 112 | return f""" 113 | Given the following user query, 114 | generate a single Python function named `solve` 115 | and the necessary import statements 116 | to perform the indicated functionality. 117 | 118 | If you need secondary functions, name them starting with `_`. 119 | 120 | Enclose the code in ```python and ``` 121 | 122 | Reply only with the corresponding Python code. 123 | Do not add any explanation. 124 | Do not execute the function. 125 | Do not add any print statements. 126 | 127 | Query: {query} 128 | Function definition: 129 | """ 130 | 131 | def use(self, query, response): 132 | code = [] 133 | imports = [] 134 | inside = False 135 | 136 | for line in response.split("\n"): 137 | if line.startswith("```python"): 138 | inside = True 139 | elif line.startswith("```"): 140 | inside = False 141 | elif inside: 142 | if line.startswith("import"): 143 | imports.append(line.split()[1]) 144 | else: 145 | code.append(line) 146 | 147 | code.append("\nresult = solve()") 148 | code = "\n".join(code).strip() 149 | 150 | yield "Will run the following code:\n\n" 151 | yield code 152 | yes = input("\n\n[y]es / [N]o ") 153 | 154 | if yes != "y": 155 | yield "(!) Operation cancelled by your request.\n" 156 | return 157 | 158 | globals = {module: importlib.import_module(module) for module in imports} 159 | locals = {} 160 | exec(code, globals, locals) 161 | result = locals["result"] 162 | 163 | yield f"\nResult: {result}" 164 | 165 | 166 | class Codegen(Tool): 167 | """ 168 | When the user makes a general question about programming or 169 | explicitly asks to generate code in a given programming language. 170 | """ 171 | 172 | def __init__(self) -> None: 173 | self.skip_use = True 174 | 175 | def prompt(self, query) -> str: 176 | return f""" 177 | Answer the following user query about programming with 178 | a general explanation in broad terms, followed by 179 | one or more examples of code, as necessary. 180 | 181 | Enclose all code examples in ``` with the corresponding 182 | programming language identifier. 183 | 184 | Query: {query} 185 | """ 186 | 187 | class Weather(Tool): 188 | """ 189 | When the user asks for the weather. 190 | """ 191 | 192 | def prompt(self, query) -> str: 193 | yaml_content = importlib.resources.files('lovelaice').joinpath('api.open-meteo.yml').read_text() 194 | return f""" 195 | You're a helpful weather assistant. I want to retrieve the weather for a user query using this OpenAPI schema: 196 | ```yaml 197 | {yaml_content} 198 | ``` 199 | 200 | If the user requests the weather for: 201 | - today, focus in the `current` parameter. 202 | - a specific day, focus in the `hourly` parameter. 203 | - a future day, focus in the `daily` parameter and use `forecast_days` parameter. 204 | - a past day, focus in the `hourly` parameter and use `past_days` parameter. 205 | - a range of days, focus in the `start_date` and `end_date` parameters. 206 | 207 | If the user requests the weather in general, focus in temperature, wind, humidity, precipitation, cloud cover, and weather codes if available. 208 | 209 | Generate the URL to retrieve the weather for the user query using the right parameters. 210 | Do not add any other text than the URL. 211 | 212 | Query: {query} 213 | URL: 214 | """ 215 | 216 | def use(self, query, response): 217 | endpoint = response.split()[1] 218 | yield f"Retrieving weather from {endpoint}\n\n" 219 | 220 | response = requests.get(endpoint) 221 | yield response.text.strip() + "\n" 222 | 223 | def conclude(self, query, output): 224 | return f""" 225 | The user issued the following query: 226 | 227 | Query: {query} 228 | 229 | The weather for the user query is: {output}. Write a short summary of the weather. If the temperature appears in the response, show itin Celsius and Fahrenheit. 230 | """ -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "lovelaice" 3 | version = "0.3.6" 4 | description = "An AI-powered assistant for your terminal and editor." 5 | readme = "Readme.md" 6 | requires-python = ">=3.10" 7 | dependencies = [ 8 | "openai>=1.58.1", 9 | "pydantic>=2.10.4", 10 | "python-dotenv>=1.0.1", 11 | "pyyaml>=6.0.2", 12 | "requests>=2.32.3", 13 | "rich>=13.9.4", 14 | ] 15 | 16 | [project.scripts] 17 | lovelaice = "lovelaice:cli.run" 18 | 19 | [project.optional-dependencies] 20 | api = [ 21 | "fastapi>=0.115.6", 22 | "uvicorn>=0.34.0", 23 | ] 24 | 25 | [build-system] 26 | requires = ["hatchling"] 27 | build-backend = "hatchling.build" 28 | 29 | [dependency-groups] 30 | dev = [ 31 | "black>=24.10.0", 32 | "pytest>=8.3.4", 33 | ] 34 | -------------------------------------------------------------------------------- /uv.lock: -------------------------------------------------------------------------------- 1 | version = 1 2 | revision = 1 3 | requires-python = ">=3.10" 4 | 5 | [[package]] 6 | name = "annotated-types" 7 | version = "0.7.0" 8 | source = { registry = "https://pypi.org/simple" } 9 | sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } 10 | wheels = [ 11 | { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, 12 | ] 13 | 14 | [[package]] 15 | name = "anyio" 16 | version = "4.7.0" 17 | source = { registry = "https://pypi.org/simple" } 18 | dependencies = [ 19 | { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, 20 | { name = "idna" }, 21 | { name = "sniffio" }, 22 | { name = "typing-extensions", marker = "python_full_version < '3.13'" }, 23 | ] 24 | sdist = { url = "https://files.pythonhosted.org/packages/f6/40/318e58f669b1a9e00f5c4453910682e2d9dd594334539c7b7817dabb765f/anyio-4.7.0.tar.gz", hash = "sha256:2f834749c602966b7d456a7567cafcb309f96482b5081d14ac93ccd457f9dd48", size = 177076 } 25 | wheels = [ 26 | { url = "https://files.pythonhosted.org/packages/a0/7a/4daaf3b6c08ad7ceffea4634ec206faeff697526421c20f07628c7372156/anyio-4.7.0-py3-none-any.whl", hash = "sha256:ea60c3723ab42ba6fff7e8ccb0488c898ec538ff4df1f1d5e642c3601d07e352", size = 93052 }, 27 | ] 28 | 29 | [[package]] 30 | name = "black" 31 | version = "24.10.0" 32 | source = { registry = "https://pypi.org/simple" } 33 | dependencies = [ 34 | { name = "click" }, 35 | { name = "mypy-extensions" }, 36 | { name = "packaging" }, 37 | { name = "pathspec" }, 38 | { name = "platformdirs" }, 39 | { name = "tomli", marker = "python_full_version < '3.11'" }, 40 | { name = "typing-extensions", marker = "python_full_version < '3.11'" }, 41 | ] 42 | sdist = { url = "https://files.pythonhosted.org/packages/d8/0d/cc2fb42b8c50d80143221515dd7e4766995bd07c56c9a3ed30baf080b6dc/black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875", size = 645813 } 43 | wheels = [ 44 | { url = "https://files.pythonhosted.org/packages/a3/f3/465c0eb5cddf7dbbfe1fecd9b875d1dcf51b88923cd2c1d7e9ab95c6336b/black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812", size = 1623211 }, 45 | { url = "https://files.pythonhosted.org/packages/df/57/b6d2da7d200773fdfcc224ffb87052cf283cec4d7102fab450b4a05996d8/black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea", size = 1457139 }, 46 | { url = "https://files.pythonhosted.org/packages/6e/c5/9023b7673904a5188f9be81f5e129fff69f51f5515655fbd1d5a4e80a47b/black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f", size = 1753774 }, 47 | { url = "https://files.pythonhosted.org/packages/e1/32/df7f18bd0e724e0d9748829765455d6643ec847b3f87e77456fc99d0edab/black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e", size = 1414209 }, 48 | { url = "https://files.pythonhosted.org/packages/c2/cc/7496bb63a9b06a954d3d0ac9fe7a73f3bf1cd92d7a58877c27f4ad1e9d41/black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad", size = 1607468 }, 49 | { url = "https://files.pythonhosted.org/packages/2b/e3/69a738fb5ba18b5422f50b4f143544c664d7da40f09c13969b2fd52900e0/black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50", size = 1437270 }, 50 | { url = "https://files.pythonhosted.org/packages/c9/9b/2db8045b45844665c720dcfe292fdaf2e49825810c0103e1191515fc101a/black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392", size = 1737061 }, 51 | { url = "https://files.pythonhosted.org/packages/a3/95/17d4a09a5be5f8c65aa4a361444d95edc45def0de887810f508d3f65db7a/black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175", size = 1423293 }, 52 | { url = "https://files.pythonhosted.org/packages/90/04/bf74c71f592bcd761610bbf67e23e6a3cff824780761f536512437f1e655/black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3", size = 1644256 }, 53 | { url = "https://files.pythonhosted.org/packages/4c/ea/a77bab4cf1887f4b2e0bce5516ea0b3ff7d04ba96af21d65024629afedb6/black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65", size = 1448534 }, 54 | { url = "https://files.pythonhosted.org/packages/4e/3e/443ef8bc1fbda78e61f79157f303893f3fddf19ca3c8989b163eb3469a12/black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f", size = 1761892 }, 55 | { url = "https://files.pythonhosted.org/packages/52/93/eac95ff229049a6901bc84fec6908a5124b8a0b7c26ea766b3b8a5debd22/black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8", size = 1434796 }, 56 | { url = "https://files.pythonhosted.org/packages/d0/a0/a993f58d4ecfba035e61fca4e9f64a2ecae838fc9f33ab798c62173ed75c/black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981", size = 1643986 }, 57 | { url = "https://files.pythonhosted.org/packages/37/d5/602d0ef5dfcace3fb4f79c436762f130abd9ee8d950fa2abdbf8bbc555e0/black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b", size = 1448085 }, 58 | { url = "https://files.pythonhosted.org/packages/47/6d/a3a239e938960df1a662b93d6230d4f3e9b4a22982d060fc38c42f45a56b/black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2", size = 1760928 }, 59 | { url = "https://files.pythonhosted.org/packages/dd/cf/af018e13b0eddfb434df4d9cd1b2b7892bab119f7a20123e93f6910982e8/black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b", size = 1436875 }, 60 | { url = "https://files.pythonhosted.org/packages/8d/a7/4b27c50537ebca8bec139b872861f9d2bf501c5ec51fcf897cb924d9e264/black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d", size = 206898 }, 61 | ] 62 | 63 | [[package]] 64 | name = "certifi" 65 | version = "2024.12.14" 66 | source = { registry = "https://pypi.org/simple" } 67 | sdist = { url = "https://files.pythonhosted.org/packages/0f/bd/1d41ee578ce09523c81a15426705dd20969f5abf006d1afe8aeff0dd776a/certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db", size = 166010 } 68 | wheels = [ 69 | { url = "https://files.pythonhosted.org/packages/a5/32/8f6669fc4798494966bf446c8c4a162e0b5d893dff088afddf76414f70e1/certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", size = 164927 }, 70 | ] 71 | 72 | [[package]] 73 | name = "charset-normalizer" 74 | version = "3.4.1" 75 | source = { registry = "https://pypi.org/simple" } 76 | sdist = { url = "https://files.pythonhosted.org/packages/16/b0/572805e227f01586461c80e0fd25d65a2115599cc9dad142fee4b747c357/charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", size = 123188 } 77 | wheels = [ 78 | { url = "https://files.pythonhosted.org/packages/0d/58/5580c1716040bc89206c77d8f74418caf82ce519aae06450393ca73475d1/charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de", size = 198013 }, 79 | { url = "https://files.pythonhosted.org/packages/d0/11/00341177ae71c6f5159a08168bcb98c6e6d196d372c94511f9f6c9afe0c6/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176", size = 141285 }, 80 | { url = "https://files.pythonhosted.org/packages/01/09/11d684ea5819e5a8f5100fb0b38cf8d02b514746607934134d31233e02c8/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037", size = 151449 }, 81 | { url = "https://files.pythonhosted.org/packages/08/06/9f5a12939db324d905dc1f70591ae7d7898d030d7662f0d426e2286f68c9/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f", size = 143892 }, 82 | { url = "https://files.pythonhosted.org/packages/93/62/5e89cdfe04584cb7f4d36003ffa2936681b03ecc0754f8e969c2becb7e24/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a", size = 146123 }, 83 | { url = "https://files.pythonhosted.org/packages/a9/ac/ab729a15c516da2ab70a05f8722ecfccc3f04ed7a18e45c75bbbaa347d61/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a", size = 147943 }, 84 | { url = "https://files.pythonhosted.org/packages/03/d2/3f392f23f042615689456e9a274640c1d2e5dd1d52de36ab8f7955f8f050/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247", size = 142063 }, 85 | { url = "https://files.pythonhosted.org/packages/f2/e3/e20aae5e1039a2cd9b08d9205f52142329f887f8cf70da3650326670bddf/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408", size = 150578 }, 86 | { url = "https://files.pythonhosted.org/packages/8d/af/779ad72a4da0aed925e1139d458adc486e61076d7ecdcc09e610ea8678db/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb", size = 153629 }, 87 | { url = "https://files.pythonhosted.org/packages/c2/b6/7aa450b278e7aa92cf7732140bfd8be21f5f29d5bf334ae987c945276639/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d", size = 150778 }, 88 | { url = "https://files.pythonhosted.org/packages/39/f4/d9f4f712d0951dcbfd42920d3db81b00dd23b6ab520419626f4023334056/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807", size = 146453 }, 89 | { url = "https://files.pythonhosted.org/packages/49/2b/999d0314e4ee0cff3cb83e6bc9aeddd397eeed693edb4facb901eb8fbb69/charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f", size = 95479 }, 90 | { url = "https://files.pythonhosted.org/packages/2d/ce/3cbed41cff67e455a386fb5e5dd8906cdda2ed92fbc6297921f2e4419309/charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f", size = 102790 }, 91 | { url = "https://files.pythonhosted.org/packages/72/80/41ef5d5a7935d2d3a773e3eaebf0a9350542f2cab4eac59a7a4741fbbbbe/charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125", size = 194995 }, 92 | { url = "https://files.pythonhosted.org/packages/7a/28/0b9fefa7b8b080ec492110af6d88aa3dea91c464b17d53474b6e9ba5d2c5/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1", size = 139471 }, 93 | { url = "https://files.pythonhosted.org/packages/71/64/d24ab1a997efb06402e3fc07317e94da358e2585165930d9d59ad45fcae2/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3", size = 149831 }, 94 | { url = "https://files.pythonhosted.org/packages/37/ed/be39e5258e198655240db5e19e0b11379163ad7070962d6b0c87ed2c4d39/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd", size = 142335 }, 95 | { url = "https://files.pythonhosted.org/packages/88/83/489e9504711fa05d8dde1574996408026bdbdbd938f23be67deebb5eca92/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00", size = 143862 }, 96 | { url = "https://files.pythonhosted.org/packages/c6/c7/32da20821cf387b759ad24627a9aca289d2822de929b8a41b6241767b461/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12", size = 145673 }, 97 | { url = "https://files.pythonhosted.org/packages/68/85/f4288e96039abdd5aeb5c546fa20a37b50da71b5cf01e75e87f16cd43304/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77", size = 140211 }, 98 | { url = "https://files.pythonhosted.org/packages/28/a3/a42e70d03cbdabc18997baf4f0227c73591a08041c149e710045c281f97b/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146", size = 148039 }, 99 | { url = "https://files.pythonhosted.org/packages/85/e4/65699e8ab3014ecbe6f5c71d1a55d810fb716bbfd74f6283d5c2aa87febf/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd", size = 151939 }, 100 | { url = "https://files.pythonhosted.org/packages/b1/82/8e9fe624cc5374193de6860aba3ea8070f584c8565ee77c168ec13274bd2/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6", size = 149075 }, 101 | { url = "https://files.pythonhosted.org/packages/3d/7b/82865ba54c765560c8433f65e8acb9217cb839a9e32b42af4aa8e945870f/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8", size = 144340 }, 102 | { url = "https://files.pythonhosted.org/packages/b5/b6/9674a4b7d4d99a0d2df9b215da766ee682718f88055751e1e5e753c82db0/charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b", size = 95205 }, 103 | { url = "https://files.pythonhosted.org/packages/1e/ab/45b180e175de4402dcf7547e4fb617283bae54ce35c27930a6f35b6bef15/charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76", size = 102441 }, 104 | { url = "https://files.pythonhosted.org/packages/0a/9a/dd1e1cdceb841925b7798369a09279bd1cf183cef0f9ddf15a3a6502ee45/charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", size = 196105 }, 105 | { url = "https://files.pythonhosted.org/packages/d3/8c/90bfabf8c4809ecb648f39794cf2a84ff2e7d2a6cf159fe68d9a26160467/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", size = 140404 }, 106 | { url = "https://files.pythonhosted.org/packages/ad/8f/e410d57c721945ea3b4f1a04b74f70ce8fa800d393d72899f0a40526401f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", size = 150423 }, 107 | { url = "https://files.pythonhosted.org/packages/f0/b8/e6825e25deb691ff98cf5c9072ee0605dc2acfca98af70c2d1b1bc75190d/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", size = 143184 }, 108 | { url = "https://files.pythonhosted.org/packages/3e/a2/513f6cbe752421f16d969e32f3583762bfd583848b763913ddab8d9bfd4f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", size = 145268 }, 109 | { url = "https://files.pythonhosted.org/packages/74/94/8a5277664f27c3c438546f3eb53b33f5b19568eb7424736bdc440a88a31f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616", size = 147601 }, 110 | { url = "https://files.pythonhosted.org/packages/7c/5f/6d352c51ee763623a98e31194823518e09bfa48be2a7e8383cf691bbb3d0/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", size = 141098 }, 111 | { url = "https://files.pythonhosted.org/packages/78/d4/f5704cb629ba5ab16d1d3d741396aec6dc3ca2b67757c45b0599bb010478/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", size = 149520 }, 112 | { url = "https://files.pythonhosted.org/packages/c5/96/64120b1d02b81785f222b976c0fb79a35875457fa9bb40827678e54d1bc8/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", size = 152852 }, 113 | { url = "https://files.pythonhosted.org/packages/84/c9/98e3732278a99f47d487fd3468bc60b882920cef29d1fa6ca460a1fdf4e6/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", size = 150488 }, 114 | { url = "https://files.pythonhosted.org/packages/13/0e/9c8d4cb99c98c1007cc11eda969ebfe837bbbd0acdb4736d228ccaabcd22/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", size = 146192 }, 115 | { url = "https://files.pythonhosted.org/packages/b2/21/2b6b5b860781a0b49427309cb8670785aa543fb2178de875b87b9cc97746/charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", size = 95550 }, 116 | { url = "https://files.pythonhosted.org/packages/21/5b/1b390b03b1d16c7e382b561c5329f83cc06623916aab983e8ab9239c7d5c/charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", size = 102785 }, 117 | { url = "https://files.pythonhosted.org/packages/38/94/ce8e6f63d18049672c76d07d119304e1e2d7c6098f0841b51c666e9f44a0/charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", size = 195698 }, 118 | { url = "https://files.pythonhosted.org/packages/24/2e/dfdd9770664aae179a96561cc6952ff08f9a8cd09a908f259a9dfa063568/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", size = 140162 }, 119 | { url = "https://files.pythonhosted.org/packages/24/4e/f646b9093cff8fc86f2d60af2de4dc17c759de9d554f130b140ea4738ca6/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", size = 150263 }, 120 | { url = "https://files.pythonhosted.org/packages/5e/67/2937f8d548c3ef6e2f9aab0f6e21001056f692d43282b165e7c56023e6dd/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", size = 142966 }, 121 | { url = "https://files.pythonhosted.org/packages/52/ed/b7f4f07de100bdb95c1756d3a4d17b90c1a3c53715c1a476f8738058e0fa/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", size = 144992 }, 122 | { url = "https://files.pythonhosted.org/packages/96/2c/d49710a6dbcd3776265f4c923bb73ebe83933dfbaa841c5da850fe0fd20b/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", size = 147162 }, 123 | { url = "https://files.pythonhosted.org/packages/b4/41/35ff1f9a6bd380303dea55e44c4933b4cc3c4850988927d4082ada230273/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", size = 140972 }, 124 | { url = "https://files.pythonhosted.org/packages/fb/43/c6a0b685fe6910d08ba971f62cd9c3e862a85770395ba5d9cad4fede33ab/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", size = 149095 }, 125 | { url = "https://files.pythonhosted.org/packages/4c/ff/a9a504662452e2d2878512115638966e75633519ec11f25fca3d2049a94a/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", size = 152668 }, 126 | { url = "https://files.pythonhosted.org/packages/6c/71/189996b6d9a4b932564701628af5cee6716733e9165af1d5e1b285c530ed/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", size = 150073 }, 127 | { url = "https://files.pythonhosted.org/packages/e4/93/946a86ce20790e11312c87c75ba68d5f6ad2208cfb52b2d6a2c32840d922/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", size = 145732 }, 128 | { url = "https://files.pythonhosted.org/packages/cd/e5/131d2fb1b0dddafc37be4f3a2fa79aa4c037368be9423061dccadfd90091/charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", size = 95391 }, 129 | { url = "https://files.pythonhosted.org/packages/27/f2/4f9a69cc7712b9b5ad8fdb87039fd89abba997ad5cbe690d1835d40405b0/charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", size = 102702 }, 130 | { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767 }, 131 | ] 132 | 133 | [[package]] 134 | name = "click" 135 | version = "8.1.8" 136 | source = { registry = "https://pypi.org/simple" } 137 | dependencies = [ 138 | { name = "colorama", marker = "sys_platform == 'win32'" }, 139 | ] 140 | sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 } 141 | wheels = [ 142 | { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 }, 143 | ] 144 | 145 | [[package]] 146 | name = "colorama" 147 | version = "0.4.6" 148 | source = { registry = "https://pypi.org/simple" } 149 | sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } 150 | wheels = [ 151 | { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, 152 | ] 153 | 154 | [[package]] 155 | name = "distro" 156 | version = "1.9.0" 157 | source = { registry = "https://pypi.org/simple" } 158 | sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722 } 159 | wheels = [ 160 | { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277 }, 161 | ] 162 | 163 | [[package]] 164 | name = "exceptiongroup" 165 | version = "1.2.2" 166 | source = { registry = "https://pypi.org/simple" } 167 | sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 } 168 | wheels = [ 169 | { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 }, 170 | ] 171 | 172 | [[package]] 173 | name = "fastapi" 174 | version = "0.115.6" 175 | source = { registry = "https://pypi.org/simple" } 176 | dependencies = [ 177 | { name = "pydantic" }, 178 | { name = "starlette" }, 179 | { name = "typing-extensions" }, 180 | ] 181 | sdist = { url = "https://files.pythonhosted.org/packages/93/72/d83b98cd106541e8f5e5bfab8ef2974ab45a62e8a6c5b5e6940f26d2ed4b/fastapi-0.115.6.tar.gz", hash = "sha256:9ec46f7addc14ea472958a96aae5b5de65f39721a46aaf5705c480d9a8b76654", size = 301336 } 182 | wheels = [ 183 | { url = "https://files.pythonhosted.org/packages/52/b3/7e4df40e585df024fac2f80d1a2d579c854ac37109675db2b0cc22c0bb9e/fastapi-0.115.6-py3-none-any.whl", hash = "sha256:e9240b29e36fa8f4bb7290316988e90c381e5092e0cbe84e7818cc3713bcf305", size = 94843 }, 184 | ] 185 | 186 | [[package]] 187 | name = "h11" 188 | version = "0.14.0" 189 | source = { registry = "https://pypi.org/simple" } 190 | sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 } 191 | wheels = [ 192 | { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 }, 193 | ] 194 | 195 | [[package]] 196 | name = "httpcore" 197 | version = "1.0.7" 198 | source = { registry = "https://pypi.org/simple" } 199 | dependencies = [ 200 | { name = "certifi" }, 201 | { name = "h11" }, 202 | ] 203 | sdist = { url = "https://files.pythonhosted.org/packages/6a/41/d7d0a89eb493922c37d343b607bc1b5da7f5be7e383740b4753ad8943e90/httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c", size = 85196 } 204 | wheels = [ 205 | { url = "https://files.pythonhosted.org/packages/87/f5/72347bc88306acb359581ac4d52f23c0ef445b57157adedb9aee0cd689d2/httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd", size = 78551 }, 206 | ] 207 | 208 | [[package]] 209 | name = "httpx" 210 | version = "0.28.1" 211 | source = { registry = "https://pypi.org/simple" } 212 | dependencies = [ 213 | { name = "anyio" }, 214 | { name = "certifi" }, 215 | { name = "httpcore" }, 216 | { name = "idna" }, 217 | ] 218 | sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 } 219 | wheels = [ 220 | { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 }, 221 | ] 222 | 223 | [[package]] 224 | name = "idna" 225 | version = "3.10" 226 | source = { registry = "https://pypi.org/simple" } 227 | sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } 228 | wheels = [ 229 | { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, 230 | ] 231 | 232 | [[package]] 233 | name = "iniconfig" 234 | version = "2.0.0" 235 | source = { registry = "https://pypi.org/simple" } 236 | sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } 237 | wheels = [ 238 | { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, 239 | ] 240 | 241 | [[package]] 242 | name = "jiter" 243 | version = "0.8.2" 244 | source = { registry = "https://pypi.org/simple" } 245 | sdist = { url = "https://files.pythonhosted.org/packages/f8/70/90bc7bd3932e651486861df5c8ffea4ca7c77d28e8532ddefe2abc561a53/jiter-0.8.2.tar.gz", hash = "sha256:cd73d3e740666d0e639f678adb176fad25c1bcbdae88d8d7b857e1783bb4212d", size = 163007 } 246 | wheels = [ 247 | { url = "https://files.pythonhosted.org/packages/f2/f3/8c11e0e87bd5934c414f9b1cfae3cbfd4a938d4669d57cb427e1c4d11a7f/jiter-0.8.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ca8577f6a413abe29b079bc30f907894d7eb07a865c4df69475e868d73e71c7b", size = 303381 }, 248 | { url = "https://files.pythonhosted.org/packages/ea/28/4cd3f0bcbf40e946bc6a62a82c951afc386a25673d3d8d5ee461f1559bbe/jiter-0.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b25bd626bde7fb51534190c7e3cb97cee89ee76b76d7585580e22f34f5e3f393", size = 311718 }, 249 | { url = "https://files.pythonhosted.org/packages/0d/17/57acab00507e60bd954eaec0837d9d7b119b4117ff49b8a62f2b646f32ed/jiter-0.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5c826a221851a8dc028eb6d7d6429ba03184fa3c7e83ae01cd6d3bd1d4bd17d", size = 335465 }, 250 | { url = "https://files.pythonhosted.org/packages/74/b9/1a3ddd2bc95ae17c815b021521020f40c60b32137730126bada962ef32b4/jiter-0.8.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d35c864c2dff13dfd79fb070fc4fc6235d7b9b359efe340e1261deb21b9fcb66", size = 355570 }, 251 | { url = "https://files.pythonhosted.org/packages/78/69/6d29e2296a934199a7d0dde673ecccf98c9c8db44caf0248b3f2b65483cb/jiter-0.8.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f557c55bc2b7676e74d39d19bcb8775ca295c7a028246175d6a8b431e70835e5", size = 381383 }, 252 | { url = "https://files.pythonhosted.org/packages/22/d7/fbc4c3fb1bf65f9be22a32759b539f88e897aeb13fe84ab0266e4423487a/jiter-0.8.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:580ccf358539153db147e40751a0b41688a5ceb275e6f3e93d91c9467f42b2e3", size = 390454 }, 253 | { url = "https://files.pythonhosted.org/packages/4d/a0/3993cda2e267fe679b45d0bcc2cef0b4504b0aa810659cdae9737d6bace9/jiter-0.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af102d3372e917cffce49b521e4c32c497515119dc7bd8a75665e90a718bbf08", size = 345039 }, 254 | { url = "https://files.pythonhosted.org/packages/b9/ef/69c18562b4c09ce88fab5df1dcaf643f6b1a8b970b65216e7221169b81c4/jiter-0.8.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cadcc978f82397d515bb2683fc0d50103acff2a180552654bb92d6045dec2c49", size = 376200 }, 255 | { url = "https://files.pythonhosted.org/packages/4d/17/0b5a8de46a6ab4d836f70934036278b49b8530c292b29dde3483326d4555/jiter-0.8.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ba5bdf56969cad2019d4e8ffd3f879b5fdc792624129741d3d83fc832fef8c7d", size = 511158 }, 256 | { url = "https://files.pythonhosted.org/packages/6c/b2/c401a0a2554b36c9e6d6e4876b43790d75139cf3936f0222e675cbc23451/jiter-0.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3b94a33a241bee9e34b8481cdcaa3d5c2116f575e0226e421bed3f7a6ea71cff", size = 503956 }, 257 | { url = "https://files.pythonhosted.org/packages/d4/02/a0291ed7d72c0ac130f172354ee3cf0b2556b69584de391463a8ee534f40/jiter-0.8.2-cp310-cp310-win32.whl", hash = "sha256:6e5337bf454abddd91bd048ce0dca5134056fc99ca0205258766db35d0a2ea43", size = 202846 }, 258 | { url = "https://files.pythonhosted.org/packages/ad/20/8c988831ae4bf437e29f1671e198fc99ba8fe49f2895f23789acad1d1811/jiter-0.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:4a9220497ca0cb1fe94e3f334f65b9b5102a0b8147646118f020d8ce1de70105", size = 204414 }, 259 | { url = "https://files.pythonhosted.org/packages/cb/b0/c1a7caa7f9dc5f1f6cfa08722867790fe2d3645d6e7170ca280e6e52d163/jiter-0.8.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:2dd61c5afc88a4fda7d8b2cf03ae5947c6ac7516d32b7a15bf4b49569a5c076b", size = 303666 }, 260 | { url = "https://files.pythonhosted.org/packages/f5/97/0468bc9eeae43079aaa5feb9267964e496bf13133d469cfdc135498f8dd0/jiter-0.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a6c710d657c8d1d2adbbb5c0b0c6bfcec28fd35bd6b5f016395f9ac43e878a15", size = 311934 }, 261 | { url = "https://files.pythonhosted.org/packages/e5/69/64058e18263d9a5f1e10f90c436853616d5f047d997c37c7b2df11b085ec/jiter-0.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9584de0cd306072635fe4b89742bf26feae858a0683b399ad0c2509011b9dc0", size = 335506 }, 262 | { url = "https://files.pythonhosted.org/packages/9d/14/b747f9a77b8c0542141d77ca1e2a7523e854754af2c339ac89a8b66527d6/jiter-0.8.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5a90a923338531b7970abb063cfc087eebae6ef8ec8139762007188f6bc69a9f", size = 355849 }, 263 | { url = "https://files.pythonhosted.org/packages/53/e2/98a08161db7cc9d0e39bc385415890928ff09709034982f48eccfca40733/jiter-0.8.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21974d246ed0181558087cd9f76e84e8321091ebfb3a93d4c341479a736f099", size = 381700 }, 264 | { url = "https://files.pythonhosted.org/packages/7a/38/1674672954d35bce3b1c9af99d5849f9256ac8f5b672e020ac7821581206/jiter-0.8.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:32475a42b2ea7b344069dc1e81445cfc00b9d0e3ca837f0523072432332e9f74", size = 389710 }, 265 | { url = "https://files.pythonhosted.org/packages/f8/9b/92f9da9a9e107d019bcf883cd9125fa1690079f323f5a9d5c6986eeec3c0/jiter-0.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b9931fd36ee513c26b5bf08c940b0ac875de175341cbdd4fa3be109f0492586", size = 345553 }, 266 | { url = "https://files.pythonhosted.org/packages/44/a6/6d030003394e9659cd0d7136bbeabd82e869849ceccddc34d40abbbbb269/jiter-0.8.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ce0820f4a3a59ddced7fce696d86a096d5cc48d32a4183483a17671a61edfddc", size = 376388 }, 267 | { url = "https://files.pythonhosted.org/packages/ad/8d/87b09e648e4aca5f9af89e3ab3cfb93db2d1e633b2f2931ede8dabd9b19a/jiter-0.8.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8ffc86ae5e3e6a93765d49d1ab47b6075a9c978a2b3b80f0f32628f39caa0c88", size = 511226 }, 268 | { url = "https://files.pythonhosted.org/packages/77/95/8008ebe4cdc82eac1c97864a8042ca7e383ed67e0ec17bfd03797045c727/jiter-0.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5127dc1abd809431172bc3fbe8168d6b90556a30bb10acd5ded41c3cfd6f43b6", size = 504134 }, 269 | { url = "https://files.pythonhosted.org/packages/26/0d/3056a74de13e8b2562e4d526de6dac2f65d91ace63a8234deb9284a1d24d/jiter-0.8.2-cp311-cp311-win32.whl", hash = "sha256:66227a2c7b575720c1871c8800d3a0122bb8ee94edb43a5685aa9aceb2782d44", size = 203103 }, 270 | { url = "https://files.pythonhosted.org/packages/4e/1e/7f96b798f356e531ffc0f53dd2f37185fac60fae4d6c612bbbd4639b90aa/jiter-0.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:cde031d8413842a1e7501e9129b8e676e62a657f8ec8166e18a70d94d4682855", size = 206717 }, 271 | { url = "https://files.pythonhosted.org/packages/a1/17/c8747af8ea4e045f57d6cfd6fc180752cab9bc3de0e8a0c9ca4e8af333b1/jiter-0.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:e6ec2be506e7d6f9527dae9ff4b7f54e68ea44a0ef6b098256ddf895218a2f8f", size = 302027 }, 272 | { url = "https://files.pythonhosted.org/packages/3c/c1/6da849640cd35a41e91085723b76acc818d4b7d92b0b6e5111736ce1dd10/jiter-0.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76e324da7b5da060287c54f2fabd3db5f76468006c811831f051942bf68c9d44", size = 310326 }, 273 | { url = "https://files.pythonhosted.org/packages/06/99/a2bf660d8ccffee9ad7ed46b4f860d2108a148d0ea36043fd16f4dc37e94/jiter-0.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:180a8aea058f7535d1c84183c0362c710f4750bef66630c05f40c93c2b152a0f", size = 334242 }, 274 | { url = "https://files.pythonhosted.org/packages/a7/5f/cea1c17864828731f11427b9d1ab7f24764dbd9aaf4648a7f851164d2718/jiter-0.8.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:025337859077b41548bdcbabe38698bcd93cfe10b06ff66617a48ff92c9aec60", size = 356654 }, 275 | { url = "https://files.pythonhosted.org/packages/e9/13/62774b7e5e7f5d5043efe1d0f94ead66e6d0f894ae010adb56b3f788de71/jiter-0.8.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ecff0dc14f409599bbcafa7e470c00b80f17abc14d1405d38ab02e4b42e55b57", size = 379967 }, 276 | { url = "https://files.pythonhosted.org/packages/ec/fb/096b34c553bb0bd3f2289d5013dcad6074948b8d55212aa13a10d44c5326/jiter-0.8.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffd9fee7d0775ebaba131f7ca2e2d83839a62ad65e8e02fe2bd8fc975cedeb9e", size = 389252 }, 277 | { url = "https://files.pythonhosted.org/packages/17/61/beea645c0bf398ced8b199e377b61eb999d8e46e053bb285c91c3d3eaab0/jiter-0.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14601dcac4889e0a1c75ccf6a0e4baf70dbc75041e51bcf8d0e9274519df6887", size = 345490 }, 278 | { url = "https://files.pythonhosted.org/packages/d5/df/834aa17ad5dcc3cf0118821da0a0cf1589ea7db9832589278553640366bc/jiter-0.8.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92249669925bc1c54fcd2ec73f70f2c1d6a817928480ee1c65af5f6b81cdf12d", size = 376991 }, 279 | { url = "https://files.pythonhosted.org/packages/67/80/87d140399d382fb4ea5b3d56e7ecaa4efdca17cd7411ff904c1517855314/jiter-0.8.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e725edd0929fa79f8349ab4ec7f81c714df51dc4e991539a578e5018fa4a7152", size = 510822 }, 280 | { url = "https://files.pythonhosted.org/packages/5c/37/3394bb47bac1ad2cb0465601f86828a0518d07828a650722e55268cdb7e6/jiter-0.8.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bf55846c7b7a680eebaf9c3c48d630e1bf51bdf76c68a5f654b8524335b0ad29", size = 503730 }, 281 | { url = "https://files.pythonhosted.org/packages/f9/e2/253fc1fa59103bb4e3aa0665d6ceb1818df1cd7bf3eb492c4dad229b1cd4/jiter-0.8.2-cp312-cp312-win32.whl", hash = "sha256:7efe4853ecd3d6110301665a5178b9856be7e2a9485f49d91aa4d737ad2ae49e", size = 203375 }, 282 | { url = "https://files.pythonhosted.org/packages/41/69/6d4bbe66b3b3b4507e47aa1dd5d075919ad242b4b1115b3f80eecd443687/jiter-0.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:83c0efd80b29695058d0fd2fa8a556490dbce9804eac3e281f373bbc99045f6c", size = 204740 }, 283 | { url = "https://files.pythonhosted.org/packages/6c/b0/bfa1f6f2c956b948802ef5a021281978bf53b7a6ca54bb126fd88a5d014e/jiter-0.8.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ca1f08b8e43dc3bd0594c992fb1fd2f7ce87f7bf0d44358198d6da8034afdf84", size = 301190 }, 284 | { url = "https://files.pythonhosted.org/packages/a4/8f/396ddb4e292b5ea57e45ade5dc48229556b9044bad29a3b4b2dddeaedd52/jiter-0.8.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5672a86d55416ccd214c778efccf3266b84f87b89063b582167d803246354be4", size = 309334 }, 285 | { url = "https://files.pythonhosted.org/packages/7f/68/805978f2f446fa6362ba0cc2e4489b945695940656edd844e110a61c98f8/jiter-0.8.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58dc9bc9767a1101f4e5e22db1b652161a225874d66f0e5cb8e2c7d1c438b587", size = 333918 }, 286 | { url = "https://files.pythonhosted.org/packages/b3/99/0f71f7be667c33403fa9706e5b50583ae5106d96fab997fa7e2f38ee8347/jiter-0.8.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:37b2998606d6dadbb5ccda959a33d6a5e853252d921fec1792fc902351bb4e2c", size = 356057 }, 287 | { url = "https://files.pythonhosted.org/packages/8d/50/a82796e421a22b699ee4d2ce527e5bcb29471a2351cbdc931819d941a167/jiter-0.8.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ab9a87f3784eb0e098f84a32670cfe4a79cb6512fd8f42ae3d0709f06405d18", size = 379790 }, 288 | { url = "https://files.pythonhosted.org/packages/3c/31/10fb012b00f6d83342ca9e2c9618869ab449f1aa78c8f1b2193a6b49647c/jiter-0.8.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79aec8172b9e3c6d05fd4b219d5de1ac616bd8da934107325a6c0d0e866a21b6", size = 388285 }, 289 | { url = "https://files.pythonhosted.org/packages/c8/81/f15ebf7de57be488aa22944bf4274962aca8092e4f7817f92ffa50d3ee46/jiter-0.8.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:711e408732d4e9a0208008e5892c2966b485c783cd2d9a681f3eb147cf36c7ef", size = 344764 }, 290 | { url = "https://files.pythonhosted.org/packages/b3/e8/0cae550d72b48829ba653eb348cdc25f3f06f8a62363723702ec18e7be9c/jiter-0.8.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:653cf462db4e8c41995e33d865965e79641ef45369d8a11f54cd30888b7e6ff1", size = 376620 }, 291 | { url = "https://files.pythonhosted.org/packages/b8/50/e5478ff9d82534a944c03b63bc217c5f37019d4a34d288db0f079b13c10b/jiter-0.8.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:9c63eaef32b7bebac8ebebf4dabebdbc6769a09c127294db6babee38e9f405b9", size = 510402 }, 292 | { url = "https://files.pythonhosted.org/packages/8e/1e/3de48bbebbc8f7025bd454cedc8c62378c0e32dd483dece5f4a814a5cb55/jiter-0.8.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:eb21aaa9a200d0a80dacc7a81038d2e476ffe473ffdd9c91eb745d623561de05", size = 503018 }, 293 | { url = "https://files.pythonhosted.org/packages/d5/cd/d5a5501d72a11fe3e5fd65c78c884e5164eefe80077680533919be22d3a3/jiter-0.8.2-cp313-cp313-win32.whl", hash = "sha256:789361ed945d8d42850f919342a8665d2dc79e7e44ca1c97cc786966a21f627a", size = 203190 }, 294 | { url = "https://files.pythonhosted.org/packages/51/bf/e5ca301245ba951447e3ad677a02a64a8845b185de2603dabd83e1e4b9c6/jiter-0.8.2-cp313-cp313-win_amd64.whl", hash = "sha256:ab7f43235d71e03b941c1630f4b6e3055d46b6cb8728a17663eaac9d8e83a865", size = 203551 }, 295 | { url = "https://files.pythonhosted.org/packages/2f/3c/71a491952c37b87d127790dd7a0b1ebea0514c6b6ad30085b16bbe00aee6/jiter-0.8.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b426f72cd77da3fec300ed3bc990895e2dd6b49e3bfe6c438592a3ba660e41ca", size = 308347 }, 296 | { url = "https://files.pythonhosted.org/packages/a0/4c/c02408042e6a7605ec063daed138e07b982fdb98467deaaf1c90950cf2c6/jiter-0.8.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2dd880785088ff2ad21ffee205e58a8c1ddabc63612444ae41e5e4b321b39c0", size = 342875 }, 297 | { url = "https://files.pythonhosted.org/packages/91/61/c80ef80ed8a0a21158e289ef70dac01e351d929a1c30cb0f49be60772547/jiter-0.8.2-cp313-cp313t-win_amd64.whl", hash = "sha256:3ac9f578c46f22405ff7f8b1f5848fb753cc4b8377fbec8470a7dc3997ca7566", size = 202374 }, 298 | ] 299 | 300 | [[package]] 301 | name = "lovelaice" 302 | version = "0.3.6" 303 | source = { editable = "." } 304 | dependencies = [ 305 | { name = "openai" }, 306 | { name = "pydantic" }, 307 | { name = "python-dotenv" }, 308 | { name = "pyyaml" }, 309 | { name = "requests" }, 310 | { name = "rich" }, 311 | ] 312 | 313 | [package.optional-dependencies] 314 | api = [ 315 | { name = "fastapi" }, 316 | { name = "uvicorn" }, 317 | ] 318 | 319 | [package.dev-dependencies] 320 | dev = [ 321 | { name = "black" }, 322 | { name = "pytest" }, 323 | ] 324 | 325 | [package.metadata] 326 | requires-dist = [ 327 | { name = "fastapi", marker = "extra == 'api'", specifier = ">=0.115.6" }, 328 | { name = "openai", specifier = ">=1.58.1" }, 329 | { name = "pydantic", specifier = ">=2.10.4" }, 330 | { name = "python-dotenv", specifier = ">=1.0.1" }, 331 | { name = "pyyaml", specifier = ">=6.0.2" }, 332 | { name = "requests", specifier = ">=2.32.3" }, 333 | { name = "rich", specifier = ">=13.9.4" }, 334 | { name = "uvicorn", marker = "extra == 'api'", specifier = ">=0.34.0" }, 335 | ] 336 | provides-extras = ["api"] 337 | 338 | [package.metadata.requires-dev] 339 | dev = [ 340 | { name = "black", specifier = ">=24.10.0" }, 341 | { name = "pytest", specifier = ">=8.3.4" }, 342 | ] 343 | 344 | [[package]] 345 | name = "markdown-it-py" 346 | version = "3.0.0" 347 | source = { registry = "https://pypi.org/simple" } 348 | dependencies = [ 349 | { name = "mdurl" }, 350 | ] 351 | sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } 352 | wheels = [ 353 | { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, 354 | ] 355 | 356 | [[package]] 357 | name = "mdurl" 358 | version = "0.1.2" 359 | source = { registry = "https://pypi.org/simple" } 360 | sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } 361 | wheels = [ 362 | { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, 363 | ] 364 | 365 | [[package]] 366 | name = "mypy-extensions" 367 | version = "1.0.0" 368 | source = { registry = "https://pypi.org/simple" } 369 | sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433 } 370 | wheels = [ 371 | { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 }, 372 | ] 373 | 374 | [[package]] 375 | name = "openai" 376 | version = "1.58.1" 377 | source = { registry = "https://pypi.org/simple" } 378 | dependencies = [ 379 | { name = "anyio" }, 380 | { name = "distro" }, 381 | { name = "httpx" }, 382 | { name = "jiter" }, 383 | { name = "pydantic" }, 384 | { name = "sniffio" }, 385 | { name = "tqdm" }, 386 | { name = "typing-extensions" }, 387 | ] 388 | sdist = { url = "https://files.pythonhosted.org/packages/27/3c/b1ecce430ed56fa3ac1b0676966d3250aab9c70a408232b71e419ea62148/openai-1.58.1.tar.gz", hash = "sha256:f5a035fd01e141fc743f4b0e02c41ca49be8fab0866d3b67f5f29b4f4d3c0973", size = 343411 } 389 | wheels = [ 390 | { url = "https://files.pythonhosted.org/packages/8e/5a/d22cd07f1a99b9e8b3c92ee0c1959188db4318828a3d88c9daac120bdd69/openai-1.58.1-py3-none-any.whl", hash = "sha256:e2910b1170a6b7f88ef491ac3a42c387f08bd3db533411f7ee391d166571d63c", size = 454279 }, 391 | ] 392 | 393 | [[package]] 394 | name = "packaging" 395 | version = "24.2" 396 | source = { registry = "https://pypi.org/simple" } 397 | sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } 398 | wheels = [ 399 | { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, 400 | ] 401 | 402 | [[package]] 403 | name = "pathspec" 404 | version = "0.12.1" 405 | source = { registry = "https://pypi.org/simple" } 406 | sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 } 407 | wheels = [ 408 | { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 }, 409 | ] 410 | 411 | [[package]] 412 | name = "platformdirs" 413 | version = "4.3.6" 414 | source = { registry = "https://pypi.org/simple" } 415 | sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302 } 416 | wheels = [ 417 | { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 }, 418 | ] 419 | 420 | [[package]] 421 | name = "pluggy" 422 | version = "1.5.0" 423 | source = { registry = "https://pypi.org/simple" } 424 | sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } 425 | wheels = [ 426 | { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, 427 | ] 428 | 429 | [[package]] 430 | name = "pydantic" 431 | version = "2.10.4" 432 | source = { registry = "https://pypi.org/simple" } 433 | dependencies = [ 434 | { name = "annotated-types" }, 435 | { name = "pydantic-core" }, 436 | { name = "typing-extensions" }, 437 | ] 438 | sdist = { url = "https://files.pythonhosted.org/packages/70/7e/fb60e6fee04d0ef8f15e4e01ff187a196fa976eb0f0ab524af4599e5754c/pydantic-2.10.4.tar.gz", hash = "sha256:82f12e9723da6de4fe2ba888b5971157b3be7ad914267dea8f05f82b28254f06", size = 762094 } 439 | wheels = [ 440 | { url = "https://files.pythonhosted.org/packages/f3/26/3e1bbe954fde7ee22a6e7d31582c642aad9e84ffe4b5fb61e63b87cd326f/pydantic-2.10.4-py3-none-any.whl", hash = "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d", size = 431765 }, 441 | ] 442 | 443 | [[package]] 444 | name = "pydantic-core" 445 | version = "2.27.2" 446 | source = { registry = "https://pypi.org/simple" } 447 | dependencies = [ 448 | { name = "typing-extensions" }, 449 | ] 450 | sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443 } 451 | wheels = [ 452 | { url = "https://files.pythonhosted.org/packages/3a/bc/fed5f74b5d802cf9a03e83f60f18864e90e3aed7223adaca5ffb7a8d8d64/pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa", size = 1895938 }, 453 | { url = "https://files.pythonhosted.org/packages/71/2a/185aff24ce844e39abb8dd680f4e959f0006944f4a8a0ea372d9f9ae2e53/pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c", size = 1815684 }, 454 | { url = "https://files.pythonhosted.org/packages/c3/43/fafabd3d94d159d4f1ed62e383e264f146a17dd4d48453319fd782e7979e/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a", size = 1829169 }, 455 | { url = "https://files.pythonhosted.org/packages/a2/d1/f2dfe1a2a637ce6800b799aa086d079998959f6f1215eb4497966efd2274/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5", size = 1867227 }, 456 | { url = "https://files.pythonhosted.org/packages/7d/39/e06fcbcc1c785daa3160ccf6c1c38fea31f5754b756e34b65f74e99780b5/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c", size = 2037695 }, 457 | { url = "https://files.pythonhosted.org/packages/7a/67/61291ee98e07f0650eb756d44998214231f50751ba7e13f4f325d95249ab/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7", size = 2741662 }, 458 | { url = "https://files.pythonhosted.org/packages/32/90/3b15e31b88ca39e9e626630b4c4a1f5a0dfd09076366f4219429e6786076/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a", size = 1993370 }, 459 | { url = "https://files.pythonhosted.org/packages/ff/83/c06d333ee3a67e2e13e07794995c1535565132940715931c1c43bfc85b11/pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236", size = 1996813 }, 460 | { url = "https://files.pythonhosted.org/packages/7c/f7/89be1c8deb6e22618a74f0ca0d933fdcb8baa254753b26b25ad3acff8f74/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962", size = 2005287 }, 461 | { url = "https://files.pythonhosted.org/packages/b7/7d/8eb3e23206c00ef7feee17b83a4ffa0a623eb1a9d382e56e4aa46fd15ff2/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9", size = 2128414 }, 462 | { url = "https://files.pythonhosted.org/packages/4e/99/fe80f3ff8dd71a3ea15763878d464476e6cb0a2db95ff1c5c554133b6b83/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af", size = 2155301 }, 463 | { url = "https://files.pythonhosted.org/packages/2b/a3/e50460b9a5789ca1451b70d4f52546fa9e2b420ba3bfa6100105c0559238/pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4", size = 1816685 }, 464 | { url = "https://files.pythonhosted.org/packages/57/4c/a8838731cb0f2c2a39d3535376466de6049034d7b239c0202a64aaa05533/pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31", size = 1982876 }, 465 | { url = "https://files.pythonhosted.org/packages/c2/89/f3450af9d09d44eea1f2c369f49e8f181d742f28220f88cc4dfaae91ea6e/pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", size = 1893421 }, 466 | { url = "https://files.pythonhosted.org/packages/9e/e3/71fe85af2021f3f386da42d291412e5baf6ce7716bd7101ea49c810eda90/pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", size = 1814998 }, 467 | { url = "https://files.pythonhosted.org/packages/a6/3c/724039e0d848fd69dbf5806894e26479577316c6f0f112bacaf67aa889ac/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", size = 1826167 }, 468 | { url = "https://files.pythonhosted.org/packages/2b/5b/1b29e8c1fb5f3199a9a57c1452004ff39f494bbe9bdbe9a81e18172e40d3/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", size = 1865071 }, 469 | { url = "https://files.pythonhosted.org/packages/89/6c/3985203863d76bb7d7266e36970d7e3b6385148c18a68cc8915fd8c84d57/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", size = 2036244 }, 470 | { url = "https://files.pythonhosted.org/packages/0e/41/f15316858a246b5d723f7d7f599f79e37493b2e84bfc789e58d88c209f8a/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", size = 2737470 }, 471 | { url = "https://files.pythonhosted.org/packages/a8/7c/b860618c25678bbd6d1d99dbdfdf0510ccb50790099b963ff78a124b754f/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", size = 1992291 }, 472 | { url = "https://files.pythonhosted.org/packages/bf/73/42c3742a391eccbeab39f15213ecda3104ae8682ba3c0c28069fbcb8c10d/pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", size = 1994613 }, 473 | { url = "https://files.pythonhosted.org/packages/94/7a/941e89096d1175d56f59340f3a8ebaf20762fef222c298ea96d36a6328c5/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", size = 2002355 }, 474 | { url = "https://files.pythonhosted.org/packages/6e/95/2359937a73d49e336a5a19848713555605d4d8d6940c3ec6c6c0ca4dcf25/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", size = 2126661 }, 475 | { url = "https://files.pythonhosted.org/packages/2b/4c/ca02b7bdb6012a1adef21a50625b14f43ed4d11f1fc237f9d7490aa5078c/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", size = 2153261 }, 476 | { url = "https://files.pythonhosted.org/packages/72/9d/a241db83f973049a1092a079272ffe2e3e82e98561ef6214ab53fe53b1c7/pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", size = 1812361 }, 477 | { url = "https://files.pythonhosted.org/packages/e8/ef/013f07248041b74abd48a385e2110aa3a9bbfef0fbd97d4e6d07d2f5b89a/pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", size = 1982484 }, 478 | { url = "https://files.pythonhosted.org/packages/10/1c/16b3a3e3398fd29dca77cea0a1d998d6bde3902fa2706985191e2313cc76/pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", size = 1867102 }, 479 | { url = "https://files.pythonhosted.org/packages/d6/74/51c8a5482ca447871c93e142d9d4a92ead74de6c8dc5e66733e22c9bba89/pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", size = 1893127 }, 480 | { url = "https://files.pythonhosted.org/packages/d3/f3/c97e80721735868313c58b89d2de85fa80fe8dfeeed84dc51598b92a135e/pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", size = 1811340 }, 481 | { url = "https://files.pythonhosted.org/packages/9e/91/840ec1375e686dbae1bd80a9e46c26a1e0083e1186abc610efa3d9a36180/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", size = 1822900 }, 482 | { url = "https://files.pythonhosted.org/packages/f6/31/4240bc96025035500c18adc149aa6ffdf1a0062a4b525c932065ceb4d868/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", size = 1869177 }, 483 | { url = "https://files.pythonhosted.org/packages/fa/20/02fbaadb7808be578317015c462655c317a77a7c8f0ef274bc016a784c54/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", size = 2038046 }, 484 | { url = "https://files.pythonhosted.org/packages/06/86/7f306b904e6c9eccf0668248b3f272090e49c275bc488a7b88b0823444a4/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", size = 2685386 }, 485 | { url = "https://files.pythonhosted.org/packages/8d/f0/49129b27c43396581a635d8710dae54a791b17dfc50c70164866bbf865e3/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", size = 1997060 }, 486 | { url = "https://files.pythonhosted.org/packages/0d/0f/943b4af7cd416c477fd40b187036c4f89b416a33d3cc0ab7b82708a667aa/pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", size = 2004870 }, 487 | { url = "https://files.pythonhosted.org/packages/35/40/aea70b5b1a63911c53a4c8117c0a828d6790483f858041f47bab0b779f44/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", size = 1999822 }, 488 | { url = "https://files.pythonhosted.org/packages/f2/b3/807b94fd337d58effc5498fd1a7a4d9d59af4133e83e32ae39a96fddec9d/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", size = 2130364 }, 489 | { url = "https://files.pythonhosted.org/packages/fc/df/791c827cd4ee6efd59248dca9369fb35e80a9484462c33c6649a8d02b565/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", size = 2158303 }, 490 | { url = "https://files.pythonhosted.org/packages/9b/67/4e197c300976af185b7cef4c02203e175fb127e414125916bf1128b639a9/pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", size = 1834064 }, 491 | { url = "https://files.pythonhosted.org/packages/1f/ea/cd7209a889163b8dcca139fe32b9687dd05249161a3edda62860430457a5/pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", size = 1989046 }, 492 | { url = "https://files.pythonhosted.org/packages/bc/49/c54baab2f4658c26ac633d798dab66b4c3a9bbf47cff5284e9c182f4137a/pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", size = 1885092 }, 493 | { url = "https://files.pythonhosted.org/packages/41/b1/9bc383f48f8002f99104e3acff6cba1231b29ef76cfa45d1506a5cad1f84/pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", size = 1892709 }, 494 | { url = "https://files.pythonhosted.org/packages/10/6c/e62b8657b834f3eb2961b49ec8e301eb99946245e70bf42c8817350cbefc/pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", size = 1811273 }, 495 | { url = "https://files.pythonhosted.org/packages/ba/15/52cfe49c8c986e081b863b102d6b859d9defc63446b642ccbbb3742bf371/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", size = 1823027 }, 496 | { url = "https://files.pythonhosted.org/packages/b1/1c/b6f402cfc18ec0024120602bdbcebc7bdd5b856528c013bd4d13865ca473/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", size = 1868888 }, 497 | { url = "https://files.pythonhosted.org/packages/bd/7b/8cb75b66ac37bc2975a3b7de99f3c6f355fcc4d89820b61dffa8f1e81677/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", size = 2037738 }, 498 | { url = "https://files.pythonhosted.org/packages/c8/f1/786d8fe78970a06f61df22cba58e365ce304bf9b9f46cc71c8c424e0c334/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", size = 2685138 }, 499 | { url = "https://files.pythonhosted.org/packages/a6/74/d12b2cd841d8724dc8ffb13fc5cef86566a53ed358103150209ecd5d1999/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", size = 1997025 }, 500 | { url = "https://files.pythonhosted.org/packages/a0/6e/940bcd631bc4d9a06c9539b51f070b66e8f370ed0933f392db6ff350d873/pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", size = 2004633 }, 501 | { url = "https://files.pythonhosted.org/packages/50/cc/a46b34f1708d82498c227d5d80ce615b2dd502ddcfd8376fc14a36655af1/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", size = 1999404 }, 502 | { url = "https://files.pythonhosted.org/packages/ca/2d/c365cfa930ed23bc58c41463bae347d1005537dc8db79e998af8ba28d35e/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", size = 2130130 }, 503 | { url = "https://files.pythonhosted.org/packages/f4/d7/eb64d015c350b7cdb371145b54d96c919d4db516817f31cd1c650cae3b21/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", size = 2157946 }, 504 | { url = "https://files.pythonhosted.org/packages/a4/99/bddde3ddde76c03b65dfd5a66ab436c4e58ffc42927d4ff1198ffbf96f5f/pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", size = 1834387 }, 505 | { url = "https://files.pythonhosted.org/packages/71/47/82b5e846e01b26ac6f1893d3c5f9f3a2eb6ba79be26eef0b759b4fe72946/pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", size = 1990453 }, 506 | { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186 }, 507 | { url = "https://files.pythonhosted.org/packages/46/72/af70981a341500419e67d5cb45abe552a7c74b66326ac8877588488da1ac/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e", size = 1891159 }, 508 | { url = "https://files.pythonhosted.org/packages/ad/3d/c5913cccdef93e0a6a95c2d057d2c2cba347815c845cda79ddd3c0f5e17d/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8", size = 1768331 }, 509 | { url = "https://files.pythonhosted.org/packages/f6/f0/a3ae8fbee269e4934f14e2e0e00928f9346c5943174f2811193113e58252/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3", size = 1822467 }, 510 | { url = "https://files.pythonhosted.org/packages/d7/7a/7bbf241a04e9f9ea24cd5874354a83526d639b02674648af3f350554276c/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f", size = 1979797 }, 511 | { url = "https://files.pythonhosted.org/packages/4f/5f/4784c6107731f89e0005a92ecb8a2efeafdb55eb992b8e9d0a2be5199335/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133", size = 1987839 }, 512 | { url = "https://files.pythonhosted.org/packages/6d/a7/61246562b651dff00de86a5f01b6e4befb518df314c54dec187a78d81c84/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc", size = 1998861 }, 513 | { url = "https://files.pythonhosted.org/packages/86/aa/837821ecf0c022bbb74ca132e117c358321e72e7f9702d1b6a03758545e2/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50", size = 2116582 }, 514 | { url = "https://files.pythonhosted.org/packages/81/b0/5e74656e95623cbaa0a6278d16cf15e10a51f6002e3ec126541e95c29ea3/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9", size = 2151985 }, 515 | { url = "https://files.pythonhosted.org/packages/63/37/3e32eeb2a451fddaa3898e2163746b0cffbbdbb4740d38372db0490d67f3/pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151", size = 2004715 }, 516 | ] 517 | 518 | [[package]] 519 | name = "pygments" 520 | version = "2.19.1" 521 | source = { registry = "https://pypi.org/simple" } 522 | sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 } 523 | wheels = [ 524 | { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, 525 | ] 526 | 527 | [[package]] 528 | name = "pytest" 529 | version = "8.3.4" 530 | source = { registry = "https://pypi.org/simple" } 531 | dependencies = [ 532 | { name = "colorama", marker = "sys_platform == 'win32'" }, 533 | { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, 534 | { name = "iniconfig" }, 535 | { name = "packaging" }, 536 | { name = "pluggy" }, 537 | { name = "tomli", marker = "python_full_version < '3.11'" }, 538 | ] 539 | sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919 } 540 | wheels = [ 541 | { url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083 }, 542 | ] 543 | 544 | [[package]] 545 | name = "python-dotenv" 546 | version = "1.0.1" 547 | source = { registry = "https://pypi.org/simple" } 548 | sdist = { url = "https://files.pythonhosted.org/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", size = 39115 } 549 | wheels = [ 550 | { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 }, 551 | ] 552 | 553 | [[package]] 554 | name = "pyyaml" 555 | version = "6.0.2" 556 | source = { registry = "https://pypi.org/simple" } 557 | sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 } 558 | wheels = [ 559 | { url = "https://files.pythonhosted.org/packages/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199 }, 560 | { url = "https://files.pythonhosted.org/packages/c7/7a/68bd47624dab8fd4afbfd3c48e3b79efe09098ae941de5b58abcbadff5cb/PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", size = 171758 }, 561 | { url = "https://files.pythonhosted.org/packages/49/ee/14c54df452143b9ee9f0f29074d7ca5516a36edb0b4cc40c3f280131656f/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", size = 718463 }, 562 | { url = "https://files.pythonhosted.org/packages/4d/61/de363a97476e766574650d742205be468921a7b532aa2499fcd886b62530/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", size = 719280 }, 563 | { url = "https://files.pythonhosted.org/packages/6b/4e/1523cb902fd98355e2e9ea5e5eb237cbc5f3ad5f3075fa65087aa0ecb669/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", size = 751239 }, 564 | { url = "https://files.pythonhosted.org/packages/b7/33/5504b3a9a4464893c32f118a9cc045190a91637b119a9c881da1cf6b7a72/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", size = 695802 }, 565 | { url = "https://files.pythonhosted.org/packages/5c/20/8347dcabd41ef3a3cdc4f7b7a2aff3d06598c8779faa189cdbf878b626a4/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", size = 720527 }, 566 | { url = "https://files.pythonhosted.org/packages/be/aa/5afe99233fb360d0ff37377145a949ae258aaab831bde4792b32650a4378/PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", size = 144052 }, 567 | { url = "https://files.pythonhosted.org/packages/b5/84/0fa4b06f6d6c958d207620fc60005e241ecedceee58931bb20138e1e5776/PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", size = 161774 }, 568 | { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612 }, 569 | { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040 }, 570 | { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829 }, 571 | { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167 }, 572 | { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952 }, 573 | { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301 }, 574 | { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638 }, 575 | { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850 }, 576 | { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980 }, 577 | { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873 }, 578 | { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302 }, 579 | { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154 }, 580 | { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223 }, 581 | { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542 }, 582 | { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164 }, 583 | { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 }, 584 | { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 }, 585 | { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 }, 586 | { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 }, 587 | { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 }, 588 | { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 }, 589 | { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 }, 590 | { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 }, 591 | { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 }, 592 | { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 }, 593 | { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 }, 594 | { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, 595 | ] 596 | 597 | [[package]] 598 | name = "requests" 599 | version = "2.32.3" 600 | source = { registry = "https://pypi.org/simple" } 601 | dependencies = [ 602 | { name = "certifi" }, 603 | { name = "charset-normalizer" }, 604 | { name = "idna" }, 605 | { name = "urllib3" }, 606 | ] 607 | sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } 608 | wheels = [ 609 | { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, 610 | ] 611 | 612 | [[package]] 613 | name = "rich" 614 | version = "13.9.4" 615 | source = { registry = "https://pypi.org/simple" } 616 | dependencies = [ 617 | { name = "markdown-it-py" }, 618 | { name = "pygments" }, 619 | { name = "typing-extensions", marker = "python_full_version < '3.11'" }, 620 | ] 621 | sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 } 622 | wheels = [ 623 | { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 }, 624 | ] 625 | 626 | [[package]] 627 | name = "sniffio" 628 | version = "1.3.1" 629 | source = { registry = "https://pypi.org/simple" } 630 | sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 } 631 | wheels = [ 632 | { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, 633 | ] 634 | 635 | [[package]] 636 | name = "starlette" 637 | version = "0.41.3" 638 | source = { registry = "https://pypi.org/simple" } 639 | dependencies = [ 640 | { name = "anyio" }, 641 | ] 642 | sdist = { url = "https://files.pythonhosted.org/packages/1a/4c/9b5764bd22eec91c4039ef4c55334e9187085da2d8a2df7bd570869aae18/starlette-0.41.3.tar.gz", hash = "sha256:0e4ab3d16522a255be6b28260b938eae2482f98ce5cc934cb08dce8dc3ba5835", size = 2574159 } 643 | wheels = [ 644 | { url = "https://files.pythonhosted.org/packages/96/00/2b325970b3060c7cecebab6d295afe763365822b1306a12eeab198f74323/starlette-0.41.3-py3-none-any.whl", hash = "sha256:44cedb2b7c77a9de33a8b74b2b90e9f50d11fcf25d8270ea525ad71a25374ff7", size = 73225 }, 645 | ] 646 | 647 | [[package]] 648 | name = "tomli" 649 | version = "2.2.1" 650 | source = { registry = "https://pypi.org/simple" } 651 | sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175 } 652 | wheels = [ 653 | { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077 }, 654 | { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429 }, 655 | { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067 }, 656 | { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030 }, 657 | { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898 }, 658 | { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894 }, 659 | { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319 }, 660 | { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273 }, 661 | { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310 }, 662 | { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309 }, 663 | { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762 }, 664 | { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453 }, 665 | { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486 }, 666 | { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349 }, 667 | { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159 }, 668 | { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243 }, 669 | { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645 }, 670 | { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584 }, 671 | { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875 }, 672 | { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418 }, 673 | { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708 }, 674 | { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582 }, 675 | { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543 }, 676 | { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691 }, 677 | { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170 }, 678 | { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530 }, 679 | { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666 }, 680 | { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954 }, 681 | { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724 }, 682 | { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383 }, 683 | { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 }, 684 | ] 685 | 686 | [[package]] 687 | name = "tqdm" 688 | version = "4.67.1" 689 | source = { registry = "https://pypi.org/simple" } 690 | dependencies = [ 691 | { name = "colorama", marker = "sys_platform == 'win32'" }, 692 | ] 693 | sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737 } 694 | wheels = [ 695 | { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540 }, 696 | ] 697 | 698 | [[package]] 699 | name = "typing-extensions" 700 | version = "4.12.2" 701 | source = { registry = "https://pypi.org/simple" } 702 | sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } 703 | wheels = [ 704 | { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, 705 | ] 706 | 707 | [[package]] 708 | name = "urllib3" 709 | version = "2.3.0" 710 | source = { registry = "https://pypi.org/simple" } 711 | sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268 } 712 | wheels = [ 713 | { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 }, 714 | ] 715 | 716 | [[package]] 717 | name = "uvicorn" 718 | version = "0.34.0" 719 | source = { registry = "https://pypi.org/simple" } 720 | dependencies = [ 721 | { name = "click" }, 722 | { name = "h11" }, 723 | { name = "typing-extensions", marker = "python_full_version < '3.11'" }, 724 | ] 725 | sdist = { url = "https://files.pythonhosted.org/packages/4b/4d/938bd85e5bf2edeec766267a5015ad969730bb91e31b44021dfe8b22df6c/uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9", size = 76568 } 726 | wheels = [ 727 | { url = "https://files.pythonhosted.org/packages/61/14/33a3a1352cfa71812a3a21e8c9bfb83f60b0011f5e36f2b1399d51928209/uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4", size = 62315 }, 728 | ] 729 | --------------------------------------------------------------------------------