Check out a free preview of the full Build an AI-Powered Fullstack Next.js App, v3 course

The "Search API & Results" Lesson is part of the full, Build an AI-Powered Fullstack Next.js App, v3 course featured in this preview video. Here's what you'd learn in this lesson:

Scott finishes the search feature. The question API endpoint is added to the application. A loading state is added to the Question component, and the results are displayed when a response is received.


Transcript from the "Search API & Results" Lesson

>> Right now, we have a qa done, assuming it works. [LAUGH] And what we need to do now is make sure we call this an API route, so we can call it from the front-end of that form that we created with our input. So let's make a new API route.

We'll go to api/, instead of doing /journal, we'll just do api/question. And make a route.ts in there if you're using TypeScript. And we'll make this a POST request, so I'll just export const POST. Like that, and we'll need the request cuz we need to get the question that you ask, so we'll get the request here.

And then to get the question from the request, we'll de-structure this. It'll be an object cuz we'll set up an object that has a question property on it. And that's gonna from request.json, like that. And then we need to get the user cuz we gotta find all the users' entries.

So we need to know who this user is, and we have our utility for that, which is getUserByClerkID. And then now we just need to get all the entries, so we can say entries = await, we bring in prisma.journalEntry.findMany. For now, we'll just find them all that where, userId is

And I really only want to select the, The entries, or I'm sorry, the content, cuz we're only using or we're making the docs. No, I guess we're using the id createdAt and content, so I'm only gonna go select those. So I think id is already there, but I was gonna put it anyway.

It always comes with an id. We want content, and then we want createdAt. Why do I do this? It's just performance on the database. The database grabs less data, it moves faster. And it's less memory. And this was 100,000 entries, and each entry had 30 properties on it.

It's a smaller memory footprint, we've only selected three properties. So we got that, and now we can ask the question. So we can say, give me the answer, await the qa function from AI. And it takes in our question, and it takes in our entries. And then we'll just send that back on NextResponse.json, always sending back on a data prompt for me, and something like the answer.

Okay, so we have that. Now we just need to make a utility function in our API utils. We'll make one that's called askQuestion. So export const askQuestion. It's gonna take in a question. It's gonna be async. And I'm just gonna copy this whole thing, paste that. And POST is good.

It's not /journal, it's /question now. And we just need to pass up a body with a JSON.stringify of an object that has a question property on it, and that's it. Any questions on that? Okay, we are almost there. What we need to do now is hook this up to our form being submitted and do something with the response, assuming [LAUGH] any of this works.

So let's do that. Let's close all my windows there. So we'll go back to the app page and the journal. We'll go to the question, and here we go, so handleSubmit. So async function now. And we just wanna get the answer. So we can say answer = await, ask the question, which is from @/utils/api.

The question is just gonna be value. I'm gonna do some loading states here cuz it's going to take a long time to come back, I'm guessing. So I'll just say loading, setLoading. SetLoading(true) when we start, setLoading(false) when we're done. Also clear the input, so setValue to empty string.

So we got our answer. And then I need some state to keep track of the answer, so I'll make some state for that, and I'll say, response, I guess. And I'll say setResponse to answer. And then from there, just some loading states, so, We can disable the button if loading is true.

We can disable the input if loading is true. And we'll just show some stuff down here, so if loading, We wanna show just some really .div. That says loading. Like that, and then when we get the response, we can show that. What did I call it? I guess I didn't spell it right.

There we go. Get the response, and then if there's a response, then just show it here. Cool, and, Should be good. Very simple, just doing a simple loading state, keeping track of the input values and the actual response that we get back so we can put it on the screen.

This would have been a lot harder to do with a server action possible. But eventually, you still have to probably do a client component anyway to handle some of the stuff you need from the server actions. So I'm just gonna keep it like that, and let's see what we broke.

So I guess I should just add some more entries here. Cohere, why does it want Cohere? Okay. I don't know why it's asking. So Cohere, it's a competitor to OpenAI. It's actually really cool. I don't know why it wants Cohere. Let me just double check my AI thing to make sure I didn't do import where it's trying to get Cohere from somewhere.

I mean, I'll install it. I just don't know why it's asking for it, it's weird, if it makes it happy. I guess it just really wanted that. [LAUGH] That was weird. I'm gonna make a new entry. Cool, I'm gonna write about my day. This is a very bad day for me.

I didn't get the promotion that I wanted. So I'll save that. I'll make another one here. This one is, let's say this was a very good day. Today, my brother graduated from school. So we'll have another good one. And that should be good enough. I just realized I never went back and changed these cards.

I guess we could do that too, but I feel like you all know how to do that. So now I can say, have I been in a good mood? I can ask that, cuz I don't know if I'm in a good mood or not, and let's see what we broke.

Yes, you have been in a good mood. [LAUGH] So apparently, I haven't. So let me ask you this, have I been in a bad mood overall this week? I guess in its head, it's like, well, you have been in a good mood, but that would mean you're in a good mood.

It's like one of these, you are in a good mood at one point. So yes, you have been in a good mood. So you gotta be very specific with it, so. The new context is not useful in refining the original answer. Therefore, the original answer still stands. Based on the new context, it is possible that you have been in a bad mood overall this week due to not getting the promotion you wanted.

However, without additional information about your mood throughout the rest of the week, it's still difficult to determine for certain. So yeah, it's right, but it's kinda weird. You know you're not talking to a person. And there's ways to fix this to make it seem better. I can, for instance, do something like, where is it?

I can tell this thing to talk like a pirate if I want to, and it'll talk like a pirate, right? So [LAUGH] there's really not much you can't do here. So you can steer it. You can make it do stuff, but for the most part, it seems good.

Any questions on this? Yes.
>> There was just a comment that in your langchain/embeddings import that you would add /openai to the end of it?
>> And not the root, and that caused the Cohere? That makes sense. So if I did that, then it wouldn't have tried to bring in that one file that probably had Cohere there.

That makes sense. Yeah, I don't know why or who is in charge of their, so langchain, they are mostly a Python shop, so I don't think JavaScript is their native thing. So the way that they export their stuff is not how people do it in JavaScript. It definitely is like Python.

So it's very confusing and just unnatural for me to understand how they do that. I can never remember any of these imports. They've already changed on me four times.
>> That part at least is very JavaScripty.
>> That part is JavaScripty, yeah, that part just makes it, yeah.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now