🔍 About This Code Showcase
This curated code snippet demonstrates how the AI Background Changer uses natural language prompts to intelligently replace image backgrounds while preserving subject integrity.
Full deployment scripts, API integrations, and proprietary details are omitted for clarity and security. This showcase highlights the core multimodal AI integration, image processing, and user interaction algorithms.
🖼️ Core Algorithm: Intelligent Background Replacement Engine
The foundation of AI Background Changer is its ability to understand natural language descriptions and apply precise background modifications while preserving the main subject:
import React, { useState, useCallback } from 'react';
import { ImageUploader } from './components/ImageUploader';
import { PromptInput } from './components/PromptInput';
import { GeneratedImage } from './components/GeneratedImage';
import { editImageWithPrompt } from './services/geminiService';
import { fileToGenerativePart } from './utils/imageUtils';
import type { FileDetails } from './types';
const App: React.FC = () => {
const [fileDetails, setFileDetails] = useState<FileDetails | null>(null);
const [prompt, setPrompt] = useState<string>('');
const [generatedImageUrl, setGeneratedImageUrl] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [error, setError] = useState<string | null>(null);
const handleImageUpload = (file: File) => {
const reader = new FileReader();
reader.onloadend = () => {
setFileDetails({
file: file,
previewUrl: reader.result as string,
});
setGeneratedImageUrl(null);
setError(null);
};
reader.readAsDataURL(file);
};
const handleGenerate = useCallback(async () => {
if (!fileDetails || !prompt) {
setError('Please upload an image and enter a prompt.');
return;
}
setIsLoading(true);
setError(null);
setGeneratedImageUrl(null);
try {
const imagePart = await fileToGenerativePart(fileDetails.file);
const result = await editImageWithPrompt(imagePart, prompt);
if (result) {
setGeneratedImageUrl(result);
} else {
setError('Could not generate image. The model may not have returned an image.');
}
} catch (e) {
console.error(e);
setError(e instanceof Error ? e.message : 'An unknown error occurred.');
} finally {
setIsLoading(false);
}
}, [fileDetails, prompt]);
const handleClear = () => {
setFileDetails(null);
setPrompt('');
setGeneratedImageUrl(null);
setError(null);
setIsLoading(false);
};
const canGenerate = fileDetails !== null && prompt.trim() !== '' && !isLoading;
return (
<div className="min-h-screen bg-gray-900 text-gray-100">
<header className="text-center mb-8">
<h1 className="text-4xl font-extrabold gradient-text">
AI Background Changer
</h1>
<p className="text-gray-400">
Upload an image, describe a new background, and let AI do the magic.
</p>
</header>
<ImageUploader onImageUpload={handleImageUpload} fileDetails={fileDetails} />
<PromptInput prompt={prompt} setPrompt={setPrompt} />
<GeneratedImage
generatedImageUrl={generatedImageUrl}
isLoading={isLoading}
error={error}
onGenerate={handleGenerate}
onClear={handleClear}
canGenerate={canGenerate}
/>
</div>
);
};
export default App;
🤖 Multimodal AI Service Integration
The AI service leverages Gemini 2.5 Flash's multimodal capabilities to understand both image content and natural language instructions for precise background editing:
import { GoogleGenAI, Modality } from "@google/genai";
import type { Part, GenerateContentResponse } from "@google/genai";
const API_KEY = process.env.API_KEY;
if (!API_KEY) {
throw new Error("API_KEY environment variable not set");
}
const ai = new GoogleGenAI({ apiKey: API_KEY });
export async function editImageWithPrompt(
imagePart: Part,
prompt: string
): Promise<string | null> {
try {
const textPart = {
text: prompt,
};
const response: GenerateContentResponse = await ai.models.generateContent({
model: 'gemini-2.5-flash-image-preview',
contents: {
parts: [imagePart, textPart],
},
config: {
responseModalities: [Modality.IMAGE, Modality.TEXT],
},
});
for (const part of response.candidates?.[0]?.content?.parts || []) {
if (part.inlineData) {
const base64ImageBytes: string = part.inlineData.data;
const mimeType = part.inlineData.mimeType;
return `data:${mimeType};base64,${base64ImageBytes}`;
}
}
return null;
} catch (error) {
console.error("Error calling Gemini API:", error);
if (error instanceof Error) {
throw new Error(`Failed to generate image: ${error.message}`);
}
throw new Error("An unknown error occurred while communicating with the API.");
}
}
export function optimizePromptForBackgroundChange(userPrompt: string): string {
const enhancedPrompt = `Change the background of this image to: ${userPrompt}.
Keep the main subject intact and properly integrated with the new background.
Ensure natural lighting and perspective consistency.
Maintain high image quality and realistic composition.`;
return enhancedPrompt;
}
📤 Advanced Image Upload & Processing
The image uploader component provides drag-and-drop functionality with file validation and preview generation optimized for AI processing:
import React, { useCallback } from 'react';
import type { FileDetails } from '../types';
import { UploadIcon } from './Icons';
interface ImageUploaderProps {
onImageUpload: (file: File) => void;
fileDetails: FileDetails | null;
}
export const ImageUploader: React.FC<ImageUploaderProps> = ({
onImageUpload,
fileDetails
}) => {
const onDrop = useCallback((event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault();
event.stopPropagation();
const files = event.dataTransfer.files;
if (files && files.length > 0) {
if (files[0].type.startsWith('image/')) {
onImageUpload(files[0]);
}
}
}, [onImageUpload]);
const onDragOver = (event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault();
event.stopPropagation();
};
const onFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const files = event.target.files;
if (files && files.length > 0) {
onImageUpload(files[0]);
}
};
const onContainerClick = () => {
document.getElementById('file-input')?.click();
};
return (
<div className="w-full">
<div
className={`
relative border-2 border-dashed rounded-lg p-8 text-center cursor-pointer
transition-all duration-300 hover:border-purple-400
${fileDetails ? 'border-purple-500 bg-purple-50' : 'border-gray-600 bg-gray-800'}
`}
onDrop={onDrop}
onDragOver={onDragOver}
onClick={onContainerClick}
>
<input
id="file-input"
type="file"
accept="image/*"
onChange={onFileChange}
className="hidden"
/>
{fileDetails ? (
<div className="space-y-4">
<img
src={fileDetails.previewUrl}
alt="Preview"
className="max-w-full max-h-64 mx-auto rounded-lg shadow-lg"
/>
<p className="text-sm text-gray-600">
{fileDetails.file.name} ({Math.round(fileDetails.file.size / 1024)} KB)
</p>
<p className="text-xs text-gray-500">
Click to change image or drag new file here
</p>
</div>
) : (
<div className="space-y-4">
<UploadIcon className="w-12 h-12 mx-auto text-gray-400" />
<div>
<p className="text-lg font-medium text-gray-300">
Upload an image to get started
</p>
<p className="text-sm text-gray-500">
Drag and drop your image here, or click to browse
</p>
</div>
</div>
)}
</div>
</div>
);
};