Workshop

Generate Trip using AI

Video thumbnail
Course icon

Sign up to watch this lesson (and more).

By logging in, you'll unlock full access to this and other free tutorials on JSM Pro.

Why? Logging in lets us personalize your learning experience, track your progress, and keep you in the loop with new workshops, coding tips, and platform updates.

You'll also be the first to know about upcoming launches, events, and exclusive discounts.

No spam—just helpful content to level up your skills.

If that sounds fair, go ahead and log in to continue →

Enter your name and email to get instant access

or

Already have an account? Log in
Lecture Summary

No specific content is available to summarize from the transcript provided.

  • No key takeaways can be derived since the transcript is empty.

Transcript

00:00:02 Okay, the form is here, but my trip to Bahamas is not yet ready.

00:00:07 Why is that?

00:00:08 Well, it's because we haven't yet implemented the Gemini AI itinerary generation.

00:00:14 So let's do that next.

00:00:15 You can head over to ai-studio.google.com and consent to sell your soul.

00:00:22 Once you do that, you'll see that you can get started with Gemini, but you'll have to sign in to get access to the dashboard.

00:00:30 Within the dashboard, you'll be able to create your API key.

00:00:34 So, just click Create API Key on the top right, and you can search for your Google project.

00:00:40 It automatically finds it right here, and you can create it in that existing project.

00:00:45 Once it gets generated, copy it, head back over to your application within your .env, and add it as Gemini.

00:00:54 I'll call it Gemini API key, and I'll paste the key that I just got.

00:00:59 But Gemini is not the only thing we'll use to generate our trips.

00:01:04 You'll want to head over to unsplash.com forward slash developers.

00:01:08 Unsplash being the largest image provider in the world that offers stock-free images.

00:01:14 So you'll want to register as a developer.

00:01:17 by filling out this form.

00:01:18 Once you verify your account via email, just go ahead to create your application.

00:01:23 Let's agree to all of these right here.

00:01:25 And I'll say travel agency.

00:01:29 and create the app.

00:01:31 Now it'll let you actually create the app.

00:01:34 So if you scroll down, you'll be able to see your key.

00:01:38 I'll copy the access key and save it to my app as Unsplash and I'll call it Unsplash access key.

00:01:48 Perfect.

00:01:49 Now let's actually put these great APIs to use within our code base.

00:01:54 To do that, I'll head over within my terminal and I'll run npm install at Google forward slash generative AI.

00:02:05 and press enter to install it.

00:02:07 Then we'll want to head over to routes.ts and we'll add a new route, but this time we'll add an API route.

00:02:18 Can you believe that?

00:02:20 An API back-end route within ReactJS.

00:02:25 No Next.js, just React.

00:02:28 That's what's possible with React Router v7.

00:02:31 So head over here and create a new route.

00:02:35 with a path of api create-trip and the file will be routes api create-trip.ts instead of tsx.

00:02:48 So if we do this properly and add a comma, that now allows us to create that file.

00:02:56 So head over to your File Explorer, head over within the app, Routes, and within Routes, create a new folder called API,

00:03:07 and within API, create a new file called CreateTrip.ts.

00:03:15 Within it, we'll deal with the logic of creating this trip.

00:03:19 And all of that will be just the regular function.

00:03:23 In this case, we can even call it an action.

00:03:26 So I'll say export const action is equal to an asynchronous function that gets access to the request.

00:03:35 which will be of a type action function args coming from React Router.

00:03:41 And then we can define exactly what this action will do.

00:03:44 For example, we're going to pass some props to it through the request object.

00:03:50 So we can automatically destructure them.

00:03:53 This is the data coming from the form.

00:03:56 So what do we have coming from the form?

00:03:59 We already saw it in that const log.

00:04:02 So I'll say const and destructure the country.

00:04:07 I'll also get the number of days.

00:04:11 Let's also get a travel style, interests, budget, group type, and the user ID.

00:04:21 And that'll be equal to await request.json.

00:04:25 Let me save this and reload the page.

00:04:29 I might also need to reload my terminal.

00:04:32 That is one thing that I noticed needs to be done after you add a new route.

00:04:37 So if I do this and reload...

00:04:39 We should be okay, I believe, but now we're getting cannot read properties of null, reading use context.

00:04:46 But after that, we're good.

00:04:48 So there's still some things that could be improved with the overall developer experience.

00:04:52 But again, being able to use server actions within React, pretty crazy, right?

00:04:59 Okay, so now that we have all of this info or the data from the form, how do we actually pass it to AI to generate it or to make something useful out of it?

00:05:09 I'll say const GenAI.

00:05:12 is equal to new GoogleGenerativeAI to which we need to pass the key.

00:05:18 So I'll say process.env.GeminiAPIKey and you can add an exclamation mark to let it know that we know that that variable will be there from ENVs.

00:05:30 We can do the same thing with the Unsplash key by saying const Unsplash API key is equal to process.env.UnsplashAxis key just like this.

00:05:44 We can then open up a try and catch block and in the catch, we can simply console that error saying error generating travel plan,

00:05:58 and then we can console log the error that happened.

00:06:01 But if everything is going well, then we need to figure out a prompt that we'll use to generate that trip.

00:06:10 So say const prompt is equal to a template string.

00:06:15 And here you can really go all out.

00:06:19 Template strings allow you to split them into multiple lines, so you can be very descriptive.

00:06:24 The more descriptive you are, the better it'll be.

00:06:27 So we'll need to say something like generate a number of days, day, itinerary for country based on the following info and then you can pass additional

00:06:44 user information such as the budget can be set to well a string of a specific budget you can repeat the same thing for what else do we have maybe interests

00:06:56 so we can close the interests right here and then pass over the interests And you can keep repeating that until you pass over all of the information.

00:07:06 But typically when you're telling AI what it needs to do, you also need to be very descriptive of the format in which you want to receive that data back.

00:07:14 So if you head over into the video kit, you'll see that here I provided the entire create trip prompt.

00:07:21 So just go ahead and delete the current one that we started typing, or you know what, type one yourself.

00:07:28 and then paste the one that we have right here.

00:07:31 You'll notice that this one looks like this.

00:07:36 It is exactly the same as we started typing it, but it also covers more different pieces of info, such as interests, travel style,

00:07:44 group type, and then I specify how it should return the itinerary and specify the lowest estimated price in a clean, non-markdown format with the following structure.

00:07:56 We want it to have a name, a description, estimated price, duration, budget, travel style, and so on.

00:08:04 Specify the best times to visit, share some weather info, the location, the itinerary, and then we specify how the itinerary should look like day by day.

00:08:14 The more info you give it, the better the result will be.

00:08:18 Finally, we are going to call that AI and pass over the prompt.

00:08:23 and that will result in the text result.

00:08:27 We can do that by calling await genai.getGenerativeModel and here you can choose whatever model you want.

00:08:37 In this case, I'll aim for something like let's do Gemini 2.0 Flash.

00:08:46 I think this one is pretty fast so we should get the results very quickly.

00:08:49 And we can also do generateContent based on the prompt, like this.

00:08:57 So now we're passing that prompt into it, and then we get back the trip data.

00:09:02 So const trip is equal to parse markdown to JSON of the text result dot response dot text.

00:09:14 This parse markdown to JSON is a function that while I was writing this app for the first time, I asked AI to actually write it,

00:09:22 which basically takes in a markdown text and it turns it into, well, JSON, right?

00:09:28 The way it works is it simply parses it and then it runs JSON.parse on it.

00:09:35 So now that we get this trip, what do you say that we also get the image of that country from the Unsplash API and then merge it with that result of the itinerary?

00:09:47 That's what'll make it stand out.

00:09:50 So I'll say const imageResponse is equal to await and we want to make a fetch request to.

00:09:58 https colon forward slash forward slash api dot unsplash dot com forward slash search forward slash photos question mark query is equal to and then we

00:10:12 can pass the country and then we can also pass some interests so that way it'll match very closely with what we need Alongside the interests,

00:10:22 we can also pass in the travel style, and then we can append the and sign, and then pass the client ID.

00:10:32 Client underscore ID is equal to Unsplash API key, because without it, it would not return anything.

00:10:41 So now that we have this image response, let's actually get some image URLs.

00:10:45 So I'll say const image URLs, is equal to, in parentheses, await, image response, dot json, outside of this parentheses,

00:10:56 we want to say dot results, dot slice, from 0 to 3, to get the first 3. And then we want to run the dot map on it, where we get each individual result

00:11:08 of a type any.

00:11:09 And for each one, we want to get back the result.

00:11:16 Or if it doesn't exist, we can get the null.

00:11:19 So once we have that, this will actually give us the images and prepare the URLs so we can save them into the database.

00:11:27 Finally, we are ready to create a trip within the database.

00:11:31 So I'll say const result is equal to a weight.

00:11:35 database.createdocument.

00:11:39 Make sure to import this database coming over from AppRite.

00:11:43 And we can pass in the database ID coming from the AppRite config, as well as AppRite config.trip collection ID.

00:11:55 We need to give it the ID of that specific trip.

00:11:58 So it'll be id.unique, also coming from AppRite.

00:12:04 And let's see why do I not have access to this createDocument.

00:12:08 Oh no, I have access to it, but it's saying that I need to pass a few more props, such as the last object, which contains the trip detail.

00:12:17 Again, I think in the database, we call the detail without the S, so make sure that you stay consistent.

00:12:23 And what we'll do here is say json.stringify and we'll pass over the entire trip that was generated for us by AI.

00:12:33 We are using the Stringify because it allows us to save the trip detail object as a string in the database and later on safely restore it by using JSON parse.

00:12:43 Alongside the trip details, we can also get the created at, which will be a new date, .to ISO string.

00:12:52 So we're getting the current date and time.

00:12:55 the image URLs attached to it, as well as the user ID.

00:12:59 So once we create this new result in the database, we'll return the data and pass over the ID as result dot dollar sign ID.

00:13:09 And this data is actually coming from React router because we need a way for us to return the data that is the result of this server action.

00:13:21 And in this case, I have this error issue.

00:13:23 It is just E.

00:13:24 Perfect.

00:13:25 So the only thing that remains for us to do is to call this API endpoint within our code base that is then calling additional API services from within

00:13:35 our form.

00:13:37 So we can head back over to Create Trip.

00:13:42 And go right here to where we were console logging the form outputs.

00:13:47 So if I now head back over here, we know where we were.

00:13:50 Right here, I'll just say const response is equal to await.

00:13:56 We're going to use a simple fetch to hit our API create trip endpoint.

00:14:02 And I'll also pass some options to it, such as a method of post.

00:14:09 Headers equal to content type will be set to application JSON, because just we want to pass some JSON over.

00:14:18 And finally, and most importantly, we want to pass over the body, which will be stringified.

00:14:23 So I'll say JSON.stringify an object that'll have the country coming from form data.

00:14:32 dot country, number of days, which is form data dot duration.

00:14:40 We'll also get access to the travel style, which is equal to form data dot travel style.

00:14:48 Interests equal to form data dot interests.

00:14:53 budget equal to form data dot budget, group type equal to form data dot group type.

00:15:02 And yeah, you definitely could have destructured the form data, so it'll be much easier to get it.

00:15:08 That way you wouldn't have to repeat yourself.

00:15:10 Here, I believe we stored it without the S, just interest.

00:15:14 And then finally, group type.

00:15:17 And to it, we can also pass the user ID as user.$id.

00:15:23 And this is making a request to the trip.

00:15:26 So this response right here should correlate with what we are returning from the actual server action, which is basically the generated trip.

00:15:37 So let's actually extract it.

00:15:40 Right after the response, I'll say const result of a type createTripResponse will be equal to awaitResponse.json.

00:15:51 And then we can check if result has its own ID, then we can navigate over to that trip's detail page.

00:16:00 So right at the top of this component, I will use the useNavigate hook.

00:16:08 So I'll say const navigate is equal to useNavigate, which is coming over from React router.

00:16:16 And then right here, I'll navigate over to forward slash trips.

00:16:23 forward slash result dot ID.

00:16:26 So we want to go to dot trip details page.

00:16:29 And we can also add an else.

00:16:31 So I'll say else.

00:16:33 We can simply console dot error saying failed to generate a trip.

00:16:39 Perfect.

00:16:40 So now we have completed the second piece of the puzzle.

00:16:43 The first one being the actual Gemini generation and adding Unsplash images and returning that as an output of our own server API endpoint action.

00:16:54 And then the second part was actually passing the data to it while calling it from our front end.

00:17:00 And then navigating over to the trip details page.

00:17:03 So what do you say that we give it a shot?

00:17:05 I will open up my browser in its full glory, enter a country.

00:17:10 I'm very interested.

00:17:11 What will it do for my country?

00:17:14 In this case, you can put yours to see what kind of trip does it generate.

00:17:19 I'll give it seven days.

00:17:21 For the group type, let's be romantic and do a couple.

00:17:24 Travel style will be interesting.

00:17:28 Let's do relaxed.

00:17:30 Let's do historical sites for interests.

00:17:34 And for this person, let's say that budget is not really important.

00:17:37 They want to do luxury.

00:17:39 Perfect.

00:17:40 So let's generate a trip.

00:17:42 It'll take some time to actually generate it, as you can see, because AI right now is thinking, it's producing the output and it's sending it over to our app.

00:17:54 Looks like the generation stopped, so either something went right or something went wrong.

00:18:01 So if we open up the console, it looks like we got error generating trip with a syntax error of unexpected token U.

00:18:11 Unexpected is not a valid JSON.

00:18:14 It's good that we console log the error, so it actually comes from error generating trip.

00:18:20 So that should help us a bit.

00:18:21 You can see that it's not coming right here as the else statement.

00:18:25 It's not coming as part of our own API response, rather it's failing the right here.

00:18:30 Error generating trip.

00:18:32 If I open up my dev terminal, we can see that we got the issue here as well.

00:18:37 And it says, value is not JSON serializable.

00:18:40 And we got another error, this time from our API, saying AppRateException collection with a requested ID could not be found.

00:18:48 Okay, interesting.

00:18:49 So now it's pretty clear where the issue is.

00:18:52 It is back within our server action where we're trying to generate a trip.

00:18:57 That is right here.

00:19:00 So I'm pointing over to AppRideConfig.

00:19:03 It's saying that the collection with the requested ID could not be found.

00:19:06 So obviously this is the issue.

00:19:09 Apprite config, trip collection ID.

00:19:12 Let's see, trip collection ID, importing it from Vite Apprite, trips collection ID.

00:19:19 And if I head over to my ENVs, right here, I'm saying Apprite, trips collection ID.

00:19:27 So this is looking good to me.

00:19:30 So it might be best to cross-verify over on Apprite dashboard by heading over to databases.

00:19:36 and then Tripp's collection.

00:19:39 I'll recopy this ID and then back in our application, I'll paste it here.

00:19:45 Oh, looks like I missed a number right there.

00:19:47 So it's actually highly likely that it worked for you on the first try, but while I was messing with my ENVs, well, looks like I deleted a number accidentally.

00:19:57 So if I head back over to my application and click generate Tripp one more time, let's see what happens now.

00:20:05 It is generating, and it looks like it stopped one more time.

00:20:10 If it didn't stop, we would be redirected to another page.

00:20:13 So if I open up the console, looks like it's pointing to the same issue, is it?

00:20:18 Maybe I have to reload the terminal.

00:20:21 Now that I reloaded it, it might work.

00:20:23 Who knows?

00:20:24 Third time's the charm.

00:20:26 Okay, the third time didn't work.

00:20:28 It's not the charm.

00:20:29 So it looks like this time we got a different error saying that our document structure is invalid, missing field trip details.

00:20:37 So it looks like I did actually rename it to details and not detail.

00:20:42 So if I go right here and change this over to trip details, we can cross verify that right here.

00:20:49 Yep, it's trip details.

00:20:52 For you it might be detail, you'll need to check out with your own database.

00:20:56 So, let me give it a go.

00:20:57 Maybe it worked for you on the first try and you're just seeing me fail.

00:21:00 How does that make you feel?

00:21:02 Okay, there we go.

00:21:03 I didn't think I would be so happy to see a 404 page, but I am.

00:21:08 The fact that we're seeing this 404 page means that we came all the way to the end of our process, because if everything goes right and if the new record

00:21:19 has been created in the database, only then will it redirect us to that trip details page.

00:21:25 And even though we cannot see the whole thing right away, at least we cannot see it in this beautiful layout, it doesn't mean that it doesn't exist.

00:21:33 If you head over to AppRide, go to the trips database and check out documents, you'll see that one of our users has created their first trip.

00:21:42 So if you want to check it out, you can just head over to data and check this out.

00:21:47 We have three separate image URLs.

00:21:50 matching what our user searched for.

00:21:52 Yep, you can actually see those images already by simply navigating over to this URL, and you'll see some of the nice photos.

00:22:01 These are looking good.

00:22:03 And we also have the created ad field, the payment link, which we'll add later, the user ID that created it, and most importantly,

00:22:12 the trip details generated by AI.

00:22:17 So here you can see that it actually gave a name to a trip, luxury, creation, history, and romance, a couple's escape.

00:22:23 And it gave us a lot of information that we might want to use to nicely display right within our application, which is exactly what we'll do in the next lesson.

00:22:33 But first, I'll go ahead and commit the changes we have right now.

00:22:38 I think I might have forgot to do it in the last lesson, but that's fine.

00:22:42 We'll do it right now.

00:22:43 I'll say git add dot git commit dash m and I'll call it generate trip using AI and I'll push it.

00:22:55 So in the next lesson, let's focus on generating this beautiful trip details page.

00:23:01 So we can finally see what our app actually does.

00:23:05 Now that we have spent a lot of time making it happen.

00:23:08 Great work.

00:23:09 We're past the most complex parts of the app.

00:23:12 So if you reach this point, leave a comment down below and let me know, Hey Adrian, I passed the AI trip generation.

00:23:20 And now I'm ready to dive into the trip details.

00:23:24 See you there.

Loading...

How did you manage to remove the blur property and reach here?

A

I used sheer determination and problem-solving skills.

B

I inspected the code, found the blur effect, and disabled it.

C

I randomly clicked buttons until something worked.

D

I have no idea, but I made it!

glass-bbok

Test Your Knowledge, Level Up

Upgrading gives you access to quizzes so you can test your knowledge, track progress, and improve your skills.

Upgrade your account

0 Comments

glass-bbok

No Comments Yet

Be the first to share your thoughts and start the conversation.

tick-guideNext Lesson

Trip Details