From 9e7c906a8e6c2f73617a9daffd132605e9fd7015 Mon Sep 17 00:00:00 2001 From: vincent d warmerdam Date: Wed, 12 Mar 2025 15:41:16 +0100 Subject: [PATCH 1/2] moar --- README.md | 90 ++++++- demo.py | 19 ++ imgs/logo.png | Bin 0 -> 19802 bytes smartfunc/__init__.py | 11 +- uv.lock | 555 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 672 insertions(+), 3 deletions(-) create mode 100644 demo.py create mode 100644 imgs/logo.png diff --git a/README.md b/README.md index c77a597..6509bc0 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,88 @@ -# smartfunc -Turn docstrings into LLM-functions + + +### smartfunc + +> Turn docstrings into LLM-functions + +## Installation + +```bash +uv pip install smartfunc +``` + + +## What is this? + +Here is a nice example of what is possible with this library: + +```python +from smartfunc import backend + +@backend("gpt-4") +def generate_summary(text: str): + """Generate a summary of the following text: {{ text }}""" + pass +``` + +The `generate_summary` function will now return a string with the summary of the text. + +## How does it work? + +This library wraps around the [llm library](https://llm.datasette.io/en/stable/index.html) made by Simon Willison. The docstring is parsed and turned into a Jinja2 template which we inject with variables to generate a prompt at runtime. We then use the backend given by the decorator to run the prompt and return the result. + +The `llm` library is minimalistic and while it does not support all the features out there it does offer a solid foundation to build on. This library is mainly meant as a method to add some syntactic sugar on top. We do get a few nice benefits from the `llm` library though: + +- The `llm` library is well maintained and has a large community +- An [ecosystem of backends](https://llm.datasette.io/en/stable/plugins/directory.html) for different LLM providers +- Many of the vendors have `async` support, which allows us to do microbatching +- Many of the vendors have schema support, which allows us to use Pydantic models to define the response +- You can use `.env` files to store your API keys + +## Extra features + +The following snippet shows how you might create a re-useable backend decorator that uses a system prompt. Also notice how we're able to use a Pydantic model to define the response. + +```python +from smartfunc import backend +from pydantic import BaseModel + +class Summary(BaseModel): + summary: str + pros: list[str] + cons: list[str] + +llmify = backend("gpt-4", system="You are a helpful assistant.", temperature=0.5) + +@llmify +def generate_poke_desc(text: str) -> Summary: + """Describe the following pokemon: {{ text }}""" + pass + +print(generate_poke_desc("pikachu")) +``` + +This is the result that we got back: + +``` +{ + 'summary': 'Pikachu is a small, electric-type Pokémon known for its adorable appearance and strong electrical abilities. It is recognized as the mascot of the Pokémon franchise, with distinctive features and a cheerful personality.', + 'pros': [ + 'Iconic and recognizable worldwide', + 'Strong electric attacks like Thunderbolt', + 'Has a cute and friendly appearance', + 'Evolves into Raichu with a Thunder Stone', + 'Popular choice in Pokémon merchandise and media' + ], + 'cons': [ + 'Not very strong in higher-level battles', + 'Weak against ground-type moves', + 'Limited to electric-type attacks unless learned through TMs', + 'Can be overshadowed by other powerful Pokémon in competitive play' + ], +} +``` + + +> [!NOTE] +> You might look at this example and wonder if you might be better off using [instructor](https://python.useinstructor.com/). After all, that library has more support for validation of parameters. This is true, but instructor requires you to learn a fair bit more about each individual backend. If you want to to use claude instead of openai then you will need to load in a different library. Here, you just need to make sure the `llm` plugin is installed and you're good to go. + diff --git a/demo.py b/demo.py new file mode 100644 index 0000000..932bafb --- /dev/null +++ b/demo.py @@ -0,0 +1,19 @@ +from smartfunc import backend +from pydantic import BaseModel +from dotenv import load_dotenv + +load_dotenv(".env") + +class Summary(BaseModel): + summary: str + pros: list[str] + cons: list[str] + +llmify = backend("gpt-4o-mini", system="You are a pirate.", temperature=0.5) + +@llmify +def generate_poke_desc(text: str) -> Summary: + """Describe the following pokemon: {{ text }}""" + pass + +print(generate_poke_desc("pikachu")) \ No newline at end of file diff --git a/imgs/logo.png b/imgs/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..add131331fe2b011a938b879498bd892b25b1d57 GIT binary patch literal 19802 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 E0)yRf?*IS* literal 0 HcmV?d00001 diff --git a/smartfunc/__init__.py b/smartfunc/__init__.py index a86236c..d138bd1 100644 --- a/smartfunc/__init__.py +++ b/smartfunc/__init__.py @@ -180,4 +180,13 @@ async def wrapper(*args, **kwargs): async def run(self, func, *args, **kwargs): new_func = self(func) - return new_func(*args, **kwargs) \ No newline at end of file + return new_func(*args, **kwargs) + + +def get_backend_models(): + for model in llm.get_models(): + print(model.model_id) + +def get_async_backend_models(): + for model in llm.get_async_models(): + print(model.model_id) diff --git a/uv.lock b/uv.lock index d58fbf2..f223a49 100644 --- a/uv.lock +++ b/uv.lock @@ -1,7 +1,562 @@ version = 1 requires-python = ">=3.12" +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, +] + +[[package]] +name = "anyio" +version = "4.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "sniffio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/73/199a98fc2dae33535d6b8e8e6ec01f8c1d76c9adb096c6b7d64823038cde/anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a", size = 181126 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/eb/e7f063ad1fec6b3178a3cd82d1a3c4de82cccf283fc42746168188e1cdd5/anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a", size = 96041 }, +] + +[[package]] +name = "certifi" +version = "2025.1.31" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393 }, +] + +[[package]] +name = "click" +version = "8.1.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "platform_system == 'Windows'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 }, +] + +[[package]] +name = "click-default-group" +version = "1.2.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1d/ce/edb087fb53de63dad3b36408ca30368f438738098e668b78c87f93cd41df/click_default_group-1.2.4.tar.gz", hash = "sha256:eb3f3c99ec0d456ca6cd2a7f08f7d4e91771bef51b01bdd9580cc6450fe1251e", size = 3505 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/1a/aff8bb287a4b1400f69e09a53bd65de96aa5cee5691925b38731c67fc695/click_default_group-1.2.4-py2.py3-none-any.whl", hash = "sha256:9b60486923720e7fc61731bdb32b617039aba820e22e1c88766b1125592eaa5f", size = 4123 }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, +] + +[[package]] +name = "diskcache" +version = "5.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3f/21/1c1ffc1a039ddcc459db43cc108658f32c57d271d7289a2794e401d0fdb6/diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc", size = 67916 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/27/4570e78fc0bf5ea0ca45eb1de3818a23787af9b390c0b0a0033a1b8236f9/diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19", size = 45550 }, +] + +[[package]] +name = "distro" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277 }, +] + +[[package]] +name = "h11" +version = "0.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 }, +] + +[[package]] +name = "httpcore" +version = "1.0.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6a/41/d7d0a89eb493922c37d343b607bc1b5da7f5be7e383740b4753ad8943e90/httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c", size = 85196 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/f5/72347bc88306acb359581ac4d52f23c0ef445b57157adedb9aee0cd689d2/httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd", size = 78551 }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 }, +] + +[[package]] +name = "jiter" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1e/c2/e4562507f52f0af7036da125bb699602ead37a2332af0788f8e0a3417f36/jiter-0.9.0.tar.gz", hash = "sha256:aadba0964deb424daa24492abc3d229c60c4a31bfee205aedbf1acc7639d7893", size = 162604 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/d7/c55086103d6f29b694ec79156242304adf521577530d9031317ce5338c59/jiter-0.9.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7b46249cfd6c48da28f89eb0be3f52d6fdb40ab88e2c66804f546674e539ec11", size = 309203 }, + { url = "https://files.pythonhosted.org/packages/b0/01/f775dfee50beb420adfd6baf58d1c4d437de41c9b666ddf127c065e5a488/jiter-0.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:609cf3c78852f1189894383cf0b0b977665f54cb38788e3e6b941fa6d982c00e", size = 319678 }, + { url = "https://files.pythonhosted.org/packages/ab/b8/09b73a793714726893e5d46d5c534a63709261af3d24444ad07885ce87cb/jiter-0.9.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d726a3890a54561e55a9c5faea1f7655eda7f105bd165067575ace6e65f80bb2", size = 341816 }, + { url = "https://files.pythonhosted.org/packages/35/6f/b8f89ec5398b2b0d344257138182cc090302854ed63ed9c9051e9c673441/jiter-0.9.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2e89dc075c1fef8fa9be219e249f14040270dbc507df4215c324a1839522ea75", size = 364152 }, + { url = "https://files.pythonhosted.org/packages/9b/ca/978cc3183113b8e4484cc7e210a9ad3c6614396e7abd5407ea8aa1458eef/jiter-0.9.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04e8ffa3c353b1bc4134f96f167a2082494351e42888dfcf06e944f2729cbe1d", size = 406991 }, + { url = "https://files.pythonhosted.org/packages/13/3a/72861883e11a36d6aa314b4922125f6ae90bdccc225cd96d24cc78a66385/jiter-0.9.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:203f28a72a05ae0e129b3ed1f75f56bc419d5f91dfacd057519a8bd137b00c42", size = 395824 }, + { url = "https://files.pythonhosted.org/packages/87/67/22728a86ef53589c3720225778f7c5fdb617080e3deaed58b04789418212/jiter-0.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fca1a02ad60ec30bb230f65bc01f611c8608b02d269f998bc29cca8619a919dc", size = 351318 }, + { url = "https://files.pythonhosted.org/packages/69/b9/f39728e2e2007276806d7a6609cda7fac44ffa28ca0d02c49a4f397cc0d9/jiter-0.9.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:237e5cee4d5d2659aaf91bbf8ec45052cc217d9446070699441a91b386ae27dc", size = 384591 }, + { url = "https://files.pythonhosted.org/packages/eb/8f/8a708bc7fd87b8a5d861f1c118a995eccbe6d672fe10c9753e67362d0dd0/jiter-0.9.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:528b6b71745e7326eed73c53d4aa57e2a522242320b6f7d65b9c5af83cf49b6e", size = 520746 }, + { url = "https://files.pythonhosted.org/packages/95/1e/65680c7488bd2365dbd2980adaf63c562d3d41d3faac192ebc7ef5b4ae25/jiter-0.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9f48e86b57bc711eb5acdfd12b6cb580a59cc9a993f6e7dcb6d8b50522dcd50d", size = 512754 }, + { url = "https://files.pythonhosted.org/packages/78/f3/fdc43547a9ee6e93c837685da704fb6da7dba311fc022e2766d5277dfde5/jiter-0.9.0-cp312-cp312-win32.whl", hash = "sha256:699edfde481e191d81f9cf6d2211debbfe4bd92f06410e7637dffb8dd5dfde06", size = 207075 }, + { url = "https://files.pythonhosted.org/packages/cd/9d/742b289016d155f49028fe1bfbeb935c9bf0ffeefdf77daf4a63a42bb72b/jiter-0.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:099500d07b43f61d8bd780466d429c45a7b25411b334c60ca875fa775f68ccb0", size = 207999 }, + { url = "https://files.pythonhosted.org/packages/e7/1b/4cd165c362e8f2f520fdb43245e2b414f42a255921248b4f8b9c8d871ff1/jiter-0.9.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:2764891d3f3e8b18dce2cff24949153ee30c9239da7c00f032511091ba688ff7", size = 308197 }, + { url = "https://files.pythonhosted.org/packages/13/aa/7a890dfe29c84c9a82064a9fe36079c7c0309c91b70c380dc138f9bea44a/jiter-0.9.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:387b22fbfd7a62418d5212b4638026d01723761c75c1c8232a8b8c37c2f1003b", size = 318160 }, + { url = "https://files.pythonhosted.org/packages/6a/38/5888b43fc01102f733f085673c4f0be5a298f69808ec63de55051754e390/jiter-0.9.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d8da8629ccae3606c61d9184970423655fb4e33d03330bcdfe52d234d32f69", size = 341259 }, + { url = "https://files.pythonhosted.org/packages/3d/5e/bbdbb63305bcc01006de683b6228cd061458b9b7bb9b8d9bc348a58e5dc2/jiter-0.9.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1be73d8982bdc278b7b9377426a4b44ceb5c7952073dd7488e4ae96b88e1103", size = 363730 }, + { url = "https://files.pythonhosted.org/packages/75/85/53a3edc616992fe4af6814c25f91ee3b1e22f7678e979b6ea82d3bc0667e/jiter-0.9.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2228eaaaa111ec54b9e89f7481bffb3972e9059301a878d085b2b449fbbde635", size = 405126 }, + { url = "https://files.pythonhosted.org/packages/ae/b3/1ee26b12b2693bd3f0b71d3188e4e5d817b12e3c630a09e099e0a89e28fa/jiter-0.9.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:11509bfecbc319459647d4ac3fd391d26fdf530dad00c13c4dadabf5b81f01a4", size = 393668 }, + { url = "https://files.pythonhosted.org/packages/11/87/e084ce261950c1861773ab534d49127d1517b629478304d328493f980791/jiter-0.9.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f22238da568be8bbd8e0650e12feeb2cfea15eda4f9fc271d3b362a4fa0604d", size = 352350 }, + { url = "https://files.pythonhosted.org/packages/f0/06/7dca84b04987e9df563610aa0bc154ea176e50358af532ab40ffb87434df/jiter-0.9.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:17f5d55eb856597607562257c8e36c42bc87f16bef52ef7129b7da11afc779f3", size = 384204 }, + { url = "https://files.pythonhosted.org/packages/16/2f/82e1c6020db72f397dd070eec0c85ebc4df7c88967bc86d3ce9864148f28/jiter-0.9.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:6a99bed9fbb02f5bed416d137944419a69aa4c423e44189bc49718859ea83bc5", size = 520322 }, + { url = "https://files.pythonhosted.org/packages/36/fd/4f0cd3abe83ce208991ca61e7e5df915aa35b67f1c0633eb7cf2f2e88ec7/jiter-0.9.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e057adb0cd1bd39606100be0eafe742de2de88c79df632955b9ab53a086b3c8d", size = 512184 }, + { url = "https://files.pythonhosted.org/packages/a0/3c/8a56f6d547731a0b4410a2d9d16bf39c861046f91f57c98f7cab3d2aa9ce/jiter-0.9.0-cp313-cp313-win32.whl", hash = "sha256:f7e6850991f3940f62d387ccfa54d1a92bd4bb9f89690b53aea36b4364bcab53", size = 206504 }, + { url = "https://files.pythonhosted.org/packages/f4/1c/0c996fd90639acda75ed7fa698ee5fd7d80243057185dc2f63d4c1c9f6b9/jiter-0.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:c8ae3bf27cd1ac5e6e8b7a27487bf3ab5f82318211ec2e1346a5b058756361f7", size = 204943 }, + { url = "https://files.pythonhosted.org/packages/78/0f/77a63ca7aa5fed9a1b9135af57e190d905bcd3702b36aca46a01090d39ad/jiter-0.9.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f0b2827fb88dda2cbecbbc3e596ef08d69bda06c6f57930aec8e79505dc17001", size = 317281 }, + { url = "https://files.pythonhosted.org/packages/f9/39/a3a1571712c2bf6ec4c657f0d66da114a63a2e32b7e4eb8e0b83295ee034/jiter-0.9.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:062b756ceb1d40b0b28f326cba26cfd575a4918415b036464a52f08632731e5a", size = 350273 }, + { url = "https://files.pythonhosted.org/packages/ee/47/3729f00f35a696e68da15d64eb9283c330e776f3b5789bac7f2c0c4df209/jiter-0.9.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6f7838bc467ab7e8ef9f387bd6de195c43bad82a569c1699cb822f6609dd4cdf", size = 206867 }, +] + +[[package]] +name = "llm" +version = "0.23" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "click-default-group" }, + { name = "openai" }, + { name = "pip" }, + { name = "pluggy" }, + { name = "puremagic" }, + { name = "pydantic" }, + { name = "pyreadline3", marker = "sys_platform == 'win32'" }, + { name = "python-ulid" }, + { name = "pyyaml" }, + { name = "setuptools" }, + { name = "sqlite-migrate" }, + { name = "sqlite-utils" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/0d/012b8d57d78f247c5f3878d3911e7431a8c7c4b8a6ecd9c984145ed019d3/llm-0.23.tar.gz", hash = "sha256:552e549a46cbcae6f3414b8f5952d6651a7f8b60b5f09444057a7a52793a6c8e", size = 49966 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/79/a80563b03fb3d0097ce344fd12e5463b90295a9d6aa1210a9a2e03e22f4e/llm-0.23-py3-none-any.whl", hash = "sha256:3c6fe7ee80104e0e5dee0eb98a1b2ad00d4874535bbf6fe9578380062cf1ee6d", size = 51602 }, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 }, + { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 }, + { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 }, + { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 }, + { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 }, + { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 }, + { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 }, + { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 }, + { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 }, + { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 }, + { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 }, + { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 }, + { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 }, + { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 }, + { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 }, + { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 }, + { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 }, + { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 }, + { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 }, + { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 }, + { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 }, + { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 }, + { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 }, + { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 }, + { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 }, + { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 }, + { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 }, + { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 }, + { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 }, + { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 }, +] + +[[package]] +name = "openai" +version = "1.66.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "httpx" }, + { name = "jiter" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d8/e1/b3e1fda1aa32d4f40d4de744e91de4de65c854c3e53c63342e4b5f9c5995/openai-1.66.2.tar.gz", hash = "sha256:9b3a843c25f81ee09b6469d483d9fba779d5c6ea41861180772f043481b0598d", size = 397041 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/6f/3315b3583ffe3e31c55b446cb22d2a7c235e65ca191674fffae62deb3c11/openai-1.66.2-py3-none-any.whl", hash = "sha256:75194057ee6bb8b732526387b6041327a05656d976fc21c064e21c8ac6b07999", size = 567268 }, +] + +[[package]] +name = "packaging" +version = "24.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, +] + +[[package]] +name = "pip" +version = "25.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/70/53/b309b4a497b09655cb7e07088966881a57d082f48ac3cb54ea729fd2c6cf/pip-25.0.1.tar.gz", hash = "sha256:88f96547ea48b940a3a385494e181e29fb8637898f88d88737c5049780f196ea", size = 1950850 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c9/bc/b7db44f5f39f9d0494071bddae6880eb645970366d0a200022a1a93d57f5/pip-25.0.1-py3-none-any.whl", hash = "sha256:c46efd13b6aa8279f33f2864459c8ce587ea6a1a59ee20de055868d8f7688f7f", size = 1841526 }, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, +] + +[[package]] +name = "puremagic" +version = "1.28" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/09/2d/40599f25667733e41bbc3d7e4c7c36d5e7860874aa5fe9c584e90b34954d/puremagic-1.28.tar.gz", hash = "sha256:195893fc129657f611b86b959aab337207d6df7f25372209269ed9e303c1a8c0", size = 314945 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/53/200a97332d10ed3edd7afcbc5f5543920ac59badfe5762598327999f012e/puremagic-1.28-py3-none-any.whl", hash = "sha256:e16cb9708ee2007142c37931c58f07f7eca956b3472489106a7245e5c3aa1241", size = 43241 }, +] + +[[package]] +name = "pydantic" +version = "2.10.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b7/ae/d5220c5c52b158b1de7ca89fc5edb72f304a70a4c540c84c8844bf4008de/pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236", size = 761681 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584", size = 431696 }, +] + +[[package]] +name = "pydantic-core" +version = "2.27.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443 } +wheels = [ + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/9b/67/4e197c300976af185b7cef4c02203e175fb127e414125916bf1128b639a9/pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", size = 1834064 }, + { url = "https://files.pythonhosted.org/packages/1f/ea/cd7209a889163b8dcca139fe32b9687dd05249161a3edda62860430457a5/pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", size = 1989046 }, + { url = "https://files.pythonhosted.org/packages/bc/49/c54baab2f4658c26ac633d798dab66b4c3a9bbf47cff5284e9c182f4137a/pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", size = 1885092 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/a4/99/bddde3ddde76c03b65dfd5a66ab436c4e58ffc42927d4ff1198ffbf96f5f/pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", size = 1834387 }, + { url = "https://files.pythonhosted.org/packages/71/47/82b5e846e01b26ac6f1893d3c5f9f3a2eb6ba79be26eef0b759b4fe72946/pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", size = 1990453 }, + { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186 }, +] + +[[package]] +name = "pyreadline3" +version = "3.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/49/4cea918a08f02817aabae639e3d0ac046fef9f9180518a3ad394e22da148/pyreadline3-3.5.4.tar.gz", hash = "sha256:8d57d53039a1c75adba8e50dd3d992b28143480816187ea5efbd5c78e6c885b7", size = 99839 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/dc/491b7661614ab97483abf2056be1deee4dc2490ecbf7bff9ab5cdbac86e1/pyreadline3-3.5.4-py3-none-any.whl", hash = "sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6", size = 83178 }, +] + +[[package]] +name = "pytest" +version = "8.3.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634 }, +] + +[[package]] +name = "pytest-asyncio" +version = "0.25.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f2/a8/ecbc8ede70921dd2f544ab1cadd3ff3bf842af27f87bbdea774c7baa1d38/pytest_asyncio-0.25.3.tar.gz", hash = "sha256:fc1da2cf9f125ada7e710b4ddad05518d4cee187ae9412e9ac9271003497f07a", size = 54239 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/17/3493c5624e48fd97156ebaec380dcaafee9506d7e2c46218ceebbb57d7de/pytest_asyncio-0.25.3-py3-none-any.whl", hash = "sha256:9e89518e0f9bd08928f97a3482fdc4e244df17529460bc038291ccaf8f85c7c3", size = 19467 }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, +] + +[[package]] +name = "python-ulid" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/db/e5e67aeca9c2420cb91f94007f30693cc3628ae9783a565fd33ffb3fbfdd/python_ulid-3.0.0.tar.gz", hash = "sha256:e50296a47dc8209d28629a22fc81ca26c00982c78934bd7766377ba37ea49a9f", size = 28822 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/4e/cc2ba2c0df2589f35a4db8473b8c2ba9bbfc4acdec4a94f1c78934d2350f/python_ulid-3.0.0-py3-none-any.whl", hash = "sha256:e4c4942ff50dbd79167ad01ac725ec58f924b4018025ce22c858bfcff99a5e31", size = 11194 }, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 } +wheels = [ + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 }, + { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 }, + { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, +] + +[[package]] +name = "setuptools" +version = "76.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/32/d2/7b171caf085ba0d40d8391f54e1c75a1cda9255f542becf84575cfd8a732/setuptools-76.0.0.tar.gz", hash = "sha256:43b4ee60e10b0d0ee98ad11918e114c70701bc6051662a9a675a0496c1a158f4", size = 1349387 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/37/66/d2d7e6ad554f3a7c7297c3f8ef6e22643ad3d35ef5c63bf488bc89f32f31/setuptools-76.0.0-py3-none-any.whl", hash = "sha256:199466a166ff664970d0ee145839f5582cb9bca7a0a3a2e795b6a9cb2308e9c6", size = 1236106 }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, +] + [[package]] name = "smartfunc" version = "0.1.0" source = { editable = "." } +dependencies = [ + { name = "diskcache" }, + { name = "jinja2" }, + { name = "llm" }, + { name = "pydantic" }, +] + +[package.optional-dependencies] +test = [ + { name = "pytest" }, + { name = "pytest-asyncio" }, +] + +[package.metadata] +requires-dist = [ + { name = "diskcache", specifier = ">=5.0.0" }, + { name = "jinja2", specifier = ">=3.0.0" }, + { name = "llm" }, + { name = "pydantic", specifier = ">=2.0.0" }, + { name = "pytest", marker = "extra == 'test'", specifier = ">=7.0.0" }, + { name = "pytest-asyncio", marker = "extra == 'test'", specifier = ">=0.21.0" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, +] + +[[package]] +name = "sqlite-fts4" +version = "1.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c2/6d/9dad6c3b433ab8912ace969c66abd595f8e0a2ccccdb73602b1291dbda29/sqlite-fts4-1.0.3.tar.gz", hash = "sha256:78b05eeaf6680e9dbed8986bde011e9c086a06cb0c931b3cf7da94c214e8930c", size = 9718 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/29/0096e8b1811aaa78cfb296996f621f41120c21c2f5cd448ae1d54979d9fc/sqlite_fts4-1.0.3-py3-none-any.whl", hash = "sha256:0359edd8dea6fd73c848989e1e2b1f31a50fe5f9d7272299ff0e8dbaa62d035f", size = 9972 }, +] + +[[package]] +name = "sqlite-migrate" +version = "0.1b0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sqlite-utils" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/13/86/1463a00d3c4bdb707c0ed4077d17687465a0aa9444593f66f6c4b49e39b5/sqlite-migrate-0.1b0.tar.gz", hash = "sha256:8d502b3ca4b9c45e56012bd35c03d23235f0823c976d4ce940cbb40e33087ded", size = 10736 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/92/994545b912e6d6feb40323047f02ca039321e690aa2c27afcd5c4105e37b/sqlite_migrate-0.1b0-py3-none-any.whl", hash = "sha256:a4125e35e1de3dc56b6b6ec60e9833ce0ce20192b929ddcb2d4246c5098859c6", size = 9986 }, +] + +[[package]] +name = "sqlite-utils" +version = "3.38" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "click-default-group" }, + { name = "pluggy" }, + { name = "python-dateutil" }, + { name = "sqlite-fts4" }, + { name = "tabulate" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/51/43/ce9183a21911e0b73248c8fb83f8b8038515cb80053912c2a009e9765564/sqlite_utils-3.38.tar.gz", hash = "sha256:1ae77b931384052205a15478d429464f6c67a3ac3b4eafd3c674ac900f623aab", size = 214449 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/eb/f8e8e827805f810838efff3311cccd2601238c5fa3fc35c1f878709e161b/sqlite_utils-3.38-py3-none-any.whl", hash = "sha256:8a27441015c3b2ef475f555861f7a2592f73bc60d247af9803a11b65fc605bf9", size = 68183 }, +] + +[[package]] +name = "tabulate" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/fe/802052aecb21e3797b8f7902564ab6ea0d60ff8ca23952079064155d1ae1/tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c", size = 81090 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f", size = 35252 }, +] + +[[package]] +name = "tqdm" +version = "4.67.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "platform_system == 'Windows'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540 }, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, +] From cb58c81ac7bb34d647ffd2fe2098f274d808dd38 Mon Sep 17 00:00:00 2001 From: vincent d warmerdam Date: Wed, 12 Mar 2025 15:49:40 +0100 Subject: [PATCH 2/2] readme --- README.md | 42 ++++++++++++++++++++++++++++++++++++++---- demo.py | 19 ------------------- 2 files changed, 38 insertions(+), 23 deletions(-) delete mode 100644 demo.py diff --git a/README.md b/README.md index 6509bc0..a5f8f42 100644 --- a/README.md +++ b/README.md @@ -40,18 +40,23 @@ The `llm` library is minimalistic and while it does not support all the features ## Extra features +### Schemas + The following snippet shows how you might create a re-useable backend decorator that uses a system prompt. Also notice how we're able to use a Pydantic model to define the response. ```python from smartfunc import backend from pydantic import BaseModel +from dotenv import load_dotenv + +load_dotenv(".env") class Summary(BaseModel): summary: str pros: list[str] cons: list[str] -llmify = backend("gpt-4", system="You are a helpful assistant.", temperature=0.5) +llmify = backend("gpt-4o-mini", system="You are a helpful assistant.", temperature=0.5) @llmify def generate_poke_desc(text: str) -> Summary: @@ -63,7 +68,7 @@ print(generate_poke_desc("pikachu")) This is the result that we got back: -``` +```python { 'summary': 'Pikachu is a small, electric-type Pokémon known for its adorable appearance and strong electrical abilities. It is recognized as the mascot of the Pokémon franchise, with distinctive features and a cheerful personality.', 'pros': [ @@ -82,7 +87,36 @@ This is the result that we got back: } ``` +Not every backend supports schemas, but you will a helpful error message if that is the case. + +> [!NOTE] +> You might look at this example and wonder if you might be better off using [instructor](https://python.useinstructor.com/). After all, that library has more support for validation of parameters and even has some utilities for multi-turn conversations. All of this is true, but instructor requires you to learn a fair bit more about each individual backend. If you want to to use claude instead of openai then you will need to load in a different library. Here, you just need to make sure the `llm` plugin is installed and you're good to go. + + +### Async + +The library also supports async functions. This is useful if you want to do microbatching or if you want to use the async backends from the `llm` library. + +```python +import asyncio +from smartfunc import async_backend +from pydantic import BaseModel +from dotenv import load_dotenv + +load_dotenv(".env") + -> [!NOTE] -> You might look at this example and wonder if you might be better off using [instructor](https://python.useinstructor.com/). After all, that library has more support for validation of parameters. This is true, but instructor requires you to learn a fair bit more about each individual backend. If you want to to use claude instead of openai then you will need to load in a different library. Here, you just need to make sure the `llm` plugin is installed and you're good to go. +class Summary(BaseModel): + summary: str + pros: list[str] + cons: list[str] + +@async_backend("gpt-4o-mini") +async def generate_poke_desc(text: str) -> Summary: + """Describe the following pokemon: {{ text }}""" + pass + +resp = asyncio.run(generate_poke_desc("pikachu")) +print(resp) +``` diff --git a/demo.py b/demo.py deleted file mode 100644 index 932bafb..0000000 --- a/demo.py +++ /dev/null @@ -1,19 +0,0 @@ -from smartfunc import backend -from pydantic import BaseModel -from dotenv import load_dotenv - -load_dotenv(".env") - -class Summary(BaseModel): - summary: str - pros: list[str] - cons: list[str] - -llmify = backend("gpt-4o-mini", system="You are a pirate.", temperature=0.5) - -@llmify -def generate_poke_desc(text: str) -> Summary: - """Describe the following pokemon: {{ text }}""" - pass - -print(generate_poke_desc("pikachu")) \ No newline at end of file