1
00:00:00,060 --> 00:00:02,640
In this video, we'll be writing the endpoint

2
00:00:02,640 --> 00:00:05,880
that will take a user's request for a place,

3
00:00:05,880 --> 00:00:09,620
city or country they wish to visit, an optional

4
00:00:09,620 --> 00:00:12,860
list of preferences and then call Gemini to

5
00:00:12,860 --> 00:00:15,380
suggest travel destinations.

6
00:00:15,380 --> 00:00:16,420
Sounds fun?

7
00:00:16,420 --> 00:00:18,280
Let's dive in.

8
00:00:18,280 --> 00:00:20,760
First, we'll be modeling the request data

9
00:00:20,760 --> 00:00:22,460
using Pydantic.

10
00:00:22,460 --> 00:00:25,740
So to get started with that, we need to import

11
00:00:25,740 --> 00:00:27,840
some models.

12
00:00:27,840 --> 00:00:31,080
So here in VSCode, let us scroll up, and just

13
00:00:31,080 --> 00:00:37,860
under OS, let us say from Pydantic, import

14
00:00:37,860 --> 00:00:40,700
base model.

15
00:00:40,700 --> 00:00:47,120
We'll also be getting some items from our

16
00:00:47,120 --> 00:00:52,060
typing library that will be list and optional,

17
00:00:52,060 --> 00:00:54,720
and we'll also import JSON so that we can

18
00:00:54,720 --> 00:00:57,120
send back JSON responses.

19
00:00:57,120 --> 00:01:00,000
Good, now we will need to define the pedantic

20
00:01:00,000 --> 00:01:02,940
model that will contain the data we are expecting

21
00:01:02,940 --> 00:01:04,860
in our request.

22
00:01:04,860 --> 00:01:10,360
So let's put it just above our endpoint.

23
00:01:10,360 --> 00:01:16,600
Let us create the class LocationRequest that

24
00:01:16,600 --> 00:01:19,060
will inherit this model.

25
00:01:19,060 --> 00:01:22,620
And for our request, we expect a location

26
00:01:22,620 --> 00:01:26,760
parameter which is a string and a preferences

27
00:01:26,760 --> 00:01:34,940
parameter which is an optional list of strings.

28
00:01:34,940 --> 00:01:38,040
And we can simply default that to an empty

29
00:01:38,040 --> 00:01:38,880
list.

30
00:01:38,880 --> 00:01:40,480
Good.

31
00:01:40,480 --> 00:01:42,960
Now that we have defined the structure of

32
00:01:42,960 --> 00:01:45,000
the data we're expecting, let us write our

33
00:01:45,000 --> 00:01:48,360
endpoint for our location text-based search

34
00:01:48,360 --> 00:01:51,080
and also define its handler.

35
00:01:51,080 --> 00:01:51,320
We're going to

36
00:01:51,320 --> 00:01:55,140
be doing that just below the root endpoint.

37
00:01:55,140 --> 00:01:57,360
Here we'll say app dot, this will be a post

38
00:01:57,360 --> 00:02:02,680
endpoint, and as we saw in our plan, it will

39
00:02:02,680 --> 00:02:11,520
be slash API for slash suggest by location.

40
00:02:11,520 --> 00:02:13,720
We can then define an handler for this.

41
00:02:13,720 --> 00:02:16,340
This will be an async function because we're

42
00:02:16,340 --> 00:02:18,460
going to be calling the Gemini API and that

43
00:02:18,460 --> 00:02:20,800
is an asynchronous process.

44
00:02:20,800 --> 00:02:26,460
So we say our handler will be suggest, underscore

45
00:02:26,460 --> 00:02:30,040
buy, underscore location, and it will take

46
00:02:30,040 --> 00:02:37,360
in a request with the shape of location request.

47
00:02:37,360 --> 00:02:39,160
Good.

48
00:02:39,160 --> 00:02:41,100
Let's put some small documentation here and

49
00:02:41,100 --> 00:02:48,520
say generates travel suggestions based

50
00:02:48,520 --> 00:02:51,280
on location search.

51
00:02:51,280 --> 00:02:52,280
Awesome.

52
00:02:52,280 --> 00:02:54,200
Now, inside this function, we need to make

53
00:02:54,200 --> 00:02:56,680
a request to the Gemini API using the data

54
00:02:56,680 --> 00:02:58,700
that we collected from our request.

55
00:02:58,700 --> 00:03:00,960
To kick that off, let's start by opening a

56
00:03:00,960 --> 00:03:03,460
try-except block, where we'll be wrapping

57
00:03:03,460 --> 00:03:05,660
our Gemini request.

58
00:03:05,660 --> 00:03:07,820
So down here, I'm just going to say try.

59
00:03:07,820 --> 00:03:09,580
We'll leave this empty for now.

60
00:03:09,580 --> 00:03:17,780
And we'll say accept exception as e.

61
00:03:17,780 --> 00:03:20,660
And here, we're just going to raise an HTTP

62
00:03:20,660 --> 00:03:24,640
error.

63
00:03:24,640 --> 00:03:27,760
With an HTTP exception, so the status code

64
00:03:27,760 --> 00:03:28,960
2500,

65
00:03:28,960 --> 00:03:30,940
indicating a server error.

66
00:03:30,940 --> 00:03:34,700
That would be status code, not status.

67
00:03:34,700 --> 00:03:36,960
Then we'll provide some detail so that the

68
00:03:36,960 --> 00:03:37,780
client can

69
00:03:37,780 --> 00:03:41,080
understand what is going on.

70
00:03:41,080 --> 00:03:45,040
And here, we'll simply say, error generating

71
00:03:45,040 --> 00:03:48,360
suggestions.

72
00:03:48,360 --> 00:03:53,780
And let us send back the error as a string.

73
00:03:53,780 --> 00:03:54,620
Good.

74
00:03:54,620 --> 00:03:56,700
Now, with this in place, we can now go into

75
00:03:56,700 --> 00:03:57,760
the Try section

76
00:03:57,760 --> 00:04:01,080
to prepare our data, send our Gemini request,

77
00:04:01,080 --> 00:04:03,500
and return the response.

78
00:04:03,500 --> 00:04:05,840
First, let us prepare our list of preferences

79
00:04:05,840 --> 00:04:07,660
for the prompt

80
00:04:07,660 --> 00:04:10,200
by converting it from a list into a single

81
00:04:10,200 --> 00:04:12,220
sentence.

82
00:04:12,220 --> 00:04:15,120
Let's go into the Try section here.

83
00:04:15,120 --> 00:04:19,279
Here we can say, preferences, text.

84
00:04:19,279 --> 00:04:21,420
Let's set that to an empty string.

85
00:04:21,420 --> 00:04:24,640
We can then say from the request,

86
00:04:24,640 --> 00:04:28,040
if we have preferences, because it's an optional

87
00:04:28,040 --> 00:04:29,540
piece of data

88
00:04:29,540 --> 00:04:33,220
that the client can send, we can then build

89
00:04:33,220 --> 00:04:34,220
our preferences

90
00:04:34,220 --> 00:04:42,480
text here and say a string newline user preferences

91
00:04:42,480 --> 00:04:47,580
and this idea we can convert our user preferences

92
00:04:47,580 --> 00:04:51,380
list into a string by making it a comma separated

93
00:04:51,380 --> 00:05:03,000
string so join request dot preferences.

94
00:05:03,000 --> 00:05:05,160
So this will simply build a preferences text

95
00:05:05,160 --> 00:05:08,260
that we can simply embed in our prompt if

96
00:05:08,260 --> 00:05:11,200
the user sends a list of preferences.

97
00:05:11,200 --> 00:05:12,800
Now with this in place, we can now write our

98
00:05:12,800 --> 00:05:13,780
full prompt.

99
00:05:13,780 --> 00:05:16,040
It's going to be a pretty substantial amount

100
00:05:16,040 --> 00:05:18,300
of text and I'm sure you don't just want

101
00:05:18,300 --> 00:05:21,260
to sit there and watch me type all that.

102
00:05:21,260 --> 00:05:24,200
So I'll just copy it from the completed version

103
00:05:24,200 --> 00:05:28,080
of the exercise files and bring it here.

104
00:05:28,080 --> 00:05:32,600
So grab the prompt and paste it here.

105
00:05:32,600 --> 00:05:35,740
As you can see, it's pretty lengthy.

106
00:05:35,740 --> 00:05:44,820
Let me format that a little bit, let's say,

107
00:05:44,820 --> 00:05:51,600
and we'll put this here, good.

108
00:05:51,600 --> 00:05:54,280
So let us go through the prompt that we just

109
00:05:54,280 --> 00:05:55,440
brought in.

110
00:05:55,440 --> 00:05:58,660
It says, you are a travel expert.

111
00:05:58,660 --> 00:06:01,220
Generate five travel destination suggestions

112
00:06:01,220 --> 00:06:04,940
near or related to the location that we sent.

113
00:06:04,940 --> 00:06:08,000
We also give it our preferences text if it

114
00:06:08,000 --> 00:06:10,180
exists, else it will just be an empty string

115
00:06:10,180 --> 00:06:13,100
and it will be completely ignored.

116
00:06:13,100 --> 00:06:15,340
Then our prompt goes further to say that for

117
00:06:15,340 --> 00:06:19,200
each destination, provide name of the destination,

118
00:06:19,200 --> 00:06:22,680
Brief description which is 2-3 sentences Best

119
00:06:22,680 --> 00:06:23,920
time to visit

120
00:06:23,920 --> 00:06:27,340
Main attractions we want to list 3 And an

121
00:06:27,340 --> 00:06:29,840
estimated budget level using the indicators

122
00:06:29,840 --> 00:06:33,820
budget, moderate or luxury Then we also want

123
00:06:33,820 --> 00:06:36,060
a formatted response back

124
00:06:36,060 --> 00:06:40,120
as a JSON array Each object in the collection

125
00:06:40,120 --> 00:06:41,400
should have

126
00:06:41,400 --> 00:06:43,560
a name field which will be the destination's

127
00:06:43,560 --> 00:06:44,440
name

128
00:06:44,440 --> 00:06:46,060
A description field which will be a brief

129
00:06:46,060 --> 00:06:47,820
description of the destination

130
00:06:47,820 --> 00:06:50,640
the best time to visit, attractions which

131
00:06:50,640 --> 00:06:54,600
will be a list of attractions, and a budget

132
00:06:54,600 --> 00:06:57,180
level which will be picked between the options

133
00:06:57,180 --> 00:07:00,000
budget, moderate and luxury.

134
00:07:00,000 --> 00:07:02,640
And we give it a final instruction by saying

135
00:07:02,640 --> 00:07:05,500
only return the JSON array, no additional

136
00:07:05,500 --> 00:07:06,020
text.

137
00:07:06,020 --> 00:07:08,500
So we don't want any explanation or descriptions

138
00:07:08,500 --> 00:07:09,860
from the model.

139
00:07:09,860 --> 00:07:14,340
Just simply return the JSON array as a string.

140
00:07:14,340 --> 00:07:15,780
Great.

141
00:07:15,780 --> 00:07:18,980
Now we can send our prompt to the Gemini API.

142
00:07:18,980 --> 00:07:20,800
So let's go ahead and do that.

143
00:07:20,800 --> 00:07:22,760
It's going to come down here.

144
00:07:22,760 --> 00:07:26,560
And we're going to say response equals.

145
00:07:26,560 --> 00:07:30,460
We'll take our GenAI client.

146
00:07:30,460 --> 00:07:39,880
We'll say models.generateContent.

147
00:07:39,880 --> 00:07:40,820
That's good.

148
00:07:40,820 --> 00:07:43,660
Now inside here, we need to pass our model.

149
00:07:43,660 --> 00:07:46,980
And that will be our constant that we defined

150
00:07:46,980 --> 00:07:48,480
up here,

151
00:07:48,480 --> 00:07:55,220
which is Gemini model.

152
00:07:55,220 --> 00:07:59,520
And then we need to also define a content

153
00:07:59,520 --> 00:08:01,540
property, which

154
00:08:01,540 --> 00:08:04,760
will be set to our prompt.

155
00:08:04,760 --> 00:08:07,900
And once we have the response back,

156
00:08:07,900 --> 00:08:17,200
Let us get the response text by saying response.text

157
00:08:17,200 --> 00:08:20,560
and we want to strip it of whitespaces so

158
00:08:20,560 --> 00:08:22,100
I'm just going to call the strip function

159
00:08:22,100 --> 00:08:24,300
on it.

160
00:08:24,300 --> 00:08:26,460
Good.

161
00:08:26,460 --> 00:08:28,800
Now that we have our response text, we need

162
00:08:28,800 --> 00:08:31,980
to clean up any markdown code because Gemini

163
00:08:31,980 --> 00:08:34,900
When I send our results which we have told

164
00:08:34,900 --> 00:08:39,659
it to send as a list of destination objects,

165
00:08:39,659 --> 00:08:43,020
it sends it as Markdown and it denotes it

166
00:08:43,020 --> 00:08:44,540
as JSON.

167
00:08:44,540 --> 00:08:47,740
So we need to clean up all that Markdown information

168
00:08:47,740 --> 00:08:51,520
so that we get clean JSON string that we can

169
00:08:51,520 --> 00:08:53,000
then parse.

170
00:08:53,000 --> 00:08:55,920
So let's go ahead and do that.

171
00:08:55,920 --> 00:09:01,540
Next we'll check if our response text starts

172
00:09:01,540 --> 00:09:10,960
with the markdown label of json.

173
00:09:10,960 --> 00:09:15,260
If it does then we'll simply strip out the

174
00:09:15,260 --> 00:09:20,520
first 7 characters which is this3 and the

175
00:09:20,520 --> 00:09:22,020
word json.

176
00:09:22,020 --> 00:09:27,560
We'll say response underscore text and start

177
00:09:27,560 --> 00:09:34,440
after the first 7 characters.

178
00:09:34,440 --> 00:09:38,440
Next we check once again if our response text

179
00:09:38,440 --> 00:09:48,180
starts with just the backticks.

180
00:09:48,180 --> 00:09:52,860
If so, we can simply copy this and say we

181
00:09:52,860 --> 00:09:58,740
want to strip the first three characters.

182
00:09:58,740 --> 00:10:05,620
Also, if our response text ends with the three

183
00:10:05,620 --> 00:10:08,780
backticks, which most likely if it has the

184
00:10:08,780 --> 00:10:10,660
first set of backticks, it would have the

185
00:10:10,660 --> 00:10:12,940
last set of backticks.

186
00:10:12,940 --> 00:10:19,980
If it does, then what we want to do is to

187
00:10:19,980 --> 00:10:27,060
get rid of those final three backticks.

188
00:10:27,060 --> 00:10:29,540
Good.

189
00:10:29,540 --> 00:10:32,260
And once we are done with this, we also want

190
00:10:32,260 --> 00:10:36,200
to still strip our response text of any white

191
00:10:36,200 --> 00:10:37,080
space.

192
00:10:37,080 --> 00:10:40,600
Just going to copy the response text and call

193
00:10:40,600 --> 00:10:43,640
the strip function on it.

194
00:10:43,640 --> 00:10:45,360
Good.

195
00:10:45,360 --> 00:10:47,600
Now that we've cleaned up our markdown, we

196
00:10:47,600 --> 00:10:50,120
can now pass it and return our destinations

197
00:10:50,120 --> 00:10:51,840
back to the user.

198
00:10:51,840 --> 00:10:53,320
So let's do that next.

199
00:10:53,320 --> 00:10:58,400
We're going to say destinations be equal to

200
00:10:58,400 --> 00:11:01,660
json.loads,

201
00:11:01,660 --> 00:11:06,020
then we can pass this, our response

202
00:11:06,020 --> 00:11:07,240
text.

203
00:11:07,240 --> 00:11:09,940
And then to the client, we can simply return

204
00:11:09,940 --> 00:11:19,900
our dictionary of destinations.

205
00:11:19,900 --> 00:11:20,900
Awesome.

206
00:11:20,900 --> 00:11:25,200
We have now finished with our text-based search

207
00:11:25,200 --> 00:11:26,600
endpoint.

208
00:11:26,600 --> 00:11:28,680
Now, to ensure that everything we just did

209
00:11:28,680 --> 00:11:31,620
is working as expected, let us test it out

210
00:11:31,620 --> 00:11:35,920
and see if we can send a search query to it

211
00:11:35,920 --> 00:11:40,500
and get results back from the Gemini API.

212
00:11:40,500 --> 00:11:42,580
Now to do that, first you should make sure

213
00:11:42,580 --> 00:11:44,340
that the file is saved.

214
00:11:44,340 --> 00:11:47,160
Then we need to put up our command line and

215
00:11:47,160 --> 00:11:49,600
run our server.

216
00:11:49,600 --> 00:11:52,320
Our server runs without errors.

217
00:11:52,320 --> 00:11:55,080
Now let us head to our browser and check out

218
00:11:55,080 --> 00:11:57,900
the documentation.

219
00:11:57,900 --> 00:11:59,560
Now back here in our browser, we previously

220
00:11:59,560 --> 00:12:02,520
had just the root endpoint, but now if we

221
00:12:02,520 --> 00:12:06,320
refresh this, we now have two endpoints, our

222
00:12:06,320 --> 00:12:08,720
root endpoint, which is a GET endpoint, and

223
00:12:08,720 --> 00:12:11,760
our new SUGGEST BY LOCATION endpoint, which

224
00:12:11,760 --> 00:12:13,040
is a POST endpoint.

225
00:12:13,040 --> 00:12:14,580
So let's test this.

226
00:12:14,580 --> 00:12:16,380
Let's expand it.

227
00:12:16,380 --> 00:12:19,820
Then we see the data it takes, location, and

228
00:12:19,820 --> 00:12:21,540
a list of preferences.

229
00:12:21,540 --> 00:12:24,220
to click try out.

230
00:12:24,220 --> 00:12:28,260
For the location, let's put in Paris.

231
00:12:28,260 --> 00:12:33,500
For the preferences, let's say beaches.

232
00:12:33,500 --> 00:12:36,600
And cuisine.

233
00:12:36,600 --> 00:12:40,820
And now we can simply click execute.

234
00:12:40,820 --> 00:12:43,220
Loading as it's performing an asynchronous

235
00:12:43,220 --> 00:12:44,640
operation.

236
00:12:44,640 --> 00:12:48,660
And once it's done, we scroll down, we see

237
00:12:48,660 --> 00:12:51,220
we get a 200 okay requests.

238
00:12:51,220 --> 00:12:51,720
So our request

239
00:12:51,720 --> 00:12:52,740
was successful.

240
00:12:52,740 --> 00:12:55,140
And we get back a list of destinations.

241
00:12:55,140 --> 00:12:57,640
As you can see, we have destinations.

242
00:12:57,640 --> 00:13:00,420
And we have the list.

243
00:13:00,420 --> 00:13:04,180
And inside the list, we have objects of destinations

244
00:13:04,180 --> 00:13:04,800
that have been

245
00:13:04,800 --> 00:13:07,540
suggested by the Gemini API.

246
00:13:07,540 --> 00:13:09,240
Down here, we have St.

247
00:13:09,240 --> 00:13:11,620
Malo, we have the description,

248
00:13:11,620 --> 00:13:13,820
The best time to visit is May to September

249
00:13:13,820 --> 00:13:17,580
and we have the top attractions and budget

250
00:13:17,580 --> 00:13:19,740
level which is set to moderate.

251
00:13:19,740 --> 00:13:20,620
Awesome.

252
00:13:20,620 --> 00:13:23,320
As you can see our endpoint works fine

253
00:13:23,320 --> 00:13:25,220
and in the next video we'll be working on

254
00:13:25,220 --> 00:13:26,720
the front end side of things

255
00:13:26,720 --> 00:13:29,180
and integrating our search feature with this

256
00:13:29,180 --> 00:13:30,520
search endpoint.

257
00:13:30,520 --> 00:13:32,000
See you there.

