sasan commited on
Commit
63ec258
1 Parent(s): cb47347

chore: Add vehicle status functionality and update skills package

Browse files
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": 1,
13
  "metadata": {
14
  "collapsed": true,
15
  "id": "oOnNfKjX4IAV"
@@ -116,7 +116,7 @@
116
  },
117
  {
118
  "cell_type": "code",
119
- "execution_count": 12,
120
  "metadata": {},
121
  "outputs": [],
122
  "source": [
@@ -128,7 +128,7 @@
128
  },
129
  {
130
  "cell_type": "code",
131
- "execution_count": 13,
132
  "metadata": {},
133
  "outputs": [],
134
  "source": [
@@ -137,7 +137,7 @@
137
  },
138
  {
139
  "cell_type": "code",
140
- "execution_count": 16,
141
  "metadata": {},
142
  "outputs": [
143
  {
@@ -153,7 +153,7 @@
153
  "'Dry run successful'"
154
  ]
155
  },
156
- "execution_count": 16,
157
  "metadata": {},
158
  "output_type": "execute_result"
159
  }
@@ -171,7 +171,7 @@
171
  },
172
  {
173
  "cell_type": "code",
174
- "execution_count": 20,
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": 47,
800
  "metadata": {},
801
  "outputs": [],
802
  "source": [
803
- "RAVEN_PROMPT_FUNC = \"\"\"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",
804
- "{raven_tools}\n",
805
  "\n",
806
- "Current status of the vehicle:\n",
807
- "{status}\n",
808
  "\n",
809
  "Previous conversation history:\n",
810
  "{history}\n",
811
  "\n",
812
- "User Query: Question: {input}\n",
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
- "Please respond in natural language. Do not refer to the provided context in your response.<human_end>\n",
 
 
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
- " kwargs[\"status\"] = self.status_prompt.format(**kwargs[\"status\"])\n",
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'\\Function:\\n<func_start>def {func_signature}<func_end>\\n<docstring_start>\\n\"\"\"\\n{func_docstring}\\n\"\"\"\\n<docstring_end>\\n'\n",
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\", \"status\", \"history\", \"intermediate_steps\"],\n",
883
  ")"
884
  ]
885
  },
886
  {
887
  "cell_type": "code",
888
- "execution_count": 48,
889
  "metadata": {},
890
  "outputs": [],
891
  "source": [
@@ -895,7 +881,7 @@
895
  },
896
  {
897
  "cell_type": "code",
898
- "execution_count": 49,
899
  "metadata": {},
900
  "outputs": [],
901
  "source": [
@@ -916,7 +902,7 @@
916
  },
917
  {
918
  "cell_type": "code",
919
- "execution_count": 50,
920
  "metadata": {},
921
  "outputs": [],
922
  "source": [
@@ -925,18 +911,19 @@
925
  },
926
  {
927
  "cell_type": "code",
928
- "execution_count": 51,
929
  "metadata": {},
930
  "outputs": [
931
  {
932
- "data": {
933
- "text/plain": [
934
- "AgentExecutor(memory=ConversationBufferWindowMemory(input_key='input', k=2), verbose=True, agent=LLMSingleActionAgent(llm_chain=LLMChain(prompt=RavenPromptTemplate(input_variables=['input', 'status', 'history', 'intermediate_steps'], template_func='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{raven_tools}\\n\\nCurrent status of the vehicle:\\n{status}\\n\\nPrevious conversation history:\\n{history}\\n\\nUser Query: Question: {input}\\n\\nIf 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>', template_ans='\\n<human>\\nYou 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\\nCurrent status of the vehicle:\\n{status}\\n\\nPrevious conversation history:\\n{history}\\n\\nUser Query: Question: {input}\\n\\nObservation:{observation}\\n\\nPlease respond in natural language. Do not refer to the provided context in your response.<human_end>\\n\\nAnswer: ', status_prompt=PromptTemplate(input_variables=['date', 'destination', 'lat', 'lon', 'time'], template='\\ncar coordinates: lat:{lat}, lon:{lon}\\ncurrent time: {time}\\ncurrent date: {date}\\ndestination: {destination}\\n'), tools=[Tool(name='get_weather', description=\"get_weather(location: str = '', **kwargs) - Returns the CURRENT weather in a specified location.\\n Args:\\n location (string) : Required. The name of the location, could be a city or lat/longitude in the following format latitude,longitude (example: 37.7749,-122.4194).\", args_schema=<class 'pydantic.v1.main.get_weatherSchema'>, func=<function get_weather at 0x114073a60>), Tool(name='find_route', description=\"find_route(lat_depart='0', lon_depart='0', city_depart='', address_destination='', depart_time='', **kwargs) - Return the distance and the estimated time to go to a specific destination from the current place, at a specified depart time.\\n :param lat_depart (string): latitude of depart\\n :param lon_depart (string): longitude of depart\\n :param city_depart (string): Required. city of depart\\n :param address_destination (string): Required. The destination\\n :param depart_time (string): departure hour, in the format '08:00:20'.\", args_schema=<class 'pydantic.v1.main.find_routeSchema'>, func=<function find_route at 0x114073920>)]), llm=Ollama(model='nexusraven')), output_parser=RavenOutputParser(), stop=['\\nReflection:', '\\nThought:']), tools=[StructuredTool(name='get_weather', description=\"get_weather(location: str = '', **kwargs) - Returns the CURRENT weather in a specified location.\\n Args:\\n location (string) : Required. The name of the location, could be a city or lat/longitude in the following format latitude,longitude (example: 37.7749,-122.4194).\", args_schema=<class 'pydantic.v1.main.get_weatherSchema'>, func=<function get_weather at 0x114073a60>), StructuredTool(name='find_route', description=\"find_route(lat_depart='0', lon_depart='0', city_depart='', address_destination='', depart_time='', **kwargs) - Return the distance and the estimated time to go to a specific destination from the current place, at a specified depart time.\\n :param lat_depart (string): latitude of depart\\n :param lon_depart (string): longitude of depart\\n :param city_depart (string): Required. city of depart\\n :param address_destination (string): Required. The destination\\n :param depart_time (string): departure hour, in the format '08:00:20'.\", args_schema=<class 'pydantic.v1.main.find_routeSchema'>, func=<function find_route at 0x114073920>)])"
935
- ]
936
- },
937
- "execution_count": 51,
938
- "metadata": {},
939
- "output_type": "execute_result"
 
940
  }
941
  ],
942
  "source": [
@@ -945,7 +932,7 @@
945
  },
946
  {
947
  "cell_type": "code",
948
- "execution_count": 52,
949
  "metadata": {},
950
  "outputs": [],
951
  "source": [
@@ -963,7 +950,7 @@
963
  },
964
  {
965
  "cell_type": "code",
966
- "execution_count": 53,
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': 'How is the weather in Luxembourg?', 'status': {'date': '2024-05-02', 'time': '15:35:33', 'destination': 'Kirchberg, Luxembourg', 'lat': '48.8566', 'lon': '2.3522'}, 'history': '', 'intermediate_steps': []}\n",
977
- "llm_output: \n",
978
- "Call: get_weather(location='Luxembourg') \n",
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[36;1m\u001b[1;3m('The current weather in Luxembourg, Luxembourg, Luxembourg is Moderate or heavy rain with thunder with a temperature of 15.0°C that feels like 13.7°C. Humidity is at 82%. Wind speed is 28.1 kph.', {'location': {'name': 'Luxembourg', 'region': 'Luxembourg', 'country': 'Luxembourg', 'lat': 49.61, 'lon': 6.13, 'tz_id': 'Europe/Luxembourg', 'localtime_epoch': 1714656936, 'localtime': '2024-05-02 15:35'}, 'current': {'last_updated': '2024-05-02 15:30', 'temp_c': 15.0, 'condition': {'text': 'Moderate or heavy rain with thunder'}, 'wind_kph': 28.1, 'wind_dir': 'WSW', 'precip_mm': 1.01, 'precip_in': 0.04, 'humidity': 82, 'cloud': 75, 'feelslike_c': 13.7}})\u001b[0m\n",
983
- "kwargs: {'input': 'How is the weather in Luxembourg?', 'status': {'date': '2024-05-02', 'time': '15:35:33', 'destination': 'Kirchberg, Luxembourg', 'lat': '48.8566', 'lon': '2.3522'}, 'history': '', 'intermediate_steps': [(AgentAction(tool='get_weather', tool_input={'location': 'Luxembourg'}, log=\"Calling get_weather with args: {'location': 'Luxembourg'}\"), ('The current weather in Luxembourg, Luxembourg, Luxembourg is Moderate or heavy rain with thunder with a temperature of 15.0°C that feels like 13.7°C. Humidity is at 82%. Wind speed is 28.1 kph.', {'location': {'name': 'Luxembourg', 'region': 'Luxembourg', 'country': 'Luxembourg', 'lat': 49.61, 'lon': 6.13, 'tz_id': 'Europe/Luxembourg', 'localtime_epoch': 1714656936, 'localtime': '2024-05-02 15:35'}, 'current': {'last_updated': '2024-05-02 15:30', 'temp_c': 15.0, 'condition': {'text': 'Moderate or heavy rain with thunder'}, 'wind_kph': 28.1, 'wind_dir': 'WSW', 'precip_mm': 1.01, 'precip_in': 0.04, 'humidity': 82, 'cloud': 75, 'feelslike_c': 13.7}}))]}\n",
984
- "llm_output: The weather in Luxembourg is moderate or heavy rain with thunder, with a temperature of 15 degrees Celsius. The wind is blowing from the west at a speed of 28.1 kilometers per hour, and there is a 75% chance of cloud cover. It feels like 13.7 degrees Celsius outside.\n",
985
- "\u001b[32;1m\u001b[1;3mThe weather in Luxembourg is moderate or heavy rain with thunder, with a temperature of 15 degrees Celsius. The wind is blowing from the west at a speed of 28.1 kilometers per hour, and there is a 75% chance of cloud cover. It feels like 13.7 degrees Celsius outside.\u001b[0m\n",
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=\"How is the weather in Luxembourg?\",\n",
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": 59,
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': 'Where are we going?', 'status': {'date': '2024-05-02', 'time': '15:35:33', 'destination': 'Kirchberg, Luxembourg', 'lat': '48.8566', 'lon': '2.3522'}, 'history': 'Human: How is the weather in Luxembourg?\\nAI: The weather in Luxembourg is moderate or heavy rain with thunder, with a temperature of 15 degrees Celsius. The wind is blowing from the west at a speed of 28.1 kilometers per hour, and there is a 75% chance of cloud cover. It feels like 13.7 degrees Celsius outside.\\nHuman: How about in Tokyo?\\nAI: The weather in Tokyo is currently clear with a temperature of 14.2 degrees Celsius and a wind speed of 6.1 kilometers per hour. There is a 0% chance of precipitation, and the humidity is at 69%. It feels like 13.5 degrees Celsius outside.', 'intermediate_steps': []}\n",
1099
- "llm_output: \n",
1100
- "Call: find_route(city_depart='Luxembourg', address_destination=['Kirchberg, Luxembourg']) \n",
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[59], 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;43mWhere are we going?\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",
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=\"Where are we going?\",\n",
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"OPTION:\n<func_start>{signature}<func_end>\n<docstring_start>\n{docstring}\n<docstring_end>"
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['routes'][0]['legs'][0]['points']:
14
- lats.append(point['latitude'])
15
- lons.append(point['longitude'])
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(mapbox_style="open-street-map", mapbox_zoom=12, mapbox_center_lat=lats[0], mapbox_center_lon=lons[0])
22
- fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
 
 
 
 
 
23
 
24
  return fig
25
 
26
 
27
- def find_route(lat_depart="0", lon_depart="0", city_depart="", address_destination="", depart_time ="", **kwargs):
 
 
 
 
 
 
 
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 city_depart (string): Required. city of depart
33
- :param address_destination (string): Required. The destination
34
  :param depart_time (string): departure hour, in the format '08:00:20'.
35
  """
36
- print(address_destination)
37
- date = "2025-03-29T"
38
- departure_time = '2024-02-01T' + depart_time
39
- lat, lon, city = check_city_coordinates(lat_depart,lon_depart,city_depart)
40
- lat_dest, lon_dest = find_coordinates(address_destination)
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
- data = r.json()
56
- #print(data)
57
-
58
- #print(data)
59
-
60
- result = data['routes'][0]['summary']
61
 
62
- # Calculate distance in kilometers (1 meter = 0.001 kilometers)
63
- distance_km = result['lengthInMeters'] * 0.001
 
 
 
 
 
 
 
64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  # Calculate travel time in minutes (1 second = 1/60 minutes)
66
- time_minutes = result['travelTimeInSeconds'] / 60
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" + (f" and {minutes} minutes" if minutes > 0 else "")
73
-
74
- # Extract arrival time from the JSON structure
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(f"The route to go to {address_destination} is {distance_km:.2f} km and {time_display}. Leaving now, the arrival time is estimated at {arrival_hour_display} " )
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