sasan commited on
Commit
7b96044
1 Parent(s): e5f444f

chore: Update vehicle destination in calculate_route function

Browse files
Files changed (5) hide show
  1. kitt.py +144 -23
  2. skills/__init__.py +18 -1
  3. skills/routing.py +4 -6
  4. skills/vehicle.py +13 -9
  5. skills/weather.py +8 -3
kitt.py CHANGED
@@ -4,19 +4,132 @@ import requests
4
  import skills
5
  from skills.common import config, vehicle
6
  from skills.routing import calculate_route
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
 
9
  # Generate options for hours (00-23)
10
  hour_options = [f"{i:02d}:00" for i in range(24)]
11
 
 
12
  def set_time(time_picker):
13
  vehicle.time = time_picker
14
  return vehicle.model_dump_json()
15
 
 
16
  def get_vehicle_status(state):
17
  return state.value["vehicle"].model_dump_json()
18
 
19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  # to be able to use the microphone on chrome, you will have to go to chrome://flags/#unsafely-treat-insecure-origin-as-secure and enter http://10.186.115.21:7860/
21
  # in "Insecure origins treated as secure", enable it and relaunch chrome
22
 
@@ -25,27 +138,28 @@ def get_vehicle_status(state):
25
  # What's the closest restaurant from here?
26
 
27
 
28
- model_answer = ""
29
- general_context = ""
30
- # Define the initial state with some initial context.
31
- print(general_context)
32
- initial_state = {"context": general_context}
33
- initial_context = initial_state["context"]
34
- # Create the Gradio interface.
35
-
36
-
37
  with gr.Blocks(theme=gr.themes.Default()) as demo:
38
  state = gr.State(
39
- value={"context": initial_context, "query": "", "vehicle": vehicle, "route_points": []}
 
 
 
 
40
  )
41
 
42
  with gr.Row():
43
  with gr.Column(scale=1, min_width=300):
44
  time_picker = gr.Dropdown(
45
- choices=hour_options, label="What time is it? (HH:MM)", value="08:00", interactive=True
 
 
 
46
  )
47
  history = gr.Radio(
48
- ["Yes", "No"], label="Maintain the conversation history?", value="No", interactive=True
 
 
 
49
  )
50
  voice_character = gr.Radio(
51
  choices=[
@@ -76,7 +190,7 @@ with gr.Blocks(theme=gr.themes.Default()) as demo:
76
 
77
  with gr.Column(scale=2, min_width=600):
78
  map_plot = gr.Plot()
79
-
80
  # map_if = gr.Interface(fn=plot_map, inputs=year_input, outputs=map_plot)
81
 
82
  with gr.Row():
@@ -87,14 +201,12 @@ with gr.Blocks(theme=gr.themes.Default()) as demo:
87
  input_text = gr.Textbox(
88
  value="How is the weather?", label="Input text", interactive=True
89
  )
90
- vehicle_status = gr.Textbox(
91
- value=get_vehicle_status(state), label="Vehicle status", interactive=False
92
  )
93
  with gr.Column():
94
  output_audio = gr.Audio(label="output audio")
95
- output_text = gr.TextArea(
96
- value="", label="Output text", interactive=False
97
- )
98
  # iface = gr.Interface(
99
  # fn=transcript,
100
  # inputs=[
@@ -113,19 +225,28 @@ with gr.Blocks(theme=gr.themes.Default()) as demo:
113
 
114
  # Update plot based on the origin and destination
115
  # Sets the current location and destination
116
- origin.submit(fn=calculate_route, inputs=[origin, destination], outputs=[map_plot, vehicle_status])
117
- destination.submit(fn=calculate_route, inputs=[origin, destination], outputs=[map_plot, vehicle_status])
 
 
 
 
 
 
 
 
118
 
119
  # Update time based on the time picker
120
  time_picker.select(fn=set_time, inputs=[time_picker], outputs=[vehicle_status])
121
 
 
 
 
122
  # close all interfaces open to make the port available
123
  gr.close_all()
124
  # Launch the interface.
125
 
126
  if __name__ == "__main__":
127
- demo.launch(
128
- debug=True, server_name="0.0.0.0", server_port=7860, ssl_verify=False
129
- )
130
 
131
  # iface.launch(debug=True, share=False, server_name="0.0.0.0", server_port=7860, ssl_verify=False)
 
4
  import skills
5
  from skills.common import config, vehicle
6
  from skills.routing import calculate_route
7
+ import ollama
8
+
9
+ ### LLM Stuff ###
10
+ from langchain_community.llms import Ollama
11
+ from langchain.tools.base import StructuredTool
12
+
13
+ from skills import (
14
+ get_weather,
15
+ find_route,
16
+ get_forecast,
17
+ vehicle_status as vehicle_status_fn,
18
+ search_points_of_interests,
19
+ search_along_route_w_coordinates,
20
+ do_anything_else,
21
+ date_time_info
22
+ )
23
+ from skills import extract_func_args
24
+
25
+
26
+ global_context = {
27
+ "vehicle": vehicle,
28
+ "query": "How is the weather?",
29
+ "route_points": [],
30
+ }
31
+
32
+
33
+ MODEL_FUNC = "nexusraven"
34
+ MODEL_GENERAL = "llama3:instruct"
35
+
36
+ RAVEN_PROMPT_FUNC = """You are a helpful AI assistant in a car (vehicle), that follows instructions extremely well. \
37
+ Answer questions concisely and do not mention what you base your reply on."
38
+
39
+ {raven_tools}
40
+
41
+ {history}
42
+
43
+ User Query: Question: {input}<human_end>
44
+ """
45
+
46
+ def get_prompt(template, input, history, tools):
47
+ # "vehicle_status": vehicle_status_fn()[0]
48
+ kwargs = {"history": history, "input": input}
49
+ prompt = "<human>:\n"
50
+ for tool in tools:
51
+ func_signature, func_docstring = tool.description.split(" - ", 1)
52
+ prompt += f'Function:\n<func_start>def {func_signature}<func_end>\n<docstring_start>\n"""\n{func_docstring}\n"""\n<docstring_end>\n'
53
+ kwargs["raven_tools"] = prompt
54
+
55
+ if history:
56
+ kwargs["history"] = f"Previous conversation history:{history}\n"
57
+
58
+ return template.format(**kwargs).replace("{{", "{").replace("}}", "}")
59
+
60
+ def use_tool(func_name, kwargs, tools):
61
+ for tool in tools:
62
+ if tool.name == func_name:
63
+ return tool.invoke(input=kwargs)
64
+ return None
65
+
66
+ tools = [
67
+ StructuredTool.from_function(get_weather),
68
+ StructuredTool.from_function(find_route),
69
+ # StructuredTool.from_function(vehicle_status),
70
+ StructuredTool.from_function(search_points_of_interests),
71
+ StructuredTool.from_function(search_along_route_w_coordinates),
72
+ StructuredTool.from_function(date_time_info),
73
+ StructuredTool.from_function(do_anything_else),
74
+ ]
75
+ # llm = Ollama(model="nexusraven", stop=["\nReflection:", "\nThought:"], keep_alive=60*10)
76
 
77
 
78
  # Generate options for hours (00-23)
79
  hour_options = [f"{i:02d}:00" for i in range(24)]
80
 
81
+
82
  def set_time(time_picker):
83
  vehicle.time = time_picker
84
  return vehicle.model_dump_json()
85
 
86
+
87
  def get_vehicle_status(state):
88
  return state.value["vehicle"].model_dump_json()
89
 
90
 
91
+ def run_generic_model(query):
92
+ print(f"Running the generic model with query: {query}")
93
+ data = {
94
+ "prompt": query,
95
+ "model": MODEL_GENERAL,
96
+ "options": {
97
+ # "temperature": 0.1,
98
+ # "stop":["\nReflection:", "\nThought:"]
99
+ }
100
+ }
101
+ out = ollama.generate(**data)
102
+ return out["response"]
103
+
104
+
105
+ def run_model(query):
106
+ print("Query: ", query)
107
+ global_context["query"] = query
108
+ global_context["prompt"] = get_prompt(RAVEN_PROMPT_FUNC, query, "", tools)
109
+ print("Prompt: ", global_context["prompt"])
110
+ data = {
111
+ "prompt": global_context["prompt"],
112
+ # "streaming": False,
113
+ "model": "nexusraven",
114
+ # "model": "smangrul/llama-3-8b-instruct-function-calling",
115
+ "raw": True,
116
+ "options": {
117
+ "temperature": 0.5,
118
+ "stop":["\nReflection:", "\nThought:"]
119
+ }
120
+ }
121
+ out = ollama.generate(**data)
122
+ llm_response = out["response"]
123
+ if "Call: " in llm_response:
124
+ func_name, kwargs = extract_func_args(llm_response)
125
+ print(f"Function: {func_name}, Args: {kwargs}")
126
+ if func_name == "do_anything_else":
127
+ return run_generic_model(query)
128
+
129
+ return use_tool(func_name, kwargs, tools)
130
+ return out["response"]
131
+
132
+
133
  # to be able to use the microphone on chrome, you will have to go to chrome://flags/#unsafely-treat-insecure-origin-as-secure and enter http://10.186.115.21:7860/
134
  # in "Insecure origins treated as secure", enable it and relaunch chrome
135
 
 
138
  # What's the closest restaurant from here?
139
 
140
 
 
 
 
 
 
 
 
 
 
141
  with gr.Blocks(theme=gr.themes.Default()) as demo:
142
  state = gr.State(
143
+ value={
144
+ # "context": initial_context,
145
+ "query": "",
146
+ "route_points": [],
147
+ }
148
  )
149
 
150
  with gr.Row():
151
  with gr.Column(scale=1, min_width=300):
152
  time_picker = gr.Dropdown(
153
+ choices=hour_options,
154
+ label="What time is it? (HH:MM)",
155
+ value="08:00",
156
+ interactive=True,
157
  )
158
  history = gr.Radio(
159
+ ["Yes", "No"],
160
+ label="Maintain the conversation history?",
161
+ value="No",
162
+ interactive=True,
163
  )
164
  voice_character = gr.Radio(
165
  choices=[
 
190
 
191
  with gr.Column(scale=2, min_width=600):
192
  map_plot = gr.Plot()
193
+
194
  # map_if = gr.Interface(fn=plot_map, inputs=year_input, outputs=map_plot)
195
 
196
  with gr.Row():
 
201
  input_text = gr.Textbox(
202
  value="How is the weather?", label="Input text", interactive=True
203
  )
204
+ vehicle_status = gr.JSON(
205
+ value=vehicle.model_dump_json(), label="Vehicle status"
206
  )
207
  with gr.Column():
208
  output_audio = gr.Audio(label="output audio")
209
+ output_text = gr.TextArea(value="", label="Output text", interactive=False)
 
 
210
  # iface = gr.Interface(
211
  # fn=transcript,
212
  # inputs=[
 
225
 
226
  # Update plot based on the origin and destination
227
  # Sets the current location and destination
228
+ origin.submit(
229
+ fn=calculate_route,
230
+ inputs=[origin, destination],
231
+ outputs=[map_plot, vehicle_status],
232
+ )
233
+ destination.submit(
234
+ fn=calculate_route,
235
+ inputs=[origin, destination],
236
+ outputs=[map_plot, vehicle_status],
237
+ )
238
 
239
  # Update time based on the time picker
240
  time_picker.select(fn=set_time, inputs=[time_picker], outputs=[vehicle_status])
241
 
242
+ # Run the model if the input text is changed
243
+ input_text.submit(fn=run_model, inputs=[input_text], outputs=[output_text])
244
+
245
  # close all interfaces open to make the port available
246
  gr.close_all()
247
  # Launch the interface.
248
 
249
  if __name__ == "__main__":
250
+ demo.launch(debug=True, server_name="0.0.0.0", server_port=7860, ssl_verify=False)
 
 
251
 
252
  # iface.launch(debug=True, share=False, server_name="0.0.0.0", server_port=7860, ssl_verify=False)
skills/__init__.py CHANGED
@@ -1,12 +1,29 @@
 
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 .poi import search_points_of_interests, search_along_route_w_coordinates
7
  from .vehicle import vehicle_status
8
 
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  def format_functions_for_prompt_raven(*functions):
11
  """Format functions for use in Prompt Raven.
12
 
 
1
+ from datetime import datetime
2
  import inspect
3
 
4
+ from .common import execute_function_call, extract_func_args, vehicle as vehicle_obj
5
  from .weather import get_weather, get_forecast
6
  from .routing import find_route
7
  from .poi import search_points_of_interests, search_along_route_w_coordinates
8
  from .vehicle import vehicle_status
9
 
10
 
11
+
12
+ def date_time_info():
13
+ """Get the current date and time."""
14
+ time = getattr(vehicle_obj, "time")
15
+ date = getattr(vehicle_obj, "date")
16
+ datetime_obj = datetime.fromisoformat(f"{date}T{time}")
17
+ human_readable_datetime = datetime_obj.strftime("%I:%M %p %A, %B %d, %Y")
18
+ return f"It is {human_readable_datetime}."
19
+
20
+
21
+ def do_anything_else():
22
+ """If the user wants to do anything else call this function. If the question doesn't match any of the functions use this one."""
23
+ return True
24
+
25
+
26
+
27
  def format_functions_for_prompt_raven(*functions):
28
  """Format functions for use in Prompt Raven.
29
 
skills/routing.py CHANGED
@@ -109,8 +109,8 @@ def find_route_tomtom(
109
 
110
 
111
  def find_route(destination=""):
112
- """
113
- Find a route and return the distance and the estimated time to go to a specific destination from the current location.
114
  :param destination (string): Required. The destination
115
  """
116
  # lat, lon, city = check_city_coordinates(lat_depart,lon_depart,city_depart)
@@ -153,7 +153,5 @@ def find_route(destination=""):
153
  arrival_hour_display = arrival_time.strftime("%H:%M")
154
 
155
  # return the distance and time
156
- return (
157
- f"The route to {destination} is {distance_km:.2f} km and {time_display}. Leaving now, the arrival time is estimated at {arrival_hour_display}.",
158
- raw_response["routes"][0]["legs"][0]["points"],
159
- )
 
109
 
110
 
111
  def find_route(destination=""):
112
+ """This function finds a route to a destination and returns the distance and the estimated time to go to a specific destination\
113
+ from the current location.
114
  :param destination (string): Required. The destination
115
  """
116
  # lat, lon, city = check_city_coordinates(lat_depart,lon_depart,city_depart)
 
153
  arrival_hour_display = arrival_time.strftime("%H:%M")
154
 
155
  # return the distance and time
156
+ return f"The route to {destination} is {distance_km:.2f} km which takes {time_display}. Leaving now, the arrival time is estimated at {arrival_hour_display}."
157
+ # raw_response["routes"][0]["legs"][0]["points"]
 
 
skills/vehicle.py CHANGED
@@ -1,7 +1,9 @@
1
  from .common 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
 
@@ -19,13 +21,15 @@ def vehicle_status() -> tuple[str, dict[str, str]]:
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
 
1
  from .common import vehicle
2
 
3
 
4
+ STATUS_TEMPLATE = """
5
+ We are at {location}, coordinates: {lat}, {lon},
6
+ current time: {time}, current date: {date} and our destination is: {destination}.
7
  """
8
 
9
 
 
21
  "destination": "Kirchberg Campus, Kirchberg"
22
  }
23
  """
24
+ # vs = {
25
+ # "location": "Luxembourg Gare, Luxembourg",
26
+ # "lat": 49.6000,
27
+ # "lon": 6.1333,
28
+ # "date": "2025-03-29",
29
+ # "time": "08:00:20",
30
+ # "destination": "Kirchberg Campus, Luxembourg"
31
+ # }
32
  vs = vehicle.dict()
33
+ vs["lat"] = vs["location_coordinates"][0]
34
+ vs["lon"] = vs["location_coordinates"][1]
35
  return STATUS_TEMPLATE.format(**vs), vs
skills/weather.py CHANGED
@@ -1,14 +1,19 @@
1
  import requests
2
 
3
- from .common import config
4
 
5
  #current weather API
6
- def get_weather(location:str= "", **kwargs):
7
  """
8
  Returns the CURRENT weather in a specified location.
9
  Args:
10
- 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).
11
  """
 
 
 
 
 
12
  # The endpoint URL provided by WeatherAPI
13
  url = f"http://api.weatherapi.com/v1/current.json?key={config.WEATHER_API_KEY}&q={location}&aqi=no"
14
  print(url)
 
1
  import requests
2
 
3
+ from .common import config, vehicle
4
 
5
  #current weather API
6
+ def get_weather(location:str= ""):
7
  """
8
  Returns the CURRENT weather in a specified location.
9
  Args:
10
+ 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). If the location is not specified, the function will return the weather in the current location.
11
  """
12
+
13
+ if location == "":
14
+ print(f"get_weather: location is empty, using the vehicle location. ({vehicle.location})")
15
+ location = vehicle.location
16
+
17
  # The endpoint URL provided by WeatherAPI
18
  url = f"http://api.weatherapi.com/v1/current.json?key={config.WEATHER_API_KEY}&q={location}&aqi=no"
19
  print(url)