Unlock the power of prompt engineering with JSON and Jinja by learning how to obtain structured data from AI responses. Enhance your skills in parsing JSON and embedding details dynamically into HTML templates.
Key Insights
- Develop detailed and specific prompts to guide AI toward structured JSON responses, including key movie details such as title, year, director, stars, genre, and memorable quotes.
- Implement effective JSON parsing to extract individual data points from AI responses, then render this structured content dynamically using Jinja templating within HTML.
- Create targeted system prompts by clearly defining the AI role (e.g., film historian and critic) to ensure relevant and high-quality responses.
Note: These materials offer prospective students a preview of how our classes are structured. Students enrolled in this course will receive access to the full set of materials, including video lectures, project-based assignments, and instructor feedback.
This is a lesson preview only. For the full lesson, purchase the course here.
Okay, Lab 3: Prompt Engineering, JSON, and Jinja. Again, lab—take a stab at it, read the instructions, see what you can do, even if you can do only a portion of it. Even if you just do the Save As—just being able to read documentation (technical writing) and act on it is a good skill. You don’t have to get anywhere near done with this.
So once you watch the actual solution that I'm about to give you, you’ll hopefully have a keener grasp of what's going on. So pause the video, tackle the lab, or just let it keep running and treat it like a normal lesson. All these labs can be treated as if they’re normal lessons—you just let them roll.
All right. In this lab, you will work on your prompt engineering skill by instructing the AI to respond to your question with a finely detailed, multi-part answer in JSON format. You will handle the response by parsing the JSON and outputting the values to variables in the Jinja HTML file.
So rather than just handing off one variable in double curly braces, you’ll have multiples. From server03py, do a Save As and call the new file server3. Again, pause if you're going to do it, because this is the solution I’m implementing now.
Okay, continuing with the lab03 solution. We're going to modify your prompt—your chat question—by requesting that the AI come up with an example of a great ’90s movie. Spoiler alert: it picks Pulp Fiction as the number one choice a lot.
Engineer the prompt with specific content. In fact, I think we're going to add something here.
We want quotes. We want good quotes. We want Pulp Fiction quotes—Big Kahuna Burger—that kind of stuff, right? We're going to add that.
Tell us the movie, when it was made, who’s in it, who’s the director, and give us some quotable quotes. Goodfellas*—another one from the ’90s—seems to be the AI’s go-to first choice, though typically Pulp Fiction (1994) comes up a lot. And why not? Great movie.
Engineer the prompt with specific content. In the system content, inform the AI that it is some kind of movie expert. You don’t just tell it you’re a general chatbot.
You tell it you’re a movie expert. Now, I’ve seen documentation that says you’re always supposed to say you are a helpful assistant. But I’ve also seen that if you want something very specific, it’s fine to be more direct. This isn’t just idle chat.
So be more specific in the role you assign, as we are here. We’re going to specify details. In the user content, specify details while clarifying that we do not need the JSON in data format—
Wait—yes, exactly. Right. Now I recall.
I didn’t want JSON. We don’t want JSON the first time. We’re just going to accept—no.
I think we kind of do want JSON, though, right? We want all these. Yeah, of course we do. Sure.
So here’s what we’re going to do. First, we’re going to say: just give us a blob of text, and we’re going to output that blob of text right to the browser—not even a webpage, not even a `
` tag or anything. Just blob of text. If you get a blob of text, just dump it in the browser. Why not?
Then we’re going to say: okay, now we want JSON back, so we can parse it and extract individual pieces of data—year, title, stars (as a list), quotable quotes (as a list), director (string), year (number), academy awards perhaps—but let’s not go too crazy.
Then we’ll publish a template. We’ll render a template. And in the rendered template, we’ll have multiple tags set up to catch these various pieces of data. And I don’t know—I got a little overly ambitious, perhaps. I was like, “Yeah, let’s have it give us 10 movies and we’ll run a loop and output all the movies.”
I don’t know about that. Not in a lab, anyway—no way. What we’re going to do is just one movie.
Yeah, absolutely not in a lab with a loop. Okay, so here we go. Let’s just take this text:
You are a film critic, expert, cinephile. All right. We’re going to take server02 lab—server03 rather—and go from server03 to server03-lab.
File → Save As → server03-lab. You are a helpful assistant?
No, you are a film historian and critic, classic movie buff, and overall cinema expert. So I have the words “film, ” “movie, ” and “cinema” all in here. Critic, buff, and expert.
Now we want our prompt: Please give an example of a great Hollywood movie from the 1990s. Okay.
Great. There you go. Take out these extra spaces.
Let’s clean up this string a bit: “Please provide an example of a great Hollywood movie from the 1990s. Please describe the movie and include important facts such as the title, year, stars, director, genre, and a few quotable or memorable quotes.”
The answer can just be a string; no JSON required. We’re going to do this twice. First, let’s just get text, right? We’re not asking for JSON right now, so let’s turn that off.
A reminder of what the difference is between text and JSON. We’re going to call this the AI answer, and we’re still going to render the AI answer.
A blob of text. But actually, we’re just returning the AI answer now because we just want a blob of text in the browser. Return AI answer.
You can also just return this directly, right? You can just say it like that—although why not have the variable? We’re going to want it later. And once we get it to show up as raw text, we’ll take it up a notch. This is the kind of thing you really do want JSON for, right? Because of all the different little pieces of data.
No webpage—just return it. That means when you hit the route, the text will just dump in the browser at the homepage.
[…Continued in Part 2 due to length…] Corrected Output (continued from Part 1):
Okay, so here you go. And we don’t need JSON yet. We can turn that off.
Just make sure you have all that. We don’t need a rendered template right now because we’re not rendering a template—we’re just dumping text into the browser.
No JSON. No JSON. The answer can just be a string.
No JSON required. Answer should just be a string. No JSON, please.
No JSON, please—yeah. The AI answer is that. And then we return or render the AI answer.
Control+C. Run 03Lab. Boom. Refresh.
Sending the request. There it is. Oh, Shawshank Redemption*, okay.
One exemplary movie from the ’90s: Shawshank Redemption*. Okay, so if we did have this as JSON—which we do not—it’s just a blob of text. That would be your title.
That would be your year, director, star, star, description. Ah, memorable quotes. “Hope is a good thing.”
“Maybe the best of things. And no good thing ever dies.” “Get busy living or get busy dying.”
Okay. Nice. Nice.
Nice, nice. Okay. So that’s all well and good.
But that’s just the opening salvo. Now we want to go back and say: okay, we want a more structured response than that. We want JSON.
We’re going to import JSON. Then we’re going to say that we want JSON. We’ll say: response format.
I know we just had it—I took it out. We should get some practice here.
Type: JSON object. That’s also a string. Comma.
Please provide… okay.
Answers should be in JSON with the following keys: title. It’ll figure out which is which.
So year, director, stars. Let’s see what it does with stars. It may give us stars as a list.
It might just give us a string with two names in it. Stars, quotes—famous quotes. Quotes.
I’ll just say “quotes.” The stars and quotes values should both be lists of at least two or three items each.
Sure. Lists of multiple items. Stars.
Description. Stars. I should put stars.
Description. Quotes. Description. Genre.
I mean, we could ask for the running time and stuff, but it’s not IMDb-level. Okay. So that’s what we’re doing.
This is prompt engineering. “Please provide an example of a great Hollywood movie from the 1990s. Describe the movie and include important facts such as the title, year, stars, and director.”
Next we’ll try to get the data back as JSON. I’ll get the AI answer as JSON and publish that. I’ll put that from index03-lab.
Add this content to the body of index03-lab. Okay. In the `
` tag, add a Jinja variable: title.
The movie data we get back from the AI will supply the value of this variable as a JSON key-value pair: movie, right? As the value of the JSON key “movie.” Okay. Back in server03-lab, say the AI’s response—
We’re going to call it ai_json to ai_json variable. Add a response format to the create method. Yep.
Absolutely—specifying what we want. What do we want? In server03-lab, add the response, right? Specify that the chat response needs to be JSON.
Parse the movie’s JSON response. Save and parse the movie’s JSON response, which we’ve done a couple of times. Three times now.
Ai_json → ai_dict. All right. We’ve already got our HTML.
Have the chat function return the HTML page and the ai_dict. We’re going to pass the whole dictionary over to Jinja. So over in the Jinja template, we’re going to have the entire dictionary.
We can’t just say “movie.” We have to say ai_dict[“movie”], which is fine, right? Because that’s the whole dictionary of six or seven properties, right? What did we say? Update the prompt to specify JSON and all its keys. All that stuff—but we don’t want it like that.
And export it as plain text. That’ll purge all that formatting. There.
Return the entire ai_dict. Okay. Pass the JSON.
We already did that. We want to output the movie data HTML page, so make HTML elements for each piece of movie data. The movie data will be coming into the HTML page not as JSON but as the AI dictionary.
We want to output the values of the various keys inside the boom, boom, boom of the Jinja template. So make one HTML tag per key or per piece of data, and give each tag a variable to render.
So: Great Hollywood Movie of the 1990s. Title. We have to change that.
It’s not just going to be “movie.” Actually, we don’t need that yet. Great Hollywood Movie.
Great Hollywood Movie of the 1990s. Title.
- Dictionary: title.
That’ll be an `
`. We don’t need “title”—we just put that.
We don’t need that. Okay. Genre we could put.
Genre. Year. Genre could also be a list, right? We don’t need double-doubles.
Year. Scrub and paste. Minutes.
Oh—we didn’t ask that. We didn’t ask that. Director.
Director. Stars. Stars.
That’s going to maybe just be a list. So why don’t we say star[0] at least. And I think we can output more than one inside here.
Star[1]. Two stars. I don’t want to put more and get an error because it doesn’t exist.
And to be safe—I don’t know if you can put more than one variable in there. I’m just going to do that.
Quotes. Quotes. We’ll do two quotes.
We’re going to get the quote at index 0 of the quotes array, and the quote at index 1. And we’ll do a ` ` tag for the quotes—even after the word “Quotes.”
They need room. Et cetera, et cetera. More tags.
Well, more specifically, we need: description.
Yep. So all that. Basically our HTML.
Yeah. We need an HTML lab three. Index 3.
File → Save As → index3-lab.
Break on these `
` tags. Yeah. Okay.
And this a little bit smaller. Okay. There we go.
It’s a lot of stuff. This is—you know—why it kind of helps to understand a little bit of HTML, like to know what these tags are doing. These are `
` tags.
These are all paragraph tags. ` ` is a line break. And `` is for bold.
You can say ``, but you can also say ``—it does work. And it’s not really considered deprecated. And here are your big headers.
The title, right? We don’t need to say “Title.” We get it.
It’s a title. We’re not doing a loop. Let’s not go crazy.
Not looping multiple movies. We didn’t ask for multiple movies. Okay.
So that should be it. We’re going to quit the server—if one is running.
And server03-lab. Boom. Okay.
Let’s make sure server03-lab. Okay. It’s not rendering.
We are going to render template lab03-lab, right? That’s what we want to render. We’re passing in the entire dictionary.
And it’s squiggling on us because we have to import `render_template`. We have to tell it we want JSON—that we did. And now we have to turn this stuff on.
Parse. That’s fine. We’re not taking just one property.
And `ai_dict`—the entire dictionary response—as the two arguments. Okay. We’ve edited.
Notice it’s updating as we edit. It’s not throwing any errors. Okay.
We need `ai_json` here. That’s `ai_json`, which we’re parsing into `ai_dict`.
Which we’re passing to the `render_template`. Response. Okay.
So just to show you all—we’re importing Flask’s `render_template`, OpenAI, and JSON.
Instantiating our app. There’s our key. Instantiating our client object.
Defining our one and only route. We’re trying to send this big request—this prompt—to the AI.
We’re asking for JSON back. We’re specifying it as a response format. And also, we’re saying so in our prompt.
This `role: user` content—that’s your prompt.
This is prompt engineering—writing the prompt. Just so. Parse.
We’re unpacking the JSON answer from the AI. Parse the JSON string into a dictionary. There.
Render `index3-lab`, which is all set up to deal with that dictionary—to handle and render the various properties of the dictionary.
Let’s see here. Browser. Go.
Unexpected character. Okay. All right.
- It would be nice to know where that character is. Well, that’s what happens when you copy and paste.
It messes up the quotes. It doesn’t like one of the quotes. That’s a dot.
No, that’s supposed to be a dot. My thing. Content role: user.
- It doesn’t like one of the characters. It’s got an issue with the characters.
Please provide… I don’t see anything. It would be awesome if it didn’t say 1303, right? Maybe it doesn’t like these little characters.
These little single… let me see. No, this should be fine.
That should be fine. What does it say? Which one doesn’t it like? What is that thing? Oh—it’s seeing a curly. It’s seeing a curly quote.
That’s weird. Where’s the curly quote? I don’t see a curly quote. We definitely don’t want curly quotes, but I’m not seeing one.
Okay. Can we find a curly quote? Curly quotes—the bane of our existence.
Okay. Here’s a curly quote. This one’s backwards, though.
Give me a forward curly quote. Okay. I’ll just type here.
Nope. Okay. Great.
Now it won’t give me one at all. There’s—there. There.
Okay. All right. Do we have a curly quote? No.
Huh. I’m not seeing it. Maybe I got it.
Nope. Unexpected character. Is it throwing an error in here? These 200 messages are good.
It means it hit the route. 404. Okay.
That means it didn’t. Huh. Wild.
Okay. This might take a while. Well, you know—you could cut, editor.
Video Editor. Cut all this. But I have to find this offending curly quote.
It should be somewhere in here. I think these are curly quotes. It would be something I pasted.
I would imagine. Like in here. Or here.
Curly quotes usually come over when you paste. Darn. Okay.
Oh boy. Oh boy.