Amitabhab commited on
Commit
880d47e
·
1 Parent(s): c752143

Some major changes. Incorporating Gradio Blocks. Incorporating db logging.

Browse files
app.py CHANGED
@@ -1,41 +1,70 @@
1
- #!/usr/bin/env python
2
  """
3
  Travel planner based on Agentic AI workflow.
4
 
5
  This module deploys a portal which can customize a day to day travel itinerary
6
  for a person using multiple specialized AI crews.
7
 
8
- Implemented using Gradio and Crew AI
9
  A deployment is available at https://huggingface.co/spaces/sambanovasystems/trip-planner
10
  """
11
 
 
12
  import json
13
  import logging
14
- import datetime
15
  from typing import List, Tuple
16
 
17
  import gradio as gr
18
  import plotly.graph_objects as go
 
19
  from crew import AddressSummaryCrew, TravelCrew
 
 
 
 
 
 
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
  def filter_map(text_list: List[str], lat: List[str], lon: List[str]) -> go.Figure:
23
  """
24
  Create a Map showing the points specified in the inputs.
25
 
26
  Args:
27
- text_list: List of the description of all locations that will be shown on the map
28
- lat: List of latitude coordinates of the locations
29
- lon: List of longitude coordinates of the locations
30
 
31
  Returns:
32
  Figure: Map with the points specified in the inputs
33
  """
34
 
 
35
  fig = go.Figure(
36
  go.Scattermapbox(lat=lat, lon=lon, mode='markers', marker=go.scattermapbox.Marker(size=11), hovertext=text_list)
37
  )
38
 
 
39
  fig.update_layout(
40
  mapbox_style='open-street-map',
41
  hovermode='closest',
@@ -56,17 +85,17 @@ def run(
56
  budget: int,
57
  ) -> Tuple[str, go.Figure]:
58
  """
59
- Run the specfied query using Crew AI agents
60
 
61
  Args:
62
- origin: Origin city of the traveller
63
- destination: Destination that traveller is going to
64
- arrival_date: Approximate date when the trip will begin in epoch time
65
- age: Age profile of traveller
66
- interests: Specific interests of the traveller
67
- cuisine_preferences: Specific cuisine preferences of the traveller
68
- children: Whether traveller has children travelling with them
69
- budget: Total budget of traveller in US Dollars
70
 
71
  Returns:
72
  Returns a tuple containing the itinerary and map
@@ -75,12 +104,18 @@ def run(
75
  arrival_date_input = datetime.datetime.fromtimestamp(arrival_date).strftime("%m-%d-%Y")
76
  else:
77
  arrival_date_input = None
78
-
79
  logger.info(
80
- f'Origin: {origin}, Destination: {destination}, Arrival Date: {arrival_date_input}, Age: {age}, Duration: {trip_duration},'
81
- f' Interests: {interests}, Cuisines: {cuisine_preferences}, Children: {children}, Daily Budget: {budget}'
 
 
82
  )
83
- inputs = {
 
 
 
 
84
  'origin': origin,
85
  'destination': destination,
86
  'arrival_date': arrival_date_input,
@@ -91,22 +126,35 @@ def run(
91
  'children': children,
92
  'budget': budget,
93
  }
94
- result = TravelCrew().crew().kickoff(inputs=inputs)
 
 
 
 
 
 
 
95
  inputs_for_address = {'text': str(result)}
96
 
97
  addresses = AddressSummaryCrew().crew().kickoff(inputs=inputs_for_address)
 
 
 
 
 
 
98
  json_addresses = None
99
- if addresses.json_dict:
100
  json_addresses = addresses.json_dict
101
- if not json_addresses:
102
  try:
103
  json_addresses = json.loads(addresses.raw)
104
  except json.JSONDecodeError as e:
105
- # Try with different format of result data generated with ```json and ending with ```
106
  try:
107
  json_addresses = json.loads(addresses.raw[8:-4])
108
  except json.JSONDecodeError as e:
109
- # Try with different format of result data generated with ``` and ending with ```
110
  try:
111
  json_addresses = json.loads(addresses.raw[4:-4])
112
  except json.JSONDecodeError as e:
@@ -120,50 +168,56 @@ def run(
120
  logger = logging.getLogger()
121
  logger.setLevel(logging.INFO)
122
 
123
- demo = gr.Interface(
124
- title='Plan your itinerary with the help of AI',
125
- description='Use this app to create a detailed itinerary on how to explore a new place.'
126
- ' Itinerary is customized to your taste. Powered by Sambanova Cloud.',
127
- fn=run,
128
- inputs=[
129
- gr.Textbox(label='Where are you travelling from?'),
130
- gr.Textbox(label='Where are you going?'),
131
- gr.DateTime(label="Approximate arrival date"),
132
- gr.Slider(label='Your age?', value=30, minimum=15, maximum=90, step=5),
133
- gr.Slider(label='How many days are you travelling?', value=5, minimum=1, maximum=14, step=1),
134
- gr.CheckboxGroup(
135
- ['Museums', 'Shopping', 'Entertainment', 'Nightlife', 'Outdoor Adventures'],
136
- label='Checkbox your specific interests.',
137
- ),
138
- gr.CheckboxGroup(
139
- [
140
- 'Ethnic',
141
- 'American',
142
- 'Italian',
143
- 'Mexican',
144
- 'Chinese',
145
- 'Japanese',
146
- 'Indian',
147
- 'Thai',
148
- 'French',
149
- 'Vietnamese',
150
- 'Vegan',
151
- ],
152
- label='Checkbox your cuisine preferences.',
153
- ),
154
- gr.Checkbox(label='Check if children are travelling with you'),
155
- gr.Slider(
156
- label='Total budget of trip in USD', show_label=True, value=1000, minimum=500, maximum=10000, step=500
157
- ),
158
- ],
159
- outputs=[
160
- gr.Textbox(
161
- label='Complete Personalized Itinerary of your Trip',
162
- show_label=True,
163
- show_copy_button=True,
164
- autoscroll=False,
165
- ),
166
- gr.Plot(label='Venues on a Map. Please verify with a Navigation System before traveling.'),
167
- ],
168
- )
 
 
 
 
 
 
169
  demo.launch()
 
 
1
  """
2
  Travel planner based on Agentic AI workflow.
3
 
4
  This module deploys a portal which can customize a day to day travel itinerary
5
  for a person using multiple specialized AI crews.
6
 
7
+ Implemented using Sambanova Cloud, Gradio and Crew AI.
8
  A deployment is available at https://huggingface.co/spaces/sambanovasystems/trip-planner
9
  """
10
 
11
+ import datetime
12
  import json
13
  import logging
 
14
  from typing import List, Tuple
15
 
16
  import gradio as gr
17
  import plotly.graph_objects as go
18
+
19
  from crew import AddressSummaryCrew, TravelCrew
20
+ from db import log_query
21
+ from fpdf import FPDF
22
+
23
+ def export_pdf(input_text:str):
24
+ """
25
+ Create a downloadable pdf for the given input text
26
 
27
+ Args:
28
+ input_text: The text that needs to be made a pdf
29
+
30
+ Result:
31
+ Downloadable pdf
32
+ """
33
+ pdf = FPDF()
34
+ pdf.add_page()
35
+ pdf.set_font("helvetica", size=12)
36
+
37
+ for line in input_text.split('\n'):
38
+ clean_line = line.strip()
39
+ if clean_line.startswith('**'):
40
+ pdf.set_font("Arial", size=12, style='B')
41
+ pdf.multi_cell(0, 5, clean_line[2:].lstrip()[:-2].rstrip())
42
+ pdf.set_font("Arial", size=12, style='')
43
+ else:
44
+ pdf.multi_cell(0, 5, clean_line)
45
+
46
+ pdf.output("output.pdf")
47
+ return "output.pdf"
48
 
49
  def filter_map(text_list: List[str], lat: List[str], lon: List[str]) -> go.Figure:
50
  """
51
  Create a Map showing the points specified in the inputs.
52
 
53
  Args:
54
+ text_list: List of the description of all locations that will be shown on the map.
55
+ lat: List of latitude coordinates of the locations.
56
+ lon: List of longitude coordinates of the locations.
57
 
58
  Returns:
59
  Figure: Map with the points specified in the inputs
60
  """
61
 
62
+ # Creating a map with the provided markers using their latitude and longitude coordinates.
63
  fig = go.Figure(
64
  go.Scattermapbox(lat=lat, lon=lon, mode='markers', marker=go.scattermapbox.Marker(size=11), hovertext=text_list)
65
  )
66
 
67
+ # Update the map by centering it on of the the provided longitude and latitude coordinates
68
  fig.update_layout(
69
  mapbox_style='open-street-map',
70
  hovermode='closest',
 
85
  budget: int,
86
  ) -> Tuple[str, go.Figure]:
87
  """
88
+ Run the specfied query using Crew AI agents.
89
 
90
  Args:
91
+ origin: Origin city of the traveller.
92
+ destination: Destination to which the traveller is going.
93
+ arrival_date: Approximate date when the trip will begin in epoch time.
94
+ age: Age profile of traveller.
95
+ interests: Specific interests of the traveller.
96
+ cuisine_preferences: Specific cuisine preferences of the traveller.
97
+ children: Whether traveller has children travelling with them.
98
+ budget: Total budget of traveller in US Dollars.
99
 
100
  Returns:
101
  Returns a tuple containing the itinerary and map
 
104
  arrival_date_input = datetime.datetime.fromtimestamp(arrival_date).strftime("%m-%d-%Y")
105
  else:
106
  arrival_date_input = None
107
+ log_query(origin, destination, age, trip_duration, budget)
108
  logger.info(
109
+ f'Origin: {origin}, Destination: {destination}, Arrival Date: {arrival_date_input},'
110
+ f' Age: {age}, Duration: {trip_duration},'
111
+ f' Interests: {interests}, Cuisines: {cuisine_preferences},'
112
+ f' Children: {children}, Daily Budget: {budget}'
113
  )
114
+
115
+ # Creating a dictionary of user provided preferences and providing these to the crew agents
116
+ # to work on.
117
+
118
+ user_preferences = {
119
  'origin': origin,
120
  'destination': destination,
121
  'arrival_date': arrival_date_input,
 
126
  'children': children,
127
  'budget': budget,
128
  }
129
+ result = TravelCrew().crew().kickoff(inputs=user_preferences)
130
+
131
+ """
132
+ Now we will pass the result to a address summary crew whose job is to extract position
133
+ coordinates of the addresses (latitude and longitude), so that the addresses in the
134
+ result can be displayed in map coordinates
135
+ """
136
+
137
  inputs_for_address = {'text': str(result)}
138
 
139
  addresses = AddressSummaryCrew().crew().kickoff(inputs=inputs_for_address)
140
+
141
+ """
142
+ We have requested the crew agent to return latitude, longitude coordinates.
143
+ But the exact way the LLMs return varies. Hence we try multiple different ways of
144
+ extracting addresses in JSON format from the result.
145
+ """
146
  json_addresses = None
147
+ if addresses.json_dict is not None:
148
  json_addresses = addresses.json_dict
149
+ if json_addresses is None:
150
  try:
151
  json_addresses = json.loads(addresses.raw)
152
  except json.JSONDecodeError as e:
153
+ # Try with different format of result data generated with ```json and ending with ```.
154
  try:
155
  json_addresses = json.loads(addresses.raw[8:-4])
156
  except json.JSONDecodeError as e:
157
+ # Try with different format of result data generated with ``` and ending with ```.
158
  try:
159
  json_addresses = json.loads(addresses.raw[4:-4])
160
  except json.JSONDecodeError as e:
 
168
  logger = logging.getLogger()
169
  logger.setLevel(logging.INFO)
170
 
171
+ with gr.Blocks() as demo:
172
+ gr.Markdown('Use this app to create a detailed itinerary on how to explore a new place.'
173
+ ' Itinerary is customized to your taste. Powered by Sambanova Cloud.')
174
+ with gr.Row():
175
+ with gr.Column(scale=1):
176
+ inp_source = gr.Textbox(label='Where are you travelling from?')
177
+ inp_dest = gr.Textbox(label='Where are you going?')
178
+ inp_cal = gr.DateTime(label='Approximate arrival date')
179
+ inp_age = gr.Slider(label='Your age?', value=30, minimum=15, maximum=90, step=5)
180
+ inp_days = gr.Slider(label='How many days are you travelling?', value=5, minimum=1, maximum=14, step=1)
181
+ inp_cuisine =\
182
+ gr.CheckboxGroup(
183
+ [
184
+ 'Ethnic',
185
+ 'American',
186
+ 'Italian',
187
+ 'Mexican',
188
+ 'Chinese',
189
+ 'Japanese',
190
+ 'Indian',
191
+ 'Thai',
192
+ 'French',
193
+ 'Vietnamese',
194
+ 'Vegan',
195
+ ],
196
+ label='Checkbox your cuisine preferences.',
197
+ )
198
+ inp_children = gr.Checkbox(label='Check if children are travelling with you')
199
+ inp_budget =\
200
+ gr.Slider(
201
+ label='Total budget of trip in USD', show_label=True, value=1000, minimum=500, maximum=10000, step=500
202
+ )
203
+ button = gr.Button("Plan your Trip")
204
+ inputs = [inp_source, inp_dest, inp_cal, inp_age, inp_days, inp_cuisine, inp_children, inp_budget]
205
+
206
+ with gr.Column(scale=2):
207
+ output_itinerary =\
208
+ gr.Textbox(
209
+ label='Complete Personalized Itinerary of your Trip',
210
+ show_label=True,
211
+ show_copy_button=True,
212
+ autoscroll=False,
213
+ )
214
+ download_btn = gr.Button("Download Itinerary")
215
+
216
+ output_map = gr.Plot(label='Venues on a Map. Please verify with a Navigation System before traveling.')
217
+ output = [output_itinerary, output_map]
218
+
219
+ button.click(fn=run, inputs=inputs, outputs=output)
220
+ download_btn_hidden = gr.DownloadButton(visible=False, elem_id="download_btn_hidden")
221
+ download_btn.click(fn=export_pdf, inputs=output_itinerary, outputs=[download_btn_hidden]).then(fn=None, inputs=None, outputs=None, js="() => document.querySelector('#download_btn_hidden').click()")
222
+
223
  demo.launch()
config/address_agents.yaml CHANGED
@@ -1,8 +1,8 @@
1
  address_summarizer:
2
  role: >
3
- Summarize Addresses into Latitude and Longitude coordinates
4
  goal: >
5
- You need to extract addresses from a provided text and convert those addresses into latitude and longitude coordinates so that they can be easily shown on a map
6
  backstory: >
7
- You are skilled at extracting addresses from lines of text into latitude and longitude coordinates
8
 
 
1
  address_summarizer:
2
  role: >
3
+ Summarize Addresses into Latitude and Longitude coordinates.
4
  goal: >
5
+ You need to extract addresses from a provided text and convert those addresses into latitude and longitude coordinates so that they can be easily shown on a map.
6
  backstory: >
7
+ You are skilled at extracting addresses from lines of text into latitude and longitude coordinates.
8
 
config/address_tasks.yaml CHANGED
@@ -1,6 +1,6 @@
1
  address_compilation_task:
2
  description: >
3
- Extract the list of addresses from {text} in convert them to latitudes and longitudes.
4
 
5
  expected_output: >
6
- Output is expected in simple JSON format with three lists. The first list should contain the name of the venue or the name of the restaurant and should be indexed by the keyword "name". The second list should contain the latitudes and indexed with the keyword "lat". The third list should contain the longitudes and indexed with the keyword "lon".
 
1
  address_compilation_task:
2
  description: >
3
+ Extract the list of addresses from {text} and convert them to latitudes and longitudes.
4
 
5
  expected_output: >
6
+ Output is expected in simple JSON format with three lists. The first list should contain the name of the venue or the name of the restaurant or the activity and should be indexed by the keyword "name". The second list should contain the latitudes and indexed with the keyword "lat". The third list should contain the longitudes and indexed with the keyword "lon".
config/agents.yaml CHANGED
@@ -2,7 +2,7 @@ personalized_activity_planner:
2
  role: >
3
  Activity Planner
4
  goal: >
5
- Research and find cool things to do at the destination, including activities and events that match the traveler's interests and age group. Create detailed notes on the activity or event. Pay importance to the planned arrival date of the traveller, which will indicate which will indicate the season.
6
  backstory: >
7
  You are skilled at creating personalized itineraries that cater to the specific preferences and demographics of travelers.
8
 
 
2
  role: >
3
  Activity Planner
4
  goal: >
5
+ Research and find cool things to do at the destination, including activities and events that match the traveler's interests and age group. Create detailed notes on the activity or event.
6
  backstory: >
7
  You are skilled at creating personalized itineraries that cater to the specific preferences and demographics of travelers.
8
 
config/requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ plotly==6.0.0
2
+ crewai==0.100.1
3
+ crewai-tools==0.33.0
4
+ gradio==5.15.0
5
+ gradio_client==1.7.0
6
+ fpdf==1.7.2
config/tasks.yaml CHANGED
@@ -11,7 +11,7 @@ personalized_activity_planning_task:
11
  - origin: {origin}
12
 
13
  - destination: {destination}
14
-
15
  - Approximate arrival data in month-day-year format: {arrival_date}
16
 
17
  - Approximate age of the adult travelers: {age}
 
11
  - origin: {origin}
12
 
13
  - destination: {destination}
14
+
15
  - Approximate arrival data in month-day-year format: {arrival_date}
16
 
17
  - Approximate age of the adult travelers: {age}
crew.py CHANGED
@@ -1,11 +1,17 @@
1
  """Implementation based on the Crew AI workflow"""
2
 
 
 
3
  from crewai import LLM, Agent, Crew, Process, Task
4
  from crewai.project import CrewBase, agent, crew, task
 
 
 
 
5
  from crewai_tools import ScrapeWebsiteTool, SerperDevTool
6
 
7
  # Change the model which you want to use below.
8
- # Currently, we use the Llama 3.1 70B model because it seems the most versatile
9
  llm = LLM(model='sambanova/Meta-Llama-3.1-70B-Instruct')
10
 
11
 
@@ -19,6 +25,7 @@ class TravelCrew:
19
  self.agents_config = 'config/agents.yaml'
20
  self.tasks_config = 'config/tasks.yaml'
21
 
 
22
  @agent
23
  def personalized_activity_planner(self) -> Agent:
24
  """
@@ -34,6 +41,7 @@ class TravelCrew:
34
  allow_delegation=False,
35
  )
36
 
 
37
  @agent
38
  def restaurant_scout(self) -> Agent:
39
  """
@@ -49,6 +57,7 @@ class TravelCrew:
49
  allow_delegation=False,
50
  )
51
 
 
52
  @agent
53
  def interest_scout(self) -> Agent:
54
  """
@@ -64,6 +73,7 @@ class TravelCrew:
64
  allow_delegation=False,
65
  )
66
 
 
67
  @agent
68
  def itinerary_compiler(self) -> Agent:
69
  """
@@ -78,6 +88,7 @@ class TravelCrew:
78
  allow_delegation=False,
79
  )
80
 
 
81
  @task
82
  def personalized_activity_planning_task(self) -> Task:
83
  """
@@ -92,6 +103,7 @@ class TravelCrew:
92
  agent=self.personalized_activity_planner(),
93
  )
94
 
 
95
  @task
96
  def interest_scout_task(self) -> Task:
97
  """
@@ -101,6 +113,7 @@ class TravelCrew:
101
  """
102
  return Task(config=self.tasks_config['interest_scout_task'], llm=llm, max_iter=1, agent=self.interest_scout())
103
 
 
104
  @task
105
  def restaurant_scenic_location_scout_task(self) -> Task:
106
  """
@@ -115,6 +128,7 @@ class TravelCrew:
115
  agent=self.restaurant_scout(),
116
  )
117
 
 
118
  @task
119
  def itinerary_compilation_task(self) -> Task:
120
  """
@@ -126,6 +140,7 @@ class TravelCrew:
126
  config=self.tasks_config['itinerary_compilation_task'], llm=llm, max_iter=1, agent=self.itinerary_compiler()
127
  )
128
 
 
129
  @crew
130
  def crew(self) -> Crew:
131
  """
@@ -147,6 +162,7 @@ class AddressSummaryCrew:
147
  agents_config = 'config/address_agents.yaml'
148
  tasks_config = 'config/address_tasks.yaml'
149
 
 
150
  @agent
151
  def address_summarizer(self) -> Agent:
152
  """
@@ -161,6 +177,7 @@ class AddressSummaryCrew:
161
  allow_delegation=False,
162
  )
163
 
 
164
  @task
165
  def address_compilation_task(self) -> Task:
166
  """
@@ -175,6 +192,7 @@ class AddressSummaryCrew:
175
  agent=self.address_summarizer(),
176
  )
177
 
 
178
  @crew
179
  def crew(self) -> Crew:
180
  """
 
1
  """Implementation based on the Crew AI workflow"""
2
 
3
+ import typing
4
+
5
  from crewai import LLM, Agent, Crew, Process, Task
6
  from crewai.project import CrewBase, agent, crew, task
7
+
8
+ # Import tools from crewai_tools
9
+ # ScrapWebsiteTool: Extract content of wensite, https://docs.crewai.com/tools/scrapewebsitetool
10
+ # SerperDevTool: Search Internet, https://docs.crewai.com/tools/serperdevtool
11
  from crewai_tools import ScrapeWebsiteTool, SerperDevTool
12
 
13
  # Change the model which you want to use below.
14
+ # Currently, we use the Llama 3.1 70B model because it seems the most versatile.
15
  llm = LLM(model='sambanova/Meta-Llama-3.1-70B-Instruct')
16
 
17
 
 
25
  self.agents_config = 'config/agents.yaml'
26
  self.tasks_config = 'config/tasks.yaml'
27
 
28
+ @typing.no_type_check
29
  @agent
30
  def personalized_activity_planner(self) -> Agent:
31
  """
 
41
  allow_delegation=False,
42
  )
43
 
44
+ @typing.no_type_check
45
  @agent
46
  def restaurant_scout(self) -> Agent:
47
  """
 
57
  allow_delegation=False,
58
  )
59
 
60
+ @typing.no_type_check
61
  @agent
62
  def interest_scout(self) -> Agent:
63
  """
 
73
  allow_delegation=False,
74
  )
75
 
76
+ @typing.no_type_check
77
  @agent
78
  def itinerary_compiler(self) -> Agent:
79
  """
 
88
  allow_delegation=False,
89
  )
90
 
91
+ @typing.no_type_check
92
  @task
93
  def personalized_activity_planning_task(self) -> Task:
94
  """
 
103
  agent=self.personalized_activity_planner(),
104
  )
105
 
106
+ @typing.no_type_check
107
  @task
108
  def interest_scout_task(self) -> Task:
109
  """
 
113
  """
114
  return Task(config=self.tasks_config['interest_scout_task'], llm=llm, max_iter=1, agent=self.interest_scout())
115
 
116
+ @typing.no_type_check
117
  @task
118
  def restaurant_scenic_location_scout_task(self) -> Task:
119
  """
 
128
  agent=self.restaurant_scout(),
129
  )
130
 
131
+ @typing.no_type_check
132
  @task
133
  def itinerary_compilation_task(self) -> Task:
134
  """
 
140
  config=self.tasks_config['itinerary_compilation_task'], llm=llm, max_iter=1, agent=self.itinerary_compiler()
141
  )
142
 
143
+ @typing.no_type_check
144
  @crew
145
  def crew(self) -> Crew:
146
  """
 
162
  agents_config = 'config/address_agents.yaml'
163
  tasks_config = 'config/address_tasks.yaml'
164
 
165
+ @typing.no_type_check
166
  @agent
167
  def address_summarizer(self) -> Agent:
168
  """
 
177
  allow_delegation=False,
178
  )
179
 
180
+ @typing.no_type_check
181
  @task
182
  def address_compilation_task(self) -> Task:
183
  """
 
192
  agent=self.address_summarizer(),
193
  )
194
 
195
+ @typing.no_type_check
196
  @crew
197
  def crew(self) -> Crew:
198
  """
db.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sqlite3
3
+ from datetime import datetime
4
+
5
+ _DB_FILE_NAME = 'query_logs.db'
6
+
7
+
8
+ def initialize_database() -> None:
9
+ """Create database and table if they don't exist"""
10
+ conn = sqlite3.connect(_DB_FILE_NAME)
11
+ c = conn.cursor()
12
+
13
+ # Create table
14
+ c.execute("""CREATE TABLE IF NOT EXISTS query_logs
15
+ (id INTEGER PRIMARY KEY AUTOINCREMENT,
16
+ timestamp DATETIME NOT NULL,
17
+ origin TEXT,
18
+ destination TEXT NOT NULL,
19
+ age INTEGER NOT NULL,
20
+ trip_duration INTEGER NOT NULL,
21
+ budget INTEGER)""")
22
+ conn.commit()
23
+ conn.close()
24
+
25
+ def retrieve_data():
26
+ """
27
+ Retrieves all data fron the table.
28
+ """
29
+
30
+ try:
31
+ # Connect to the SQLite database
32
+ conn = sqlite3.connect(_DB_FILE_NAME)
33
+ cursor = conn.cursor()
34
+
35
+ # Retrieve all data from the specified table
36
+ cursor.execute(f"SELECT * FROM query_logs")
37
+ data = cursor.fetchall()
38
+
39
+ # Close the database connection
40
+ conn.close()
41
+ for item in data:
42
+ print (item)
43
+
44
+ except sqlite3.Error as e:
45
+ print(f"Error: {e}")
46
+ return None
47
+
48
+
49
+ def log_query(origin: str, destination: str,
50
+ age: int, trip_duration: int, budget: int) -> None:
51
+ """Log a query to the database"""
52
+
53
+ # Check if file exists, if not initialize the db
54
+ if not os.path.isfile(_DB_FILE_NAME):
55
+ initialize_database()
56
+
57
+ conn = sqlite3.connect(_DB_FILE_NAME)
58
+ c = conn.cursor()
59
+
60
+ # Insert log record
61
+ c.execute(
62
+ """INSERT INTO query_logs
63
+ (timestamp, origin, destination, age, trip_duration, budget)
64
+ VALUES (?, ?, ?, ?, ?, ?)""",
65
+ (datetime.now(), origin, destination, age, trip_duration, budget),
66
+ )
67
+ conn.commit()
68
+ conn.close()
69
+
70
+ """
71
+ If this program is executed directly, just print out all the data in the tables
72
+ """
73
+ if __name__ == "__main__":
74
+ retrieve_data()