Created
July 15, 2024 15:37
-
-
Save gtchakama/beada7d84216a36f0be2b99d172a5942 to your computer and use it in GitHub Desktop.
This React component, Gemini, integrates with Google's Generative AI to analyze images. Users can upload an image and select a character from a predefined list, such as "William Shakespeare" or "A Scientist". The AI then generates a description of the image as if narrated by the selected character. Here's an overview of the component's functiona…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useState } from "react"; | |
import { GoogleGenerativeAI } from "@google/generative-ai"; | |
function Gemini() { | |
// State variables to manage component data | |
const [loading, setLoading] = useState(false); | |
const [apiData, setApiData] = useState(""); | |
const [selectedFile, setSelectedFile] = useState(null); | |
const [selectedCharacter, setSelectedCharacter] = useState(""); | |
const [whoSpoke, setWhoSpoke] = useState(""); | |
// List of characters for the dropdown selection | |
const characters = [ | |
"William Shakespeare", | |
"A politician", | |
"A Doctor", | |
"A 5 year old child", | |
"A Scientist", | |
"an Influencer", | |
]; | |
// Initialize Google Generative AI with API key | |
const genAI = new GoogleGenerativeAI(process.env.NEXT_PUBLIC__API_GEN_API); | |
// Function to convert file to base64 for API consumption | |
const fileToGenerativePart = async (file) => { | |
const base64EncodedDataPromise = new Promise((resolve) => { | |
const reader = new FileReader(); | |
reader.onloadend = () => resolve(reader.result.split(",")[1]); | |
reader.readAsDataURL(file); | |
}); | |
return { | |
inlineData: { data: await base64EncodedDataPromise, mimeType: file.type }, | |
}; | |
}; | |
// Function to handle image upload and analysis | |
const imageUpload = async () => { | |
if (!selectedFile || !selectedCharacter) { | |
alert("Please select both an image and a character."); | |
return; | |
} | |
setLoading(true); | |
try { | |
// Convert image to required format | |
const imagePart = await fileToGenerativePart(selectedFile); | |
// Initialize AI model | |
const model = genAI.getGenerativeModel({ model: "gemini-1.5-flash" }); | |
// Set up prompt for the AI | |
const prompt = `You receive images and explain what it is like ${selectedCharacter}.`; | |
// Generate content using the AI model | |
const result = await model.generateContent([prompt, imagePart]); | |
const response = await result.response; | |
const text = await response.text(); | |
// Update state with AI response | |
setApiData(text); | |
} catch (error) { | |
console.error("Error analyzing image:", error); | |
alert("An error occurred while analyzing the image. Please try again."); | |
} finally { | |
setLoading(false); | |
setWhoSpoke(selectedCharacter); | |
setSelectedCharacter(""); // Reset character selection | |
} | |
}; | |
// Event handler for file selection | |
const handleFileChange = (e) => { | |
setSelectedFile(e.target.files[0]); | |
}; | |
// Event handler for character selection | |
const handleCharacterChange = (e) => { | |
setSelectedCharacter(e.target.value); | |
}; | |
return ( | |
<div className="container mx-auto px-4 py-8 max-w-3xl"> | |
<h1 className="text-3xl font-bold mb-8 text-center"> | |
Google Gemini Pro AI Image Analysis | |
</h1> | |
<div className="flex flex-col space-y-4"> | |
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> | |
{/* File upload form */} | |
<form className="bg-white p-4 rounded-lg shadow-md"> | |
<div className="flex flex-col space-y-2"> | |
<label htmlFor="image" className="text-gray-700 font-medium"> | |
Upload Image: | |
</label> | |
<input | |
type="file" | |
id="image" | |
className="w-full px-3 py-2 text-sm text-gray-700 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" | |
onChange={handleFileChange} | |
accept="image/*" | |
/> | |
</div> | |
</form> | |
{/* Character selection dropdown */} | |
<div className="bg-white p-4 rounded-lg shadow-md"> | |
<label htmlFor="character" className="text-gray-700 font-medium block mb-2"> | |
Select Character: | |
</label> | |
<select | |
id="character" | |
className="w-full px-3 py-2 text-sm text-gray-700 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" | |
value={selectedCharacter} | |
onChange={handleCharacterChange} | |
> | |
<option value="">Choose a character...</option> | |
{characters.map((character, index) => ( | |
<option key={index} value={character}> | |
{character} | |
</option> | |
))} | |
</select> | |
</div> | |
</div> | |
{/* Analysis button */} | |
<button | |
className={`w-full py-3 px-4 rounded-md text-white font-medium transition duration-300 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-700 ${ | |
loading || !selectedFile || !selectedCharacter | |
? "bg-gray-400 cursor-not-allowed" | |
: "bg-blue-600 hover:bg-blue-700" | |
}`} | |
onClick={imageUpload} | |
disabled={loading || !selectedFile || !selectedCharacter} | |
> | |
{loading ? ( | |
<div className="flex items-center justify-center"> | |
{/* Loading spinner SVG */} | |
<svg | |
className="animate-spin mr-2 h-5 w-5 text-white" | |
xmlns="http://www.w3.org/2000/svg" | |
fill="none" | |
viewBox="0 0 24 24" | |
> | |
<circle | |
className="opacity-25" | |
cx="12" | |
cy="12" | |
r="10" | |
stroke="currentColor" | |
strokeWidth="4" | |
></circle> | |
<path | |
className="opacity-75" | |
fill="currentColor" | |
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" | |
></path> | |
</svg> | |
Analyzing Image... | |
</div> | |
) : ( | |
"Analyze Image" | |
)} | |
</button> | |
</div> | |
{/* Analysis result section */} | |
<div className="mt-8"> | |
{apiData && !loading && ( | |
<div className="bg-white p-6 rounded-lg shadow-md"> | |
<h2 className="text-xl font-semibold mb-4">{whoSpoke} says:</h2> | |
<p className="text-gray-700 text-left whitespace-pre-wrap"> | |
{apiData} | |
</p> | |
</div> | |
)} | |
{loading && ( | |
<p className="text-gray-500 text-center">Analyzing image...</p> | |
)} | |
</div> | |
</div> | |
); | |
} | |
export default Gemini; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This React component,
Gemini
, integrates with Google's Generative AI to analyze images. Users can upload an image and select a character from a predefined list, such as "William Shakespeare" or "A Scientist". The AI then generates a description of the image as if narrated by the selected character. Here's an overview of the component's functionality:Features
Components and Hooks
Functions
Usage
To use this component, ensure you have the necessary API key set in your environment variables. The component provides a simple and interactive interface for users to upload images, select characters, and receive AI-generated descriptions.