diff --git a/poetry.lock b/poetry.lock index e4bce3b3e..37b092147 100644 --- a/poetry.lock +++ b/poetry.lock @@ -13,87 +13,87 @@ files = [ [[package]] name = "aiohttp" -version = "3.9.0" +version = "3.9.1" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.8" files = [ - {file = "aiohttp-3.9.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6896b8416be9ada4d22cd359d7cb98955576ce863eadad5596b7cdfbf3e17c6c"}, - {file = "aiohttp-3.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1736d87dad8ef46a8ec9cddd349fa9f7bd3a064c47dd6469c0d6763d3d49a4fc"}, - {file = "aiohttp-3.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8c9e5f4d7208cda1a2bb600e29069eecf857e6980d0ccc922ccf9d1372c16f4b"}, - {file = "aiohttp-3.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8488519aa05e636c5997719fe543c8daf19f538f4fa044f3ce94bee608817cff"}, - {file = "aiohttp-3.9.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ab16c254e2312efeb799bc3c06897f65a133b38b69682bf75d1f1ee1a9c43a9"}, - {file = "aiohttp-3.9.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7a94bde005a8f926d0fa38b88092a03dea4b4875a61fbcd9ac6f4351df1b57cd"}, - {file = "aiohttp-3.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b777c9286b6c6a94f50ddb3a6e730deec327e9e2256cb08b5530db0f7d40fd8"}, - {file = "aiohttp-3.9.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:571760ad7736b34d05597a1fd38cbc7d47f7b65deb722cb8e86fd827404d1f6b"}, - {file = "aiohttp-3.9.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:deac0a32aec29608eb25d730f4bc5a261a65b6c48ded1ed861d2a1852577c932"}, - {file = "aiohttp-3.9.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:4ee1b4152bc3190cc40ddd6a14715e3004944263ea208229ab4c297712aa3075"}, - {file = "aiohttp-3.9.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:3607375053df58ed6f23903aa10cf3112b1240e8c799d243bbad0f7be0666986"}, - {file = "aiohttp-3.9.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:65b0a70a25456d329a5e1426702dde67be0fb7a4ead718005ba2ca582d023a94"}, - {file = "aiohttp-3.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5a2eb5311a37fe105aa35f62f75a078537e1a9e4e1d78c86ec9893a3c97d7a30"}, - {file = "aiohttp-3.9.0-cp310-cp310-win32.whl", hash = "sha256:2cbc14a13fb6b42d344e4f27746a4b03a2cb0c1c3c5b932b0d6ad8881aa390e3"}, - {file = "aiohttp-3.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:ac9669990e2016d644ba8ae4758688534aabde8dbbc81f9af129c3f5f01ca9cd"}, - {file = "aiohttp-3.9.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f8e05f5163528962ce1d1806fce763ab893b1c5b7ace0a3538cd81a90622f844"}, - {file = "aiohttp-3.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4afa8f71dba3a5a2e1e1282a51cba7341ae76585345c43d8f0e624882b622218"}, - {file = "aiohttp-3.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f929f4c9b9a00f3e6cc0587abb95ab9c05681f8b14e0fe1daecfa83ea90f8318"}, - {file = "aiohttp-3.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28185e36a78d247c55e9fbea2332d16aefa14c5276a582ce7a896231c6b1c208"}, - {file = "aiohttp-3.9.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a486ddf57ab98b6d19ad36458b9f09e6022de0381674fe00228ca7b741aacb2f"}, - {file = "aiohttp-3.9.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70e851f596c00f40a2f00a46126c95c2e04e146015af05a9da3e4867cfc55911"}, - {file = "aiohttp-3.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5b7bf8fe4d39886adc34311a233a2e01bc10eb4e842220235ed1de57541a896"}, - {file = "aiohttp-3.9.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c67a51ea415192c2e53e4e048c78bab82d21955b4281d297f517707dc836bf3d"}, - {file = "aiohttp-3.9.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:694df243f394629bcae2d8ed94c589a181e8ba8604159e6e45e7b22e58291113"}, - {file = "aiohttp-3.9.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3dd8119752dd30dd7bca7d4bc2a92a59be6a003e4e5c2cf7e248b89751b8f4b7"}, - {file = "aiohttp-3.9.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:eb6dfd52063186ac97b4caa25764cdbcdb4b10d97f5c5f66b0fa95052e744eb7"}, - {file = "aiohttp-3.9.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:d97c3e286d0ac9af6223bc132dc4bad6540b37c8d6c0a15fe1e70fb34f9ec411"}, - {file = "aiohttp-3.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:816f4db40555026e4cdda604a1088577c1fb957d02f3f1292e0221353403f192"}, - {file = "aiohttp-3.9.0-cp311-cp311-win32.whl", hash = "sha256:3abf0551874fecf95f93b58f25ef4fc9a250669a2257753f38f8f592db85ddea"}, - {file = "aiohttp-3.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:e18d92c3e9e22553a73e33784fcb0ed484c9874e9a3e96c16a8d6a1e74a0217b"}, - {file = "aiohttp-3.9.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:99ae01fb13a618b9942376df77a1f50c20a281390dad3c56a6ec2942e266220d"}, - {file = "aiohttp-3.9.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:05857848da443c8c12110d99285d499b4e84d59918a21132e45c3f0804876994"}, - {file = "aiohttp-3.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:317719d7f824eba55857fe0729363af58e27c066c731bc62cd97bc9c3d9c7ea4"}, - {file = "aiohttp-3.9.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1e3b3c107ccb0e537f309f719994a55621acd2c8fdf6d5ce5152aed788fb940"}, - {file = "aiohttp-3.9.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45820ddbb276113ead8d4907a7802adb77548087ff5465d5c554f9aa3928ae7d"}, - {file = "aiohttp-3.9.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:05a183f1978802588711aed0dea31e697d760ce9055292db9dc1604daa9a8ded"}, - {file = "aiohttp-3.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51a4cd44788ea0b5e6bb8fa704597af3a30be75503a7ed1098bc5b8ffdf6c982"}, - {file = "aiohttp-3.9.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:673343fbc0c1ac44d0d2640addc56e97a052504beacd7ade0dc5e76d3a4c16e8"}, - {file = "aiohttp-3.9.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7e8a3b79b6d186a9c99761fd4a5e8dd575a48d96021f220ac5b5fa856e5dd029"}, - {file = "aiohttp-3.9.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6777a390e41e78e7c45dab43a4a0196c55c3b8c30eebe017b152939372a83253"}, - {file = "aiohttp-3.9.0-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7ae5f99a32c53731c93ac3075abd3e1e5cfbe72fc3eaac4c27c9dd64ba3b19fe"}, - {file = "aiohttp-3.9.0-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:f1e4f254e9c35d8965d377e065c4a8a55d396fe87c8e7e8429bcfdeeb229bfb3"}, - {file = "aiohttp-3.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:11ca808f9a6b63485059f5f6e164ef7ec826483c1212a44f268b3653c91237d8"}, - {file = "aiohttp-3.9.0-cp312-cp312-win32.whl", hash = "sha256:de3cc86f4ea8b4c34a6e43a7306c40c1275e52bfa9748d869c6b7d54aa6dad80"}, - {file = "aiohttp-3.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:ca4fddf84ac7d8a7d0866664936f93318ff01ee33e32381a115b19fb5a4d1202"}, - {file = "aiohttp-3.9.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:f09960b5bb1017d16c0f9e9f7fc42160a5a49fa1e87a175fd4a2b1a1833ea0af"}, - {file = "aiohttp-3.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8303531e2c17b1a494ffaeba48f2da655fe932c4e9a2626c8718403c83e5dd2b"}, - {file = "aiohttp-3.9.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4790e44f46a4aa07b64504089def5744d3b6780468c4ec3a1a36eb7f2cae9814"}, - {file = "aiohttp-3.9.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1d7edf74a36de0e5ca50787e83a77cf352f5504eb0ffa3f07000a911ba353fb"}, - {file = "aiohttp-3.9.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:94697c7293199c2a2551e3e3e18438b4cba293e79c6bc2319f5fd652fccb7456"}, - {file = "aiohttp-3.9.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a1b66dbb8a7d5f50e9e2ea3804b01e766308331d0cac76eb30c563ac89c95985"}, - {file = "aiohttp-3.9.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9623cfd9e85b76b83ef88519d98326d4731f8d71869867e47a0b979ffec61c73"}, - {file = "aiohttp-3.9.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f32c86dc967ab8c719fd229ce71917caad13cc1e8356ee997bf02c5b368799bf"}, - {file = "aiohttp-3.9.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f50b4663c3e0262c3a361faf440761fbef60ccdde5fe8545689a4b3a3c149fb4"}, - {file = "aiohttp-3.9.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:dcf71c55ec853826cd70eadb2b6ac62ec577416442ca1e0a97ad875a1b3a0305"}, - {file = "aiohttp-3.9.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:42fe4fd9f0dfcc7be4248c162d8056f1d51a04c60e53366b0098d1267c4c9da8"}, - {file = "aiohttp-3.9.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:76a86a9989ebf82ee61e06e2bab408aec4ea367dc6da35145c3352b60a112d11"}, - {file = "aiohttp-3.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f9e09a1c83521d770d170b3801eea19b89f41ccaa61d53026ed111cb6f088887"}, - {file = "aiohttp-3.9.0-cp38-cp38-win32.whl", hash = "sha256:a00ce44c21612d185c5275c5cba4bab8d7c1590f248638b667ed8a782fa8cd6f"}, - {file = "aiohttp-3.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:d5b9345ab92ebe6003ae11d8092ce822a0242146e6fa270889b9ba965457ca40"}, - {file = "aiohttp-3.9.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:98d21092bf2637c5fa724a428a69e8f5955f2182bff61f8036827cf6ce1157bf"}, - {file = "aiohttp-3.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:35a68cd63ca6aaef5707888f17a70c36efe62b099a4e853d33dc2e9872125be8"}, - {file = "aiohttp-3.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3d7f6235c7475658acfc1769d968e07ab585c79f6ca438ddfecaa9a08006aee2"}, - {file = "aiohttp-3.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db04d1de548f7a62d1dd7e7cdf7c22893ee168e22701895067a28a8ed51b3735"}, - {file = "aiohttp-3.9.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:536b01513d67d10baf6f71c72decdf492fb7433c5f2f133e9a9087379d4b6f31"}, - {file = "aiohttp-3.9.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c8b0a6487e8109427ccf638580865b54e2e3db4a6e0e11c02639231b41fc0f"}, - {file = "aiohttp-3.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7276fe0017664414fdc3618fca411630405f1aaf0cc3be69def650eb50441787"}, - {file = "aiohttp-3.9.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:23170247ef89ffa842a02bbfdc425028574d9e010611659abeb24d890bc53bb8"}, - {file = "aiohttp-3.9.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b1a2ea8252cacc7fd51df5a56d7a2bb1986ed39be9397b51a08015727dfb69bd"}, - {file = "aiohttp-3.9.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2d71abc15ff7047412ef26bf812dfc8d0d1020d664617f4913df2df469f26b76"}, - {file = "aiohttp-3.9.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:2d820162c8c2bdbe97d328cd4f417c955ca370027dce593345e437b2e9ffdc4d"}, - {file = "aiohttp-3.9.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:2779f5e7c70f7b421915fd47db332c81de365678180a9f3ab404088f87ba5ff9"}, - {file = "aiohttp-3.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:366bc870d7ac61726f32a489fbe3d1d8876e87506870be66b01aeb84389e967e"}, - {file = "aiohttp-3.9.0-cp39-cp39-win32.whl", hash = "sha256:1df43596b826022b14998f0460926ce261544fedefe0d2f653e1b20f49e96454"}, - {file = "aiohttp-3.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:9c196b30f1b1aa3363a69dd69079ae9bec96c2965c4707eaa6914ba099fb7d4f"}, - {file = "aiohttp-3.9.0.tar.gz", hash = "sha256:09f23292d29135025e19e8ff4f0a68df078fe4ee013bca0105b2e803989de92d"}, + {file = "aiohttp-3.9.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e1f80197f8b0b846a8d5cf7b7ec6084493950d0882cc5537fb7b96a69e3c8590"}, + {file = "aiohttp-3.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c72444d17777865734aa1a4d167794c34b63e5883abb90356a0364a28904e6c0"}, + {file = "aiohttp-3.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9b05d5cbe9dafcdc733262c3a99ccf63d2f7ce02543620d2bd8db4d4f7a22f83"}, + {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c4fa235d534b3547184831c624c0b7c1e262cd1de847d95085ec94c16fddcd5"}, + {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:289ba9ae8e88d0ba16062ecf02dd730b34186ea3b1e7489046fc338bdc3361c4"}, + {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bff7e2811814fa2271be95ab6e84c9436d027a0e59665de60edf44e529a42c1f"}, + {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81b77f868814346662c96ab36b875d7814ebf82340d3284a31681085c051320f"}, + {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b9c7426923bb7bd66d409da46c41e3fb40f5caf679da624439b9eba92043fa6"}, + {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8d44e7bf06b0c0a70a20f9100af9fcfd7f6d9d3913e37754c12d424179b4e48f"}, + {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:22698f01ff5653fe66d16ffb7658f582a0ac084d7da1323e39fd9eab326a1f26"}, + {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ca7ca5abfbfe8d39e653870fbe8d7710be7a857f8a8386fc9de1aae2e02ce7e4"}, + {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:8d7f98fde213f74561be1d6d3fa353656197f75d4edfbb3d94c9eb9b0fc47f5d"}, + {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5216b6082c624b55cfe79af5d538e499cd5f5b976820eac31951fb4325974501"}, + {file = "aiohttp-3.9.1-cp310-cp310-win32.whl", hash = "sha256:0e7ba7ff228c0d9a2cd66194e90f2bca6e0abca810b786901a569c0de082f489"}, + {file = "aiohttp-3.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:c7e939f1ae428a86e4abbb9a7c4732bf4706048818dfd979e5e2839ce0159f23"}, + {file = "aiohttp-3.9.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:df9cf74b9bc03d586fc53ba470828d7b77ce51b0582d1d0b5b2fb673c0baa32d"}, + {file = "aiohttp-3.9.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ecca113f19d5e74048c001934045a2b9368d77b0b17691d905af18bd1c21275e"}, + {file = "aiohttp-3.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8cef8710fb849d97c533f259103f09bac167a008d7131d7b2b0e3a33269185c0"}, + {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bea94403a21eb94c93386d559bce297381609153e418a3ffc7d6bf772f59cc35"}, + {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91c742ca59045dce7ba76cab6e223e41d2c70d79e82c284a96411f8645e2afff"}, + {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6c93b7c2e52061f0925c3382d5cb8980e40f91c989563d3d32ca280069fd6a87"}, + {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee2527134f95e106cc1653e9ac78846f3a2ec1004cf20ef4e02038035a74544d"}, + {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11ff168d752cb41e8492817e10fb4f85828f6a0142b9726a30c27c35a1835f01"}, + {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b8c3a67eb87394386847d188996920f33b01b32155f0a94f36ca0e0c635bf3e3"}, + {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c7b5d5d64e2a14e35a9240b33b89389e0035e6de8dbb7ffa50d10d8b65c57449"}, + {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:69985d50a2b6f709412d944ffb2e97d0be154ea90600b7a921f95a87d6f108a2"}, + {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:c9110c06eaaac7e1f5562caf481f18ccf8f6fdf4c3323feab28a93d34cc646bd"}, + {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d737e69d193dac7296365a6dcb73bbbf53bb760ab25a3727716bbd42022e8d7a"}, + {file = "aiohttp-3.9.1-cp311-cp311-win32.whl", hash = "sha256:4ee8caa925aebc1e64e98432d78ea8de67b2272252b0a931d2ac3bd876ad5544"}, + {file = "aiohttp-3.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:a34086c5cc285be878622e0a6ab897a986a6e8bf5b67ecb377015f06ed316587"}, + {file = "aiohttp-3.9.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f800164276eec54e0af5c99feb9494c295118fc10a11b997bbb1348ba1a52065"}, + {file = "aiohttp-3.9.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:500f1c59906cd142d452074f3811614be04819a38ae2b3239a48b82649c08821"}, + {file = "aiohttp-3.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0b0a6a36ed7e164c6df1e18ee47afbd1990ce47cb428739d6c99aaabfaf1b3af"}, + {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69da0f3ed3496808e8cbc5123a866c41c12c15baaaead96d256477edf168eb57"}, + {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:176df045597e674fa950bf5ae536be85699e04cea68fa3a616cf75e413737eb5"}, + {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b796b44111f0cab6bbf66214186e44734b5baab949cb5fb56154142a92989aeb"}, + {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f27fdaadce22f2ef950fc10dcdf8048407c3b42b73779e48a4e76b3c35bca26c"}, + {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcb6532b9814ea7c5a6a3299747c49de30e84472fa72821b07f5a9818bce0f66"}, + {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:54631fb69a6e44b2ba522f7c22a6fb2667a02fd97d636048478db2fd8c4e98fe"}, + {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4b4c452d0190c5a820d3f5c0f3cd8a28ace48c54053e24da9d6041bf81113183"}, + {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:cae4c0c2ca800c793cae07ef3d40794625471040a87e1ba392039639ad61ab5b"}, + {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:565760d6812b8d78d416c3c7cfdf5362fbe0d0d25b82fed75d0d29e18d7fc30f"}, + {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:54311eb54f3a0c45efb9ed0d0a8f43d1bc6060d773f6973efd90037a51cd0a3f"}, + {file = "aiohttp-3.9.1-cp312-cp312-win32.whl", hash = "sha256:85c3e3c9cb1d480e0b9a64c658cd66b3cfb8e721636ab8b0e746e2d79a7a9eed"}, + {file = "aiohttp-3.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:11cb254e397a82efb1805d12561e80124928e04e9c4483587ce7390b3866d213"}, + {file = "aiohttp-3.9.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8a22a34bc594d9d24621091d1b91511001a7eea91d6652ea495ce06e27381f70"}, + {file = "aiohttp-3.9.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:598db66eaf2e04aa0c8900a63b0101fdc5e6b8a7ddd805c56d86efb54eb66672"}, + {file = "aiohttp-3.9.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2c9376e2b09895c8ca8b95362283365eb5c03bdc8428ade80a864160605715f1"}, + {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41473de252e1797c2d2293804e389a6d6986ef37cbb4a25208de537ae32141dd"}, + {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c5857612c9813796960c00767645cb5da815af16dafb32d70c72a8390bbf690"}, + {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffcd828e37dc219a72c9012ec44ad2e7e3066bec6ff3aaa19e7d435dbf4032ca"}, + {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:219a16763dc0294842188ac8a12262b5671817042b35d45e44fd0a697d8c8361"}, + {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f694dc8a6a3112059258a725a4ebe9acac5fe62f11c77ac4dcf896edfa78ca28"}, + {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bcc0ea8d5b74a41b621ad4a13d96c36079c81628ccc0b30cfb1603e3dfa3a014"}, + {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:90ec72d231169b4b8d6085be13023ece8fa9b1bb495e4398d847e25218e0f431"}, + {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:cf2a0ac0615842b849f40c4d7f304986a242f1e68286dbf3bd7a835e4f83acfd"}, + {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:0e49b08eafa4f5707ecfb321ab9592717a319e37938e301d462f79b4e860c32a"}, + {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2c59e0076ea31c08553e868cec02d22191c086f00b44610f8ab7363a11a5d9d8"}, + {file = "aiohttp-3.9.1-cp38-cp38-win32.whl", hash = "sha256:4831df72b053b1eed31eb00a2e1aff6896fb4485301d4ccb208cac264b648db4"}, + {file = "aiohttp-3.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:3135713c5562731ee18f58d3ad1bf41e1d8883eb68b363f2ffde5b2ea4b84cc7"}, + {file = "aiohttp-3.9.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cfeadf42840c1e870dc2042a232a8748e75a36b52d78968cda6736de55582766"}, + {file = "aiohttp-3.9.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:70907533db712f7aa791effb38efa96f044ce3d4e850e2d7691abd759f4f0ae0"}, + {file = "aiohttp-3.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cdefe289681507187e375a5064c7599f52c40343a8701761c802c1853a504558"}, + {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7481f581251bb5558ba9f635db70908819caa221fc79ee52a7f58392778c636"}, + {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:49f0c1b3c2842556e5de35f122fc0f0b721334ceb6e78c3719693364d4af8499"}, + {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0d406b01a9f5a7e232d1b0d161b40c05275ffbcbd772dc18c1d5a570961a1ca4"}, + {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d8e4450e7fe24d86e86b23cc209e0023177b6d59502e33807b732d2deb6975f"}, + {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c0266cd6f005e99f3f51e583012de2778e65af6b73860038b968a0a8888487a"}, + {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab221850108a4a063c5b8a70f00dd7a1975e5a1713f87f4ab26a46e5feac5a0e"}, + {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c88a15f272a0ad3d7773cf3a37cc7b7d077cbfc8e331675cf1346e849d97a4e5"}, + {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:237533179d9747080bcaad4d02083ce295c0d2eab3e9e8ce103411a4312991a0"}, + {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:02ab6006ec3c3463b528374c4cdce86434e7b89ad355e7bf29e2f16b46c7dd6f"}, + {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04fa38875e53eb7e354ece1607b1d2fdee2d175ea4e4d745f6ec9f751fe20c7c"}, + {file = "aiohttp-3.9.1-cp39-cp39-win32.whl", hash = "sha256:82eefaf1a996060602f3cc1112d93ba8b201dbf5d8fd9611227de2003dddb3b7"}, + {file = "aiohttp-3.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:9b05d33ff8e6b269e30a7957bd3244ffbce2a7a35a81b81c382629b80af1a8bf"}, + {file = "aiohttp-3.9.1.tar.gz", hash = "sha256:8fc49a87ac269d4529da45871e2ffb6874e87779c3d0e2ccd813c0899221239d"}, ] [package.dependencies] @@ -411,32 +411,32 @@ files = [ [[package]] name = "boto3" -version = "1.29.6" +version = "1.29.7" description = "The AWS SDK for Python" optional = false python-versions = ">= 3.7" files = [ - {file = "boto3-1.29.6-py3-none-any.whl", hash = "sha256:f4d19e01d176c3a5a05e4af733185ff1891b08a3c38d4a439800fa132aa6e9be"}, - {file = "boto3-1.29.6.tar.gz", hash = "sha256:d1d0d979a70bf9b0b13ae3b017f8523708ad953f62d16f39a602d67ee9b25554"}, + {file = "boto3-1.29.7-py3-none-any.whl", hash = "sha256:96e9890ebe7cd823b5f4976dd676e112c000c6528c28e20a2f274590589dd18b"}, + {file = "boto3-1.29.7.tar.gz", hash = "sha256:1eb4c548118b5fc5e018dee956fd33e6fb249cd1f2def85f1bba816aef4d9f3e"}, ] [package.dependencies] -botocore = ">=1.32.6,<1.33.0" +botocore = ">=1.32.7,<1.33.0" jmespath = ">=0.7.1,<2.0.0" -s3transfer = ">=0.7.0,<0.8.0" +s3transfer = ">=0.8.0,<0.9.0" [package.extras] crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.32.6" +version = "1.32.7" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">= 3.7" files = [ - {file = "botocore-1.32.6-py3-none-any.whl", hash = "sha256:4454f967a4d1a01e3e6205c070455bc4e8fd53b5b0753221581ae679c55a9dfd"}, - {file = "botocore-1.32.6.tar.gz", hash = "sha256:ecec876103783b5efe6099762dda60c2af67e45f7c0ab4568e8265d11c6c449b"}, + {file = "botocore-1.32.7-py3-none-any.whl", hash = "sha256:58b33d02cafa23461c8a9d211b30e8cded992380a84de409379fd02811fa3e11"}, + {file = "botocore-1.32.7.tar.gz", hash = "sha256:c6795c731b04c8e3635588c44cfd1a4462fc5987859195522c96812cf3eceff9"}, ] [package.dependencies] @@ -448,7 +448,7 @@ urllib3 = [ ] [package.extras] -crt = ["awscrt (==0.19.12)"] +crt = ["awscrt (==0.19.17)"] [[package]] name = "brotli" @@ -1275,7 +1275,7 @@ graph = ["objgraph (>=1.7.2)"] name = "diskcache" version = "5.6.3" description = "Disk Cache -- Disk and file backed persistent cache." -optional = true +optional = false python-versions = ">=3" files = [ {file = "diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19"}, @@ -1565,13 +1565,13 @@ files = [ [[package]] name = "fake-useragent" -version = "1.3.0" +version = "1.4.0" description = "Up-to-date simple useragent faker with real world database" optional = false python-versions = "*" files = [ - {file = "fake-useragent-1.3.0.tar.gz", hash = "sha256:0b3a223b4c03e3df46b0e9ff53ad26cf4690f68871396b9c59a7fa6ee830c395"}, - {file = "fake_useragent-1.3.0-py3-none-any.whl", hash = "sha256:73cee1d10bcd1deb25a15e916f6674c537d2d9088ecb4d7af98c2619f83827d1"}, + {file = "fake-useragent-1.4.0.tar.gz", hash = "sha256:5426e4015d8ccc5bb25f64d3dfcfd3915eba30ffebd31b86b60dc7a4c5d65528"}, + {file = "fake_useragent-1.4.0-py3-none-any.whl", hash = "sha256:9acce439ee2c6cf9c3772fa6c200f62dc8d56605063327a4d8c5d0e47f414b85"}, ] [package.dependencies] @@ -1664,6 +1664,43 @@ files = [ {file = "filetype-1.2.0.tar.gz", hash = "sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb"}, ] +[[package]] +name = "flaml" +version = "2.1.1" +description = "A fast library for automated machine learning and tuning" +optional = false +python-versions = ">=3.6" +files = [ + {file = "FLAML-2.1.1-py3-none-any.whl", hash = "sha256:ba34f1a06f3cbc6bb23a2ea4830a264375f6bba497f402122a73e42647a15535"}, + {file = "FLAML-2.1.1.tar.gz", hash = "sha256:53e94aacc996da80fe779bc6833d3b25c80c77fe11667d0912798e49293282eb"}, +] + +[package.dependencies] +NumPy = ">=1.17.0rc1" + +[package.extras] +autogen = ["diskcache", "openai (==0.27.8)", "termcolor"] +automl = ["lightgbm (>=2.3.1)", "pandas (>=1.1.4)", "scikit-learn (>=0.24)", "scipy (>=1.4.1)", "xgboost (>=0.90)"] +autozero = ["packaging", "pandas", "scikit-learn"] +azureml = ["azureml-mlflow"] +benchmark = ["catboost (>=0.26)", "pandas (==1.1.4)", "psutil (==5.8.0)", "xgboost (==1.3.3)"] +blendsearch = ["optuna (==2.8.0)", "packaging"] +catboost = ["catboost (>=0.26)"] +forecast = ["hcrystalball (==0.1.10)", "holidays (<0.14)", "prophet (>=1.0.1)", "pytorch-forecasting (>=0.9.0)", "pytorch-lightning (==1.9.0)", "statsmodels (>=0.12.2)", "tensorboardX (==2.6)"] +hf = ["datasets", "nltk", "rouge-score", "seqeval", "transformers[torch] (==4.26)"] +mathchat = ["diskcache", "openai (==0.27.8)", "pydantic (==1.10.9)", "sympy", "termcolor", "wolframalpha"] +nlp = ["datasets", "nltk", "rouge-score", "seqeval", "transformers[torch] (==4.26)"] +nni = ["nni"] +notebook = ["jupyter"] +openai = ["diskcache", "openai (==0.27.8)"] +ray = ["ray[tune] (>=1.13,<2.0)"] +retrievechat = ["chromadb", "diskcache", "openai (==0.27.8)", "sentence-transformers", "termcolor", "tiktoken"] +spark = ["joblib (<1.3.0)", "joblibspark (>=0.5.0)", "pyspark (>=3.2.0)"] +synapse = ["joblib (<1.3.0)", "joblibspark (>=0.5.0)", "optuna (==2.8.0)", "pyspark (>=3.2.0)"] +test = ["catboost (>=0.26,<1.2)", "coverage (>=5.3)", "dataclasses", "datasets", "hcrystalball (==0.1.10)", "ipykernel", "joblib (<1.3.0)", "joblibspark (>=0.5.0)", "lightgbm (>=2.3.1)", "mlflow", "nbconvert", "nbformat", "nltk", "openml", "optuna (==2.8.0)", "packaging", "pandas (>=1.1.4)", "pre-commit", "psutil (==5.8.0)", "pydantic (==1.10.9)", "pyspark (>=3.2.0)", "pytest (>=6.1.1)", "pytorch-forecasting (>=0.9.0,<=0.10.1)", "pytorch-lightning (<1.9.1)", "requests (<2.29.0)", "rgf-python", "rouge-score", "scikit-learn (>=0.24)", "scipy (>=1.4.1)", "seqeval", "statsmodels (>=0.12.2)", "sympy", "tensorboardX (==2.6)", "thop", "torch", "torchvision", "transformers[torch] (==4.26)", "wolframalpha", "xgboost (>=0.90)"] +ts-forecast = ["hcrystalball (==0.1.10)", "holidays (<0.14)", "prophet (>=1.0.1)", "statsmodels (>=0.12.2)"] +vw = ["scikit-learn", "vowpalwabbit (>=8.10.0,<9.0.0)"] + [[package]] name = "flask" version = "3.0.0" @@ -2888,13 +2925,13 @@ files = [ [[package]] name = "idna" -version = "3.4" +version = "3.6" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, ] [[package]] @@ -2965,13 +3002,13 @@ files = [ [[package]] name = "ipykernel" -version = "6.27.0" +version = "6.26.0" description = "IPython Kernel for Jupyter" optional = false python-versions = ">=3.8" files = [ - {file = "ipykernel-6.27.0-py3-none-any.whl", hash = "sha256:4388caa3c2cba0a381e20d289545e88a8aef1fe57a884d4c018718ec8c23c121"}, - {file = "ipykernel-6.27.0.tar.gz", hash = "sha256:7f4986f606581be73bfb32dc7a1ac9fa0e804c9be50ddf1c7a119413e982693f"}, + {file = "ipykernel-6.26.0-py3-none-any.whl", hash = "sha256:3ba3dc97424b87b31bb46586b5167b3161b32d7820b9201a9e698c71e271602c"}, + {file = "ipykernel-6.26.0.tar.gz", hash = "sha256:553856658eb8430bbe9653ea041a41bff63e9606fc4628873fc92a6cf3abd404"}, ] [package.dependencies] @@ -2998,24 +3035,23 @@ test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio" [[package]] name = "ipython" -version = "8.17.2" +version = "8.18.1" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.9" files = [ - {file = "ipython-8.17.2-py3-none-any.whl", hash = "sha256:1e4d1d666a023e3c93585ba0d8e962867f7a111af322efff6b9c58062b3e5444"}, - {file = "ipython-8.17.2.tar.gz", hash = "sha256:126bb57e1895594bb0d91ea3090bbd39384f6fe87c3d57fd558d0670f50339bb"}, + {file = "ipython-8.18.1-py3-none-any.whl", hash = "sha256:e8267419d72d81955ec1177f8a29aaa90ac80ad647499201119e2f05e99aa397"}, + {file = "ipython-8.18.1.tar.gz", hash = "sha256:ca6f079bb33457c66e233e4580ebfc4128855b4cf6370dddd73842a9563e8a27"}, ] [package.dependencies] -appnope = {version = "*", markers = "sys_platform == \"darwin\""} colorama = {version = "*", markers = "sys_platform == \"win32\""} decorator = "*" exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} jedi = ">=0.16" matplotlib-inline = "*" pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} -prompt-toolkit = ">=3.0.30,<3.0.37 || >3.0.37,<3.1.0" +prompt-toolkit = ">=3.0.41,<3.1.0" pygments = ">=2.4.0" stack-data = "*" traitlets = ">=5" @@ -3559,13 +3595,13 @@ six = "*" [[package]] name = "langfuse" -version = "1.7.5" +version = "1.9.2" description = "A client library for accessing langfuse" optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langfuse-1.7.5-py3-none-any.whl", hash = "sha256:ebbcc52f454a9c7cfc9f382e66fddafddb0219f9233598317bbcb66c215b39b6"}, - {file = "langfuse-1.7.5.tar.gz", hash = "sha256:99fc5a30b157a16cc3dcb82e84af13fabc2fd0d192be32ef2ad6d9a7fe27d130"}, + {file = "langfuse-1.9.2-py3-none-any.whl", hash = "sha256:0a171830ec15b26e6b512db4612422a48402d422c1269091390d0b81fbdfe46b"}, + {file = "langfuse-1.9.2.tar.gz", hash = "sha256:6542d38013e9ca21ab3d31840bdd517a79cb6db72ddb30fec8ad0d999d0e2bfd"}, ] [package.dependencies] @@ -4169,38 +4205,38 @@ dill = ">=0.3.7" [[package]] name = "mypy" -version = "1.7.0" +version = "1.7.1" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5da84d7bf257fd8f66b4f759a904fd2c5a765f70d8b52dde62b521972a0a2357"}, - {file = "mypy-1.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a3637c03f4025f6405737570d6cbfa4f1400eb3c649317634d273687a09ffc2f"}, - {file = "mypy-1.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b633f188fc5ae1b6edca39dae566974d7ef4e9aaaae00bc36efe1f855e5173ac"}, - {file = "mypy-1.7.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d6ed9a3997b90c6f891138e3f83fb8f475c74db4ccaa942a1c7bf99e83a989a1"}, - {file = "mypy-1.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:1fe46e96ae319df21359c8db77e1aecac8e5949da4773c0274c0ef3d8d1268a9"}, - {file = "mypy-1.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:df67fbeb666ee8828f675fee724cc2cbd2e4828cc3df56703e02fe6a421b7401"}, - {file = "mypy-1.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a79cdc12a02eb526d808a32a934c6fe6df07b05f3573d210e41808020aed8b5d"}, - {file = "mypy-1.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f65f385a6f43211effe8c682e8ec3f55d79391f70a201575def73d08db68ead1"}, - {file = "mypy-1.7.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e81ffd120ee24959b449b647c4b2fbfcf8acf3465e082b8d58fd6c4c2b27e46"}, - {file = "mypy-1.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:f29386804c3577c83d76520abf18cfcd7d68264c7e431c5907d250ab502658ee"}, - {file = "mypy-1.7.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:87c076c174e2c7ef8ab416c4e252d94c08cd4980a10967754f91571070bf5fbe"}, - {file = "mypy-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6cb8d5f6d0fcd9e708bb190b224089e45902cacef6f6915481806b0c77f7786d"}, - {file = "mypy-1.7.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d93e76c2256aa50d9c82a88e2f569232e9862c9982095f6d54e13509f01222fc"}, - {file = "mypy-1.7.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cddee95dea7990e2215576fae95f6b78a8c12f4c089d7e4367564704e99118d3"}, - {file = "mypy-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:d01921dbd691c4061a3e2ecdbfbfad029410c5c2b1ee88946bf45c62c6c91210"}, - {file = "mypy-1.7.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:185cff9b9a7fec1f9f7d8352dff8a4c713b2e3eea9c6c4b5ff7f0edf46b91e41"}, - {file = "mypy-1.7.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7a7b1e399c47b18feb6f8ad4a3eef3813e28c1e871ea7d4ea5d444b2ac03c418"}, - {file = "mypy-1.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc9fe455ad58a20ec68599139ed1113b21f977b536a91b42bef3ffed5cce7391"}, - {file = "mypy-1.7.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d0fa29919d2e720c8dbaf07d5578f93d7b313c3e9954c8ec05b6d83da592e5d9"}, - {file = "mypy-1.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:2b53655a295c1ed1af9e96b462a736bf083adba7b314ae775563e3fb4e6795f5"}, - {file = "mypy-1.7.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c1b06b4b109e342f7dccc9efda965fc3970a604db70f8560ddfdee7ef19afb05"}, - {file = "mypy-1.7.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bf7a2f0a6907f231d5e41adba1a82d7d88cf1f61a70335889412dec99feeb0f8"}, - {file = "mypy-1.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:551d4a0cdcbd1d2cccdcc7cb516bb4ae888794929f5b040bb51aae1846062901"}, - {file = "mypy-1.7.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:55d28d7963bef00c330cb6461db80b0b72afe2f3c4e2963c99517cf06454e665"}, - {file = "mypy-1.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:870bd1ffc8a5862e593185a4c169804f2744112b4a7c55b93eb50f48e7a77010"}, - {file = "mypy-1.7.0-py3-none-any.whl", hash = "sha256:96650d9a4c651bc2a4991cf46f100973f656d69edc7faf91844e87fe627f7e96"}, - {file = "mypy-1.7.0.tar.gz", hash = "sha256:1e280b5697202efa698372d2f39e9a6713a0395a756b1c6bd48995f8d72690dc"}, + {file = "mypy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12cce78e329838d70a204293e7b29af9faa3ab14899aec397798a4b41be7f340"}, + {file = "mypy-1.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1484b8fa2c10adf4474f016e09d7a159602f3239075c7bf9f1627f5acf40ad49"}, + {file = "mypy-1.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31902408f4bf54108bbfb2e35369877c01c95adc6192958684473658c322c8a5"}, + {file = "mypy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f2c2521a8e4d6d769e3234350ba7b65ff5d527137cdcde13ff4d99114b0c8e7d"}, + {file = "mypy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:fcd2572dd4519e8a6642b733cd3a8cfc1ef94bafd0c1ceed9c94fe736cb65b6a"}, + {file = "mypy-1.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4b901927f16224d0d143b925ce9a4e6b3a758010673eeded9b748f250cf4e8f7"}, + {file = "mypy-1.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2f7f6985d05a4e3ce8255396df363046c28bea790e40617654e91ed580ca7c51"}, + {file = "mypy-1.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:944bdc21ebd620eafefc090cdf83158393ec2b1391578359776c00de00e8907a"}, + {file = "mypy-1.7.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9c7ac372232c928fff0645d85f273a726970c014749b924ce5710d7d89763a28"}, + {file = "mypy-1.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:f6efc9bd72258f89a3816e3a98c09d36f079c223aa345c659622f056b760ab42"}, + {file = "mypy-1.7.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6dbdec441c60699288adf051f51a5d512b0d818526d1dcfff5a41f8cd8b4aaf1"}, + {file = "mypy-1.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4fc3d14ee80cd22367caaaf6e014494415bf440980a3045bf5045b525680ac33"}, + {file = "mypy-1.7.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c6e4464ed5f01dc44dc9821caf67b60a4e5c3b04278286a85c067010653a0eb"}, + {file = "mypy-1.7.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d9b338c19fa2412f76e17525c1b4f2c687a55b156320acb588df79f2e6fa9fea"}, + {file = "mypy-1.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:204e0d6de5fd2317394a4eff62065614c4892d5a4d1a7ee55b765d7a3d9e3f82"}, + {file = "mypy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:84860e06ba363d9c0eeabd45ac0fde4b903ad7aa4f93cd8b648385a888e23200"}, + {file = "mypy-1.7.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8c5091ebd294f7628eb25ea554852a52058ac81472c921150e3a61cdd68f75a7"}, + {file = "mypy-1.7.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40716d1f821b89838589e5b3106ebbc23636ffdef5abc31f7cd0266db936067e"}, + {file = "mypy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cf3f0c5ac72139797953bd50bc6c95ac13075e62dbfcc923571180bebb662e9"}, + {file = "mypy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:78e25b2fd6cbb55ddfb8058417df193f0129cad5f4ee75d1502248e588d9e0d7"}, + {file = "mypy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:75c4d2a6effd015786c87774e04331b6da863fc3fc4e8adfc3b40aa55ab516fe"}, + {file = "mypy-1.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2643d145af5292ee956aa0a83c2ce1038a3bdb26e033dadeb2f7066fb0c9abce"}, + {file = "mypy-1.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75aa828610b67462ffe3057d4d8a4112105ed211596b750b53cbfe182f44777a"}, + {file = "mypy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ee5d62d28b854eb61889cde4e1dbc10fbaa5560cb39780c3995f6737f7e82120"}, + {file = "mypy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:72cf32ce7dd3562373f78bd751f73c96cfb441de147cc2448a92c1a308bd0ca6"}, + {file = "mypy-1.7.1-py3-none-any.whl", hash = "sha256:f7c5d642db47376a0cc130f0de6d055056e010debdaf0707cd2b0fc7e7ef30ea"}, + {file = "mypy-1.7.1.tar.gz", hash = "sha256:fcb6d9afb1b6208b4c712af0dafdc650f518836065df0d4fb1d800f5d6773db2"}, ] [package.dependencies] @@ -5092,13 +5128,13 @@ win-unicode-console = {version = "*", markers = "platform_system == \"Windows\" [[package]] name = "pexpect" -version = "4.8.0" +version = "4.9.0" description = "Pexpect allows easy control of interactive console applications." optional = false python-versions = "*" files = [ - {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, - {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, + {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, + {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, ] [package.dependencies] @@ -5106,12 +5142,12 @@ ptyprocess = ">=0.5" [[package]] name = "pgvector" -version = "0.2.3" +version = "0.2.4" description = "pgvector support for Python" optional = false python-versions = ">=3.8" files = [ - {file = "pgvector-0.2.3-py2.py3-none-any.whl", hash = "sha256:9d53dc01138ecc7c9aca64e4680cfa9edf4c38f9cb8ed7098317871fdd211824"}, + {file = "pgvector-0.2.4-py2.py3-none-any.whl", hash = "sha256:548e1f88d3c7433020c1c177feddad2f36915c262852d621f9018fcafff6870b"}, ] [package.dependencies] @@ -5733,6 +5769,34 @@ files = [ [package.dependencies] pyasn1 = ">=0.4.6,<0.6.0" +[[package]] +name = "pyautogen" +version = "0.2.0" +description = "Enabling Next-Gen LLM Applications via Multi-Agent Conversation Framework" +optional = false +python-versions = ">=3.8, <3.12" +files = [ + {file = "pyautogen-0.2.0-py3-none-any.whl", hash = "sha256:d7bf4d239f85152e191026d8173f649e256c431cf31b93ca3629cd2f0c525a46"}, + {file = "pyautogen-0.2.0.tar.gz", hash = "sha256:858f2d15eaa68f043f7b67b975a6d27f738c98ca4d7e0e96b400061c0ac3e692"}, +] + +[package.dependencies] +diskcache = "*" +flaml = "*" +openai = ">=1.2,<2.0" +python-dotenv = "*" +termcolor = "*" +tiktoken = "*" + +[package.extras] +blendsearch = ["flaml[blendsearch]"] +graphs = ["matplotlib (>=3.8.1,<3.9.0)", "networkx (>=3.2.1,<3.3.0)"] +lmm = ["pillow", "replicate"] +mathchat = ["pydantic (==1.10.9)", "sympy", "wolframalpha"] +retrievechat = ["chromadb", "ipython", "pypdf", "sentence-transformers"] +teachable = ["chromadb"] +test = ["coverage (>=5.3)", "ipykernel", "nbconvert", "nbformat", "pre-commit", "pytest (>=6.1.1)", "pytest-asyncio"] + [[package]] name = "pycparser" version = "2.21" @@ -7025,126 +7089,126 @@ files = [ [[package]] name = "s3transfer" -version = "0.7.0" +version = "0.8.0" description = "An Amazon S3 Transfer Manager" optional = false python-versions = ">= 3.7" files = [ - {file = "s3transfer-0.7.0-py3-none-any.whl", hash = "sha256:10d6923c6359175f264811ef4bf6161a3156ce8e350e705396a7557d6293c33a"}, - {file = "s3transfer-0.7.0.tar.gz", hash = "sha256:fd3889a66f5fe17299fe75b82eae6cf722554edca744ca5d5fe308b104883d2e"}, + {file = "s3transfer-0.8.0-py3-none-any.whl", hash = "sha256:baa479dc2e63e5c2ed51611b4d46cdf0295e2070d8d0b86b22f335ee5b954986"}, + {file = "s3transfer-0.8.0.tar.gz", hash = "sha256:e8d6bd52ffd99841e3a57b34370a54841f12d3aab072af862cdcc50955288002"}, ] [package.dependencies] -botocore = ">=1.12.36,<2.0a.0" +botocore = ">=1.32.7,<2.0a.0" [package.extras] -crt = ["botocore[crt] (>=1.20.29,<2.0a.0)"] +crt = ["botocore[crt] (>=1.32.7,<2.0a.0)"] [[package]] name = "safetensors" -version = "0.4.0" +version = "0.4.1" description = "" optional = true python-versions = ">=3.7" files = [ - {file = "safetensors-0.4.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:2289ae6dbe6d027ecee016b28ced13a2e21a0b3a3a757a23033a2d1c0b1bad55"}, - {file = "safetensors-0.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bf6458959f310f551cbbeef2255527ade5f783f952738e73e4d0136198cc3bfe"}, - {file = "safetensors-0.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b6b60a58a8f7cc7aed3b5b73dce1f5259a53c83d9ba43a76a874e6ad868c1b4d"}, - {file = "safetensors-0.4.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:491b3477e4d0d4599bb75d79da4b75af2e6ed9b1f6ec2b715991f0bc927bf09a"}, - {file = "safetensors-0.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59d2e10b7e0cd18bb73ed7c17c624a5957b003b81345e18159591771c26ee428"}, - {file = "safetensors-0.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3f667a4c12fb593f5f66ce966cb1b14a7148898b2b1a7f79e0761040ae1e3c51"}, - {file = "safetensors-0.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f9909512bcb6f712bdd04c296cdfb0d8ff73d258ffc5af884bb62ea02d221e0"}, - {file = "safetensors-0.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d33d29e846821f0e4f92614022949b09ccf063cb36fe2f9fe099cde1efbfbb87"}, - {file = "safetensors-0.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4d512525a8e05a045ce6698066ba0c5378c174a83e0b3720a8c7799dc1bb06f3"}, - {file = "safetensors-0.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0219cea445177f6ad1f9acd3a8d025440c8ff436d70a4a7c7ba9c36066aa9474"}, - {file = "safetensors-0.4.0-cp310-none-win32.whl", hash = "sha256:67ab171eeaad6972d3971c53d29d53353c67f6743284c6d637b59fa3e54c8a94"}, - {file = "safetensors-0.4.0-cp310-none-win_amd64.whl", hash = "sha256:7ffc736039f08a9ca1f09816a7481b8e4469c06e8f8a5ffa8cb67ddd79e6d77f"}, - {file = "safetensors-0.4.0-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:4fe9e3737b30de458225a23926219ca30b902ee779b6a3df96eaab2b6d625ec2"}, - {file = "safetensors-0.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7916e814a90008de767b1c164a1d83803693c661ffe9af5a697b22e2752edb0"}, - {file = "safetensors-0.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cbc4a4da01143472323c145f3c289e5f6fabde0ac0a3414dabf912a21692fff4"}, - {file = "safetensors-0.4.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a54c21654a47669b38e359e8f852af754b786c9da884bb61ad5e9af12bd71ccb"}, - {file = "safetensors-0.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:25cd407955bad5340ba17f9f8ac789a0d751601a311e2f7b2733f9384478c95e"}, - {file = "safetensors-0.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:82e8fc4e3503cd738fd40718a430fe0e5ce6e7ff91a73d6ce628bbb89c41e8ce"}, - {file = "safetensors-0.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48b92059b1a4ad163024d4f526e0e73ebe2bb3ae70537e15e347820b4de5dc27"}, - {file = "safetensors-0.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5daa05058f7dce85b5f9f60c4eab483ed7859d63978f08a76e52e78859ff20ca"}, - {file = "safetensors-0.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a86565a5c112dd855909e20144947b4f53abb78c4de207f36ca71ee63ba5b90d"}, - {file = "safetensors-0.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38032078ed9fea52d06584e441bccc73fb475c4581600c6d6166de2fe2deb3d1"}, - {file = "safetensors-0.4.0-cp311-none-win32.whl", hash = "sha256:2f99d90c91b7c76b40a862acd9085bc77f7974a27dee7cfcebe46149af5a99a1"}, - {file = "safetensors-0.4.0-cp311-none-win_amd64.whl", hash = "sha256:74e2a448ffe19be188b457b130168190ee73b5a75e45ba96796320c1f5ae35d2"}, - {file = "safetensors-0.4.0-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:1e2f9c69b41d03b4826ffb96b29e07444bb6b34a78a7bafd0b88d59e8ec75b8a"}, - {file = "safetensors-0.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3910fb5bf747413b59f1a34e6d2a993b589fa7d919709518823c70efaaa350bd"}, - {file = "safetensors-0.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf8fdca709b2470a35a59b1e6dffea75cbe1214b22612b5dd4c93947697aea8b"}, - {file = "safetensors-0.4.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f27b8ef814c5fb43456caeb7f3cbb889b76115180aad1f42402839c14a47c5b"}, - {file = "safetensors-0.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7b2d6101eccc43c7be0cb052f13ceda64288b3d8b344b988ed08d7133cbce2f3"}, - {file = "safetensors-0.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fdc34027b545a69be3d4220c140b276129523e4e46db06ad1a0b60d6a4cf9214"}, - {file = "safetensors-0.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db7bb48ca9e90bb9526c71b388d38d8de160c0354f4c5126df23e8701a870dcb"}, - {file = "safetensors-0.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a78ffc0795d3595cd9e4d453502e35f764276c49e434b25556a15a337db4dafc"}, - {file = "safetensors-0.4.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8e735b0f79090f6855b55e205e820b7b595502ffca0009a5c13eef3661ce465b"}, - {file = "safetensors-0.4.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f8d2416734e850d5392afffbcb2b8985ea29fb171f1cb197e2ae51b8e35d6438"}, - {file = "safetensors-0.4.0-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:e853e189ba7d47eaf561094586692ba2bbdd258c096f1755805cac098de0e6ab"}, - {file = "safetensors-0.4.0-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:4b2aa57b5a4d576f3d1dd6e56980026340f156f8a13c13016bfac4e25295b53f"}, - {file = "safetensors-0.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b6c1316ffde6cb4bf22c7445bc9fd224b4d1b9dd7320695f5611c89e802e4b6"}, - {file = "safetensors-0.4.0-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:003077ec85261d00061058fa12e3c1d2055366b02ce8f2938929359ffbaff2b8"}, - {file = "safetensors-0.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bd63d83a92f1437a8b0431779320376030ae43ace980bea5686d515de0784100"}, - {file = "safetensors-0.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2077801800b4b13301d8d6290c7fb5bd60737320001717153ebc4371776643b5"}, - {file = "safetensors-0.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7abe0e157a49a75aeeccfbc4f3dac38d8f98512d3cdb35c200f8e628dc5773cf"}, - {file = "safetensors-0.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3bfed574f6b1e7e7fe1f17213278875ef6c6e8b1582ab6eda93947db1178cae6"}, - {file = "safetensors-0.4.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:964ef166a286ce3b023d0d0bd0e21d440a1c8028981c8abdb136bc7872ba9b3d"}, - {file = "safetensors-0.4.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:44f84373e42183bd56a13a1f2d8acb1db7fedaeffbd83e79cec861477eee1af4"}, - {file = "safetensors-0.4.0-cp37-none-win32.whl", hash = "sha256:c68132727dd86fb641102e494d445f705efe402f4d5e24b278183a15499ab400"}, - {file = "safetensors-0.4.0-cp37-none-win_amd64.whl", hash = "sha256:1db87155454c168aef118d5657a403aee48a4cb08d8851a981157f07351ea317"}, - {file = "safetensors-0.4.0-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:9e583fa68e5a07cc859c4e13c1ebff12029904aa2e27185cf04a1f57fe9a81c4"}, - {file = "safetensors-0.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:73e7696dcf3f72f99545eb1abe6106ad65ff1f62381d6ce4b34be3272552897a"}, - {file = "safetensors-0.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4936096a57c62e84e200f92620a536be067fc5effe46ecc7f230ebb496ecd579"}, - {file = "safetensors-0.4.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:87b328ee1591adac332543e1f5fc2c2d7f149b745ebb0d58d7850818ff9cee27"}, - {file = "safetensors-0.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b69554c143336256260eceff1d3c0969172a641b54d4668489a711b05f92a2c0"}, - {file = "safetensors-0.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ebf6bcece5d5d1bd6416472f94604d2c834ca752ac60ed42dba7157e595a990"}, - {file = "safetensors-0.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6686ce01b8602d55a7d9903c90d4a6e6f90aeb6ddced7cf4605892d0ba94bcb8"}, - {file = "safetensors-0.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9b8fd6cc2f3bda444a048b541c843c7b7fefc89c4120d7898ea7d5b026e93891"}, - {file = "safetensors-0.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8a6abfe67692f81b8bdb99c837f28351c17e624ebf136970c850ee989c720446"}, - {file = "safetensors-0.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:27a24ca8822c469ee452db4c13418ba983315a0d863c018a9af15f2305eac38c"}, - {file = "safetensors-0.4.0-cp38-none-win32.whl", hash = "sha256:c4a0a47c8640167792d8261ee21b26430bbc39130a7edaad7f4c0bc05669d00e"}, - {file = "safetensors-0.4.0-cp38-none-win_amd64.whl", hash = "sha256:a738970a367f39249e2abb900d9441a8a86d7ff50083e5eaa6e7760a9f216014"}, - {file = "safetensors-0.4.0-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:806379f37e1abd5d302288c4b2f4186dd7ea7143d4c7811f90a8077f0ae8967b"}, - {file = "safetensors-0.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2b9b94133ed2ae9dda0e95dcace7b7556eba023ffa4c4ae6df8f99377f571d6a"}, - {file = "safetensors-0.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b563a14c43614815a6b524d2e4edeaace50b717f7e7487bb227dd5b68350f5a"}, - {file = "safetensors-0.4.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:00a9b157be660fb7ba88fa2eedd05ec93793a5b61e43e783e10cb0b995372802"}, - {file = "safetensors-0.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c8f194f45ab6aa767993c24f0aeb950af169dbc5d611b94c9021a1d13b8a1a34"}, - {file = "safetensors-0.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:469360b9451db10bfed3881378d5a71b347ecb1ab4f42367d77b8164a13af70b"}, - {file = "safetensors-0.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5f75fa97ccf32a3c7af476c6a0e851023197d3c078f6de3612008fff94735f9"}, - {file = "safetensors-0.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:acf0180283c2efae72f1d8c0a4a7974662091df01be3aa43b5237b1e52ed0a01"}, - {file = "safetensors-0.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:cd02b495ba0814619f40bda46771bb06dbbf1d42524b66fa03b2a736c77e4515"}, - {file = "safetensors-0.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c42bdea183dbaa99e2f0e6120dc524df79cf4289a6f90f30a534444ef20f49fa"}, - {file = "safetensors-0.4.0-cp39-none-win32.whl", hash = "sha256:cef7bb5d9feae7146c3c3c7b3aef7d2c8b39ba7f5ff4252d368eb69462a47076"}, - {file = "safetensors-0.4.0-cp39-none-win_amd64.whl", hash = "sha256:79dd46fb1f19282fd12f544471efb97823ede927cedbf9cf35550d92b349fdd2"}, - {file = "safetensors-0.4.0-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:002301c1afa32909f83745b0c124d002e7ae07e15671f3b43cbebd0ffc5e6037"}, - {file = "safetensors-0.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:67762d36ae088c73d4a3c96bfc4ea8d31233554f35b6cace3a18533238d462ea"}, - {file = "safetensors-0.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f45230f20a206e5e4c7f7bbf9342178410c6f8b0af889843aa99045a76f7691"}, - {file = "safetensors-0.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f2ca939bbd8fb2f4dfa28e39a146dad03bc9325e9fc831b68f7b98f69a5a2f1"}, - {file = "safetensors-0.4.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:61a00f281391fae5ce91df70918bb61c12d2d514a493fd8056e12114be729911"}, - {file = "safetensors-0.4.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:435fd136a42492b280cb55126f9ce9535b35dd49df2c5d572a5945455a439448"}, - {file = "safetensors-0.4.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f0daa788273d683258fb1e4a5e16bef4486b2fca536451a2591bc0f4a6488895"}, - {file = "safetensors-0.4.0-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:0620ab0d41e390ccb1c4ea8f63dc00cb5f0b96a5cdd3cd0d64c21765720c074a"}, - {file = "safetensors-0.4.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc1fa8d067733cb67f22926689ee808f08afacf7700d2ffb44efae90a0693eb1"}, - {file = "safetensors-0.4.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaa40bc363edda145db75cd030f3b1822e5478d550c3500a42502ecef32c959"}, - {file = "safetensors-0.4.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b561fbc044db7beff2ece0ec219a291809d45a38d30c6b38e7cc46482582f4ba"}, - {file = "safetensors-0.4.0-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:79a983b09782dacf9a1adb19bb98f4a8f6c3144108939f572c047b5797e43cf5"}, - {file = "safetensors-0.4.0-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:10b65cd3ad79f5d0daf281523b4146bc271a34bb7430d4e03212e0de8622dab8"}, - {file = "safetensors-0.4.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:114decacc475a6a9e2f9102a00c171d113ddb5d35cb0bda0db2c0c82b2eaa9ce"}, - {file = "safetensors-0.4.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:72ddb741dd5fe42521db76a70e012f76995516a12e7e0ef26be03ea9be77802a"}, - {file = "safetensors-0.4.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c5556c2ec75f5a6134866eddd7341cb36062e6edaea343478a279591b63ddba"}, - {file = "safetensors-0.4.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed50f239b0ce7ae85b078395593b4a351ede7e6f73af25f4873e3392336f64c9"}, - {file = "safetensors-0.4.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:495dcaea8fbab70b927d2274e2547824462737acbf98ccd851a71124f779a5c6"}, - {file = "safetensors-0.4.0-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3f4d90c79a65ba2fe2ff0876f6140748f0a3ce6a21e27a35190f4f96321803f8"}, - {file = "safetensors-0.4.0-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:7a524382b5c55b5fbb168e0e9d3f502450c8cf3fb81b93e880018437c206a482"}, - {file = "safetensors-0.4.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:9849ea60c7e840bfdd6030ad454d4a6ba837b3398c902f15a30460dd6961c28c"}, - {file = "safetensors-0.4.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:6c42623ae7045615d9eaa6877b9df1db4e9cc71ecc14bcc721ea1e475dddd595"}, - {file = "safetensors-0.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80cb8342f00f3c41b3b93b1a599b84723280d3ac90829bc62262efc03ab28793"}, - {file = "safetensors-0.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8c4f5ed4ede384dea8c99bae76b0718a828dbf7b2c8ced1f44e3b9b1a124475"}, - {file = "safetensors-0.4.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40d7cf03493bfe75ef62e2c716314474b28d9ba5bf4909763e4b8dd14330c01a"}, - {file = "safetensors-0.4.0-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:232029f0a9fa6fa1f737324eda98a700409811186888536a2333cbbf64e41741"}, - {file = "safetensors-0.4.0-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:9ed55f4a20c78ff3e8477efb63c8303c2152cdfb3bfea4d025a80f54d38fd628"}, - {file = "safetensors-0.4.0.tar.gz", hash = "sha256:b985953c3cf11e942eac4317ef3db3da713e274109cf7cfb6076d877054f013e"}, + {file = "safetensors-0.4.1-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:cba01c6b76e01ec453933b3b3c0157c59b52881c83eaa0f7666244e71aa75fd1"}, + {file = "safetensors-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7a8f6f679d97ea0135c7935c202feefbd042c149aa70ee759855e890c01c7814"}, + {file = "safetensors-0.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbc2ce1f5ae5143a7fb72b71fa71db6a42b4f6cf912aa3acdc6b914084778e68"}, + {file = "safetensors-0.4.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2d87d993eaefe6611a9c241a8bd364a5f1ffed5771c74840363a6c4ed8d868f6"}, + {file = "safetensors-0.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:097e9af2efa8778cd2f0cba451784253e62fa7cc9fc73c0744d27212f7294e25"}, + {file = "safetensors-0.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d10a9f7bae608ccfdc009351f01dc3d8535ff57f9488a58a4c38e45bf954fe93"}, + {file = "safetensors-0.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:270b99885ec14abfd56c1d7f28ada81740a9220b4bae960c3de1c6fe84af9e4d"}, + {file = "safetensors-0.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:285b52a481e7ba93e29ad4ec5841ef2c4479ef0a6c633c4e2629e0508453577b"}, + {file = "safetensors-0.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c3c9f0ca510e0de95abd6424789dcbc879942a3a4e29b0dfa99d9427bf1da75c"}, + {file = "safetensors-0.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:88b4653059c903015284a9722f9a46838c654257173b279c8f6f46dbe80b612d"}, + {file = "safetensors-0.4.1-cp310-none-win32.whl", hash = "sha256:2fe6926110e3d425c4b684a4379b7796fdc26ad7d16922ea1696c8e6ea7e920f"}, + {file = "safetensors-0.4.1-cp310-none-win_amd64.whl", hash = "sha256:a79e16222106b2f5edbca1b8185661477d8971b659a3c814cc6f15181a9b34c8"}, + {file = "safetensors-0.4.1-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:d93321eea0dd7e81b283e47a1d20dee6069165cc158286316d0d06d340de8fe8"}, + {file = "safetensors-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8ff8e41c8037db17de0ea2a23bc684f43eaf623be7d34906fe1ac10985b8365e"}, + {file = "safetensors-0.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39d36f1d88468a87c437a1bc27c502e71b6ca44c385a9117a9f9ba03a75cc9c6"}, + {file = "safetensors-0.4.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7ef010e9afcb4057fb6be3d0a0cfa07aac04fe97ef73fe4a23138d8522ba7c17"}, + {file = "safetensors-0.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b287304f2b2220d51ccb51fd857761e78bcffbeabe7b0238f8dc36f2edfd9542"}, + {file = "safetensors-0.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e09000b2599e1836314430f81a3884c66a5cbabdff5d9f175b5d560d4de38d78"}, + {file = "safetensors-0.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9c80ce0001efa16066358d2dd77993adc25f5a6c61850e4ad096a2232930bce"}, + {file = "safetensors-0.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:413e1f6ac248f7d1b755199a06635e70c3515493d3b41ba46063dec33aa2ebb7"}, + {file = "safetensors-0.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3ac139377cfe71ba04573f1cda66e663b7c3e95be850e9e6c2dd4b5984bd513"}, + {file = "safetensors-0.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:04157d008385bea66d12fe90844a80d4a76dc25ec5230b5bd9a630496d1b7c03"}, + {file = "safetensors-0.4.1-cp311-none-win32.whl", hash = "sha256:5f25297148ec665f0deb8bd67e9564634d8d6841041ab5393ccfe203379ea88b"}, + {file = "safetensors-0.4.1-cp311-none-win_amd64.whl", hash = "sha256:b2f8877990a72ff595507b80f4b69036a9a1986a641f8681adf3425d97d3d2a5"}, + {file = "safetensors-0.4.1-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:eb2c1da1cc39509d1a55620a5f4d14f8911c47a89c926a96e6f4876e864375a3"}, + {file = "safetensors-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:303d2c0415cf15a28f8d7f17379ea3c34c2b466119118a34edd9965983a1a8a6"}, + {file = "safetensors-0.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb4cb3e37a9b961ddd68e873b29fe9ab4a081e3703412e34aedd2b7a8e9cafd9"}, + {file = "safetensors-0.4.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ae5497adc68669db2fed7cb2dad81e6a6106e79c9a132da3efdb6af1db1014fa"}, + {file = "safetensors-0.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b30abd0cddfe959d1daedf92edcd1b445521ebf7ddefc20860ed01486b33c90"}, + {file = "safetensors-0.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d784a98c492c751f228a4a894c3b8a092ff08b24e73b5568938c28b8c0e8f8df"}, + {file = "safetensors-0.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e57a5ab08b0ec7a7caf30d2ac79bb30c89168431aca4f8854464bb9461686925"}, + {file = "safetensors-0.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:edcf3121890b5f0616aa5a54683b1a5d2332037b970e507d6bb7841a3a596556"}, + {file = "safetensors-0.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:fdb58dee173ef33634c3016c459d671ca12d11e6acf9db008261cbe58107e579"}, + {file = "safetensors-0.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:780dc21eb3fd32ddd0e8c904bdb0290f2454f4ac21ae71e94f9ce72db1900a5a"}, + {file = "safetensors-0.4.1-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:48901bd540f8a3c1791314bc5c8a170927bf7f6acddb75bf0a263d081a3637d4"}, + {file = "safetensors-0.4.1-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:3b0b7b2d5976fbed8a05e2bbdce5816a59e6902e9e7c7e07dc723637ed539787"}, + {file = "safetensors-0.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f69903ff49cb30b9227fb5d029bea276ea20d04b06803877a420c5b1b74c689"}, + {file = "safetensors-0.4.1-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0ddd050e01f3e843aa8c1c27bf68675b8a08e385d0045487af4d70418c3cb356"}, + {file = "safetensors-0.4.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a82bc2bd7a9a0e08239bdd6d7774d64121f136add93dfa344a2f1a6d7ef35fa"}, + {file = "safetensors-0.4.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6ace9e66a40f98a216ad661245782483cf79cf56eb2b112650bb904b0baa9db5"}, + {file = "safetensors-0.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82cbb8f4d022f2e94498cbefca900698b8ded3d4f85212f47da614001ff06652"}, + {file = "safetensors-0.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:791edc10a3c359a2f5f52d5cddab0df8a45107d91027d86c3d44e57162e5d934"}, + {file = "safetensors-0.4.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:83c2cfbe8c6304f0891e7bb378d56f66d2148972eeb5f747cd8a2246886f0d8c"}, + {file = "safetensors-0.4.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:04dd14f53f5500eb4c4149674216ba1000670efbcf4b1b5c2643eb244e7882ea"}, + {file = "safetensors-0.4.1-cp37-none-win32.whl", hash = "sha256:d5b3defa74f3723a388bfde2f5d488742bc4879682bd93267c09a3bcdf8f869b"}, + {file = "safetensors-0.4.1-cp37-none-win_amd64.whl", hash = "sha256:25a043cbb59d4f75e9dd87fdf5c009dd8830105a2c57ace49b72167dd9808111"}, + {file = "safetensors-0.4.1-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:3f6a520af7f2717c5ecba112041f2c8af1ca6480b97bf957aba81ed9642e654c"}, + {file = "safetensors-0.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c3807ac3b16288dffebb3474b555b56fe466baa677dfc16290dcd02dca1ab228"}, + {file = "safetensors-0.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b58ba13a9e82b4bc3fc221914f6ef237fe6c2adb13cede3ace64d1aacf49610"}, + {file = "safetensors-0.4.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dac4bb42f8679aadc59bd91a4c5a1784a758ad49d0912995945cd674089f628e"}, + {file = "safetensors-0.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:911b48dc09e321a194def3a7431662ff4f03646832f3a8915bbf0f449b8a5fcb"}, + {file = "safetensors-0.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:82571d20288c975c1b30b08deb9b1c3550f36b31191e1e81fae87669a92217d0"}, + {file = "safetensors-0.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da52ee0dc8ba03348ffceab767bd8230842fdf78f8a996e2a16445747143a778"}, + {file = "safetensors-0.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2536b11ce665834201072e9397404170f93f3be10cca9995b909f023a04501ee"}, + {file = "safetensors-0.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:998fbac99ca956c3a09fe07cc0b35fac26a521fa8865a690686d889f0ff4e4a6"}, + {file = "safetensors-0.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:845be0aafabf2a60c2d482d4e93023fecffe5e5443d801d7a7741bae9de41233"}, + {file = "safetensors-0.4.1-cp38-none-win32.whl", hash = "sha256:ce7a28bc8af685a69d7e869d09d3e180a275e3281e29cf5f1c7319e231932cc7"}, + {file = "safetensors-0.4.1-cp38-none-win_amd64.whl", hash = "sha256:e056fb9e22d118cc546107f97dc28b449d88274207dd28872bd668c86216e4f6"}, + {file = "safetensors-0.4.1-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:bdc0d039e44a727824639824090bd8869535f729878fa248addd3dc01db30eae"}, + {file = "safetensors-0.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3c1b1d510c7aba71504ece87bf393ea82638df56303e371e5e2cf09d18977dd7"}, + {file = "safetensors-0.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bd0afd95c1e497f520e680ea01e0397c0868a3a3030e128438cf6e9e3fcd671"}, + {file = "safetensors-0.4.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f603bdd8deac6726d39f41688ed353c532dd53935234405d79e9eb53f152fbfb"}, + {file = "safetensors-0.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d8a85e3e47e0d4eebfaf9a58b40aa94f977a56050cb5598ad5396a9ee7c087c6"}, + {file = "safetensors-0.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0ccb5aa0f3be2727117e5631200fbb3a5b3a2b3757545a92647d6dd8be6658f"}, + {file = "safetensors-0.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d784938534e255473155e4d9f276ee69eb85455b6af1292172c731409bf9adee"}, + {file = "safetensors-0.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a257de175c254d39ccd6a21341cd62eb7373b05c1e618a78096a56a857e0c316"}, + {file = "safetensors-0.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6fd80f7794554091836d4d613d33a7d006e2b8d6ba014d06f97cebdfda744f64"}, + {file = "safetensors-0.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:35803201d980efcf964b75a0a2aee97fe5e9ecc5f3ad676b38fafdfe98e0620d"}, + {file = "safetensors-0.4.1-cp39-none-win32.whl", hash = "sha256:7ff8a36e0396776d3ed9a106fc9a9d7c55d4439ca9a056a24bf66d343041d3e6"}, + {file = "safetensors-0.4.1-cp39-none-win_amd64.whl", hash = "sha256:bfa2e20342b81921b98edba52f8deb68843fa9c95250739a56b52ceda5ea5c61"}, + {file = "safetensors-0.4.1-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ae2d5a31cfb8a973a318f7c4d2cffe0bd1fe753cdf7bb41a1939d45a0a06f964"}, + {file = "safetensors-0.4.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1a45dbf03e8334d3a5dc93687d98b6dc422f5d04c7d519dac09b84a3c87dd7c6"}, + {file = "safetensors-0.4.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2297b359d91126c0f9d4fd17bae3cfa2fe3a048a6971b8db07db746ad92f850c"}, + {file = "safetensors-0.4.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bda3d98e2bcece388232cfc551ebf063b55bdb98f65ab54df397da30efc7dcc5"}, + {file = "safetensors-0.4.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8934bdfd202ebd0697040a3dff40dd77bc4c5bbf3527ede0532f5e7fb4d970f"}, + {file = "safetensors-0.4.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:42c3710cec7e5c764c7999697516370bee39067de0aa089b7e2cfb97ac8c6b20"}, + {file = "safetensors-0.4.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:53134226053e56bd56e73f7db42596e7908ed79f3c9a1016e4c1dade593ac8e5"}, + {file = "safetensors-0.4.1-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:257d59e40a1b367cb544122e7451243d65b33c3f34d822a347f4eea6fdf97fdf"}, + {file = "safetensors-0.4.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d54c2f1826e790d1eb2d2512bfd0ee443f0206b423d6f27095057c7f18a0687"}, + {file = "safetensors-0.4.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:645b3f1138fce6e818e79d4128afa28f0657430764cc045419c1d069ff93f732"}, + {file = "safetensors-0.4.1-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e9a7ffb1e551c6df51d267f5a751f042b183df22690f6feceac8d27364fd51d7"}, + {file = "safetensors-0.4.1-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:44e230fbbe120de564b64f63ef3a8e6ff02840fa02849d9c443d56252a1646d4"}, + {file = "safetensors-0.4.1-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:9d16b3b2fcc6fca012c74bd01b5619c655194d3e3c13e4d4d0e446eefa39a463"}, + {file = "safetensors-0.4.1-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:5d95ea4d8b32233910734a904123bdd3979c137c461b905a5ed32511defc075f"}, + {file = "safetensors-0.4.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:dab431699b5d45e0ca043bc580651ce9583dda594e62e245b7497adb32e99809"}, + {file = "safetensors-0.4.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16d8bbb7344e39cb9d4762e85c21df94ebeb03edac923dd94bb9ed8c10eac070"}, + {file = "safetensors-0.4.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1faf5111c66a6ba91f85dff2e36edaaf36e6966172703159daeef330de4ddc7b"}, + {file = "safetensors-0.4.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:660ca1d8bff6c7bc7c6b30b9b32df74ef3ab668f5df42cefd7588f0d40feadcb"}, + {file = "safetensors-0.4.1-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:ae2f67f04ed0bb2e56fd380a8bd3eef03f609df53f88b6f5c7e89c08e52aae00"}, + {file = "safetensors-0.4.1-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:c8ed5d2c04cdc1afc6b3c28d59580448ac07732c50d94c15e14670f9c473a2ce"}, + {file = "safetensors-0.4.1-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:2b6a2814278b6660261aa9a9aae524616de9f1ec364e3716d219b6ed8f91801f"}, + {file = "safetensors-0.4.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3cfd1ca35eacc635f0eaa894e5c5ed83ffebd0f95cac298fd430014fa7323631"}, + {file = "safetensors-0.4.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4177b456c6b0c722d82429127b5beebdaf07149d265748e97e0a34ff0b3694c8"}, + {file = "safetensors-0.4.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:313e8472197bde54e3ec54a62df184c414582979da8f3916981b6a7954910a1b"}, + {file = "safetensors-0.4.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fdb4adb76e21bad318210310590de61c9f4adcef77ee49b4a234f9dc48867869"}, + {file = "safetensors-0.4.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:1d568628e9c43ca15eb96c217da73737c9ccb07520fafd8a1eba3f2750614105"}, + {file = "safetensors-0.4.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:573b6023a55a2f28085fc0a84e196c779b6cbef4d9e73acea14c8094fee7686f"}, + {file = "safetensors-0.4.1.tar.gz", hash = "sha256:2304658e6ada81a5223225b4efe84748e760c46079bffedf7e321763cafb36c9"}, ] [package.extras] @@ -7565,13 +7629,13 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyam [[package]] name = "storage3" -version = "0.6.1" +version = "0.7.0" description = "Supabase Storage client for Python." optional = false python-versions = ">=3.8,<4.0" files = [ - {file = "storage3-0.6.1-py3-none-any.whl", hash = "sha256:0a8b8dc08f4d2268c8f46035fffcb13be99ed489bd0be29786f979c42f5a7169"}, - {file = "storage3-0.6.1.tar.gz", hash = "sha256:7f50c2279da604c3c088fc72f6d10fee146e30fe9ecbf9d505cea5c884622700"}, + {file = "storage3-0.7.0-py3-none-any.whl", hash = "sha256:dd2d6e68f7a3dc038047ed62fa8bdc5c2e3d6b6e56ee2951195d084bcce71605"}, + {file = "storage3-0.7.0.tar.gz", hash = "sha256:9ddecc775cdc04514413bd44b9ec61bc25aad9faadabefdb6e6e88b33756f5fd"}, ] [package.dependencies] @@ -7597,13 +7661,13 @@ test = ["pylint", "pytest", "pytest-black", "pytest-cov", "pytest-pylint"] [[package]] name = "supabase" -version = "2.0.3" +version = "2.1.0" description = "Supabase client for Python." optional = false python-versions = ">=3.8,<4.0" files = [ - {file = "supabase-2.0.3-py3-none-any.whl", hash = "sha256:7385c1bd7897d93ba0fb1c5f33496efcbab2264eb44738c4c14284adbfd97099"}, - {file = "supabase-2.0.3.tar.gz", hash = "sha256:89b6556bf4f5f2e3dd1255f5840ceb12c3dc187ce8947b9bc0f5f7b0ad010971"}, + {file = "supabase-2.1.0-py3-none-any.whl", hash = "sha256:7467261d6b7c3e9b62a396a1718c2c73fb07d51b70e4bb0fe0cde7e029c3b320"}, + {file = "supabase-2.1.0.tar.gz", hash = "sha256:44facb425162061176d22ff0baed3055503c54a61cfd84c47eb438df44052ee3"}, ] [package.dependencies] @@ -7611,7 +7675,7 @@ gotrue = ">=1.3.0,<2.0.0" httpx = ">=0.24.0,<0.25.0" postgrest = ">=0.10.8,<0.14.0" realtime = ">=1.0.0,<2.0.0" -storage3 = ">=0.5.3,<0.7.0" +storage3 = ">=0.5.3,<0.8.0" supafunc = ">=0.3.1,<0.4.0" [[package]] @@ -8244,13 +8308,13 @@ files = [ [[package]] name = "types-redis" -version = "4.6.0.10" +version = "4.6.0.11" description = "Typing stubs for redis" optional = false python-versions = ">=3.7" files = [ - {file = "types-redis-4.6.0.10.tar.gz", hash = "sha256:aa7fb5f743534500f274ddf11ab1c910aae1020481865a36b799e1d67de2aaf3"}, - {file = "types_redis-4.6.0.10-py3-none-any.whl", hash = "sha256:00f003da884ec3d1d54633186b4cbd587b39782595c5603330cc46a51f9bcf6e"}, + {file = "types-redis-4.6.0.11.tar.gz", hash = "sha256:c8cfc84635183deca2db4a528966c5566445fd3713983f0034fb0f5a09e0890d"}, + {file = "types_redis-4.6.0.11-py3-none-any.whl", hash = "sha256:94fc61118601fb4f79206b33b9f4344acff7ca1d7bba67834987fb0efcf6a770"}, ] [package.dependencies] @@ -9096,4 +9160,4 @@ local = ["ctransformers", "llama-cpp-python", "sentence-transformers"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.11" -content-hash = "62e47482eefda134f0801744360624549d7024861380f51f280f60450d768615" +content-hash = "1930ee9350f8d29899117ba0ffce4eff58b10b99e4d135b8d4ba52bca9e50d88" diff --git a/pyproject.toml b/pyproject.toml index 7f8cb136c..d36a2bb9a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -102,11 +102,12 @@ boto3 = "^1.28.63" numexpr = "^2.8.6" qianfan = "0.0.5" pgvector = "^0.2.3" +pyautogen = "^0.2.0" [tool.poetry.group.dev.dependencies] pytest-asyncio = "^0.21.1" types-redis = "^4.6.0.5" -ipykernel = "^6.21.2" +ipykernel = "^6.26.0" mypy = "^1.1.1" ruff = "^0.1.5" httpx = "*" diff --git a/src/backend/langflow/__main__.py b/src/backend/langflow/__main__.py index 515613c23..5eb92d133 100644 --- a/src/backend/langflow/__main__.py +++ b/src/backend/langflow/__main__.py @@ -313,7 +313,7 @@ def superuser( if create_super_user(db=session, username=username, password=password): # Verify that the superuser was created - from langflow.services.database.models.user.user import User + from langflow.services.database.models.user.model import User user: User = session.query(User).filter(User.username == username).first() if user is None or not user.is_superuser: diff --git a/src/backend/langflow/alembic/versions/2ac71eb9c3ae_adds_credential_table.py b/src/backend/langflow/alembic/versions/2ac71eb9c3ae_adds_credential_table.py new file mode 100644 index 000000000..3f974dc04 --- /dev/null +++ b/src/backend/langflow/alembic/versions/2ac71eb9c3ae_adds_credential_table.py @@ -0,0 +1,45 @@ +"""Adds Credential table + +Revision ID: c1c8e217a069 +Revises: 7d2162acc8b2 +Create Date: 2023-11-24 10:45:38.465302 + +""" +from typing import Sequence, Union + +import sqlalchemy as sa +import sqlmodel +from alembic import op + +# revision identifiers, used by Alembic. +revision: str = '2ac71eb9c3ae' +down_revision: Union[str, None] = '7d2162acc8b2' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + try: + op.create_table('credential', + sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=True), + sa.Column('value', sqlmodel.sql.sqltypes.AutoString(), nullable=True), + sa.Column('provider', sqlmodel.sql.sqltypes.AutoString(), nullable=True), + sa.Column('user_id', sqlmodel.sql.sqltypes.GUID(), nullable=False), + sa.Column('id', sqlmodel.sql.sqltypes.GUID(), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=False), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + except Exception: + pass + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + try: + op.drop_table('credential') + except Exception: + pass + # ### end Alembic commands ### diff --git a/src/backend/langflow/alembic/versions/fd531f8868b1_fix_credential_table.py b/src/backend/langflow/alembic/versions/fd531f8868b1_fix_credential_table.py new file mode 100644 index 000000000..db20f928b --- /dev/null +++ b/src/backend/langflow/alembic/versions/fd531f8868b1_fix_credential_table.py @@ -0,0 +1,38 @@ +"""Fix Credential table + +Revision ID: fd531f8868b1 +Revises: 2ac71eb9c3ae +Create Date: 2023-11-24 15:07:37.566516 + +""" +from typing import Sequence, Union + +from alembic import op + +# revision identifiers, used by Alembic. +revision: str = 'fd531f8868b1' +down_revision: Union[str, None] = '2ac71eb9c3ae' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + try: + with op.batch_alter_table('credential', schema=None) as batch_op: + batch_op.create_foreign_key("fk_credential_user_id", 'user', ['user_id'], ['id']) + except Exception: + pass + + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + try: + with op.batch_alter_table('credential', schema=None) as batch_op: + batch_op.drop_constraint("fk_credential_user_id", type_='foreignkey') + except Exception: + pass + + # ### end Alembic commands ### diff --git a/src/backend/langflow/api/router.py b/src/backend/langflow/api/router.py index b87a24ea3..24d64b401 100644 --- a/src/backend/langflow/api/router.py +++ b/src/backend/langflow/api/router.py @@ -1,14 +1,16 @@ # Router for base api from fastapi import APIRouter + from langflow.api.v1 import ( + api_key_router, chat_router, + credentials_router, endpoints_router, - validate_router, flows_router, + login_router, store_router, users_router, - api_key_router, - login_router, + validate_router, ) router = APIRouter( @@ -22,3 +24,4 @@ router.include_router(flows_router) router.include_router(users_router) router.include_router(api_key_router) router.include_router(login_router) +router.include_router(credentials_router) diff --git a/src/backend/langflow/api/v1/__init__.py b/src/backend/langflow/api/v1/__init__.py index 197b9730f..6368a0cc8 100644 --- a/src/backend/langflow/api/v1/__init__.py +++ b/src/backend/langflow/api/v1/__init__.py @@ -1,11 +1,12 @@ -from langflow.api.v1.endpoints import router as endpoints_router -from langflow.api.v1.validate import router as validate_router +from langflow.api.v1.api_key import router as api_key_router from langflow.api.v1.chat import router as chat_router +from langflow.api.v1.credential import router as credentials_router +from langflow.api.v1.endpoints import router as endpoints_router from langflow.api.v1.flows import router as flows_router +from langflow.api.v1.login import router as login_router from langflow.api.v1.store import router as store_router from langflow.api.v1.users import router as users_router -from langflow.api.v1.api_key import router as api_key_router -from langflow.api.v1.login import router as login_router +from langflow.api.v1.validate import router as validate_router __all__ = [ "chat_router", @@ -16,4 +17,5 @@ __all__ = [ "users_router", "api_key_router", "login_router", + "credentials_router", ] diff --git a/src/backend/langflow/api/v1/api_key.py b/src/backend/langflow/api/v1/api_key.py index fcd9c934f..48cf7d1ca 100644 --- a/src/backend/langflow/api/v1/api_key.py +++ b/src/backend/langflow/api/v1/api_key.py @@ -1,27 +1,27 @@ +from typing import TYPE_CHECKING from uuid import UUID -from fastapi import APIRouter, HTTPException, Depends -from langflow.api.v1.schemas import ApiKeysResponse, ApiKeyCreateRequest + +from fastapi import APIRouter, Depends, HTTPException +from sqlmodel import Session + +from langflow.api.v1.schemas import ApiKeyCreateRequest, ApiKeysResponse from langflow.services.auth import utils as auth_utils -from langflow.services.database.models.api_key.api_key import ( - ApiKeyCreate, - UnmaskedApiKeyRead, -) # Assuming you have these methods in your service layer from langflow.services.database.models.api_key.crud import ( - get_api_keys, create_api_key, delete_api_key, + get_api_keys, ) -from langflow.services.database.models.user.user import User +from langflow.services.database.models.api_key.model import ( + ApiKeyCreate, + UnmaskedApiKeyRead, +) +from langflow.services.database.models.user.model import User from langflow.services.deps import ( get_session, get_settings_service, ) -from typing import TYPE_CHECKING - - -from sqlmodel import Session if TYPE_CHECKING: pass @@ -85,3 +85,16 @@ def save_store_api_key( return {"detail": "API Key saved"} except Exception as e: raise HTTPException(status_code=400, detail=str(e)) from e + + +@router.delete("/store") +def delete_store_api_key( + current_user: User = Depends(auth_utils.get_current_active_user), + db: Session = Depends(get_session), +): + try: + current_user.store_api_key = None + db.commit() + return {"detail": "API Key deleted"} + except Exception as e: + raise HTTPException(status_code=400, detail=str(e)) from e diff --git a/src/backend/langflow/api/v1/chat.py b/src/backend/langflow/api/v1/chat.py index 66e23aa5a..877ee07bd 100644 --- a/src/backend/langflow/api/v1/chat.py +++ b/src/backend/langflow/api/v1/chat.py @@ -1,27 +1,15 @@ -from fastapi import ( - APIRouter, - Depends, - HTTPException, - Query, - WebSocket, - WebSocketException, - status, -) +from fastapi import APIRouter, Depends, HTTPException, Query, WebSocket, WebSocketException, status from fastapi.responses import StreamingResponse -from loguru import logger -from sqlmodel import Session - from langflow.api.utils import build_input_keys_response from langflow.api.v1.schemas import BuildStatus, BuiltResponse, InitResponse, StreamData from langflow.graph.graph.base import Graph -from langflow.services.auth.utils import ( - get_current_active_user, - get_current_user_by_jwt, -) +from langflow.services.auth.utils import get_current_active_user, get_current_user_by_jwt from langflow.services.cache.service import BaseCacheService from langflow.services.cache.utils import update_build_status from langflow.services.chat.service import ChatService from langflow.services.deps import get_cache_service, get_chat_service, get_session +from loguru import logger +from sqlmodel import Session router = APIRouter(tags=["Chat"]) @@ -148,7 +136,7 @@ async def stream_build( # Some error could happen when building the graph graph = Graph.from_payload(graph_data) - number_of_nodes = len(graph.nodes) + number_of_nodes = len(graph.vertices) update_build_status(cache_service, flow_id, BuildStatus.IN_PROGRESS) try: diff --git a/src/backend/langflow/api/v1/credential.py b/src/backend/langflow/api/v1/credential.py new file mode 100644 index 000000000..f4347afcd --- /dev/null +++ b/src/backend/langflow/api/v1/credential.py @@ -0,0 +1,90 @@ +from datetime import datetime +from uuid import UUID + +from fastapi import APIRouter, Depends, HTTPException +from langflow.services.auth import utils as auth_utils +from langflow.services.auth.utils import get_current_active_user +from langflow.services.database.models.credential import Credential, CredentialCreate, CredentialRead, CredentialUpdate +from langflow.services.database.models.user.model import User +from langflow.services.deps import get_session, get_settings_service +from sqlmodel import Session + +router = APIRouter(prefix="/credentials", tags=["Credentials"]) + + +@router.post("/", response_model=CredentialRead, status_code=201) +def create_credential( + *, + session: Session = Depends(get_session), + credential: CredentialCreate, + current_user: User = Depends(get_current_active_user), + settings_service=Depends(get_settings_service), +): + """Create a new credential.""" + try: + # check if credential name already exists + credential_exists = ( + session.query(Credential) + .filter(Credential.name == credential.name, Credential.user_id == current_user.id) + .first() + ) + if credential_exists: + raise HTTPException(status_code=400, detail="Credential name already exists") + + db_credential = Credential.model_validate(credential, from_attributes=True) + if not db_credential.value: + raise HTTPException(status_code=400, detail="Credential value cannot be empty") + encrypted = auth_utils.encrypt_api_key(db_credential.value, settings_service=settings_service) + db_credential.value = encrypted + db_credential.user_id = current_user.id + session.add(db_credential) + session.commit() + session.refresh(db_credential) + return db_credential + except Exception as e: + if isinstance(e, HTTPException): + raise e + raise HTTPException(status_code=500, detail=str(e)) from e + + +@router.get("/", response_model=list[CredentialRead], status_code=200) +def read_credentials( + *, + session: Session = Depends(get_session), + current_user: User = Depends(get_current_active_user), +): + """Read all credentials.""" + try: + credentials = session.query(Credential).filter(Credential.user_id == current_user.id).all() + return credentials + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) from e + + +@router.patch("/{credential_id}", response_model=CredentialRead, status_code=200) +def update_credential( + *, + session: Session = Depends(get_session), + credential_id: UUID, + credential: CredentialUpdate, + current_user: User = Depends(get_current_active_user), +): + """Update a credential.""" + try: + db_credential = ( + session.query(Credential) + .filter(Credential.id == credential_id, Credential.user_id == current_user.id) + .first() + ) + if not db_credential: + raise HTTPException(status_code=404, detail="Credential not found") + + credential_data = credential.model_dump(exclude_unset=True) + for key, value in credential_data.items(): + setattr(db_credential, key, value) + db_credential.updated_at = datetime.utcnow() + session.commit() + session.refresh(db_credential) + return db_credential + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) from e diff --git a/src/backend/langflow/api/v1/endpoints.py b/src/backend/langflow/api/v1/endpoints.py index 2d2ebd952..51d3e8bad 100644 --- a/src/backend/langflow/api/v1/endpoints.py +++ b/src/backend/langflow/api/v1/endpoints.py @@ -3,8 +3,6 @@ from typing import Annotated, Optional, Union import sqlalchemy as sa from fastapi import APIRouter, Body, Depends, HTTPException, UploadFile, status -from loguru import logger - from langflow.api.v1.schemas import ( CustomComponentCode, ProcessResponse, @@ -14,17 +12,14 @@ from langflow.api.v1.schemas import ( ) from langflow.interface.custom.custom_component import CustomComponent from langflow.interface.custom.directory_reader import DirectoryReader +from langflow.interface.types import build_langchain_template_custom_component, create_and_validate_component from langflow.processing.process import process_graph_cached, process_tweaks from langflow.services.auth.utils import api_key_security, get_current_active_user from langflow.services.cache.utils import save_uploaded_file from langflow.services.database.models.flow import Flow -from langflow.services.database.models.user.user import User -from langflow.services.deps import ( - get_session, - get_session_service, - get_settings_service, - get_task_service, -) +from langflow.services.database.models.user.model import User +from langflow.services.deps import get_session, get_session_service, get_settings_service, get_task_service +from loguru import logger try: from langflow.worker import process_graph_cached_task @@ -34,9 +29,8 @@ except ImportError: raise NotImplementedError("Celery is not installed") -from sqlmodel import Session - from langflow.services.task.service import TaskService +from sqlmodel import Session # build router router = APIRouter(tags=["Base"]) @@ -208,9 +202,7 @@ async def custom_component( raw_code: CustomComponentCode, user: User = Depends(get_current_active_user), ): - from langflow.interface.types import ( - build_langchain_template_custom_component, - ) + component = create_and_validate_component(raw_code.code) extractor = CustomComponent(code=raw_code.code) extractor.validate() @@ -219,10 +211,8 @@ async def custom_component( @router.post("/custom_component/reload", status_code=HTTPStatus.OK) -async def reload_custom_component(path: str): - from langflow.interface.types import ( - build_langchain_template_custom_component, - ) +async def reload_custom_component(path: str, user: User = Depends(get_current_active_user)): + from langflow.interface.types import build_langchain_template_custom_component try: reader = DirectoryReader("") @@ -235,3 +225,15 @@ async def reload_custom_component(path: str): return build_langchain_template_custom_component(extractor, user_id=user.id) except Exception as exc: raise HTTPException(status_code=400, detail=str(exc)) + + +@router.post("/custom_component/update", status_code=HTTPStatus.OK) +async def custom_component_update( + raw_code: CustomComponentCode, + user: User = Depends(get_current_active_user), +): + component = create_and_validate_component(raw_code.code) + + component_node = build_langchain_template_custom_component(component, user_id=user.id, update_field=raw_code.field) + # Update the field + return component_node diff --git a/src/backend/langflow/api/v1/flows.py b/src/backend/langflow/api/v1/flows.py index d35b2a8d5..939899553 100644 --- a/src/backend/langflow/api/v1/flows.py +++ b/src/backend/langflow/api/v1/flows.py @@ -11,7 +11,7 @@ from langflow.api.utils import remove_api_keys from langflow.api.v1.schemas import FlowListCreate, FlowListRead from langflow.services.auth.utils import get_current_active_user from langflow.services.database.models.flow import Flow, FlowCreate, FlowRead, FlowUpdate -from langflow.services.database.models.user.user import User +from langflow.services.database.models.user.model import User from langflow.services.deps import get_session, get_settings_service # build router diff --git a/src/backend/langflow/api/v1/schemas.py b/src/backend/langflow/api/v1/schemas.py index 99a8b08cb..cb22bcd92 100644 --- a/src/backend/langflow/api/v1/schemas.py +++ b/src/backend/langflow/api/v1/schemas.py @@ -2,13 +2,14 @@ from enum import Enum from pathlib import Path from typing import Any, Dict, List, Optional, Union from uuid import UUID -from langflow.services.database.models.api_key.api_key import ApiKeyRead -from langflow.services.database.models.flow import FlowCreate, FlowRead -from langflow.services.database.models.user import UserRead -from langflow.services.database.models.base import orjson_dumps from pydantic import BaseModel, Field, field_validator +from langflow.services.database.models.api_key.model import ApiKeyRead +from langflow.services.database.models.base import orjson_dumps +from langflow.services.database.models.flow import FlowCreate, FlowRead +from langflow.services.database.models.user import UserRead + class BuildStatus(Enum): """Status of the build.""" @@ -156,6 +157,7 @@ class StreamData(BaseModel): class CustomComponentCode(BaseModel): code: str + field: Optional[str] = None class CustomComponentResponseError(BaseModel): diff --git a/src/backend/langflow/api/v1/store.py b/src/backend/langflow/api/v1/store.py index 273ea41e4..e3d6cee9d 100644 --- a/src/backend/langflow/api/v1/store.py +++ b/src/backend/langflow/api/v1/store.py @@ -4,7 +4,7 @@ from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, Query from langflow.services.auth import utils as auth_utils -from langflow.services.database.models.user.user import User +from langflow.services.database.models.user.model import User from langflow.services.deps import get_settings_service, get_store_service from langflow.services.store.exceptions import CustomException from langflow.services.store.schema import ( diff --git a/src/backend/langflow/components/agents/AgentInitializer.py b/src/backend/langflow/components/agents/AgentInitializer.py new file mode 100644 index 000000000..2e8a9de2f --- /dev/null +++ b/src/backend/langflow/components/agents/AgentInitializer.py @@ -0,0 +1,37 @@ +from typing import Callable, List, Union + +from langchain.agents import AgentExecutor, AgentType, initialize_agent, types + +from langflow import CustomComponent +from langflow.field_typing import BaseChatMemory, BaseLanguageModel, Tool + + +class AgentInitializerComponent(CustomComponent): + display_name: str = "Agent Initializer" + description: str = "Initialize a Langchain Agent." + documentation: str = "https://python.langchain.com/docs/modules/agents/agent_types/" + + def build_config(self): + agents = list(types.AGENT_TO_CLASS.keys()) + # field_type and required are optional + return { + "agent": {"options": agents, "value": agents[0], "display_name": "Agent Type"}, + "max_iterations": {"display_name": "Max Iterations", "value": 10}, + "memory": {"display_name": "Memory"}, + "tools": {"display_name": "Tools"}, + "llm": {"display_name": "Language Model"}, + } + + def build( + self, agent: str, llm: BaseLanguageModel, memory: BaseChatMemory, tools: List[Tool], max_iterations: int + ) -> Union[AgentExecutor, Callable]: + agent = AgentType(agent) + return initialize_agent( + tools=tools, + llm=llm, + agent=agent, + memory=memory, + return_intermediate_steps=True, + handle_parsing_errors=True, + max_iterations=max_iterations, + ) diff --git a/src/backend/langflow/components/chains/LLMChain.py b/src/backend/langflow/components/chains/LLMChain.py index b14eef302..ec88e128a 100644 --- a/src/backend/langflow/components/chains/LLMChain.py +++ b/src/backend/langflow/components/chains/LLMChain.py @@ -1,10 +1,12 @@ -from langflow import CustomComponent +from typing import Callable, Optional, Union + from langchain.chains import LLMChain -from typing import Optional, Union, Callable + +from langflow import CustomComponent from langflow.field_typing import ( - BasePromptTemplate, BaseLanguageModel, BaseMemory, + BasePromptTemplate, Chain, ) diff --git a/src/backend/langflow/config.yaml b/src/backend/langflow/config.yaml index d234ce8ea..39bdc1ed6 100644 --- a/src/backend/langflow/config.yaml +++ b/src/backend/langflow/config.yaml @@ -5,8 +5,6 @@ agents: documentation: "https://python.langchain.com/docs/modules/agents/toolkits/openapi" CSVAgent: documentation: "https://python.langchain.com/docs/modules/agents/toolkits/csv" - AgentInitializer: - documentation: "https://python.langchain.com/docs/modules/agents/agent_types/" VectorStoreAgent: documentation: "" VectorStoreRouterAgent: diff --git a/src/backend/langflow/field_typing/constants.py b/src/backend/langflow/field_typing/constants.py index 646af0bac..76ef3aa5b 100644 --- a/src/backend/langflow/field_typing/constants.py +++ b/src/backend/langflow/field_typing/constants.py @@ -3,11 +3,12 @@ from typing import Callable, Dict, Union from langchain.agents.agent import AgentExecutor from langchain.chains.base import Chain from langchain.document_loaders.base import BaseLoader -from langchain.llms.base import BaseLanguageModel, BaseLLM +from langchain.llms.base import BaseLLM from langchain.memory.chat_memory import BaseChatMemory from langchain.prompts import BasePromptTemplate, ChatPromptTemplate, PromptTemplate from langchain.schema import BaseOutputParser, BaseRetriever, Document from langchain.schema.embeddings import Embeddings +from langchain.schema.language_model import BaseLanguageModel from langchain.schema.memory import BaseMemory from langchain.text_splitter import TextSplitter from langchain.tools import Tool diff --git a/src/backend/langflow/graph/edge/base.py b/src/backend/langflow/graph/edge/base.py index f9d77741b..c9c1077f6 100644 --- a/src/backend/langflow/graph/edge/base.py +++ b/src/backend/langflow/graph/edge/base.py @@ -1,7 +1,7 @@ +from typing import TYPE_CHECKING, List, Optional + from loguru import logger -from typing import TYPE_CHECKING from pydantic import BaseModel, Field -from typing import List, Optional if TYPE_CHECKING: from langflow.graph.vertex.base import Vertex @@ -22,8 +22,8 @@ class TargetHandle(BaseModel): class Edge: def __init__(self, source: "Vertex", target: "Vertex", edge: dict): - self.source: "Vertex" = source - self.target: "Vertex" = target + self.source_id: str = source.id + self.target_id: str = target.id if data := edge.get("data", {}): self._source_handle = data.get("sourceHandle", {}) self._target_handle = data.get("targetHandle", {}) @@ -31,7 +31,7 @@ class Edge: self.target_handle: TargetHandle = TargetHandle(**self._target_handle) self.target_param = self.target_handle.fieldName # validate handles - self.validate_handles() + self.validate_handles(source, target) else: # Logging here because this is a breaking change logger.error("Edge data is empty") @@ -41,9 +41,9 @@ class Edge: # target_param is documents self.target_param = self._target_handle.split("|")[1] # Validate in __init__ to fail fast - self.validate_edge() + self.validate_edge(source, target) - def validate_handles(self) -> None: + def validate_handles(self, source, target) -> None: if self.target_handle.inputTypes is None: self.valid_handles = self.target_handle.type in self.source_handle.baseClasses else: @@ -54,26 +54,20 @@ class Edge: if not self.valid_handles: logger.debug(self.source_handle) logger.debug(self.target_handle) - raise ValueError( - f"Edge between {self.source.vertex_type} and {self.target.vertex_type} " f"has invalid handles" - ) + raise ValueError(f"Edge between {source.vertex_type} and {target.vertex_type} " f"has invalid handles") def __setstate__(self, state): - self.source = state["source"] - self.target = state["target"] + self.source_id = state["source_id"] + self.target_id = state["target_id"] self.target_param = state["target_param"] self.source_handle = state.get("source_handle") self.target_handle = state.get("target_handle") - def reset(self) -> None: - self.source._build_params() - self.target._build_params() - - def validate_edge(self) -> None: + def validate_edge(self, source, target) -> None: # Validate that the outputs of the source node are valid inputs # for the target node - self.source_types = self.source.output - self.target_reqs = self.target.required_inputs + self.target.optional_inputs + self.source_types = source.output + self.target_reqs = target.required_inputs + target.optional_inputs # Both lists contain strings and sometimes a string contains the value we are # looking for e.g. comgin_out=["Chain"] and target_reqs=["LLMChain"] # so we need to check if any of the strings in source_types is in target_reqs @@ -88,13 +82,11 @@ class Edge: if no_matched_type: logger.debug(self.source_types) logger.debug(self.target_reqs) - raise ValueError( - f"Edge between {self.source.vertex_type} and {self.target.vertex_type} " f"has no matched type" - ) + raise ValueError(f"Edge between {source.vertex_type} and {target.vertex_type} " f"has no matched type") def __repr__(self) -> str: return ( - f"Edge(source={self.source.id}, target={self.target.id}, target_param={self.target_param}" + f"Edge(source={self.source_id}, target={self.target_id}, target_param={self.target_param}" f", matched_type={self.matched_type})" ) diff --git a/src/backend/langflow/graph/graph/base.py b/src/backend/langflow/graph/graph/base.py index e9431a5ec..9f80907a8 100644 --- a/src/backend/langflow/graph/graph/base.py +++ b/src/backend/langflow/graph/graph/base.py @@ -13,32 +13,32 @@ from langflow.utils import payload class Graph: - """A class representing a graph of nodes and edges.""" + """A class representing a graph of vertices and edges.""" def __init__( self, nodes: List[Dict], edges: List[Dict[str, str]], ) -> None: - self._nodes = nodes + self._vertices = nodes self._edges = edges self.raw_graph_data = {"nodes": nodes, "edges": edges} - self.top_level_nodes = [] - for node in self._nodes: - if node_id := node.get("id"): - self.top_level_nodes.append(node_id) + self.top_level_vertices = [] + for vertex in self._vertices: + if vertex_id := vertex.get("id"): + self.top_level_vertices.append(vertex_id) self._graph_data = process_flow(self.raw_graph_data) - self._nodes = self._graph_data["nodes"] + self._vertices = self._graph_data["nodes"] self._edges = self._graph_data["edges"] self._build_graph() + def __getstate__(self): + return self.raw_graph_data + def __setstate__(self, state): - self.__dict__.update(state) - for edge in self.edges: - edge.reset() - edge.validate_edge() + self.__init__(**state) @classmethod def from_payload(cls, payload: Dict) -> "Graph": @@ -54,9 +54,9 @@ class Graph: if "data" in payload: payload = payload["data"] try: - nodes = payload["nodes"] + vertices = payload["nodes"] edges = payload["edges"] - return cls(nodes, edges) + return cls(vertices, edges) except KeyError as exc: logger.exception(exc) raise ValueError( @@ -69,61 +69,69 @@ class Graph: return self.__repr__() == other.__repr__() def _build_graph(self) -> None: - """Builds the graph from the nodes and edges.""" - self.nodes = self._build_vertices() + """Builds the graph from the vertices and edges.""" + self.vertices = self._build_vertices() + self.vertex_ids = [vertex.id for vertex in self.vertices] self.edges = self._build_edges() - for edge in self.edges: - edge.source.add_edge(edge) - edge.target.add_edge(edge) - # This is a hack to make sure that the LLM node is sent to - # the toolkit node - self._build_node_params() - # remove invalid nodes - self._validate_nodes() + # This is a hack to make sure that the LLM vertex is sent to + # the toolkit vertex + self._build_vertex_params() + # remove invalid vertices + self._validate_vertices() - def _build_node_params(self) -> None: - """Identifies and handles the LLM node within the graph.""" - llm_node = None - for node in self.nodes: - node._build_params() - if isinstance(node, LLMVertex): - llm_node = node + def _build_vertex_params(self) -> None: + """Identifies and handles the LLM vertex within the graph.""" + llm_vertex = None + for vertex in self.vertices: + vertex._build_params() + if isinstance(vertex, LLMVertex): + llm_vertex = vertex - if llm_node: - for node in self.nodes: - if isinstance(node, ToolkitVertex): - node.params["llm"] = llm_node + if llm_vertex: + for vertex in self.vertices: + if isinstance(vertex, ToolkitVertex): + vertex.params["llm"] = llm_vertex - def _validate_nodes(self) -> None: - """Check that all nodes have edges""" - if len(self.nodes) == 1: + def _validate_vertices(self) -> None: + """Check that all vertices have edges""" + if len(self.vertices) == 1: return - for node in self.nodes: - if not self._validate_node(node): - raise ValueError(f"{node.vertex_type} is not connected to any other components") + for vertex in self.vertices: + if not self._validate_vertex(vertex): + raise ValueError(f"{vertex.vertex_type} is not connected to any other components") - def _validate_node(self, node: Vertex) -> bool: - """Validates a node.""" - # All nodes that do not have edges are invalid - return len(node.edges) > 0 + def _validate_vertex(self, vertex: Vertex) -> bool: + """Validates a vertex.""" + # All vertices that do not have edges are invalid + return len(self.get_vertex_edges(vertex.id)) > 0 - def get_node(self, node_id: str) -> Union[None, Vertex]: - """Returns a node by id.""" - return next((node for node in self.nodes if node.id == node_id), None) + def get_vertex(self, vertex_id: str) -> Union[None, Vertex]: + """Returns a vertex by id.""" + return next((vertex for vertex in self.vertices if vertex.id == vertex_id), None) - def get_nodes_with_target(self, node: Vertex) -> List[Vertex]: - """Returns the nodes connected to a node.""" - connected_nodes: List[Vertex] = [edge.source for edge in self.edges if edge.target == node] - return connected_nodes + def get_vertex_edges(self, vertex_id: str) -> List[Edge]: + """Returns a list of edges for a given vertex.""" + return [edge for edge in self.edges if edge.source_id == vertex_id or edge.target_id == vertex_id] + + def get_vertices_with_target(self, vertex_id: str) -> List[Vertex]: + """Returns the vertices connected to a vertex.""" + vertices: List[Vertex] = [] + for edge in self.edges: + if edge.target_id == vertex_id: + vertex = self.get_vertex(edge.source_id) + if vertex is None: + continue + vertices.append(vertex) + return vertices async def build(self) -> Chain: """Builds the graph.""" - # Get root node - root_node = payload.get_root_node(self) - if root_node is None: - raise ValueError("No root node found") - return await root_node.build() + # Get root vertex + root_vertex = payload.get_root_vertex(self) + if root_vertex is None: + raise ValueError("No root vertex found") + return await root_vertex.build() def topological_sort(self) -> List[Vertex]: """ @@ -136,25 +144,25 @@ class Graph: ValueError: If the graph contains a cycle. """ # States: 0 = unvisited, 1 = visiting, 2 = visited - state = {node: 0 for node in self.nodes} + state = {vertex: 0 for vertex in self.vertices} sorted_vertices = [] - def dfs(node): - if state[node] == 1: + def dfs(vertex): + if state[vertex] == 1: # We have a cycle raise ValueError("Graph contains a cycle, cannot perform topological sort") - if state[node] == 0: - state[node] = 1 - for edge in node.edges: - if edge.source == node: + if state[vertex] == 0: + state[vertex] = 1 + for edge in vertex.edges: + if edge.source == vertex: dfs(edge.target) - state[node] = 2 - sorted_vertices.append(node) + state[vertex] = 2 + sorted_vertices.append(vertex) - # Visit each node - for node in self.nodes: - if state[node] == 0: - dfs(node) + # Visit each vertex + for vertex in self.vertices: + if state[vertex] == 0: + dfs(vertex) return list(reversed(sorted_vertices)) @@ -164,17 +172,21 @@ class Graph: logger.debug("There are %s vertices in the graph", len(sorted_vertices)) yield from sorted_vertices - def get_node_neighbors(self, node: Vertex) -> Dict[Vertex, int]: - """Returns the neighbors of a node.""" + def get_vertex_neighbors(self, vertex: Vertex) -> Dict[Vertex, int]: + """Returns the neighbors of a vertex.""" neighbors: Dict[Vertex, int] = {} for edge in self.edges: - if edge.source == node: - neighbor = edge.target + if edge.source_id == vertex.id: + neighbor = self.get_vertex(edge.target_id) + if neighbor is None: + continue if neighbor not in neighbors: neighbors[neighbor] = 0 neighbors[neighbor] += 1 - elif edge.target == node: - neighbor = edge.source + elif edge.target_id == vertex.id: + neighbor = self.get_vertex(edge.source_id) + if neighbor is None: + continue if neighbor not in neighbors: neighbors[neighbor] = 0 neighbors[neighbor] += 1 @@ -182,59 +194,59 @@ class Graph: def _build_edges(self) -> List[Edge]: """Builds the edges of the graph.""" - # Edge takes two nodes as arguments, so we need to build the nodes first + # Edge takes two vertices as arguments, so we need to build the vertices first # and then build the edges - # if we can't find a node, we raise an error + # if we can't find a vertex, we raise an error edges: List[Edge] = [] for edge in self._edges: - source = self.get_node(edge["source"]) - target = self.get_node(edge["target"]) + source = self.get_vertex(edge["source"]) + target = self.get_vertex(edge["target"]) if source is None: - raise ValueError(f"Source node {edge['source']} not found") + raise ValueError(f"Source vertex {edge['source']} not found") if target is None: - raise ValueError(f"Target node {edge['target']} not found") + raise ValueError(f"Target vertex {edge['target']} not found") edges.append(Edge(source, target, edge)) return edges - def _get_vertex_class(self, node_type: str, node_lc_type: str) -> Type[Vertex]: - """Returns the node class based on the node type.""" - if node_type in FILE_TOOLS: + def _get_vertex_class(self, vertex_type: str, vertex_lc_type: str) -> Type[Vertex]: + """Returns the vertex class based on the vertex type.""" + if vertex_type in FILE_TOOLS: return FileToolVertex - if node_type in lazy_load_vertex_dict.VERTEX_TYPE_MAP: - return lazy_load_vertex_dict.VERTEX_TYPE_MAP[node_type] + if vertex_type in lazy_load_vertex_dict.VERTEX_TYPE_MAP: + return lazy_load_vertex_dict.VERTEX_TYPE_MAP[vertex_type] return ( - lazy_load_vertex_dict.VERTEX_TYPE_MAP[node_lc_type] - if node_lc_type in lazy_load_vertex_dict.VERTEX_TYPE_MAP + lazy_load_vertex_dict.VERTEX_TYPE_MAP[vertex_lc_type] + if vertex_lc_type in lazy_load_vertex_dict.VERTEX_TYPE_MAP else Vertex ) def _build_vertices(self) -> List[Vertex]: """Builds the vertices of the graph.""" - nodes: List[Vertex] = [] - for node in self._nodes: - node_data = node["data"] - node_type: str = node_data["type"] # type: ignore - node_lc_type: str = node_data["node"]["template"]["_type"] # type: ignore + vertices: List[Vertex] = [] + for vertex in self._vertices: + vertex_data = vertex["data"] + vertex_type: str = vertex_data["type"] # type: ignore + vertex_lc_type: str = vertex_data["node"]["template"]["_type"] # type: ignore - VertexClass = self._get_vertex_class(node_type, node_lc_type) - vertex = VertexClass(node) - vertex.set_top_level(self.top_level_nodes) - nodes.append(vertex) + VertexClass = self._get_vertex_class(vertex_type, vertex_lc_type) + vertex = VertexClass(vertex, graph=self) + vertex.set_top_level(self.top_level_vertices) + vertices.append(vertex) - return nodes + return vertices - def get_children_by_node_type(self, node: Vertex, node_type: str) -> List[Vertex]: - """Returns the children of a node based on the node type.""" + def get_children_by_vertex_type(self, vertex: Vertex, vertex_type: str) -> List[Vertex]: + """Returns the children of a vertex based on the vertex type.""" children = [] - node_types = [node.data["type"]] - if "node" in node.data: - node_types += node.data["node"]["base_classes"] - if node_type in node_types: - children.append(node) + vertex_types = [vertex.data["type"]] + if "node" in vertex.data: + vertex_types += vertex.data["node"]["base_classes"] + if vertex_type in vertex_types: + children.append(vertex) return children def __repr__(self): - node_ids = [node.id for node in self.nodes] - edges_repr = "\n".join([f"{edge.source.id} --> {edge.target.id}" for edge in self.edges]) - return f"Graph:\nNodes: {node_ids}\nConnections:\n{edges_repr}" + vertex_ids = [vertex.id for vertex in self.vertices] + edges_repr = "\n".join([f"{edge.source_id} --> {edge.target_id}" for edge in self.edges]) + return f"Graph:\nNodes: {vertex_ids}\nConnections:\n{edges_repr}" diff --git a/src/backend/langflow/graph/vertex/base.py b/src/backend/langflow/graph/vertex/base.py index 5ea645980..dc9e76f8a 100644 --- a/src/backend/langflow/graph/vertex/base.py +++ b/src/backend/langflow/graph/vertex/base.py @@ -1,33 +1,32 @@ import ast import inspect -import pickle import types from typing import TYPE_CHECKING, Any, Dict, List, Optional -from loguru import logger - from langflow.graph.utils import UnbuiltObject -from langflow.graph.vertex.utils import is_basic_type from langflow.interface.initialize import loading from langflow.interface.listing import lazy_load_dict from langflow.utils.constants import DIRECT_TYPES from langflow.utils.util import sync_to_async +from loguru import logger if TYPE_CHECKING: from langflow.graph.edge.base import Edge + from langflow.graph.graph.base import Graph class Vertex: def __init__( self, data: Dict, + graph: "Graph", base_type: Optional[str] = None, is_task: bool = False, params: Optional[Dict] = None, ) -> None: + self.graph = graph self.id: str = data["id"] self._data = data - self.edges: List["Edge"] = [] self.base_type: Optional[str] = base_type self._parse_data() self._built_object = UnbuiltObject() @@ -39,43 +38,28 @@ class Vertex: self.parent_node_id: Optional[str] = self._data.get("parent_node_id") self.parent_is_top_level = False - def reset_params(self): - for edge in self.edges: - if edge.source != self: - target_param = edge.target_param - if target_param in ["document", "texts"]: - # this means they got data and have already ingested it - # so we continue after removing the param - self.params.pop(target_param, None) - continue - - if target_param in self.params and not is_basic_type(self.params[target_param]): - # edge.source.params = {} - edge.source._build_params() - edge.source._built_object = UnbuiltObject() - edge.source._built = False - - self.params[target_param] = edge.source + @property + def edges(self) -> List["Edge"]: + return self.graph.get_vertex_edges(self.id) def __getstate__(self): - state_dict = self.__dict__.copy() - try: - # try pickling the built object - # if it fails, then we need to delete it - # and build it again - pickle.dumps(state_dict["_built_object"]) - except Exception: - self.reset_params() - del state_dict["_built_object"] - del state_dict["_built"] - return state_dict + return { + "_data": self._data, + "params": {}, + "base_type": self.base_type, + "is_task": self.is_task, + "id": self.id, + "_built_object": UnbuiltObject(), + "_built": False, + "parent_node_id": self.parent_node_id, + "parent_is_top_level": self.parent_is_top_level, + } def __setstate__(self, state): self._data = state["_data"] self.params = state["params"] self.base_type = state["base_type"] self.is_task = state["is_task"] - self.edges = state["edges"] self.id = state["id"] self._parse_data() if "_built_object" in state: @@ -144,6 +128,10 @@ class Vertex: # and use that as the value for the param # If the type is "str", then we need to get the value of the "value" key # and use that as the value for the param + + if self.graph is None: + raise ValueError("Graph not found") + template_dict = {key: value for key, value in self.data["node"]["template"].items() if isinstance(value, dict)} params = self.params.copy() if self.params else {} @@ -155,9 +143,9 @@ class Vertex: if template_dict[param_key]["list"]: if param_key not in params: params[param_key] = [] - params[param_key].append(edge.source) - elif edge.target.id == self.id: - params[param_key] = edge.source + params[param_key].append(self.graph.get_vertex(edge.source_id)) + elif edge.target_id == self.id: + params[param_key] = self.graph.get_vertex(edge.source_id) for key, value in template_dict.items(): if key in params: @@ -177,33 +165,33 @@ class Vertex: else: raise ValueError(f"File path not found for {self.vertex_type}") elif value.get("type") in DIRECT_TYPES and params.get(key) is None: + val = value.get("value") if value.get("type") == "code": try: - params[key] = ast.literal_eval(value.get("value")) + params[key] = ast.literal_eval(val) if val else None except Exception as exc: logger.debug(f"Error parsing code: {exc}") - params[key] = value.get("value") + params[key] = val elif value.get("type") in ["dict", "NestedDict"]: # When dict comes from the frontend it comes as a # list of dicts, so we need to convert it to a dict # before passing it to the build method - _value = value.get("value") - if isinstance(_value, list): + if isinstance(val, list): params[key] = {k: v for item in value.get("value", []) for k, v in item.items()} - elif isinstance(_value, dict): - params[key] = _value - elif value.get("type") == "int" and value.get("value") is not None: + elif isinstance(val, dict): + params[key] = val + elif value.get("type") == "int" and val is not None: try: - params[key] = int(value.get("value")) + params[key] = int(val) except ValueError: - params[key] = value.get("value") - elif value.get("type") == "float" and value.get("value") is not None: + params[key] = val + elif value.get("type") == "float" and val is not None: try: - params[key] = float(value.get("value")) + params[key] = float(val) except ValueError: - params[key] = value.get("value") + params[key] = val else: - params[key] = value.get("value") + params[key] = val if not value.get("required") and params.get(key) is None: if value.get("default"): @@ -266,7 +254,7 @@ class Vertex: pass # If there's no task_id, build the vertex locally - await self.build(user_id) + await self.build(user_id=user_id) return self._built_object async def _build_node_and_update_params(self, key, node, user_id=None): diff --git a/src/backend/langflow/graph/vertex/types.py b/src/backend/langflow/graph/vertex/types.py index c288a4b0a..92c920d35 100644 --- a/src/backend/langflow/graph/vertex/types.py +++ b/src/backend/langflow/graph/vertex/types.py @@ -1,14 +1,14 @@ import ast from typing import Any, Dict, List, Optional, Union -from langflow.graph.utils import flatten_list +from langflow.graph.utils import UnbuiltObject, flatten_list from langflow.graph.vertex.base import Vertex from langflow.interface.utils import extract_input_variables_from_prompt class AgentVertex(Vertex): - def __init__(self, data: Dict, params: Optional[Dict] = None): - super().__init__(data, base_type="agents", params=params) + def __init__(self, data: Dict, graph, params: Optional[Dict] = None): + super().__init__(data, graph=graph, base_type="agents", params=params) self.tools: List[Union[ToolkitVertex, ToolVertex]] = [] self.chains: List[ChainVertex] = [] @@ -28,7 +28,7 @@ class AgentVertex(Vertex): for edge in self.edges: if not hasattr(edge, "source"): continue - source_node = edge.source + source_node = self.graph.get_vertex(edge.source_id) if isinstance(source_node, (ToolVertex, ToolkitVertex)): self.tools.append(source_node) elif isinstance(source_node, ChainVertex): @@ -51,16 +51,21 @@ class AgentVertex(Vertex): class ToolVertex(Vertex): - def __init__(self, data: Dict, params: Optional[Dict] = None): - super().__init__(data, base_type="tools", params=params) + def __init__( + self, + data: Dict, + graph, + params: Optional[Dict] = None, + ): + super().__init__(data, graph=graph, base_type="tools", params=params) class LLMVertex(Vertex): built_node_type = None class_built_object = None - def __init__(self, data: Dict, params: Optional[Dict] = None): - super().__init__(data, base_type="llms", params=params) + def __init__(self, data: Dict, graph, params: Optional[Dict] = None): + super().__init__(data, graph=graph, base_type="llms", params=params) async def build(self, force: bool = False, user_id=None, *args, **kwargs) -> Any: # LLM is different because some models might take up too much memory @@ -77,18 +82,18 @@ class LLMVertex(Vertex): class ToolkitVertex(Vertex): - def __init__(self, data: Dict, params=None): - super().__init__(data, base_type="toolkits", params=params) + def __init__(self, data: Dict, graph, params=None): + super().__init__(data, graph=graph, base_type="toolkits", params=params) class FileToolVertex(ToolVertex): - def __init__(self, data: Dict, params=None): - super().__init__(data, params=params) + def __init__(self, data: Dict, graph, params=None): + super().__init__(data, graph=graph, params=params) class WrapperVertex(Vertex): - def __init__(self, data: Dict): - super().__init__(data, base_type="wrappers") + def __init__(self, data: Dict, graph): + super().__init__(data, graph=graph, base_type="wrappers") async def build(self, force: bool = False, user_id=None, *args, **kwargs) -> Any: if not self._built or force: @@ -99,14 +104,14 @@ class WrapperVertex(Vertex): class DocumentLoaderVertex(Vertex): - def __init__(self, data: Dict, params: Optional[Dict] = None): - super().__init__(data, base_type="documentloaders", params=params) + def __init__(self, data: Dict, graph, params: Optional[Dict] = None): + super().__init__(data, graph=graph, base_type="documentloaders", params=params) def _built_object_repr(self): # This built_object is a list of documents. Maybe we should # show how many documents are in the list? - if self._built_object: + if self._built_object and not isinstance(self._built_object, UnbuiltObject): avg_length = sum(len(doc.page_content) for doc in self._built_object if hasattr(doc, "page_content")) / len( self._built_object ) @@ -117,28 +122,19 @@ class DocumentLoaderVertex(Vertex): class EmbeddingVertex(Vertex): - def __init__(self, data: Dict, params: Optional[Dict] = None): - super().__init__(data, base_type="embeddings", params=params) + def __init__(self, data: Dict, graph, params: Optional[Dict] = None): + super().__init__(data, graph=graph, base_type="embeddings", params=params) class VectorStoreVertex(Vertex): - def __init__(self, data: Dict, params=None): - super().__init__(data, base_type="vectorstores") + def __init__(self, data: Dict, graph, params=None): + super().__init__(data, graph=graph, base_type="vectorstores") self.params = params or {} # VectorStores may contain databse connections # so we need to define the __reduce__ method and the __setstate__ method # to avoid pickling errors - def clean_edges_for_pickling(self): - # for each edge that has self as source - # we need to clear the _built_object of the target - # so that we don't try to pickle a database connection - for edge in self.edges: - if edge.source == self: - edge.target._built_object = None - edge.target._built = False - edge.target.params[edge.target_param] = self def remove_docs_and_texts_from_params(self): # remove documents and texts from params @@ -146,17 +142,16 @@ class VectorStoreVertex(Vertex): self.params.pop("documents", None) self.params.pop("texts", None) - def __getstate__(self): - # We want to save the params attribute - # and if "documents" or "texts" are in the params - # we want to remove them because they have already - # been processed. - params = self.params.copy() - params.pop("documents", None) - params.pop("texts", None) - self.clean_edges_for_pickling() + # def __getstate__(self): + # # We want to save the params attribute + # # and if "documents" or "texts" are in the params + # # we want to remove them because they have already + # # been processed. + # params = self.params.copy() + # params.pop("documents", None) + # params.pop("texts", None) - return super().__getstate__() + # return super().__getstate__() def __setstate__(self, state): super().__setstate__(state) @@ -164,24 +159,24 @@ class VectorStoreVertex(Vertex): class MemoryVertex(Vertex): - def __init__(self, data: Dict): - super().__init__(data, base_type="memory") + def __init__(self, data: Dict, graph): + super().__init__(data, graph=graph, base_type="memory") class RetrieverVertex(Vertex): - def __init__(self, data: Dict): - super().__init__(data, base_type="retrievers") + def __init__(self, data: Dict, graph): + super().__init__(data, graph=graph, base_type="retrievers") class TextSplitterVertex(Vertex): - def __init__(self, data: Dict, params: Optional[Dict] = None): - super().__init__(data, base_type="textsplitters", params=params) + def __init__(self, data: Dict, graph, params: Optional[Dict] = None): + super().__init__(data, graph=graph, base_type="textsplitters", params=params) def _built_object_repr(self): # This built_object is a list of documents. Maybe we should # show how many documents are in the list? - if self._built_object: + if self._built_object and not isinstance(self._built_object, UnbuiltObject): avg_length = sum(len(doc.page_content) for doc in self._built_object) / len(self._built_object) return f"""{self.vertex_type}({len(self._built_object)} documents) \nAvg. Document Length (characters): {int(avg_length)} @@ -190,8 +185,8 @@ class TextSplitterVertex(Vertex): class ChainVertex(Vertex): - def __init__(self, data: Dict): - super().__init__(data, base_type="chains") + def __init__(self, data: Dict, graph): + super().__init__(data, graph=graph, base_type="chains") async def build( self, @@ -220,8 +215,8 @@ class ChainVertex(Vertex): class PromptVertex(Vertex): - def __init__(self, data: Dict): - super().__init__(data, base_type="prompts") + def __init__(self, data: Dict, graph): + super().__init__(data, graph=graph, base_type="prompts") async def build( self, @@ -271,9 +266,13 @@ class PromptVertex(Vertex): # so the prompt format doesn't break artifacts.pop("handle_keys", None) try: - if not hasattr(self._built_object, "template") and hasattr(self._built_object, "prompt"): + if ( + not hasattr(self._built_object, "template") + and hasattr(self._built_object, "prompt") + and not isinstance(self._built_object, UnbuiltObject) + ): template = self._built_object.prompt.template - else: + elif not isinstance(self._built_object, UnbuiltObject) and hasattr(self._built_object, "template"): template = self._built_object.template for key, value in artifacts.items(): if value: @@ -285,13 +284,13 @@ class PromptVertex(Vertex): class OutputParserVertex(Vertex): - def __init__(self, data: Dict): - super().__init__(data, base_type="output_parsers") + def __init__(self, data: Dict, graph): + super().__init__(data, graph=graph, base_type="output_parsers") class CustomComponentVertex(Vertex): - def __init__(self, data: Dict): - super().__init__(data, base_type="custom_components", is_task=True) + def __init__(self, data: Dict, graph): + super().__init__(data, graph=graph, base_type="custom_components", is_task=True) def _built_object_repr(self): if self.task_id and self.is_task: diff --git a/src/backend/langflow/interface/custom/component.py b/src/backend/langflow/interface/custom/component.py index 98ccf8db3..594ec982f 100644 --- a/src/backend/langflow/interface/custom/component.py +++ b/src/backend/langflow/interface/custom/component.py @@ -1,9 +1,11 @@ import ast import operator +import warnings from typing import Any, ClassVar, Optional from cachetools import TTLCache, cachedmethod from fastapi import HTTPException + from langflow.interface.custom.code_parser import CodeParser from langflow.utils import validate @@ -23,11 +25,20 @@ class Component: code: Optional[str] = None _function_entrypoint_name: str = "build" field_config: dict = {} + _user_id: Optional[str] def __init__(self, **data): self.cache = TTLCache(maxsize=1024, ttl=60) for key, value in data.items(): - setattr(self, key, value) + if key == "user_id": + setattr(self, "_user_id", value) + else: + setattr(self, key, value) + + def __setattr__(self, key, value): + if key == "_user_id" and hasattr(self, "_user_id"): + warnings.warn("user_id is immutable and cannot be changed.") + super().__setattr__(key, value) @cachedmethod(cache=operator.attrgetter("cache")) def get_code_tree(self, code: str): diff --git a/src/backend/langflow/interface/custom/custom_component.py b/src/backend/langflow/interface/custom/custom_component.py index 032ed1476..f887ed025 100644 --- a/src/backend/langflow/interface/custom/custom_component.py +++ b/src/backend/langflow/interface/custom/custom_component.py @@ -5,7 +5,6 @@ from uuid import UUID import yaml from cachetools import TTLCache, cachedmethod from fastapi import HTTPException - from langflow.field_typing.constants import CUSTOM_COMPONENT_SUPPORTED_TYPES from langflow.interface.custom.component import Component from langflow.interface.custom.directory_reader import DirectoryReader @@ -15,7 +14,7 @@ from langflow.interface.custom.utils import ( ) from langflow.services.database.models.flow import Flow from langflow.services.database.utils import session_getter -from langflow.services.deps import get_db_service +from langflow.services.deps import get_credential_service, get_db_service from langflow.utils import validate @@ -184,6 +183,37 @@ class CustomComponent(Component): return super().build_template_config(attributes) + @property + def keys(self): + def get_credential(name: str): + if hasattr(self, "_user_id") and not self._user_id: + raise ValueError(f"User id is not set for {self.__class__.__name__}") + credential_service = get_credential_service() # Get service instance + # Retrieve and decrypt the credential by name for the current user + db_service = get_db_service() + with session_getter(db_service) as session: + return credential_service.get_credential(user_id=self._user_id, name=name, session=session) + + return get_credential + + def list_key_names(self): + if hasattr(self, "_user_id") and not self._user_id: + raise ValueError(f"User id is not set for {self.__class__.__name__}") + credential_service = get_credential_service() + db_service = get_db_service() + with session_getter(db_service) as session: + return credential_service.list_credentials(user_id=self._user_id, session=session) + + def index(self, value: int = 0): + """Returns a function that returns the value at the given index in the iterable.""" + + def get_index(iterable: List[Any]): + if iterable: + return iterable[value] + return iterable + + return get_index + @property def get_function(self): return validate.create_function(self.code, self.function_entrypoint_name) @@ -201,7 +231,7 @@ class CustomComponent(Component): return await build_sorted_vertices(graph_data, self.user_id) def list_flows(self, *, get_session: Optional[Callable] = None) -> List[Flow]: - if not self.user_id: + if not self._user_id: raise ValueError("Session is invalid") try: get_session = get_session or session_getter diff --git a/src/backend/langflow/interface/types.py b/src/backend/langflow/interface/types.py index 94c924033..1095c380e 100644 --- a/src/backend/langflow/interface/types.py +++ b/src/backend/langflow/interface/types.py @@ -3,13 +3,11 @@ import contextlib import re import traceback import warnings -from typing import Any, List, Optional, Union +from typing import Any, Dict, List, Optional, Union from uuid import UUID from cachetools import LRUCache, cached from fastapi import HTTPException -from loguru import logger - from langflow.api.utils import get_new_key from langflow.interface.agents.base import agent_creator from langflow.interface.chains.base import chain_creator @@ -35,6 +33,7 @@ from langflow.template.field.base import TemplateField from langflow.template.frontend_node.constants import CLASSES_TO_REMOVE from langflow.template.frontend_node.custom_components import CustomComponentFrontendNode from langflow.utils.util import get_base_classes +from loguru import logger # Used to get the base_classes list @@ -201,7 +200,9 @@ def update_attributes(frontend_node, template_config): frontend_node[attribute] = template_config[attribute] -def build_field_config(custom_component: CustomComponent, user_id: Optional[Union[str, UUID]] = None): +def build_field_config( + custom_component: CustomComponent, user_id: Optional[Union[str, UUID]] = None, update_field=None +): """Build the field configuration for a custom component""" try: @@ -222,7 +223,19 @@ def build_field_config(custom_component: CustomComponent, user_id: Optional[Unio ) from exc try: - return custom_class(user_id=user_id).build_config() + build_config: Dict = custom_class(user_id=user_id).build_config() + + for field_name, field_dict in build_config.items(): + if update_field is not None and field_name != update_field: + continue + try: + update_field_dict(field_dict) + build_config[field_name] = field_dict + except Exception as exc: + logger.error(f"Error while getting build_config: {str(exc)}") + + return build_config + except Exception as exc: logger.error(f"Error while building field config: {str(exc)}") raise HTTPException( @@ -234,6 +247,18 @@ def build_field_config(custom_component: CustomComponent, user_id: Optional[Unio ) from exc +def update_field_dict(field_dict): + """Update the field dictionary by calling options() or value() if they are callable""" + if "options" in field_dict and callable(field_dict["options"]): + field_dict["options"] = field_dict["options"]() + # Also update the "refresh" key + field_dict["refresh"] = True + + if "value" in field_dict and callable(field_dict["value"]): + field_dict["value"] = field_dict["value"](field_dict.get("options", [])) + field_dict["refresh"] = True + + def add_extra_fields(frontend_node, field_config, function_args): """Add extra fields to the frontend node""" if not function_args: @@ -314,7 +339,9 @@ def add_output_types(frontend_node, return_types: List[str]): def build_langchain_template_custom_component( - custom_component: CustomComponent, user_id: Optional[Union[str, UUID]] = None + custom_component: CustomComponent, + user_id: Optional[Union[str, UUID]] = None, + update_field: Optional[str] = None, ): """Build a custom component template for the langchain""" try: @@ -328,7 +355,7 @@ def build_langchain_template_custom_component( update_attributes(frontend_node, template_config) logger.debug("Updated attributes") - field_config = build_field_config(custom_component, user_id=user_id) + field_config = build_field_config(custom_component, user_id=user_id, update_field=update_field) logger.debug("Built field config") entrypoint_args = custom_component.get_function_entrypoint_args @@ -514,3 +541,9 @@ def merge_nested_dicts(dict1, dict2): else: dict1[key] = value return dict1 + + +def create_and_validate_component(code: str) -> CustomComponent: + component = CustomComponent(code=code) + component.validate() + return component diff --git a/src/backend/langflow/services/auth/utils.py b/src/backend/langflow/services/auth/utils.py index da0ee7396..912d1fbe8 100644 --- a/src/backend/langflow/services/auth/utils.py +++ b/src/backend/langflow/services/auth/utils.py @@ -8,10 +8,10 @@ from fastapi.security import APIKeyHeader, APIKeyQuery, OAuth2PasswordBearer from jose import JWTError, jwt from sqlmodel import Session -from langflow.services.database.models.api_key.api_key import ApiKey +from langflow.services.database.models.api_key.model import ApiKey from langflow.services.database.models.api_key.crud import check_key from langflow.services.database.models.user.crud import get_user_by_id, get_user_by_username, update_user_last_login_at -from langflow.services.database.models.user.user import User +from langflow.services.database.models.user.model import User from langflow.services.deps import get_session, get_settings_service oauth2_login = OAuth2PasswordBearer(tokenUrl="api/v1/login", auto_error=False) diff --git a/src/backend/langflow/services/credentials/__init__.py b/src/backend/langflow/services/credentials/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/backend/langflow/services/credentials/factory.py b/src/backend/langflow/services/credentials/factory.py new file mode 100644 index 000000000..c44a43da4 --- /dev/null +++ b/src/backend/langflow/services/credentials/factory.py @@ -0,0 +1,15 @@ +from typing import TYPE_CHECKING + +from langflow.services.credentials.service import CredentialService +from langflow.services.factory import ServiceFactory + +if TYPE_CHECKING: + from langflow.services.settings.service import SettingsService + + +class CredentialServiceFactory(ServiceFactory): + def __init__(self): + super().__init__(CredentialService) + + def create(self, settings_service: "SettingsService"): + return CredentialService(settings_service) diff --git a/src/backend/langflow/services/credentials/service.py b/src/backend/langflow/services/credentials/service.py new file mode 100644 index 000000000..1d37fc6b9 --- /dev/null +++ b/src/backend/langflow/services/credentials/service.py @@ -0,0 +1,32 @@ +from typing import TYPE_CHECKING, Union +from uuid import UUID + +from fastapi import Depends +from langflow.services.auth import utils as auth_utils +from langflow.services.base import Service +from langflow.services.database.models.credential.model import Credential +from langflow.services.deps import get_session +from sqlmodel import Session + +if TYPE_CHECKING: + from langflow.services.settings.service import SettingsService + + +class CredentialService(Service): + name = "credential_service" + + def __init__(self, settings_service: "SettingsService"): + self.settings_service = settings_service + + def get_credential(self, user_id: Union[UUID, str], name: str, session: Session = Depends(get_session)) -> str: + # we get the credential from the database + credential = session.query(Credential).filter(Credential.user_id == user_id, Credential.name == name).first() + # we decrypt the value + if not credential: + raise ValueError(f"{name} credential not found.") + decrypted = auth_utils.decrypt_api_key(credential.value, settings_service=self.settings_service) + return decrypted + + def list_credentials(self, user_id: Union[UUID, str], session: Session = Depends(get_session)) -> list[Credential]: + credentials = session.query(Credential).filter(Credential.user_id == user_id).all() + return [credential.name for credential in credentials] diff --git a/src/backend/langflow/services/database/models/__init__.py b/src/backend/langflow/services/database/models/__init__.py index 3cc4231a3..9dd3e0285 100644 --- a/src/backend/langflow/services/database/models/__init__.py +++ b/src/backend/langflow/services/database/models/__init__.py @@ -1,5 +1,6 @@ +from .api_key import ApiKey +from .credential import Credential from .flow import Flow from .user import User -from .api_key import ApiKey -__all__ = ["Flow", "User", "ApiKey"] +__all__ = ["Flow", "User", "ApiKey", "Credential"] diff --git a/src/backend/langflow/services/database/models/api_key/__init__.py b/src/backend/langflow/services/database/models/api_key/__init__.py index fbb8265b9..001b0327e 100644 --- a/src/backend/langflow/services/database/models/api_key/__init__.py +++ b/src/backend/langflow/services/database/models/api_key/__init__.py @@ -1,3 +1,3 @@ -from .api_key import ApiKey, ApiKeyCreate, UnmaskedApiKeyRead, ApiKeyRead +from .model import ApiKey, ApiKeyCreate, UnmaskedApiKeyRead, ApiKeyRead __all__ = ["ApiKey", "ApiKeyCreate", "UnmaskedApiKeyRead", "ApiKeyRead"] diff --git a/src/backend/langflow/services/database/models/api_key/api_key.py b/src/backend/langflow/services/database/models/api_key/model.py similarity index 86% rename from src/backend/langflow/services/database/models/api_key/api_key.py rename to src/backend/langflow/services/database/models/api_key/model.py index 684027ee2..1d81a09c2 100644 --- a/src/backend/langflow/services/database/models/api_key/api_key.py +++ b/src/backend/langflow/services/database/models/api_key/model.py @@ -1,15 +1,15 @@ -from pydantic import validator -from sqlmodel import Field, Relationship -from uuid import UUID, uuid4 -from typing import Optional, TYPE_CHECKING from datetime import datetime -from langflow.services.database.models.base import SQLModelSerializable +from typing import TYPE_CHECKING, Optional +from uuid import UUID, uuid4 + +from pydantic import validator +from sqlmodel import Field, Relationship, SQLModel if TYPE_CHECKING: from langflow.services.database.models.user import User -class ApiKeyBase(SQLModelSerializable): +class ApiKeyBase(SQLModel): name: Optional[str] = Field(index=True) created_at: datetime = Field(default_factory=datetime.utcnow) last_used_at: Optional[datetime] = Field(default=None, nullable=True) diff --git a/src/backend/langflow/services/database/models/base.py b/src/backend/langflow/services/database/models/base.py index 9dff68c19..53ee2c37e 100644 --- a/src/backend/langflow/services/database/models/base.py +++ b/src/backend/langflow/services/database/models/base.py @@ -1,4 +1,3 @@ -from sqlmodel import SQLModel import orjson @@ -16,9 +15,3 @@ def orjson_dumps(v, *, default=None, sort_keys=False, indent_2=True): if default is None: return orjson.dumps(v, option=option).decode() return orjson.dumps(v, default=default, option=option).decode() - - -class SQLModelSerializable(SQLModel): - # TODO[pydantic]: The following keys were removed: `json_loads`, `json_dumps`. - # Check https://docs.pydantic.dev/dev-v2/migration/#changes-to-config for more information. - pass diff --git a/src/backend/langflow/services/database/models/component/__init__.py b/src/backend/langflow/services/database/models/component/__init__.py index c787c3e04..c5ad7d47f 100644 --- a/src/backend/langflow/services/database/models/component/__init__.py +++ b/src/backend/langflow/services/database/models/component/__init__.py @@ -1,3 +1,3 @@ -from .component import Component, ComponentModel +from .model import Component, ComponentModel __all__ = ["Component", "ComponentModel"] diff --git a/src/backend/langflow/services/database/models/component/component.py b/src/backend/langflow/services/database/models/component/model.py similarity index 85% rename from src/backend/langflow/services/database/models/component/component.py rename to src/backend/langflow/services/database/models/component/model.py index 5c4e6c13a..0a5afc440 100644 --- a/src/backend/langflow/services/database/models/component/component.py +++ b/src/backend/langflow/services/database/models/component/model.py @@ -1,11 +1,11 @@ -from langflow.services.database.models.base import SQLModelSerializable, SQLModel -from sqlmodel import Field -from typing import Optional -from datetime import datetime import uuid +from datetime import datetime +from typing import Optional + +from sqlmodel import Field, SQLModel -class Component(SQLModelSerializable, table=True): +class Component(SQLModel, table=True): id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) frontend_node_id: uuid.UUID = Field(index=True) name: str = Field(index=True) diff --git a/src/backend/langflow/services/database/models/credential/__init__.py b/src/backend/langflow/services/database/models/credential/__init__.py new file mode 100644 index 000000000..2f8b6cd01 --- /dev/null +++ b/src/backend/langflow/services/database/models/credential/__init__.py @@ -0,0 +1,3 @@ +from .model import Credential, CredentialCreate, CredentialRead, CredentialUpdate + +__all__ = ["Credential", "CredentialCreate", "CredentialRead", "CredentialUpdate"] diff --git a/src/backend/langflow/services/database/models/credential/model.py b/src/backend/langflow/services/database/models/credential/model.py new file mode 100644 index 000000000..4a5424364 --- /dev/null +++ b/src/backend/langflow/services/database/models/credential/model.py @@ -0,0 +1,45 @@ +from datetime import datetime +from typing import TYPE_CHECKING, Optional +from uuid import UUID, uuid4 + +from langflow.services.database.models.credential.schema import CredentialType +from sqlmodel import Field, Relationship, SQLModel + +if TYPE_CHECKING: + from langflow.services.database.models.user import User + + +class CredentialBase(SQLModel): + name: Optional[str] = Field(None, description="Name of the credential") + value: Optional[str] = Field(None, description="Encrypted value of the credential") + provider: Optional[str] = Field(None, description="Provider of the credential (e.g OpenAI)") + + +class Credential(CredentialBase, table=True): + id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True, description="Unique ID for the credential") + # name is unique per user + created_at: datetime = Field(default_factory=datetime.utcnow, description="Creation time of the credential") + updated_at: Optional[datetime] = Field(None, description="Last update time of the credential") + # foreign key to user table + user_id: UUID = Field(description="User ID associated with this credential", foreign_key="user.id") + user: "User" = Relationship(back_populates="credentials") + + if TYPE_CHECKING: + user: "User" = Relationship(back_populates="credentials") + + +class CredentialCreate(CredentialBase): + # AcceptedProviders is a custom Enum + provider: CredentialType = Field(description="Provider of the credential (e.g OpenAI)") + + +class CredentialRead(SQLModel): + id: UUID + name: Optional[str] = Field(None, description="Name of the credential") + provider: Optional[str] = Field(None, description="Provider of the credential (e.g OpenAI)") + + +class CredentialUpdate(SQLModel): + id: UUID # Include the ID for updating + name: Optional[str] = Field(None, description="Name of the credential") + value: Optional[str] = Field(None, description="Encrypted value of the credential") diff --git a/src/backend/langflow/services/database/models/credential/schema.py b/src/backend/langflow/services/database/models/credential/schema.py new file mode 100644 index 000000000..985915340 --- /dev/null +++ b/src/backend/langflow/services/database/models/credential/schema.py @@ -0,0 +1,8 @@ +from enum import Enum + + +class CredentialType(str, Enum): + """CredentialType is an Enum of the accepted providers""" + + OPENAI_API_KEY = "OPENAI_API_KEY" + ANTHROPIC_API_KEY = "ANTHROPIC_API_KEY" diff --git a/src/backend/langflow/services/database/models/flow/__init__.py b/src/backend/langflow/services/database/models/flow/__init__.py index 7c7cc0172..3c861963c 100644 --- a/src/backend/langflow/services/database/models/flow/__init__.py +++ b/src/backend/langflow/services/database/models/flow/__init__.py @@ -1,3 +1,3 @@ -from .flow import Flow, FlowCreate, FlowRead, FlowUpdate +from .model import Flow, FlowCreate, FlowRead, FlowUpdate __all__ = ["Flow", "FlowCreate", "FlowRead", "FlowUpdate"] diff --git a/src/backend/langflow/services/database/models/flow/flow.py b/src/backend/langflow/services/database/models/flow/model.py similarity index 91% rename from src/backend/langflow/services/database/models/flow/flow.py rename to src/backend/langflow/services/database/models/flow/model.py index 5bd3802ba..51902a2b3 100644 --- a/src/backend/langflow/services/database/models/flow/flow.py +++ b/src/backend/langflow/services/database/models/flow/model.py @@ -5,15 +5,13 @@ from typing import TYPE_CHECKING, Dict, Optional from uuid import UUID, uuid4 from pydantic import field_serializer, field_validator -from sqlmodel import JSON, Column, Field, Relationship - -from langflow.services.database.models.base import SQLModelSerializable +from sqlmodel import JSON, Column, Field, Relationship, SQLModel if TYPE_CHECKING: from langflow.services.database.models.user import User -class FlowBase(SQLModelSerializable): +class FlowBase(SQLModel): name: str = Field(index=True) description: Optional[str] = Field(index=True, nullable=True, default=None) data: Optional[Dict] = Field(default=None, nullable=True) @@ -69,7 +67,7 @@ class FlowRead(FlowBase): user_id: UUID = Field() -class FlowUpdate(SQLModelSerializable): +class FlowUpdate(SQLModel): name: Optional[str] = None description: Optional[str] = None data: Optional[Dict] = None diff --git a/src/backend/langflow/services/database/models/user/__init__.py b/src/backend/langflow/services/database/models/user/__init__.py index da9170eb7..eecf6d0b1 100644 --- a/src/backend/langflow/services/database/models/user/__init__.py +++ b/src/backend/langflow/services/database/models/user/__init__.py @@ -1,4 +1,4 @@ -from .user import User, UserCreate, UserRead, UserUpdate +from .model import User, UserCreate, UserRead, UserUpdate __all__ = [ "User", diff --git a/src/backend/langflow/services/database/models/user/crud.py b/src/backend/langflow/services/database/models/user/crud.py index c7239bcee..75ce56038 100644 --- a/src/backend/langflow/services/database/models/user/crud.py +++ b/src/backend/langflow/services/database/models/user/crud.py @@ -2,7 +2,7 @@ from datetime import datetime, timezone from typing import Union from uuid import UUID from fastapi import Depends, HTTPException, status -from langflow.services.database.models.user.user import User, UserUpdate +from langflow.services.database.models.user.model import User, UserUpdate from langflow.services.deps import get_session from sqlalchemy.exc import IntegrityError from sqlmodel import Session diff --git a/src/backend/langflow/services/database/models/user/user.py b/src/backend/langflow/services/database/models/user/model.py similarity index 82% rename from src/backend/langflow/services/database/models/user/user.py rename to src/backend/langflow/services/database/models/user/model.py index 50525d025..5be02f1d0 100644 --- a/src/backend/langflow/services/database/models/user/user.py +++ b/src/backend/langflow/services/database/models/user/model.py @@ -1,17 +1,16 @@ -from langflow.services.database.models.base import SQLModel, SQLModelSerializable -from sqlmodel import Field, Relationship - - from datetime import datetime -from typing import Optional, TYPE_CHECKING +from typing import TYPE_CHECKING, Optional from uuid import UUID, uuid4 +from sqlmodel import Field, Relationship, SQLModel + if TYPE_CHECKING: from langflow.services.database.models.api_key import ApiKey + from langflow.services.database.models.credential import Credential from langflow.services.database.models.flow import Flow -class User(SQLModelSerializable, table=True): +class User(SQLModel, table=True): id: UUID = Field(default_factory=uuid4, primary_key=True, unique=True) username: str = Field(index=True, unique=True) password: str = Field() @@ -27,6 +26,10 @@ class User(SQLModelSerializable, table=True): ) store_api_key: str = Field(default=None, nullable=True) flows: list["Flow"] = Relationship(back_populates="user") + credentials: list["Credential"] = Relationship( + back_populates="user", + sa_relationship_kwargs={"cascade": "delete"}, + ) class UserCreate(SQLModel): diff --git a/src/backend/langflow/services/database/service.py b/src/backend/langflow/services/database/service.py index 48e576e81..f41a2484d 100644 --- a/src/backend/langflow/services/database/service.py +++ b/src/backend/langflow/services/database/service.py @@ -1,19 +1,21 @@ +import time from pathlib import Path from typing import TYPE_CHECKING + +import sqlalchemy as sa +from alembic import command, util +from alembic.config import Config +from loguru import logger +from sqlalchemy import inspect +from sqlalchemy.exc import OperationalError +from sqlmodel import Session, SQLModel, create_engine + from langflow.services.base import Service +from langflow.services.database import models # noqa from langflow.services.database.models.user.crud import get_user_by_username from langflow.services.database.utils import Result, TableResults from langflow.services.deps import get_settings_service from langflow.services.utils import teardown_superuser -from sqlalchemy import inspect -import sqlalchemy as sa -from sqlalchemy.exc import OperationalError -from sqlmodel import SQLModel, Session, create_engine -from loguru import logger -from alembic.config import Config -from alembic import command, util -from langflow.services.database import models # noqa -import time if TYPE_CHECKING: from sqlalchemy.engine import Engine diff --git a/src/backend/langflow/services/deps.py b/src/backend/langflow/services/deps.py index 776c0b2c4..2cac77a17 100644 --- a/src/backend/langflow/services/deps.py +++ b/src/backend/langflow/services/deps.py @@ -12,6 +12,11 @@ if TYPE_CHECKING: from langflow.services.settings.service import SettingsService from langflow.services.store.service import StoreService from langflow.services.task.service import TaskService + from langflow.services.credentials.service import CredentialService + + +def get_credential_service() -> "CredentialService": + return service_manager.get(ServiceType.CREDENTIAL_SERVICE) def get_settings_service() -> "SettingsService": diff --git a/src/backend/langflow/services/schema.py b/src/backend/langflow/services/schema.py index b899923fe..e35df5dec 100644 --- a/src/backend/langflow/services/schema.py +++ b/src/backend/langflow/services/schema.py @@ -15,3 +15,4 @@ class ServiceType(str, Enum): SESSION_SERVICE = "session_service" TASK_SERVICE = "task_service" STORE_SERVICE = "store_service" + CREDENTIAL_SERVICE = "credential_service" diff --git a/src/backend/langflow/services/store/exceptions.py b/src/backend/langflow/services/store/exceptions.py index 058b21652..df86d59bc 100644 --- a/src/backend/langflow/services/store/exceptions.py +++ b/src/backend/langflow/services/store/exceptions.py @@ -17,7 +17,7 @@ class ForbiddenError(CustomException): class APIKeyError(CustomException): def __init__(self, detail="API key error"): - super().__init__(detail, 401) + super().__init__(detail, 400) #! Should be 401 class FilterError(CustomException): diff --git a/src/backend/langflow/services/store/service.py b/src/backend/langflow/services/store/service.py index 92cd67447..f8c322355 100644 --- a/src/backend/langflow/services/store/service.py +++ b/src/backend/langflow/services/store/service.py @@ -445,6 +445,8 @@ class StoreService(Service): result: List[ListComponentResponse] = [] authorized = False + metadata = {} + comp_count = 0 try: result, metadata = await self.query_components( api_key=store_api_key, diff --git a/src/backend/langflow/services/utils.py b/src/backend/langflow/services/utils.py index 72807ee0c..40d2d7ea4 100644 --- a/src/backend/langflow/services/utils.py +++ b/src/backend/langflow/services/utils.py @@ -18,6 +18,7 @@ def get_factories_and_deps(): from langflow.services.settings import factory as settings_factory from langflow.services.store import factory as store_factory from langflow.services.task import factory as task_factory + from langflow.services.credentials import factory as credentials_factory return [ (settings_factory.SettingsServiceFactory(), []), @@ -40,11 +41,12 @@ def get_factories_and_deps(): [ServiceType.CACHE_SERVICE], ), (store_factory.StoreServiceFactory(), [ServiceType.SETTINGS_SERVICE]), + (credentials_factory.CredentialServiceFactory(), [ServiceType.SETTINGS_SERVICE]), ] def get_or_create_super_user(session: Session, username, password, is_default): - from langflow.services.database.models.user.user import User + from langflow.services.database.models.user.model import User user = session.query(User).filter(User.username == username).first() @@ -127,7 +129,7 @@ def teardown_superuser(settings_service, session): try: logger.debug("AUTO_LOGIN is set to False. Removing default superuser if exists.") username = DEFAULT_SUPERUSER - from langflow.services.database.models.user.user import User + from langflow.services.database.models.user.model import User user = session.query(User).filter(User.username == username).first() if user and user.is_superuser: diff --git a/src/backend/langflow/template/field/base.py b/src/backend/langflow/template/field/base.py index e596f21be..82394c807 100644 --- a/src/backend/langflow/template/field/base.py +++ b/src/backend/langflow/template/field/base.py @@ -59,6 +59,9 @@ class TemplateFieldCreator(BaseModel, ABC): info: Optional[str] = "" """Additional information about the field to be shown in the tooltip. Defaults to an empty string.""" + refresh: Optional[bool] = None + """Specifies if the field should be refreshed. Defaults to False.""" + def to_dict(self): result = self.model_dump() # Remove key if it is None diff --git a/src/backend/langflow/template/frontend_node/base.py b/src/backend/langflow/template/frontend_node/base.py index dc64b0fd8..35686cf6a 100644 --- a/src/backend/langflow/template/frontend_node/base.py +++ b/src/backend/langflow/template/frontend_node/base.py @@ -1,15 +1,15 @@ -from collections import defaultdict import re +from collections import defaultdict from typing import ClassVar, DefaultDict, Dict, List, Optional from pydantic import BaseModel, Field -from langflow.template.frontend_node.formatter import field_formatters +from langflow.template.field.base import TemplateField from langflow.template.frontend_node.constants import ( CLASSES_TO_REMOVE, FORCE_SHOW_FIELDS, ) -from langflow.template.field.base import TemplateField +from langflow.template.frontend_node.formatter import field_formatters from langflow.template.template.base import Template from langflow.utils import constants @@ -51,7 +51,9 @@ class FrontendNode(BaseModel): documentation: str = "" custom_fields: Optional[DefaultDict[str, List[str]]] = defaultdict(list) output_types: List[str] = [] + full_path: Optional[str] = None field_formatters: FieldFormatters = Field(default_factory=FieldFormatters) + beta: bool = False error: Optional[str] = None diff --git a/src/backend/langflow/utils/logger.py b/src/backend/langflow/utils/logger.py index 08ac40c98..060ad9731 100644 --- a/src/backend/langflow/utils/logger.py +++ b/src/backend/langflow/utils/logger.py @@ -1,11 +1,11 @@ -from typing import Optional -from loguru import logger -from pathlib import Path -from rich.logging import RichHandler -from platformdirs import user_cache_dir import os -import orjson +from pathlib import Path +from typing import Optional +import orjson +from loguru import logger +from platformdirs import user_cache_dir +from rich.logging import RichHandler VALID_LOG_LEVELS = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] @@ -66,4 +66,4 @@ def configure(log_level: Optional[str] = None, log_file: Optional[Path] = None): logger.debug(f"Logger set up with log level: {log_level}") if log_file: - logger.info(f"Log file: {log_file}") + logger.debug(f"Log file: {log_file}") diff --git a/src/backend/langflow/utils/payload.py b/src/backend/langflow/utils/payload.py index 02cca5c71..0e2f0fc7a 100644 --- a/src/backend/langflow/utils/payload.py +++ b/src/backend/langflow/utils/payload.py @@ -28,16 +28,16 @@ def extract_input_variables(nodes): return nodes -def get_root_node(graph): +def get_root_vertex(graph): """ Returns the root node of the template. """ - incoming_edges = {edge.source for edge in graph.edges} + incoming_edges = {edge.source_id for edge in graph.edges} - if not incoming_edges and len(graph.nodes) == 1: - return graph.nodes[0] + if not incoming_edges and len(graph.vertices) == 1: + return graph.vertices[0] - return next((node for node in graph.nodes if node not in incoming_edges), None) + return next((node for node in graph.vertices if node.id not in incoming_edges), None) def build_json(root, graph) -> Dict: diff --git a/src/backend/langflow/utils/validate.py b/src/backend/langflow/utils/validate.py index 51c4894d5..0a33dfa01 100644 --- a/src/backend/langflow/utils/validate.py +++ b/src/backend/langflow/utils/validate.py @@ -1,7 +1,7 @@ import ast import contextlib import importlib -import types +from types import FunctionType from typing import Dict @@ -61,7 +61,7 @@ def eval_function(function_string: str): ( obj for name, obj in namespace.items() - if isinstance(obj, types.FunctionType) and obj.__code__.co_filename == "" + if isinstance(obj, FunctionType) and obj.__code__.co_filename == "" ), None, ) diff --git a/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx b/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx index b64ee617b..0ea79c7dd 100644 --- a/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx @@ -21,11 +21,17 @@ import PromptAreaComponent from "../../../../components/promptComponent"; import TextAreaComponent from "../../../../components/textAreaComponent"; import ToggleShadComponent from "../../../../components/toggleShadComponent"; import { Button } from "../../../../components/ui/button"; -import { TOOLTIP_EMPTY } from "../../../../constants/constants"; +import { + LANGFLOW_SUPPORTED_TYPES, + TOOLTIP_EMPTY, +} from "../../../../constants/constants"; +import { alertContext } from "../../../../contexts/alertContext"; import { FlowsContext } from "../../../../contexts/flowsContext"; import { typesContext } from "../../../../contexts/typesContext"; import { undoRedoContext } from "../../../../contexts/undoRedoContext"; +import { postCustomComponentUpdate } from "../../../../controllers/API"; import { ParameterComponentType } from "../../../../types/components"; +import { NodeDataType } from "../../../../types/flow"; import { convertObjToArray, convertValuesToNumbers, @@ -59,6 +65,7 @@ export default function ParameterComponent({ const ref = useRef(null); const refHtml = useRef(null); const infoHtml = useRef(null); + const { setErrorData } = useContext(alertContext); const updateNodeInternals = useUpdateNodeInternals(); const [position, setPosition] = useState(0); const { setTabsState, tabId, flows } = useContext(FlowsContext); @@ -93,6 +100,25 @@ export default function ParameterComponent({ const { takeSnapshot } = useContext(undoRedoContext); + const handleUpdateValues = async (name: string, data: NodeDataType) => { + const code = data.node?.template["code"]?.value; + if (!code) { + console.error("Code not found in the template"); + return; + } + + try { + const res = await postCustomComponentUpdate(code, name); + if (res.status === 200 && data.node?.template) { + let clone = cloneDeep(data); + clone.node!.template[name] = res.data.template[name]; + setData(clone); + } + } catch (err) { + setErrorData(err as { title: string; list?: Array }); + } + }; + const handleOnNewValue = ( newValue: string | string[] | boolean | Object[] ): void => { @@ -222,17 +248,7 @@ export default function ParameterComponent({ }, [tooltipTitle, flow]); return !showNode ? ( - left && - (type === "str" || - type === "bool" || - type === "float" || - type === "code" || - type === "prompt" || - type === "file" || - type === "int" || - type === "dict" || - type === "NestedDict") && - !optionalHandle ? ( + left && LANGFLOW_SUPPORTED_TYPES.has(type ?? "") && !optionalHandle ? ( <> ) : ( + )} ) : left === true && type === "code" ? (
@@ -491,6 +511,7 @@ export default function ParameterComponent({ data.node!.template[name].value = newValue; handleOnNewValue(newValue); }} + id="div-dict-input" />
) : left === true && type === "dict" ? ( diff --git a/src/frontend/src/CustomNodes/GenericNode/index.tsx b/src/frontend/src/CustomNodes/GenericNode/index.tsx index 01b7738cc..c39249b22 100644 --- a/src/frontend/src/CustomNodes/GenericNode/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/index.tsx @@ -38,7 +38,7 @@ export default function GenericNode({ const { types, deleteNode, reactFlowInstance, setFilterEdge, getFilterEdge } = useContext(typesContext); const name = nodeIconsLucide[data.type] ? data.type : types[data.type]; - const [inputName, setInputName] = useState(true); + const [inputName, setInputName] = useState(false); const [nodeName, setNodeName] = useState(data.node!.display_name); const [inputDescription, setInputDescription] = useState(false); const [nodeDescription, setNodeDescription] = useState( @@ -206,13 +206,21 @@ export default function GenericNode({ ) : (
{ setInputName(true); takeSnapshot(); }} > - {data.node?.display_name} +
+ {data.node?.display_name} +
+ {data.node?.flow && ( + + )}
)} diff --git a/src/frontend/src/components/SanitizedHTMLWrapper/index.tsx b/src/frontend/src/components/SanitizedHTMLWrapper/index.tsx index db26ad918..832ea8505 100644 --- a/src/frontend/src/components/SanitizedHTMLWrapper/index.tsx +++ b/src/frontend/src/components/SanitizedHTMLWrapper/index.tsx @@ -11,6 +11,7 @@ const SanitizedHTMLWrapper = ({ return (
{ return ( diff --git a/src/frontend/src/components/dictComponent/index.tsx b/src/frontend/src/components/dictComponent/index.tsx index b17c678b3..066819ba1 100644 --- a/src/frontend/src/components/dictComponent/index.tsx +++ b/src/frontend/src/components/dictComponent/index.tsx @@ -10,6 +10,7 @@ export default function DictComponent({ onChange, disabled, editNode = false, + id = "", }: DictComponentType): JSX.Element { useEffect(() => { if (disabled) { @@ -30,7 +31,7 @@ export default function DictComponent({ )} > { -
+
{ @@ -45,6 +46,7 @@ export default function DictComponent({ : "input-disable pointer-events-none cursor-pointer" } placeholder="Click to edit your dictionary..." + data-testid="dict-input" />
diff --git a/src/frontend/src/components/dropdownComponent/index.tsx b/src/frontend/src/components/dropdownComponent/index.tsx index d6fcec772..b5e3f534e 100644 --- a/src/frontend/src/components/dropdownComponent/index.tsx +++ b/src/frontend/src/components/dropdownComponent/index.tsx @@ -11,6 +11,7 @@ export default function Dropdown({ editNode = false, numberOfOptions = 0, apiModal = false, + id = "", }: DropDownComponentType): JSX.Element { let [internalValue, setInternalValue] = useState( value === "" || !value ? "Choose an option" : value @@ -31,15 +32,19 @@ export default function Dropdown({ > {({ open }) => ( <> -
+
- + {internalValue} @@ -63,7 +68,7 @@ export default function Dropdown({ editNode ? "dropdown-component-true-options nowheel custom-scroll" : "dropdown-component-false-options nowheel custom-scroll", - apiModal ? "mb-2 w-[250px]" : "absolute" + apiModal ? "mb-2 w-[250px]" : "absolute w-full" )} > {options.map((option, id) => ( @@ -86,6 +91,7 @@ export default function Dropdown({ selected ? "font-semibold" : "font-normal", "block truncate " )} + data-testid={`${option}-${id ?? ""}-option`} > {option} diff --git a/src/frontend/src/components/genericIconComponent/index.tsx b/src/frontend/src/components/genericIconComponent/index.tsx index 8290e124f..db415ed5b 100644 --- a/src/frontend/src/components/genericIconComponent/index.tsx +++ b/src/frontend/src/components/genericIconComponent/index.tsx @@ -3,7 +3,10 @@ import { IconComponentProps } from "../../types/components"; import { nodeIconsLucide } from "../../utils/styleUtils"; const ForwardedIconComponent = forwardRef( - ({ name, className, iconColor, stroke }: IconComponentProps, ref) => { + ( + { name, className, iconColor, stroke, id = "" }: IconComponentProps, + ref + ) => { const TargetIcon = nodeIconsLucide[name] ?? nodeIconsLucide["unknown"]; return ( ); } diff --git a/src/frontend/src/components/keypairListComponent/index.tsx b/src/frontend/src/components/keypairListComponent/index.tsx index 2f175ea67..08c1d9da4 100644 --- a/src/frontend/src/components/keypairListComponent/index.tsx +++ b/src/frontend/src/components/keypairListComponent/index.tsx @@ -53,7 +53,7 @@ export default function KeypairListComponent({ return (
{!editNode && ( {!editNode && ( {}, - addFlow: async (newProject: boolean, flowData?: FlowType) => "", + addFlow: async ( + newProject: boolean, + flowData?: FlowType, + override?: boolean + ) => "", updateFlow: (newFlow: FlowType) => {}, incrementNodeId: () => uid(), downloadFlow: (flow: FlowType) => {}, @@ -78,7 +82,7 @@ const FlowsContextInitialValue: FlowsContextType = { selection: { nodes: any; edges: any }, position: { x: number; y: number; paneX?: number; paneY?: number } ) => {}, - saveComponent: async (component: NodeDataType) => "", + saveComponent: async (component: NodeDataType, override: boolean) => "", deleteComponent: (key: string) => {}, version: "", }; @@ -496,7 +500,8 @@ export function FlowsProvider({ children }: { children: ReactNode }) { const addFlow = async ( newProject: Boolean, - flow?: FlowType + flow?: FlowType, + override?: boolean ): Promise => { if (newProject) { let flowData = flow @@ -505,6 +510,15 @@ export function FlowsProvider({ children }: { children: ReactNode }) { // Create a new flow with a default name if no flow is provided. + if (override) { + deleteComponent(flow!.name); + const newFlow = createNewFlow(flowData, flow!); + const { id } = await saveFlowToDatabase(newFlow); + newFlow.id = id; + addFlowToLocalState(newFlow); + return; + } + const newFlow = createNewFlow(flowData, flow!); const newName = addVersionToDuplicates(newFlow, flows); @@ -595,14 +609,16 @@ export function FlowsProvider({ children }: { children: ReactNode }) { newFlows[index].data = newFlow.data; newFlows[index].name = newFlow.name; } + newFlow = { + ...newFlow, + }; return newFlows; }); } async function saveFlow(newFlow: FlowType, silent?: boolean) { - console.log(newFlow); - if (newFlow?.data?.nodes?.length === 0) return; + try { // updates flow in db const updatedFlow = await updateFlowInDatabase(newFlow); @@ -615,14 +631,10 @@ export function FlowsProvider({ children }: { children: ReactNode }) { const newFlows = [...prevState]; const index = newFlows.findIndex((flow) => flow.id === newFlow.id); if (index !== -1) { - newFlows[index] = { - ...newFlows[index], - description: updatedFlow.description, - data: updatedFlow.data, - name: updatedFlow.name, - }; + newFlows[index].description = newFlow.description ?? ""; + newFlows[index].data = newFlow.data; + newFlows[index].name = newFlow.name; } - return newFlows; }); //update tabs state @@ -644,9 +656,9 @@ export function FlowsProvider({ children }: { children: ReactNode }) { } } - function saveComponent(component: NodeDataType) { + function saveComponent(component: NodeDataType, override: boolean) { component.node!.official = false; - return addFlow(true, createFlowComponent(component, version)); + return addFlow(true, createFlowComponent(component, version), override); } function deleteComponent(key: string) { diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index dc5fc014e..37e579428 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -360,6 +360,16 @@ export async function postCustomComponent( return await api.post(`${BASE_URL_API}custom_component`, { code }); } +export async function postCustomComponentUpdate( + code: string, + field: string +): Promise> { + return await api.post(`${BASE_URL_API}custom_component/update`, { + code, + field, + }); +} + export async function onLogin(user: LoginType) { try { const response = await api.post( diff --git a/src/frontend/src/modals/ApiModal/index.tsx b/src/frontend/src/modals/ApiModal/index.tsx index dde0090c1..93d85549d 100644 --- a/src/frontend/src/modals/ApiModal/index.tsx +++ b/src/frontend/src/modals/ApiModal/index.tsx @@ -13,7 +13,10 @@ import { // import "ace-builds/webpack-resolver"; import CodeTabsComponent from "../../components/codeTabsComponent"; import IconComponent from "../../components/genericIconComponent"; -import { EXPORT_CODE_DIALOG } from "../../constants/constants"; +import { + EXPORT_CODE_DIALOG, + LANGFLOW_SUPPORTED_TYPES, +} from "../../constants/constants"; import { AuthContext } from "../../contexts/authContext"; import { FlowsContext } from "../../contexts/flowsContext"; import { TemplateVariableType } from "../../types/api"; @@ -99,15 +102,9 @@ const ApiModal = forwardRef( (templateField) => templateField.charAt(0) !== "_" && node.data.node.template[templateField].show && - (node.data.node.template[templateField].type === "str" || - node.data.node.template[templateField].type === "bool" || - node.data.node.template[templateField].type === "float" || - node.data.node.template[templateField].type === "code" || - node.data.node.template[templateField].type === "prompt" || - node.data.node.template[templateField].type === "file" || - node.data.node.template[templateField].type === "int" || - node.data.node.template[templateField].type === "dict" || - node.data.node.template[templateField].type === "NestedDict") + LANGFLOW_SUPPORTED_TYPES.has( + node.data.node.template[templateField].type + ) ) .map((n, i) => { arrNodesWithValues.push(node["id"]); @@ -146,9 +143,9 @@ const ApiModal = forwardRef( ); if (existingTweak) { - existingTweak[tw][template["name"]] = changes as string; + existingTweak[tw][template["name"]!] = changes as string; - if (existingTweak[tw][template["name"]] == template.value) { + if (existingTweak[tw][template["name"]!] == template.value) { tweak.current.forEach((element) => { if (element[tw] && Object.keys(element[tw])?.length === 0) { tweak.current = tweak.current.filter((obj) => { @@ -161,7 +158,7 @@ const ApiModal = forwardRef( } else { const newTweak = { [tw]: { - [template["name"]]: changes, + [template["name"]!]: changes, }, } as uniqueTweakType; tweak.current.push(newTweak); diff --git a/src/frontend/src/modals/ConfirmationModal/index.tsx b/src/frontend/src/modals/ConfirmationModal/index.tsx index 7a164660d..5a2a50a8b 100644 --- a/src/frontend/src/modals/ConfirmationModal/index.tsx +++ b/src/frontend/src/modals/ConfirmationModal/index.tsx @@ -36,10 +36,15 @@ function ConfirmationModal({ size, open, onClose, + onCancel, }: ConfirmationModalType) { const Icon: any = nodeIconsLucide[icon]; const [modalOpen, setModalOpen] = useState(open ?? false); + useEffect(() => { + if (open) setModalOpen(open); + }, [open]); + useEffect(() => { if (onClose) onClose!(modalOpen); }, [modalOpen]); @@ -86,6 +91,7 @@ function ConfirmationModal({ className="mt-5" variant="outline" onClick={() => { + if (onCancel) onCancel(); setModalOpen(false); }} > diff --git a/src/frontend/src/modals/EditNodeModal/index.tsx b/src/frontend/src/modals/EditNodeModal/index.tsx index c8016bf2b..59e9c6697 100644 --- a/src/frontend/src/modals/EditNodeModal/index.tsx +++ b/src/frontend/src/modals/EditNodeModal/index.tsx @@ -25,7 +25,10 @@ import { TableHeader, TableRow, } from "../../components/ui/table"; -import { limitScrollFieldsModal } from "../../constants/constants"; +import { + LANGFLOW_SUPPORTED_TYPES, + limitScrollFieldsModal, +} from "../../constants/constants"; import { FlowsContext } from "../../contexts/flowsContext"; import { typesContext } from "../../contexts/typesContext"; import { NodeDataType } from "../../types/flow"; @@ -123,7 +126,7 @@ const EditNodeModal = forwardRef( "edit-node-modal-box", nodeLength > limitScrollFieldsModal ? "overflow-scroll overflow-x-hidden custom-scroll" - : "overflow-hidden" + : "" )} > {nodeLength > 0 && ( @@ -144,24 +147,9 @@ const EditNodeModal = forwardRef( (templateParam) => templateParam.charAt(0) !== "_" && myData.node?.template[templateParam].show && - (myData.node.template[templateParam] - .type === "str" || - myData.node.template[templateParam] - .type === "bool" || - myData.node.template[templateParam] - .type === "float" || - myData.node.template[templateParam] - .type === "code" || - myData.node.template[templateParam] - .type === "prompt" || - myData.node.template[templateParam] - .type === "file" || - myData.node.template[templateParam] - .type === "int" || - myData.node.template[templateParam] - .type === "dict" || - myData.node.template[templateParam] - .type === "NestedDict") + LANGFLOW_SUPPORTED_TYPES.has( + myData.node.template[templateParam].type + ) ) .map((templateParam, index) => ( @@ -261,7 +249,7 @@ const EditNodeModal = forwardRef( value={ myData.node!.template[ templateParam - ].value.toString() === "{}" + ]?.value?.toString() === "{}" ? { yourkey: "value", } @@ -275,6 +263,7 @@ const EditNodeModal = forwardRef( ].value = newValue; handleOnNewValue(newValue, templateParam); }} + id="editnode-div-dict-input" />
) : myData.node?.template[templateParam] @@ -380,6 +369,7 @@ const EditNodeModal = forwardRef( templateParam ].value ?? "Choose an option" } + id={"dropdown-edit-" + index} >
) : myData.node?.template[templateParam] diff --git a/src/frontend/src/modals/dictAreaModal/index.tsx b/src/frontend/src/modals/dictAreaModal/index.tsx index 9cc525b48..8a59344fe 100644 --- a/src/frontend/src/modals/dictAreaModal/index.tsx +++ b/src/frontend/src/modals/dictAreaModal/index.tsx @@ -54,6 +54,7 @@ export default function DictAreaModal({ />