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/05-local-execution.ipynb b/docs/05-local-execution.ipynb index 2ceaf072e4596b72ebf60446a7d053c8bb640444..e3e6572b9c79869c622e92a6796da33e89686316 100644 --- a/docs/05-local-execution.ipynb +++ b/docs/05-local-execution.ipynb @@ -351,7 +351,7 @@ " n_gpu_layers=-1 if enable_gpu else 0,\n", " n_ctx=2048,\n", ")\n", - "_llm.verbose=False\n", + "_llm.verbose = False\n", "llm = LlamaCppLLM(name=\"Mistral-7B-v0.2-Instruct\", llm=_llm, max_tokens=None)\n", "\n", "rl = RouteLayer(encoder=encoder, routes=routes, llm=llm)" diff --git a/docs/07-ollama-local-execution.ipynb b/docs/07-ollama-local-execution.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..91a011cb51efa4ca98cb47d227f4b43fbbd9bda3 --- /dev/null +++ b/docs/07-ollama-local-execution.ipynb @@ -0,0 +1,485 @@ +{ + "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(llm_name=\"openhermes\") # 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": [ + "\n", + "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/encoders/vision-transformer.ipynb b/docs/encoders/vision-transformer.ipynb index eee2a31460ff4b36c9b6c9b59c5b54c66fe9e6a6..c8f9d0b4b993caf71a51d143a06f912fecc9704c 100644 --- a/docs/encoders/vision-transformer.ipynb +++ b/docs/encoders/vision-transformer.ipynb @@ -73,7 +73,9 @@ "from datasets import load_dataset\n", "\n", "images = load_dataset(\"aurelio-ai/shrek-detection\")\n", - "shrek_entries = filter(lambda entry: entry[\"is_shrek\"], images[\"train\"]) # We only want Shrek images for our route\n", + "shrek_entries = filter(\n", + " lambda entry: entry[\"is_shrek\"], images[\"train\"]\n", + ") # We only want Shrek images for our route\n", "shrek_images = list(map(lambda entry: entry[\"image\"], shrek_entries))\n", "shrek_images" ] @@ -95,10 +97,7 @@ "source": [ "from semantic_router import Route\n", "\n", - "shrek = Route(\n", - " name=\"shrek\",\n", - " utterances=shrek_images\n", - ")\n", + "shrek = Route(name=\"shrek\", utterances=shrek_images)\n", "\n", "routes = [shrek]" ] @@ -131,7 +130,9 @@ "source": [ "from semantic_router.encoders import VitEncoder\n", "\n", - "encoder = VitEncoder(device=\"mps\") # Using MBP Metal acceleration (for other platforms, please see https://pytorch.org/docs/stable/tensor_attributes.html#torch.device)" + "encoder = VitEncoder(\n", + " device=\"mps\"\n", + ") # Using MBP Metal acceleration (for other platforms, please see https://pytorch.org/docs/stable/tensor_attributes.html#torch.device)" ] }, { @@ -179,12 +180,21 @@ "\n", "from PIL import Image\n", "\n", + "\n", "def load_img(url):\n", " resp = requests.get(url)\n", " return Image.open(BytesIO(resp.content))\n", "\n", - "test_shrek = load_img(\"https://static.wikia.nocookie.net/dreamworks/images/6/67/Shrek_Profile.jpg/revision/latest/thumbnail/width/360/height/360?cb=20231223041813\")\n", - "test_not_shrek = list(map(lambda entry: entry[\"image\"], filter(lambda entry: not entry[\"is_shrek\"], images[\"train\"])))[0]" + "\n", + "test_shrek = load_img(\n", + " \"https://static.wikia.nocookie.net/dreamworks/images/6/67/Shrek_Profile.jpg/revision/latest/thumbnail/width/360/height/360?cb=20231223041813\"\n", + ")\n", + "test_not_shrek = list(\n", + " map(\n", + " lambda entry: entry[\"image\"],\n", + " filter(lambda entry: not entry[\"is_shrek\"], images[\"train\"]),\n", + " )\n", + ")[0]" ] }, { diff --git a/docs/examples/pinecone-and-scaling.ipynb b/docs/examples/pinecone-and-scaling.ipynb index d541ee9b866e1b9f73bd319f2a80ffd7f58fe7bf..142380a596dbd658305fa4cae6d2b9904123ca81 100644 --- a/docs/examples/pinecone-and-scaling.ipynb +++ b/docs/examples/pinecone-and-scaling.ipynb @@ -1,876 +1,881 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "UxqB7_Ieur0s" - }, - "source": [ - "[](https://colab.research.google.com/github/aurelio-labs/semantic-router/blob/main/docs/examples/pinecone-and-scaling.ipynb) [](https://nbviewer.org/github/aurelio-labs/semantic-router/blob/main/docs/examples/pinecone-and-scaling.ipynb)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "EduhQaNAur0u" - }, - "source": [ - "# Scaling to Many Routes and Using Pinecone" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "_4JgNeX4ur0v" - }, - "source": [ - "Semantic router can be used with many hundreds, thousands, or even more routes. At very large scales it can be useful to use a vector database to store and search though your route vector space. Although we do not demonstrate _very large_ scale in this notebook, we will demonstrate more routes than usual and we will also see how to use the `PineconeIndex` for potential scalability and route persistence beyond our local machines." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "bbmw8CO4ur0v" - }, - "source": [ - "## Installing the Library" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "dLElfRhgur0v" - }, - "outputs": [], - "source": [ - "!pip install -qU \\\n", - " \"semantic-router[local, pinecone]==0.0.22\" \\\n", - " datasets==2.17.0" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Downloading Routes" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "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", - "Using the latest cached version of the dataset since aurelio-ai/generic-routes couldn't be found on the Hugging Face Hub\n", - "Found the latest cached dataset configuration 'default' at /Users/jamesbriggs/.cache/huggingface/datasets/aurelio-ai___generic-routes/default/0.0.0/5ed6ce316bb803dc716232e6c5f0eb1c7400e24d (last modified on Sun Feb 18 15:49:32 2024).\n" - ] - }, - { - "data": { - "text/plain": [ - "Dataset({\n", - " features: ['name', 'utterances', 'description', 'function_schema', 'llm', 'score_threshold'],\n", - " num_rows: 50\n", - "})" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from datasets import load_dataset\n", - "\n", - "data = load_dataset(\"aurelio-ai/generic-routes\", split=\"train\")\n", - "data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Each row in this dataset is a single route:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'name': 'politics',\n", - " 'utterances': [\"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 presidentdon't you just hate the president\",\n", - " \"they're going to destroy this country!\",\n", - " 'they will save the country!'],\n", - " 'description': None,\n", - " 'function_schema': None,\n", - " 'llm': None,\n", - " 'score_threshold': 0.82}" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "data[0]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We transform these into `Route` objects like so:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Route(name='politics', utterances=[\"isn't politics the best thing ever\", \"why don't you tell me about your political opinions\", \"don't you just love the presidentdon't you just hate the president\", \"they're going to destroy this country!\", 'they will save the country!'], description=None, function_schema=None, llm=None, score_threshold=0.82)" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from semantic_router import Route\n", - "\n", - "routes = [Route(**data[i]) for i in range(len(data))]\n", - "routes[0]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next we initialize an `encoder`. We will use a simple `HuggingFaceEncoder`, we can also use popular encoder APIs like `CohereEncoder` and `OpenAIEncoder`." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "BI9AiDspur0y", - "outputId": "27329a54-3f16-44a5-ac20-13a6b26afb97" - }, - "outputs": [], - "source": [ - "from semantic_router.encoders import HuggingFaceEncoder\n", - "\n", - "encoder = HuggingFaceEncoder()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we initialize our `PineconeIndex`, all it requires is a [Pinecone API key](https://app.pinecone.io) (you do need to be using Pinecone Serverless)." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m2024-02-18 17:11:50 WARNING semantic_router.utils.logger Index could not be initialized.\u001b[0m\n" - ] - } - ], - "source": [ - "import os\n", - "from getpass import getpass\n", - "from semantic_router.index import PineconeIndex\n", - "\n", - "os.environ[\"PINECONE_API_KEY\"] = os.environ.get(\"PINECONE_API_KEY\") or getpass(\"Enter Pinecone API key: \")\n", - "\n", - "index = PineconeIndex()" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m2024-02-18 17:12:21 INFO semantic_router.utils.logger local\u001b[0m\n" - ] - } - ], - "source": [ - "from semantic_router import RouteLayer\n", - "\n", - "rl = RouteLayer(encoder=encoder, routes=routes, index=index)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "GuLCeIS5ur0y" - }, - "source": [ - "We run the solely static routes layer:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "_rNREh7gur0y", - "outputId": "f3a1dc0b-d760-4efb-b634-d3547011dcb7" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'chitchat'" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "rl(\"how's the weather today?\").name" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "_If you see a warning about no classification being found, wait a moment and run the above cell again._" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "McbLKO26ur0y" - }, - "source": [ - "## Loading Index From Previous Initialization" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "ANAoEjxYur0y" - }, - "source": [ - "Because we're using Pinecone our route index can now persist / be access from different locations by simply connecting to the pre-existing index, by default this index uses the identifier `\"semantic-router--index\"` — this is the index we'll be loading here, but we can change the name via the `index_name` parameter if preferred.\n", - "\n", - "First, let's delete our old route layer, `index`, and `routes`." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "id": "5jaF1Xa5ur0y" - }, - "outputs": [], - "source": [ - "del rl, index, routes" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's load our index first. As mentioned, `\"index\"` is the default index name, so we don't need to specify this parameter — but we do so below for demonstrative purposes." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "index = PineconeIndex(index_name=\"index\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We load the pre-existing routes from this index like so:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[('fitness_tips', 'suggest a workout routine'),\n", - " ('daily_inspiration', 'give me an inspirational quote'),\n", - " ('creative_writing_and_literature', 'how can I improve my writing skills?'),\n", - " ('chitchat', \"let's go to the chippy\"),\n", - " ('astronomy_and_space_exploration',\n", - " 'what are some interesting facts about the universe?'),\n", - " ('chitchat', 'the weather is horrendous'),\n", - " ('cloud_computing', 'AWS vs Azure vs Google Cloud'),\n", - " ('chitchat', 'how are things going?'),\n", - " ('educational_facts', 'tell me an interesting fact'),\n", - " ('chitchat', \"how's the weather today?\"),\n", - " ('ethical_considerations_in_tech', 'ethical hacking and its importance'),\n", - " ('compliments', 'say something nice about me'),\n", - " ('food_and_recipes', \"what's your favorite food?\"),\n", - " ('interview_preparation', 'common programming interview questions'),\n", - " ('gaming_and_esports', 'what are the popular games right now?'),\n", - " ('frameworks_and_libraries',\n", - " \"what's the difference between React and Angular?\"),\n", - " ('environmental_awareness', 'how can I be more eco-friendly?'),\n", - " ('career_advice_in_tech',\n", - " 'how to build a portfolio for software development'),\n", - " ('educational_facts', 'do you know any historical trivia?'),\n", - " ('interview_preparation', 'tips for technical interviews'),\n", - " ('data_structures_and_algorithms', 'algorithms every developer should know'),\n", - " ('cybersecurity_best_practices', 'securing your web applications'),\n", - " ('jokes', 'know any good jokes?'),\n", - " ('interview_preparation', 'how to prepare for a coding interview'),\n", - " ('coding_standards_and_conventions', 'maintaining consistency in codebase'),\n", - " ('cloud_computing', 'best practices for cloud security'),\n", - " ('historical_events', 'tell me about a significant historical event'),\n", - " ('coding_standards_and_conventions', 'JavaScript coding conventions'),\n", - " ('career_advice_in_tech', 'navigating career growth in tech'),\n", - " ('development_tools', 'best Git clients for macOS'),\n", - " ('environmental_awareness', 'what are some ways to save the planet?'),\n", - " ('historical_events', 'who was a notable figure in ancient history?'),\n", - " ('career_advice', 'suggest some career development tips'),\n", - " ('compliments', 'I need some positive vibes'),\n", - " ('frameworks_and_libraries', 'best Python libraries for data analysis'),\n", - " ('book_recommendations', \"what's your favorite book?\"),\n", - " ('gardening_and_horticulture', 'suggest some easy-care indoor plants'),\n", - " ('mental_health_support', 'what are ways to improve mental health?'),\n", - " ('data_structures_and_algorithms', 'basic data structures for beginners'),\n", - " ('hobbies_and_interests', 'suggest me a hobby'),\n", - " ('career_advice_in_tech', 'tips for landing your first tech job'),\n", - " ('art_and_culture', \"what's an interesting cultural tradition?\"),\n", - " ('language_learning', 'suggest ways to learn a new language'),\n", - " ('cybersecurity_best_practices',\n", - " 'introduction to ethical hacking for developers'),\n", - " ('debugging_tips', 'tips for debugging asynchronous code'),\n", - " ('coding_standards_and_conventions', 'why coding standards matter'),\n", - " ('daily_inspiration', 'share something uplifting'),\n", - " ('environmental_awareness', 'tell me about sustainability practices'),\n", - " ('career_advice', 'how can I improve my resume?'),\n", - " ('daily_inspiration', 'I need some inspiration for today'),\n", - " ('debugging_tips', 'best tools for JavaScript debugging'),\n", - " ('food_and_recipes', 'tell me about a dish from your country'),\n", - " ('jokes', 'make me laugh'),\n", - " ('best_practices', 'best practices for error handling in JavaScript'),\n", - " ('gaming_and_esports', 'suggest a good game for beginners'),\n", - " ('hobbies_and_interests', 'what are your interests?'),\n", - " ('machine_learning_in_development', 'using TensorFlow for beginners'),\n", - " ('language_syntax', 'how do closures work in JavaScript?'),\n", - " ('machine_learning_in_development',\n", - " 'machine learning model deployment best practices'),\n", - " ('gaming_and_esports', 'tell me about upcoming esports events'),\n", - " ('art_and_culture', 'suggest some must-visit museums'),\n", - " ('language_learning', 'how can I improve my Spanish?'),\n", - " ('mindfulness_and_wellness', 'how can I relax?'),\n", - " ('astronomy_and_space_exploration', 'tell me about the latest space mission'),\n", - " ('machine_learning_in_development',\n", - " 'how to start with machine learning in Python'),\n", - " ('frameworks_and_libraries', 'introduction to Django for web development'),\n", - " ('data_structures_and_algorithms', 'complexity analysis of algorithms'),\n", - " ('debugging_tips', 'how do I debug segmentation faults in C++?'),\n", - " ('career_advice', 'what are the emerging career fields?'),\n", - " ('creative_writing_and_literature', 'suggest some classic literature'),\n", - " ('hobbies_and_interests', \"I'm looking for a new pastime\"),\n", - " ('best_practices', 'how to write clean code in Python'),\n", - " ('fitness_tips', 'how can I stay active at home?'),\n", - " ('ethical_considerations_in_tech',\n", - " 'the role of ethics in artificial intelligence'),\n", - " ('cloud_computing', 'introduction to cloud storage options'),\n", - " ('ethical_considerations_in_tech', 'privacy concerns in app development'),\n", - " ('language_syntax', 'explain the syntax of Python functions'),\n", - " ('creative_writing_and_literature', 'what are some tips for storytelling?'),\n", - " ('cybersecurity_best_practices', 'common security vulnerabilities to avoid'),\n", - " ('book_recommendations', 'I need a book recommendation'),\n", - " ('mental_health_support', 'how can I manage stress?'),\n", - " ('chitchat', 'lovely weather today'),\n", - " ('mental_health_support', 'share some self-care practices'),\n", - " ('best_practices', 'what are the best practices for REST API design?'),\n", - " ('food_and_recipes', 'suggest a recipe for dinner'),\n", - " ('language_syntax', 'what are the new features in Java 15?'),\n", - " ('gardening_and_horticulture', 'how do I start a vegetable garden?'),\n", - " ('language_learning',\n", - " 'what are some effective language learning techniques?'),\n", - " ('historical_events', 'share an interesting piece of medieval history'),\n", - " ('mindfulness_and_wellness', 'tell me about mindfulness'),\n", - " ('development_tools', 'using Docker in development'),\n", - " ('book_recommendations', 'suggest a good book to read'),\n", - " ('gardening_and_horticulture',\n", - " 'what are some tips for sustainable gardening?'),\n", - " ('art_and_culture', 'tell me about your favorite artist'),\n", - " ('educational_facts', 'share a science fact'),\n", - " ('astronomy_and_space_exploration', 'how can I stargaze effectively?'),\n", - " ('fitness_tips', 'give me a fitness tip'),\n", - " ('development_tools', 'recommendations for Python IDEs'),\n", - " ('jokes', 'tell me a joke'),\n", - " ('compliments', 'give me a compliment'),\n", - " ('politics', \"why don't you tell me about your political opinions\"),\n", - " ('pet_care_advice', 'suggest some tips for cat care'),\n", - " ('music_discovery', 'suggest some new music'),\n", - " ('personal_questions', \"what's your favorite color?\"),\n", - " ('travel_stories', 'tell me about your favorite travel destination'),\n", - " ('tech_trends', 'tell me about the latest gadgets'),\n", - " ('science_and_innovation', 'tell me about a recent innovation'),\n", - " ('programming_challenges', 'suggest a coding challenge for beginners'),\n", - " ('project_management_in_tech', 'agile vs waterfall project management'),\n", - " ('science_and_innovation', 'what are the latest scientific discoveries?'),\n", - " ('programming_challenges', 'where can I find algorithmic puzzles?'),\n", - " ('personal_questions', 'what do you like to do for fun?'),\n", - " ('open_source_contributions', 'best practices for open-source contributors'),\n", - " ('music_discovery', 'who are the top artists right now?'),\n", - " ('mobile_app_development', 'optimizing performance in mobile apps'),\n", - " ('open_source_contributions', 'how to start contributing to open source'),\n", - " ('programming_challenges', 'programming tasks to improve problem-solving'),\n", - " ('politics', \"isn't politics the best thing ever\"),\n", - " ('politics',\n", - " \"don't you just love the presidentdon't you just hate the president\"),\n", - " ('project_management_in_tech', 'how to lead a development team'),\n", - " ('philosophical_questions', 'what is the meaning of life?'),\n", - " ('version_control_systems', 'introduction to SVN for beginners'),\n", - " ('software_architecture', 'explain microservices architecture'),\n", - " ('version_control_systems', 'best practices for branching in Git'),\n", - " ('pet_care_advice', 'what should I know about keeping a pet rabbit?'),\n", - " ('politics', 'they will save the country!'),\n", - " ('pet_care_advice', 'how can I train my dog?'),\n", - " ('philosophical_questions', 'what are your thoughts on free will?'),\n", - " ('mobile_app_development',\n", - " 'best tools for cross-platform mobile development'),\n", - " ('personal_questions', 'do you have any hobbies?'),\n", - " ('travel_stories', 'share a travel story'),\n", - " ('science_and_innovation', 'how does AI impact our daily lives?'),\n", - " ('movie_suggestions', \"what's your favorite movie?\"),\n", - " ('mobile_app_development', 'Kotlin vs Swift for mobile development'),\n", - " ('mindfulness_and_wellness', 'give me a wellness tip'),\n", - " ('motivation', 'I need some motivation'),\n", - " ('music_discovery', 'recommend songs for a workout playlist'),\n", - " ('software_architecture', 'introduction to domain-driven design'),\n", - " ('software_architecture', 'differences between MVC and MVVM'),\n", - " ('movie_suggestions', 'suggest a good movie for tonight'),\n", - " ('web_development_trends', 'emerging back-end technologies'),\n", - " ('philosophical_questions', 'do you believe in fate?'),\n", - " ('web_development_trends', 'the future of web development'),\n", - " ('web_development_trends', \"what's new in front-end development?\"),\n", - " ('motivation', 'give me a motivational quote'),\n", - " ('tech_trends', \"what's new in technology?\"),\n", - " ('version_control_systems', 'how to revert a commit in Git'),\n", - " ('project_management_in_tech', 'tools for managing tech projects'),\n", - " ('movie_suggestions', 'recommend a movie'),\n", - " ('motivation', 'inspire me'),\n", - " ('travel_stories', \"what's the most interesting place you've visited?\"),\n", - " ('tech_trends', 'what are the emerging tech trends?'),\n", - " ('politics', \"they're going to destroy this country!\"),\n", - " ('open_source_contributions', 'finding projects that accept contributions')]" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "index.get_routes()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will transform these into a dictionary format that we can use to initialize our `Route` objects." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "routes_dict = {}\n", - "for route, utterance in index.get_routes():\n", - " if route not in routes_dict:\n", - " routes_dict[route] = []\n", - " routes_dict[route].append(utterance)" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'jokes': ['tell me a joke', 'make me laugh', 'know any good jokes?'],\n", - " 'career_advice': ['suggest some career development tips',\n", - " 'what are the emerging career fields?',\n", - " 'how can I improve my resume?'],\n", - " 'environmental_awareness': ['tell me about sustainability practices',\n", - " 'how can I be more eco-friendly?',\n", - " 'what are some ways to save the planet?'],\n", - " 'data_structures_and_algorithms': ['algorithms every developer should know',\n", - " 'basic data structures for beginners',\n", - " 'complexity analysis of algorithms'],\n", - " 'chitchat': ['lovely weather today',\n", - " \"how's the weather today?\",\n", - " 'how are things going?',\n", - " 'the weather is horrendous',\n", - " \"let's go to the chippy\"],\n", - " 'daily_inspiration': ['share something uplifting',\n", - " 'give me an inspirational quote',\n", - " 'I need some inspiration for today'],\n", - " 'career_advice_in_tech': ['how to build a portfolio for software development',\n", - " 'navigating career growth in tech',\n", - " 'tips for landing your first tech job'],\n", - " 'cloud_computing': ['best practices for cloud security',\n", - " 'introduction to cloud storage options',\n", - " 'AWS vs Azure vs Google Cloud'],\n", - " 'language_syntax': ['explain the syntax of Python functions',\n", - " 'how do closures work in JavaScript?',\n", - " 'what are the new features in Java 15?'],\n", - " 'art_and_culture': [\"what's an interesting cultural tradition?\",\n", - " 'suggest some must-visit museums',\n", - " 'tell me about your favorite artist'],\n", - " 'hobbies_and_interests': [\"I'm looking for a new pastime\",\n", - " 'what are your interests?',\n", - " 'suggest me a hobby'],\n", - " 'mental_health_support': ['what are ways to improve mental health?',\n", - " 'how can I manage stress?',\n", - " 'share some self-care practices'],\n", - " 'gardening_and_horticulture': ['how do I start a vegetable garden?',\n", - " 'suggest some easy-care indoor plants',\n", - " 'what are some tips for sustainable gardening?'],\n", - " 'book_recommendations': ['I need a book recommendation',\n", - " \"what's your favorite book?\",\n", - " 'suggest a good book to read'],\n", - " 'development_tools': ['best Git clients for macOS',\n", - " 'using Docker in development',\n", - " 'recommendations for Python IDEs'],\n", - " 'debugging_tips': ['best tools for JavaScript debugging',\n", - " 'how do I debug segmentation faults in C++?',\n", - " 'tips for debugging asynchronous code'],\n", - " 'cybersecurity_best_practices': ['securing your web applications',\n", - " 'common security vulnerabilities to avoid',\n", - " 'introduction to ethical hacking for developers'],\n", - " 'interview_preparation': ['how to prepare for a coding interview',\n", - " 'common programming interview questions',\n", - " 'tips for technical interviews'],\n", - " 'best_practices': ['how to write clean code in Python',\n", - " 'best practices for error handling in JavaScript',\n", - " 'what are the best practices for REST API design?'],\n", - " 'educational_facts': ['do you know any historical trivia?',\n", - " 'share a science fact',\n", - " 'tell me an interesting fact'],\n", - " 'language_learning': ['what are some effective language learning techniques?',\n", - " 'suggest ways to learn a new language',\n", - " 'how can I improve my Spanish?'],\n", - " 'mindfulness_and_wellness': ['tell me about mindfulness',\n", - " 'how can I relax?',\n", - " 'give me a wellness tip'],\n", - " 'gaming_and_esports': ['suggest a good game for beginners',\n", - " 'what are the popular games right now?',\n", - " 'tell me about upcoming esports events'],\n", - " 'historical_events': ['tell me about a significant historical event',\n", - " 'who was a notable figure in ancient history?',\n", - " 'share an interesting piece of medieval history'],\n", - " 'frameworks_and_libraries': ['best Python libraries for data analysis',\n", - " 'introduction to Django for web development',\n", - " \"what's the difference between React and Angular?\"],\n", - " 'food_and_recipes': ['suggest a recipe for dinner',\n", - " 'tell me about a dish from your country',\n", - " \"what's your favorite food?\"],\n", - " 'fitness_tips': ['suggest a workout routine',\n", - " 'give me a fitness tip',\n", - " 'how can I stay active at home?'],\n", - " 'ethical_considerations_in_tech': ['ethical hacking and its importance',\n", - " 'privacy concerns in app development',\n", - " 'the role of ethics in artificial intelligence'],\n", - " 'astronomy_and_space_exploration': ['tell me about the latest space mission',\n", - " 'what are some interesting facts about the universe?',\n", - " 'how can I stargaze effectively?'],\n", - " 'creative_writing_and_literature': ['what are some tips for storytelling?',\n", - " 'suggest some classic literature',\n", - " 'how can I improve my writing skills?'],\n", - " 'machine_learning_in_development': ['using TensorFlow for beginners',\n", - " 'machine learning model deployment best practices',\n", - " 'how to start with machine learning in Python'],\n", - " 'compliments': ['give me a compliment',\n", - " 'say something nice about me',\n", - " 'I need some positive vibes'],\n", - " 'coding_standards_and_conventions': ['maintaining consistency in codebase',\n", - " 'why coding standards matter',\n", - " 'JavaScript coding conventions'],\n", - " 'politics': [\"why don't you tell me about your political opinions\",\n", - " \"they're going to destroy this country!\",\n", - " 'they will save the country!',\n", - " \"isn't politics the best thing ever\",\n", - " \"don't you just love the presidentdon't you just hate the president\"],\n", - " 'motivation': ['give me a motivational quote',\n", - " 'inspire me',\n", - " 'I need some motivation'],\n", - " 'movie_suggestions': ['recommend a movie',\n", - " \"what's your favorite movie?\",\n", - " 'suggest a good movie for tonight'],\n", - " 'music_discovery': ['suggest some new music',\n", - " 'recommend songs for a workout playlist',\n", - " 'who are the top artists right now?'],\n", - " 'web_development_trends': [\"what's new in front-end development?\",\n", - " 'emerging back-end technologies',\n", - " 'the future of web development'],\n", - " 'science_and_innovation': ['tell me about a recent innovation',\n", - " 'how does AI impact our daily lives?',\n", - " 'what are the latest scientific discoveries?'],\n", - " 'open_source_contributions': ['best practices for open-source contributors',\n", - " 'how to start contributing to open source',\n", - " 'finding projects that accept contributions'],\n", - " 'travel_stories': [\"what's the most interesting place you've visited?\",\n", - " 'tell me about your favorite travel destination',\n", - " 'share a travel story'],\n", - " 'pet_care_advice': ['how can I train my dog?',\n", - " 'suggest some tips for cat care',\n", - " 'what should I know about keeping a pet rabbit?'],\n", - " 'mobile_app_development': ['Kotlin vs Swift for mobile development',\n", - " 'optimizing performance in mobile apps',\n", - " 'best tools for cross-platform mobile development'],\n", - " 'version_control_systems': ['introduction to SVN for beginners',\n", - " 'how to revert a commit in Git',\n", - " 'best practices for branching in Git'],\n", - " 'project_management_in_tech': ['agile vs waterfall project management',\n", - " 'tools for managing tech projects',\n", - " 'how to lead a development team'],\n", - " 'programming_challenges': ['where can I find algorithmic puzzles?',\n", - " 'programming tasks to improve problem-solving',\n", - " 'suggest a coding challenge for beginners'],\n", - " 'tech_trends': [\"what's new in technology?\",\n", - " 'tell me about the latest gadgets',\n", - " 'what are the emerging tech trends?'],\n", - " 'software_architecture': ['introduction to domain-driven design',\n", - " 'differences between MVC and MVVM',\n", - " 'explain microservices architecture'],\n", - " 'philosophical_questions': ['what is the meaning of life?',\n", - " 'do you believe in fate?',\n", - " 'what are your thoughts on free will?'],\n", - " 'personal_questions': [\"what's your favorite color?\",\n", - " 'what do you like to do for fun?',\n", - " 'do you have any hobbies?']}" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "routes_dict" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we transform these into a list of `Route` objects." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Route(name='jokes', utterances=['tell me a joke', 'make me laugh', 'know any good jokes?'], description=None, function_schema=None, llm=None, score_threshold=None)" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "routes = [Route(name=route, utterances=utterances) for route, utterances in routes_dict.items()]\n", - "routes[0]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we reinitialize our `RouteLayer`:" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 35 - }, - "id": "YyFKV8jMur0z", - "outputId": "29cf80f4-552c-47bb-fbf9-019f5dfdf00a" - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m2024-02-18 17:16:19 INFO semantic_router.utils.logger local\u001b[0m\n" - ] - } - ], - "source": [ - "from semantic_router import RouteLayer\n", - "\n", - "rl = RouteLayer(encoder=encoder, routes=routes, index=index)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And test it again:" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'jokes'" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "rl(\"say something to make me laugh\").name" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'jokes'" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "rl(\"tell me something amusing\").name" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'chitchat'" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "rl(\"it's raining cats and dogs today\").name" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Qt0vkq2Xur00" - }, - "source": [ - "Perfect, our routes loaded from our `PineconeIndex` are working as expected! As mentioned, we can use the `PineconeIndex` for persistance and high scale use-cases, for example where we might have hundreds of thousands of utterances, or even millions." - ] + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "UxqB7_Ieur0s" + }, + "source": [ + "[](https://colab.research.google.com/github/aurelio-labs/semantic-router/blob/main/docs/examples/pinecone-and-scaling.ipynb) [](https://nbviewer.org/github/aurelio-labs/semantic-router/blob/main/docs/examples/pinecone-and-scaling.ipynb)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "EduhQaNAur0u" + }, + "source": [ + "# Scaling to Many Routes and Using Pinecone" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_4JgNeX4ur0v" + }, + "source": [ + "Semantic router can be used with many hundreds, thousands, or even more routes. At very large scales it can be useful to use a vector database to store and search though your route vector space. Although we do not demonstrate _very large_ scale in this notebook, we will demonstrate more routes than usual and we will also see how to use the `PineconeIndex` for potential scalability and route persistence beyond our local machines." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "bbmw8CO4ur0v" + }, + "source": [ + "## Installing the Library" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "dLElfRhgur0v" + }, + "outputs": [], + "source": [ + "!pip install -qU \\\n", + " \"semantic-router[local, pinecone]==0.0.22\" \\\n", + " datasets==2.17.0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Downloading Routes" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "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", + "Using the latest cached version of the dataset since aurelio-ai/generic-routes couldn't be found on the Hugging Face Hub\n", + "Found the latest cached dataset configuration 'default' at /Users/jamesbriggs/.cache/huggingface/datasets/aurelio-ai___generic-routes/default/0.0.0/5ed6ce316bb803dc716232e6c5f0eb1c7400e24d (last modified on Sun Feb 18 15:49:32 2024).\n" + ] + }, + { + "data": { + "text/plain": [ + "Dataset({\n", + " features: ['name', 'utterances', 'description', 'function_schema', 'llm', 'score_threshold'],\n", + " num_rows: 50\n", + "})" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from datasets import load_dataset\n", + "\n", + "data = load_dataset(\"aurelio-ai/generic-routes\", split=\"train\")\n", + "data" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Each row in this dataset is a single route:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'name': 'politics',\n", + " 'utterances': [\"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 presidentdon't you just hate the president\",\n", + " \"they're going to destroy this country!\",\n", + " 'they will save the country!'],\n", + " 'description': None,\n", + " 'function_schema': None,\n", + " 'llm': None,\n", + " 'score_threshold': 0.82}" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data[0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We transform these into `Route` objects like so:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Route(name='politics', utterances=[\"isn't politics the best thing ever\", \"why don't you tell me about your political opinions\", \"don't you just love the presidentdon't you just hate the president\", \"they're going to destroy this country!\", 'they will save the country!'], description=None, function_schema=None, llm=None, score_threshold=0.82)" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from semantic_router import Route\n", + "\n", + "routes = [Route(**data[i]) for i in range(len(data))]\n", + "routes[0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next we initialize an `encoder`. We will use a simple `HuggingFaceEncoder`, we can also use popular encoder APIs like `CohereEncoder` and `OpenAIEncoder`." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "BI9AiDspur0y", + "outputId": "27329a54-3f16-44a5-ac20-13a6b26afb97" + }, + "outputs": [], + "source": [ + "from semantic_router.encoders import HuggingFaceEncoder\n", + "\n", + "encoder = HuggingFaceEncoder()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we initialize our `PineconeIndex`, all it requires is a [Pinecone API key](https://app.pinecone.io) (you do need to be using Pinecone Serverless)." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[33m2024-02-18 17:11:50 WARNING semantic_router.utils.logger Index could not be initialized.\u001b[0m\n" + ] + } + ], + "source": [ + "import os\n", + "from getpass import getpass\n", + "from semantic_router.index import PineconeIndex\n", + "\n", + "os.environ[\"PINECONE_API_KEY\"] = os.environ.get(\"PINECONE_API_KEY\") or getpass(\n", + " \"Enter Pinecone API key: \"\n", + ")\n", + "\n", + "index = PineconeIndex()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m2024-02-18 17:12:21 INFO semantic_router.utils.logger local\u001b[0m\n" + ] + } + ], + "source": [ + "from semantic_router import RouteLayer\n", + "\n", + "rl = RouteLayer(encoder=encoder, routes=routes, index=index)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "GuLCeIS5ur0y" + }, + "source": [ + "We run the solely static routes layer:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "_rNREh7gur0y", + "outputId": "f3a1dc0b-d760-4efb-b634-d3547011dcb7" + }, + "outputs": [ { - "cell_type": "markdown", - "metadata": { - "id": "J0oD1dxIur00" - }, - "source": [ - "---" + "data": { + "text/plain": [ + "'chitchat'" ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" } - ], - "metadata": { + ], + "source": [ + "rl(\"how's the weather today?\").name" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "_If you see a warning about no classification being found, wait a moment and run the above cell again._" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "McbLKO26ur0y" + }, + "source": [ + "## Loading Index From Previous Initialization" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ANAoEjxYur0y" + }, + "source": [ + "Because we're using Pinecone our route index can now persist / be access from different locations by simply connecting to the pre-existing index, by default this index uses the identifier `\"semantic-router--index\"` — this is the index we'll be loading here, but we can change the name via the `index_name` parameter if preferred.\n", + "\n", + "First, let's delete our old route layer, `index`, and `routes`." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "id": "5jaF1Xa5ur0y" + }, + "outputs": [], + "source": [ + "del rl, index, routes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's load our index first. As mentioned, `\"index\"` is the default index name, so we don't need to specify this parameter — but we do so below for demonstrative purposes." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "index = PineconeIndex(index_name=\"index\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We load the pre-existing routes from this index like so:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[('fitness_tips', 'suggest a workout routine'),\n", + " ('daily_inspiration', 'give me an inspirational quote'),\n", + " ('creative_writing_and_literature', 'how can I improve my writing skills?'),\n", + " ('chitchat', \"let's go to the chippy\"),\n", + " ('astronomy_and_space_exploration',\n", + " 'what are some interesting facts about the universe?'),\n", + " ('chitchat', 'the weather is horrendous'),\n", + " ('cloud_computing', 'AWS vs Azure vs Google Cloud'),\n", + " ('chitchat', 'how are things going?'),\n", + " ('educational_facts', 'tell me an interesting fact'),\n", + " ('chitchat', \"how's the weather today?\"),\n", + " ('ethical_considerations_in_tech', 'ethical hacking and its importance'),\n", + " ('compliments', 'say something nice about me'),\n", + " ('food_and_recipes', \"what's your favorite food?\"),\n", + " ('interview_preparation', 'common programming interview questions'),\n", + " ('gaming_and_esports', 'what are the popular games right now?'),\n", + " ('frameworks_and_libraries',\n", + " \"what's the difference between React and Angular?\"),\n", + " ('environmental_awareness', 'how can I be more eco-friendly?'),\n", + " ('career_advice_in_tech',\n", + " 'how to build a portfolio for software development'),\n", + " ('educational_facts', 'do you know any historical trivia?'),\n", + " ('interview_preparation', 'tips for technical interviews'),\n", + " ('data_structures_and_algorithms', 'algorithms every developer should know'),\n", + " ('cybersecurity_best_practices', 'securing your web applications'),\n", + " ('jokes', 'know any good jokes?'),\n", + " ('interview_preparation', 'how to prepare for a coding interview'),\n", + " ('coding_standards_and_conventions', 'maintaining consistency in codebase'),\n", + " ('cloud_computing', 'best practices for cloud security'),\n", + " ('historical_events', 'tell me about a significant historical event'),\n", + " ('coding_standards_and_conventions', 'JavaScript coding conventions'),\n", + " ('career_advice_in_tech', 'navigating career growth in tech'),\n", + " ('development_tools', 'best Git clients for macOS'),\n", + " ('environmental_awareness', 'what are some ways to save the planet?'),\n", + " ('historical_events', 'who was a notable figure in ancient history?'),\n", + " ('career_advice', 'suggest some career development tips'),\n", + " ('compliments', 'I need some positive vibes'),\n", + " ('frameworks_and_libraries', 'best Python libraries for data analysis'),\n", + " ('book_recommendations', \"what's your favorite book?\"),\n", + " ('gardening_and_horticulture', 'suggest some easy-care indoor plants'),\n", + " ('mental_health_support', 'what are ways to improve mental health?'),\n", + " ('data_structures_and_algorithms', 'basic data structures for beginners'),\n", + " ('hobbies_and_interests', 'suggest me a hobby'),\n", + " ('career_advice_in_tech', 'tips for landing your first tech job'),\n", + " ('art_and_culture', \"what's an interesting cultural tradition?\"),\n", + " ('language_learning', 'suggest ways to learn a new language'),\n", + " ('cybersecurity_best_practices',\n", + " 'introduction to ethical hacking for developers'),\n", + " ('debugging_tips', 'tips for debugging asynchronous code'),\n", + " ('coding_standards_and_conventions', 'why coding standards matter'),\n", + " ('daily_inspiration', 'share something uplifting'),\n", + " ('environmental_awareness', 'tell me about sustainability practices'),\n", + " ('career_advice', 'how can I improve my resume?'),\n", + " ('daily_inspiration', 'I need some inspiration for today'),\n", + " ('debugging_tips', 'best tools for JavaScript debugging'),\n", + " ('food_and_recipes', 'tell me about a dish from your country'),\n", + " ('jokes', 'make me laugh'),\n", + " ('best_practices', 'best practices for error handling in JavaScript'),\n", + " ('gaming_and_esports', 'suggest a good game for beginners'),\n", + " ('hobbies_and_interests', 'what are your interests?'),\n", + " ('machine_learning_in_development', 'using TensorFlow for beginners'),\n", + " ('language_syntax', 'how do closures work in JavaScript?'),\n", + " ('machine_learning_in_development',\n", + " 'machine learning model deployment best practices'),\n", + " ('gaming_and_esports', 'tell me about upcoming esports events'),\n", + " ('art_and_culture', 'suggest some must-visit museums'),\n", + " ('language_learning', 'how can I improve my Spanish?'),\n", + " ('mindfulness_and_wellness', 'how can I relax?'),\n", + " ('astronomy_and_space_exploration', 'tell me about the latest space mission'),\n", + " ('machine_learning_in_development',\n", + " 'how to start with machine learning in Python'),\n", + " ('frameworks_and_libraries', 'introduction to Django for web development'),\n", + " ('data_structures_and_algorithms', 'complexity analysis of algorithms'),\n", + " ('debugging_tips', 'how do I debug segmentation faults in C++?'),\n", + " ('career_advice', 'what are the emerging career fields?'),\n", + " ('creative_writing_and_literature', 'suggest some classic literature'),\n", + " ('hobbies_and_interests', \"I'm looking for a new pastime\"),\n", + " ('best_practices', 'how to write clean code in Python'),\n", + " ('fitness_tips', 'how can I stay active at home?'),\n", + " ('ethical_considerations_in_tech',\n", + " 'the role of ethics in artificial intelligence'),\n", + " ('cloud_computing', 'introduction to cloud storage options'),\n", + " ('ethical_considerations_in_tech', 'privacy concerns in app development'),\n", + " ('language_syntax', 'explain the syntax of Python functions'),\n", + " ('creative_writing_and_literature', 'what are some tips for storytelling?'),\n", + " ('cybersecurity_best_practices', 'common security vulnerabilities to avoid'),\n", + " ('book_recommendations', 'I need a book recommendation'),\n", + " ('mental_health_support', 'how can I manage stress?'),\n", + " ('chitchat', 'lovely weather today'),\n", + " ('mental_health_support', 'share some self-care practices'),\n", + " ('best_practices', 'what are the best practices for REST API design?'),\n", + " ('food_and_recipes', 'suggest a recipe for dinner'),\n", + " ('language_syntax', 'what are the new features in Java 15?'),\n", + " ('gardening_and_horticulture', 'how do I start a vegetable garden?'),\n", + " ('language_learning',\n", + " 'what are some effective language learning techniques?'),\n", + " ('historical_events', 'share an interesting piece of medieval history'),\n", + " ('mindfulness_and_wellness', 'tell me about mindfulness'),\n", + " ('development_tools', 'using Docker in development'),\n", + " ('book_recommendations', 'suggest a good book to read'),\n", + " ('gardening_and_horticulture',\n", + " 'what are some tips for sustainable gardening?'),\n", + " ('art_and_culture', 'tell me about your favorite artist'),\n", + " ('educational_facts', 'share a science fact'),\n", + " ('astronomy_and_space_exploration', 'how can I stargaze effectively?'),\n", + " ('fitness_tips', 'give me a fitness tip'),\n", + " ('development_tools', 'recommendations for Python IDEs'),\n", + " ('jokes', 'tell me a joke'),\n", + " ('compliments', 'give me a compliment'),\n", + " ('politics', \"why don't you tell me about your political opinions\"),\n", + " ('pet_care_advice', 'suggest some tips for cat care'),\n", + " ('music_discovery', 'suggest some new music'),\n", + " ('personal_questions', \"what's your favorite color?\"),\n", + " ('travel_stories', 'tell me about your favorite travel destination'),\n", + " ('tech_trends', 'tell me about the latest gadgets'),\n", + " ('science_and_innovation', 'tell me about a recent innovation'),\n", + " ('programming_challenges', 'suggest a coding challenge for beginners'),\n", + " ('project_management_in_tech', 'agile vs waterfall project management'),\n", + " ('science_and_innovation', 'what are the latest scientific discoveries?'),\n", + " ('programming_challenges', 'where can I find algorithmic puzzles?'),\n", + " ('personal_questions', 'what do you like to do for fun?'),\n", + " ('open_source_contributions', 'best practices for open-source contributors'),\n", + " ('music_discovery', 'who are the top artists right now?'),\n", + " ('mobile_app_development', 'optimizing performance in mobile apps'),\n", + " ('open_source_contributions', 'how to start contributing to open source'),\n", + " ('programming_challenges', 'programming tasks to improve problem-solving'),\n", + " ('politics', \"isn't politics the best thing ever\"),\n", + " ('politics',\n", + " \"don't you just love the presidentdon't you just hate the president\"),\n", + " ('project_management_in_tech', 'how to lead a development team'),\n", + " ('philosophical_questions', 'what is the meaning of life?'),\n", + " ('version_control_systems', 'introduction to SVN for beginners'),\n", + " ('software_architecture', 'explain microservices architecture'),\n", + " ('version_control_systems', 'best practices for branching in Git'),\n", + " ('pet_care_advice', 'what should I know about keeping a pet rabbit?'),\n", + " ('politics', 'they will save the country!'),\n", + " ('pet_care_advice', 'how can I train my dog?'),\n", + " ('philosophical_questions', 'what are your thoughts on free will?'),\n", + " ('mobile_app_development',\n", + " 'best tools for cross-platform mobile development'),\n", + " ('personal_questions', 'do you have any hobbies?'),\n", + " ('travel_stories', 'share a travel story'),\n", + " ('science_and_innovation', 'how does AI impact our daily lives?'),\n", + " ('movie_suggestions', \"what's your favorite movie?\"),\n", + " ('mobile_app_development', 'Kotlin vs Swift for mobile development'),\n", + " ('mindfulness_and_wellness', 'give me a wellness tip'),\n", + " ('motivation', 'I need some motivation'),\n", + " ('music_discovery', 'recommend songs for a workout playlist'),\n", + " ('software_architecture', 'introduction to domain-driven design'),\n", + " ('software_architecture', 'differences between MVC and MVVM'),\n", + " ('movie_suggestions', 'suggest a good movie for tonight'),\n", + " ('web_development_trends', 'emerging back-end technologies'),\n", + " ('philosophical_questions', 'do you believe in fate?'),\n", + " ('web_development_trends', 'the future of web development'),\n", + " ('web_development_trends', \"what's new in front-end development?\"),\n", + " ('motivation', 'give me a motivational quote'),\n", + " ('tech_trends', \"what's new in technology?\"),\n", + " ('version_control_systems', 'how to revert a commit in Git'),\n", + " ('project_management_in_tech', 'tools for managing tech projects'),\n", + " ('movie_suggestions', 'recommend a movie'),\n", + " ('motivation', 'inspire me'),\n", + " ('travel_stories', \"what's the most interesting place you've visited?\"),\n", + " ('tech_trends', 'what are the emerging tech trends?'),\n", + " ('politics', \"they're going to destroy this country!\"),\n", + " ('open_source_contributions', 'finding projects that accept contributions')]" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "index.get_routes()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will transform these into a dictionary format that we can use to initialize our `Route` objects." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "routes_dict = {}\n", + "for route, utterance in index.get_routes():\n", + " if route not in routes_dict:\n", + " routes_dict[route] = []\n", + " routes_dict[route].append(utterance)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'jokes': ['tell me a joke', 'make me laugh', 'know any good jokes?'],\n", + " 'career_advice': ['suggest some career development tips',\n", + " 'what are the emerging career fields?',\n", + " 'how can I improve my resume?'],\n", + " 'environmental_awareness': ['tell me about sustainability practices',\n", + " 'how can I be more eco-friendly?',\n", + " 'what are some ways to save the planet?'],\n", + " 'data_structures_and_algorithms': ['algorithms every developer should know',\n", + " 'basic data structures for beginners',\n", + " 'complexity analysis of algorithms'],\n", + " 'chitchat': ['lovely weather today',\n", + " \"how's the weather today?\",\n", + " 'how are things going?',\n", + " 'the weather is horrendous',\n", + " \"let's go to the chippy\"],\n", + " 'daily_inspiration': ['share something uplifting',\n", + " 'give me an inspirational quote',\n", + " 'I need some inspiration for today'],\n", + " 'career_advice_in_tech': ['how to build a portfolio for software development',\n", + " 'navigating career growth in tech',\n", + " 'tips for landing your first tech job'],\n", + " 'cloud_computing': ['best practices for cloud security',\n", + " 'introduction to cloud storage options',\n", + " 'AWS vs Azure vs Google Cloud'],\n", + " 'language_syntax': ['explain the syntax of Python functions',\n", + " 'how do closures work in JavaScript?',\n", + " 'what are the new features in Java 15?'],\n", + " 'art_and_culture': [\"what's an interesting cultural tradition?\",\n", + " 'suggest some must-visit museums',\n", + " 'tell me about your favorite artist'],\n", + " 'hobbies_and_interests': [\"I'm looking for a new pastime\",\n", + " 'what are your interests?',\n", + " 'suggest me a hobby'],\n", + " 'mental_health_support': ['what are ways to improve mental health?',\n", + " 'how can I manage stress?',\n", + " 'share some self-care practices'],\n", + " 'gardening_and_horticulture': ['how do I start a vegetable garden?',\n", + " 'suggest some easy-care indoor plants',\n", + " 'what are some tips for sustainable gardening?'],\n", + " 'book_recommendations': ['I need a book recommendation',\n", + " \"what's your favorite book?\",\n", + " 'suggest a good book to read'],\n", + " 'development_tools': ['best Git clients for macOS',\n", + " 'using Docker in development',\n", + " 'recommendations for Python IDEs'],\n", + " 'debugging_tips': ['best tools for JavaScript debugging',\n", + " 'how do I debug segmentation faults in C++?',\n", + " 'tips for debugging asynchronous code'],\n", + " 'cybersecurity_best_practices': ['securing your web applications',\n", + " 'common security vulnerabilities to avoid',\n", + " 'introduction to ethical hacking for developers'],\n", + " 'interview_preparation': ['how to prepare for a coding interview',\n", + " 'common programming interview questions',\n", + " 'tips for technical interviews'],\n", + " 'best_practices': ['how to write clean code in Python',\n", + " 'best practices for error handling in JavaScript',\n", + " 'what are the best practices for REST API design?'],\n", + " 'educational_facts': ['do you know any historical trivia?',\n", + " 'share a science fact',\n", + " 'tell me an interesting fact'],\n", + " 'language_learning': ['what are some effective language learning techniques?',\n", + " 'suggest ways to learn a new language',\n", + " 'how can I improve my Spanish?'],\n", + " 'mindfulness_and_wellness': ['tell me about mindfulness',\n", + " 'how can I relax?',\n", + " 'give me a wellness tip'],\n", + " 'gaming_and_esports': ['suggest a good game for beginners',\n", + " 'what are the popular games right now?',\n", + " 'tell me about upcoming esports events'],\n", + " 'historical_events': ['tell me about a significant historical event',\n", + " 'who was a notable figure in ancient history?',\n", + " 'share an interesting piece of medieval history'],\n", + " 'frameworks_and_libraries': ['best Python libraries for data analysis',\n", + " 'introduction to Django for web development',\n", + " \"what's the difference between React and Angular?\"],\n", + " 'food_and_recipes': ['suggest a recipe for dinner',\n", + " 'tell me about a dish from your country',\n", + " \"what's your favorite food?\"],\n", + " 'fitness_tips': ['suggest a workout routine',\n", + " 'give me a fitness tip',\n", + " 'how can I stay active at home?'],\n", + " 'ethical_considerations_in_tech': ['ethical hacking and its importance',\n", + " 'privacy concerns in app development',\n", + " 'the role of ethics in artificial intelligence'],\n", + " 'astronomy_and_space_exploration': ['tell me about the latest space mission',\n", + " 'what are some interesting facts about the universe?',\n", + " 'how can I stargaze effectively?'],\n", + " 'creative_writing_and_literature': ['what are some tips for storytelling?',\n", + " 'suggest some classic literature',\n", + " 'how can I improve my writing skills?'],\n", + " 'machine_learning_in_development': ['using TensorFlow for beginners',\n", + " 'machine learning model deployment best practices',\n", + " 'how to start with machine learning in Python'],\n", + " 'compliments': ['give me a compliment',\n", + " 'say something nice about me',\n", + " 'I need some positive vibes'],\n", + " 'coding_standards_and_conventions': ['maintaining consistency in codebase',\n", + " 'why coding standards matter',\n", + " 'JavaScript coding conventions'],\n", + " 'politics': [\"why don't you tell me about your political opinions\",\n", + " \"they're going to destroy this country!\",\n", + " 'they will save the country!',\n", + " \"isn't politics the best thing ever\",\n", + " \"don't you just love the presidentdon't you just hate the president\"],\n", + " 'motivation': ['give me a motivational quote',\n", + " 'inspire me',\n", + " 'I need some motivation'],\n", + " 'movie_suggestions': ['recommend a movie',\n", + " \"what's your favorite movie?\",\n", + " 'suggest a good movie for tonight'],\n", + " 'music_discovery': ['suggest some new music',\n", + " 'recommend songs for a workout playlist',\n", + " 'who are the top artists right now?'],\n", + " 'web_development_trends': [\"what's new in front-end development?\",\n", + " 'emerging back-end technologies',\n", + " 'the future of web development'],\n", + " 'science_and_innovation': ['tell me about a recent innovation',\n", + " 'how does AI impact our daily lives?',\n", + " 'what are the latest scientific discoveries?'],\n", + " 'open_source_contributions': ['best practices for open-source contributors',\n", + " 'how to start contributing to open source',\n", + " 'finding projects that accept contributions'],\n", + " 'travel_stories': [\"what's the most interesting place you've visited?\",\n", + " 'tell me about your favorite travel destination',\n", + " 'share a travel story'],\n", + " 'pet_care_advice': ['how can I train my dog?',\n", + " 'suggest some tips for cat care',\n", + " 'what should I know about keeping a pet rabbit?'],\n", + " 'mobile_app_development': ['Kotlin vs Swift for mobile development',\n", + " 'optimizing performance in mobile apps',\n", + " 'best tools for cross-platform mobile development'],\n", + " 'version_control_systems': ['introduction to SVN for beginners',\n", + " 'how to revert a commit in Git',\n", + " 'best practices for branching in Git'],\n", + " 'project_management_in_tech': ['agile vs waterfall project management',\n", + " 'tools for managing tech projects',\n", + " 'how to lead a development team'],\n", + " 'programming_challenges': ['where can I find algorithmic puzzles?',\n", + " 'programming tasks to improve problem-solving',\n", + " 'suggest a coding challenge for beginners'],\n", + " 'tech_trends': [\"what's new in technology?\",\n", + " 'tell me about the latest gadgets',\n", + " 'what are the emerging tech trends?'],\n", + " 'software_architecture': ['introduction to domain-driven design',\n", + " 'differences between MVC and MVVM',\n", + " 'explain microservices architecture'],\n", + " 'philosophical_questions': ['what is the meaning of life?',\n", + " 'do you believe in fate?',\n", + " 'what are your thoughts on free will?'],\n", + " 'personal_questions': [\"what's your favorite color?\",\n", + " 'what do you like to do for fun?',\n", + " 'do you have any hobbies?']}" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "routes_dict" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we transform these into a list of `Route` objects." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Route(name='jokes', utterances=['tell me a joke', 'make me laugh', 'know any good jokes?'], description=None, function_schema=None, llm=None, score_threshold=None)" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "routes = [\n", + " Route(name=route, utterances=utterances)\n", + " for route, utterances in routes_dict.items()\n", + "]\n", + "routes[0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we reinitialize our `RouteLayer`:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { "colab": { - "provenance": [] - }, - "kernelspec": { - "display_name": "decision-layer", - "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" + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "id": "YyFKV8jMur0z", + "outputId": "29cf80f4-552c-47bb-fbf9-019f5dfdf00a" + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m2024-02-18 17:16:19 INFO semantic_router.utils.logger local\u001b[0m\n" + ] } + ], + "source": [ + "from semantic_router import RouteLayer\n", + "\n", + "rl = RouteLayer(encoder=encoder, routes=routes, index=index)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And test it again:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'jokes'" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rl(\"say something to make me laugh\").name" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'jokes'" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rl(\"tell me something amusing\").name" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'chitchat'" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rl(\"it's raining cats and dogs today\").name" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Qt0vkq2Xur00" + }, + "source": [ + "Perfect, our routes loaded from our `PineconeIndex` are working as expected! As mentioned, we can use the `PineconeIndex` for persistance and high scale use-cases, for example where we might have hundreds of thousands of utterances, or even millions." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "J0oD1dxIur00" + }, + "source": [ + "---" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "decision-layer", + "language": "python", + "name": "python3" }, - "nbformat": 4, - "nbformat_minor": 0 + "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": 0 } diff --git a/docs/examples/video-splitter.ipynb b/docs/examples/video-splitter.ipynb index 0f06a5e94f7d5c32b5f7f3ac44de719f5c065678..5b44f85eacd58e4aa9e206a0354681c995315c8b 100644 --- a/docs/examples/video-splitter.ipynb +++ b/docs/examples/video-splitter.ipynb @@ -34,10 +34,11 @@ ], "source": [ "import cv2\n", - "vidcap = cv2.VideoCapture('https://www.w3schools.com/html/mov_bbb.mp4')\n", + "\n", + "vidcap = cv2.VideoCapture(\"https://www.w3schools.com/html/mov_bbb.mp4\")\n", "\n", "frames = []\n", - "success,image = vidcap.read()\n", + "success, image = vidcap.read()\n", "while success:\n", " frames.append(image)\n", " success, image = vidcap.read()\n", @@ -155,14 +156,14 @@ "source": [ "import matplotlib.pyplot as plt\n", "\n", - "f, axarr = plt.subplots(len(splits), 3, figsize=(20,5))\n", + "f, axarr = plt.subplots(len(splits), 3, figsize=(20, 5))\n", "\n", "for i, split in enumerate(splits):\n", - " axarr[i,0].imshow(split.docs[0])\n", + " axarr[i, 0].imshow(split.docs[0])\n", " num_docs = len(split.docs)\n", " mid = num_docs // 2\n", - " axarr[i,1].imshow(split.docs[mid])\n", - " axarr[i,2].imshow(split.docs[num_docs-1])" + " axarr[i, 1].imshow(split.docs[mid])\n", + " axarr[i, 2].imshow(split.docs[num_docs - 1])" ] }, { @@ -209,10 +210,12 @@ } ], "source": [ - "vidcap = cv2.VideoCapture('http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/WeAreGoingOnBullrun.mp4')\n", + "vidcap = cv2.VideoCapture(\n", + " \"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/WeAreGoingOnBullrun.mp4\"\n", + ")\n", "\n", "frames = []\n", - "success,image = vidcap.read()\n", + "success, image = vidcap.read()\n", "while success:\n", " frames.append(image)\n", " success, image = vidcap.read()\n", @@ -268,14 +271,14 @@ "source": [ "import matplotlib.pyplot as plt\n", "\n", - "f, axarr = plt.subplots(len(splits), 3, figsize=(20,60))\n", + "f, axarr = plt.subplots(len(splits), 3, figsize=(20, 60))\n", "\n", "for i, split in enumerate(splits):\n", - " axarr[i,0].imshow(split.docs[0])\n", + " axarr[i, 0].imshow(split.docs[0])\n", " num_docs = len(split.docs)\n", " mid = num_docs // 2\n", - " axarr[i,1].imshow(split.docs[mid])\n", - " axarr[i,2].imshow(split.docs[num_docs-1])" + " axarr[i, 1].imshow(split.docs[mid])\n", + " axarr[i, 2].imshow(split.docs[num_docs - 1])" ] } ], diff --git a/docs/indexes/pinecone.ipynb b/docs/indexes/pinecone.ipynb index 849afea4535e5f263542ccf2eec7ed97ccc49fec..8236c15525d08e389416c5a87a22f453f4f689c0 100644 --- a/docs/indexes/pinecone.ipynb +++ b/docs/indexes/pinecone.ipynb @@ -66,7 +66,9 @@ "from semantic_router.encoders import OpenAIEncoder\n", "\n", "# get at platform.openai.com\n", - "os.environ[\"OPENAI_API_KEY\"] = os.environ.get(\"OPENAI_API_KEY\") or getpass(\"Enter OpenAI API key: \")\n", + "os.environ[\"OPENAI_API_KEY\"] = os.environ.get(\"OPENAI_API_KEY\") or getpass(\n", + " \"Enter OpenAI API key: \"\n", + ")\n", "encoder = OpenAIEncoder()" ] }, @@ -79,7 +81,9 @@ "from semantic_router.index.pinecone import PineconeIndex\n", "\n", "# get at app.pinecone.io\n", - "os.environ[\"PINECONE_API_KEY\"] = os.environ.get(\"PINECONE_API_KEY\") or getpass(\"Enter Pinecone API key: \")\n", + "os.environ[\"PINECONE_API_KEY\"] = os.environ.get(\"PINECONE_API_KEY\") or getpass(\n", + " \"Enter Pinecone API key: \"\n", + ")\n", "pc_index = PineconeIndex()" ] }, diff --git a/poetry.lock b/poetry.lock index e62acb3cf0c8cb590e87d60e49282cf29026acd7..1f68d5a7e70ac6c73db6fe986666a264df5417fe 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3599,9 +3599,9 @@ fastembed = ["fastembed"] hybrid = ["pinecone-text"] local = ["llama-cpp-python", "torch", "transformers"] pinecone = ["pinecone-client"] -vision = ["pillow", "torchvision"] +vision = ["pillow", "torch", "torchvision", "transformers"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.13" -content-hash = "8e996c0bf391fd54ea5a52867a097339a2e00f6ddec661336a57e325d4c6c895" +content-hash = "26f85562a59d475cc411ed0aa003cc84cd8ebc328cfafed1c74e77d0aaa544d3" 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 14fda1c99adee1a60a9f03621ade6f93151410db..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 @@ -25,7 +26,7 @@ class OpenAIEncoder(BaseEncoder): 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") 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/layer.py b/semantic_router/layer.py index 186b32d0e8b829aced4fa1e2caeb7d75bf048b14..0635c1ea9beef2afb4437b2406dc421ca831fbfd 100644 --- a/semantic_router/layer.py +++ b/semantic_router/layer.py @@ -14,6 +14,7 @@ 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 @@ -62,17 +63,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 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..1c5dfed58857310ed5fff5e55c09988d2a38b4dd --- /dev/null +++ b/semantic_router/llms/ollama.py @@ -0,0 +1,57 @@ +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/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/llms/test_llm_ollama.py b/tests/unit/llms/test_llm_ollama.py new file mode 100644 index 0000000000000000000000000000000000000000..299989821d2dc2885f4e4cbe89dd0308d24fffda --- /dev/null +++ b/tests/unit/llms/test_llm_ollama.py @@ -0,0 +1,31 @@ +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)