chore: Add vehicle status functionality and update skills package
Browse files- car_assistant_eta.ipynb +0 -0
- car_assistant_slim.ipynb +0 -2
- car_assistant_text.ipynb +60 -67
- skills/__init__.py +3 -2
- skills/common.py +17 -0
- skills/routing.py +93 -49
- skills/vehicle.py +31 -0
car_assistant_eta.ipynb
ADDED
The diff for this file is too large to render.
See raw diff
|
|
car_assistant_slim.ipynb
CHANGED
@@ -19,8 +19,6 @@
|
|
19 |
"name": "stderr",
|
20 |
"output_type": "stream",
|
21 |
"text": [
|
22 |
-
"/opt/homebrew/Caskroom/miniconda/base/envs/llm/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",
|
23 |
-
" from .autonotebook import tqdm as notebook_tqdm\n",
|
24 |
"/opt/homebrew/Caskroom/miniconda/base/envs/llm/lib/python3.11/site-packages/transformers/utils/generic.py:441: UserWarning: torch.utils._pytree._register_pytree_node is deprecated. Please use torch.utils._pytree.register_pytree_node instead.\n",
|
25 |
" _torch_pytree._register_pytree_node(\n",
|
26 |
"/opt/homebrew/Caskroom/miniconda/base/envs/llm/lib/python3.11/site-packages/transformers/utils/generic.py:309: UserWarning: torch.utils._pytree._register_pytree_node is deprecated. Please use torch.utils._pytree.register_pytree_node instead.\n",
|
|
|
19 |
"name": "stderr",
|
20 |
"output_type": "stream",
|
21 |
"text": [
|
|
|
|
|
22 |
"/opt/homebrew/Caskroom/miniconda/base/envs/llm/lib/python3.11/site-packages/transformers/utils/generic.py:441: UserWarning: torch.utils._pytree._register_pytree_node is deprecated. Please use torch.utils._pytree.register_pytree_node instead.\n",
|
23 |
" _torch_pytree._register_pytree_node(\n",
|
24 |
"/opt/homebrew/Caskroom/miniconda/base/envs/llm/lib/python3.11/site-packages/transformers/utils/generic.py:309: UserWarning: torch.utils._pytree._register_pytree_node is deprecated. Please use torch.utils._pytree.register_pytree_node instead.\n",
|
car_assistant_text.ipynb
CHANGED
@@ -9,7 +9,7 @@
|
|
9 |
},
|
10 |
{
|
11 |
"cell_type": "code",
|
12 |
-
"execution_count":
|
13 |
"metadata": {
|
14 |
"collapsed": true,
|
15 |
"id": "oOnNfKjX4IAV"
|
@@ -116,7 +116,7 @@
|
|
116 |
},
|
117 |
{
|
118 |
"cell_type": "code",
|
119 |
-
"execution_count":
|
120 |
"metadata": {},
|
121 |
"outputs": [],
|
122 |
"source": [
|
@@ -128,7 +128,7 @@
|
|
128 |
},
|
129 |
{
|
130 |
"cell_type": "code",
|
131 |
-
"execution_count":
|
132 |
"metadata": {},
|
133 |
"outputs": [],
|
134 |
"source": [
|
@@ -137,7 +137,7 @@
|
|
137 |
},
|
138 |
{
|
139 |
"cell_type": "code",
|
140 |
-
"execution_count":
|
141 |
"metadata": {},
|
142 |
"outputs": [
|
143 |
{
|
@@ -153,7 +153,7 @@
|
|
153 |
"'Dry run successful'"
|
154 |
]
|
155 |
},
|
156 |
-
"execution_count":
|
157 |
"metadata": {},
|
158 |
"output_type": "execute_result"
|
159 |
}
|
@@ -171,7 +171,7 @@
|
|
171 |
},
|
172 |
{
|
173 |
"cell_type": "code",
|
174 |
-
"execution_count":
|
175 |
"metadata": {},
|
176 |
"outputs": [],
|
177 |
"source": [
|
@@ -710,7 +710,7 @@
|
|
710 |
"source": [
|
711 |
"import langchain\n",
|
712 |
"langchain.debug=False\n",
|
713 |
-
"from skills import get_weather, find_route, get_forecast"
|
714 |
]
|
715 |
},
|
716 |
{
|
@@ -777,14 +777,10 @@
|
|
777 |
"tools = [\n",
|
778 |
" StructuredTool.from_function(get_weather),\n",
|
779 |
" StructuredTool.from_function(find_route),\n",
|
|
|
780 |
"]"
|
781 |
]
|
782 |
},
|
783 |
-
{
|
784 |
-
"cell_type": "markdown",
|
785 |
-
"metadata": {},
|
786 |
-
"source": []
|
787 |
-
},
|
788 |
{
|
789 |
"cell_type": "code",
|
790 |
"execution_count": 5,
|
@@ -796,47 +792,37 @@
|
|
796 |
},
|
797 |
{
|
798 |
"cell_type": "code",
|
799 |
-
"execution_count":
|
800 |
"metadata": {},
|
801 |
"outputs": [],
|
802 |
"source": [
|
803 |
-
"RAVEN_PROMPT_FUNC = \"\"\"You are a
|
804 |
-
"{raven_tools}\n",
|
805 |
"\n",
|
806 |
-
"
|
807 |
-
"{status}\n",
|
808 |
"\n",
|
809 |
"Previous conversation history:\n",
|
810 |
"{history}\n",
|
811 |
"\n",
|
812 |
-
"User Query: Question: {input}
|
813 |
-
"\n",
|
814 |
-
"If it helps to answer the question please pick a function from the above options that best answers the user query and fill in the appropriate arguments.<human_end>\"\"\"\n",
|
815 |
"\n",
|
816 |
"RAVEN_PROMPT_ANS = \"\"\"\n",
|
817 |
"<human>\n",
|
818 |
"You are a useful AI assistant in a car, that follows instructions extremely well. Help as much as you can. Answer questions concisely and do not mention what you base your reply on.\n",
|
819 |
"\n",
|
820 |
-
"Current status of the vehicle:\n",
|
821 |
-
"{status}\n",
|
822 |
-
"\n",
|
823 |
"Previous conversation history:\n",
|
824 |
"{history}\n",
|
825 |
"\n",
|
826 |
-
"User Query: Question: {input}\n",
|
827 |
-
"\n",
|
828 |
"Observation:{observation}\n",
|
829 |
"\n",
|
830 |
-
"
|
|
|
|
|
831 |
"\n",
|
832 |
"Answer: \"\"\"\n",
|
833 |
"\n",
|
834 |
"\n",
|
835 |
-
"STATUS_TEMPLATE = \"\"\"\n",
|
836 |
-
"car coordinates: lat:{lat}, lon:{lon}\n",
|
837 |
-
"current time: {time}\n",
|
838 |
-
"current date: {date}\n",
|
839 |
-
"destination: {destination}\n",
|
840 |
"\"\"\"\n",
|
841 |
"status_prompt = PromptTemplate.from_template(STATUS_TEMPLATE)\n",
|
842 |
"\n",
|
@@ -862,13 +848,13 @@
|
|
862 |
" pp = self.template_ans.format(**kwargs).replace(\"{{\", \"{\").replace(\"}}\", \"}\")\n",
|
863 |
" return pp\n",
|
864 |
"\n",
|
865 |
-
" if \"status\" in kwargs:\n",
|
866 |
-
"
|
867 |
"\n",
|
868 |
" prompt = \"<human>:\\n\"\n",
|
869 |
" for tool in self.tools:\n",
|
870 |
" func_signature, func_docstring = tool.description.split(\" - \", 1)\n",
|
871 |
-
" prompt += f'
|
872 |
" kwargs[\"raven_tools\"] = prompt\n",
|
873 |
" pp = self.template_func.format(**kwargs).replace(\"{{\", \"{\").replace(\"}}\", \"}\")\n",
|
874 |
" return pp\n",
|
@@ -879,13 +865,13 @@
|
|
879 |
" template_ans=RAVEN_PROMPT_ANS,\n",
|
880 |
" status_prompt=status_prompt,\n",
|
881 |
" tools=tools,\n",
|
882 |
-
" input_variables=[\"input\", \"
|
883 |
")"
|
884 |
]
|
885 |
},
|
886 |
{
|
887 |
"cell_type": "code",
|
888 |
-
"execution_count":
|
889 |
"metadata": {},
|
890 |
"outputs": [],
|
891 |
"source": [
|
@@ -895,7 +881,7 @@
|
|
895 |
},
|
896 |
{
|
897 |
"cell_type": "code",
|
898 |
-
"execution_count":
|
899 |
"metadata": {},
|
900 |
"outputs": [],
|
901 |
"source": [
|
@@ -916,7 +902,7 @@
|
|
916 |
},
|
917 |
{
|
918 |
"cell_type": "code",
|
919 |
-
"execution_count":
|
920 |
"metadata": {},
|
921 |
"outputs": [],
|
922 |
"source": [
|
@@ -925,18 +911,19 @@
|
|
925 |
},
|
926 |
{
|
927 |
"cell_type": "code",
|
928 |
-
"execution_count":
|
929 |
"metadata": {},
|
930 |
"outputs": [
|
931 |
{
|
932 |
-
"
|
933 |
-
|
934 |
-
|
935 |
-
|
936 |
-
|
937 |
-
|
938 |
-
|
939 |
-
|
|
|
940 |
}
|
941 |
],
|
942 |
"source": [
|
@@ -945,7 +932,7 @@
|
|
945 |
},
|
946 |
{
|
947 |
"cell_type": "code",
|
948 |
-
"execution_count":
|
949 |
"metadata": {},
|
950 |
"outputs": [],
|
951 |
"source": [
|
@@ -963,7 +950,7 @@
|
|
963 |
},
|
964 |
{
|
965 |
"cell_type": "code",
|
966 |
-
"execution_count":
|
967 |
"metadata": {},
|
968 |
"outputs": [
|
969 |
{
|
@@ -973,16 +960,14 @@
|
|
973 |
"\n",
|
974 |
"\n",
|
975 |
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
|
976 |
-
"kwargs: {'input': '
|
977 |
-
"llm_output:
|
978 |
-
"
|
979 |
-
"\u001b[32;1m\u001b[1;3mCalling get_weather with args: {'location': 'Luxembourg'}\u001b[0mhttp://api.weatherapi.com/v1/current.json?key=d1c4d0d8ef6847339a0125737240903&q=Luxembourg&aqi=no\n",
|
980 |
-
"\n",
|
981 |
"\n",
|
982 |
-
"Reflection:\u001b[
|
983 |
-
"kwargs: {'input': '
|
984 |
-
"llm_output: The
|
985 |
-
"\u001b[32;1m\u001b[1;3mThe
|
986 |
"\n",
|
987 |
"\u001b[1m> Finished chain.\u001b[0m\n"
|
988 |
]
|
@@ -990,11 +975,20 @@
|
|
990 |
],
|
991 |
"source": [
|
992 |
"call = agent_chain.run(\n",
|
993 |
-
" input=\"
|
994 |
-
" status= status\n",
|
995 |
")"
|
996 |
]
|
997 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
998 |
{
|
999 |
"cell_type": "code",
|
1000 |
"execution_count": 93,
|
@@ -1085,7 +1079,7 @@
|
|
1085 |
},
|
1086 |
{
|
1087 |
"cell_type": "code",
|
1088 |
-
"execution_count":
|
1089 |
"metadata": {},
|
1090 |
"outputs": [
|
1091 |
{
|
@@ -1095,10 +1089,9 @@
|
|
1095 |
"\n",
|
1096 |
"\n",
|
1097 |
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
|
1098 |
-
"kwargs: {'input': '
|
1099 |
-
"llm_output:
|
1100 |
-
"
|
1101 |
-
"\u001b[32;1m\u001b[1;3mCalling find_route with args: {'city_depart': 'Luxembourg', 'address_destination': ['Kirchberg, Luxembourg']}\u001b[0m['Kirchberg, Luxembourg']\n"
|
1102 |
]
|
1103 |
},
|
1104 |
{
|
@@ -1108,7 +1101,7 @@
|
|
1108 |
"traceback": [
|
1109 |
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
1110 |
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
|
1111 |
-
"Cell \u001b[0;32mIn[
|
1112 |
"File \u001b[0;32m/opt/homebrew/Caskroom/miniconda/base/envs/llm/lib/python3.11/site-packages/langchain_core/_api/deprecation.py:145\u001b[0m, in \u001b[0;36mdeprecated.<locals>.deprecate.<locals>.warning_emitting_wrapper\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 143\u001b[0m warned \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m 144\u001b[0m emit_warning()\n\u001b[0;32m--> 145\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mwrapped\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
|
1113 |
"File \u001b[0;32m/opt/homebrew/Caskroom/miniconda/base/envs/llm/lib/python3.11/site-packages/langchain/chains/base.py:550\u001b[0m, in \u001b[0;36mChain.run\u001b[0;34m(self, callbacks, tags, metadata, *args, **kwargs)\u001b[0m\n\u001b[1;32m 545\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m(args[\u001b[38;5;241m0\u001b[39m], callbacks\u001b[38;5;241m=\u001b[39mcallbacks, tags\u001b[38;5;241m=\u001b[39mtags, metadata\u001b[38;5;241m=\u001b[39mmetadata)[\n\u001b[1;32m 546\u001b[0m _output_key\n\u001b[1;32m 547\u001b[0m ]\n\u001b[1;32m 549\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m kwargs \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m args:\n\u001b[0;32m--> 550\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcallbacks\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcallbacks\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtags\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtags\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmetadata\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmetadata\u001b[49m\u001b[43m)\u001b[49m[\n\u001b[1;32m 551\u001b[0m _output_key\n\u001b[1;32m 552\u001b[0m ]\n\u001b[1;32m 554\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m kwargs \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m args:\n\u001b[1;32m 555\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 556\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m`run` supported with either positional arguments or keyword arguments,\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 557\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m but none were provided.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 558\u001b[0m )\n",
|
1114 |
"File \u001b[0;32m/opt/homebrew/Caskroom/miniconda/base/envs/llm/lib/python3.11/site-packages/langchain_core/_api/deprecation.py:145\u001b[0m, in \u001b[0;36mdeprecated.<locals>.deprecate.<locals>.warning_emitting_wrapper\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 143\u001b[0m warned \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m 144\u001b[0m emit_warning()\n\u001b[0;32m--> 145\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mwrapped\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
|
@@ -1130,7 +1123,7 @@
|
|
1130 |
],
|
1131 |
"source": [
|
1132 |
"call = agent_chain.run(\n",
|
1133 |
-
" input=\"
|
1134 |
" status= status\n",
|
1135 |
")"
|
1136 |
]
|
|
|
9 |
},
|
10 |
{
|
11 |
"cell_type": "code",
|
12 |
+
"execution_count": 2,
|
13 |
"metadata": {
|
14 |
"collapsed": true,
|
15 |
"id": "oOnNfKjX4IAV"
|
|
|
116 |
},
|
117 |
{
|
118 |
"cell_type": "code",
|
119 |
+
"execution_count": 7,
|
120 |
"metadata": {},
|
121 |
"outputs": [],
|
122 |
"source": [
|
|
|
128 |
},
|
129 |
{
|
130 |
"cell_type": "code",
|
131 |
+
"execution_count": 8,
|
132 |
"metadata": {},
|
133 |
"outputs": [],
|
134 |
"source": [
|
|
|
137 |
},
|
138 |
{
|
139 |
"cell_type": "code",
|
140 |
+
"execution_count": 9,
|
141 |
"metadata": {},
|
142 |
"outputs": [
|
143 |
{
|
|
|
153 |
"'Dry run successful'"
|
154 |
]
|
155 |
},
|
156 |
+
"execution_count": 9,
|
157 |
"metadata": {},
|
158 |
"output_type": "execute_result"
|
159 |
}
|
|
|
171 |
},
|
172 |
{
|
173 |
"cell_type": "code",
|
174 |
+
"execution_count": 10,
|
175 |
"metadata": {},
|
176 |
"outputs": [],
|
177 |
"source": [
|
|
|
710 |
"source": [
|
711 |
"import langchain\n",
|
712 |
"langchain.debug=False\n",
|
713 |
+
"from skills import get_weather, find_route, get_forecast, vehicle_status, vehicle"
|
714 |
]
|
715 |
},
|
716 |
{
|
|
|
777 |
"tools = [\n",
|
778 |
" StructuredTool.from_function(get_weather),\n",
|
779 |
" StructuredTool.from_function(find_route),\n",
|
780 |
+
" StructuredTool.from_function(vehicle_status),\n",
|
781 |
"]"
|
782 |
]
|
783 |
},
|
|
|
|
|
|
|
|
|
|
|
784 |
{
|
785 |
"cell_type": "code",
|
786 |
"execution_count": 5,
|
|
|
792 |
},
|
793 |
{
|
794 |
"cell_type": "code",
|
795 |
+
"execution_count": 16,
|
796 |
"metadata": {},
|
797 |
"outputs": [],
|
798 |
"source": [
|
799 |
+
"RAVEN_PROMPT_FUNC = \"\"\"You are a helpful AI assistant in a car (vehicle), that follows instructions extremely well. You are aware of car's location through status information and take that into account before responding. Answer questions concisely and do not mention what you base your reply on.\"\n",
|
|
|
800 |
"\n",
|
801 |
+
"{raven_tools}\n",
|
|
|
802 |
"\n",
|
803 |
"Previous conversation history:\n",
|
804 |
"{history}\n",
|
805 |
"\n",
|
806 |
+
"User Query: Question: {input}<human_end>\n",
|
807 |
+
"\"\"\"\n",
|
|
|
808 |
"\n",
|
809 |
"RAVEN_PROMPT_ANS = \"\"\"\n",
|
810 |
"<human>\n",
|
811 |
"You are a useful AI assistant in a car, that follows instructions extremely well. Help as much as you can. Answer questions concisely and do not mention what you base your reply on.\n",
|
812 |
"\n",
|
|
|
|
|
|
|
813 |
"Previous conversation history:\n",
|
814 |
"{history}\n",
|
815 |
"\n",
|
|
|
|
|
816 |
"Observation:{observation}\n",
|
817 |
"\n",
|
818 |
+
"User Query: Question: {input}\n",
|
819 |
+
"\n",
|
820 |
+
"Please respond in natural language. Do not refer to the provided context and observation in your response.<human_end>\n",
|
821 |
"\n",
|
822 |
"Answer: \"\"\"\n",
|
823 |
"\n",
|
824 |
"\n",
|
825 |
+
"STATUS_TEMPLATE = \"\"\"We are at these geo coordinates: lat:{lat}, lon:{lon}, current time: {time}, current date: {date} and our destination is: {destination}\n",
|
|
|
|
|
|
|
|
|
826 |
"\"\"\"\n",
|
827 |
"status_prompt = PromptTemplate.from_template(STATUS_TEMPLATE)\n",
|
828 |
"\n",
|
|
|
848 |
" pp = self.template_ans.format(**kwargs).replace(\"{{\", \"{\").replace(\"}}\", \"}\")\n",
|
849 |
" return pp\n",
|
850 |
"\n",
|
851 |
+
" # if \"status\" in kwargs:\n",
|
852 |
+
" # kwargs[\"status\"] = self.status_prompt.format(**kwargs[\"status\"])\n",
|
853 |
"\n",
|
854 |
" prompt = \"<human>:\\n\"\n",
|
855 |
" for tool in self.tools:\n",
|
856 |
" func_signature, func_docstring = tool.description.split(\" - \", 1)\n",
|
857 |
+
" prompt += f'Function:\\n<func_start>def {func_signature}<func_end>\\n<docstring_start>\\n\"\"\"\\n{func_docstring}\\n\"\"\"\\n<docstring_end>\\n'\n",
|
858 |
" kwargs[\"raven_tools\"] = prompt\n",
|
859 |
" pp = self.template_func.format(**kwargs).replace(\"{{\", \"{\").replace(\"}}\", \"}\")\n",
|
860 |
" return pp\n",
|
|
|
865 |
" template_ans=RAVEN_PROMPT_ANS,\n",
|
866 |
" status_prompt=status_prompt,\n",
|
867 |
" tools=tools,\n",
|
868 |
+
" input_variables=[\"input\", \"history\", \"intermediate_steps\"],\n",
|
869 |
")"
|
870 |
]
|
871 |
},
|
872 |
{
|
873 |
"cell_type": "code",
|
874 |
+
"execution_count": 17,
|
875 |
"metadata": {},
|
876 |
"outputs": [],
|
877 |
"source": [
|
|
|
881 |
},
|
882 |
{
|
883 |
"cell_type": "code",
|
884 |
+
"execution_count": 18,
|
885 |
"metadata": {},
|
886 |
"outputs": [],
|
887 |
"source": [
|
|
|
902 |
},
|
903 |
{
|
904 |
"cell_type": "code",
|
905 |
+
"execution_count": 19,
|
906 |
"metadata": {},
|
907 |
"outputs": [],
|
908 |
"source": [
|
|
|
911 |
},
|
912 |
{
|
913 |
"cell_type": "code",
|
914 |
+
"execution_count": 1,
|
915 |
"metadata": {},
|
916 |
"outputs": [
|
917 |
{
|
918 |
+
"ename": "NameError",
|
919 |
+
"evalue": "name 'agent_chain' is not defined",
|
920 |
+
"output_type": "error",
|
921 |
+
"traceback": [
|
922 |
+
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
923 |
+
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
|
924 |
+
"Cell \u001b[0;32mIn[1], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43magent_chain\u001b[49m\n",
|
925 |
+
"\u001b[0;31mNameError\u001b[0m: name 'agent_chain' is not defined"
|
926 |
+
]
|
927 |
}
|
928 |
],
|
929 |
"source": [
|
|
|
932 |
},
|
933 |
{
|
934 |
"cell_type": "code",
|
935 |
+
"execution_count": 21,
|
936 |
"metadata": {},
|
937 |
"outputs": [],
|
938 |
"source": [
|
|
|
950 |
},
|
951 |
{
|
952 |
"cell_type": "code",
|
953 |
+
"execution_count": 22,
|
954 |
"metadata": {},
|
955 |
"outputs": [
|
956 |
{
|
|
|
960 |
"\n",
|
961 |
"\n",
|
962 |
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
|
963 |
+
"kwargs: {'input': \"What's our current location?\", 'history': '', 'intermediate_steps': []}\n",
|
964 |
+
"llm_output: Call: vehicle_status(prompt='Question: What is our current location?') \n",
|
965 |
+
"\u001b[32;1m\u001b[1;3mCalling vehicle_status with args: {'prompt': 'Question: What is our current location?'}\u001b[0m\n",
|
|
|
|
|
966 |
"\n",
|
967 |
+
"Reflection:\u001b[38;5;200m\u001b[1;3m('We are at Mondorf-les-Bains, Luxembourg, current time: 08:00:20, current date: 2025-03-29 and our destination is: Kirchberg Campus, Kirchberg.\\n', {'location': 'Mondorf-les-Bains, Luxembourg', 'date': '2025-03-29', 'time': '08:00:20', 'destination': 'Kirchberg Campus, Kirchberg'})\u001b[0m\n",
|
968 |
+
"kwargs: {'input': \"What's our current location?\", 'history': '', 'intermediate_steps': [(AgentAction(tool='vehicle_status', tool_input={'prompt': 'Question: What is our current location?'}, log=\"Calling vehicle_status with args: {'prompt': 'Question: What is our current location?'}\"), ('We are at Mondorf-les-Bains, Luxembourg, current time: 08:00:20, current date: 2025-03-29 and our destination is: Kirchberg Campus, Kirchberg.\\n', {'location': 'Mondorf-les-Bains, Luxembourg', 'date': '2025-03-29', 'time': '08:00:20', 'destination': 'Kirchberg Campus, Kirchberg'}))]}\n",
|
969 |
+
"llm_output: The current location of the car is the location that was last observed by the user, which is \"Mondorf-les-Bains, Luxembourg\".\n",
|
970 |
+
"\u001b[32;1m\u001b[1;3mThe current location of the car is the location that was last observed by the user, which is \"Mondorf-les-Bains, Luxembourg\".\u001b[0m\n",
|
971 |
"\n",
|
972 |
"\u001b[1m> Finished chain.\u001b[0m\n"
|
973 |
]
|
|
|
975 |
],
|
976 |
"source": [
|
977 |
"call = agent_chain.run(\n",
|
978 |
+
" input=\"What's our current location?\",\n",
|
979 |
+
" # status= status\n",
|
980 |
")"
|
981 |
]
|
982 |
},
|
983 |
+
{
|
984 |
+
"cell_type": "code",
|
985 |
+
"execution_count": 23,
|
986 |
+
"metadata": {},
|
987 |
+
"outputs": [],
|
988 |
+
"source": [
|
989 |
+
"vehicle.vehicle.location = \"Mondorf-les-Bains, Luxembourg\""
|
990 |
+
]
|
991 |
+
},
|
992 |
{
|
993 |
"cell_type": "code",
|
994 |
"execution_count": 93,
|
|
|
1079 |
},
|
1080 |
{
|
1081 |
"cell_type": "code",
|
1082 |
+
"execution_count": 67,
|
1083 |
"metadata": {},
|
1084 |
"outputs": [
|
1085 |
{
|
|
|
1089 |
"\n",
|
1090 |
"\n",
|
1091 |
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
|
1092 |
+
"kwargs: {'input': \"What's our destination?\", 'status': {'date': '2024-05-02', 'time': '15:53:47', 'destination': 'Kirchberg, Luxembourg', 'lat': '48.8566', 'lon': '2.3522'}, 'history': '', 'intermediate_steps': []}\n",
|
1093 |
+
"llm_output: Call: find_route(city_depart='Kirchberg', address_destination='Luxembourg') \n",
|
1094 |
+
"\u001b[32;1m\u001b[1;3mCalling find_route with args: {'city_depart': 'Kirchberg', 'address_destination': 'Luxembourg'}\u001b[0mLuxembourg\n"
|
|
|
1095 |
]
|
1096 |
},
|
1097 |
{
|
|
|
1101 |
"traceback": [
|
1102 |
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
1103 |
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
|
1104 |
+
"Cell \u001b[0;32mIn[67], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m call \u001b[38;5;241m=\u001b[39m \u001b[43magent_chain\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 2\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mWhat\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43ms our destination?\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 3\u001b[0m \u001b[43m \u001b[49m\u001b[43mstatus\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mstatus\u001b[49m\n\u001b[1;32m 4\u001b[0m \u001b[43m)\u001b[49m\n",
|
1105 |
"File \u001b[0;32m/opt/homebrew/Caskroom/miniconda/base/envs/llm/lib/python3.11/site-packages/langchain_core/_api/deprecation.py:145\u001b[0m, in \u001b[0;36mdeprecated.<locals>.deprecate.<locals>.warning_emitting_wrapper\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 143\u001b[0m warned \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m 144\u001b[0m emit_warning()\n\u001b[0;32m--> 145\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mwrapped\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
|
1106 |
"File \u001b[0;32m/opt/homebrew/Caskroom/miniconda/base/envs/llm/lib/python3.11/site-packages/langchain/chains/base.py:550\u001b[0m, in \u001b[0;36mChain.run\u001b[0;34m(self, callbacks, tags, metadata, *args, **kwargs)\u001b[0m\n\u001b[1;32m 545\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m(args[\u001b[38;5;241m0\u001b[39m], callbacks\u001b[38;5;241m=\u001b[39mcallbacks, tags\u001b[38;5;241m=\u001b[39mtags, metadata\u001b[38;5;241m=\u001b[39mmetadata)[\n\u001b[1;32m 546\u001b[0m _output_key\n\u001b[1;32m 547\u001b[0m ]\n\u001b[1;32m 549\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m kwargs \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m args:\n\u001b[0;32m--> 550\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcallbacks\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcallbacks\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtags\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtags\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmetadata\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmetadata\u001b[49m\u001b[43m)\u001b[49m[\n\u001b[1;32m 551\u001b[0m _output_key\n\u001b[1;32m 552\u001b[0m ]\n\u001b[1;32m 554\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m kwargs \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m args:\n\u001b[1;32m 555\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 556\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m`run` supported with either positional arguments or keyword arguments,\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 557\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m but none were provided.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 558\u001b[0m )\n",
|
1107 |
"File \u001b[0;32m/opt/homebrew/Caskroom/miniconda/base/envs/llm/lib/python3.11/site-packages/langchain_core/_api/deprecation.py:145\u001b[0m, in \u001b[0;36mdeprecated.<locals>.deprecate.<locals>.warning_emitting_wrapper\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 143\u001b[0m warned \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m 144\u001b[0m emit_warning()\n\u001b[0;32m--> 145\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mwrapped\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
|
|
|
1123 |
],
|
1124 |
"source": [
|
1125 |
"call = agent_chain.run(\n",
|
1126 |
+
" input=\"What's our destination?\",\n",
|
1127 |
" status= status\n",
|
1128 |
")"
|
1129 |
]
|
skills/__init__.py
CHANGED
@@ -1,8 +1,9 @@
|
|
1 |
import inspect
|
2 |
|
3 |
-
from .common import execute_function_call, extract_func_args
|
4 |
from .weather import get_weather, get_forecast
|
5 |
from .routing import find_route
|
|
|
6 |
|
7 |
|
8 |
def format_functions_for_prompt_raven(*functions):
|
@@ -16,7 +17,7 @@ def format_functions_for_prompt_raven(*functions):
|
|
16 |
signature = f"{func.__name__}{inspect.signature(func)}"
|
17 |
docstring = inspect.getdoc(func)
|
18 |
formatted_functions.append(
|
19 |
-
f"
|
20 |
)
|
21 |
return "\n".join(formatted_functions)
|
22 |
|
|
|
1 |
import inspect
|
2 |
|
3 |
+
from .common import execute_function_call, extract_func_args, vehicle
|
4 |
from .weather import get_weather, get_forecast
|
5 |
from .routing import find_route
|
6 |
+
from .vehicle import vehicle_status
|
7 |
|
8 |
|
9 |
def format_functions_for_prompt_raven(*functions):
|
|
|
17 |
signature = f"{func.__name__}{inspect.signature(func)}"
|
18 |
docstring = inspect.getdoc(func)
|
19 |
formatted_functions.append(
|
20 |
+
f"Function:\n<func_start>{signature}<func_end>\n<docstring_start>\n{docstring}\n<docstring_end>"
|
21 |
)
|
22 |
return "\n".join(formatted_functions)
|
23 |
|
skills/common.py
CHANGED
@@ -3,6 +3,7 @@ from typing import Union
|
|
3 |
|
4 |
|
5 |
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
|
6 |
|
7 |
import skills
|
8 |
|
@@ -13,6 +14,14 @@ class Settings(BaseSettings):
|
|
13 |
model_config = SettingsConfigDict(env_file=".env")
|
14 |
|
15 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
def execute_function_call(text: str, dry_run=False) -> str:
|
17 |
function_name_match = re.search(r"Call: (\w+)", text)
|
18 |
function_name = function_name_match.group(1) if function_name_match else None
|
@@ -43,3 +52,11 @@ def extract_func_args(text: str) -> tuple[str, dict]:
|
|
43 |
|
44 |
|
45 |
config = Settings() # type: ignore
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
|
4 |
|
5 |
from pydantic_settings import BaseSettings, SettingsConfigDict
|
6 |
+
from pydantic import BaseModel
|
7 |
|
8 |
import skills
|
9 |
|
|
|
14 |
model_config = SettingsConfigDict(env_file=".env")
|
15 |
|
16 |
|
17 |
+
class VehicleStatus(BaseModel):
|
18 |
+
location: str
|
19 |
+
location_coordinates: tuple[float, float] # (latitude, longitude)
|
20 |
+
date: str
|
21 |
+
time: str
|
22 |
+
destination: str
|
23 |
+
|
24 |
+
|
25 |
def execute_function_call(text: str, dry_run=False) -> str:
|
26 |
function_name_match = re.search(r"Call: (\w+)", text)
|
27 |
function_name = function_name_match.group(1) if function_name_match else None
|
|
|
52 |
|
53 |
|
54 |
config = Settings() # type: ignore
|
55 |
+
|
56 |
+
vehicle = VehicleStatus(
|
57 |
+
location="Luxembourg Gare, Luxembourg",
|
58 |
+
location_coordinates=(49.6002, 6.1296),
|
59 |
+
date="2025-03-29",
|
60 |
+
time="08:00:20",
|
61 |
+
destination="Kirchberg Campus, Kirchberg"
|
62 |
+
)
|
skills/routing.py
CHANGED
@@ -1,3 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
def calculate_route():
|
2 |
api_key = "api_key"
|
3 |
origin = "49.631997,6.171029"
|
@@ -10,82 +30,106 @@ def calculate_route():
|
|
10 |
lats = []
|
11 |
lons = []
|
12 |
|
13 |
-
for point in data[
|
14 |
-
lats.append(point[
|
15 |
-
lons.append(point[
|
16 |
# fig = px.line_geo(lat=lats, lon=lons)
|
17 |
# fig.update_geos(fitbounds="locations")
|
18 |
|
19 |
fig = px.line_mapbox(lat=lats, lon=lons, zoom=12, height=600)
|
20 |
|
21 |
-
fig.update_layout(
|
22 |
-
|
|
|
|
|
|
|
|
|
|
|
23 |
|
24 |
return fig
|
25 |
|
26 |
|
27 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
"""
|
29 |
Return the distance and the estimated time to go to a specific destination from the current place, at a specified depart time.
|
30 |
:param lat_depart (string): latitude of depart
|
31 |
:param lon_depart (string): longitude of depart
|
32 |
-
:param
|
33 |
-
:param
|
34 |
:param depart_time (string): departure hour, in the format '08:00:20'.
|
35 |
"""
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
#print(lat_dest, lon_dest)
|
42 |
-
|
43 |
-
#print(departure_time)
|
44 |
-
|
45 |
-
r = requests.get('https://api.tomtom.com/routing/1/calculateRoute/{0},{1}:{2},{3}/json?key={4}&departAt={5}'.format(
|
46 |
-
lat_depart,
|
47 |
-
lon_depart,
|
48 |
-
lat_dest,
|
49 |
-
lon_dest,
|
50 |
-
TOMTOM_KEY,
|
51 |
-
departure_time
|
52 |
-
))
|
53 |
|
54 |
# Parse JSON from the response
|
55 |
-
|
56 |
-
#print(data)
|
57 |
-
|
58 |
-
#print(data)
|
59 |
-
|
60 |
-
result = data['routes'][0]['summary']
|
61 |
|
62 |
-
|
63 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
# Calculate travel time in minutes (1 second = 1/60 minutes)
|
66 |
-
time_minutes =
|
67 |
if time_minutes < 60:
|
68 |
time_display = f"{time_minutes:.0f} minutes"
|
69 |
else:
|
70 |
hours = int(time_minutes / 60)
|
71 |
minutes = int(time_minutes % 60)
|
72 |
-
time_display = f"{hours} hours" + (
|
73 |
-
|
74 |
-
|
75 |
-
arrival_time_str = result['arrivalTime']
|
76 |
-
|
77 |
-
# Convert string to datetime object
|
78 |
-
arrival_time = datetime.fromisoformat(arrival_time_str)
|
79 |
|
80 |
# Extract and display the arrival hour in HH:MM format
|
81 |
arrival_hour_display = arrival_time.strftime("%H:%M")
|
82 |
|
83 |
-
|
84 |
# return the distance and time
|
85 |
-
return
|
86 |
-
|
87 |
-
|
88 |
-
# Sort the results based on distance
|
89 |
-
#sorted_results = sorted(results, key=lambda x: x['dist'])
|
90 |
-
|
91 |
-
#return ". ".join(formatted_results)
|
|
|
1 |
+
from datetime import datetime
|
2 |
+
|
3 |
+
import requests
|
4 |
+
|
5 |
+
from .common import config, vehicle
|
6 |
+
|
7 |
+
|
8 |
+
def find_coordinates(address):
|
9 |
+
"""
|
10 |
+
Find the coordinates of a specific address.
|
11 |
+
:param address (string): Required. The address
|
12 |
+
"""
|
13 |
+
url = f"https://api.tomtom.com/search/2/geocode/{address}.json?key={config.TOMTOM_API_KEY}"
|
14 |
+
response = requests.get(url)
|
15 |
+
data = response.json()
|
16 |
+
lat = data["results"][0]["position"]["lat"]
|
17 |
+
lon = data["results"][0]["position"]["lon"]
|
18 |
+
return lat, lon
|
19 |
+
|
20 |
+
|
21 |
def calculate_route():
|
22 |
api_key = "api_key"
|
23 |
origin = "49.631997,6.171029"
|
|
|
30 |
lats = []
|
31 |
lons = []
|
32 |
|
33 |
+
for point in data["routes"][0]["legs"][0]["points"]:
|
34 |
+
lats.append(point["latitude"])
|
35 |
+
lons.append(point["longitude"])
|
36 |
# fig = px.line_geo(lat=lats, lon=lons)
|
37 |
# fig.update_geos(fitbounds="locations")
|
38 |
|
39 |
fig = px.line_mapbox(lat=lats, lon=lons, zoom=12, height=600)
|
40 |
|
41 |
+
fig.update_layout(
|
42 |
+
mapbox_style="open-street-map",
|
43 |
+
mapbox_zoom=12,
|
44 |
+
mapbox_center_lat=lats[0],
|
45 |
+
mapbox_center_lon=lons[0],
|
46 |
+
)
|
47 |
+
fig.update_layout(margin={"r": 0, "t": 0, "l": 0, "b": 0})
|
48 |
|
49 |
return fig
|
50 |
|
51 |
|
52 |
+
def find_route_tomtom(
|
53 |
+
lat_depart="0",
|
54 |
+
lon_depart="0",
|
55 |
+
lat_dest="0",
|
56 |
+
lon_dest="0",
|
57 |
+
depart_datetime="",
|
58 |
+
**kwargs,
|
59 |
+
):
|
60 |
"""
|
61 |
Return the distance and the estimated time to go to a specific destination from the current place, at a specified depart time.
|
62 |
:param lat_depart (string): latitude of depart
|
63 |
:param lon_depart (string): longitude of depart
|
64 |
+
:param lat_dest (string): latitude of destination
|
65 |
+
:param lon_dest (string): longitude of destination
|
66 |
:param depart_time (string): departure hour, in the format '08:00:20'.
|
67 |
"""
|
68 |
+
|
69 |
+
r = requests.get(
|
70 |
+
f"https://api.tomtom.com/routing/1/calculateRoute/{lat_depart},{lon_depart}:{lat_dest},{lon_dest}/json?key={config.TOMTOM_API_KEY}&departAt={depart_datetime}",
|
71 |
+
timeout=5,
|
72 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
|
74 |
# Parse JSON from the response
|
75 |
+
response = r.json()
|
|
|
|
|
|
|
|
|
|
|
76 |
|
77 |
+
result = response["routes"][0]["summary"]
|
78 |
+
|
79 |
+
|
80 |
+
|
81 |
+
distance_m = result["lengthInMeters"]
|
82 |
+
duration_s = result["travelTimeInSeconds"]
|
83 |
+
arrival_time = result["arrivalTime"]
|
84 |
+
# Convert string to datetime object
|
85 |
+
arrival_time = datetime.fromisoformat(arrival_time)
|
86 |
|
87 |
+
return {
|
88 |
+
"distance_m": distance_m,
|
89 |
+
"duration_s": duration_s,
|
90 |
+
"arrival_time": arrival_time,
|
91 |
+
}, response
|
92 |
+
|
93 |
+
|
94 |
+
def find_route(destination=""):
|
95 |
+
"""
|
96 |
+
Find a route and return the distance and the estimated time to go to a specific destination from the current location.
|
97 |
+
:param destination (string): Required. The destination
|
98 |
+
"""
|
99 |
+
# lat, lon, city = check_city_coordinates(lat_depart,lon_depart,city_depart)
|
100 |
+
lat_dest, lon_dest = find_coordinates(destination)
|
101 |
+
print(f"lat_dest: {lat_dest}, lon_dest: {lon_dest}")
|
102 |
+
|
103 |
+
# Extract the latitude and longitude of the vehicle
|
104 |
+
vehicle_coordinates = getattr(vehicle, "location_coordinates")
|
105 |
+
lat_depart, lon_depart = vehicle_coordinates
|
106 |
+
print(f"lat_depart: {lat_depart}, lon_depart: {lon_depart}")
|
107 |
+
|
108 |
+
date = getattr(vehicle, "date")
|
109 |
+
time = getattr(vehicle, "time")
|
110 |
+
departure_time = f"{date}T{time}"
|
111 |
+
|
112 |
+
trip_info, raw_response = find_route_tomtom(
|
113 |
+
lat_depart, lon_depart, lat_dest, lon_dest, departure_time
|
114 |
+
)
|
115 |
+
|
116 |
+
distance, duration, arrival_time = trip_info["distance_m"], trip_info["duration_s"], trip_info["arrival_time"]
|
117 |
+
|
118 |
+
# Calculate distance in kilometers (1 meter = 0.001 kilometers)
|
119 |
+
distance_km = distance * 0.001
|
120 |
# Calculate travel time in minutes (1 second = 1/60 minutes)
|
121 |
+
time_minutes = duration / 60
|
122 |
if time_minutes < 60:
|
123 |
time_display = f"{time_minutes:.0f} minutes"
|
124 |
else:
|
125 |
hours = int(time_minutes / 60)
|
126 |
minutes = int(time_minutes % 60)
|
127 |
+
time_display = f"{hours} hours" + (
|
128 |
+
f" and {minutes} minutes" if minutes > 0 else ""
|
129 |
+
)
|
|
|
|
|
|
|
|
|
130 |
|
131 |
# Extract and display the arrival hour in HH:MM format
|
132 |
arrival_hour_display = arrival_time.strftime("%H:%M")
|
133 |
|
|
|
134 |
# return the distance and time
|
135 |
+
return f"This is the answer you must copy exactly as is: The route to {destination} is {distance_km:.2f} km and {time_display}. Leaving now, the arrival time is estimated at {arrival_hour_display} "
|
|
|
|
|
|
|
|
|
|
|
|
skills/vehicle.py
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from skills import vehicle
|
2 |
+
|
3 |
+
|
4 |
+
STATUS_TEMPLATE = """We are at {location}, current time: {time}, current date: {date} and our destination is: {destination}.
|
5 |
+
"""
|
6 |
+
|
7 |
+
|
8 |
+
def vehicle_status() -> tuple[str, dict[str, str]]:
|
9 |
+
"""Get current vehicle status, which includes, location, date, time, destination.
|
10 |
+
Call this to get the current destination or location of the car/vehicle.
|
11 |
+
Returns:
|
12 |
+
dict[str, str]: The vehicle status. For example:
|
13 |
+
{
|
14 |
+
"location": "Luxembourg Gare, Luxembourg",
|
15 |
+
"lat": 49.6000,
|
16 |
+
"lon": 6.1333,
|
17 |
+
"date": "2025-03-29",
|
18 |
+
"time": "08:00:20",
|
19 |
+
"destination": "Kirchberg Campus, Kirchberg"
|
20 |
+
}
|
21 |
+
"""
|
22 |
+
vs = {
|
23 |
+
"location": "Luxembourg Gare, Luxembourg",
|
24 |
+
"lat": 49.6000,
|
25 |
+
"lon": 6.1333,
|
26 |
+
"date": "2025-03-29",
|
27 |
+
"time": "08:00:20",
|
28 |
+
"destination": "Kirchberg Campus, Kirchberg"
|
29 |
+
}
|
30 |
+
vs = vehicle.dict()
|
31 |
+
return STATUS_TEMPLATE.format(**vs), vs
|