Claude Code Built My Entire AI Image Generation App β
Claude Code TutorialsFreshπ
2025-12-01
Tutorial Overview β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β LEARNING PATH β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β LEARN β
β βββββ β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β Watch βββββΊβ Understand βββββΊβ Follow β β
β β Tutorial β β Concepts β β Along β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β β
β βΌ β
β PRACTICE β
β ββββββββ β
β βββββββββββββββ βββββββββββββββ β
β β Try It βββββΊβ Experiment β β
β β Yourself β β & Adapt β β
β βββββββββββββββ βββββββββββββββ β
β β β
β βΌ β
β MASTER β
β ββββββ β
β βββββββββββββββ βββββββββββββββ β
β β Build βββββΊβ Share & β β
β β Your Own β β Iterate β β
β βββββββββββββββ βββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββKey Takeaways β
- Core concepts explained
- Step-by-step implementation
- Practical examples
Transcript β
[00:00] It's been an insane few weeks in the world of AI. We've seen the release of Opus 4.5, which is probably the best coding model out there right now. And they have a few powerful image generation models like Nano Banana Pro, Flux 2 and even Z-Image Turbo. And I've been having a lot of fun with all of the stack. So I thought let's build a fun application together using Opus 4.5 as the coding agent and Nano Banana Pro as the image editing or generation model.
[00:30] Nano Banana Pro is good for a lot of different applications, but one of its strengths is to create images with consistent characters. As an example, we've got this image of this model. Now she's got these tattoos on her right arm, and this will be important as we use the same character in different images. So we could of course upload this image to Nano Banana and say something like "a woman walking her dog". And if we look at the result, we can see it's definitely the same character. In fact, if I put these images side by side,
[01:01] we can see all of the details and characteristics of this character was carried over. Now this technology can be powerful for creating social media personalities or for promoting brands. Now I don't know about you, but one thing I suck at is building up these prompts. I tend to send very simple prompts like the one over here, but did you know you can actually specify a lot more things in the prompts, like the camera or the lanes that was used, or the scene composition, or the backgrounds, or the lighting. So I want to build an app that actually
[01:32] assists me in building up these prompts by giving me or my users a very simple interface. What I also want to do is make it very easy to create these different personas or avatars. So I should be able to upload a reference image like this and maybe give this character a name and a brief description. And it should be really easy to inject this character into my prompts. So in this video, I'll take you through the entire process. And this is not scripted. I actually want to walk you through my
[02:02] process of setting up the project, creating the implementation plan, and working with the agent to build this from start all the way to production. And this won't be a simple app either. We'll actually allow users to sign up and provide their own API keys. And besides for user authentication, we'll also integrate file management. So that means when the images are generated, they will be stored on the file system, and the users will be able to view them in their galleries. And maybe for fun, we
[02:32] could have a public gallery, so users can decide which images they want to share publicly. And people can view the exact prompts they probably use to generate those images. So enough talk, let's build this. All right, so let's talk about the prerequisites. In order to use Nano Banana Pro, you will need an API key. So for that, go to aistudio.google.com. Then go to Get API Key. Then from this screen, click on Create API Key. Give your key a name. I'll just call my Nano Banana Pro tutorial.
[03:03] Then select the project. If you don't yet have one, simply click on Create Project and give it a name. Right, so after creating your key, you will have to set up your billing account. To do that, all you have to do is click on Set up Billing. Now, if this is your first time setting up your billing account on Google Cloud Platform, Google will actually give you free credits. So you should be able to follow along for free. Either way, we should now be able to copy our key. Now, we don't need the key right now, so I'm simply going to leave this page open and we'll get back to it in a few minutes.
[03:34] Right, so with all of that out of the way, let's start building our project. Now, setting up the project can be quite tricky. It usually means installing a lot of different dependencies. But in order to speed things up and save some tokens, we'll simply use a boilerplate template. So in your code editor, let's open up a new terminal session and let's run npx create, a genetic app at lightest. And I'll just add spice and period at the end in order to install this in the current working directory.
[04:05] Then let's simply say yes and press Enter. And for the package manager, I'll use pnpm. If you don't have pnpm set up, simply use npm. So all this will do is copy across all the boilerplate code that I've already set up for you. It's completely free to use, by the way, and it is open source. Now, at this point, you might be wondering if you could use something like Lovable or Bolt to build this application. And I guess you could, but honestly, I find this process a lot easier and it gives you way more control.
[04:37] So even if you're not a developer, I highly recommend you try this process. All right, cool. So everything was copied across. Now, for all the devies out there, this is a Next.js 16 project that uses Postgres as its database. We also have a few other libraries installed, like Vercel's Blob Storage for file management. We're using Drizzle ORM with a Tailwind and Shat C and set up and using the AI SDK along with Open Router for any AI related functionality.
[05:07] Now, to start this project and to view what we currently have, we can simply run the following command in the terminal, npm run dev or also to use pnpm. Now, we can view our app on localized port 3000. So at this stage, we have this border plate project. And if we scroll down to this checklist, we can see exactly what we need to set up. So we need to add a few environment variables to hook up our database and our auth system. We'll be using Google Auth as our provider. Now, for this specific video, we actually won't be using
[05:39] the AI SDK with Open Router. We will be calling Google's endpoint directly. Either way, let's start with our database. We will be using Docker Desktop to spin up our database. So if you don't have Docker installed yet, simply go to docker.com and download Docker Desktop. Right, so on Docker Desktop, you won't see any containers at the moment. Now, back in our app, I'm simply going to start a new terminal session. I'm actually going to rename this one to database. Now, to start up our database, all we
[06:10] have to do is run docker compose up-d. So this will create our database and start it. And we can confirm that by going back to Docker Desktop. And now we can see this nano-banana-pro folder with our Postgres database, which is currently running. Now, in order to set up our database, all we really have to do is run these two commands. So I'll copy the first one and run it in the terminal. Then let's copy the second command and let's run that in the terminal as well. And we can actually view
[06:40] the contents of the database by running npm run DB studio. That will give us this URL. And if we have a look at our tables, we can see all of our auth tables. And by the way, we can see the actual database schema by going to source, lib, and this schema file. And in here, we can view all the table definitions. Right, so now that our database is correctly set up, we can move on to the next step. In fact, if we click on recheck, the database connection and schema is now successful.
[07:11] So you'll notice in the template that we actually have this sign in button. And if we click it, it doesn't do anything. That's because we started to set up our Google client ID and client secret. So to get our client ID and secret, let's go to cloud.google.com. Let's go to console. And in this project dropdown, you can view all the projects that you already created. And since we created a project earlier, when creating the API key, you should see the project every year. I just decided to create this API key under this innate end tutorial project.
[07:42] But this is not an innate end tutorial at all. I just already set up my billing details on this project. And you will also notice that I still have $288 left of free credits. And I didn't pay for this. Google assigned this after I created my account. Right, then from this left menu, let's click on APIs and services. Now, the first thing you need to do is to set up your consent screen. So to go to your OAuth consent screen, and you will see a button with the text get started. So simply go through that process.
[08:13] It's really simple. After you completed the consent screen, go to audience. And there should be a button called publish app. Simply click on that. Then go to clients, click on create client. For the application type, select web app. And let's give it a name. I'll call my nano banana pro prompt generator. And under authorized redirect URIs, click on add URI. And now we have to provide a very specific URL. Now you can find this in the project by going to our .env file.
[08:45] And just before these Google variables, you will find the redirect URI. So let's copy this. Let's paste it into this field. And let's click on create. This will give us our client ID and secret. So let's copy the ID. Let's add it to our environment variable file. And let's do the same for the secret. And if you go back to our app and refresh, we can now see that everything is green except the AI integration, which is fine because we won't be using open router in this video. What we can test in the meantime though
[09:16] is whether or not we can sign in. And that's it. Our authentication system is working. We can click on our profile. I can view my email address and everything is correct. Cool. Right now that we have a border by project, we finally ready to build our application. So in Cloud Code, I'm going to switch over to planning mode. And this is where we really want to discuss and plan this project with the agent. So I'll simply use voice to text for this. Hey there, I need your assistance with planning this application.
[09:48] This is just an idea that I have. The new Nano Banana Pro image generation model was recently released. Now this is a really powerful model for generating and editing images using AI. One of the strengths of this model is to create images with consistent characters. So you can upload a reference image and then get the model to make changes to the image or generate brand new images using that character or details from that image, like their likeness or their
[10:20] clothing or the setting, etc. Now one of the challenges of working with Nano Banana is with coming up with unique and detailed prompts. Simply sending a one-liner is not good enough. A good prompt should include all sorts of things like the location, the setting, the background, the lighting, the camera that was used, the character's poses, so details around the subject, like their clothing or hair or their pose or their facial expression, etc.
[10:52] So what I want us to do is build an application that assists the user in building out complex prompts. The UI should be simple to use and intuitive. Now for image to image generations, what I would like is for the user to be able to create avatars. This means they don't have to re-upload the same image for a character all the time. They should have an option to create new avatars, upload the image once, and maybe add a description of that character.
[11:23] So when the user selects image to image generation, they should select from their list of avatars. So the way I kind of imagine the UI is that the UI will be split into three columns. On the left-hand side, you will have all the attributes related to the prompt, like the setting and the lighting, the cameras, and even the subjects. So users should be able to add a subject and for that subject, select the avatar and for that avatar, customize things like their poses,
[11:55] their actions, their clothing, hair, makeup, all of that stuff. And for the attributes, they should be predefined templates that people can select from. So of course, for each attribute, they should have the ability to enter free text, but they should also be able to just select from a dropdown that will bring up a modal with predefined templates. In the middle section, this is where users would click the Generate button, but in this section, they should also be able to view a preview of that prompt.
[12:26] So as they're changing attributes on the left-hand side, they should be able to see the preview in this middle pane. And there should also be a little setting toggle. And when I click on that, a modal should be opened where they can set any other attributes that are allowed by this Nano, Banana Pro API. Things like their resolution, the aspect ratio, and on the right-hand side, on the right-hand pane, this is where they can view the images that are being generated. This should show suitable loading
[12:57] spinners or skeleton loaders, and then show the results as they're being generated. And yes, users should be able to generate more than one image at a time. So maybe you can give them the option to select between one, two, three, or four images. Users should be able to sign into their account where they will be able to generate these images. Images should be persisted in file storage for that user. This means users should have access to a
[13:28] gallery where they can view the generations. But as a fun feature, I want users to be able to select an image that they want to make public. So they can change the status of these images. By default, the status would be private. But if they want to share the image with the world, they can set the status to public. So in other words, users will have local galleries for only their images, but there should also be a public-facing gallery on the main page of the website
[13:58] that showcases everyone's work. Each image should also include the original prompt that was used to generate that image. This is really how I work with these models. I try to really just throw everything out there in the planning phase and see what the model comes up with. I am going to enable thinking mode and let's send this. And by the way, you can see that I am using Opus 4.5 for this generation. Oh, you know what? I'm actually just going to interrupt this generation.
[14:28] And sorry for this interruption. I really want to go through this unscripted so you can see my actual workflow. I'll leave a link to this article in the description. This gives us a bunch of tips and tricks for getting the best out of Nano Banana Pro. And this could definitely guide our agent to come up with this UI. So it establishes things like the subject and the composition and the actions, the location, and details around the camera and lighting, etc. So this is perfect for our application. So I'm actually going to copy all of this and I'm going to create a
[14:59] new subfolder on the docs, technical, I'll create a new folder called Nano Banana. And in there, I'll just create a new file called tips.md. And it's based in everything that we just copied. And then I'll actually link to another article. And this official article shows us how we can use Nano Banana Pro. So simply look for this new with Gemini 3 Pro image section. And then let's copy all of this, including the coded example.
[15:29] Then I'm just going to create a new file under Nano Banana. I'll just call it SDK example.md. It's based all of this in and that's cool. So we now have prompting tips as well as a coding example. So what we can do is pull this entire folder into the chat. And it's a, I've attached the folder containing documentation. This contains tips for prompting this model, which should guide the design of our app and the types of attributes that we should be able to dynamically set.
[16:01] Then we've also got a coding example, which shows you how you can use the Google SDK for generating images and editing images with this model. So when planning these applications, it can be really helpful to provide any additional context that you want. Now, if you're simply vibe coding, you could ask the agent to use an MCP server like context seven to retrieve this documentation for you, especially a documentation around using the Google SDK. But I personally like to have a handle on
[16:32] what I'm adding to these applications. So I always encourage people to actually read the docs. As a cloud code, when I ask us a few questions, like how would you like the predefined templates organized? So let's have a look at these options, name and description. So each template shows a name and a helpful description explaining the effect, name and the preview image, or the name only. Or simply go with name and description. I think with preview images, it could be quite challenging because we'll have to actually upload the preview images for each of those options.
[17:04] Should users be able to save and reuse their favorite prompt configurations as presets? Now that's an excellent suggestion. I'll go with option one. For the public gallery, should images show the creator's profile, like the name or avatar alongside the image and prompt? Let's go with option one. Should the app support generating images in a conversational or iterative way, where users can refine previous generations with follow-up instructions? Let's go with option one. And let's submit this.
[17:35] Now, while this is generating the implementation plan, I actually thought of another requirement for our app. Now, I don't want to go bankrupt, and I'm not going to try and sell this as a service. So I think the best solution is for people to bring their own API keys to our application. And we need to securely store that API key somewhere. So let's do this. All right. So I forgot to mention, users will actually bring their own Google API keys. So we should not be using a single key or an environment variable. We need to sum our stored key securely
[18:07] against the user's profile. Think carefully about how we can implement this securely. Should users be able to test their API keys? No, I don't think that's necessary. We'll just save it. And where should users manage their keys? We'll just add it to the profile or settings page. And let's submit these. All right. So we've got our plan, but there is one thing I like to add to this as well. You just say, hey, so we are currently dealing with a boilerplate project. So go ahead and remove any components or pages or functions or logic
[18:39] in this boilerplate project that's not related to our main project. Usually, the agent will be clever enough to understand that this is a boilerplate, and it's allowed to make changes. But just in case, I'll just add it to the implementation plan. And by the way, I do like that it's actually going to encrypt the API keys as well. So it's going to use an encryption key to encrypt and decrypt these API keys. That's really cool. Our plan was updated. And now we've got this phase zero, which will first remove all the boilerplate stuff before building the rest of the app.
[19:11] All right. I'm happy with this. But instead of just telling the agent to go ahead and implement all of these changes, I do want to free up the context window. If we go to slash context, we can see that we're already using 70% of the context window. So there's absolutely no way we can implement this entire application within the same conversation. And of course, if we clear the conversation, we're going to use all of this context. So what we can do instead is ask the agent to take everything
[19:41] that we've just planned and discussed and then store all of this as an implementation plan in the project directory. So I'm just going to switch over to change mode. And thinking must be on. And then we can run a custom command called create dash feature. So let's run the command create dash feature. So this is a command that you get with my boilerplate template. And all this really does is it tells the model to create a new sub folder within a specs folder for this specific change.
[20:13] And it should create two files, a requirements file and an implementation plan. So we should see all of this pop up in a second within this specs folder. In fact, we can already see the nano banana image generator folder. And I was just waiting for our requirements doc and the implementation plan. Oh, and I should also mention that if you want to use BMAT or spec kit at this point, that's perfectly fine as well. Honestly, I prefer this method as it's really clean. It uses very few tokens.
[20:43] And it's super simple to implement. And cool. So we now have our implementation plan, which is split up into phases with actionable tasks per phase. So this makes it really easy. We can now clear the conversation, freeing up all that context. And now we can simply drag in this folder, put it into the chat. And it's a, please implement phase zero to phase three of the implementation plan. This also marked the tasks as complete once you're done with the changes.
[21:14] And it's in this. Now there are a few reasons why we'd want to implement this one phase at a time. Of course, it keeps the context window for the agent clean. But another benefit is we can also review the code changes. If we're simply making a massive amount of changes, it's so hard to keep track of what the agent actually changed. So in order to be able to do code reviews without feeling overwhelmed, it definitely makes sense to implement one phase at a time and review the changes before moving on. So I'm not sure if this ever happened to you, but sometimes when you run a cloud
[21:46] code in the terminal within the code editor, it will sometimes just stop without any reason. And then you kind of have to close cloud code and then resume the conversation. Or sometimes it just closes the IDE completely. I'm not sure why that happens. And hopefully, anthropic will implement a fix for that. And one solution I found that works for me is to open up a PowerShell window outside of the IDE. So if you run into those same types of issues, then try that. I also felt that the cloud code extension is way more stable.
[22:18] So you can simply install the cloud code extension. It looks something like this. You can also go into planning mode and get it to ask for permission before making changes or in it automatically. And you can enable thinking mode and access a few of the commands. I personally find that the terminal just gives a few more options. So I'll just stick with that. Right, cool. So cloud code just finished phases one and two and three. And if you open the implementation plan, we can see that all of these tasks have been flagged as complete.
[22:49] So that's phase one, two, and three. Now in order to continue to phase four, really, all we have to do is clear the chat. This will clear up the context window. And then we can pull in the folder just like we did previously and ask the agent to continue. So you could simply drag and drop it in. Or of course, another way is to simply tag it so you can enter the add sign. Then let's search for the nano image generator.
[23:19] This first result. Then it say, please implement phases four to six and mark the tasks as complete after you've completed your changes. And let's send this. And that's really my workflow. Get the agent to implement a few phases or maybe just one phase at a time. Then clear the conversation and ask the agent to continue to the next phase. So I'll get both code to complete the rest of these changes. And I'll see you when everything is done. All right. This is looking awesome.
[23:50] We've just implemented all of these phases. So if I go to the implementation plan, phase 12 was the final phase and everything has been marked as complete. Now, if we go down to the bottom of the implementation plan, we can see under the environment variables, we now need to add one new environment variable. And that's this encryption key. So I'm just going to copy this variable name. And in our .env file, it's placed in that name. And now we just need a value. So what I'm actually going to do is clear
[24:21] our conversation with Claude. And it's a please generate a value for this encryption secret variable. And cool. Now I'm just going to copy this entire thing and add all of this to the .env file. Awesome. So this will encrypt the API keys. I do take note that when I deploy this to production, I will be using a separate encryption key. So if you do want to try out the app, it's completely secure. All right. So now that we've implemented all of these phases, there's one more thing I like to do.
[24:53] I'm actually just going to pull in this folder again. And let's say, all right. So we've just implemented all of the phases in this implementation plan. Please do a thorough code review and resolve any issues that you run into. Ensure that the solution was correctly and completely implemented and that the code and solution is optimal. Right. So the code review is done. And it's saying that all 12 phases have been properly implemented. All right. So it looks like no issues were found. And this application is production ready.
[25:25] So let's start the dev server and test this for ourselves. All right. So we've got this home page. And here we can also see this public gallery, which seems to contain dummy data at this stage. Then we can also view our profile. I'm just going to sign out. Let's try to sign back. And that seems to take us to this dashboard page, which actually doesn't exist. I would imagine that after signing in, we should be redirected to this generate page. Right. So let's get Claude to fix this. I'm going to pull in all of this context again. Let's say, all right.
[25:56] So I'm just testing the app for the first time after implementing this new feature. I noticed that after signing in, I'm redirected to a dashboard page, which doesn't exist. I would expect the user to be redirected to the generate page. Please have a look at the application and ensure that all the links are working correctly. All right. So apparently that's fixed. And this time we are redirected to the generate page. Awesome. So let's see what we have here. We have our gallery page, which says we don't have any images
[26:26] yet, which is correct. We haven't created any avatars yet, which is correct. And we have settings. I also noticed that on the generate page, we have this button to add our API key. So let's actually do that. So on this page, let's go to our Google API keys. Then I'm going to copy my API key. Let's paste it into this field and let's save this. So saving the key actually failed. And if we have a look at our dev server, we can see this error message.
[26:57] So I'm actually going to copy all of this and back in Claude, let's say, hey there, I tried to save my API key, but got the following error message. Then for additional context, I'm just going to copy this key. This is what the key looks like in the .env file. And let's paste this in and let's send this. And so after that fix, I'm just going to try again. So let's copy the key and let's paste it in. Let's save it. And apparently the
[27:27] key was saved this time. Now I do want to see what's actually stored in the database. So let's start up Drizzle Studio. Let's go to user API keys and we have this encrypted key field. And yes, I can confirm that this key is actually different to the one that I got from AI Studio. So it's definitely been encrypted. All right, so now that we've stored our key, let's see if we're able to actually generate images. So this is exactly what I wanted. On the left-hand side, we have the prompt builder, where we can select styles
[27:58] and locations and add subjects. And in the middle, we can see the preview of the prompt, along with all of these settings. And on the right-hand side, we can see the generated images. So let's go to avatars. Let's create a new avatar and I'll upload an image. All right, so I've got this character. Let's just call this character Luna and it's described as character. Okay, be simple. It's a female model, 30 years old, long brown hair and arm tattoos. So we've got a type, which is human and
[28:30] let's create this avatar. Cool. Now let's go back to generate. Again, for the style, let's select photo realistic and let's select our location as cafe. Let's select our lighting as cinematic. And for the camera, let's select close up. Then under add subjects, let's select our avatar. Cool. Let's select the pose. So these are very boring. So these are quite boring. We can definitely extend them, but let's just select leaning. And under action, let's select laughing
[29:02] and it's actually leave clothing. So hopefully it will use the clothing in the reference image. Under expression, let's select and we'll just leave everything else. And we also have additional instructions. While in the middle pane, we can see the prompt that was generated. Let's just try to generate one image and for the resolution, let's go with 1K. And for the aspect ratio, let's go with portrait and here goes nothing. Let's generate this image and I don't know something went wrong. So again, what we can do is go to our dev
[29:34] server and see if there are any errors. So I'll just copy all of these errors. Let's go back to Claude. I'm going to clear the conversation and let's say, right, so I just tried to generate my first image, but I got this error message. Please can you resolve it? And let's paste this in and let's send this. All right. So I had a bit of a back and forth with Claude to resolve this issue. I noticed during the conversation that it actually didn't know what model name to use.
[30:04] So it clearly deviated from this SDK example that we provided during planning. So really all I did is I added this example code into the conversation and Claude had a look at it and said, oh, I actually implemented the wrong structure and I'm using the wrong model name. Either way, apparently this is fixed. So let's try to run this again. For the resolution, we'll do 1K with an aspect ratio of portrait. Well, here goes nothing. Let's try to generate this image. And there we go. We have our image.
[30:35] How awesome is that? I noticed that we actually can't view it in full screen mode, which I do want to fix. And also when we click on our avatar, it simply injects the word "Luna" or the name of the avatar instead of the description. So let's fix this. All right. So it seems like we are able to generate our images now, but I do want to make a few enhancements. When I click on the avatar or when I select an avatar, it simply injects the name of the avatar into the prompt
[31:05] instead of the actual description of the avatar, which would be more useful. Also, after the image was generated, there's no way to actually view the image in full screen mode. Awesome. Let's end this. While this is cooking, I want to ask you a favor. Let me know down in the comments if you actually enjoy these long form videos where we build full stack applications using a genetic tools like Claude Code. Also, I would appreciate it if you could hit the like button and subscribe to my channel. It really helps me out.
[31:35] There also seems to be no way to actually store these presets. And there's another thing that I noticed. There doesn't seem to be any way to save these presets. Please can you ensure that we are able to store presets. All right. So hopefully we can now save presets. So I'll just go through the process of selecting all of these values again. So let's just do this, this. All right. So we now have to save presets button. Let's do that. It's a woman at cafe. Let's save this.
[32:07] Oh, and what you would also notice is that we now see the actual full description of the avatar and not just the name. All right. So if I refresh this page, hopefully we can click on a preset and that's actually it. So it's automatically populated all of these fields and selected the avatar. All right. So presets are working. And if we go to gallery, we can see the generations that we created so far and they are set to private. And of course we can click on any image and we can view the full prompt
[32:37] with all the settings that were used. This is excellent. Now let's see what happens if we change this from private to public. Let's go back to the homepage. And now we can see this public gallery. It shows the prompt along with the user that created this image. And if I click on the image, it brings up this pop-up. I actually want the image in this model to be the main focus and the prompt and all the settings just below it so that the image is large. So let's actually do that. Hey there. So when I click on an image in the
[33:07] gallery or the public gallery, it brings up a model with the image to the side. And then we have the prompt and all the settings on the right-hand side. This means that the images are really small. Instead, make it so the image is as large as possible. And inside the prompt and the settings are smaller text underneath it. Right. This is starting to look way better. So if we click on any of these images, we get the image in a larger size along with the prompt and the user that created it at the bottom.
[33:38] All right. So for the public image section, let's create a separate page where people can search for and view all the public images. Also, when I click on a user's profile, they should view all the publicly available images for that specific user. And maybe we can make it fun by also showing the top contributors. And maybe people can also like images. And therefore, we also want to show a section that shows the most liked images.
[34:10] So while this is running, I'm actually going to open up another terminal session and with Claude code. And what I'm going to do is this. Let's extend the prompt builder. I do like all the options that's there, but I think it's very limited. Instead of having dropdowns next to each of these properties, rather open up a model with individual cards. This model should also contain a search feature at the top and please add way more examples and variety. Right. So these two Claude code sessions cook
[34:42] and we'll have a look at the results in a minute. Right. So let's have a look at this public gallery thing. So I can see my image is click on view all images. And here we can see the public gallery with a search box. We've got most liked. So how do we actually like these? Right. So I can click on this little heart and then that will add a like. That's awesome. If I click on the user name, it indeed takes me to the public gallery for that specific user. And we can also see the top contributors.
[35:12] As it seems this other session completed as well. So let's have a look at that. When we go to generate, we don't have to drop down anymore. Instead, if we click on this, it brings up this model with all these different cards. Or I can just type a custom value. And I just thought I'm unable to scroll through any of these cards. So all we have to do is go back to Claude and say, all right. So I just tested this when the model shows up, I'm unable to scroll down to view all of the cards in the model. It's kind of clipping through the bottom of the page.
[35:43] Right. Cool. So this issue is resolved as well. It's actually do something like a 3D animation. And for the location, let's select back alley for the lighting. Let's go with golden hour. Of course, let's select our subject for the post. We'll just do arms crossed. And that's actually it. Let's go ahead and generate this. So I hope you can see the potential in this. Of course, you can add as many different settings as you want with different presets, whatever. And there's our result. And this actually does look like our
[36:14] character along with the tattoos and now in a 3D render form. This is just amazing. All right. So we did a massive amount of work here. We've had over 109 file changes. So at this point, I'm going to create a checkpoint. This will simply grab all of the changes we made and create a commit along with a suitable comment on that commit. So it's basically going to grab all of these files and create a new checkpoint for us. And checkpoints or commits will simply
[36:45] allow us to roll back to this state. If we ever end up breaking the app. Perfect. All these files are now gone. We can see our commit down here with a detailed comment. Now, another thing I'd like to do at this stage is to update our clod.md file. This file still contains all of the stuff from the border plate project. So I'm actually going to clear this file. And in clod code, we can now run the slash init command. So the agent will now analyze our code base and create a proper clod.md file.
[37:17] Right. So now our clod file is up to date as well. So what I'm going to do is go to source control and let's just say update clod.md file. Cool. All right. So I think I'm happy with this project. It's perfect for an MVP. And I think we're ready to deploy this to production. So from get up, I'm just going to create a new repository. And let's give it a name. Let's do something like nano banana pro prompt generator. And then for the visibility, I'll just make mine public. So if you guys want you more than welcome
[37:48] to simply clone this or download it for yourself. Let's create this repository. Then let's go to the bottom. And I'm going to copy all of these commands. I'll open a new terminal. And I'll just run each of those commands one at a time. So this should now push up all of our changes to the GitHub repository. So if I refresh this now, and here we can see all of our source code, we can still see the readme file from that border plate project. So if you want, you can just ask both go to update the readme file as well.
[38:20] Please can you also update the readme file to reflect the actual application and not the border plate stuff. Okay, let's run this. Either way, this is good enough. So let's now move this to an actual production instance. The easiest way to deploy these applications is without a doubt, Versal. So simply go to Versal.com and create an account. Then let's create a new project. Then from the list of repositories, let's import the one that we just created. Then under environment variables, we need to copy across all the
[38:51] environment variables that we used in our project. Really, the easiest way is to simply open up the .env file. So we can just copy all of this and paste it into this field. This will automatically pull in all the environment variables. Now I'm simply going to remove the ones that we don't need, like those polar variables. And by the way, if you want to learn how to use polar to add payment processing to your app, then I'll link to a video in the description where I show you exactly how. Now we do have to make a few changes.
[39:22] We need to create a Postgres database for production. Luckily, that's very easy with Versal as well. So in Versal, simply go through storage. Then click on create database. Let's create a neon database. Let's click on continue. Then we can select our region. Let's click on continue. Then for the name, let's call it Nano Banana Pro Prompt Gen. All right, then let's create this database. Okay, let's click on done. Then from this screen, click on show secret.
[39:54] And what we want is a Postgres URL. So I just copy this entire line. Back in our environment variables, let's paste in that value. Now for the better auth secret, I'm simply going to set a new value. Now for the Google client ID and client secret, I do recommend setting different values than what you had in dev. I'm going to do this off camera, but really all you have to do is create a new auth in Google Cloud Platform, exactly how you did it for dev, and then copy the client ID and client secret.
[40:25] You could just call that credential production. All right, so we don't need open router. I'm going to remove all these open router variables. We don't need embedding models or remove that. And now for the URL, it's still pointing to localized and we don't yet have the correct value. So I'll just leave it at localhost, but we will change this in a second. Now this is also really important. In development, we use the local file system to store the generated images. In fact, let me show you. So if we have a look
[40:55] at our public folder, we have this upload subfolder, which contains our avatar images, as well as the generated images. Now this won't work in production. Vercel doesn't allow you to store files like this in the project folder. You have to use external storage, and that is where this blob retry token comes in. Now again, thankfully this is really simple. Back in Vercel, go to storage, click on create database, select blob, which is
[41:26] fast object storage. Let's click on continue. Let's give it a name like nano banana pro prons. Let's create this. Then let's click on the storage. Let's go to dot env dot local. Then let's copy this value and let's paste it into this field. And finally, let's click on deploy. All right, so now just the bolt actually failed, and that is because of the database migration. For the postcards URL, I accidentally included a variable name in this value.
[41:56] So let's just remove it and let's try to redeploy. And that's it. The project was now deployed. So let's go back to the dashboard. And this one will give us this public facing URL. So anyone with this link will be able to use our app. So if you guys are curious to play with this app, then just simply go to this URL. I'll link to it in the description of this video. Now we're not done yet. Back in Google Cloud Platform, what we have to do is add this URL to the authorized redirect URIs.
[42:27] So let's simply add a new URI. Let's paste in the link to our app. We also have to copy across API, auth callback, and Google. And of course, let's save this. Then back in Versal, let's go to settings. Let's go to environment variables. And now let's update a few things here as well. Let's go to next public app URL. Let's click on edit. And now let's change this from localhost to our actual production URL. And let's save this. After making changes to environment variables,
[42:57] you do need to restart your server. So another way to do that, if you miss that prompt, is to simply go to deployments, then look for your last deployment, click on these three dots, and click on redeploy. And click on redeploy again. Well, all right. Let's give this a spin in production this time. Let's try to sign in. All right. Seems good. I was able to authenticate myself. Let's try to save an API key. So I'll simply copy the key from AI Studio. Let's add it to our app.
[43:29] And let's save this. And apparently, the key was saved. All right. Then let's try to create an avatar. So let's click on create avatar. Let's upload this image. And again, I'll just call this avatar Luna. For the description, let's just say female model, 30 years old, long dark hair, armed tattoos. Let's click on create. All right. Cool. So we've got our avatar. Now let's see if we can actually generate any images. So let's try something. We'll go with hyper-realistic.
[43:59] For the location, let's do a rooftop. For the lighting, we can go with golden hour. For the camera, let's go with medium close up. Then we'll add our subject. Let's select our avatar. Then for the pose, let's just go with-- let's go with something insane, like jumping. And for the action, we'll do something like laughing. Let's go ahead and maybe change the resolution. Let's generate this image. And that actually worked. So we've got our image. And that's definitely our model.
[44:31] With the tattoos, the outfit, everything. Now the sky really is the limit here. We can add as many different presets as we want. And another powerful ability we could add is to generate these images as background tasks using something like inches. I've already created a video on using InJest to generate images. So if you are interested, then I'll link to that video in the description as well. So I hope you enjoyed this video. If you did, hit the like button and subscribe. And I'll see you in the next one.