How I keep faces the same when editing photos with Nano Banana and GPT Image
The most common complaint about AI photo editing is not quality. It's "that's not me anymore". You ask for a different jacket and get a different person wearing it. I build AI Photo Edit, an AI photo editor where you up
The most common complaint about AI photo editing is not quality. It's "that's not me anymore". You ask for a different jacket and get a different person wearing it.
I build AI Photo Edit, an AI photo editor where you upload a photo and type one sentence, like "dress him in a navy suit". It runs on two image models, Nano Banana 2.1 (Google) and GPT Image 2.5 (OpenAI). Both follow instructions well. Neither knows that for my users the face is the one thing that must not change.
What fixed it was not a model or a face-swap step. It was one paragraph appended to every prompt, plus a check for edits that need more than one photo. Here is how that paragraph is built, the version that broke, and the edits that still don't work.
TL;DR Put a short paragraph of rules after the user's instruction. Protect identity, not appearance, and give every rule a way out for when the user asks for exactly what it protects. Then test it on the edits it might block. A copyable template and an eight-edit test list are below.
Users write the change, the server writes the rules
Users only type what they want changed. They never see the protective wording. The server adds it before the request goes to the model:
// The user's sentence first, our rules after it.
export function editPrompt(userPrompt: string): string {
return `${userPrompt.trim()}\n\n${RULES}`;
}
RULES is a short paragraph. I'm not going to paste our production wording, because it took a lot of test runs to get right, but each of its sentences has one job:
- Apply the change above, and only that change.
- Keep every person recognizable as themselves.
- Leave everything the instruction doesn't mention where it was.
- Say what happens when the user asks for a new art style.
- Keep the original light and color unless the user asks otherwise.
Here is a version you can copy. It is not our production text, and I haven't run it through my test set, so treat it as a starting point:
Edit request: {what the user typed}
Rules for this edit:
- Change only what the edit request asks for. People, objects, framing
and background stay as they are.
- Every person stays recognizable: same face shape, eyes, nose, mouth,
skin tone and age. Their expression changes only if the request asks.
- If the request asks for an art style (painting, cartoon, sketch),
apply it to the whole image and keep each person recognizable in it.
- Keep the original lighting, colors and camera look unless the request
changes them.
- Do not add text, watermarks or extra people.
If you try it, test "make him laugh" and "turn it into a watercolor painting" first. Those are the two edits that broke my first version, as the next section shows. The full test list is near the end. I'd like to know in the comments what you get.
The same function feeds every provider. Nano Banana takes the result as prompt with the photos in image_input, and GPT Image gets the same text with input_urls. Only the body shape changes. The rules are always in English, whatever language the interface is in, so both models get the same instruction.
The user's sentence goes first. The rules come after it and point back to it, so the request stays the main instruction and the rules only limit everything around it.
Version one was too strict
My first paragraph tried to protect everything: the face, the expression, the hair, the pose and the "photographic look". On normal edits it worked. Then I ran my test list, and two edits came back almost unchanged:
- "Make him laugh": the expression rule won, so he kept the same polite smile.
- "Turn the photo into a watercolor painting": the "keep the photographic look" rule won, so it stayed a photo.
The models weren't failing. They were obeying the rules I gave them over the user's request.
The fix was to protect identity, not appearance. Asking for the same recognizable person still allows a laugh, a beard or a painted version of the same man. Asking for the same expression and the same look does not. Then each rule that could block an edit got an explicit way out:
- art style: if the user asks for a new style, the whole image changes style, not just part of it.
- lighting and color: kept, unless the user asks to change them.
Every protective rule needs to know what happens when the user asks for exactly the thing it protects. If it doesn't say, the model guesses, and it usually picks the rule.
What it does on one photo
Every edit below starts from the same original. They are not chained, and they are not retouched. The portrait is a test image I generated, not a customer photo.
| Instruction | Result |
|---|---|
| Dress him in a navy suit with a white shirt and a dark tie | ![]() |
| Put him in a snowy mountain village in winter, wearing a warm puffer jacket | ![]() |
| Give him a full beard and longer, swept-back hair | ![]() |
| Turn the photo into a watercolor painting | ![]() |
The watercolor shows the style rule working. The whole frame changes style, and the cafΓ©, the cup, the people in the background and the man himself all stay where they were.
Tested on both models
Before launch I ran the same instructions through both models with this exact prompt setup, at 2K, keeping the original aspect ratio:
| Instruction | Nano Banana 2.1 | GPT Image 2.5 |
|---|---|---|
| New outfit, new background, add an accessory, remove tourists, overcast to sunset, change text on a sign | Works; nothing else moves | Works |
| Watercolor painting | Works (after the fix above) | Barely changes |
| Make him laugh | Works (after the fix above) | Works |
| Time per edit, upload included | about 30β50 s | about 50β70 s |
A few things I learned from that run and the ones after it:
- GPT Image is weak at full style changes. It edits content well but resists turning a photo into a painting. For a painting, use Nano Banana.
- Some instructions barely change anything on either model. "1970s film look" and "make it daytime" on an indoor restaurant photo came back nearly identical to the original. I took them out of the suggested prompts rather than promising something the models don't do.
- Each model wins on different photos. When I asked both to make AI-looking images more realistic, Nano Banana gave better skin on portraits (pores, fine lines, natural shine), and GPT Image was clearly better on products and interiors (glass, color, walls). So users can switch models per edit.
- Provider timeouts happen. I hit four "generate task timeout" errors in about fifteen Nano Banana runs on one provider. A failed edit is now retried once on a second provider, and if that fails too, the credits go back automatically.
Edits that need a second photo
Some edits reference another image: "put the jacket from the second photo on him". If the user hasn't uploaded that second photo yet, the model doesn't ask. It invents a jacket.
So the editor reads the instruction before sending it and counts how many photos it refers to:
const ORDER: Record<string, number> = {
second: 2, '2nd': 2, other: 2, another: 2,
third: 3, '3rd': 3, fourth: 4, '4th': 4,
};
const PHOTO = '(?:photo|picture|image|pic|shot)s?';
const mention = new RegExp(
`\\b(${Object.keys(ORDER).join('|')})\\s+${PHOTO}\\b`,
'gi'
);
export function photosInPrompt(prompt: string): number {
let count = 1;
for (const match of prompt.matchAll(mention)) {
count = Math.max(count, ORDER[match[1].toLowerCase()] ?? 1);
}
return count;
}
The real version also catches "both photos" and "these three pictures". If the instruction needs two photos and only one is uploaded, the button waits and asks for the other one, and nothing is charged.
With both photos in place, the same paragraph keeps the person intact while the jacket comes from the reference:
| Person | Jacket | Result |
|---|---|---|
![]() |
![]() |
![]() |
The same flow, with up to four photos, is what the AI image combiner page does.
A test list for your own prompt
These are the eight kinds of edits in my test list. Use one portrait for every edit that involves a person, so a changed face is easy to spot.
| Kind | Example instruction | What a failure looks like |
|---|---|---|
| Outfit | Dress him in a navy suit with a white shirt and a dark tie | The face or body changes along with the clothes |
| Background | Put him in a snowy mountain village in winter | The person is redrawn instead of placed in the new scene |
| Add something | Give the dog a red scarf and a ball | The dog's breed, color or pose changes |
| Remove something | Remove all the people in the background and keep the man in the green jacket | The man who stays is changed too, or smudges are left behind |
| Style | Turn the photo into a watercolor painting | It stays a photo, or only part of the frame changes |
| Light | Replace the grey sky with a dramatic orange sunset | The sky changes but the light on the scene doesn't |
| Text | Remove all the writing from the chalkboard sign | Other parts of the photo get cleaned up too |
| Expression | Make him laugh | The same smile as before (rules too strict) or a different person (rules too loose) |
The style and expression rows matter most: they show whether your rules are too strict or too loose. The other six check that the rules keep the rest of the photo in place.
Takeaways
- Put the user's instruction first and your rules after it, pointing back to it.
- Protect identity (the same recognizable person), not appearance. Expression, hair and style are things people want to change.
- Give every protective rule an exit for when the user asks for exactly what it protects.
- Test the edits your rules might block (a laugh, a painting), not only the ones they're meant to protect.
- Check whether an instruction refers to photos that aren't there before you call the model.
- Drop the prompts a model can't do from your suggestions, instead of letting users find out.
If you're building something similar, I'd like to hear how you handle identity: prompt only, like this, or a face-similarity check after generation? And if you ran the template above, which edits did it break? I haven't added a similarity check yet, because in about twenty test edits neither model quietly returned the photo unchanged. That may change as real traffic grows.
Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.






