diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a3e9023c19904291817b73f2b47b14c328b5d0ac..f94862c0d44dd19a6c431c3ea5f15febb5e0179d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,11 +11,11 @@ Please follow these guidelines when making a contribution: - Ensure that the Pull Request title is prepended with a [valid type](https://flank.github.io/flank/pr_titles/). E.g. `feat: My New Feature`. - Run linting (and fix any issues that are flagged) by: - Navigating to /semantic-router. - - Running `poetry run make lint` to fix linting issues. - - Running `poetry run black .` to fix `black` linting issues. - - Running `poetry run ruff . --fix` to fix `ruff` linting issues (where possible, others may need manual changes). - - Confirming the linters pass using `poetry run make lint` again. - - Running `ruff . --fix`. + - Running `make lint` to fix linting issues. + - Running `black .` to fix `black` linting issues. + - Running `ruff . --fix` to fix `ruff` linting issues (where possible, others may need manual changes). + - Running `mypy .` and then fixing any of the issues that are raised. + - Confirming the linters pass using `make lint` again. - Ensure that, for any new code, new [PyTests are written](https://github.com/aurelio-labs/semantic-router/tree/main/tests/unit). If any code is removed, then ensure that corresponding PyTests are also removed. Finally, ensure that all remaining PyTests pass using `pytest ./tests` (to avoid integration tests you can run `pytest ./tests/unit`. - Codecov checks will inform you if any code is not covered by PyTests upon creating the PR. You should aim to cover new code with PyTests. diff --git a/Makefile b/Makefile index adf4eb0c4079749a2f86a0a862292f3ed0931265..a7c69643704677ab7650f8b350c74cad0b5c7a4e 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ format: - poetry run black --target-version py39 . + poetry run black --target-version py39 -l 88 . poetry run ruff --select I --fix . PYTHON_FILES=. @@ -7,9 +7,9 @@ lint: PYTHON_FILES=. lint_diff: PYTHON_FILES=$(shell git diff --name-only --diff-filter=d main | grep -E '\.py$$') lint lint_diff: - poetry run black --target-version py39 $(PYTHON_FILES) --check + poetry run black --target-version py39 -l 88 $(PYTHON_FILES) --check poetry run ruff . poetry run mypy $(PYTHON_FILES) test: - poetry run pytest -vv -n 20 --cov=semantic_router --cov-report=term-missing --cov-report=xml --cov-fail-under=80 + poetry run pytest -vv -n 20 --cov=semantic_router --cov-report=term-missing --cov-report=xml diff --git a/coverage.xml b/coverage.xml index 7eb662b902de37fa6581d52548d1cf54db5e5be4..5088c54e5a3540a52642431cd0533ed6aae47578 100644 --- a/coverage.xml +++ b/coverage.xml @@ -1,12 +1,12 @@ <?xml version="1.0" ?> -<coverage version="7.4.0" timestamp="1707722055292" lines-valid="1402" lines-covered="1188" line-rate="0.8474" branches-covered="0" branches-valid="0" branch-rate="0" complexity="0"> - <!-- Generated by coverage.py: https://coverage.readthedocs.io/en/7.4.0 --> +<coverage version="7.4.1" timestamp="1708577611401" lines-valid="1704" lines-covered="1346" line-rate="0.7899" branches-covered="0" branches-valid="0" branch-rate="0" complexity="0"> + <!-- Generated by coverage.py: https://coverage.readthedocs.io/en/7.4.1 --> <!-- Based on https://raw.githubusercontent.com/cobertura/web/master/htdocs/xml/coverage-04.dtd --> <sources> <source>/home/dustinmorris/semantic-router/semantic_router</source> </sources> <packages> - <package name="." line-rate="0.9055" branch-rate="0" complexity="0"> + <package name="." line-rate="0.9" branch-rate="0" complexity="0"> <classes> <class name="__init__.py" filename="__init__.py" complexity="0" line-rate="1" branch-rate="0"> <methods/> @@ -127,284 +127,285 @@ <line number="189" hits="1"/> </lines> </class> - <class name="layer.py" filename="layer.py" complexity="0" line-rate="0.9055" branch-rate="0"> + <class name="layer.py" filename="layer.py" complexity="0" line-rate="0.8949" branch-rate="0"> <methods/> <lines> <line number="1" hits="1"/> <line number="2" hits="1"/> <line number="3" hits="1"/> <line number="4" hits="1"/> - <line number="6" hits="1"/> + <line number="5" hits="1"/> <line number="7" hits="1"/> <line number="8" hits="1"/> - <line number="10" hits="1"/> + <line number="9" hits="1"/> <line number="11" hits="1"/> <line number="12" hits="1"/> <line number="13" hits="1"/> <line number="14" hits="1"/> <line number="15" hits="1"/> + <line number="16" hits="1"/> + <line number="17" hits="1"/> <line number="18" hits="1"/> - <line number="20" hits="1"/> <line number="21" hits="1"/> - <line number="22" hits="1"/> + <line number="23" hits="1"/> <line number="24" hits="1"/> - <line number="25" hits="0"/> - <line number="26" hits="0"/> - <line number="27" hits="0"/> + <line number="25" hits="1"/> + <line number="27" hits="1"/> <line number="28" hits="0"/> + <line number="29" hits="0"/> + <line number="30" hits="0"/> <line number="31" hits="0"/> - <line number="32" hits="0"/> - <line number="34" hits="1"/> - <line number="35" hits="1"/> - <line number="36" hits="0"/> + <line number="34" hits="0"/> + <line number="35" hits="0"/> + <line number="37" hits="1"/> + <line number="38" hits="1"/> <line number="39" hits="0"/> - <line number="41" hits="1"/> <line number="42" hits="0"/> - <line number="43" hits="0"/> - <line number="44" hits="0"/> - <line number="47" hits="1"/> - <line number="53" hits="1"/> - <line number="55" hits="1"/> - <line number="61" hits="1"/> - <line number="62" hits="1"/> - <line number="66" hits="1"/> - <line number="67" hits="0"/> - <line number="68" hits="1"/> - <line number="69" hits="0"/> + <line number="44" hits="1"/> + <line number="45" hits="0"/> + <line number="46" hits="0"/> + <line number="47" hits="0"/> + <line number="50" hits="1"/> + <line number="56" hits="1"/> + <line number="58" hits="1"/> + <line number="64" hits="1"/> + <line number="65" hits="1"/> + <line number="69" hits="1"/> <line number="70" hits="1"/> - <line number="71" hits="0"/> - <line number="72" hits="1"/> - <line number="73" hits="0"/> - <line number="74" hits="1"/> + <line number="71" hits="1"/> + <line number="72" hits="0"/> <line number="75" hits="1"/> - <line number="76" hits="1"/> <line number="78" hits="1"/> <line number="79" hits="1"/> + <line number="80" hits="1"/> <line number="81" hits="1"/> - <line number="82" hits="1"/> <line number="83" hits="1"/> <line number="84" hits="1"/> <line number="85" hits="1"/> <line number="86" hits="1"/> <line number="87" hits="1"/> + <line number="88" hits="1"/> <line number="89" hits="1"/> + <line number="90" hits="1"/> + <line number="91" hits="1"/> <line number="93" hits="1"/> - <line number="94" hits="1"/> - <line number="95" hits="1"/> - <line number="96" hits="1"/> <line number="97" hits="1"/> <line number="98" hits="1"/> - <line number="102" hits="0"/> - <line number="104" hits="1"/> + <line number="100" hits="1"/> + <line number="101" hits="1"/> + <line number="102" hits="1"/> + <line number="103" hits="1"/> <line number="105" hits="1"/> - <line number="111" hits="1"/> + <line number="106" hits="1"/> + <line number="110" hits="1"/> + <line number="112" hits="1"/> <line number="113" hits="1"/> - <line number="114" hits="1"/> - <line number="117" hits="1"/> - <line number="118" hits="1"/> + <line number="115" hits="1"/> + <line number="116" hits="1"/> + <line number="121" hits="1"/> <line number="122" hits="1"/> - <line number="125" hits="1"/> - <line number="126" hits="0"/> + <line number="124" hits="1"/> <line number="128" hits="1"/> <line number="129" hits="1"/> - <line number="130" hits="1"/> - <line number="131" hits="1"/> - <line number="132" hits="1"/> - <line number="134" hits="1"/> <line number="135" hits="1"/> - <line number="136" hits="1"/> + <line number="137" hits="1"/> <line number="138" hits="1"/> - <line number="139" hits="1"/> - <line number="140" hits="1"/> <line number="141" hits="1"/> <line number="142" hits="1"/> - <line number="143" hits="1"/> - <line number="145" hits="1"/> <line number="146" hits="1"/> - <line number="147" hits="0"/> <line number="149" hits="1"/> - <line number="150" hits="1"/> + <line number="150" hits="0"/> + <line number="152" hits="1"/> <line number="153" hits="1"/> <line number="154" hits="1"/> <line number="155" hits="1"/> <line number="156" hits="1"/> - <line number="157" hits="1"/> + <line number="158" hits="1"/> <line number="159" hits="1"/> + <line number="160" hits="1"/> + <line number="162" hits="1"/> + <line number="163" hits="1"/> + <line number="164" hits="1"/> <line number="165" hits="1"/> <line number="166" hits="1"/> <line number="167" hits="1"/> - <line number="168" hits="1"/> <line number="169" hits="1"/> + <line number="170" hits="1"/> + <line number="171" hits="0"/> <line number="173" hits="1"/> - <line number="175" hits="1"/> - <line number="176" hits="1"/> + <line number="174" hits="1"/> <line number="177" hits="1"/> <line number="178" hits="1"/> + <line number="179" hits="1"/> <line number="180" hits="1"/> - <line number="181" hits="1"/> <line number="182" hits="1"/> - <line number="184" hits="1"/> - <line number="186" hits="1"/> - <line number="188" hits="1"/> <line number="189" hits="1"/> <line number="190" hits="1"/> <line number="191" hits="1"/> - <line number="194" hits="1"/> - <line number="195" hits="1"/> - <line number="197" hits="1"/> + <line number="192" hits="1"/> + <line number="196" hits="1"/> + <line number="198" hits="1"/> + <line number="199" hits="1"/> + <line number="200" hits="1"/> + <line number="201" hits="1"/> <line number="203" hits="1"/> <line number="204" hits="1"/> <line number="205" hits="1"/> - <line number="206" hits="1"/> - <line number="208" hits="1"/> - <line number="210" hits="1"/> + <line number="207" hits="1"/> + <line number="209" hits="1"/> + <line number="211" hits="1"/> <line number="212" hits="1"/> - <line number="214" hits="1"/> - <line number="215" hits="1"/> - <line number="216" hits="1"/> - <line number="217" hits="1"/> - <line number="222" hits="1"/> - <line number="223" hits="1"/> - <line number="224" hits="1"/> - <line number="225" hits="1"/> + <line number="213" hits="1"/> + <line number="214" hits="0"/> + <line number="217" hits="0"/> + <line number="218" hits="1"/> + <line number="220" hits="1"/> + <line number="226" hits="1"/> + <line number="227" hits="1"/> <line number="228" hits="1"/> - <line number="229" hits="0"/> - <line number="230" hits="0"/> - <line number="236" hits="0"/> - <line number="237" hits="0"/> + <line number="229" hits="1"/> + <line number="231" hits="1"/> + <line number="233" hits="1"/> + <line number="235" hits="1"/> + <line number="237" hits="1"/> + <line number="238" hits="1"/> <line number="239" hits="0"/> <line number="240" hits="1"/> - <line number="243" hits="1"/> <line number="245" hits="1"/> - <line number="246" hits="0"/> - <line number="252" hits="1"/> - <line number="253" hits="1"/> - <line number="254" hits="1"/> - <line number="255" hits="1"/> - <line number="256" hits="1"/> - <line number="258" hits="1"/> - <line number="259" hits="1"/> - <line number="260" hits="1"/> - <line number="261" hits="1"/> - <line number="262" hits="1"/> - <line number="264" hits="1"/> - <line number="265" hits="1"/> + <line number="246" hits="1"/> + <line number="247" hits="1"/> + <line number="248" hits="1"/> + <line number="251" hits="1"/> + <line number="252" hits="0"/> + <line number="253" hits="0"/> + <line number="259" hits="0"/> + <line number="260" hits="0"/> + <line number="262" hits="0"/> + <line number="263" hits="1"/> <line number="266" hits="1"/> - <line number="267" hits="1"/> - <line number="269" hits="1"/> - <line number="270" hits="1"/> - <line number="272" hits="1"/> - <line number="274" hits="1"/> + <line number="268" hits="1"/> + <line number="269" hits="0"/> <line number="275" hits="1"/> + <line number="276" hits="1"/> + <line number="277" hits="1"/> <line number="278" hits="1"/> <line number="279" hits="1"/> <line number="281" hits="1"/> <line number="282" hits="1"/> + <line number="283" hits="1"/> <line number="284" hits="1"/> <line number="285" hits="1"/> <line number="287" hits="1"/> <line number="288" hits="1"/> + <line number="289" hits="1"/> <line number="290" hits="1"/> <line number="292" hits="1"/> <line number="293" hits="1"/> <line number="295" hits="1"/> - <line number="296" hits="1"/> <line number="297" hits="1"/> <line number="298" hits="1"/> - <line number="299" hits="1"/> <line number="301" hits="1"/> - <line number="302" hits="1"/> - <line number="304" hits="1"/> - <line number="305" hits="1"/> - <line number="310" hits="1"/> + <line number="306" hits="1"/> + <line number="308" hits="1"/> + <line number="309" hits="1"/> <line number="311" hits="1"/> - <line number="313" hits="1"/> - <line number="315" hits="1"/> - <line number="318" hits="1"/> + <line number="312" hits="0"/> + <line number="314" hits="1"/> + <line number="320" hits="1"/> <line number="321" hits="1"/> <line number="322" hits="1"/> <line number="323" hits="1"/> - <line number="330" hits="1"/> - <line number="331" hits="1"/> - <line number="337" hits="1"/> - <line number="340" hits="1"/> - <line number="341" hits="1"/> - <line number="342" hits="1"/> - <line number="344" hits="1"/> - <line number="346" hits="1"/> - <line number="348" hits="1"/> - <line number="349" hits="1"/> - <line number="351" hits="1"/> + <line number="325" hits="1"/> + <line number="326" hits="1"/> + <line number="328" hits="1"/> + <line number="330" hits="0"/> + <line number="345" hits="1"/> + <line number="347" hits="1"/> + <line number="350" hits="1"/> <line number="352" hits="1"/> <line number="354" hits="1"/> - <line number="355" hits="1"/> - <line number="357" hits="1"/> - <line number="358" hits="1"/> - <line number="359" hits="1"/> <line number="360" hits="1"/> - <line number="361" hits="1"/> - <line number="362" hits="1"/> <line number="363" hits="1"/> + <line number="364" hits="1"/> <line number="365" hits="1"/> - <line number="368" hits="1"/> - <line number="369" hits="1"/> - <line number="372" hits="1"/> + <line number="367" hits="1"/> + <line number="370" hits="1"/> + <line number="371" hits="1"/> <line number="373" hits="1"/> + <line number="374" hits="1"/> <line number="375" hits="1"/> <line number="376" hits="1"/> + <line number="377" hits="1"/> <line number="378" hits="1"/> <line number="379" hits="1"/> - <line number="380" hits="1"/> - <line number="382" hits="1"/> + <line number="381" hits="1"/> <line number="384" hits="1"/> + <line number="385" hits="1"/> <line number="388" hits="1"/> <line number="389" hits="1"/> - <line number="390" hits="1"/> + <line number="391" hits="0"/> + <line number="392" hits="0"/> <line number="394" hits="1"/> <line number="395" hits="1"/> - <line number="401" hits="1"/> - <line number="402" hits="1"/> - <line number="403" hits="1"/> + <line number="396" hits="1"/> + <line number="398" hits="1"/> + <line number="400" hits="1"/> + <line number="404" hits="1"/> <line number="405" hits="1"/> <line number="406" hits="1"/> - <line number="407" hits="1"/> - <line number="409" hits="1"/> + <line number="410" hits="1"/> <line number="411" hits="1"/> - <line number="415" hits="1"/> <line number="417" hits="1"/> - <line number="424" hits="1"/> - <line number="426" hits="1"/> + <line number="418" hits="1"/> + <line number="419" hits="1"/> + <line number="421" hits="1"/> + <line number="422" hits="1"/> + <line number="423" hits="1"/> + <line number="425" hits="1"/> <line number="427" hits="1"/> - <line number="429" hits="1"/> - <line number="430" hits="1"/> - <line number="432" hits="1"/> - <line number="437" hits="1"/> - <line number="439" hits="1"/> + <line number="431" hits="1"/> + <line number="433" hits="1"/> <line number="441" hits="1"/> - <line number="442" hits="0"/> - <line number="443" hits="0"/> - <line number="445" hits="1"/> + <line number="442" hits="1"/> + <line number="443" hits="1"/> + <line number="444" hits="1"/> + <line number="446" hits="1"/> <line number="447" hits="1"/> - <line number="451" hits="1"/> + <line number="449" hits="1"/> + <line number="450" hits="1"/> <line number="452" hits="1"/> - <line number="453" hits="1"/> - <line number="455" hits="1"/> + <line number="457" hits="1"/> <line number="459" hits="1"/> - <line number="460" hits="1"/> <line number="461" hits="1"/> - <line number="462" hits="1"/> - <line number="463" hits="1"/> - <line number="464" hits="1"/> + <line number="462" hits="0"/> + <line number="463" hits="0"/> <line number="465" hits="1"/> - <line number="468" hits="1"/> + <line number="467" hits="1"/> + <line number="471" hits="1"/> + <line number="472" hits="1"/> + <line number="473" hits="1"/> <line number="474" hits="1"/> - <line number="475" hits="1"/> <line number="476" hits="1"/> - <line number="478" hits="1"/> + <line number="477" hits="1"/> <line number="479" hits="1"/> - <line number="480" hits="1"/> + <line number="483" hits="1"/> + <line number="484" hits="1"/> + <line number="485" hits="1"/> + <line number="486" hits="1"/> + <line number="487" hits="1"/> <line number="488" hits="1"/> + <line number="489" hits="1"/> + <line number="491" hits="1"/> <line number="492" hits="1"/> + <line number="495" hits="1"/> + <line number="501" hits="1"/> + <line number="502" hits="1"/> + <line number="503" hits="1"/> + <line number="505" hits="1"/> + <line number="506" hits="1"/> + <line number="507" hits="1"/> + <line number="515" hits="1"/> + <line number="519" hits="1"/> </lines> </class> <class name="linear.py" filename="linear.py" complexity="0" line-rate="1" branch-rate="0"> @@ -425,87 +426,93 @@ <line number="30" hits="1"/> </lines> </class> - <class name="route.py" filename="route.py" complexity="0" line-rate="0.9103" branch-rate="0"> + <class name="route.py" filename="route.py" complexity="0" line-rate="0.9048" branch-rate="0"> <methods/> <lines> <line number="1" hits="1"/> <line number="2" hits="1"/> <line number="3" hits="1"/> <line number="5" hits="1"/> - <line number="7" hits="1"/> + <line number="6" hits="1"/> <line number="8" hits="1"/> <line number="9" hits="1"/> <line number="10" hits="1"/> - <line number="13" hits="1"/> + <line number="11" hits="1"/> <line number="14" hits="1"/> <line number="15" hits="1"/> <line number="16" hits="1"/> - <line number="18" hits="1"/> + <line number="17" hits="1"/> <line number="19" hits="1"/> <line number="20" hits="1"/> <line number="21" hits="1"/> <line number="22" hits="1"/> - <line number="25" hits="1"/> + <line number="23" hits="1"/> <line number="26" hits="1"/> - <line number="28" hits="1"/> + <line number="27" hits="1"/> <line number="29" hits="1"/> <line number="30" hits="1"/> - <line number="33" hits="1"/> - <line number="35" hits="1"/> + <line number="31" hits="1"/> + <line number="34" hits="1"/> <line number="36" hits="1"/> <line number="37" hits="1"/> <line number="38" hits="1"/> - <line number="41" hits="1"/> + <line number="39" hits="1"/> <line number="42" hits="1"/> <line number="43" hits="1"/> <line number="44" hits="1"/> <line number="45" hits="1"/> <line number="46" hits="1"/> <line number="47" hits="1"/> - <line number="49" hits="1"/> + <line number="48" hits="1"/> <line number="50" hits="1"/> <line number="51" hits="1"/> - <line number="52" hits="1"/> - <line number="56" hits="0"/> - <line number="57" hits="0"/> - <line number="62" hits="0"/> - <line number="65" hits="0"/> - <line number="68" hits="1"/> - <line number="69" hits="1"/> - <line number="71" hits="1"/> + <line number="53" hits="1"/> + <line number="54" hits="1"/> + <line number="55" hits="1"/> + <line number="56" hits="1"/> + <line number="60" hits="0"/> + <line number="61" hits="0"/> + <line number="66" hits="0"/> + <line number="69" hits="0"/> <line number="72" hits="1"/> - <line number="74" hits="1"/> - <line number="75" hits="1"/> - <line number="76" hits="1"/> + <line number="73" hits="1"/> <line number="78" hits="1"/> <line number="79" hits="1"/> - <line number="83" hits="1"/> - <line number="84" hits="1"/> - <line number="85" hits="1"/> + <line number="80" hits="1"/> + <line number="81" hits="0"/> <line number="86" hits="1"/> <line number="88" hits="1"/> <line number="89" hits="1"/> - <line number="91" hits="1"/> + <line number="90" hits="1"/> <line number="92" hits="1"/> - <line number="94" hits="1"/> - <line number="95" hits="1"/> - <line number="96" hits="1"/> - <line number="98" hits="0"/> + <line number="93" hits="1"/> + <line number="97" hits="1"/> + <line number="98" hits="1"/> + <line number="99" hits="1"/> <line number="100" hits="1"/> - <line number="101" hits="1"/> <line number="102" hits="1"/> - <line number="104" hits="1"/> - <line number="129" hits="1"/> - <line number="130" hits="1"/> - <line number="131" hits="1"/> - <line number="132" hits="0"/> - <line number="134" hits="1"/> - <line number="136" hits="1"/> - <line number="138" hits="1"/> - <line number="139" hits="1"/> - <line number="140" hits="1"/> - <line number="141" hits="1"/> - <line number="142" hits="0"/> + <line number="103" hits="1"/> + <line number="105" hits="1"/> + <line number="106" hits="1"/> + <line number="108" hits="1"/> + <line number="109" hits="1"/> + <line number="110" hits="1"/> + <line number="112" hits="0"/> + <line number="114" hits="1"/> + <line number="115" hits="1"/> + <line number="116" hits="1"/> + <line number="118" hits="1"/> + <line number="143" hits="1"/> + <line number="144" hits="1"/> + <line number="145" hits="1"/> + <line number="146" hits="0"/> + <line number="148" hits="1"/> + <line number="150" hits="1"/> + <line number="152" hits="1"/> + <line number="153" hits="1"/> + <line number="154" hits="1"/> + <line number="155" hits="1"/> + <line number="156" hits="0"/> </lines> </class> <class name="schema.py" filename="schema.py" complexity="0" line-rate="0.8929" branch-rate="0"> @@ -648,7 +655,7 @@ </class> </classes> </package> - <package name="encoders" line-rate="0.8771" branch-rate="0" complexity="0"> + <package name="encoders" line-rate="0.834" branch-rate="0" complexity="0"> <classes> <class name="__init__.py" filename="encoders/__init__.py" complexity="0" line-rate="1" branch-rate="0"> <methods/> @@ -662,7 +669,8 @@ <line number="7" hits="1"/> <line number="8" hits="1"/> <line number="9" hits="1"/> - <line number="11" hits="1"/> + <line number="10" hits="1"/> + <line number="12" hits="1"/> </lines> </class> <class name="base.py" filename="encoders/base.py" complexity="0" line-rate="1" branch-rate="0"> @@ -739,15 +747,15 @@ <line number="2" hits="1"/> <line number="4" hits="1"/> <line number="6" hits="1"/> - <line number="9" hits="1"/> + <line number="7" hits="1"/> <line number="10" hits="1"/> <line number="11" hits="1"/> <line number="12" hits="1"/> - <line number="14" hits="1"/> - <line number="21" hits="1"/> + <line number="13" hits="1"/> + <line number="15" hits="1"/> <line number="22" hits="1"/> <line number="23" hits="1"/> - <line number="28" hits="1"/> + <line number="24" hits="1"/> <line number="29" hits="1"/> <line number="30" hits="1"/> <line number="31" hits="1"/> @@ -755,14 +763,15 @@ <line number="33" hits="1"/> <line number="34" hits="1"/> <line number="35" hits="1"/> - <line number="39" hits="1"/> + <line number="36" hits="1"/> <line number="40" hits="1"/> <line number="41" hits="1"/> <line number="42" hits="1"/> <line number="43" hits="1"/> - <line number="46" hits="1"/> + <line number="44" hits="1"/> <line number="47" hits="1"/> <line number="48" hits="1"/> + <line number="49" hits="1"/> </lines> </class> <class name="fastembed.py" filename="encoders/fastembed.py" complexity="0" line-rate="0.8667" branch-rate="0"> @@ -865,7 +874,7 @@ <line number="114" hits="0"/> </lines> </class> - <class name="mistral.py" filename="encoders/mistral.py" complexity="0" line-rate="0.95" branch-rate="0"> + <class name="mistral.py" filename="encoders/mistral.py" complexity="0" line-rate="0.9512" branch-rate="0"> <methods/> <lines> <line number="2" hits="1"/> @@ -875,11 +884,11 @@ <line number="7" hits="1"/> <line number="8" hits="1"/> <line number="10" hits="1"/> - <line number="13" hits="1"/> - <line number="16" hits="1"/> + <line number="11" hits="1"/> + <line number="14" hits="1"/> <line number="17" hits="1"/> - <line number="19" hits="1"/> - <line number="25" hits="1"/> + <line number="18" hits="1"/> + <line number="20" hits="1"/> <line number="26" hits="1"/> <line number="27" hits="1"/> <line number="28" hits="1"/> @@ -887,14 +896,14 @@ <line number="30" hits="1"/> <line number="31" hits="1"/> <line number="32" hits="1"/> - <line number="33" hits="0"/> + <line number="33" hits="1"/> <line number="34" hits="0"/> - <line number="36" hits="1"/> + <line number="35" hits="0"/> <line number="37" hits="1"/> <line number="38" hits="1"/> <line number="39" hits="1"/> <line number="40" hits="1"/> - <line number="43" hits="1"/> + <line number="41" hits="1"/> <line number="44" hits="1"/> <line number="45" hits="1"/> <line number="46" hits="1"/> @@ -904,13 +913,14 @@ <line number="50" hits="1"/> <line number="51" hits="1"/> <line number="52" hits="1"/> - <line number="54" hits="1"/> + <line number="53" hits="1"/> <line number="55" hits="1"/> <line number="56" hits="1"/> <line number="57" hits="1"/> + <line number="58" hits="1"/> </lines> </class> - <class name="openai.py" filename="encoders/openai.py" complexity="0" line-rate="0.9783" branch-rate="0"> + <class name="openai.py" filename="encoders/openai.py" complexity="0" line-rate="1" branch-rate="0"> <methods/> <lines> <line number="1" hits="1"/> @@ -922,43 +932,45 @@ <line number="8" hits="1"/> <line number="10" hits="1"/> <line number="11" hits="1"/> - <line number="14" hits="1"/> + <line number="12" hits="1"/> <line number="15" hits="1"/> <line number="16" hits="1"/> <line number="17" hits="1"/> - <line number="19" hits="1"/> - <line number="26" hits="1"/> - <line number="27" hits="1"/> + <line number="18" hits="1"/> + <line number="20" hits="1"/> <line number="28" hits="1"/> <line number="29" hits="1"/> <line number="30" hits="1"/> - <line number="31" hits="0"/> + <line number="31" hits="1"/> <line number="32" hits="1"/> <line number="33" hits="1"/> <line number="34" hits="1"/> <line number="35" hits="1"/> - <line number="39" hits="1"/> - <line number="41" hits="1"/> + <line number="36" hits="1"/> + <line number="37" hits="1"/> + <line number="38" hits="1"/> <line number="42" hits="1"/> - <line number="43" hits="1"/> <line number="44" hits="1"/> <line number="45" hits="1"/> + <line number="46" hits="1"/> + <line number="47" hits="1"/> <line number="48" hits="1"/> - <line number="49" hits="1"/> - <line number="50" hits="1"/> - <line number="55" hits="1"/> - <line number="56" hits="1"/> - <line number="57" hits="1"/> + <line number="51" hits="1"/> + <line number="52" hits="1"/> + <line number="53" hits="1"/> <line number="58" hits="1"/> <line number="59" hits="1"/> <line number="60" hits="1"/> <line number="61" hits="1"/> <line number="62" hits="1"/> <line number="63" hits="1"/> + <line number="64" hits="1"/> <line number="65" hits="1"/> - <line number="70" hits="1"/> - <line number="72" hits="1"/> + <line number="66" hits="1"/> + <line number="68" hits="1"/> <line number="73" hits="1"/> + <line number="75" hits="1"/> + <line number="76" hits="1"/> </lines> </class> <class name="tfidf.py" filename="encoders/tfidf.py" complexity="0" line-rate="0.9844" branch-rate="0"> @@ -1030,17 +1042,17 @@ <line number="80" hits="1"/> </lines> </class> - <class name="zure.py" filename="encoders/zure.py" complexity="0" line-rate="0.9444" branch-rate="0"> + <class name="vit.py" filename="encoders/vit.py" complexity="0" line-rate="0.4737" branch-rate="0"> <methods/> <lines> <line number="1" hits="1"/> - <line number="2" hits="1"/> <line number="3" hits="1"/> + <line number="4" hits="1"/> <line number="5" hits="1"/> - <line number="6" hits="1"/> <line number="7" hits="1"/> - <line number="9" hits="1"/> <line number="10" hits="1"/> + <line number="11" hits="1"/> + <line number="12" hits="1"/> <line number="13" hits="1"/> <line number="14" hits="1"/> <line number="15" hits="1"/> @@ -1050,10 +1062,72 @@ <line number="19" hits="1"/> <line number="20" hits="1"/> <line number="22" hits="1"/> - <line number="31" hits="1"/> - <line number="32" hits="1"/> - <line number="33" hits="1"/> - <line number="34" hits="1"/> + <line number="23" hits="1"/> + <line number="24" hits="1"/> + <line number="26" hits="1"/> + <line number="27" hits="1"/> + <line number="28" hits="1"/> + <line number="29" hits="1"/> + <line number="30" hits="1"/> + <line number="36" hits="0"/> + <line number="37" hits="0"/> + <line number="38" hits="0"/> + <line number="39" hits="0"/> + <line number="40" hits="0"/> + <line number="46" hits="0"/> + <line number="47" hits="0"/> + <line number="49" hits="0"/> + <line number="53" hits="0"/> + <line number="55" hits="0"/> + <line number="56" hits="0"/> + <line number="59" hits="0"/> + <line number="60" hits="0"/> + <line number="61" hits="0"/> + <line number="63" hits="0"/> + <line number="65" hits="1"/> + <line number="66" hits="0"/> + <line number="67" hits="0"/> + <line number="68" hits="0"/> + <line number="69" hits="0"/> + <line number="71" hits="1"/> + <line number="72" hits="0"/> + <line number="73" hits="0"/> + <line number="74" hits="0"/> + <line number="76" hits="1"/> + <line number="81" hits="0"/> + <line number="82" hits="0"/> + <line number="83" hits="0"/> + <line number="84" hits="0"/> + <line number="85" hits="0"/> + <line number="86" hits="0"/> + <line number="92" hits="0"/> + <line number="93" hits="0"/> + </lines> + </class> + <class name="zure.py" filename="encoders/zure.py" complexity="0" line-rate="0.9589" branch-rate="0"> + <methods/> + <lines> + <line number="1" hits="1"/> + <line number="2" hits="1"/> + <line number="3" hits="1"/> + <line number="5" hits="1"/> + <line number="6" hits="1"/> + <line number="7" hits="1"/> + <line number="9" hits="1"/> + <line number="10" hits="1"/> + <line number="11" hits="1"/> + <line number="14" hits="1"/> + <line number="15" hits="1"/> + <line number="16" hits="1"/> + <line number="17" hits="1"/> + <line number="18" hits="1"/> + <line number="19" hits="1"/> + <line number="20" hits="1"/> + <line number="21" hits="1"/> + <line number="23" hits="1"/> + <line number="32" hits="1"/> + <line number="33" hits="1"/> + <line number="34" hits="1"/> <line number="35" hits="1"/> <line number="36" hits="1"/> <line number="37" hits="1"/> @@ -1062,54 +1136,300 @@ <line number="40" hits="1"/> <line number="41" hits="1"/> <line number="42" hits="1"/> - <line number="43" hits="0"/> + <line number="43" hits="1"/> <line number="44" hits="1"/> <line number="45" hits="1"/> + <line number="46" hits="1"/> + <line number="48" hits="1"/> <line number="49" hits="1"/> <line number="50" hits="1"/> - <line number="51" hits="1"/> - <line number="52" hits="0"/> + <line number="51" hits="0"/> + <line number="52" hits="1"/> <line number="53" hits="1"/> <line number="54" hits="1"/> - <line number="55" hits="1"/> - <line number="56" hits="0"/> + <line number="55" hits="0"/> + <line number="56" hits="1"/> <line number="57" hits="1"/> <line number="58" hits="1"/> - <line number="59" hits="1"/> - <line number="60" hits="0"/> - <line number="61" hits="1"/> + <line number="59" hits="0"/> + <line number="60" hits="1"/> + <line number="67" hits="1"/> <line number="68" hits="1"/> - <line number="69" hits="1"/> + <line number="75" hits="1"/> <line number="76" hits="1"/> - <line number="77" hits="1"/> + <line number="80" hits="1"/> <line number="81" hits="1"/> <line number="82" hits="1"/> <line number="83" hits="1"/> <line number="84" hits="1"/> - <line number="85" hits="1"/> + <line number="87" hits="1"/> <line number="88" hits="1"/> <line number="89" hits="1"/> - <line number="90" hits="1"/> + <line number="92" hits="1"/> <line number="93" hits="1"/> <line number="94" hits="1"/> - <line number="95" hits="1"/> - <line number="97" hits="1"/> + <line number="96" hits="1"/> + <line number="98" hits="1"/> <line number="99" hits="1"/> <line number="100" hits="1"/> <line number="101" hits="1"/> <line number="102" hits="1"/> <line number="103" hits="1"/> <line number="104" hits="1"/> - <line number="105" hits="1"/> - <line number="107" hits="1"/> - <line number="112" hits="1"/> + <line number="106" hits="1"/> + <line number="111" hits="1"/> + <line number="113" hits="1"/> <line number="114" hits="1"/> - <line number="115" hits="1"/> </lines> </class> </classes> </package> - <package name="llms" line-rate="0.7214" branch-rate="0" complexity="0"> + <package name="index" line-rate="0.4842" branch-rate="0" complexity="0"> + <classes> + <class name="__init__.py" filename="index/__init__.py" complexity="0" line-rate="1" branch-rate="0"> + <methods/> + <lines> + <line number="1" hits="1"/> + <line number="2" hits="1"/> + <line number="3" hits="1"/> + <line number="5" hits="1"/> + </lines> + </class> + <class name="base.py" filename="index/base.py" complexity="0" line-rate="0.7619" branch-rate="0"> + <methods/> + <lines> + <line number="1" hits="1"/> + <line number="3" hits="1"/> + <line number="4" hits="1"/> + <line number="7" hits="1"/> + <line number="16" hits="1"/> + <line number="17" hits="1"/> + <line number="18" hits="1"/> + <line number="19" hits="1"/> + <line number="20" hits="1"/> + <line number="22" hits="1"/> + <line number="29" hits="0"/> + <line number="31" hits="1"/> + <line number="36" hits="0"/> + <line number="38" hits="1"/> + <line number="43" hits="0"/> + <line number="45" hits="1"/> + <line number="50" hits="0"/> + <line number="52" hits="1"/> + <line number="57" hits="0"/> + <line number="59" hits="1"/> + <line number="60" hits="1"/> + </lines> + </class> + <class name="local.py" filename="index/local.py" complexity="0" line-rate="0.8519" branch-rate="0"> + <methods/> + <lines> + <line number="1" hits="1"/> + <line number="3" hits="1"/> + <line number="5" hits="1"/> + <line number="6" hits="1"/> + <line number="9" hits="1"/> + <line number="10" hits="1"/> + <line number="16" hits="1"/> + <line number="17" hits="1"/> + <line number="19" hits="1"/> + <line number="20" hits="1"/> + <line number="22" hits="1"/> + <line number="25" hits="1"/> + <line number="26" hits="1"/> + <line number="27" hits="1"/> + <line number="28" hits="1"/> + <line number="30" hits="0"/> + <line number="31" hits="1"/> + <line number="32" hits="1"/> + <line number="33" hits="1"/> + <line number="34" hits="1"/> + <line number="36" hits="1"/> + <line number="37" hits="1"/> + <line number="38" hits="1"/> + <line number="40" hits="1"/> + <line number="47" hits="0"/> + <line number="48" hits="0"/> + <line number="49" hits="0"/> + <line number="51" hits="1"/> + <line number="52" hits="1"/> + <line number="58" hits="1"/> + <line number="62" hits="1"/> + <line number="63" hits="1"/> + <line number="64" hits="1"/> + <line number="66" hits="1"/> + <line number="68" hits="1"/> + <line number="69" hits="1"/> + <line number="71" hits="1"/> + <line number="75" hits="1"/> + <line number="80" hits="1"/> + <line number="81" hits="1"/> + <line number="82" hits="1"/> + <line number="83" hits="1"/> + <line number="85" hits="0"/> + <line number="89" hits="1"/> + <line number="93" hits="0"/> + <line number="95" hits="1"/> + <line number="97" hits="1"/> + <line number="98" hits="0"/> + <line number="99" hits="1"/> + <line number="100" hits="1"/> + <line number="102" hits="1"/> + <line number="103" hits="1"/> + <line number="104" hits="1"/> + <line number="106" hits="0"/> + </lines> + </class> + <class name="pinecone.py" filename="index/pinecone.py" complexity="0" line-rate="0.2887" branch-rate="0"> + <methods/> + <lines> + <line number="1" hits="1"/> + <line number="2" hits="1"/> + <line number="3" hits="1"/> + <line number="4" hits="1"/> + <line number="6" hits="1"/> + <line number="7" hits="1"/> + <line number="8" hits="1"/> + <line number="10" hits="1"/> + <line number="11" hits="1"/> + <line number="14" hits="1"/> + <line number="15" hits="0"/> + <line number="18" hits="1"/> + <line number="19" hits="1"/> + <line number="20" hits="1"/> + <line number="21" hits="1"/> + <line number="22" hits="1"/> + <line number="24" hits="1"/> + <line number="25" hits="0"/> + <line number="27" hits="0"/> + <line number="28" hits="0"/> + <line number="29" hits="0"/> + <line number="31" hits="1"/> + <line number="32" hits="0"/> + <line number="39" hits="1"/> + <line number="40" hits="1"/> + <line number="41" hits="1"/> + <line number="42" hits="1"/> + <line number="43" hits="1"/> + <line number="44" hits="1"/> + <line number="45" hits="1"/> + <line number="46" hits="1"/> + <line number="47" hits="1"/> + <line number="48" hits="1"/> + <line number="49" hits="1"/> + <line number="51" hits="1"/> + <line number="52" hits="0"/> + <line number="53" hits="0"/> + <line number="55" hits="0"/> + <line number="56" hits="0"/> + <line number="57" hits="0"/> + <line number="58" hits="0"/> + <line number="60" hits="0"/> + <line number="62" hits="1"/> + <line number="63" hits="0"/> + <line number="64" hits="0"/> + <line number="66" hits="0"/> + <line number="67" hits="0"/> + <line number="68" hits="0"/> + <line number="73" hits="0"/> + <line number="74" hits="0"/> + <line number="75" hits="0"/> + <line number="76" hits="0"/> + <line number="78" hits="1"/> + <line number="79" hits="0"/> + <line number="80" hits="0"/> + <line number="81" hits="0"/> + <line number="84" hits="0"/> + <line number="91" hits="0"/> + <line number="92" hits="0"/> + <line number="93" hits="0"/> + <line number="94" hits="0"/> + <line number="95" hits="0"/> + <line number="97" hits="0"/> + <line number="99" hits="0"/> + <line number="100" hits="0"/> + <line number="101" hits="0"/> + <line number="107" hits="0"/> + <line number="108" hits="0"/> + <line number="109" hits="0"/> + <line number="110" hits="0"/> + <line number="111" hits="0"/> + <line number="113" hits="1"/> + <line number="116" hits="0"/> + <line number="117" hits="0"/> + <line number="119" hits="0"/> + <line number="120" hits="0"/> + <line number="121" hits="0"/> + <line number="122" hits="0"/> + <line number="123" hits="0"/> + <line number="124" hits="0"/> + <line number="125" hits="0"/> + <line number="127" hits="0"/> + <line number="129" hits="1"/> + <line number="130" hits="0"/> + <line number="131" hits="0"/> + <line number="132" hits="0"/> + <line number="134" hits="1"/> + <line number="138" hits="0"/> + <line number="139" hits="0"/> + <line number="140" hits="0"/> + <line number="141" hits="0"/> + <line number="143" hits="0"/> + <line number="144" hits="0"/> + <line number="146" hits="0"/> + <line number="149" hits="0"/> + <line number="150" hits="0"/> + <line number="151" hits="0"/> + <line number="152" hits="0"/> + <line number="154" hits="0"/> + <line number="155" hits="0"/> + <line number="156" hits="0"/> + <line number="159" hits="0"/> + <line number="160" hits="0"/> + <line number="163" hits="0"/> + <line number="165" hits="0"/> + <line number="166" hits="0"/> + <line number="167" hits="0"/> + <line number="170" hits="0"/> + <line number="171" hits="0"/> + <line number="173" hits="0"/> + <line number="176" hits="0"/> + <line number="177" hits="0"/> + <line number="178" hits="0"/> + <line number="180" hits="0"/> + <line number="182" hits="1"/> + <line number="190" hits="0"/> + <line number="191" hits="0"/> + <line number="192" hits="0"/> + <line number="194" hits="1"/> + <line number="195" hits="0"/> + <line number="196" hits="0"/> + <line number="197" hits="0"/> + <line number="199" hits="0"/> + <line number="201" hits="1"/> + <line number="202" hits="0"/> + <line number="204" hits="1"/> + <line number="205" hits="0"/> + <line number="206" hits="0"/> + <line number="207" hits="0"/> + <line number="213" hits="0"/> + <line number="215" hits="1"/> + <line number="216" hits="0"/> + <line number="217" hits="0"/> + <line number="218" hits="0"/> + <line number="219" hits="0"/> + <line number="224" hits="0"/> + <line number="225" hits="0"/> + <line number="226" hits="0"/> + <line number="228" hits="1"/> + <line number="229" hits="0"/> + <line number="231" hits="1"/> + <line number="232" hits="0"/> + </lines> + </class> + </classes> + </package> + <package name="llms" line-rate="0.7321" branch-rate="0" complexity="0"> <classes> <class name="__init__.py" filename="llms/__init__.py" complexity="0" line-rate="1" branch-rate="0"> <methods/> @@ -1248,7 +1568,7 @@ <line number="74" hits="0"/> </lines> </class> - <class name="mistral.py" filename="llms/mistral.py" complexity="0" line-rate="0.8286" branch-rate="0"> + <class name="mistral.py" filename="llms/mistral.py" complexity="0" line-rate="0.8333" branch-rate="0"> <methods/> <lines> <line number="1" hits="1"/> @@ -1257,12 +1577,12 @@ <line number="6" hits="1"/> <line number="7" hits="1"/> <line number="8" hits="1"/> - <line number="11" hits="1"/> + <line number="9" hits="1"/> <line number="12" hits="1"/> <line number="13" hits="1"/> <line number="14" hits="1"/> - <line number="16" hits="1"/> - <line number="23" hits="1"/> + <line number="15" hits="1"/> + <line number="17" hits="1"/> <line number="24" hits="1"/> <line number="25" hits="1"/> <line number="26" hits="1"/> @@ -1270,25 +1590,26 @@ <line number="28" hits="1"/> <line number="29" hits="1"/> <line number="30" hits="1"/> - <line number="31" hits="0"/> + <line number="31" hits="1"/> <line number="32" hits="0"/> - <line number="35" hits="1"/> + <line number="33" hits="0"/> <line number="36" hits="1"/> - <line number="38" hits="1"/> + <line number="37" hits="1"/> <line number="39" hits="1"/> <line number="40" hits="1"/> <line number="41" hits="1"/> <line number="42" hits="1"/> - <line number="49" hits="1"/> - <line number="51" hits="1"/> - <line number="52" hits="0"/> - <line number="53" hits="1"/> - <line number="54" hits="0"/> + <line number="43" hits="1"/> + <line number="50" hits="1"/> + <line number="52" hits="1"/> + <line number="53" hits="0"/> + <line number="54" hits="1"/> <line number="55" hits="0"/> <line number="56" hits="0"/> + <line number="57" hits="0"/> </lines> </class> - <class name="openai.py" filename="llms/openai.py" complexity="0" line-rate="0.8571" branch-rate="0"> + <class name="openai.py" filename="llms/openai.py" complexity="0" line-rate="0.8889" branch-rate="0"> <methods/> <lines> <line number="1" hits="1"/> @@ -1297,35 +1618,36 @@ <line number="6" hits="1"/> <line number="7" hits="1"/> <line number="8" hits="1"/> - <line number="11" hits="1"/> + <line number="9" hits="1"/> <line number="12" hits="1"/> <line number="13" hits="1"/> <line number="14" hits="1"/> - <line number="16" hits="1"/> - <line number="23" hits="1"/> + <line number="15" hits="1"/> + <line number="17" hits="1"/> <line number="24" hits="1"/> <line number="25" hits="1"/> <line number="26" hits="1"/> <line number="27" hits="1"/> - <line number="28" hits="0"/> + <line number="28" hits="1"/> <line number="29" hits="1"/> <line number="30" hits="1"/> <line number="31" hits="1"/> <line number="32" hits="1"/> - <line number="35" hits="1"/> + <line number="33" hits="1"/> <line number="36" hits="1"/> - <line number="38" hits="1"/> + <line number="37" hits="1"/> <line number="39" hits="1"/> <line number="40" hits="1"/> <line number="41" hits="1"/> <line number="42" hits="1"/> - <line number="49" hits="1"/> - <line number="51" hits="1"/> - <line number="52" hits="0"/> - <line number="53" hits="1"/> - <line number="54" hits="0"/> + <line number="43" hits="1"/> + <line number="50" hits="1"/> + <line number="52" hits="1"/> + <line number="53" hits="0"/> + <line number="54" hits="1"/> <line number="55" hits="0"/> <line number="56" hits="0"/> + <line number="57" hits="0"/> </lines> </class> <class name="openrouter.py" filename="llms/openrouter.py" complexity="0" line-rate="0.8649" branch-rate="0"> @@ -1370,7 +1692,7 @@ <line number="61" hits="0"/> </lines> </class> - <class name="zure.py" filename="llms/zure.py" complexity="0" line-rate="0.8684" branch-rate="0"> + <class name="zure.py" filename="llms/zure.py" complexity="0" line-rate="0.8974" branch-rate="0"> <methods/> <lines> <line number="1" hits="1"/> @@ -1379,38 +1701,39 @@ <line number="6" hits="1"/> <line number="7" hits="1"/> <line number="8" hits="1"/> - <line number="11" hits="1"/> + <line number="9" hits="1"/> <line number="12" hits="1"/> <line number="13" hits="1"/> <line number="14" hits="1"/> - <line number="16" hits="1"/> - <line number="25" hits="1"/> + <line number="15" hits="1"/> + <line number="17" hits="1"/> <line number="26" hits="1"/> <line number="27" hits="1"/> <line number="28" hits="1"/> <line number="29" hits="1"/> - <line number="30" hits="0"/> + <line number="30" hits="1"/> <line number="31" hits="1"/> <line number="32" hits="1"/> <line number="33" hits="1"/> <line number="34" hits="1"/> <line number="35" hits="1"/> - <line number="38" hits="1"/> + <line number="36" hits="1"/> <line number="39" hits="1"/> <line number="40" hits="1"/> <line number="41" hits="1"/> - <line number="43" hits="1"/> + <line number="42" hits="1"/> <line number="44" hits="1"/> <line number="45" hits="1"/> <line number="46" hits="1"/> <line number="47" hits="1"/> - <line number="54" hits="1"/> - <line number="56" hits="1"/> - <line number="57" hits="0"/> - <line number="58" hits="1"/> - <line number="59" hits="0"/> + <line number="48" hits="1"/> + <line number="55" hits="1"/> + <line number="57" hits="1"/> + <line number="58" hits="0"/> + <line number="59" hits="1"/> <line number="60" hits="0"/> <line number="61" hits="0"/> + <line number="62" hits="0"/> </lines> </class> </classes> @@ -1504,12 +1827,25 @@ </class> </classes> </package> - <package name="utils" line-rate="0.4688" branch-rate="0" complexity="0"> + <package name="utils" line-rate="0.5278" branch-rate="0" complexity="0"> <classes> <class name="__init__.py" filename="utils/__init__.py" complexity="0" line-rate="1" branch-rate="0"> <methods/> <lines/> </class> + <class name="defaults.py" filename="utils/defaults.py" complexity="0" line-rate="1" branch-rate="0"> + <methods/> + <lines> + <line number="1" hits="1"/> + <line number="2" hits="1"/> + <line number="5" hits="1"/> + <line number="6" hits="1"/> + <line number="10" hits="1"/> + <line number="14" hits="1"/> + <line number="18" hits="1"/> + <line number="22" hits="1"/> + </lines> + </class> <class name="function_call.py" filename="utils/function_call.py" complexity="0" line-rate="0.3667" branch-rate="0"> <methods/> <lines> diff --git a/docs/07-ollama-local-execution.ipynb b/docs/07-ollama-local-execution.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..cf26b77ec5355d41efb6a69a896c52a3dd8f53f8 --- /dev/null +++ b/docs/07-ollama-local-execution.ipynb @@ -0,0 +1,486 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[](https://colab.research.google.com/github/aurelio-labs/semantic-router/blob/main/docs/07-ollama-local-execution.ipynb) [](https://nbviewer.org/github/aurelio-labs/semantic-router/blob/main/docs/07-ollama-local-execution.ipynb)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Local Dynamic Routes - With Ollama" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Fully local Semantic Router with Ollama and HuggingFace Encoder\n", + "\n", + "There are many reasons users might choose to roll their own LLMs rather than use a third-party service. Whether it's due to cost, privacy or compliance, Semantic Router supports the use of \"local\" LLMs through `llama.cpp`.\n", + "\n", + "Below is an example of using semantic router which leverages Ollama in order to utilize the **OpenHermes** LLM. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We need `pillow`, `torch` and `transformers` for the HuggingFace encoders." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Installing the Library and Dependencies" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: semantic_router[local]==0.0.23 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (0.0.23)\n", + "Requirement already satisfied: pillow in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (10.2.0)\n", + "Requirement already satisfied: torch in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (2.2.0)\n", + "Requirement already satisfied: transformers in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (4.38.0)\n", + "Requirement already satisfied: black<24.0.0,>=23.12.1 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from semantic_router[local]==0.0.23) (23.12.1)\n", + "Requirement already satisfied: cohere<5.0,>=4.32 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from semantic_router[local]==0.0.23) (4.47)\n", + "Requirement already satisfied: colorama<0.5.0,>=0.4.6 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from semantic_router[local]==0.0.23) (0.4.6)\n", + "Requirement already satisfied: colorlog<7.0.0,>=6.8.0 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from semantic_router[local]==0.0.23) (6.8.2)\n", + "Requirement already satisfied: llama-cpp-python<0.3.0,>=0.2.28 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from semantic_router[local]==0.0.23) (0.2.45)\n", + "Requirement already satisfied: mistralai<0.0.13,>=0.0.12 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from semantic_router[local]==0.0.23) (0.0.12)\n", + "Requirement already satisfied: numpy<2.0.0,>=1.25.2 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from semantic_router[local]==0.0.23) (1.26.4)\n", + "Requirement already satisfied: openai<2.0.0,>=1.10.0 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from semantic_router[local]==0.0.23) (1.12.0)\n", + "Requirement already satisfied: pydantic<3.0.0,>=2.5.3 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from semantic_router[local]==0.0.23) (2.6.1)\n", + "Requirement already satisfied: pyyaml<7.0.0,>=6.0.1 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from semantic_router[local]==0.0.23) (6.0.1)\n", + "Requirement already satisfied: filelock in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from torch) (3.13.1)\n", + "Requirement already satisfied: typing-extensions>=4.8.0 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from torch) (4.9.0)\n", + "Requirement already satisfied: sympy in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from torch) (1.12)\n", + "Requirement already satisfied: networkx in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from torch) (3.2.1)\n", + "Requirement already satisfied: jinja2 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from torch) (3.1.3)\n", + "Requirement already satisfied: fsspec in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from torch) (2024.2.0)\n", + "Requirement already satisfied: huggingface-hub<1.0,>=0.19.3 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from transformers) (0.20.3)\n", + "Requirement already satisfied: packaging>=20.0 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from transformers) (23.2)\n", + "Requirement already satisfied: regex!=2019.12.17 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from transformers) (2023.12.25)\n", + "Requirement already satisfied: requests in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from transformers) (2.31.0)\n", + "Requirement already satisfied: tokenizers<0.19,>=0.14 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from transformers) (0.15.2)\n", + "Requirement already satisfied: safetensors>=0.4.1 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from transformers) (0.4.2)\n", + "Requirement already satisfied: tqdm>=4.27 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from transformers) (4.66.2)\n", + "Requirement already satisfied: click>=8.0.0 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from black<24.0.0,>=23.12.1->semantic_router[local]==0.0.23) (8.1.7)\n", + "Requirement already satisfied: mypy-extensions>=0.4.3 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from black<24.0.0,>=23.12.1->semantic_router[local]==0.0.23) (1.0.0)\n", + "Requirement already satisfied: pathspec>=0.9.0 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from black<24.0.0,>=23.12.1->semantic_router[local]==0.0.23) (0.12.1)\n", + "Requirement already satisfied: platformdirs>=2 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from black<24.0.0,>=23.12.1->semantic_router[local]==0.0.23) (4.2.0)\n", + "Requirement already satisfied: aiohttp<4.0,>=3.0 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from cohere<5.0,>=4.32->semantic_router[local]==0.0.23) (3.9.3)\n", + "Requirement already satisfied: backoff<3.0,>=2.0 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from cohere<5.0,>=4.32->semantic_router[local]==0.0.23) (2.2.1)\n", + "Requirement already satisfied: fastavro<2.0,>=1.8 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from cohere<5.0,>=4.32->semantic_router[local]==0.0.23) (1.9.4)\n", + "Requirement already satisfied: importlib_metadata<7.0,>=6.0 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from cohere<5.0,>=4.32->semantic_router[local]==0.0.23) (6.11.0)\n", + "Requirement already satisfied: urllib3<3,>=1.26 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from cohere<5.0,>=4.32->semantic_router[local]==0.0.23) (2.2.1)\n", + "Requirement already satisfied: diskcache>=5.6.1 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from llama-cpp-python<0.3.0,>=0.2.28->semantic_router[local]==0.0.23) (5.6.3)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from jinja2->torch) (2.1.5)\n", + "Requirement already satisfied: httpx<0.26.0,>=0.25.2 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from mistralai<0.0.13,>=0.0.12->semantic_router[local]==0.0.23) (0.25.2)\n", + "Requirement already satisfied: orjson<4.0.0,>=3.9.10 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from mistralai<0.0.13,>=0.0.12->semantic_router[local]==0.0.23) (3.9.14)\n", + "Requirement already satisfied: anyio<5,>=3.5.0 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from openai<2.0.0,>=1.10.0->semantic_router[local]==0.0.23) (4.2.0)\n", + "Requirement already satisfied: distro<2,>=1.7.0 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from openai<2.0.0,>=1.10.0->semantic_router[local]==0.0.23) (1.9.0)\n", + "Requirement already satisfied: sniffio in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from openai<2.0.0,>=1.10.0->semantic_router[local]==0.0.23) (1.3.0)\n", + "Requirement already satisfied: annotated-types>=0.4.0 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from pydantic<3.0.0,>=2.5.3->semantic_router[local]==0.0.23) (0.6.0)\n", + "Requirement already satisfied: pydantic-core==2.16.2 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from pydantic<3.0.0,>=2.5.3->semantic_router[local]==0.0.23) (2.16.2)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from requests->transformers) (3.3.2)\n", + "Requirement already satisfied: idna<4,>=2.5 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from requests->transformers) (3.6)\n", + "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from requests->transformers) (2024.2.2)\n", + "Requirement already satisfied: mpmath>=0.19 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from sympy->torch) (1.3.0)\n", + "Requirement already satisfied: aiosignal>=1.1.2 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from aiohttp<4.0,>=3.0->cohere<5.0,>=4.32->semantic_router[local]==0.0.23) (1.3.1)\n", + "Requirement already satisfied: attrs>=17.3.0 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from aiohttp<4.0,>=3.0->cohere<5.0,>=4.32->semantic_router[local]==0.0.23) (23.2.0)\n", + "Requirement already satisfied: frozenlist>=1.1.1 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from aiohttp<4.0,>=3.0->cohere<5.0,>=4.32->semantic_router[local]==0.0.23) (1.4.1)\n", + "Requirement already satisfied: multidict<7.0,>=4.5 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from aiohttp<4.0,>=3.0->cohere<5.0,>=4.32->semantic_router[local]==0.0.23) (6.0.5)\n", + "Requirement already satisfied: yarl<2.0,>=1.0 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from aiohttp<4.0,>=3.0->cohere<5.0,>=4.32->semantic_router[local]==0.0.23) (1.9.4)\n", + "Requirement already satisfied: httpcore==1.* in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from httpx<0.26.0,>=0.25.2->mistralai<0.0.13,>=0.0.12->semantic_router[local]==0.0.23) (1.0.3)\n", + "Requirement already satisfied: h11<0.15,>=0.13 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from httpcore==1.*->httpx<0.26.0,>=0.25.2->mistralai<0.0.13,>=0.0.12->semantic_router[local]==0.0.23) (0.14.0)\n", + "Requirement already satisfied: zipp>=0.5 in c:\\users\\siraj\\documents\\personal\\work\\aurelio\\20240123 semantic router\\venvs\\semantic_router\\lib\\site-packages (from importlib_metadata<7.0,>=6.0->cohere<5.0,>=4.32->semantic_router[local]==0.0.23) (3.17.0)\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\n", + "[notice] A new release of pip is available: 23.1.2 -> 24.0\n", + "[notice] To update, run: python.exe -m pip install --upgrade pip\n" + ] + } + ], + "source": [ + "!pip install semantic_router[local]==0.0.23 \\\n", + "pillow torch transformers" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\Users\\Siraj\\Documents\\Personal\\Work\\Aurelio\\20240123 Semantic Router\\venvs\\semantic_router\\Lib\\site-packages\\tqdm\\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + } + ], + "source": [ + "from semantic_router.encoders import HuggingFaceEncoder\n", + "\n", + "encoder = HuggingFaceEncoder()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Define Static Routes" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "from semantic_router import Route\n", + "\n", + "# we could use this as a guide for our chatbot to avoid political conversations\n", + "politics = Route(\n", + " name=\"politics\",\n", + " utterances=[\n", + " \"isn't politics the best thing ever\",\n", + " \"why don't you tell me about your political opinions\",\n", + " \"don't you just love the president\" \"don't you just hate the president\",\n", + " \"they're going to destroy this country!\",\n", + " \"they will save the country!\",\n", + " ],\n", + ")\n", + "\n", + "# this could be used as an indicator to our chatbot to switch to a more\n", + "# conversational prompt\n", + "chitchat = Route(\n", + " name=\"chitchat\",\n", + " utterances=[\n", + " \"how's the weather today?\",\n", + " \"how are things going?\",\n", + " \"lovely weather today\",\n", + " \"the weather is horrendous\",\n", + " \"let's go to the chippy\",\n", + " ],\n", + ")\n", + "\n", + "# we place both of our decisions together into single list\n", + "routes = [politics, chitchat]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Define Route Layer with Ollama" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m2024-02-22 10:59:54 INFO semantic_router.utils.logger local\u001b[0m\n" + ] + } + ], + "source": [ + "from semantic_router.layer import RouteLayer\n", + "from semantic_router.llms.ollama import OllamaLLM\n", + "\n", + "\n", + "llm = OllamaLLM(\n", + " llm_name=\"openhermes\"\n", + ") # Change llm_name if you want to use a different LLM with dynamic routes.\n", + "rl = RouteLayer(encoder=encoder, routes=routes, llm=llm)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test Static Routes" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'politics'" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rl(\"don't you love politics?\").name" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'chitchat'" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rl(\"how's the weather today?\").name" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "rl(\"I'm interested in learning about llama 2\").name" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test Dynamic Routes\n", + "\n", + "Dynamic routes work by associating a function with a route. If the input utterance is similar enough to the utterances of the route, such that route is chosen by the semantic router, then this triggers a secondary process: \n", + "\n", + "The LLM we specified in the `RouteLayer` (we specified Ollama, which isn't strictly an LLM, but which defaults to using the `OpenHermes` LLM), is then usde to take a `function_schema`, and the input utterance, and extract values from the input utterance which can be used as arguments for `function` described by the the `funcion_schema`. The returned values can then be used in the `function` to obtain an output.\n", + "\n", + "So, in short, it's a way of generating `function` inputs from an utterance, if that utterance matches the route utterances closely enough.\n", + "\n", + "In the below example the utterance **\"what is the time in new york city?\"** is used to trigger the \"get_time\" route, which has the `function_schema` of a likewise named `get_time()` function associated with it. Then Ollama is used to run `OpenHermes` locally, which extracts the correctly formatted IANA timezone (`\"America/New York\"`), based on this utterance and information we provide it about the `function` in the `function_schema`. The returned stirng \"America/New York\" can then be used directly in the `get_time()` function to return the actual time in New York city." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "from datetime import datetime\n", + "from zoneinfo import ZoneInfo\n", + "\n", + "\n", + "def get_time(timezone: str) -> str:\n", + " \"\"\"\n", + " Finds the current time in a specific timezone.\n", + "\n", + " :param timezone: The timezone to find the current time in, should\n", + " be a valid timezone from the IANA Time Zone Database like\n", + " \"America/New_York\" or \"Europe/London\". Do NOT put the place\n", + " name itself like \"rome\", or \"new york\", you must provide\n", + " the IANA format.\n", + " :type timezone: str\n", + " :return: The current time in the specified timezone.\n", + " \"\"\"\n", + " now = datetime.now(ZoneInfo(timezone))\n", + " return now.strftime(\"%H:%M\")" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'01:59'" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_time(\"America/New_York\")" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'name': 'get_time',\n", + " 'description': 'Finds the current time in a specific timezone.\\n\\n:param timezone: The timezone to find the current time in, should\\n be a valid timezone from the IANA Time Zone Database like\\n \"America/New_York\" or \"Europe/London\". Do NOT put the place\\n name itself like \"rome\", or \"new york\", you must provide\\n the IANA format.\\n:type timezone: str\\n:return: The current time in the specified timezone.\\n ',\n", + " 'signature': '(timezone: str) -> str',\n", + " 'output': \"<class 'str'>\"}" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from semantic_router.utils.function_call import get_schema\n", + "\n", + "schema = get_schema(get_time)\n", + "schema" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "time_route = Route(\n", + " name=\"get_time\",\n", + " utterances=[\n", + " \"what is the time in new york city?\",\n", + " \"what is the time in london?\",\n", + " \"I live in Rome, what time is it?\",\n", + " ],\n", + " function_schema=schema,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m2024-02-22 10:59:55 INFO semantic_router.utils.logger Adding `get_time` route\u001b[0m\n" + ] + } + ], + "source": [ + "rl.add(time_route)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m2024-02-22 11:01:29 INFO semantic_router.utils.logger Extracting function input...\u001b[0m\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m2024-02-22 11:01:32 INFO semantic_router.utils.logger LLM output: {\n", + " \"timezone\": \"America/New_York\"\n", + "}\u001b[0m\n", + "\u001b[32m2024-02-22 11:01:32 INFO semantic_router.utils.logger Function inputs: {'timezone': 'America/New_York'}\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "name='get_time' function_call={'timezone': 'America/New_York'} similarity_score=None trigger=None\n" + ] + } + ], + "source": [ + "out = rl(\"what is the time in new york city?\")\n", + "print(out)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'02:01'" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_time(**out.function_call)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "semantic_splitter_1", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/08-multi-modal.ipynb b/docs/08-multi-modal.ipynb index e5e42399119a4dff6afb0ec586abb9bce537232a..f4c72f311a4faf0bcb1bd1dee6ea8618866d1493 100644 --- a/docs/08-multi-modal.ipynb +++ b/docs/08-multi-modal.ipynb @@ -42,7 +42,7 @@ "outputs": [], "source": [ "!pip install -qU \\\n", - " \"semantic-router[local]==0.0.25\" \\\n", + " \"semantic-router[vision]==0.0.25\" \\\n", " datasets==2.17.0" ] }, diff --git a/docs/examples/rolling-window-splitter.ipynb b/docs/examples/rolling-window-splitter.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..b94d3a5615ec9b2edda91da90a481be235829bef --- /dev/null +++ b/docs/examples/rolling-window-splitter.ipynb @@ -0,0 +1,193 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "text = \"\"\"\n", + "In a recent surge of social media discussions on Weibo, Chinese netizens have been engaging in conversations about the struggles and challenges of earning money. The online debate sparked a wave of opinions and perspectives on the relationship between hard work, high pay, and finding contentment. Among the tweets, several users pontificated that one should avoid earning \"too much hard-earned money.\"\n", + "The tweets and discussions revolve around the idea that working too hard for one's income can have a detrimental effect on one's life, both physically and mentally. Some users advocate for finding opportunities that align with one's strengths and passions, rather than simply focusing on high-paying jobs that may require excessive hours and intense labor.\n", + "One Weibo user pontificates, \"Don't earn that much hard-earned money,\" a sentiment echoed by others with tweets such as, \"Why is it that when earning money, that process always has to be so tough?\" This question is followed by a comparison between two types of people - those who are used to earning money the hard way and those who seem to effortlessly obtain wealth. While the former group is depicted as having been taught to suffer from a young age, the latter is shown as being able to focus solely on their natural talents and thriving in their niche advantageously.\n", + "Discussions on the platform draw attention to a variety of issues that those who earn money the hard way might face. For example, they are described as likely having to work overtime, forgo time off for illness or rest, and maintain an unyielding dedication to their occupation, which often results in a never-ending cycle of work without any perceived progression in their lives.\n", + "Another tweet that captures this sentiment reads, \"Drowning in more work and poverty despite trying harder and harder,\" pointing to a sense of despair and dissatisfaction that comes with work that is both disproportionately demanding and inadequately rewarding. Critics also note how the pursuit of hard-earned money could potentially create physical and mental health risks due to the unrelenting pressure and stress that these jobs might impose.\n", + "Conversely, those in favor of earning money with less difficulty contend that it's crucial to harness one's strengths and passions to create opportunities that yield financial success without the need for excessive labor. The debate revolves around the concept that people should seek out ways to work smarter, not harder, especially if it means a healthier and more fulfilling lifestyle.\n", + "In fact, the notion of a \"vicious cycle,\" often attributed to those chasing hard-earned money, is juxtaposed with an idealized image of someone operating in their zone of excellence. Confidently focused on their strengths, such individuals are depicted as enjoying a more relaxed and less stressful work environment, one in which they can thrive without the need for never-ending overtime or self-sacrifice.\n", + "Some tweets even extend this sentiment to the broader socio-economic context, observing how wealth is not merely derived from manual labor or high-paying positions requiring extraordinary work hours. The tweets emphasize the importance of cultivating an entrepreneurial spirit and a penchant for innovative thinking, especially in the modern digital age.\n", + "One user writes, \"Too hard-earned money isn't worth it. Learn how to make money using your brain, not your body,\" while another suggests, \"Love will flow towards those who are not lacking in love, and money will flow towards those who are not lacking in money!\"\n", + "While some of the discussions take a somewhat passive-aggressive view, others acknowledge that financial security and comfort might not always be possible for everyone. In a more realistic tone, a user remarks, \"If life were so easy that diligence led to wealth, then the world's richest person would be the best worker bee. But that's not the case.\" This acknowledgment underscores the complexities of the economy and the role that factors like luck, connections, and a rapidly evolving job market can play in financial success.\n", + "Some users are quick to criticize the notion that earning money the hard way should be avoided, with one tweet expressing, \"The person who advises you to avoid hard-earned money is likely a scammer who profits off providing emotional value in exchange for exploitation.\" Others argue that while it's essential to find enjoyment and fulfillment in one's work, it's crucial not to shun or belittle those who choose to work in physically demanding or high-paying industries.\n", + "Overall, the Weibo discussions offer a fascinating insight into the complexities of the modern Chinese labor market and the work-life balance that people strive to achieve. As in many countries, striking the right balance between work and play is an ongoing challenge for many Chinese citizens. However, the conversations on Weibo signal an increasing awareness of the importance of finding meaningful, fulfilling, and financially rewarding work that doesn't necessitate excessive sacrifice or sufferance.\n", + "In the end, as one user succinctly puts it, \"Make sure you're earning your money in a way that brings you joy and satisfaction. That's the only way to ensure that your life doesn't become a never-ending cycle of hard work without any tangible progress.\"\n", + "In this context, social media discussions focusing on the trials and tribulations of earning money serve not only as an outlet for venting frustrations but also as a means of promoting dialogue and shared understanding about the challenges faced by workers across all industries. These virtual conversations sparked by tweets and in-depth discussions likely resonate with a wide swath of Chinese citizens struggling to navigate the complexities of balancing a career that pays well with one that brings them joy, fulfillment, and a sense of purpose.\n", + "As the discussions on Weibo continue to evolve and unfold, it is evident that the discourse around work, money, and life satisfaction holds the potential to inspire meaningful change and shift societal attitudes towards a more holistic, balanced, and humane understanding of success and prosperity.\n", + "---\n", + "Note: The translated tweets and user quotes from Chinese to English were used as the foundation for the long-form news article. The author tried to maintain the integrity of the original content in the translation while adapting it to fit a journalistic format. No inaccuracies were introduced during translation, and the opinion-based nature of the original content was preserved while maintaining objectivity.\n", + "Heart count: 0/2\n", + "Note: The author did not include any Chinese characters in the final response.\n", + "Collapse\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/jamesbriggs/opt/anaconda3/envs/decision-layer/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + } + ], + "source": [ + "import os\n", + "from getpass import getpass\n", + "from semantic_router.splitters import RollingWindowSplitter\n", + "from semantic_router.encoders import OpenAIEncoder\n", + "\n", + "os.environ[\"OPENAI_API_KEY\"] = os.getenv(\"OPENAI_API_KEY\") or getpass(\n", + " \"Enter your OpenAI API key: \"\n", + ")\n", + "\n", + "splitter = RollingWindowSplitter(\n", + " encoder=OpenAIEncoder(),\n", + " min_split_tokens=50,\n", + " max_split_tokens=300,\n", + " window_size=5, # sentences\n", + " plot_splits=True,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[33m2024-02-23 08:44:26 WARNING semantic_router.utils.logger Single document exceeds the maximum token limit of 300. Splitting to sentences before semantically splitting.\u001b[0m\n", + "\u001b[32m2024-02-23 08:44:26 INFO semantic_router.utils.logger Iteration 0: Trying threshold: 0.8881277932028191\u001b[0m\n", + "\u001b[32m2024-02-23 08:44:26 INFO semantic_router.utils.logger Iteration 0: Median tokens per split: 24.0\u001b[0m\n", + "\u001b[32m2024-02-23 08:44:26 INFO semantic_router.utils.logger Iteration 0: Adjusting high to 0.8781277932028191\u001b[0m\n", + "\u001b[32m2024-02-23 08:44:26 INFO semantic_router.utils.logger Iteration 1: Trying threshold: 0.8687934834140205\u001b[0m\n", + "\u001b[32m2024-02-23 08:44:26 INFO semantic_router.utils.logger Iteration 1: Median tokens per split: 34.5\u001b[0m\n", + "\u001b[32m2024-02-23 08:44:26 INFO semantic_router.utils.logger Iteration 1: Adjusting high to 0.8587934834140205\u001b[0m\n", + "\u001b[32m2024-02-23 08:44:26 INFO semantic_router.utils.logger Final optimal threshold: 0.8687934834140205\u001b[0m\n", + "\u001b[32m2024-02-23 08:44:27 INFO semantic_router.utils.logger Split finalized with 218 tokens due to threshold 0.8687934834140205.\u001b[0m\n", + "\u001b[32m2024-02-23 08:44:27 INFO semantic_router.utils.logger Split finalized with 262 tokens due to exceeding token limit of 300.\u001b[0m\n", + "\u001b[32m2024-02-23 08:44:27 INFO semantic_router.utils.logger Split finalized with 137 tokens due to threshold 0.8687934834140205.\u001b[0m\n", + "\u001b[32m2024-02-23 08:44:27 INFO semantic_router.utils.logger Split finalized with 249 tokens due to threshold 0.8687934834140205.\u001b[0m\n", + "\u001b[32m2024-02-23 08:44:27 INFO semantic_router.utils.logger Split finalized with 117 tokens due to threshold 0.8687934834140205.\u001b[0m\n", + "\u001b[32m2024-02-23 08:44:27 INFO semantic_router.utils.logger Split finalized with 171 tokens due to threshold 0.8687934834140205.\u001b[0m\n", + "\u001b[32m2024-02-23 08:44:27 INFO semantic_router.utils.logger Split finalized with 72 tokens due to threshold 0.8687934834140205.\u001b[0m\n", + "\u001b[32m2024-02-23 08:44:27 INFO semantic_router.utils.logger Final split added with 23 tokens due to remaining documents.\u001b[0m\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "<Figure size 1200x600 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "splits = splitter([text])" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Split 1, tokens 218, triggered by: 0.85\n", + "\u001b[31mIn a recent surge of social media discussions on Weibo, Chinese netizens have been engaging in conversations about the struggles and challenges of earning money. The online debate sparked a wave of opinions and perspectives on the relationship between hard work, high pay, and finding contentment. Among the tweets, several users pontificated that one should avoid earning \"too much hard-earned money.\" The tweets and discussions revolve around the idea that working too hard for one's income can have a detrimental effect on one's life, both physically and mentally. Some users advocate for finding opportunities that align with one's strengths and passions, rather than simply focusing on high-paying jobs that may require excessive hours and intense labor. One Weibo user pontificates, \"Don't earn that much hard-earned money,\" a sentiment echoed by others with tweets such as, \"Why is it that when earning money, that process always has to be so tough?\" This question is followed by a comparison between two types of people - those who are used to earning money the hard way and those who seem to effortlessly obtain wealth.\u001b[0m\n", + "----------------------------------------------------------------------------------------\n", + "\n", + "\n", + "Split 2, tokens 262, triggered by: token limit\n", + "\u001b[32mWhile the former group is depicted as having been taught to suffer from a young age, the latter is shown as being able to focus solely on their natural talents and thriving in their niche advantageously. Discussions on the platform draw attention to a variety of issues that those who earn money the hard way might face. For example, they are described as likely having to work overtime, forgo time off for illness or rest, and maintain an unyielding dedication to their occupation, which often results in a never-ending cycle of work without any perceived progression in their lives. Another tweet that captures this sentiment reads, \"Drowning in more work and poverty despite trying harder and harder,\" pointing to a sense of despair and dissatisfaction that comes with work that is both disproportionately demanding and inadequately rewarding. Critics also note how the pursuit of hard-earned money could potentially create physical and mental health risks due to the unrelenting pressure and stress that these jobs might impose. Conversely, those in favor of earning money with less difficulty contend that it's crucial to harness one's strengths and passions to create opportunities that yield financial success without the need for excessive labor. The debate revolves around the concept that people should seek out ways to work smarter, not harder, especially if it means a healthier and more fulfilling lifestyle.\u001b[0m\n", + "----------------------------------------------------------------------------------------\n", + "\n", + "\n", + "Split 3, tokens 137, triggered by: 0.85\n", + "\u001b[34mIn fact, the notion of a \"vicious cycle,\" often attributed to those chasing hard-earned money, is juxtaposed with an idealized image of someone operating in their zone of excellence. Confidently focused on their strengths, such individuals are depicted as enjoying a more relaxed and less stressful work environment, one in which they can thrive without the need for never-ending overtime or self-sacrifice. Some tweets even extend this sentiment to the broader socio-economic context, observing how wealth is not merely derived from manual labor or high-paying positions requiring extraordinary work hours. The tweets emphasize the importance of cultivating an entrepreneurial spirit and a penchant for innovative thinking, especially in the modern digital age.\u001b[0m\n", + "----------------------------------------------------------------------------------------\n", + "\n", + "\n", + "Split 4, tokens 249, triggered by: 0.86\n", + "\u001b[35mOne user writes, \"Too hard-earned money isn't worth it. Learn how to make money using your brain, not your body,\" while another suggests, \"Love will flow towards those who are not lacking in love, and money will flow towards those who are not lacking in money!\" While some of the discussions take a somewhat passive-aggressive view, others acknowledge that financial security and comfort might not always be possible for everyone. In a more realistic tone, a user remarks, \"If life were so easy that diligence led to wealth, then the world's richest person would be the best worker bee. But that's not the case.\" This acknowledgment underscores the complexities of the economy and the role that factors like luck, connections, and a rapidly evolving job market can play in financial success. Some users are quick to criticize the notion that earning money the hard way should be avoided, with one tweet expressing, \"The person who advises you to avoid hard-earned money is likely a scammer who profits off providing emotional value in exchange for exploitation.\" Others argue that while it's essential to find enjoyment and fulfillment in one's work, it's crucial not to shun or belittle those who choose to work in physically demanding or high-paying industries.\u001b[0m\n", + "----------------------------------------------------------------------------------------\n", + "\n", + "\n", + "Split 5, tokens 117, triggered by: 0.87\n", + "\u001b[31mOverall, the Weibo discussions offer a fascinating insight into the complexities of the modern Chinese labor market and the work-life balance that people strive to achieve. As in many countries, striking the right balance between work and play is an ongoing challenge for many Chinese citizens. However, the conversations on Weibo signal an increasing awareness of the importance of finding meaningful, fulfilling, and financially rewarding work that doesn't necessitate excessive sacrifice or sufferance. In the end, as one user succinctly puts it, \"Make sure you're earning your money in a way that brings you joy and satisfaction.\u001b[0m\n", + "----------------------------------------------------------------------------------------\n", + "\n", + "\n", + "Split 6, tokens 171, triggered by: 0.82\n", + "\u001b[32mThat's the only way to ensure that your life doesn't become a never-ending cycle of hard work without any tangible progress.\" In this context, social media discussions focusing on the trials and tribulations of earning money serve not only as an outlet for venting frustrations but also as a means of promoting dialogue and shared understanding about the challenges faced by workers across all industries. These virtual conversations sparked by tweets and in-depth discussions likely resonate with a wide swath of Chinese citizens struggling to navigate the complexities of balancing a career that pays well with one that brings them joy, fulfillment, and a sense of purpose. As the discussions on Weibo continue to evolve and unfold, it is evident that the discourse around work, money, and life satisfaction holds the potential to inspire meaningful change and shift societal attitudes towards a more holistic, balanced, and humane understanding of success and prosperity.\u001b[0m\n", + "----------------------------------------------------------------------------------------\n", + "\n", + "\n", + "Split 7, tokens 72, triggered by: 0.80\n", + "\u001b[34m--- Note: The translated tweets and user quotes from Chinese to English were used as the foundation for the long-form news article. The author tried to maintain the integrity of the original content in the translation while adapting it to fit a journalistic format. No inaccuracies were introduced during translation, and the opinion-based nature of the original content was preserved while maintaining objectivity.\u001b[0m\n", + "----------------------------------------------------------------------------------------\n", + "\n", + "\n", + "Split 8, tokens 23, triggered by: final split\n", + "\u001b[35mHeart count: 0/2 Note: The author did not include any Chinese characters in the final response. Collapse\u001b[0m\n", + "----------------------------------------------------------------------------------------\n", + "\n", + "\n" + ] + } + ], + "source": [ + "splitter.print(splits)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/poetry.lock b/poetry.lock index 086172b533de9799378950b333e4c1783cb7e5a6..8e64ef1d97c81c96f2e3d8bc7e9a70c242e50649 100644 --- a/poetry.lock +++ b/poetry.lock @@ -449,13 +449,13 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} [[package]] name = "cohere" -version = "4.47" +version = "4.50" description = "Python SDK for the Cohere API" optional = false python-versions = ">=3.8,<4.0" files = [ - {file = "cohere-4.47-py3-none-any.whl", hash = "sha256:8b96a1ab57713eceffb4ffd58bf647055676fb741a4e5153c14296f9814c77fa"}, - {file = "cohere-4.47.tar.gz", hash = "sha256:d689212079c1a545bd497b143cff7aa5632831fa6cf41bf7acc93b4a6effb839"}, + {file = "cohere-4.50-py3-none-any.whl", hash = "sha256:790744034c76cabd9c3d8e05c0b2e85733caee64e695e5a9904c4527202c913e"}, + {file = "cohere-4.50.tar.gz", hash = "sha256:64908677069fee23bb5dc968d576eab3ed644278e800bb7dcc3e5a336e5fc206"}, ] [package.dependencies] @@ -528,65 +528,128 @@ traitlets = ">=4" [package.extras] test = ["pytest"] +[[package]] +name = "contourpy" +version = "1.2.0" +description = "Python library for calculating contours of 2D quadrilateral grids" +optional = true +python-versions = ">=3.9" +files = [ + {file = "contourpy-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0274c1cb63625972c0c007ab14dd9ba9e199c36ae1a231ce45d725cbcbfd10a8"}, + {file = "contourpy-1.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ab459a1cbbf18e8698399c595a01f6dcc5c138220ca3ea9e7e6126232d102bb4"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fdd887f17c2f4572ce548461e4f96396681212d858cae7bd52ba3310bc6f00f"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d16edfc3fc09968e09ddffada434b3bf989bf4911535e04eada58469873e28e"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c203f617abc0dde5792beb586f827021069fb6d403d7f4d5c2b543d87edceb9"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b69303ceb2e4d4f146bf82fda78891ef7bcd80c41bf16bfca3d0d7eb545448aa"}, + {file = "contourpy-1.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:884c3f9d42d7218304bc74a8a7693d172685c84bd7ab2bab1ee567b769696df9"}, + {file = "contourpy-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4a1b1208102be6e851f20066bf0e7a96b7d48a07c9b0cfe6d0d4545c2f6cadab"}, + {file = "contourpy-1.2.0-cp310-cp310-win32.whl", hash = "sha256:34b9071c040d6fe45d9826cbbe3727d20d83f1b6110d219b83eb0e2a01d79488"}, + {file = "contourpy-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:bd2f1ae63998da104f16a8b788f685e55d65760cd1929518fd94cd682bf03e41"}, + {file = "contourpy-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dd10c26b4eadae44783c45ad6655220426f971c61d9b239e6f7b16d5cdaaa727"}, + {file = "contourpy-1.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5c6b28956b7b232ae801406e529ad7b350d3f09a4fde958dfdf3c0520cdde0dd"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebeac59e9e1eb4b84940d076d9f9a6cec0064e241818bcb6e32124cc5c3e377a"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:139d8d2e1c1dd52d78682f505e980f592ba53c9f73bd6be102233e358b401063"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e9dc350fb4c58adc64df3e0703ab076f60aac06e67d48b3848c23647ae4310e"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18fc2b4ed8e4a8fe849d18dce4bd3c7ea637758c6343a1f2bae1e9bd4c9f4686"}, + {file = "contourpy-1.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:16a7380e943a6d52472096cb7ad5264ecee36ed60888e2a3d3814991a0107286"}, + {file = "contourpy-1.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8d8faf05be5ec8e02a4d86f616fc2a0322ff4a4ce26c0f09d9f7fb5330a35c95"}, + {file = "contourpy-1.2.0-cp311-cp311-win32.whl", hash = "sha256:67b7f17679fa62ec82b7e3e611c43a016b887bd64fb933b3ae8638583006c6d6"}, + {file = "contourpy-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:99ad97258985328b4f207a5e777c1b44a83bfe7cf1f87b99f9c11d4ee477c4de"}, + {file = "contourpy-1.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:575bcaf957a25d1194903a10bc9f316c136c19f24e0985a2b9b5608bdf5dbfe0"}, + {file = "contourpy-1.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9e6c93b5b2dbcedad20a2f18ec22cae47da0d705d454308063421a3b290d9ea4"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:464b423bc2a009088f19bdf1f232299e8b6917963e2b7e1d277da5041f33a779"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:68ce4788b7d93e47f84edd3f1f95acdcd142ae60bc0e5493bfd120683d2d4316"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d7d1f8871998cdff5d2ff6a087e5e1780139abe2838e85b0b46b7ae6cc25399"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e739530c662a8d6d42c37c2ed52a6f0932c2d4a3e8c1f90692ad0ce1274abe0"}, + {file = "contourpy-1.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:247b9d16535acaa766d03037d8e8fb20866d054d3c7fbf6fd1f993f11fc60ca0"}, + {file = "contourpy-1.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:461e3ae84cd90b30f8d533f07d87c00379644205b1d33a5ea03381edc4b69431"}, + {file = "contourpy-1.2.0-cp312-cp312-win32.whl", hash = "sha256:1c2559d6cffc94890b0529ea7eeecc20d6fadc1539273aa27faf503eb4656d8f"}, + {file = "contourpy-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:491b1917afdd8638a05b611a56d46587d5a632cabead889a5440f7c638bc6ed9"}, + {file = "contourpy-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5fd1810973a375ca0e097dee059c407913ba35723b111df75671a1976efa04bc"}, + {file = "contourpy-1.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:999c71939aad2780f003979b25ac5b8f2df651dac7b38fb8ce6c46ba5abe6ae9"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7caf9b241464c404613512d5594a6e2ff0cc9cb5615c9475cc1d9b514218ae8"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:266270c6f6608340f6c9836a0fb9b367be61dde0c9a9a18d5ece97774105ff3e"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbd50d0a0539ae2e96e537553aff6d02c10ed165ef40c65b0e27e744a0f10af8"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11f8d2554e52f459918f7b8e6aa20ec2a3bce35ce95c1f0ef4ba36fbda306df5"}, + {file = "contourpy-1.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ce96dd400486e80ac7d195b2d800b03e3e6a787e2a522bfb83755938465a819e"}, + {file = "contourpy-1.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6d3364b999c62f539cd403f8123ae426da946e142312a514162adb2addd8d808"}, + {file = "contourpy-1.2.0-cp39-cp39-win32.whl", hash = "sha256:1c88dfb9e0c77612febebb6ac69d44a8d81e3dc60f993215425b62c1161353f4"}, + {file = "contourpy-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:78e6ad33cf2e2e80c5dfaaa0beec3d61face0fb650557100ee36db808bfa6843"}, + {file = "contourpy-1.2.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:be16975d94c320432657ad2402f6760990cb640c161ae6da1363051805fa8108"}, + {file = "contourpy-1.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b95a225d4948b26a28c08307a60ac00fb8671b14f2047fc5476613252a129776"}, + {file = "contourpy-1.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0d7e03c0f9a4f90dc18d4e77e9ef4ec7b7bbb437f7f675be8e530d65ae6ef956"}, + {file = "contourpy-1.2.0.tar.gz", hash = "sha256:171f311cb758de7da13fc53af221ae47a5877be5a0843a9fe150818c51ed276a"}, +] + +[package.dependencies] +numpy = ">=1.20,<2.0" + +[package.extras] +bokeh = ["bokeh", "selenium"] +docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.6.1)", "types-Pillow"] +test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] +test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] + [[package]] name = "coverage" -version = "7.4.1" +version = "7.4.3" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:077d366e724f24fc02dbfe9d946534357fda71af9764ff99d73c3c596001bbd7"}, - {file = "coverage-7.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0193657651f5399d433c92f8ae264aff31fc1d066deee4b831549526433f3f61"}, - {file = "coverage-7.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d17bbc946f52ca67adf72a5ee783cd7cd3477f8f8796f59b4974a9b59cacc9ee"}, - {file = "coverage-7.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3277f5fa7483c927fe3a7b017b39351610265308f5267ac6d4c2b64cc1d8d25"}, - {file = "coverage-7.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6dceb61d40cbfcf45f51e59933c784a50846dc03211054bd76b421a713dcdf19"}, - {file = "coverage-7.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6008adeca04a445ea6ef31b2cbaf1d01d02986047606f7da266629afee982630"}, - {file = "coverage-7.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c61f66d93d712f6e03369b6a7769233bfda880b12f417eefdd4f16d1deb2fc4c"}, - {file = "coverage-7.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b9bb62fac84d5f2ff523304e59e5c439955fb3b7f44e3d7b2085184db74d733b"}, - {file = "coverage-7.4.1-cp310-cp310-win32.whl", hash = "sha256:f86f368e1c7ce897bf2457b9eb61169a44e2ef797099fb5728482b8d69f3f016"}, - {file = "coverage-7.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:869b5046d41abfea3e381dd143407b0d29b8282a904a19cb908fa24d090cc018"}, - {file = "coverage-7.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b8ffb498a83d7e0305968289441914154fb0ef5d8b3157df02a90c6695978295"}, - {file = "coverage-7.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3cacfaefe6089d477264001f90f55b7881ba615953414999c46cc9713ff93c8c"}, - {file = "coverage-7.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d6850e6e36e332d5511a48a251790ddc545e16e8beaf046c03985c69ccb2676"}, - {file = "coverage-7.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18e961aa13b6d47f758cc5879383d27b5b3f3dcd9ce8cdbfdc2571fe86feb4dd"}, - {file = "coverage-7.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfd1e1b9f0898817babf840b77ce9fe655ecbe8b1b327983df485b30df8cc011"}, - {file = "coverage-7.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6b00e21f86598b6330f0019b40fb397e705135040dbedc2ca9a93c7441178e74"}, - {file = "coverage-7.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:536d609c6963c50055bab766d9951b6c394759190d03311f3e9fcf194ca909e1"}, - {file = "coverage-7.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7ac8f8eb153724f84885a1374999b7e45734bf93a87d8df1e7ce2146860edef6"}, - {file = "coverage-7.4.1-cp311-cp311-win32.whl", hash = "sha256:f3771b23bb3675a06f5d885c3630b1d01ea6cac9e84a01aaf5508706dba546c5"}, - {file = "coverage-7.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:9d2f9d4cc2a53b38cabc2d6d80f7f9b7e3da26b2f53d48f05876fef7956b6968"}, - {file = "coverage-7.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f68ef3660677e6624c8cace943e4765545f8191313a07288a53d3da188bd8581"}, - {file = "coverage-7.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:23b27b8a698e749b61809fb637eb98ebf0e505710ec46a8aa6f1be7dc0dc43a6"}, - {file = "coverage-7.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e3424c554391dc9ef4a92ad28665756566a28fecf47308f91841f6c49288e66"}, - {file = "coverage-7.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0860a348bf7004c812c8368d1fc7f77fe8e4c095d661a579196a9533778e156"}, - {file = "coverage-7.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe558371c1bdf3b8fa03e097c523fb9645b8730399c14fe7721ee9c9e2a545d3"}, - {file = "coverage-7.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3468cc8720402af37b6c6e7e2a9cdb9f6c16c728638a2ebc768ba1ef6f26c3a1"}, - {file = "coverage-7.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:02f2edb575d62172aa28fe00efe821ae31f25dc3d589055b3fb64d51e52e4ab1"}, - {file = "coverage-7.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ca6e61dc52f601d1d224526360cdeab0d0712ec104a2ce6cc5ccef6ed9a233bc"}, - {file = "coverage-7.4.1-cp312-cp312-win32.whl", hash = "sha256:ca7b26a5e456a843b9b6683eada193fc1f65c761b3a473941efe5a291f604c74"}, - {file = "coverage-7.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:85ccc5fa54c2ed64bd91ed3b4a627b9cce04646a659512a051fa82a92c04a448"}, - {file = "coverage-7.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8bdb0285a0202888d19ec6b6d23d5990410decb932b709f2b0dfe216d031d218"}, - {file = "coverage-7.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:918440dea04521f499721c039863ef95433314b1db00ff826a02580c1f503e45"}, - {file = "coverage-7.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:379d4c7abad5afbe9d88cc31ea8ca262296480a86af945b08214eb1a556a3e4d"}, - {file = "coverage-7.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b094116f0b6155e36a304ff912f89bbb5067157aff5f94060ff20bbabdc8da06"}, - {file = "coverage-7.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2f5968608b1fe2a1d00d01ad1017ee27efd99b3437e08b83ded9b7af3f6f766"}, - {file = "coverage-7.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:10e88e7f41e6197ea0429ae18f21ff521d4f4490aa33048f6c6f94c6045a6a75"}, - {file = "coverage-7.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a4a3907011d39dbc3e37bdc5df0a8c93853c369039b59efa33a7b6669de04c60"}, - {file = "coverage-7.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6d224f0c4c9c98290a6990259073f496fcec1b5cc613eecbd22786d398ded3ad"}, - {file = "coverage-7.4.1-cp38-cp38-win32.whl", hash = "sha256:23f5881362dcb0e1a92b84b3c2809bdc90db892332daab81ad8f642d8ed55042"}, - {file = "coverage-7.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:a07f61fc452c43cd5328b392e52555f7d1952400a1ad09086c4a8addccbd138d"}, - {file = "coverage-7.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8e738a492b6221f8dcf281b67129510835461132b03024830ac0e554311a5c54"}, - {file = "coverage-7.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:46342fed0fff72efcda77040b14728049200cbba1279e0bf1188f1f2078c1d70"}, - {file = "coverage-7.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9641e21670c68c7e57d2053ddf6c443e4f0a6e18e547e86af3fad0795414a628"}, - {file = "coverage-7.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aeb2c2688ed93b027eb0d26aa188ada34acb22dceea256d76390eea135083950"}, - {file = "coverage-7.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d12c923757de24e4e2110cf8832d83a886a4cf215c6e61ed506006872b43a6d1"}, - {file = "coverage-7.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0491275c3b9971cdbd28a4595c2cb5838f08036bca31765bad5e17edf900b2c7"}, - {file = "coverage-7.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8dfc5e195bbef80aabd81596ef52a1277ee7143fe419efc3c4d8ba2754671756"}, - {file = "coverage-7.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1a78b656a4d12b0490ca72651fe4d9f5e07e3c6461063a9b6265ee45eb2bdd35"}, - {file = "coverage-7.4.1-cp39-cp39-win32.whl", hash = "sha256:f90515974b39f4dea2f27c0959688621b46d96d5a626cf9c53dbc653a895c05c"}, - {file = "coverage-7.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:64e723ca82a84053dd7bfcc986bdb34af8d9da83c521c19d6b472bc6880e191a"}, - {file = "coverage-7.4.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:32a8d985462e37cfdab611a6f95b09d7c091d07668fdc26e47a725ee575fe166"}, - {file = "coverage-7.4.1.tar.gz", hash = "sha256:1ed4b95480952b1a26d863e546fa5094564aa0065e1e5f0d4d0041f293251d04"}, + {file = "coverage-7.4.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8580b827d4746d47294c0e0b92854c85a92c2227927433998f0d3320ae8a71b6"}, + {file = "coverage-7.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:718187eeb9849fc6cc23e0d9b092bc2348821c5e1a901c9f8975df0bc785bfd4"}, + {file = "coverage-7.4.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:767b35c3a246bcb55b8044fd3a43b8cd553dd1f9f2c1eeb87a302b1f8daa0524"}, + {file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae7f19afe0cce50039e2c782bff379c7e347cba335429678450b8fe81c4ef96d"}, + {file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba3a8aaed13770e970b3df46980cb068d1c24af1a1968b7818b69af8c4347efb"}, + {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ee866acc0861caebb4f2ab79f0b94dbfbdbfadc19f82e6e9c93930f74e11d7a0"}, + {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:506edb1dd49e13a2d4cac6a5173317b82a23c9d6e8df63efb4f0380de0fbccbc"}, + {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd6545d97c98a192c5ac995d21c894b581f1fd14cf389be90724d21808b657e2"}, + {file = "coverage-7.4.3-cp310-cp310-win32.whl", hash = "sha256:f6a09b360d67e589236a44f0c39218a8efba2593b6abdccc300a8862cffc2f94"}, + {file = "coverage-7.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:18d90523ce7553dd0b7e23cbb28865db23cddfd683a38fb224115f7826de78d0"}, + {file = "coverage-7.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cbbe5e739d45a52f3200a771c6d2c7acf89eb2524890a4a3aa1a7fa0695d2a47"}, + {file = "coverage-7.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:489763b2d037b164846ebac0cbd368b8a4ca56385c4090807ff9fad817de4113"}, + {file = "coverage-7.4.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:451f433ad901b3bb00184d83fd83d135fb682d780b38af7944c9faeecb1e0bfe"}, + {file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fcc66e222cf4c719fe7722a403888b1f5e1682d1679bd780e2b26c18bb648cdc"}, + {file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3ec74cfef2d985e145baae90d9b1b32f85e1741b04cd967aaf9cfa84c1334f3"}, + {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:abbbd8093c5229c72d4c2926afaee0e6e3140de69d5dcd918b2921f2f0c8baba"}, + {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:35eb581efdacf7b7422af677b92170da4ef34500467381e805944a3201df2079"}, + {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8249b1c7334be8f8c3abcaaa996e1e4927b0e5a23b65f5bf6cfe3180d8ca7840"}, + {file = "coverage-7.4.3-cp311-cp311-win32.whl", hash = "sha256:cf30900aa1ba595312ae41978b95e256e419d8a823af79ce670835409fc02ad3"}, + {file = "coverage-7.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:18c7320695c949de11a351742ee001849912fd57e62a706d83dfc1581897fa2e"}, + {file = "coverage-7.4.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b51bfc348925e92a9bd9b2e48dad13431b57011fd1038f08316e6bf1df107d10"}, + {file = "coverage-7.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d6cdecaedea1ea9e033d8adf6a0ab11107b49571bbb9737175444cea6eb72328"}, + {file = "coverage-7.4.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b2eccb883368f9e972e216c7b4c7c06cabda925b5f06dde0650281cb7666a30"}, + {file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c00cdc8fa4e50e1cc1f941a7f2e3e0f26cb2a1233c9696f26963ff58445bac7"}, + {file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9a4a8dd3dcf4cbd3165737358e4d7dfbd9d59902ad11e3b15eebb6393b0446e"}, + {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:062b0a75d9261e2f9c6d071753f7eef0fc9caf3a2c82d36d76667ba7b6470003"}, + {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ebe7c9e67a2d15fa97b77ea6571ce5e1e1f6b0db71d1d5e96f8d2bf134303c1d"}, + {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c0a120238dd71c68484f02562f6d446d736adcc6ca0993712289b102705a9a3a"}, + {file = "coverage-7.4.3-cp312-cp312-win32.whl", hash = "sha256:37389611ba54fd6d278fde86eb2c013c8e50232e38f5c68235d09d0a3f8aa352"}, + {file = "coverage-7.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:d25b937a5d9ffa857d41be042b4238dd61db888533b53bc76dc082cb5a15e914"}, + {file = "coverage-7.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:28ca2098939eabab044ad68850aac8f8db6bf0b29bc7f2887d05889b17346454"}, + {file = "coverage-7.4.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:280459f0a03cecbe8800786cdc23067a8fc64c0bd51dc614008d9c36e1659d7e"}, + {file = "coverage-7.4.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c0cdedd3500e0511eac1517bf560149764b7d8e65cb800d8bf1c63ebf39edd2"}, + {file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a9babb9466fe1da12417a4aed923e90124a534736de6201794a3aea9d98484e"}, + {file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dec9de46a33cf2dd87a5254af095a409ea3bf952d85ad339751e7de6d962cde6"}, + {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:16bae383a9cc5abab9bb05c10a3e5a52e0a788325dc9ba8499e821885928968c"}, + {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2c854ce44e1ee31bda4e318af1dbcfc929026d12c5ed030095ad98197eeeaed0"}, + {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ce8c50520f57ec57aa21a63ea4f325c7b657386b3f02ccaedeccf9ebe27686e1"}, + {file = "coverage-7.4.3-cp38-cp38-win32.whl", hash = "sha256:708a3369dcf055c00ddeeaa2b20f0dd1ce664eeabde6623e516c5228b753654f"}, + {file = "coverage-7.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:1bf25fbca0c8d121a3e92a2a0555c7e5bc981aee5c3fdaf4bb7809f410f696b9"}, + {file = "coverage-7.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b253094dbe1b431d3a4ac2f053b6d7ede2664ac559705a704f621742e034f1f"}, + {file = "coverage-7.4.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:77fbfc5720cceac9c200054b9fab50cb2a7d79660609200ab83f5db96162d20c"}, + {file = "coverage-7.4.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6679060424faa9c11808598504c3ab472de4531c571ab2befa32f4971835788e"}, + {file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4af154d617c875b52651dd8dd17a31270c495082f3d55f6128e7629658d63765"}, + {file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8640f1fde5e1b8e3439fe482cdc2b0bb6c329f4bb161927c28d2e8879c6029ee"}, + {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:69b9f6f66c0af29642e73a520b6fed25ff9fd69a25975ebe6acb297234eda501"}, + {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0842571634f39016a6c03e9d4aba502be652a6e4455fadb73cd3a3a49173e38f"}, + {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a78ed23b08e8ab524551f52953a8a05d61c3a760781762aac49f8de6eede8c45"}, + {file = "coverage-7.4.3-cp39-cp39-win32.whl", hash = "sha256:c0524de3ff096e15fcbfe8f056fdb4ea0bf497d584454f344d59fce069d3e6e9"}, + {file = "coverage-7.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:0209a6369ccce576b43bb227dc8322d8ef9e323d089c6f3f26a597b09cb4d2aa"}, + {file = "coverage-7.4.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:7cbde573904625509a3f37b6fecea974e363460b556a627c60dc2f47e2fffa51"}, + {file = "coverage-7.4.3.tar.gz", hash = "sha256:276f6077a5c61447a48d133ed13e759c09e62aff0dc84274a68dc18660104d52"}, ] [package.dependencies] @@ -595,6 +658,21 @@ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.1 [package.extras] toml = ["tomli"] +[[package]] +name = "cycler" +version = "0.12.1" +description = "Composable style cycles" +optional = true +python-versions = ">=3.8" +files = [ + {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, + {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, +] + +[package.extras] +docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] +tests = ["pytest", "pytest-cov", "pytest-xdist"] + [[package]] name = "debugpy" version = "1.8.1" @@ -793,6 +871,71 @@ files = [ {file = "flatbuffers-23.5.26.tar.gz", hash = "sha256:9ea1144cac05ce5d86e2859f431c6cd5e66cd9c78c558317c7955fb8d4c78d89"}, ] +[[package]] +name = "fonttools" +version = "4.49.0" +description = "Tools to manipulate font files" +optional = true +python-versions = ">=3.8" +files = [ + {file = "fonttools-4.49.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d970ecca0aac90d399e458f0b7a8a597e08f95de021f17785fb68e2dc0b99717"}, + {file = "fonttools-4.49.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac9a745b7609f489faa65e1dc842168c18530874a5f5b742ac3dd79e26bca8bc"}, + {file = "fonttools-4.49.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ba0e00620ca28d4ca11fc700806fd69144b463aa3275e1b36e56c7c09915559"}, + {file = "fonttools-4.49.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdee3ab220283057e7840d5fb768ad4c2ebe65bdba6f75d5d7bf47f4e0ed7d29"}, + {file = "fonttools-4.49.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ce7033cb61f2bb65d8849658d3786188afd80f53dad8366a7232654804529532"}, + {file = "fonttools-4.49.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:07bc5ea02bb7bc3aa40a1eb0481ce20e8d9b9642a9536cde0218290dd6085828"}, + {file = "fonttools-4.49.0-cp310-cp310-win32.whl", hash = "sha256:86eef6aab7fd7c6c8545f3ebd00fd1d6729ca1f63b0cb4d621bccb7d1d1c852b"}, + {file = "fonttools-4.49.0-cp310-cp310-win_amd64.whl", hash = "sha256:1fac1b7eebfce75ea663e860e7c5b4a8831b858c17acd68263bc156125201abf"}, + {file = "fonttools-4.49.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:edc0cce355984bb3c1d1e89d6a661934d39586bb32191ebff98c600f8957c63e"}, + {file = "fonttools-4.49.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:83a0d9336de2cba86d886507dd6e0153df333ac787377325a39a2797ec529814"}, + {file = "fonttools-4.49.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36c8865bdb5cfeec88f5028e7e592370a0657b676c6f1d84a2108e0564f90e22"}, + {file = "fonttools-4.49.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33037d9e56e2562c710c8954d0f20d25b8386b397250d65581e544edc9d6b942"}, + {file = "fonttools-4.49.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8fb022d799b96df3eaa27263e9eea306bd3d437cc9aa981820850281a02b6c9a"}, + {file = "fonttools-4.49.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33c584c0ef7dc54f5dd4f84082eabd8d09d1871a3d8ca2986b0c0c98165f8e86"}, + {file = "fonttools-4.49.0-cp311-cp311-win32.whl", hash = "sha256:cbe61b158deb09cffdd8540dc4a948d6e8f4d5b4f3bf5cd7db09bd6a61fee64e"}, + {file = "fonttools-4.49.0-cp311-cp311-win_amd64.whl", hash = "sha256:fc11e5114f3f978d0cea7e9853627935b30d451742eeb4239a81a677bdee6bf6"}, + {file = "fonttools-4.49.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d647a0e697e5daa98c87993726da8281c7233d9d4ffe410812a4896c7c57c075"}, + {file = "fonttools-4.49.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f3bbe672df03563d1f3a691ae531f2e31f84061724c319652039e5a70927167e"}, + {file = "fonttools-4.49.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bebd91041dda0d511b0d303180ed36e31f4f54b106b1259b69fade68413aa7ff"}, + {file = "fonttools-4.49.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4145f91531fd43c50f9eb893faa08399816bb0b13c425667c48475c9f3a2b9b5"}, + {file = "fonttools-4.49.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ea329dafb9670ffbdf4dbc3b0e5c264104abcd8441d56de77f06967f032943cb"}, + {file = "fonttools-4.49.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c076a9e548521ecc13d944b1d261ff3d7825048c338722a4bd126d22316087b7"}, + {file = "fonttools-4.49.0-cp312-cp312-win32.whl", hash = "sha256:b607ea1e96768d13be26d2b400d10d3ebd1456343eb5eaddd2f47d1c4bd00880"}, + {file = "fonttools-4.49.0-cp312-cp312-win_amd64.whl", hash = "sha256:a974c49a981e187381b9cc2c07c6b902d0079b88ff01aed34695ec5360767034"}, + {file = "fonttools-4.49.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b85ec0bdd7bdaa5c1946398cbb541e90a6dfc51df76dfa88e0aaa41b335940cb"}, + {file = "fonttools-4.49.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:af20acbe198a8a790618ee42db192eb128afcdcc4e96d99993aca0b60d1faeb4"}, + {file = "fonttools-4.49.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d418b1fee41a1d14931f7ab4b92dc0bc323b490e41d7a333eec82c9f1780c75"}, + {file = "fonttools-4.49.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b44a52b8e6244b6548851b03b2b377a9702b88ddc21dcaf56a15a0393d425cb9"}, + {file = "fonttools-4.49.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7c7125068e04a70739dad11857a4d47626f2b0bd54de39e8622e89701836eabd"}, + {file = "fonttools-4.49.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:29e89d0e1a7f18bc30f197cfadcbef5a13d99806447c7e245f5667579a808036"}, + {file = "fonttools-4.49.0-cp38-cp38-win32.whl", hash = "sha256:9d95fa0d22bf4f12d2fb7b07a46070cdfc19ef5a7b1c98bc172bfab5bf0d6844"}, + {file = "fonttools-4.49.0-cp38-cp38-win_amd64.whl", hash = "sha256:768947008b4dc552d02772e5ebd49e71430a466e2373008ce905f953afea755a"}, + {file = "fonttools-4.49.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:08877e355d3dde1c11973bb58d4acad1981e6d1140711230a4bfb40b2b937ccc"}, + {file = "fonttools-4.49.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fdb54b076f25d6b0f0298dc706acee5052de20c83530fa165b60d1f2e9cbe3cb"}, + {file = "fonttools-4.49.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0af65c720520710cc01c293f9c70bd69684365c6015cc3671db2b7d807fe51f2"}, + {file = "fonttools-4.49.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f255ce8ed7556658f6d23f6afd22a6d9bbc3edb9b96c96682124dc487e1bf42"}, + {file = "fonttools-4.49.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d00af0884c0e65f60dfaf9340e26658836b935052fdd0439952ae42e44fdd2be"}, + {file = "fonttools-4.49.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:263832fae27481d48dfafcc43174644b6706639661e242902ceb30553557e16c"}, + {file = "fonttools-4.49.0-cp39-cp39-win32.whl", hash = "sha256:0404faea044577a01bb82d47a8fa4bc7a54067fa7e324785dd65d200d6dd1133"}, + {file = "fonttools-4.49.0-cp39-cp39-win_amd64.whl", hash = "sha256:b050d362df50fc6e38ae3954d8c29bf2da52be384649ee8245fdb5186b620836"}, + {file = "fonttools-4.49.0-py3-none-any.whl", hash = "sha256:af281525e5dd7fa0b39fb1667b8d5ca0e2a9079967e14c4bfe90fd1cd13e0f18"}, + {file = "fonttools-4.49.0.tar.gz", hash = "sha256:ebf46e7f01b7af7861310417d7c49591a85d99146fc23a5ba82fdb28af156321"}, +] + +[package.extras] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] +graphite = ["lz4 (>=1.7.4.2)"] +interpolatable = ["munkres", "pycairo", "scipy"] +lxml = ["lxml (>=4.0)"] +pathops = ["skia-pathops (>=0.5.0)"] +plot = ["matplotlib"] +repacker = ["uharfbuzz (>=0.23.0)"] +symfont = ["sympy"] +type1 = ["xattr"] +ufo = ["fs (>=2.2.0,<3)"] +unicode = ["unicodedata2 (>=15.1.0)"] +woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] + [[package]] name = "frozenlist" version = "1.4.1" @@ -927,13 +1070,13 @@ files = [ [[package]] name = "httpcore" -version = "1.0.3" +version = "1.0.4" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpcore-1.0.3-py3-none-any.whl", hash = "sha256:9a6a501c3099307d9fd76ac244e08503427679b1e81ceb1d922485e2f2462ad2"}, - {file = "httpcore-1.0.3.tar.gz", hash = "sha256:5c0f9546ad17dac4d0772b0808856eb616eb8b48ce94f49ed819fd6982a8a544"}, + {file = "httpcore-1.0.4-py3-none-any.whl", hash = "sha256:ac418c1db41bade2ad53ae2f3834a3a0f5ae76b56cf5aa497d2d033384fc7d73"}, + {file = "httpcore-1.0.4.tar.gz", hash = "sha256:cb2839ccfcba0d2d3c1131d3c3e26dfc327326fbe7a5dc0dbfe9f6c9151bb022"}, ] [package.dependencies] @@ -944,7 +1087,7 @@ h11 = ">=0.13,<0.15" asyncio = ["anyio (>=4.0,<5.0)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<0.24.0)"] +trio = ["trio (>=0.22.0,<0.25.0)"] [[package]] name = "httpx" @@ -1047,6 +1190,24 @@ docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.link perf = ["ipython"] testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] +[[package]] +name = "importlib-resources" +version = "6.1.1" +description = "Read resources from Python packages" +optional = true +python-versions = ">=3.8" +files = [ + {file = "importlib_resources-6.1.1-py3-none-any.whl", hash = "sha256:e8bf90d8213b486f428c9c39714b920041cb02c184686a3dee24905aaa8105d6"}, + {file = "importlib_resources-6.1.1.tar.gz", hash = "sha256:3893a00122eafde6894c59914446a512f728a0c1a45f9bb9b63721b6bacf0b4a"}, +] + +[package.dependencies] +zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff", "zipp (>=3.17)"] + [[package]] name = "iniconfig" version = "2.0.0" @@ -1218,14 +1379,127 @@ traitlets = ">=5.3" docs = ["myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"] test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"] +[[package]] +name = "kiwisolver" +version = "1.4.5" +description = "A fast implementation of the Cassowary constraint solver" +optional = true +python-versions = ">=3.7" +files = [ + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af"}, + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3"}, + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b"}, + {file = "kiwisolver-1.4.5-cp310-cp310-win32.whl", hash = "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238"}, + {file = "kiwisolver-1.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f"}, + {file = "kiwisolver-1.4.5-cp311-cp311-win32.whl", hash = "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac"}, + {file = "kiwisolver-1.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a"}, + {file = "kiwisolver-1.4.5-cp312-cp312-win32.whl", hash = "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20"}, + {file = "kiwisolver-1.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-win32.whl", hash = "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-win_amd64.whl", hash = "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250"}, + {file = "kiwisolver-1.4.5-cp38-cp38-win32.whl", hash = "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e"}, + {file = "kiwisolver-1.4.5-cp38-cp38-win_amd64.whl", hash = "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77"}, + {file = "kiwisolver-1.4.5-cp39-cp39-win32.whl", hash = "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f"}, + {file = "kiwisolver-1.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee"}, + {file = "kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec"}, +] + [[package]] name = "llama-cpp-python" -version = "0.2.44" +version = "0.2.50" description = "Python bindings for the llama.cpp library" optional = true python-versions = ">=3.8" files = [ - {file = "llama_cpp_python-0.2.44.tar.gz", hash = "sha256:afe0e93548d4ba75f20bc754039907594738a6381c9f4602922bcc8a418b2039"}, + {file = "llama_cpp_python-0.2.50.tar.gz", hash = "sha256:28caf4e665dac62ad1d347061b7a96669af7fb9e7f1e4e8c17e736504e321a51"}, ] [package.dependencies] @@ -1309,6 +1583,55 @@ files = [ {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] +[[package]] +name = "matplotlib" +version = "3.8.3" +description = "Python plotting package" +optional = true +python-versions = ">=3.9" +files = [ + {file = "matplotlib-3.8.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cf60138ccc8004f117ab2a2bad513cc4d122e55864b4fe7adf4db20ca68a078f"}, + {file = "matplotlib-3.8.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5f557156f7116be3340cdeef7f128fa99b0d5d287d5f41a16e169819dcf22357"}, + {file = "matplotlib-3.8.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f386cf162b059809ecfac3bcc491a9ea17da69fa35c8ded8ad154cd4b933d5ec"}, + {file = "matplotlib-3.8.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3c5f96f57b0369c288bf6f9b5274ba45787f7e0589a34d24bdbaf6d3344632f"}, + {file = "matplotlib-3.8.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:83e0f72e2c116ca7e571c57aa29b0fe697d4c6425c4e87c6e994159e0c008635"}, + {file = "matplotlib-3.8.3-cp310-cp310-win_amd64.whl", hash = "sha256:1c5c8290074ba31a41db1dc332dc2b62def469ff33766cbe325d32a3ee291aea"}, + {file = "matplotlib-3.8.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5184e07c7e1d6d1481862ee361905b7059f7fe065fc837f7c3dc11eeb3f2f900"}, + {file = "matplotlib-3.8.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d7e7e0993d0758933b1a241a432b42c2db22dfa37d4108342ab4afb9557cbe3e"}, + {file = "matplotlib-3.8.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:04b36ad07eac9740fc76c2aa16edf94e50b297d6eb4c081e3add863de4bb19a7"}, + {file = "matplotlib-3.8.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c42dae72a62f14982f1474f7e5c9959fc4bc70c9de11cc5244c6e766200ba65"}, + {file = "matplotlib-3.8.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bf5932eee0d428192c40b7eac1399d608f5d995f975cdb9d1e6b48539a5ad8d0"}, + {file = "matplotlib-3.8.3-cp311-cp311-win_amd64.whl", hash = "sha256:40321634e3a05ed02abf7c7b47a50be50b53ef3eaa3a573847431a545585b407"}, + {file = "matplotlib-3.8.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:09074f8057917d17ab52c242fdf4916f30e99959c1908958b1fc6032e2d0f6d4"}, + {file = "matplotlib-3.8.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5745f6d0fb5acfabbb2790318db03809a253096e98c91b9a31969df28ee604aa"}, + {file = "matplotlib-3.8.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97653d869a71721b639714b42d87cda4cfee0ee74b47c569e4874c7590c55c5"}, + {file = "matplotlib-3.8.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:242489efdb75b690c9c2e70bb5c6550727058c8a614e4c7716f363c27e10bba1"}, + {file = "matplotlib-3.8.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:83c0653c64b73926730bd9ea14aa0f50f202ba187c307a881673bad4985967b7"}, + {file = "matplotlib-3.8.3-cp312-cp312-win_amd64.whl", hash = "sha256:ef6c1025a570354297d6c15f7d0f296d95f88bd3850066b7f1e7b4f2f4c13a39"}, + {file = "matplotlib-3.8.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c4af3f7317f8a1009bbb2d0bf23dfaba859eb7dd4ccbd604eba146dccaaaf0a4"}, + {file = "matplotlib-3.8.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4c6e00a65d017d26009bac6808f637b75ceade3e1ff91a138576f6b3065eeeba"}, + {file = "matplotlib-3.8.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7b49ab49a3bea17802df6872f8d44f664ba8f9be0632a60c99b20b6db2165b7"}, + {file = "matplotlib-3.8.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6728dde0a3997396b053602dbd907a9bd64ec7d5cf99e728b404083698d3ca01"}, + {file = "matplotlib-3.8.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:813925d08fb86aba139f2d31864928d67511f64e5945ca909ad5bc09a96189bb"}, + {file = "matplotlib-3.8.3-cp39-cp39-win_amd64.whl", hash = "sha256:cd3a0c2be76f4e7be03d34a14d49ded6acf22ef61f88da600a18a5cd8b3c5f3c"}, + {file = "matplotlib-3.8.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fa93695d5c08544f4a0dfd0965f378e7afc410d8672816aff1e81be1f45dbf2e"}, + {file = "matplotlib-3.8.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9764df0e8778f06414b9d281a75235c1e85071f64bb5d71564b97c1306a2afc"}, + {file = "matplotlib-3.8.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5e431a09e6fab4012b01fc155db0ce6dccacdbabe8198197f523a4ef4805eb26"}, + {file = "matplotlib-3.8.3.tar.gz", hash = "sha256:7b416239e9ae38be54b028abbf9048aff5054a9aba5416bef0bd17f9162ce161"}, +] + +[package.dependencies] +contourpy = ">=1.0.1" +cycler = ">=0.10" +fonttools = ">=4.22.0" +importlib-resources = {version = ">=3.2.0", markers = "python_version < \"3.10\""} +kiwisolver = ">=1.3.1" +numpy = ">=1.21,<2" +packaging = ">=20.0" +pillow = ">=8" +pyparsing = ">=2.3.1" +python-dateutil = ">=2.7" + [[package]] name = "matplotlib-inline" version = "0.1.6" @@ -1840,36 +2163,36 @@ reference = ["Pillow", "google-re2"] [[package]] name = "onnxruntime" -version = "1.17.0" +version = "1.17.1" description = "ONNX Runtime is a runtime accelerator for Machine Learning models" optional = true python-versions = "*" files = [ - {file = "onnxruntime-1.17.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:d2b22a25a94109cc983443116da8d9805ced0256eb215c5e6bc6dcbabefeab96"}, - {file = "onnxruntime-1.17.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4c87d83c6f58d1af2675fc99e3dc810f2dbdb844bcefd0c1b7573632661f6fc"}, - {file = "onnxruntime-1.17.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dba55723bf9b835e358f48c98a814b41692c393eb11f51e02ece0625c756b797"}, - {file = "onnxruntime-1.17.0-cp310-cp310-win32.whl", hash = "sha256:ee48422349cc500273beea7607e33c2237909f58468ae1d6cccfc4aecd158565"}, - {file = "onnxruntime-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:f34cc46553359293854e38bdae2ab1be59543aad78a6317e7746d30e311110c3"}, - {file = "onnxruntime-1.17.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:16d26badd092c8c257fa57c458bb600d96dc15282c647ccad0ed7b2732e6c03b"}, - {file = "onnxruntime-1.17.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6f1273bebcdb47ed932d076c85eb9488bc4768fcea16d5f2747ca692fad4f9d3"}, - {file = "onnxruntime-1.17.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cb60fd3c2c1acd684752eb9680e89ae223e9801a9b0e0dc7b28adabe45a2e380"}, - {file = "onnxruntime-1.17.0-cp311-cp311-win32.whl", hash = "sha256:4b038324586bc905299e435f7c00007e6242389c856b82fe9357fdc3b1ef2bdc"}, - {file = "onnxruntime-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:93d39b3fa1ee01f034f098e1c7769a811a21365b4883f05f96c14a2b60c6028b"}, - {file = "onnxruntime-1.17.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:90c0890e36f880281c6c698d9bc3de2afbeee2f76512725ec043665c25c67d21"}, - {file = "onnxruntime-1.17.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7466724e809a40e986b1637cba156ad9fc0d1952468bc00f79ef340bc0199552"}, - {file = "onnxruntime-1.17.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d47bee7557a8b99c8681b6882657a515a4199778d6d5e24e924d2aafcef55b0a"}, - {file = "onnxruntime-1.17.0-cp312-cp312-win32.whl", hash = "sha256:bb1bf1ee575c665b8bbc3813ab906e091a645a24ccc210be7932154b8260eca1"}, - {file = "onnxruntime-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:ac2f286da3494b29b4186ca193c7d4e6a2c1f770c4184c7192c5da142c3dec28"}, - {file = "onnxruntime-1.17.0-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1ec485643b93e0a3896c655eb2426decd63e18a278bb7ccebc133b340723624f"}, - {file = "onnxruntime-1.17.0-cp38-cp38-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:83c35809cda898c5a11911c69ceac8a2ac3925911854c526f73bad884582f911"}, - {file = "onnxruntime-1.17.0-cp38-cp38-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fa464aa4d81df818375239e481887b656e261377d5b6b9a4692466f5f3261edc"}, - {file = "onnxruntime-1.17.0-cp38-cp38-win32.whl", hash = "sha256:b7b337cd0586f7836601623cbd30a443df9528ef23965860d11c753ceeb009f2"}, - {file = "onnxruntime-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:fbb9faaf51d01aa2c147ef52524d9326744c852116d8005b9041809a71838878"}, - {file = "onnxruntime-1.17.0-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:5a06ab84eaa350bf64b1d747b33ccf10da64221ed1f38f7287f15eccbec81603"}, - {file = "onnxruntime-1.17.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d3d11db2c8242766212a68d0b139745157da7ce53bd96ba349a5c65e5a02357"}, - {file = "onnxruntime-1.17.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5632077c3ab8b0cd4f74b0af9c4e924be012b1a7bcd7daa845763c6c6bf14b7d"}, - {file = "onnxruntime-1.17.0-cp39-cp39-win32.whl", hash = "sha256:61a12732cba869b3ad2d4e29ab6cb62c7a96f61b8c213f7fcb961ba412b70b37"}, - {file = "onnxruntime-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:461fa0fc7d9c392c352b6cccdedf44d818430f3d6eacd924bb804fdea2dcfd02"}, + {file = "onnxruntime-1.17.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:d43ac17ac4fa3c9096ad3c0e5255bb41fd134560212dc124e7f52c3159af5d21"}, + {file = "onnxruntime-1.17.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:55b5e92a4c76a23981c998078b9bf6145e4fb0b016321a8274b1607bd3c6bd35"}, + {file = "onnxruntime-1.17.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ebbcd2bc3a066cf54e6f18c75708eb4d309ef42be54606d22e5bdd78afc5b0d7"}, + {file = "onnxruntime-1.17.1-cp310-cp310-win32.whl", hash = "sha256:5e3716b5eec9092e29a8d17aab55e737480487deabfca7eac3cd3ed952b6ada9"}, + {file = "onnxruntime-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:fbb98cced6782ae1bb799cc74ddcbbeeae8819f3ad1d942a74d88e72b6511337"}, + {file = "onnxruntime-1.17.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:36fd6f87a1ecad87e9c652e42407a50fb305374f9a31d71293eb231caae18784"}, + {file = "onnxruntime-1.17.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99a8bddeb538edabc524d468edb60ad4722cff8a49d66f4e280c39eace70500b"}, + {file = "onnxruntime-1.17.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd7fddb4311deb5a7d3390cd8e9b3912d4d963efbe4dfe075edbaf18d01c024e"}, + {file = "onnxruntime-1.17.1-cp311-cp311-win32.whl", hash = "sha256:606a7cbfb6680202b0e4f1890881041ffc3ac6e41760a25763bd9fe146f0b335"}, + {file = "onnxruntime-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:53e4e06c0a541696ebdf96085fd9390304b7b04b748a19e02cf3b35c869a1e76"}, + {file = "onnxruntime-1.17.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:40f08e378e0f85929712a2b2c9b9a9cc400a90c8a8ca741d1d92c00abec60843"}, + {file = "onnxruntime-1.17.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac79da6d3e1bb4590f1dad4bb3c2979d7228555f92bb39820889af8b8e6bd472"}, + {file = "onnxruntime-1.17.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ae9ba47dc099004e3781f2d0814ad710a13c868c739ab086fc697524061695ea"}, + {file = "onnxruntime-1.17.1-cp312-cp312-win32.whl", hash = "sha256:2dff1a24354220ac30e4a4ce2fb1df38cb1ea59f7dac2c116238d63fe7f4c5ff"}, + {file = "onnxruntime-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:6226a5201ab8cafb15e12e72ff2a4fc8f50654e8fa5737c6f0bd57c5ff66827e"}, + {file = "onnxruntime-1.17.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:cd0c07c0d1dfb8629e820b05fda5739e4835b3b82faf43753d2998edf2cf00aa"}, + {file = "onnxruntime-1.17.1-cp38-cp38-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:617ebdf49184efa1ba6e4467e602fbfa029ed52c92f13ce3c9f417d303006381"}, + {file = "onnxruntime-1.17.1-cp38-cp38-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9dae9071e3facdf2920769dceee03b71c684b6439021defa45b830d05e148924"}, + {file = "onnxruntime-1.17.1-cp38-cp38-win32.whl", hash = "sha256:835d38fa1064841679433b1aa8138b5e1218ddf0cfa7a3ae0d056d8fd9cec713"}, + {file = "onnxruntime-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:96621e0c555c2453bf607606d08af3f70fbf6f315230c28ddea91754e17ad4e6"}, + {file = "onnxruntime-1.17.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:7a9539935fb2d78ebf2cf2693cad02d9930b0fb23cdd5cf37a7df813e977674d"}, + {file = "onnxruntime-1.17.1-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:45c6a384e9d9a29c78afff62032a46a993c477b280247a7e335df09372aedbe9"}, + {file = "onnxruntime-1.17.1-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4e19f966450f16863a1d6182a685ca33ae04d7772a76132303852d05b95411ea"}, + {file = "onnxruntime-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e2ae712d64a42aac29ed7a40a426cb1e624a08cfe9273dcfe681614aa65b07dc"}, + {file = "onnxruntime-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:f7e9f7fb049825cdddf4a923cfc7c649d84d63c0134315f8e0aa9e0c3004672c"}, ] [package.dependencies] @@ -1905,61 +2228,61 @@ datalib = ["numpy (>=1)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"] [[package]] name = "orjson" -version = "3.9.14" +version = "3.9.15" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = false python-versions = ">=3.8" files = [ - {file = "orjson-3.9.14-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:793f6c9448ab6eb7d4974b4dde3f230345c08ca6c7995330fbceeb43a5c8aa5e"}, - {file = "orjson-3.9.14-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6bc7928d161840096adc956703494b5c0193ede887346f028216cac0af87500"}, - {file = "orjson-3.9.14-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:58b36f54da759602d8e2f7dad958752d453dfe2c7122767bc7f765e17dc59959"}, - {file = "orjson-3.9.14-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:abcda41ecdc950399c05eff761c3de91485d9a70d8227cb599ad3a66afe93bcc"}, - {file = "orjson-3.9.14-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df76ecd17b1b3627bddfd689faaf206380a1a38cc9f6c4075bd884eaedcf46c2"}, - {file = "orjson-3.9.14-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d450a8e0656efb5d0fcb062157b918ab02dcca73278975b4ee9ea49e2fcf5bd5"}, - {file = "orjson-3.9.14-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:95c03137b0cf66517c8baa65770507a756d3a89489d8ecf864ea92348e1beabe"}, - {file = "orjson-3.9.14-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20837e10835c98973673406d6798e10f821e7744520633811a5a3d809762d8cc"}, - {file = "orjson-3.9.14-cp310-none-win32.whl", hash = "sha256:1f7b6f3ef10ae8e3558abb729873d033dbb5843507c66b1c0767e32502ba96bb"}, - {file = "orjson-3.9.14-cp310-none-win_amd64.whl", hash = "sha256:ea890e6dc1711aeec0a33b8520e395c2f3d59ead5b4351a788e06bf95fc7ba81"}, - {file = "orjson-3.9.14-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c19009ff37f033c70acd04b636380379499dac2cba27ae7dfc24f304deabbc81"}, - {file = "orjson-3.9.14-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19cdea0664aec0b7f385be84986d4defd3334e9c3c799407686ee1c26f7b8251"}, - {file = "orjson-3.9.14-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:135d518f73787ce323b1a5e21fb854fe22258d7a8ae562b81a49d6c7f826f2a3"}, - {file = "orjson-3.9.14-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d2cf1d0557c61c75e18cf7d69fb689b77896e95553e212c0cc64cf2087944b84"}, - {file = "orjson-3.9.14-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7c11667421df2d8b18b021223505dcc3ee51be518d54e4dc49161ac88ac2b87"}, - {file = "orjson-3.9.14-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eefc41ba42e75ed88bc396d8fe997beb20477f3e7efa000cd7a47eda452fbb2"}, - {file = "orjson-3.9.14-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:917311d6a64d1c327c0dfda1e41f3966a7fb72b11ca7aa2e7a68fcccc7db35d9"}, - {file = "orjson-3.9.14-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4dc1c132259b38d12c6587d190cd09cd76e3b5273ce71fe1372437b4cbc65f6f"}, - {file = "orjson-3.9.14-cp311-none-win32.whl", hash = "sha256:6f39a10408478f4c05736a74da63727a1ae0e83e3533d07b19443400fe8591ca"}, - {file = "orjson-3.9.14-cp311-none-win_amd64.whl", hash = "sha256:26280a7fcb62d8257f634c16acebc3bec626454f9ab13558bbf7883b9140760e"}, - {file = "orjson-3.9.14-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:08e722a8d06b13b67a51f247a24938d1a94b4b3862e40e0eef3b2e98c99cd04c"}, - {file = "orjson-3.9.14-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2591faa0c031cf3f57e5bce1461cfbd6160f3f66b5a72609a130924917cb07d"}, - {file = "orjson-3.9.14-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e2450d87dd7b4f277f4c5598faa8b49a0c197b91186c47a2c0b88e15531e4e3e"}, - {file = "orjson-3.9.14-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:90903d2908158a2c9077a06f11e27545de610af690fb178fd3ba6b32492d4d1c"}, - {file = "orjson-3.9.14-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ce6f095eef0026eae76fc212f20f786011ecf482fc7df2f4c272a8ae6dd7b1ef"}, - {file = "orjson-3.9.14-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:751250a31fef2bac05a2da2449aae7142075ea26139271f169af60456d8ad27a"}, - {file = "orjson-3.9.14-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9a1af21160a38ee8be3f4fcf24ee4b99e6184cadc7f915d599f073f478a94d2c"}, - {file = "orjson-3.9.14-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:449bf090b2aa4e019371d7511a6ea8a5a248139205c27d1834bb4b1e3c44d936"}, - {file = "orjson-3.9.14-cp312-none-win_amd64.whl", hash = "sha256:a603161318ff699784943e71f53899983b7dee571b4dd07c336437c9c5a272b0"}, - {file = "orjson-3.9.14-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:814f288c011efdf8f115c5ebcc1ab94b11da64b207722917e0ceb42f52ef30a3"}, - {file = "orjson-3.9.14-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a88cafb100af68af3b9b29b5ccd09fdf7a48c63327916c8c923a94c336d38dd3"}, - {file = "orjson-3.9.14-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ba3518b999f88882ade6686f1b71e207b52e23546e180499be5bbb63a2f9c6e6"}, - {file = "orjson-3.9.14-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:978f416bbff9da8d2091e3cf011c92da68b13f2c453dcc2e8109099b2a19d234"}, - {file = "orjson-3.9.14-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75fc593cf836f631153d0e21beaeb8d26e144445c73645889335c2247fcd71a0"}, - {file = "orjson-3.9.14-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23d1528db3c7554f9d6eeb09df23cb80dd5177ec56eeb55cc5318826928de506"}, - {file = "orjson-3.9.14-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:7183cc68ee2113b19b0b8714221e5e3b07b3ba10ca2bb108d78fd49cefaae101"}, - {file = "orjson-3.9.14-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:df3266d54246cb56b8bb17fa908660d2a0f2e3f63fbc32451ffc1b1505051d07"}, - {file = "orjson-3.9.14-cp38-none-win32.whl", hash = "sha256:7913079b029e1b3501854c9a78ad938ed40d61fe09bebab3c93e60ff1301b189"}, - {file = "orjson-3.9.14-cp38-none-win_amd64.whl", hash = "sha256:29512eb925b620e5da2fd7585814485c67cc6ba4fe739a0a700c50467a8a8065"}, - {file = "orjson-3.9.14-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5bf597530544db27a8d76aced49cfc817ee9503e0a4ebf0109cd70331e7bbe0c"}, - {file = "orjson-3.9.14-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac650d49366fa41fe702e054cb560171a8634e2865537e91f09a8d05ea5b1d37"}, - {file = "orjson-3.9.14-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:236230433a9a4968ab895140514c308fdf9f607cb8bee178a04372b771123860"}, - {file = "orjson-3.9.14-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3014ccbda9be0b1b5f8ea895121df7e6524496b3908f4397ff02e923bcd8f6dd"}, - {file = "orjson-3.9.14-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ac0c7eae7ad3a223bde690565442f8a3d620056bd01196f191af8be58a5248e1"}, - {file = "orjson-3.9.14-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fca33fdd0b38839b01912c57546d4f412ba7bfa0faf9bf7453432219aec2df07"}, - {file = "orjson-3.9.14-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f75823cc1674a840a151e999a7dfa0d86c911150dd6f951d0736ee9d383bf415"}, - {file = "orjson-3.9.14-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6f52ac2eb49e99e7373f62e2a68428c6946cda52ce89aa8fe9f890c7278e2d3a"}, - {file = "orjson-3.9.14-cp39-none-win32.whl", hash = "sha256:0572f174f50b673b7df78680fb52cd0087a8585a6d06d295a5f790568e1064c6"}, - {file = "orjson-3.9.14-cp39-none-win_amd64.whl", hash = "sha256:ab90c02cb264250b8a58cedcc72ed78a4a257d956c8d3c8bebe9751b818dfad8"}, - {file = "orjson-3.9.14.tar.gz", hash = "sha256:06fb40f8e49088ecaa02f1162581d39e2cf3fd9dbbfe411eb2284147c99bad79"}, + {file = "orjson-3.9.15-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d61f7ce4727a9fa7680cd6f3986b0e2c732639f46a5e0156e550e35258aa313a"}, + {file = "orjson-3.9.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4feeb41882e8aa17634b589533baafdceb387e01e117b1ec65534ec724023d04"}, + {file = "orjson-3.9.15-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fbbeb3c9b2edb5fd044b2a070f127a0ac456ffd079cb82746fc84af01ef021a4"}, + {file = "orjson-3.9.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b66bcc5670e8a6b78f0313bcb74774c8291f6f8aeef10fe70e910b8040f3ab75"}, + {file = "orjson-3.9.15-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2973474811db7b35c30248d1129c64fd2bdf40d57d84beed2a9a379a6f57d0ab"}, + {file = "orjson-3.9.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fe41b6f72f52d3da4db524c8653e46243c8c92df826ab5ffaece2dba9cccd58"}, + {file = "orjson-3.9.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4228aace81781cc9d05a3ec3a6d2673a1ad0d8725b4e915f1089803e9efd2b99"}, + {file = "orjson-3.9.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6f7b65bfaf69493c73423ce9db66cfe9138b2f9ef62897486417a8fcb0a92bfe"}, + {file = "orjson-3.9.15-cp310-none-win32.whl", hash = "sha256:2d99e3c4c13a7b0fb3792cc04c2829c9db07838fb6973e578b85c1745e7d0ce7"}, + {file = "orjson-3.9.15-cp310-none-win_amd64.whl", hash = "sha256:b725da33e6e58e4a5d27958568484aa766e825e93aa20c26c91168be58e08cbb"}, + {file = "orjson-3.9.15-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c8e8fe01e435005d4421f183038fc70ca85d2c1e490f51fb972db92af6e047c2"}, + {file = "orjson-3.9.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87f1097acb569dde17f246faa268759a71a2cb8c96dd392cd25c668b104cad2f"}, + {file = "orjson-3.9.15-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff0f9913d82e1d1fadbd976424c316fbc4d9c525c81d047bbdd16bd27dd98cfc"}, + {file = "orjson-3.9.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8055ec598605b0077e29652ccfe9372247474375e0e3f5775c91d9434e12d6b1"}, + {file = "orjson-3.9.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d6768a327ea1ba44c9114dba5fdda4a214bdb70129065cd0807eb5f010bfcbb5"}, + {file = "orjson-3.9.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12365576039b1a5a47df01aadb353b68223da413e2e7f98c02403061aad34bde"}, + {file = "orjson-3.9.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:71c6b009d431b3839d7c14c3af86788b3cfac41e969e3e1c22f8a6ea13139404"}, + {file = "orjson-3.9.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e18668f1bd39e69b7fed19fa7cd1cd110a121ec25439328b5c89934e6d30d357"}, + {file = "orjson-3.9.15-cp311-none-win32.whl", hash = "sha256:62482873e0289cf7313461009bf62ac8b2e54bc6f00c6fabcde785709231a5d7"}, + {file = "orjson-3.9.15-cp311-none-win_amd64.whl", hash = "sha256:b3d336ed75d17c7b1af233a6561cf421dee41d9204aa3cfcc6c9c65cd5bb69a8"}, + {file = "orjson-3.9.15-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:82425dd5c7bd3adfe4e94c78e27e2fa02971750c2b7ffba648b0f5d5cc016a73"}, + {file = "orjson-3.9.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c51378d4a8255b2e7c1e5cc430644f0939539deddfa77f6fac7b56a9784160a"}, + {file = "orjson-3.9.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6ae4e06be04dc00618247c4ae3f7c3e561d5bc19ab6941427f6d3722a0875ef7"}, + {file = "orjson-3.9.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bcef128f970bb63ecf9a65f7beafd9b55e3aaf0efc271a4154050fc15cdb386e"}, + {file = "orjson-3.9.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b72758f3ffc36ca566ba98a8e7f4f373b6c17c646ff8ad9b21ad10c29186f00d"}, + {file = "orjson-3.9.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c57bc7b946cf2efa67ac55766e41764b66d40cbd9489041e637c1304400494"}, + {file = "orjson-3.9.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:946c3a1ef25338e78107fba746f299f926db408d34553b4754e90a7de1d44068"}, + {file = "orjson-3.9.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2f256d03957075fcb5923410058982aea85455d035607486ccb847f095442bda"}, + {file = "orjson-3.9.15-cp312-none-win_amd64.whl", hash = "sha256:5bb399e1b49db120653a31463b4a7b27cf2fbfe60469546baf681d1b39f4edf2"}, + {file = "orjson-3.9.15-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:b17f0f14a9c0ba55ff6279a922d1932e24b13fc218a3e968ecdbf791b3682b25"}, + {file = "orjson-3.9.15-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f6cbd8e6e446fb7e4ed5bac4661a29e43f38aeecbf60c4b900b825a353276a1"}, + {file = "orjson-3.9.15-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:76bc6356d07c1d9f4b782813094d0caf1703b729d876ab6a676f3aaa9a47e37c"}, + {file = "orjson-3.9.15-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fdfa97090e2d6f73dced247a2f2d8004ac6449df6568f30e7fa1a045767c69a6"}, + {file = "orjson-3.9.15-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7413070a3e927e4207d00bd65f42d1b780fb0d32d7b1d951f6dc6ade318e1b5a"}, + {file = "orjson-3.9.15-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9cf1596680ac1f01839dba32d496136bdd5d8ffb858c280fa82bbfeb173bdd40"}, + {file = "orjson-3.9.15-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:809d653c155e2cc4fd39ad69c08fdff7f4016c355ae4b88905219d3579e31eb7"}, + {file = "orjson-3.9.15-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:920fa5a0c5175ab14b9c78f6f820b75804fb4984423ee4c4f1e6d748f8b22bc1"}, + {file = "orjson-3.9.15-cp38-none-win32.whl", hash = "sha256:2b5c0f532905e60cf22a511120e3719b85d9c25d0e1c2a8abb20c4dede3b05a5"}, + {file = "orjson-3.9.15-cp38-none-win_amd64.whl", hash = "sha256:67384f588f7f8daf040114337d34a5188346e3fae6c38b6a19a2fe8c663a2f9b"}, + {file = "orjson-3.9.15-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:6fc2fe4647927070df3d93f561d7e588a38865ea0040027662e3e541d592811e"}, + {file = "orjson-3.9.15-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34cbcd216e7af5270f2ffa63a963346845eb71e174ea530867b7443892d77180"}, + {file = "orjson-3.9.15-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f541587f5c558abd93cb0de491ce99a9ef8d1ae29dd6ab4dbb5a13281ae04cbd"}, + {file = "orjson-3.9.15-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92255879280ef9c3c0bcb327c5a1b8ed694c290d61a6a532458264f887f052cb"}, + {file = "orjson-3.9.15-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:05a1f57fb601c426635fcae9ddbe90dfc1ed42245eb4c75e4960440cac667262"}, + {file = "orjson-3.9.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ede0bde16cc6e9b96633df1631fbcd66491d1063667f260a4f2386a098393790"}, + {file = "orjson-3.9.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e88b97ef13910e5f87bcbc4dd7979a7de9ba8702b54d3204ac587e83639c0c2b"}, + {file = "orjson-3.9.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:57d5d8cf9c27f7ef6bc56a5925c7fbc76b61288ab674eb352c26ac780caa5b10"}, + {file = "orjson-3.9.15-cp39-none-win32.whl", hash = "sha256:001f4eb0ecd8e9ebd295722d0cbedf0748680fb9998d3993abaed2f40587257a"}, + {file = "orjson-3.9.15-cp39-none-win_amd64.whl", hash = "sha256:ea0b183a5fe6b2b45f3b854b0d19c4e932d6f5934ae1f723b07cf9560edd4ec7"}, + {file = "orjson-3.9.15.tar.gz", hash = "sha256:95cae920959d772f30ab36d3b25f83bb0f3be671e986c72ce22f8fa700dae061"}, ] [[package]] @@ -2100,23 +2423,26 @@ xmp = ["defusedxml"] [[package]] name = "pinecone-client" -version = "3.0.3" +version = "3.1.0" description = "Pinecone client and SDK" optional = true -python-versions = ">=3.8,<3.13" +python-versions = ">=3.8,<4.0" files = [ - {file = "pinecone_client-3.0.3-py3-none-any.whl", hash = "sha256:940c942aeb259145e1cd6d3f214ad977dbb4dc2e626b3528fb5015c64c3e6190"}, - {file = "pinecone_client-3.0.3.tar.gz", hash = "sha256:2ad3ef7627edc4d9ee248d9781861c4341d6d27a15bc05f6bef53d958837d374"}, + {file = "pinecone_client-3.1.0-py3-none-any.whl", hash = "sha256:66dfe9859ed5b3412c3b59c68c9706c0f522cafd1a15c5d05e28d5664c2c48a4"}, + {file = "pinecone_client-3.1.0.tar.gz", hash = "sha256:45b8206013f91a982b994f1fbaa39e7e8c99d30ef3778a9f319c43b8c992fc42"}, ] [package.dependencies] certifi = ">=2019.11.17" tqdm = ">=4.64.1" typing-extensions = ">=3.7.4" -urllib3 = ">=1.26.0" +urllib3 = [ + {version = ">=1.26.0", markers = "python_version >= \"3.8\" and python_version < \"3.12\""}, + {version = ">=1.26.5", markers = "python_version >= \"3.12\" and python_version < \"4.0\""}, +] [package.extras] -grpc = ["googleapis-common-protos (>=1.53.0)", "grpc-gateway-protoc-gen-openapiv2 (==0.1.0)", "grpcio (>=1.44.0)", "lz4 (>=3.1.3)", "protobuf (>=3.20.0,<3.21.0)"] +grpc = ["googleapis-common-protos (>=1.53.0)", "grpc-gateway-protoc-gen-openapiv2 (==0.1.0)", "grpcio (>=1.44.0)", "grpcio (>=1.59.0)", "lz4 (>=3.1.3)", "protobuf (>=3.20.0,<3.21.0)"] [[package]] name = "pinecone-text" @@ -2276,18 +2602,18 @@ files = [ [[package]] name = "pydantic" -version = "2.6.1" +version = "2.6.2" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.6.1-py3-none-any.whl", hash = "sha256:0b6a909df3192245cb736509a92ff69e4fef76116feffec68e93a567347bae6f"}, - {file = "pydantic-2.6.1.tar.gz", hash = "sha256:4fd5c182a2488dc63e6d32737ff19937888001e2a6d86e94b3f233104a5d1fa9"}, + {file = "pydantic-2.6.2-py3-none-any.whl", hash = "sha256:37a5432e54b12fecaa1049c5195f3d860a10e01bdfd24f1840ef14bd0d3aeab3"}, + {file = "pydantic-2.6.2.tar.gz", hash = "sha256:a09be1c3d28f3abe37f8a78af58284b236a92ce520105ddc91a6d29ea1176ba7"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.16.2" +pydantic-core = "2.16.3" typing-extensions = ">=4.6.1" [package.extras] @@ -2295,90 +2621,90 @@ email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.16.2" +version = "2.16.3" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.16.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3fab4e75b8c525a4776e7630b9ee48aea50107fea6ca9f593c98da3f4d11bf7c"}, - {file = "pydantic_core-2.16.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8bde5b48c65b8e807409e6f20baee5d2cd880e0fad00b1a811ebc43e39a00ab2"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2924b89b16420712e9bb8192396026a8fbd6d8726224f918353ac19c4c043d2a"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:16aa02e7a0f539098e215fc193c8926c897175d64c7926d00a36188917717a05"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:936a787f83db1f2115ee829dd615c4f684ee48ac4de5779ab4300994d8af325b"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:459d6be6134ce3b38e0ef76f8a672924460c455d45f1ad8fdade36796df1ddc8"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9ee4febb249c591d07b2d4dd36ebcad0ccd128962aaa1801508320896575ef"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40a0bd0bed96dae5712dab2aba7d334a6c67cbcac2ddfca7dbcc4a8176445990"}, - {file = "pydantic_core-2.16.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:870dbfa94de9b8866b37b867a2cb37a60c401d9deb4a9ea392abf11a1f98037b"}, - {file = "pydantic_core-2.16.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:308974fdf98046db28440eb3377abba274808bf66262e042c412eb2adf852731"}, - {file = "pydantic_core-2.16.2-cp310-none-win32.whl", hash = "sha256:a477932664d9611d7a0816cc3c0eb1f8856f8a42435488280dfbf4395e141485"}, - {file = "pydantic_core-2.16.2-cp310-none-win_amd64.whl", hash = "sha256:8f9142a6ed83d90c94a3efd7af8873bf7cefed2d3d44387bf848888482e2d25f"}, - {file = "pydantic_core-2.16.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:406fac1d09edc613020ce9cf3f2ccf1a1b2f57ab00552b4c18e3d5276c67eb11"}, - {file = "pydantic_core-2.16.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce232a6170dd6532096cadbf6185271e4e8c70fc9217ebe105923ac105da9978"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a90fec23b4b05a09ad988e7a4f4e081711a90eb2a55b9c984d8b74597599180f"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8aafeedb6597a163a9c9727d8a8bd363a93277701b7bfd2749fbefee2396469e"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9957433c3a1b67bdd4c63717eaf174ebb749510d5ea612cd4e83f2d9142f3fc8"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0d7a9165167269758145756db43a133608a531b1e5bb6a626b9ee24bc38a8f7"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dffaf740fe2e147fedcb6b561353a16243e654f7fe8e701b1b9db148242e1272"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ed79883b4328b7f0bd142733d99c8e6b22703e908ec63d930b06be3a0e7113"}, - {file = "pydantic_core-2.16.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cf903310a34e14651c9de056fcc12ce090560864d5a2bb0174b971685684e1d8"}, - {file = "pydantic_core-2.16.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:46b0d5520dbcafea9a8645a8164658777686c5c524d381d983317d29687cce97"}, - {file = "pydantic_core-2.16.2-cp311-none-win32.whl", hash = "sha256:70651ff6e663428cea902dac297066d5c6e5423fda345a4ca62430575364d62b"}, - {file = "pydantic_core-2.16.2-cp311-none-win_amd64.whl", hash = "sha256:98dc6f4f2095fc7ad277782a7c2c88296badcad92316b5a6e530930b1d475ebc"}, - {file = "pydantic_core-2.16.2-cp311-none-win_arm64.whl", hash = "sha256:ef6113cd31411eaf9b39fc5a8848e71c72656fd418882488598758b2c8c6dfa0"}, - {file = "pydantic_core-2.16.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:88646cae28eb1dd5cd1e09605680c2b043b64d7481cdad7f5003ebef401a3039"}, - {file = "pydantic_core-2.16.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7b883af50eaa6bb3299780651e5be921e88050ccf00e3e583b1e92020333304b"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bf26c2e2ea59d32807081ad51968133af3025c4ba5753e6a794683d2c91bf6e"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99af961d72ac731aae2a1b55ccbdae0733d816f8bfb97b41909e143de735f522"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02906e7306cb8c5901a1feb61f9ab5e5c690dbbeaa04d84c1b9ae2a01ebe9379"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5362d099c244a2d2f9659fb3c9db7c735f0004765bbe06b99be69fbd87c3f15"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ac426704840877a285d03a445e162eb258924f014e2f074e209d9b4ff7bf380"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b94cbda27267423411c928208e89adddf2ea5dd5f74b9528513f0358bba019cb"}, - {file = "pydantic_core-2.16.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6db58c22ac6c81aeac33912fb1af0e930bc9774166cdd56eade913d5f2fff35e"}, - {file = "pydantic_core-2.16.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396fdf88b1b503c9c59c84a08b6833ec0c3b5ad1a83230252a9e17b7dfb4cffc"}, - {file = "pydantic_core-2.16.2-cp312-none-win32.whl", hash = "sha256:7c31669e0c8cc68400ef0c730c3a1e11317ba76b892deeefaf52dcb41d56ed5d"}, - {file = "pydantic_core-2.16.2-cp312-none-win_amd64.whl", hash = "sha256:a3b7352b48fbc8b446b75f3069124e87f599d25afb8baa96a550256c031bb890"}, - {file = "pydantic_core-2.16.2-cp312-none-win_arm64.whl", hash = "sha256:a9e523474998fb33f7c1a4d55f5504c908d57add624599e095c20fa575b8d943"}, - {file = "pydantic_core-2.16.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:ae34418b6b389d601b31153b84dce480351a352e0bb763684a1b993d6be30f17"}, - {file = "pydantic_core-2.16.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:732bd062c9e5d9582a30e8751461c1917dd1ccbdd6cafb032f02c86b20d2e7ec"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b52776a2e3230f4854907a1e0946eec04d41b1fc64069ee774876bbe0eab55"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef551c053692b1e39e3f7950ce2296536728871110e7d75c4e7753fb30ca87f4"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ebb892ed8599b23fa8f1799e13a12c87a97a6c9d0f497525ce9858564c4575a4"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa6c8c582036275997a733427b88031a32ffa5dfc3124dc25a730658c47a572f"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ba0884a91f1aecce75202473ab138724aa4fb26d7707f2e1fa6c3e68c84fbf"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7924e54f7ce5d253d6160090ddc6df25ed2feea25bfb3339b424a9dd591688bc"}, - {file = "pydantic_core-2.16.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69a7b96b59322a81c2203be537957313b07dd333105b73db0b69212c7d867b4b"}, - {file = "pydantic_core-2.16.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7e6231aa5bdacda78e96ad7b07d0c312f34ba35d717115f4b4bff6cb87224f0f"}, - {file = "pydantic_core-2.16.2-cp38-none-win32.whl", hash = "sha256:41dac3b9fce187a25c6253ec79a3f9e2a7e761eb08690e90415069ea4a68ff7a"}, - {file = "pydantic_core-2.16.2-cp38-none-win_amd64.whl", hash = "sha256:f685dbc1fdadb1dcd5b5e51e0a378d4685a891b2ddaf8e2bba89bd3a7144e44a"}, - {file = "pydantic_core-2.16.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:55749f745ebf154c0d63d46c8c58594d8894b161928aa41adbb0709c1fe78b77"}, - {file = "pydantic_core-2.16.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b30b0dd58a4509c3bd7eefddf6338565c4905406aee0c6e4a5293841411a1286"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18de31781cdc7e7b28678df7c2d7882f9692ad060bc6ee3c94eb15a5d733f8f7"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5864b0242f74b9dd0b78fd39db1768bc3f00d1ffc14e596fd3e3f2ce43436a33"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8f9186ca45aee030dc8234118b9c0784ad91a0bb27fc4e7d9d6608a5e3d386c"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc6f6c9be0ab6da37bc77c2dda5f14b1d532d5dbef00311ee6e13357a418e646"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa057095f621dad24a1e906747179a69780ef45cc8f69e97463692adbcdae878"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ad84731a26bcfb299f9eab56c7932d46f9cad51c52768cace09e92a19e4cf55"}, - {file = "pydantic_core-2.16.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3b052c753c4babf2d1edc034c97851f867c87d6f3ea63a12e2700f159f5c41c3"}, - {file = "pydantic_core-2.16.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e0f686549e32ccdb02ae6f25eee40cc33900910085de6aa3790effd391ae10c2"}, - {file = "pydantic_core-2.16.2-cp39-none-win32.whl", hash = "sha256:7afb844041e707ac9ad9acad2188a90bffce2c770e6dc2318be0c9916aef1469"}, - {file = "pydantic_core-2.16.2-cp39-none-win_amd64.whl", hash = "sha256:9da90d393a8227d717c19f5397688a38635afec89f2e2d7af0df037f3249c39a"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5f60f920691a620b03082692c378661947d09415743e437a7478c309eb0e4f82"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:47924039e785a04d4a4fa49455e51b4eb3422d6eaacfde9fc9abf8fdef164e8a"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6294e76b0380bb7a61eb8a39273c40b20beb35e8c87ee101062834ced19c545"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe56851c3f1d6f5384b3051c536cc81b3a93a73faf931f404fef95217cf1e10d"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9d776d30cde7e541b8180103c3f294ef7c1862fd45d81738d156d00551005784"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:72f7919af5de5ecfaf1eba47bf9a5d8aa089a3340277276e5636d16ee97614d7"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:4bfcbde6e06c56b30668a0c872d75a7ef3025dc3c1823a13cf29a0e9b33f67e8"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ff7c97eb7a29aba230389a2661edf2e9e06ce616c7e35aa764879b6894a44b25"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9b5f13857da99325dcabe1cc4e9e6a3d7b2e2c726248ba5dd4be3e8e4a0b6d0e"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a7e41e3ada4cca5f22b478c08e973c930e5e6c7ba3588fb8e35f2398cdcc1545"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60eb8ceaa40a41540b9acae6ae7c1f0a67d233c40dc4359c256ad2ad85bdf5e5"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7beec26729d496a12fd23cf8da9944ee338c8b8a17035a560b585c36fe81af20"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:22c5f022799f3cd6741e24f0443ead92ef42be93ffda0d29b2597208c94c3753"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:eca58e319f4fd6df004762419612122b2c7e7d95ffafc37e890252f869f3fb2a"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed957db4c33bc99895f3a1672eca7e80e8cda8bd1e29a80536b4ec2153fa9804"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:459c0d338cc55d099798618f714b21b7ece17eb1a87879f2da20a3ff4c7628e2"}, - {file = "pydantic_core-2.16.2.tar.gz", hash = "sha256:0ba503850d8b8dcc18391f10de896ae51d37fe5fe43dbfb6a35c5c5cad271a06"}, + {file = "pydantic_core-2.16.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4"}, + {file = "pydantic_core-2.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99"}, + {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979"}, + {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db"}, + {file = "pydantic_core-2.16.3-cp310-none-win32.whl", hash = "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132"}, + {file = "pydantic_core-2.16.3-cp310-none-win_amd64.whl", hash = "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb"}, + {file = "pydantic_core-2.16.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4"}, + {file = "pydantic_core-2.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f"}, + {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e"}, + {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba"}, + {file = "pydantic_core-2.16.3-cp311-none-win32.whl", hash = "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721"}, + {file = "pydantic_core-2.16.3-cp311-none-win_amd64.whl", hash = "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df"}, + {file = "pydantic_core-2.16.3-cp311-none-win_arm64.whl", hash = "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9"}, + {file = "pydantic_core-2.16.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff"}, + {file = "pydantic_core-2.16.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e"}, + {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca"}, + {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf"}, + {file = "pydantic_core-2.16.3-cp312-none-win32.whl", hash = "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe"}, + {file = "pydantic_core-2.16.3-cp312-none-win_amd64.whl", hash = "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed"}, + {file = "pydantic_core-2.16.3-cp312-none-win_arm64.whl", hash = "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6"}, + {file = "pydantic_core-2.16.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01"}, + {file = "pydantic_core-2.16.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c"}, + {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8"}, + {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5"}, + {file = "pydantic_core-2.16.3-cp38-none-win32.whl", hash = "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a"}, + {file = "pydantic_core-2.16.3-cp38-none-win_amd64.whl", hash = "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed"}, + {file = "pydantic_core-2.16.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820"}, + {file = "pydantic_core-2.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8"}, + {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b"}, + {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972"}, + {file = "pydantic_core-2.16.3-cp39-none-win32.whl", hash = "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2"}, + {file = "pydantic_core-2.16.3-cp39-none-win_amd64.whl", hash = "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da"}, + {file = "pydantic_core-2.16.3.tar.gz", hash = "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad"}, ] [package.dependencies] @@ -2399,6 +2725,20 @@ files = [ plugins = ["importlib-metadata"] windows-terminal = ["colorama (>=0.4.6)"] +[[package]] +name = "pyparsing" +version = "3.1.1" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +optional = true +python-versions = ">=3.6.8" +files = [ + {file = "pyparsing-3.1.1-py3-none-any.whl", hash = "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb"}, + {file = "pyparsing-3.1.1.tar.gz", hash = "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db"}, +] + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + [[package]] name = "pyreadline3" version = "3.4.1" @@ -2693,7 +3033,7 @@ cffi = {version = "*", markers = "implementation_name == \"pypy\""} name = "regex" version = "2023.12.25" description = "Alternative regular expression module, to replace re." -optional = true +optional = false python-versions = ">=3.7" files = [ {file = "regex-2023.12.25-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0694219a1d54336fd0445ea382d49d36882415c0134ee1e8332afd1529f0baa5"}, @@ -3025,6 +3365,58 @@ files = [ [package.dependencies] mpmath = ">=0.19" +[[package]] +name = "tiktoken" +version = "0.6.0" +description = "tiktoken is a fast BPE tokeniser for use with OpenAI's models" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tiktoken-0.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:277de84ccd8fa12730a6b4067456e5cf72fef6300bea61d506c09e45658d41ac"}, + {file = "tiktoken-0.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c44433f658064463650d61387623735641dcc4b6c999ca30bc0f8ba3fccaf5c"}, + {file = "tiktoken-0.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afb9a2a866ae6eef1995ab656744287a5ac95acc7e0491c33fad54d053288ad3"}, + {file = "tiktoken-0.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c62c05b3109fefca26fedb2820452a050074ad8e5ad9803f4652977778177d9f"}, + {file = "tiktoken-0.6.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0ef917fad0bccda07bfbad835525bbed5f3ab97a8a3e66526e48cdc3e7beacf7"}, + {file = "tiktoken-0.6.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e095131ab6092d0769a2fda85aa260c7c383072daec599ba9d8b149d2a3f4d8b"}, + {file = "tiktoken-0.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:05b344c61779f815038292a19a0c6eb7098b63c8f865ff205abb9ea1b656030e"}, + {file = "tiktoken-0.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cefb9870fb55dca9e450e54dbf61f904aab9180ff6fe568b61f4db9564e78871"}, + {file = "tiktoken-0.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:702950d33d8cabc039845674107d2e6dcabbbb0990ef350f640661368df481bb"}, + {file = "tiktoken-0.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8d49d076058f23254f2aff9af603863c5c5f9ab095bc896bceed04f8f0b013a"}, + {file = "tiktoken-0.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:430bc4e650a2d23a789dc2cdca3b9e5e7eb3cd3935168d97d43518cbb1f9a911"}, + {file = "tiktoken-0.6.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:293cb8669757301a3019a12d6770bd55bec38a4d3ee9978ddbe599d68976aca7"}, + {file = "tiktoken-0.6.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7bd1a288b7903aadc054b0e16ea78e3171f70b670e7372432298c686ebf9dd47"}, + {file = "tiktoken-0.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac76e000183e3b749634968a45c7169b351e99936ef46f0d2353cd0d46c3118d"}, + {file = "tiktoken-0.6.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:17cc8a4a3245ab7d935c83a2db6bb71619099d7284b884f4b2aea4c74f2f83e3"}, + {file = "tiktoken-0.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:284aebcccffe1bba0d6571651317df6a5b376ff6cfed5aeb800c55df44c78177"}, + {file = "tiktoken-0.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c1a3a5d33846f8cd9dd3b7897c1d45722f48625a587f8e6f3d3e85080559be8"}, + {file = "tiktoken-0.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6318b2bb2337f38ee954fd5efa82632c6e5ced1d52a671370fa4b2eff1355e91"}, + {file = "tiktoken-0.6.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f5f0f2ed67ba16373f9a6013b68da298096b27cd4e1cf276d2d3868b5c7efd1"}, + {file = "tiktoken-0.6.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:75af4c0b16609c2ad02581f3cdcd1fb698c7565091370bf6c0cf8624ffaba6dc"}, + {file = "tiktoken-0.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:45577faf9a9d383b8fd683e313cf6df88b6076c034f0a16da243bb1c139340c3"}, + {file = "tiktoken-0.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7c1492ab90c21ca4d11cef3a236ee31a3e279bb21b3fc5b0e2210588c4209e68"}, + {file = "tiktoken-0.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e2b380c5b7751272015400b26144a2bab4066ebb8daae9c3cd2a92c3b508fe5a"}, + {file = "tiktoken-0.6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9f497598b9f58c99cbc0eb764b4a92272c14d5203fc713dd650b896a03a50ad"}, + {file = "tiktoken-0.6.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e65e8bd6f3f279d80f1e1fbd5f588f036b9a5fa27690b7f0cc07021f1dfa0839"}, + {file = "tiktoken-0.6.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5f1495450a54e564d236769d25bfefbf77727e232d7a8a378f97acddee08c1ae"}, + {file = "tiktoken-0.6.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6c4e4857d99f6fb4670e928250835b21b68c59250520a1941618b5b4194e20c3"}, + {file = "tiktoken-0.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:168d718f07a39b013032741867e789971346df8e89983fe3c0ef3fbd5a0b1cb9"}, + {file = "tiktoken-0.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:47fdcfe11bd55376785a6aea8ad1db967db7f66ea81aed5c43fad497521819a4"}, + {file = "tiktoken-0.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fb7d2ccbf1a7784810aff6b80b4012fb42c6fc37eaa68cb3b553801a5cc2d1fc"}, + {file = "tiktoken-0.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ccb7a111ee76af5d876a729a347f8747d5ad548e1487eeea90eaf58894b3138"}, + {file = "tiktoken-0.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2048e1086b48e3c8c6e2ceeac866561374cd57a84622fa49a6b245ffecb7744"}, + {file = "tiktoken-0.6.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:07f229a5eb250b6403a61200199cecf0aac4aa23c3ecc1c11c1ca002cbb8f159"}, + {file = "tiktoken-0.6.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:432aa3be8436177b0db5a2b3e7cc28fd6c693f783b2f8722539ba16a867d0c6a"}, + {file = "tiktoken-0.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:8bfe8a19c8b5c40d121ee7938cd9c6a278e5b97dc035fd61714b4f0399d2f7a1"}, + {file = "tiktoken-0.6.0.tar.gz", hash = "sha256:ace62a4ede83c75b0374a2ddfa4b76903cf483e9cb06247f566be3bf14e6beed"}, +] + +[package.dependencies] +regex = ">=2022.1.18" +requests = ">=2.26.0" + +[package.extras] +blobfile = ["blobfile (>=2)"] + [[package]] name = "tokenizers" version = "0.15.2" @@ -3165,36 +3557,36 @@ files = [ [[package]] name = "torch" -version = "2.2.0" +version = "2.2.1" description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" optional = true python-versions = ">=3.8.0" files = [ - {file = "torch-2.2.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:d366158d6503a3447e67f8c0ad1328d54e6c181d88572d688a625fac61b13a97"}, - {file = "torch-2.2.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:707f2f80402981e9f90d0038d7d481678586251e6642a7a6ef67fc93511cb446"}, - {file = "torch-2.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:15c8f0a105c66b28496092fca1520346082e734095f8eaf47b5786bac24b8a31"}, - {file = "torch-2.2.0-cp310-none-macosx_10_9_x86_64.whl", hash = "sha256:0ca4df4b728515ad009b79f5107b00bcb2c63dc202d991412b9eb3b6a4f24349"}, - {file = "torch-2.2.0-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:3d3eea2d5969b9a1c9401429ca79efc668120314d443d3463edc3289d7f003c7"}, - {file = "torch-2.2.0-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:0d1c580e379c0d48f0f0a08ea28d8e373295aa254de4f9ad0631f9ed8bc04c24"}, - {file = "torch-2.2.0-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:9328e3c1ce628a281d2707526b4d1080eae7c4afab4f81cea75bde1f9441dc78"}, - {file = "torch-2.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:03c8e660907ac1b8ee07f6d929c4e15cd95be2fb764368799cca02c725a212b8"}, - {file = "torch-2.2.0-cp311-none-macosx_10_9_x86_64.whl", hash = "sha256:da0cefe7f84ece3e3b56c11c773b59d1cb2c0fd83ddf6b5f7f1fd1a987b15c3e"}, - {file = "torch-2.2.0-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:f81d23227034221a4a4ff8ef24cc6cec7901edd98d9e64e32822778ff01be85e"}, - {file = "torch-2.2.0-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:dcbfb2192ac41ca93c756ebe9e2af29df0a4c14ee0e7a0dd78f82c67a63d91d4"}, - {file = "torch-2.2.0-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:9eeb42971619e24392c9088b5b6d387d896e267889d41d267b1fec334f5227c5"}, - {file = "torch-2.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:c718b2ca69a6cac28baa36d86d8c0ec708b102cebd1ceb1b6488e404cd9be1d1"}, - {file = "torch-2.2.0-cp312-none-macosx_10_9_x86_64.whl", hash = "sha256:f11d18fceb4f9ecb1ac680dde7c463c120ed29056225d75469c19637e9f98d12"}, - {file = "torch-2.2.0-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:ee1da852bfd4a7e674135a446d6074c2da7194c1b08549e31eae0b3138c6b4d2"}, - {file = "torch-2.2.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:0d819399819d0862268ac531cf12a501c253007df4f9e6709ede8a0148f1a7b8"}, - {file = "torch-2.2.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:08f53ccc38c49d839bc703ea1b20769cc8a429e0c4b20b56921a9f64949bf325"}, - {file = "torch-2.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:93bffe3779965a71dab25fc29787538c37c5d54298fd2f2369e372b6fb137d41"}, - {file = "torch-2.2.0-cp38-none-macosx_10_9_x86_64.whl", hash = "sha256:c17ec323da778efe8dad49d8fb534381479ca37af1bfc58efdbb8607a9d263a3"}, - {file = "torch-2.2.0-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:c02685118008834e878f676f81eab3a952b7936fa31f474ef8a5ff4b5c78b36d"}, - {file = "torch-2.2.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:d9f39d6f53cec240a0e3baa82cb697593340f9d4554cee6d3d6ca07925c2fac0"}, - {file = "torch-2.2.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:51770c065206250dc1222ea7c0eff3f88ab317d3e931cca2aee461b85fbc2472"}, - {file = "torch-2.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:008e4c6ad703de55af760c73bf937ecdd61a109f9b08f2bbb9c17e7c7017f194"}, - {file = "torch-2.2.0-cp39-none-macosx_10_9_x86_64.whl", hash = "sha256:de8680472dd14e316f42ceef2a18a301461a9058cd6e99a1f1b20f78f11412f1"}, - {file = "torch-2.2.0-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:99e1dcecb488e3fd25bcaac56e48cdb3539842904bdc8588b0b255fde03a254c"}, + {file = "torch-2.2.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:8d3bad336dd2c93c6bcb3268e8e9876185bda50ebde325ef211fb565c7d15273"}, + {file = "torch-2.2.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:5297f13370fdaca05959134b26a06a7f232ae254bf2e11a50eddec62525c9006"}, + {file = "torch-2.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:5f5dee8433798888ca1415055f5e3faf28a3bad660e4c29e1014acd3275ab11a"}, + {file = "torch-2.2.1-cp310-none-macosx_10_9_x86_64.whl", hash = "sha256:b6d78338acabf1fb2e88bf4559d837d30230cf9c3e4337261f4d83200df1fcbe"}, + {file = "torch-2.2.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:6ab3ea2e29d1aac962e905142bbe50943758f55292f1b4fdfb6f4792aae3323e"}, + {file = "torch-2.2.1-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:d86664ec85902967d902e78272e97d1aff1d331f7619d398d3ffab1c9b8e9157"}, + {file = "torch-2.2.1-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:d6227060f268894f92c61af0a44c0d8212e19cb98d05c20141c73312d923bc0a"}, + {file = "torch-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:77e990af75fb1675490deb374d36e726f84732cd5677d16f19124934b2409ce9"}, + {file = "torch-2.2.1-cp311-none-macosx_10_9_x86_64.whl", hash = "sha256:46085e328d9b738c261f470231e987930f4cc9472d9ffb7087c7a1343826ac51"}, + {file = "torch-2.2.1-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:2d9e7e5ecbb002257cf98fae13003abbd620196c35f85c9e34c2adfb961321ec"}, + {file = "torch-2.2.1-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:ada53aebede1c89570e56861b08d12ba4518a1f8b82d467c32665ec4d1f4b3c8"}, + {file = "torch-2.2.1-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:be21d4c41ecebed9e99430dac87de1439a8c7882faf23bba7fea3fea7b906ac1"}, + {file = "torch-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:79848f46196750367dcdf1d2132b722180b9d889571e14d579ae82d2f50596c5"}, + {file = "torch-2.2.1-cp312-none-macosx_10_9_x86_64.whl", hash = "sha256:7ee804847be6be0032fbd2d1e6742fea2814c92bebccb177f0d3b8e92b2d2b18"}, + {file = "torch-2.2.1-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:84b2fb322ab091039fdfe74e17442ff046b258eb5e513a28093152c5b07325a7"}, + {file = "torch-2.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5c0c83aa7d94569997f1f474595e808072d80b04d34912ce6f1a0e1c24b0c12a"}, + {file = "torch-2.2.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:91a1b598055ba06b2c386415d2e7f6ac818545e94c5def597a74754940188513"}, + {file = "torch-2.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:8f93ddf3001ecec16568390b507652644a3a103baa72de3ad3b9c530e3277098"}, + {file = "torch-2.2.1-cp38-none-macosx_10_9_x86_64.whl", hash = "sha256:0e8bdd4c77ac2584f33ee14c6cd3b12767b4da508ec4eed109520be7212d1069"}, + {file = "torch-2.2.1-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:6a21bcd7076677c97ca7db7506d683e4e9db137e8420eb4a68fb67c3668232a7"}, + {file = "torch-2.2.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f1b90ac61f862634039265cd0f746cc9879feee03ff962c803486301b778714b"}, + {file = "torch-2.2.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:ed9e29eb94cd493b36bca9cb0b1fd7f06a0688215ad1e4b3ab4931726e0ec092"}, + {file = "torch-2.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:c47bc25744c743f3835831a20efdcfd60aeb7c3f9804a213f61e45803d16c2a5"}, + {file = "torch-2.2.1-cp39-none-macosx_10_9_x86_64.whl", hash = "sha256:0952549bcb43448c8d860d5e3e947dd18cbab491b14638e21750cb3090d5ad3e"}, + {file = "torch-2.2.1-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:26bd2272ec46fc62dcf7d24b2fb284d44fcb7be9d529ebf336b9860350d674ed"}, ] [package.dependencies] @@ -3214,7 +3606,7 @@ nvidia-cusparse-cu12 = {version = "12.1.0.106", markers = "platform_system == \" nvidia-nccl-cu12 = {version = "2.19.3", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} nvidia-nvtx-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} sympy = "*" -triton = {version = "2.2.0", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +triton = {version = "2.2.0", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version < \"3.12\""} typing-extensions = ">=4.8.0" [package.extras] @@ -3223,43 +3615,42 @@ optree = ["optree (>=0.9.1)"] [[package]] name = "torchvision" -version = "0.17.0" +version = "0.17.1" description = "image and video datasets and models for torch deep learning" optional = true python-versions = ">=3.8" files = [ - {file = "torchvision-0.17.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:153882cd8ff8e3dbef5c5054fdd15df64e85420546805a90c0b2221f2f119c4a"}, - {file = "torchvision-0.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c55c2f86e3f3a21ddd92739a972366244e9b17916e836ec47167b0a0c083c65f"}, - {file = "torchvision-0.17.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:605950cdcefe6c5aef85709ade17b1525bcf171e122cce1df09e666d96525b90"}, - {file = "torchvision-0.17.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:3d86c212fc6379e9bec3ac647d062e34c2cf36c26b98840b66573eb9fbe1f1d9"}, - {file = "torchvision-0.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:71b314813faf13cecb09a4a635b5e4b274e8df0b1921681038d491c529555bb6"}, - {file = "torchvision-0.17.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:10d276821f115fb369e6cf1f1b77b2cca60cda12cbb39a41513a9d3d0f2a93ae"}, - {file = "torchvision-0.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3eef2daddadb5c21e802e0550dd7e3ee3d98c430f4aed212ae3ba0358558be1"}, - {file = "torchvision-0.17.0-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:acc0d098ab8c295a750f0218bf5bf7bfc2f2c21f9c2fe3fc30b695cd94f4c759"}, - {file = "torchvision-0.17.0-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:3d2e9552d72e4037f2db6f7d97989a2e2f95763aa1861963a3faf521bb1610c4"}, - {file = "torchvision-0.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:f8e542cf71e1294fcb5635038eae6702df543dc90706f0836ec80e75efc511fc"}, - {file = "torchvision-0.17.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:816ae1a4506b1cb0f638e1827cae7ab768c731369ab23e86839f177926197143"}, - {file = "torchvision-0.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:be39874c239215a39b3c431c7016501f1a45bfbbebf2fe8e11d8339b5ea23bca"}, - {file = "torchvision-0.17.0-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:8fe14d580557aef2c45dd462c069ff936b6507b215c4b496f30973ae8cff917d"}, - {file = "torchvision-0.17.0-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:4608ba3246c45c968ede40e7640e4eed64556210faa154cf1ffccb1cadabe445"}, - {file = "torchvision-0.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:b755d6d3e021239d2408bf3794d0d3dcffbc629f1fd808c43d8b346045a098c4"}, - {file = "torchvision-0.17.0-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:870d7cda57420e44d20eb07bfe37bf5344a06434a7a6195b4c7f3dd55838587d"}, - {file = "torchvision-0.17.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:477f6e64a9d798c0f5adefc300acc220da6f17ef5c1e110d20108f66554fee4d"}, - {file = "torchvision-0.17.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:a54a15bd6f3dbb04ebd36c5a87530b2e090ee4b9b15eb89eda558ab3e50396a0"}, - {file = "torchvision-0.17.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e041ce3336364413bab051a3966d884bab25c200f98ca8a065f0abe758c3005e"}, - {file = "torchvision-0.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:7887f767670c72aa20f5237042d0ca1462da18f66a3ea8c36b6ba67ce26b82fc"}, - {file = "torchvision-0.17.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b1ced438b81ef662a71c8c81debaf0c80455b35b811ca55a4c3c593d721b560a"}, - {file = "torchvision-0.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b53569c52bd4bd1176a1e49d8ea55883bcf57e1614cb97e2e8ce372768299b70"}, - {file = "torchvision-0.17.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7f373507afcd9022ebd9f50b31da8dbac1ea6783ffb77d1f1ab8806425c0a83b"}, - {file = "torchvision-0.17.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:085251ab36340206dc7e1be59a15fa5e307d45ccd66889f5d7bf1ba5e7ecdc57"}, - {file = "torchvision-0.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:4c0d4c0af58af2752aad235150bd794d0f324e6eeac5cd13c440bda5dce622d3"}, + {file = "torchvision-0.17.1-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:06418880212b66e45e855dd39f536e7fd48b4e6b034a11dd9fe9e2384afb51ec"}, + {file = "torchvision-0.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:33d65d0c7fdcb3f7bc1dd8ed30ea3cd7e0587b4ad1b104b5677c8191a8bad9f1"}, + {file = "torchvision-0.17.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:aaefef2be6a02f206085ce4bb6c0078b03ebf48cb6ff82bd762ff6248475e08e"}, + {file = "torchvision-0.17.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:ebe5fdb466aff8a8e8e755de84a843418b6f8d500624752c05eaa638d7700f3d"}, + {file = "torchvision-0.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:9d4d45a996f4313e9c5db4da71d31508d44f7ccfbf29d3442bdcc2ad13e0b6f3"}, + {file = "torchvision-0.17.1-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:ea2ccdbf5974e0bf27fd6644a33b19cb0700297cf397bb0469e762c11c6c4105"}, + {file = "torchvision-0.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9106e32c9f1e70afa8172cf1b064cf9c2998d8dff0769ec69d537b20209ee43d"}, + {file = "torchvision-0.17.1-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:5966936c669a08870f6547cd0a90d08b157aeda03293f79e2adbb934687175ed"}, + {file = "torchvision-0.17.1-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:e74f5a26ef8190eab0c38b3f63914fea94e58e3b2f0e5466611c9f63bd91a80b"}, + {file = "torchvision-0.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:a2109c1a1dcf71e8940d43e91f78c4dd5bf0fcefb3a0a42244102752009f5862"}, + {file = "torchvision-0.17.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5d241d2a5fb4e608677fccf6f80b34a124446d324ee40c7814ce54bce888275b"}, + {file = "torchvision-0.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e0fe98d9d92c23d2262ff82f973242951b9357fb640f8888ac50848bd00f5b45"}, + {file = "torchvision-0.17.1-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:32dc5de86d2ade399e11087095674ca08a1649fb322cfe69336d28add467edcb"}, + {file = "torchvision-0.17.1-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:54902877410ffb5458ee52b6d0de4b25cf01496bee736d6825301a5f0398536e"}, + {file = "torchvision-0.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:cc22c1ed0f1aba3f98fd72b6f60021f57aec1d2f6af518522e8a0a83848de3a8"}, + {file = "torchvision-0.17.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:2621097065fa1c827885e2b52102e839a3541b933b7a90e0fa3c42c3de1bc3cf"}, + {file = "torchvision-0.17.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5ce76466af2b5a30573939cae1e6e62e29316ceb3ee748091002f312ab0912f6"}, + {file = "torchvision-0.17.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:bd5dcd14a32945c72f5c19341add94aa7c23dd7bca2bafde44d0f3c4344d17ed"}, + {file = "torchvision-0.17.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:dca22795cc02ca0d5ddc08c1422ff620bc9899f63d15dc36f71ef37250e17b75"}, + {file = "torchvision-0.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:524405457dd97d9ab0e48df502f819d0f41a113ce8f00470bb9926d9d36efcf1"}, + {file = "torchvision-0.17.1-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:58299a724b37b893c7ce4d0b32ea1480c30e467cc114167964b45f6013f6c2d3"}, + {file = "torchvision-0.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8a1b17fb158b2b881f2c8796fe1839a624e49d5fd07aa61f6dae60ba4819421a"}, + {file = "torchvision-0.17.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:429d63eb7551aa4d8f6cdf08d109b5570c20cbcce36d9cb95b24556418e4dc82"}, + {file = "torchvision-0.17.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:0ecc9a58171bd555aed583bf2f72e7fd6cc4f767c14f8b80b6a8725eacf4ceb1"}, + {file = "torchvision-0.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:5f427ebee15521edcd836bfe05e86feb5189b5c943b9e3999ed0e3f391fbaa1d"}, ] [package.dependencies] numpy = "*" pillow = ">=5.3.0,<8.3.dev0 || >=8.4.dev0" -requests = "*" -torch = "2.2.0" +torch = "2.2.1" [package.extras] scipy = ["scipy"] @@ -3321,13 +3712,13 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0, [[package]] name = "transformers" -version = "4.37.2" +version = "4.38.1" description = "State-of-the-art Machine Learning for JAX, PyTorch and TensorFlow" optional = true python-versions = ">=3.8.0" files = [ - {file = "transformers-4.37.2-py3-none-any.whl", hash = "sha256:595a8b12a1fcc4ad0ced49ce206c58e17be68c85d7aee3d7546d04a32c910d2e"}, - {file = "transformers-4.37.2.tar.gz", hash = "sha256:f307082ae5d528b8480611a4879a4a11651012d0e9aaea3f6cf17219ffd95542"}, + {file = "transformers-4.38.1-py3-none-any.whl", hash = "sha256:a7a9265fb060183e9d975cbbadc4d531b10281589c43f6d07563f86322728973"}, + {file = "transformers-4.38.1.tar.gz", hash = "sha256:86dc84ccbe36123647e84cbd50fc31618c109a41e6be92514b064ab55bf1304c"}, ] [package.dependencies] @@ -3344,16 +3735,16 @@ tqdm = ">=4.27" [package.extras] accelerate = ["accelerate (>=0.21.0)"] -agents = ["Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.21.0)", "datasets (!=2.5.0)", "diffusers", "opencv-python", "sentencepiece (>=0.1.91,!=0.1.92)", "torch (>=1.11,!=1.12.0)"] -all = ["Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.21.0)", "av (==9.2.0)", "codecarbon (==1.2.0)", "decord (==0.6.0)", "flax (>=0.4.1,<=0.7.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "phonemizer", "protobuf", "pyctcdecode (>=0.4.0)", "ray[tune] (>=2.7.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "tensorflow (>=2.6,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timm", "tokenizers (>=0.14,<0.19)", "torch (>=1.11,!=1.12.0)", "torchaudio", "torchvision"] +agents = ["Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.21.0)", "datasets (!=2.5.0)", "diffusers", "opencv-python", "sentencepiece (>=0.1.91,!=0.1.92)", "torch"] +all = ["Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.21.0)", "av (==9.2.0)", "codecarbon (==1.2.0)", "decord (==0.6.0)", "flax (>=0.4.1,<=0.7.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "phonemizer", "protobuf", "pyctcdecode (>=0.4.0)", "ray[tune] (>=2.7.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "tensorflow (>=2.6,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timm", "tokenizers (>=0.14,<0.19)", "torch", "torchaudio", "torchvision"] audio = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] codecarbon = ["codecarbon (==1.2.0)"] deepspeed = ["accelerate (>=0.21.0)", "deepspeed (>=0.9.3)"] -deepspeed-testing = ["GitPython (<3.1.19)", "accelerate (>=0.21.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "deepspeed (>=0.9.3)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "hf-doc-builder (>=0.3.0)", "nltk", "optuna", "parameterized", "protobuf", "psutil", "pydantic (<2)", "pytest (>=7.2.0)", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.1.5)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "timeout-decorator"] -dev = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.21.0)", "av (==9.2.0)", "beautifulsoup4", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "decord (==0.6.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "flax (>=0.4.1,<=0.7.0)", "fugashi (>=1.0)", "hf-doc-builder", "hf-doc-builder (>=0.3.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "nltk", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic (<2)", "pytest (>=7.2.0)", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.1.5)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "tensorflow (>=2.6,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timeout-decorator", "timm", "tokenizers (>=0.14,<0.19)", "torch (>=1.11,!=1.12.0)", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] -dev-tensorflow = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "hf-doc-builder", "hf-doc-builder (>=0.3.0)", "isort (>=5.5.4)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "nltk", "onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic (<2)", "pytest (>=7.2.0)", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.1.5)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "tensorflow (>=2.6,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timeout-decorator", "tokenizers (>=0.14,<0.19)", "urllib3 (<2.0.0)"] -dev-torch = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.21.0)", "beautifulsoup4", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "fugashi (>=1.0)", "hf-doc-builder", "hf-doc-builder (>=0.3.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "kenlm", "librosa", "nltk", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic (<2)", "pytest (>=7.2.0)", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.1.5)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "timeout-decorator", "timm", "tokenizers (>=0.14,<0.19)", "torch (>=1.11,!=1.12.0)", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] -docs = ["Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.21.0)", "av (==9.2.0)", "codecarbon (==1.2.0)", "decord (==0.6.0)", "flax (>=0.4.1,<=0.7.0)", "hf-doc-builder", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "phonemizer", "protobuf", "pyctcdecode (>=0.4.0)", "ray[tune] (>=2.7.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "tensorflow (>=2.6,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timm", "tokenizers (>=0.14,<0.19)", "torch (>=1.11,!=1.12.0)", "torchaudio", "torchvision"] +deepspeed-testing = ["GitPython (<3.1.19)", "accelerate (>=0.21.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "deepspeed (>=0.9.3)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "hf-doc-builder (>=0.3.0)", "nltk", "optuna", "parameterized", "protobuf", "psutil", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.1.5)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "timeout-decorator"] +dev = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.21.0)", "av (==9.2.0)", "beautifulsoup4", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "decord (==0.6.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "flax (>=0.4.1,<=0.7.0)", "fugashi (>=1.0)", "hf-doc-builder", "hf-doc-builder (>=0.3.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "nltk", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.1.5)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "tensorflow (>=2.6,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timeout-decorator", "timm", "tokenizers (>=0.14,<0.19)", "torch", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] +dev-tensorflow = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "hf-doc-builder", "hf-doc-builder (>=0.3.0)", "isort (>=5.5.4)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "nltk", "onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.1.5)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "tensorflow (>=2.6,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timeout-decorator", "tokenizers (>=0.14,<0.19)", "urllib3 (<2.0.0)"] +dev-torch = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.21.0)", "beautifulsoup4", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "fugashi (>=1.0)", "hf-doc-builder", "hf-doc-builder (>=0.3.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "kenlm", "librosa", "nltk", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.1.5)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "timeout-decorator", "timm", "tokenizers (>=0.14,<0.19)", "torch", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] +docs = ["Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.21.0)", "av (==9.2.0)", "codecarbon (==1.2.0)", "decord (==0.6.0)", "flax (>=0.4.1,<=0.7.0)", "hf-doc-builder", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "phonemizer", "protobuf", "pyctcdecode (>=0.4.0)", "ray[tune] (>=2.7.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "tensorflow (>=2.6,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timm", "tokenizers (>=0.14,<0.19)", "torch", "torchaudio", "torchvision"] docs-specific = ["hf-doc-builder"] flax = ["flax (>=0.4.1,<=0.7.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "optax (>=0.0.8,<=0.1.4)"] flax-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] @@ -3370,20 +3761,20 @@ ray = ["ray[tune] (>=2.7.0)"] retrieval = ["datasets (!=2.5.0)", "faiss-cpu"] sagemaker = ["sagemaker (>=2.31.0)"] sentencepiece = ["protobuf", "sentencepiece (>=0.1.91,!=0.1.92)"] -serving = ["fastapi", "pydantic (<2)", "starlette", "uvicorn"] +serving = ["fastapi", "pydantic", "starlette", "uvicorn"] sigopt = ["sigopt"] sklearn = ["scikit-learn"] speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)", "torchaudio"] -testing = ["GitPython (<3.1.19)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "hf-doc-builder (>=0.3.0)", "nltk", "parameterized", "protobuf", "psutil", "pydantic (<2)", "pytest (>=7.2.0)", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.1.5)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "tensorboard", "timeout-decorator"] +testing = ["GitPython (<3.1.19)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "hf-doc-builder (>=0.3.0)", "nltk", "parameterized", "protobuf", "psutil", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.1.5)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "tensorboard", "timeout-decorator"] tf = ["keras-nlp (>=0.3.1)", "onnxconverter-common", "tensorflow (>=2.6,<2.16)", "tensorflow-text (<2.16)", "tf2onnx"] tf-cpu = ["keras-nlp (>=0.3.1)", "onnxconverter-common", "tensorflow-cpu (>=2.6,<2.16)", "tensorflow-text (<2.16)", "tf2onnx"] tf-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] timm = ["timm"] tokenizers = ["tokenizers (>=0.14,<0.19)"] -torch = ["accelerate (>=0.21.0)", "torch (>=1.11,!=1.12.0)"] +torch = ["accelerate (>=0.21.0)", "torch"] torch-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)", "torchaudio"] torch-vision = ["Pillow (>=10.0.1,<=15.0)", "torchvision"] -torchhub = ["filelock", "huggingface-hub (>=0.19.3,<1.0)", "importlib-metadata", "numpy (>=1.17)", "packaging (>=20.0)", "protobuf", "regex (!=2019.12.17)", "requests", "sentencepiece (>=0.1.91,!=0.1.92)", "tokenizers (>=0.14,<0.19)", "torch (>=1.11,!=1.12.0)", "tqdm (>=4.27)"] +torchhub = ["filelock", "huggingface-hub (>=0.19.3,<1.0)", "importlib-metadata", "numpy (>=1.17)", "packaging (>=20.0)", "protobuf", "regex (!=2019.12.17)", "requests", "sentencepiece (>=0.1.91,!=0.1.92)", "tokenizers (>=0.14,<0.19)", "torch", "tqdm (>=4.27)"] video = ["av (==9.2.0)", "decord (==0.6.0)"] vision = ["Pillow (>=10.0.1,<=15.0)"] @@ -3607,9 +3998,10 @@ fastembed = ["fastembed"] hybrid = ["pinecone-text"] local = ["llama-cpp-python", "torch", "transformers"] pinecone = ["pinecone-client"] +processing = ["matplotlib"] vision = ["pillow", "torch", "torchvision", "transformers"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.13" -content-hash = "d731e15933adffd9195afea19cca5bd31dad4a574bd132e3252c110b728c1eeb" +content-hash = "7e533decdcadb8bed91697d492129d5f6136d10624b9c1f5322b6b7c26c47bc7" diff --git a/pyproject.toml b/pyproject.toml index 5a310d06d49ef97406a258643bcdcfae1aeb46a9..7c910b9148f8bbc9afaefa92e1097961f3693b24 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "semantic-router" -version = "0.0.23" +version = "0.0.24" description = "Super fast semantic router for AI decision making" authors = [ "James Briggs <james@aurelio.ai>", @@ -30,9 +30,12 @@ transformers = {version = "^4.36.2", optional = true} llama-cpp-python = {version = "^0.2.28", optional = true} black = "^23.12.1" colorama = "^0.4.6" -pinecone-client = {version = "^3.0.0", optional = true} -pillow = {version = "^10.2.0", optional = true} -torchvision = {version = "^0.17.0", optional = true} +pinecone-client = {version="^3.0.0", optional = true} +regex = "^2023.12.25" +torchvision = { version = "^0.17.0", optional = true} +pillow = { version= "^10.2.0", optional = true} +tiktoken = "^0.6.0" +matplotlib = { version="^3.8.3", optional = true} [tool.poetry.extras] hybrid = ["pinecone-text"] @@ -40,6 +43,7 @@ fastembed = ["fastembed"] local = ["torch", "transformers", "llama-cpp-python"] pinecone = ["pinecone-client"] vision = ["torch", "torchvision", "transformers", "pillow"] +processing = ["matplotlib"] [tool.poetry.group.dev.dependencies] ipykernel = "^6.25.0" diff --git a/semantic_router/__init__.py b/semantic_router/__init__.py index 7ac0c93ebe77c6c37c9cd8c960db48a399adac11..d810106abbd425f673391ada9a802561532318b3 100644 --- a/semantic_router/__init__.py +++ b/semantic_router/__init__.py @@ -4,4 +4,4 @@ from semantic_router.route import Route __all__ = ["RouteLayer", "HybridRouteLayer", "Route", "LayerConfig"] -__version__ = "0.0.23" +__version__ = "0.0.24" diff --git a/semantic_router/encoders/clip.py b/semantic_router/encoders/clip.py index 4f4342f1af2f4e88a1df1b9107e306b6927f5fd2..67e58e86234e0a9bc739c1e2c2cc5fd352e6e790 100644 --- a/semantic_router/encoders/clip.py +++ b/semantic_router/encoders/clip.py @@ -86,16 +86,20 @@ class CLIPEncoder(BaseEncoder): processor = CLIPProcessor.from_pretrained(self.name) model = CLIPModel.from_pretrained(self.name, **self.model_kwargs) + self.device = self._get_device() + model.to(self.device) + return tokenizer, processor, model + + def _get_device(self) -> str: if self.device: - pass + device = self.device elif self._torch.cuda.is_available(): - self.device = "cuda" + device = "cuda" elif self._torch.backends.mps.is_available(): - self.device = "mps" + device = "mps" else: - self.device = "cpu" - model.to(self.device) - return tokenizer, processor, model + device = "cpu" + return device def _encode_text(self, docs: List[str]) -> Any: inputs = self._tokenizer( diff --git a/semantic_router/encoders/cohere.py b/semantic_router/encoders/cohere.py index 6bc7d661b1794fc0c23443e06dab78a977fa9d28..b49769eb4c1b32c36467d299f4905477b522bb1a 100644 --- a/semantic_router/encoders/cohere.py +++ b/semantic_router/encoders/cohere.py @@ -4,6 +4,7 @@ from typing import List, Optional import cohere from semantic_router.encoders import BaseEncoder +from semantic_router.utils.defaults import EncoderDefault class CohereEncoder(BaseEncoder): @@ -19,7 +20,7 @@ class CohereEncoder(BaseEncoder): input_type: Optional[str] = "search_query", ): if name is None: - name = os.getenv("COHERE_MODEL_NAME", "embed-english-v3.0") + name = EncoderDefault.COHERE.value["embedding_model"] super().__init__( name=name, score_threshold=score_threshold, diff --git a/semantic_router/encoders/mistral.py b/semantic_router/encoders/mistral.py index 88857de3e61e19984f5ee1036c1097bd9245c8b2..c76f1e74a1e86ede34f87ca6857c17dd71487ccd 100644 --- a/semantic_router/encoders/mistral.py +++ b/semantic_router/encoders/mistral.py @@ -8,6 +8,7 @@ from mistralai.exceptions import MistralException from mistralai.models.embeddings import EmbeddingResponse from semantic_router.encoders import BaseEncoder +from semantic_router.utils.defaults import EncoderDefault class MistralEncoder(BaseEncoder): @@ -23,7 +24,7 @@ class MistralEncoder(BaseEncoder): score_threshold: float = 0.82, ): if name is None: - name = os.getenv("MISTRAL_MODEL_NAME", "mistral-embed") + name = EncoderDefault.MISTRAL.value["embedding_model"] super().__init__(name=name, score_threshold=score_threshold) api_key = mistralai_api_key or os.getenv("MISTRALAI_API_KEY") if api_key is None: diff --git a/semantic_router/encoders/openai.py b/semantic_router/encoders/openai.py index 7957f913b342b8fc8a13284783f38d3ca62ce176..7699c3c1558cde828055d28b1c313424d3253a54 100644 --- a/semantic_router/encoders/openai.py +++ b/semantic_router/encoders/openai.py @@ -8,6 +8,7 @@ from openai._types import NotGiven from openai.types import CreateEmbeddingResponse from semantic_router.encoders import BaseEncoder +from semantic_router.utils.defaults import EncoderDefault from semantic_router.utils.logger import logger @@ -20,17 +21,19 @@ class OpenAIEncoder(BaseEncoder): self, name: Optional[str] = None, openai_api_key: Optional[str] = None, + openai_org_id: Optional[str] = None, score_threshold: float = 0.82, dimensions: Union[int, NotGiven] = NotGiven(), ): if name is None: - name = os.getenv("OPENAI_MODEL_NAME", "text-embedding-ada-002") + name = EncoderDefault.OPENAI.value["embedding_model"] super().__init__(name=name, score_threshold=score_threshold) api_key = openai_api_key or os.getenv("OPENAI_API_KEY") + openai_org_id = openai_org_id or os.getenv("OPENAI_ORG_ID") if api_key is None: raise ValueError("OpenAI API key cannot be 'None'.") try: - self.client = openai.Client(api_key=api_key) + self.client = openai.Client(api_key=api_key, organization=openai_org_id) except Exception as e: raise ValueError( f"OpenAI API client failed to initialize. Error: {e}" diff --git a/semantic_router/encoders/vit.py b/semantic_router/encoders/vit.py index 801d29943c7416b25bc97a3cfb3a069fe13e6953..9e64a7a80d339c98ae2b9102efe2913f33aab92b 100644 --- a/semantic_router/encoders/vit.py +++ b/semantic_router/encoders/vit.py @@ -61,15 +61,21 @@ class VitEncoder(BaseEncoder): model = ViTModel.from_pretrained(self.name, **self.model_kwargs) - if self.device: - model.to(self.device) - - else: - device = "cuda" if self._torch.cuda.is_available() else "cpu" - model.to(device) - self.device = device + self.device = self._get_device() + model.to(self.device) return processor, model + + def _get_device(self) -> str: + if self.device: + device = self.device + elif self._torch.cuda.is_available(): + device = "cuda" + elif self._torch.backends.mps.is_available(): + device = "mps" + else: + device = "cpu" + return device def _process_images(self, images: List[Any]): rgb_images = [self._ensure_rgb(img) for img in images] diff --git a/semantic_router/encoders/zure.py b/semantic_router/encoders/zure.py index b53fb66259ba38879827594dc7fdd6b106eb9409..8a43e361e43fa1228fd57b737237d8e02aba099f 100644 --- a/semantic_router/encoders/zure.py +++ b/semantic_router/encoders/zure.py @@ -7,6 +7,7 @@ from openai import OpenAIError from openai.types import CreateEmbeddingResponse from semantic_router.encoders import BaseEncoder +from semantic_router.utils.defaults import EncoderDefault from semantic_router.utils.logger import logger @@ -30,7 +31,7 @@ class AzureOpenAIEncoder(BaseEncoder): ): name = deployment_name if name is None: - name = os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME", "text-embedding-ada-002") + name = EncoderDefault.AZURE.value["embedding_model"] super().__init__(name=name, score_threshold=score_threshold) self.api_key = api_key self.deployment_name = deployment_name @@ -42,9 +43,7 @@ class AzureOpenAIEncoder(BaseEncoder): if self.api_key is None: raise ValueError("No Azure OpenAI API key provided.") if self.deployment_name is None: - self.deployment_name = os.getenv( - "AZURE_OPENAI_DEPLOYMENT_NAME", "text-embedding-ada-002" - ) + self.deployment_name = EncoderDefault.AZURE.value["deployment_name"] # deployment_name may still be None, but it is optional in the API if self.azure_endpoint is None: self.azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT") diff --git a/semantic_router/index/base.py b/semantic_router/index/base.py index 351692df71316a8d779de43de96014dff88e6a12..5271b897298af0d99efb5e6f23f87c94da4e7b12 100644 --- a/semantic_router/index/base.py +++ b/semantic_router/index/base.py @@ -37,7 +37,8 @@ class BaseIndex(BaseModel): def describe(self) -> dict: """ - Returns a dictionary with index details such as type, dimensions, and total vector count. + Returns a dictionary with index details such as type, dimensions, and total + vector count. This method should be implemented by subclasses. """ raise NotImplementedError("This method should be implemented by subclasses.") diff --git a/semantic_router/index/local.py b/semantic_router/index/local.py index e462463171bdd75d722588d9a99d2d5b338fb9f2..81da71d1d6114cb58849ec364a0fa175254020c6 100644 --- a/semantic_router/index/local.py +++ b/semantic_router/index/local.py @@ -16,7 +16,8 @@ class LocalIndex(BaseIndex): super().__init__(index=index, routes=routes, utterances=utterances) self.type = "local" - class Config: # Stop pydantic from complaining about Optional[np.ndarray] type hints. + class Config: + # Stop pydantic from complaining about Optional[np.ndarray]type hints. arbitrary_types_allowed = True def add( @@ -83,7 +84,8 @@ class LocalIndex(BaseIndex): self.utterances = np.delete(self.utterances, delete_idx, axis=0) else: raise ValueError( - "Attempted to delete route records but either index, routes or utterances is None." + "Attempted to delete route records but either index, routes or " + "utterances is None." ) def delete_index(self): diff --git a/semantic_router/index/pinecone.py b/semantic_router/index/pinecone.py index 35f7f879f1f615065fdc77c6816c67c953c6960c..886cd8065ca7b9f2e8eb19cda3658b0a4c21d9e3 100644 --- a/semantic_router/index/pinecone.py +++ b/semantic_router/index/pinecone.py @@ -23,9 +23,9 @@ class PineconeRecord(BaseModel): def __init__(self, **data): super().__init__(**data) - # generate ID based on route name and utterances to prevent duplicates clean_route = clean_route_name(self.route) - utterance_id = hashlib.md5(self.utterance.encode()).hexdigest() + # Use SHA-256 for a more secure hash + utterance_id = hashlib.sha256(self.utterance.encode()).hexdigest() self.id = f"{clean_route}#{utterance_id}" def to_dict(self): @@ -51,13 +51,8 @@ class PineconeIndex(BaseIndex): def __init__(self, **data): super().__init__(**data) self._initialize_client() - self.type = "pinecone" self.client = self._initialize_client() - if not self.index_name.startswith(self.index_prefix): - self.index_name = f"{self.index_prefix}{self.index_name}" - # Create or connect to an existing Pinecone index - self.index = self._init_index() def _initialize_client(self, api_key: Optional[str] = None): try: diff --git a/semantic_router/layer.py b/semantic_router/layer.py index 640a68a7034db84131f1768dde02204fedf38277..3ef16206d638a96cf9274112c61388fec0e31a03 100644 --- a/semantic_router/layer.py +++ b/semantic_router/layer.py @@ -14,11 +14,13 @@ from semantic_router.index.local import LocalIndex from semantic_router.llms import BaseLLM, OpenAILLM from semantic_router.route import Route from semantic_router.schema import Encoder, EncoderType, RouteChoice +from semantic_router.utils.defaults import EncoderDefault from semantic_router.utils.logger import logger def is_valid(layer_config: str) -> bool: - """Make sure the given string is json format and contains the 3 keys: ["encoder_name", "encoder_type", "routes"]""" + """Make sure the given string is json format and contains the 3 keys: + ["encoder_name", "encoder_type", "routes"]""" try: output_json = json.loads(layer_config) required_keys = ["encoder_name", "encoder_type", "routes"] @@ -62,17 +64,16 @@ class LayerConfig: ): self.encoder_type = encoder_type if encoder_name is None: - # if encoder_name is not provided, use the default encoder for type - # TODO base these values on default values in encoders themselves.. - # TODO without initializing them (as this is just config) - if encoder_type == EncoderType.OPENAI: - encoder_name = "text-embedding-ada-002" - elif encoder_type == EncoderType.COHERE: - encoder_name = "embed-english-v3.0" - elif encoder_type == EncoderType.FASTEMBED: - encoder_name = "BAAI/bge-small-en-v1.5" - elif encoder_type == EncoderType.HUGGINGFACE: - raise NotImplementedError + for encode_type in EncoderType: + if encode_type.value == self.encoder_type: + if self.encoder_type == EncoderType.HUGGINGFACE.value: + raise NotImplementedError( + "HuggingFace encoder not supported by LayerConfig yet." + ) + encoder_name = EncoderDefault[encode_type.name].value[ + "embedding_model" + ] + break logger.info(f"Using default {encoder_type} encoder: {encoder_name}") self.encoder_name = encoder_name self.routes = routes @@ -209,7 +210,8 @@ class RouteLayer: matching_routes = [route for route in self.routes if route.name == top_class] if not matching_routes: logger.error( - f"No route found with name {top_class}. Check to see if any Routes have been defined." + f"No route found with name {top_class}. Check to see if any Routes " + "have been defined." ) return None return matching_routes[0] @@ -431,15 +433,19 @@ class RouteLayer: self, X: List[str], y: List[str], + batch_size: int = 500, max_iter: int = 500, ): # convert inputs into array - Xq: Any = np.array(self.encoder(X)) + Xq: List[List[float]] = [] + for i in tqdm(range(0, len(X), batch_size), desc="Generating embeddings"): + emb = np.array(self.encoder(X[i : i + batch_size])) + Xq.extend(emb) # initial eval (we will iterate from here) - best_acc = self._vec_evaluate(Xq=Xq, y=y) + best_acc = self._vec_evaluate(Xq=np.array(Xq), y=y) best_thresholds = self.get_thresholds() # begin fit - for _ in (pbar := tqdm(range(max_iter))): + for _ in (pbar := tqdm(range(max_iter), desc="Training")): pbar.set_postfix({"acc": round(best_acc, 2)}) # Find the best score threshold for each route thresholds = threshold_random_search( @@ -457,12 +463,16 @@ class RouteLayer: # update route layer to best thresholds self._update_thresholds(score_thresholds=best_thresholds) - def evaluate(self, X: List[str], y: List[str]) -> float: + def evaluate(self, X: List[str], y: List[str], batch_size: int = 500) -> float: """ Evaluate the accuracy of the route selection. """ - Xq = np.array(self.encoder(X)) - accuracy = self._vec_evaluate(Xq=Xq, y=y) + Xq: List[List[float]] = [] + for i in tqdm(range(0, len(X), batch_size), desc="Generating embeddings"): + emb = np.array(self.encoder(X[i : i + batch_size])) + Xq.extend(emb) + + accuracy = self._vec_evaluate(Xq=np.array(Xq), y=y) return accuracy def _vec_evaluate(self, Xq: Union[List[float], Any], y: List[str]) -> float: diff --git a/semantic_router/llms/base.py b/semantic_router/llms/base.py index 1c02c78b65f3dce3babf0ee1cbb6d2a03e780b7b..963c754a1c49ec4c9d2308562dd6f6f17e090090 100644 --- a/semantic_router/llms/base.py +++ b/semantic_router/llms/base.py @@ -46,33 +46,55 @@ class BaseLLM(BaseModel): logger.info("Extracting function input...") prompt = f""" - You are a helpful assistant designed to output JSON. - Given the following function schema - << {function_schema} >> - and query - << {query} >> - extract the parameters values from the query, in a valid JSON format. - Example: - Input: - query: "How is the weather in Hawaii right now in International units?" - schema: - {{ - "name": "get_weather", - "description": "Useful to get the weather in a specific location", - "signature": "(location: str, degree: str) -> str", - "output": "<class 'str'>", - }} - - Result: {{ - "location": "London", - "degree": "Celsius", - }} - - Input: - query: {query} - schema: {function_schema} - Result: - """ +You are an accurate and reliable computer program that only outputs valid JSON. +Your task is to output JSON representing the input arguments of a Python function. + +This is the Python function's schema: + +### FUNCTION_SCHEMA Start ### + {function_schema} +### FUNCTION_SCHEMA End ### + +This is the input query. + +### QUERY Start ### + {query} +### QUERY End ### + +The arguments that you need to provide values for, together with their datatypes, are stated in "signature" in the FUNCTION_SCHEMA. +The values these arguments must take are made clear by the QUERY. +Use the FUNCTION_SCHEMA "description" too, as this might provide helpful clues about the arguments and their values. +Return only JSON, stating the argument names and their corresponding values. + +### FORMATTING_INSTRUCTIONS Start ### + Return a respones in valid JSON format. Do not return any other explanation or text, just the JSON. + The JSON-Keys are the names of the arguments, and JSON-values are the values those arguments should take. +### FORMATTING_INSTRUCTIONS End ### + +### EXAMPLE Start ### + === EXAMPLE_INPUT_QUERY Start === + "How is the weather in Hawaii right now in International units?" + === EXAMPLE_INPUT_QUERY End === + === EXAMPLE_INPUT_SCHEMA Start === + {{ + "name": "get_weather", + "description": "Useful to get the weather in a specific location", + "signature": "(location: str, degree: str) -> str", + "output": "<class 'str'>", + }} + === EXAMPLE_INPUT_QUERY End === + === EXAMPLE_OUTPUT Start === + {{ + "location": "Hawaii", + "degree": "Celsius", + }} + === EXAMPLE_OUTPUT End === +### EXAMPLE End ### + +Note: I will tip $500 for and accurate JSON output. You will be penalized for an inaccurate JSON output. + +Provide JSON output now: +""" llm_input = [Message(role="user", content=prompt)] output = self(llm_input) diff --git a/semantic_router/llms/mistral.py b/semantic_router/llms/mistral.py index 0f74bcbde93e17f3faf1e95dd4d3bbe791a4155c..e17ba8bab050d6dbdccf3f22376729fd921c692e 100644 --- a/semantic_router/llms/mistral.py +++ b/semantic_router/llms/mistral.py @@ -5,6 +5,7 @@ from mistralai.client import MistralClient from semantic_router.llms import BaseLLM from semantic_router.schema import Message +from semantic_router.utils.defaults import EncoderDefault from semantic_router.utils.logger import logger @@ -21,7 +22,7 @@ class MistralAILLM(BaseLLM): max_tokens: int = 200, ): if name is None: - name = os.getenv("MISTRALAI_CHAT_MODEL_NAME", "mistral-tiny") + name = EncoderDefault.MISTRAL.value["language_model"] super().__init__(name=name) api_key = mistralai_api_key or os.getenv("MISTRALAI_API_KEY") if api_key is None: diff --git a/semantic_router/llms/ollama.py b/semantic_router/llms/ollama.py new file mode 100644 index 0000000000000000000000000000000000000000..df35ac06a97748ece6a2da86fad58bb7e4a0a52f --- /dev/null +++ b/semantic_router/llms/ollama.py @@ -0,0 +1,58 @@ +from typing import List, Optional + +import requests + +from semantic_router.llms import BaseLLM +from semantic_router.schema import Message +from semantic_router.utils.logger import logger + + +class OllamaLLM(BaseLLM): + temperature: Optional[float] + llm_name: Optional[str] + max_tokens: Optional[int] + stream: Optional[bool] + + def __init__( + self, + name: str = "ollama", + temperature: float = 0.2, + llm_name: str = "openhermes", + max_tokens: Optional[int] = 200, + stream: bool = False, + ): + super().__init__(name=name) + self.temperature = temperature + self.llm_name = llm_name + self.max_tokens = max_tokens + self.stream = stream + + def __call__( + self, + messages: List[Message], + temperature: Optional[float] = None, + llm_name: Optional[str] = None, + max_tokens: Optional[int] = None, + stream: Optional[bool] = None, + ) -> str: + # Use instance defaults if not overridden + temperature = temperature if temperature is not None else self.temperature + llm_name = llm_name if llm_name is not None else self.llm_name + max_tokens = max_tokens if max_tokens is not None else self.max_tokens + stream = stream if stream is not None else self.stream + + try: + payload = { + "model": llm_name, + "messages": [m.to_openai() for m in messages], + "options": {"temperature": temperature, "num_predict": max_tokens}, + "format": "json", + "stream": stream, + } + response = requests.post("http://localhost:11434/api/chat", json=payload) + output = response.json()["message"]["content"] + + return output + except Exception as e: + logger.error(f"LLM error: {e}") + raise Exception(f"LLM error: {e}") from e diff --git a/semantic_router/llms/openai.py b/semantic_router/llms/openai.py index a93ce0e7ab2747fc77e537e485b7699779919e04..892375945f4064c4b9af1f70e4be3463a4993d0d 100644 --- a/semantic_router/llms/openai.py +++ b/semantic_router/llms/openai.py @@ -5,6 +5,7 @@ import openai from semantic_router.llms import BaseLLM from semantic_router.schema import Message +from semantic_router.utils.defaults import EncoderDefault from semantic_router.utils.logger import logger @@ -21,7 +22,7 @@ class OpenAILLM(BaseLLM): max_tokens: int = 200, ): if name is None: - name = os.getenv("OPENAI_CHAT_MODEL_NAME", "gpt-3.5-turbo") + name = EncoderDefault.OPENAI.value["language_model"] super().__init__(name=name) api_key = openai_api_key or os.getenv("OPENAI_API_KEY") if api_key is None: diff --git a/semantic_router/llms/zure.py b/semantic_router/llms/zure.py index d3af1cdadcae57460c6a94491bfd6e7960e2b5f8..26b7901f7b595ed1705a81484598f4389a242d26 100644 --- a/semantic_router/llms/zure.py +++ b/semantic_router/llms/zure.py @@ -5,6 +5,7 @@ import openai from semantic_router.llms import BaseLLM from semantic_router.schema import Message +from semantic_router.utils.defaults import EncoderDefault from semantic_router.utils.logger import logger @@ -23,7 +24,7 @@ class AzureOpenAILLM(BaseLLM): api_version="2023-07-01-preview", ): if name is None: - name = os.getenv("OPENAI_CHAT_MODEL_NAME", "gpt-3.5-turbo") + name = EncoderDefault.AZURE.value["language_model"] super().__init__(name=name) api_key = openai_api_key or os.getenv("AZURE_OPENAI_API_KEY") if api_key is None: diff --git a/semantic_router/schema.py b/semantic_router/schema.py index 8bb5a65f6f3c0d5e315ac433cc68b55cdc25989a..8841902161f6b72b1c5ee3245b3b08e1994609eb 100644 --- a/semantic_router/schema.py +++ b/semantic_router/schema.py @@ -1,5 +1,5 @@ from enum import Enum -from typing import Any, List, Optional +from typing import List, Optional from pydantic.v1 import BaseModel from pydantic.v1.dataclasses import dataclass @@ -77,6 +77,12 @@ class Message(BaseModel): class DocumentSplit(BaseModel): - docs: List[Any] + docs: List[str] is_triggered: bool = False triggered_score: Optional[float] = None + token_count: Optional[int] = None + metadata: Optional[dict] = None + + @property + def content(self) -> str: + return " ".join(self.docs) diff --git a/semantic_router/splitters/__init__.py b/semantic_router/splitters/__init__.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..44acb9e39ef60f0db98b2b07ddafee69cffeb756 100644 --- a/semantic_router/splitters/__init__.py +++ b/semantic_router/splitters/__init__.py @@ -0,0 +1,11 @@ +from semantic_router.splitters.base import BaseSplitter +from semantic_router.splitters.consecutive_sim import ConsecutiveSimSplitter +from semantic_router.splitters.cumulative_sim import CumulativeSimSplitter +from semantic_router.splitters.rolling_window import RollingWindowSplitter + +__all__ = [ + "BaseSplitter", + "ConsecutiveSimSplitter", + "CumulativeSimSplitter", + "RollingWindowSplitter", +] diff --git a/semantic_router/splitters/base.py b/semantic_router/splitters/base.py index 7f66c8bceff2292f1193161c57d87178d07a60aa..0514e014e34e50b03a1285395591d71f67775b17 100644 --- a/semantic_router/splitters/base.py +++ b/semantic_router/splitters/base.py @@ -1,14 +1,38 @@ -from typing import Any, List +from typing import List -from pydantic.v1 import BaseModel +from colorama import Fore, Style +from pydantic.v1 import BaseModel, Extra from semantic_router.encoders import BaseEncoder +from semantic_router.schema import DocumentSplit class BaseSplitter(BaseModel): name: str encoder: BaseEncoder - score_threshold: float - def __call__(self, docs: List[Any]) -> List[List[float]]: + class Config: + extra = Extra.allow + + def __call__(self, docs: List[str]) -> List[DocumentSplit]: raise NotImplementedError("Subclasses must implement this method") + + def print(self, document_splits: List[DocumentSplit]) -> None: + colors = [Fore.RED, Fore.GREEN, Fore.BLUE, Fore.MAGENTA] + for i, split in enumerate(document_splits): + color = colors[i % len(colors)] + colored_content = f"{color}{split.content}{Style.RESET_ALL}" + if split.is_triggered: + triggered = f"{split.triggered_score:.2f}" + elif i == len(document_splits) - 1: + triggered = "final split" + else: + triggered = "token limit" + print( + f"Split {i + 1}, " + f"tokens {split.token_count}, " + f"triggered by: {triggered}" + ) + print(colored_content) + print("-" * 88) + print("\n") diff --git a/semantic_router/splitters/consecutive_sim.py b/semantic_router/splitters/consecutive_sim.py index f30bbc755061640300f861e04fc7febba57fe947..4a2e110645ae90932871c36c5eb30f537943ad6f 100644 --- a/semantic_router/splitters/consecutive_sim.py +++ b/semantic_router/splitters/consecutive_sim.py @@ -19,8 +19,9 @@ class ConsecutiveSimSplitter(BaseSplitter): name: str = "consecutive_similarity_splitter", score_threshold: float = 0.45, ): - super().__init__(name=name, score_threshold=score_threshold, encoder=encoder) + super().__init__(name=name, encoder=encoder) encoder.score_threshold = score_threshold + self.score_threshold = score_threshold def __call__(self, docs: List[Any]): # Check if there's only a single document diff --git a/semantic_router/splitters/cumulative_sim.py b/semantic_router/splitters/cumulative_sim.py index f7a6475ad809a8b1eb877f592cf9ca0799941ba2..e9dd8deb2b1f24f519fab47c8fb61cc7e8f0f221 100644 --- a/semantic_router/splitters/cumulative_sim.py +++ b/semantic_router/splitters/cumulative_sim.py @@ -8,9 +8,9 @@ from semantic_router.splitters.base import BaseSplitter class CumulativeSimSplitter(BaseSplitter): - """ - Called "cumulative sim" because we check the similarities of the embeddings of cumulative concatenated documents with the next document. + Called "cumulative sim" because we check the similarities of the + embeddings of cumulative concatenated documents with the next document. """ def __init__( @@ -19,15 +19,17 @@ class CumulativeSimSplitter(BaseSplitter): name: str = "cumulative_similarity_splitter", score_threshold: float = 0.45, ): - super().__init__(name=name, score_threshold=score_threshold, encoder=encoder) + super().__init__(name=name, encoder=encoder) encoder.score_threshold = score_threshold + self.score_threshold = score_threshold def __call__(self, docs: List[str]): total_docs = len(docs) # Check if there's only a single document if total_docs == 1: raise ValueError( - "There is only one document provided; at least two are required to determine topics based on similarity." + "There is only one document provided; at least two are required " + "to determine topics based on similarity." ) splits = [] curr_split_start_idx = 0 @@ -35,10 +37,12 @@ class CumulativeSimSplitter(BaseSplitter): for idx in range(0, total_docs): if idx + 1 < total_docs: # Ensure there is a next document to compare with. if idx == 0: - # On the first iteration, compare the first document directly to the second. + # On the first iteration, compare the + # first document directly to the second. curr_split_docs = docs[idx] else: - # For subsequent iterations, compare cumulative documents up to the current one with the next. + # For subsequent iterations, compare cumulative + # documents up to the current one with the next. curr_split_docs = "\n".join(docs[curr_split_start_idx : idx + 1]) next_doc = docs[idx + 1] diff --git a/semantic_router/splitters/rolling_window.py b/semantic_router/splitters/rolling_window.py new file mode 100644 index 0000000000000000000000000000000000000000..0e7c651de4fbe3e113e6ad0313f7b2d2ce1355d3 --- /dev/null +++ b/semantic_router/splitters/rolling_window.py @@ -0,0 +1,334 @@ +from typing import List + +import numpy as np + +from semantic_router.encoders.base import BaseEncoder +from semantic_router.schema import DocumentSplit +from semantic_router.splitters.base import BaseSplitter +from semantic_router.splitters.utils import split_to_sentences, tiktoken_length +from semantic_router.utils.logger import logger + + +class RollingWindowSplitter(BaseSplitter): + def __init__( + self, + encoder: BaseEncoder, + threshold_adjustment=0.01, + dynamic_threshold: bool = True, + window_size=5, + min_split_tokens=100, + max_split_tokens=300, + split_tokens_tolerance=10, + plot_splits=False, + name="rolling_window_splitter", + ): + super().__init__(name=name, encoder=encoder) + self.calculated_threshold: float + self.encoder = encoder + self.threshold_adjustment = threshold_adjustment + self.dynamic_threshold = dynamic_threshold + self.window_size = window_size + self.plot_splits = plot_splits + self.min_split_tokens = min_split_tokens + self.max_split_tokens = max_split_tokens + self.split_tokens_tolerance = split_tokens_tolerance + + def encode_documents(self, docs: List[str]) -> np.ndarray: + try: + embeddings = self.encoder(docs) + return np.array(embeddings) + except Exception as e: + logger.error(f"Error encoding documents {docs}: {e}") + raise + + def calculate_similarity_scores(self, encoded_docs: np.ndarray) -> List[float]: + raw_similarities = [] + for idx in range(1, len(encoded_docs)): + window_start = max(0, idx - self.window_size) + cumulative_context = np.mean(encoded_docs[window_start:idx], axis=0) + curr_sim_score = np.dot(cumulative_context, encoded_docs[idx]) / ( + np.linalg.norm(cumulative_context) * np.linalg.norm(encoded_docs[idx]) + + 1e-10 + ) + raw_similarities.append(curr_sim_score) + return raw_similarities + + def find_split_indices(self, similarities: List[float]) -> List[int]: + split_indices = [] + for idx in range(1, len(similarities)): + if similarities[idx] < self.calculated_threshold: + split_indices.append(idx + 1) + return split_indices + + def find_optimal_threshold(self, docs: List[str], encoded_docs: np.ndarray): + token_counts = [tiktoken_length(doc) for doc in docs] + cumulative_token_counts = np.cumsum([0] + token_counts) + similarity_scores = self.calculate_similarity_scores(encoded_docs) + + # Analyze the distribution of similarity scores to set initial bounds + median_score = np.median(similarity_scores) + std_dev = np.std(similarity_scores) + + # Set initial bounds based on median and standard deviation + low = max(0.0, float(median_score - std_dev)) + high = min(1.0, float(median_score + std_dev)) + + iteration = 0 + while low <= high: + self.calculated_threshold = (low + high) / 2 + logger.info( + f"Iteration {iteration}: Trying threshold: {self.calculated_threshold}" + ) + split_indices = self.find_split_indices(similarity_scores) + + # Calculate the token counts for each split using the cumulative sums + split_token_counts = [ + cumulative_token_counts[end] - cumulative_token_counts[start] + for start, end in zip( + [0] + split_indices, split_indices + [len(token_counts)] + ) + ] + + # Calculate the median token count for the splits + median_tokens = np.median(split_token_counts) + logger.info( + f"Iteration {iteration}: Median tokens per split: {median_tokens}" + ) + if ( + self.min_split_tokens - self.split_tokens_tolerance + <= median_tokens + <= self.max_split_tokens + self.split_tokens_tolerance + ): + logger.info( + f"Iteration {iteration}: " + f"Optimal threshold {self.calculated_threshold} found " + f"with median tokens ({median_tokens}) in target range " + f" {self.min_split_tokens}-{self.max_split_tokens}." + ) + break + elif median_tokens < self.min_split_tokens: + high = self.calculated_threshold - self.threshold_adjustment + logger.info(f"Iteration {iteration}: Adjusting high to {high}") + else: + low = self.calculated_threshold + self.threshold_adjustment + logger.info(f"Iteration {iteration}: Adjusting low to {low}") + iteration += 1 + + logger.info(f"Final optimal threshold: {self.calculated_threshold}") + return self.calculated_threshold + + def split_documents( + self, docs: List[str], split_indices: List[int], similarities: List[float] + ) -> List[DocumentSplit]: + """ + This method iterates through each document, appending it to the current split + until it either reaches a split point (determined by split_indices) or exceeds + the maximum token limit for a split (self.max_split_tokens). + When a document causes the current token count to exceed this limit, + or when a split point is reached and the minimum token requirement is met, + the current split is finalized and added to the List of splits. + """ + token_counts = [tiktoken_length(doc) for doc in docs] + splits, current_split = [], [] + current_tokens_count = 0 + + for doc_idx, doc in enumerate(docs): + doc_token_count = token_counts[doc_idx] + + # Check if current index is a split point based on similarity + if doc_idx + 1 in split_indices: + if current_tokens_count + doc_token_count >= self.min_split_tokens: + # Include the current document before splitting + # if it doesn't exceed the max limit + current_split.append(doc) + current_tokens_count += doc_token_count + + triggered_score = ( + similarities[doc_idx] if doc_idx < len(similarities) else None + ) + splits.append( + DocumentSplit( + docs=current_split.copy(), + is_triggered=True, + triggered_score=triggered_score, + token_count=current_tokens_count, + ) + ) + logger.info( + f"Split finalized with {current_tokens_count} tokens due to " + f"threshold {self.calculated_threshold}." + ) + current_split, current_tokens_count = [], 0 + continue # Move to the next document after splitting + + # Check if adding the current document exceeds the max token limit + if current_tokens_count + doc_token_count > self.max_split_tokens: + if current_tokens_count >= self.min_split_tokens: + splits.append( + DocumentSplit( + docs=current_split.copy(), + is_triggered=False, + triggered_score=None, + token_count=current_tokens_count, + ) + ) + logger.info( + f"Split finalized with {current_tokens_count} tokens due to " + f"exceeding token limit of {self.max_split_tokens}." + ) + current_split, current_tokens_count = [], 0 + + current_split.append(doc) + current_tokens_count += doc_token_count + + # Handle the last split + if current_split: + splits.append( + DocumentSplit( + docs=current_split.copy(), + is_triggered=False, + triggered_score=None, + token_count=current_tokens_count, + ) + ) + logger.info( + f"Final split added with {current_tokens_count} " + "tokens due to remaining documents." + ) + + # Validation to ensure no tokens are lost during the split + original_token_count = sum(token_counts) + split_token_count = sum( + [tiktoken_length(doc) for split in splits for doc in split.docs] + ) + if original_token_count != split_token_count: + logger.error( + f"Token count mismatch: {original_token_count} != {split_token_count}" + ) + raise ValueError( + f"Token count mismatch: {original_token_count} != {split_token_count}" + ) + + return splits + + def plot_similarity_scores( + self, similarities: List[float], split_indices: List[int] + ): + try: + from matplotlib import pyplot as plt + except ImportError: + logger.warning( + "Plotting is disabled. Please `pip install " + "semantic-router[processing]`." + ) + return + + if not self.plot_splits: + return + plt.figure(figsize=(12, 6)) + plt.plot(similarities, label="Similarity Scores", marker="o") + for split_index in split_indices: + plt.axvline( + x=split_index - 1, + color="r", + linestyle="--", + label="Split" if split_index == split_indices[0] else "", + ) + plt.axhline( + y=self.calculated_threshold, + color="g", + linestyle="-.", + label="Threshold Similarity Score", + ) + + # Annotating each similarity score + for i, score in enumerate(similarities): + plt.annotate( + f"{score:.2f}", # Formatting to two decimal places + (i, score), + textcoords="offset points", + xytext=(0, 10), # Positioning the text above the point + ha="center", + ) # Center-align the text + + plt.xlabel("Document Segment Index") + plt.ylabel("Similarity Score") + plt.title( + f"Threshold: {self.calculated_threshold} |" + f" Window Size: {self.window_size}", + loc="right", + fontsize=10, + ) + plt.suptitle("Document Similarity Scores", fontsize=14) + plt.legend() + plt.show() + + def plot_sentence_similarity_scores( + self, docs: List[str], threshold: float, window_size: int + ): + try: + from matplotlib import pyplot as plt + except ImportError: + logger.warning("Plotting is disabled. Please `pip install matplotlib`.") + return + """ + Computes similarity scores between the average of the last + 'window_size' sentences and the next one, + plots a graph of these similarity scores, and prints the first + sentence after a similarity score below + a specified threshold. + """ + sentences = [sentence for doc in docs for sentence in split_to_sentences(doc)] + encoded_sentences = self.encode_documents(sentences) + similarity_scores = [] + + for i in range(window_size, len(encoded_sentences)): + window_avg_encoding = np.mean( + encoded_sentences[i - window_size : i], axis=0 + ) + sim_score = np.dot(window_avg_encoding, encoded_sentences[i]) / ( + np.linalg.norm(window_avg_encoding) + * np.linalg.norm(encoded_sentences[i]) + + 1e-10 + ) + similarity_scores.append(sim_score) + + plt.figure(figsize=(10, 8)) + plt.plot(similarity_scores, marker="o", linestyle="-", color="b") + plt.title("Sliding Window Sentence Similarity Scores") + plt.xlabel("Sentence Index") + plt.ylabel("Similarity Score") + plt.grid(True) + plt.axhline(y=threshold, color="r", linestyle="--", label="Threshold") + plt.show() + + for i, score in enumerate(similarity_scores): + if score < threshold: + print( + f"First sentence after similarity score " + f"below {threshold}: {sentences[i + window_size]}" + ) + + def __call__(self, docs: List[str]) -> List[DocumentSplit]: + if not docs: + raise ValueError("At least one document is required for splitting.") + + if len(docs) == 1: + token_count = tiktoken_length(docs[0]) + if token_count > self.max_split_tokens: + logger.warning( + f"Single document exceeds the maximum token limit " + f"of {self.max_split_tokens}. " + "Splitting to sentences before semantically splitting." + ) + docs = split_to_sentences(docs[0]) + encoded_docs = self.encode_documents(docs) + if self.dynamic_threshold: + self.find_optimal_threshold(docs, encoded_docs) + else: + self.calculated_threshold = self.encoder.score_threshold + similarities = self.calculate_similarity_scores(encoded_docs) + split_indices = self.find_split_indices(similarities=similarities) + splits = self.split_documents(docs, split_indices, similarities) + self.plot_similarity_scores(similarities, split_indices) + return splits diff --git a/semantic_router/splitters/utils.py b/semantic_router/splitters/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..349c3eaac76017c53dd5425abfe65e7e2952a679 --- /dev/null +++ b/semantic_router/splitters/utils.py @@ -0,0 +1,63 @@ +import regex +import tiktoken + + +def split_to_sentences(text: str) -> list[str]: + """ + Enhanced regex pattern to split a given text into sentences more accurately. + + The enhanced regex pattern includes handling for: + - Direct speech and quotations. + - Abbreviations, initials, and acronyms. + - Decimal numbers and dates. + - Ellipses and other punctuation marks used in informal text. + - Removing control characters and format characters. + + Args: + text (str): The text to split into sentences. + + Returns: + list: A list of sentences extracted from the text. + """ + regex_pattern = r""" + # Negative lookbehind for word boundary, word char, dot, word char + (?<!\b\w\.\w.) + # Negative lookbehind for single uppercase initials like "A." + (?<!\b[A-Z][a-z]\.) + # Negative lookbehind for abbreviations like "U.S." + (?<!\b[A-Z]\.) + # Negative lookbehind for abbreviations with uppercase letters and dots + (?<!\b\p{Lu}\.\p{Lu}.) + # Negative lookbehind for numbers, to avoid splitting decimals + (?<!\b\p{N}\.) + # Positive lookbehind for punctuation followed by whitespace + (?<=\.|\?|!|:|\.\.\.)\s+ + # Positive lookahead for uppercase letter or opening quote at word boundary + (?="?(?=[A-Z])|"\b) + # OR + | + # Splits after punctuation that follows closing punctuation, followed by + # whitespace + (?<=[\"\'\]\)\}][\.!?])\s+(?=[\"\'\(A-Z]) + # OR + | + # Splits after punctuation if not preceded by a period + (?<=[^\.][\.!?])\s+(?=[A-Z]) + # OR + | + # Handles splitting after ellipses + (?<=\.\.\.)\s+(?=[A-Z]) + # OR + | + # Matches and removes control characters and format characters + [\p{Cc}\p{Cf}]+ + """ + sentences = regex.split(regex_pattern, text, flags=regex.VERBOSE) + sentences = [sentence.strip() for sentence in sentences if sentence.strip()] + return sentences + + +def tiktoken_length(text: str) -> int: + tokenizer = tiktoken.get_encoding("cl100k_base") + tokens = tokenizer.encode(text, disallowed_special=()) + return len(tokens) diff --git a/semantic_router/utils/defaults.py b/semantic_router/utils/defaults.py new file mode 100644 index 0000000000000000000000000000000000000000..7b5a3b5f9485ab5fe4b1f31d9fd391e944da09b6 --- /dev/null +++ b/semantic_router/utils/defaults.py @@ -0,0 +1,28 @@ +import os +from enum import Enum + + +class EncoderDefault(Enum): + FASTEMBED = { + "embedding_model": "BAAI/bge-small-en-v1.5", + "language_model": "BAAI/bge-small-en-v1.5", + } + OPENAI = { + "embedding_model": os.getenv("OPENAI_MODEL_NAME", "text-embedding-ada-002"), + "language_model": os.getenv("OPENAI_CHAT_MODEL_NAME", "gpt-3.5-turbo"), + } + COHERE = { + "embedding_model": os.getenv("COHERE_MODEL_NAME", "embed-english-v3.0"), + "language_model": os.getenv("COHERE_CHAT_MODEL_NAME", "command"), + } + MISTRAL = { + "embedding_model": os.getenv("MISTRAL_MODEL_NAME", "mistral-embed"), + "language_model": os.getenv("MISTRALAI_CHAT_MODEL_NAME", "mistral-tiny"), + } + AZURE = { + "embedding_model": os.getenv("AZURE_OPENAI_MODEL", "text-embedding-ada-002"), + "language_model": os.getenv("OPENAI_CHAT_MODEL_NAME", "gpt-3.5-turbo"), + "deployment_name": os.getenv( + "AZURE_OPENAI_DEPLOYMENT_NAME", "text-embedding-ada-002" + ), + } diff --git a/tests/unit/encoders/test_openai.py b/tests/unit/encoders/test_openai.py index 4679ee939f7d4b494150a8a52f4b4c33a0e6c8db..508e9e9e197a8a0b87fb179554d43c18686c1b44 100644 --- a/tests/unit/encoders/test_openai.py +++ b/tests/unit/encoders/test_openai.py @@ -14,7 +14,9 @@ def openai_encoder(mocker): class TestOpenAIEncoder: def test_openai_encoder_init_success(self, mocker): - mocker.patch("os.getenv", return_value="fake-api-key") + # -- Mock the return value of os.getenv 3 times: model name, api key and org ID + side_effect = ["fake-model-name", "fake-api-key", "fake-org-id"] + mocker.patch("os.getenv", side_effect=side_effect) encoder = OpenAIEncoder() assert encoder.client is not None diff --git a/tests/unit/llms/test_llm_ollama.py b/tests/unit/llms/test_llm_ollama.py new file mode 100644 index 0000000000000000000000000000000000000000..369e5f4444789c3bb70988455bb49c7df4792445 --- /dev/null +++ b/tests/unit/llms/test_llm_ollama.py @@ -0,0 +1,32 @@ +import pytest + +from semantic_router.llms.ollama import OllamaLLM +from semantic_router.schema import Message + + +@pytest.fixture +def ollama_llm(): + return OllamaLLM() + + +class TestOllamaLLM: + def test_ollama_llm_init_success(self, ollama_llm): + assert ollama_llm.name == "ollama" + assert ollama_llm.temperature == 0.2 + assert ollama_llm.llm_name == "openhermes" + assert ollama_llm.max_tokens == 200 + assert ollama_llm.stream is False + + def test_ollama_llm_call_success(self, ollama_llm, mocker): + mock_response = mocker.MagicMock() + mock_response.json.return_value = {"message": {"content": "test response"}} + mocker.patch("requests.post", return_value=mock_response) + + output = ollama_llm([Message(role="user", content="test")]) + assert output == "test response" + + def test_ollama_llm_error_handling(self, ollama_llm, mocker): + mocker.patch("requests.post", side_effect=Exception("LLM error")) + with pytest.raises(Exception) as exc_info: + ollama_llm([Message(role="user", content="test")]) + assert "LLM error" in str(exc_info.value) diff --git a/tests/unit/test_layer.py b/tests/unit/test_layer.py index 00bad4ff5f32dda8c0ec748b2f16388ef7e3e101..415150a597ee396d593c88b651658bd28410fc80 100644 --- a/tests/unit/test_layer.py +++ b/tests/unit/test_layer.py @@ -399,10 +399,11 @@ class TestRouteLayer: # Load the LayerConfig from the temporary file layer_config = LayerConfig.from_file(str(config_path)) - # Using BaseLLM because trying to create a useable Mock LLM is a nightmare. + # Using BaseLLM because trying to create a usable Mock LLM is a nightmare. assert isinstance( layer_config.routes[0].llm, BaseLLM - ), "LLM should be instantiated and associated with the route based on the config" + ), "LLM should be instantiated and associated with the route based on the " + "config" assert ( layer_config.routes[0].llm.name == "fake-model-v1" ), "LLM instance should have the 'name' attribute set correctly" @@ -432,13 +433,13 @@ class TestLayerFit: # unpack test data X, y = zip(*test_data) # evaluate - route_layer.evaluate(X=X, y=y) + route_layer.evaluate(X=X, y=y, batch_size=int(len(test_data) / 5)) def test_fit(self, openai_encoder, routes, test_data): route_layer = RouteLayer(encoder=openai_encoder, routes=routes) # unpack test data X, y = zip(*test_data) - route_layer.fit(X=X, y=y) + route_layer.fit(X=X, y=y, batch_size=int(len(test_data) / 5)) # Add more tests for edge cases and error handling as needed.