Full Stack Image Generator App

Full Stack Image Generator App

Share It With Your Firends:

Learn how to build an AI Image Generator app using React, Firebase, and the Hugging Face API in just one hour! This comprehensive full-stack tutorial takes you step-by-step through the process, from setting up your React app to implementing important features like Firebase storage, Firestore, and React routing. Perfect for beginners and experienced developers alike, this tutorial will equip you with the skills to build your own image generation app. So don’t wait, let’s get started and take your development skills to the next level!

index.css

@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;300&family=Poppins:wght@400&display=swap');
@tailwind base;
@tailwind components;
@tailwind utilities;

body {
  margin: 0;
  font-family: 'Montserrat', sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #333;
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
    monospace;
}

*{
  box-sizing: border-box;
}

header{
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 80px;
  background-color: #ffff;
}

header .menu{
  display: flex;
  align-items: center;
}

.menu .logo{
  border-radius: 50%;
  height: 30px;
  width: 30px;
  border: 1px solid #ddd;
  margin-right: 10px;
}

.menu button{
  background-color: transparent;
  color: #333;
  border: none;
  font-size: 15px;
}

header .menu .link{
  padding: 10px 20px;
  text-decoration: none;
  color: #555;
}


.login-page{
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  width: 100%;
  align-items: center;
  text-align: center;
}

.button{
  background-color: #555;
  color: #fff;
  border-radius: 4px;
  border: none;
  outline: none;
  padding: 8px 10px;
}

.container{
  margin: auto;
  max-width: 1000px;
}

.m-2{
  margin-top: 20px;
}

.community-showcase{
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  max-width: 1000px;
}

.post{
  width: 32%;
  max-width: 400px;
  display: flex;
  flex-direction: column;
  align-items: center;
  overflow: hidden;
  border-radius: 10px;
  margin: 5px;
  box-shadow: 0 0 10px rgb(0, 0, 0, 0.3);
}

.post img{
  position: relative;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.imageGen{
  max-width: 1000px;
  border-radius: 20px 40px;
  margin: 20px auto;
  padding: 10px;
  background-color: transparent;
}

.generate-form{
  display: flex;
  align-items: center;
  width: 100%;
}

.generate-form input{
  flex: 1;
  padding: 10px;
  border: 1px solid #ddd;
  border-radius: 10px;
}

.generate-form input:focus{
  outline: 0.6px solid blue;
}

.generate-form button{
  margin-left: 10px;
  border: none;
  width: 100px;
  background-color: #04acfa;
  color: #fff;
  padding: 10px;
  cursor: pointer;
}

.imageGen .result-image{
  max-width: 400px;
  margin: auto;
  margin-top: 20px;
}

.result-image img{
  width: 100%;
  border-radius: 5px;
  height: auto;
}

.result-image .action{
  display: flex;
}

.action button{
  background-color: #f5f9fb;
  color: #333;
  border: none;
  padding: 10px;
  margin: 10px;
  border-radius: 5px;
}

.loading{
  display: flex;
  width: 100%;
  text-align: center;
  margin: 70px auto;
  align-items: center;
}

.loading p{
  margin: auto;
  text-align: center;
}

.share-form{
  display: none;
}

.d-flex{
  display: flex;
  align-items: center;
}

h1 span{
  color: #04acfa;
}
 
.logo{
  border: 1px solid #ddd;
  border-radius: 50%;
  height: 40px;
  width: 40px;
}

@media screen and (max-width: 1000px) {
  header{
    padding: 8px;
    font-size: 15px;
  }

  header .menu .link{
    padding: 8px 10px;
    font-size: 14px;
  }
}

firebase-config.js

// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
import {getAuth} from "firebase/auth";
import { GoogleAuthProvider } from "firebase/auth";
import {getFirestore} from "firebase/firestore"
import {getStorage} from "firebase/storage"

// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries

// Your web app's Firebase configuration
const firebaseConfig = {
  //key here
};

// Initialize Firebase
const app = initializeApp(firebaseConfig);

export const Auth = getAuth(app)
export const Provider = new GoogleAuthProvider()
export const db = getFirestore(app)
export const storage = getStorage(app)

App.js

import React from 'react'
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import ImageGenerationForm from './components/Generate'
import Home from './components/Home'
import Login from './components/Login'
import Navbar from './components/Navbar'

const App = () => {
  return (
    <div>
    <BrowserRouter>
    <Navbar/>
    <main className="sm:p-8 px-4 py-8 w-full bg-[#f9fafe] min-h-[calc(100vh-73px)]">
    <div className="container">
      <Routes>
        <Route path='/' element={<Home/>}/>
        <Route path='/login' element={<Login/>}/>
        <Route path="/generate" element={<ImageGenerationForm/>}/>
      </Routes>
      </div>
      </main>
    </BrowserRouter>
    </div>
  )
}

export default App

loadinganimation.js

import * as React from 'react';
import CircularProgress from '@mui/material/CircularProgress';
import Box from '@mui/material/Box';

export function CircularIndeterminate() {
  return (
    <Box sx={{ display: 'flex' }}>
      <CircularProgress />
    </Box>
  );
}

tailwind.config.js

/** @type {import('tailwindcss').Config} */

module.exports = {
  content: ['./src/**/*.{js,jsx}'],
  theme: {
    extend: {
      screens: {
        xs: '480px',
      },
      fontFamily: {
        inter: ['Inter var', 'sans-serif'],
      },
      boxShadow: {
        card: '0 0 1px 0 rgba(189,192,207,0.06),0 10px 16px -1px rgba(189,192,207,0.2)',
        cardhover: '0 0 1px 0 rgba(189,192,207,0.06),0 10px 16px -1px rgba(189,192,207,0.4)',
      },
    },
  },
  plugins: [],
};

Login.jsx

import React from 'react'
import { Provider, Auth } from '../firebase-config'
import { signInWithPopup } from 'firebase/auth';
import { useNavigate } from 'react-router-dom';

const Login = () => {
  const navigator = useNavigate();
  
  const signIn = async () =>{
    await signInWithPopup(Auth, Provider)
    .then(res=>{console.log(res); navigator("/")})
    .catch(err=>console.log(err))
  }
  return (
    <div className='login-page'>
        <h2>Login Here!</h2>
        <button className='button' onClick={signIn}>Sign In With Google</button>
    </div>
  )
}

export default Login

Navbar.jsx

import React from 'react'
import { Link } from 'react-router-dom'
import {useAuthState} from 'react-firebase-hooks/auth';
import {Auth} from "../firebase-config"
import { signOut } from 'firebase/auth';
import LogoutIcon from '@mui/icons-material/Logout';
import { useNavigate } from 'react-router-dom';

const Navbar = () => {
  const [user] = useAuthState(Auth)
  const navigator = useNavigate()
  const logOut = async () => {
    await signOut(Auth)
    navigator("/")
  }
  return (
    <header>
        <h3>CwaLabs</h3>

        <div className="menu">
            <Link className='link' to="/">Home</Link>
            {user && <Link className='link' to={"/generate"}>Generate</Link>}
            {user? <div className='link'><div className='d-flex'><img className='logo' src={user.photoURL} alt="" />  <button onClick={logOut}><LogoutIcon/></button></div></div>
            : <Link className='link' to={"/login"}>Login</Link>
            }
        </div>
    </header>
  )
}

export default Navbar

Generate.jsx

import React, { useState } from "react";
import ShareIcon from '@mui/icons-material/Share';
import FileDownloadIcon from '@mui/icons-material/FileDownload';
import { CircularIndeterminate } from "../loadanimation";
import { Auth, db, storage } from '../firebase-config';
import { getDownloadURL, ref, uploadBytes } from 'firebase/storage';
import { v4 } from 'uuid';
import { collection, addDoc } from 'firebase/firestore';
import {useAuthState} from "react-firebase-hooks/auth"

const API_TOKEN = "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";

const ImageGenerationForm = () => {
  const [loading, setLoading] = useState(false);
  const [output, setOutput] = useState(null);
  const [prompt, setPrompt] = useState("")
  const [imageFile, setImageFile] = useState(null);

  const [user] = useAuthState(Auth) 
  const postRef = collection(db, "posts")

  const uploadImage = async () =>{
    if(imageFile !== null){
      const imageRef = ref(storage, `images/${imageFile.name + v4()}`)
      uploadBytes(imageRef, imageFile)
      .then(()=>{
        getDownloadURL(imageRef)
        .then((url)=>{
          if(prompt !== ""){
            addDoc(postRef, {
              prompt: prompt,
              image: url,
              user: user.displayName,
              logo: user.photoURL,
            })
            .then(res=>alert("posted"))
            .catch(err=>console.log(err))
          }
        })
      })
      .catch(err=>console.log(err))
    }

  }

  const handleSubmit = async (event) => {
    event.preventDefault();
    setLoading(true);

    const input = event.target.elements.input.value;
    setPrompt(input)
    const response = await fetch(
      "https://api-inference.huggingface.co/models/CompVis/stable-diffusion-v1-4",
      {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${API_TOKEN}`,
        },
        body: JSON.stringify({ inputs: input }),
      }
    );

    if (!response.ok) {
      throw new Error("Failed to generate image");
    }

    const blob = await response.blob();
    setOutput(URL.createObjectURL(blob));
    setImageFile(new File([blob], "art.png", { type: "image/png" }));
    setLoading(false);
  };

  const handleDownload = () => {
    const link = document.createElement("a");
    link.href = output;
    link.download = "art.png";
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  };

  return (<div className="imageGen">
    <div>
        <h1 className="font-extrabold text-[#222328] text-[32px]">Prompt Your Creativity!</h1>
        <p className="mt-2 text-[#666e75] text-[14px] max-w-[500px]">Browse through a collection of imaginative and visually stunning images generated by DALL-E AI</p>
      </div>
    <form className="generate-form mt-2" onSubmit={handleSubmit}>
      <input type="text" name="input" placeholder="type your prompt here..." />
      <button type="submit" className="button">Generate</button>
    </form>
    {loading && <div className="loading"><p><CircularIndeterminate/></p></div>}
    {!loading && output && (
      <div className="result-image">
        <img src={output} alt="art"  />
        <div className="action">
            <button onClick={handleDownload}><FileDownloadIcon/></button>
            {user && <button onClick={uploadImage}><ShareIcon/></button>}
        </div>
      </div>
    )}

    </div>);
  
};

export default ImageGenerationForm;

FormField.jsx

import React from 'react';

const FormField = ({
  labelName,
  type,
  name,
  placeholder,
  value,
  handleChange,
  isSurpriseMe,
  handleSurpriseMe,
}) => (
  <div>
    <div className="flex items-center gap-2 mb-2">
      <label
        htmlFor={name}
        className="block text-sm font-medium text-gray-900"
      >
        {labelName}
      </label>
      {isSurpriseMe && (
        <button
          type="button"
          onClick={handleSurpriseMe}
          className="font-semibold text-xs bg-[#EcECF1] py-1 px-2 rounded-[5px] text-black"
        >
          Surprise me
        </button>
      )}
    </div>
    <input
      type={type}
      id={name}
      name={name}
      className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-[#6469ff] focus:border-[#6469ff] outline-none block w-full p-3"
      placeholder={placeholder}
      value={value}
      onChange={handleChange}
      required
    />
  </div>
);

export default FormField;

DisplayPost.jsx

import React from 'react'
import deflogo from "../logo.png"

const DisplayPost = (props) => {
  const {logo, image, prompt, user} = props.post;

  return (
    <div className="rounded-xl group relative shadow-card hover:shadow-cardhover card">
      <img 
      className='w-full h-auto object-cover rounded-xl' 
      src={image} 
      alt={prompt} 
      />

      <div className={"group-hover:flex flex-col max-h-[94.5%] hidden absolute bottom-0 left-0 right-0 bg-[#fff] m-2 p-4 rounded-md"}>
          <div className="d-flex">
            <img className='logo mr-2' src={logo? logo: deflogo} alt={prompt} />
            <div>
              <span style={{color: "#888",fontSize: "12px", textTransform: "lowercase"}}>{user}</span>
              <p style={{"fontSize": "14px"}}>{prompt}</p>
            </div>
          </div>
      </div>

    </div>
  )
}

export default DisplayPost

Home.jsx

import React from 'react'
import { useState, useEffect } from 'react'
import { getDocs, collection } from 'firebase/firestore';
import { db } from '../firebase-config';
import DisplayPost from './DisplayPost';
import { CircularIndeterminate } from "../loadanimation";
import FormField from "./FormField"

const Home = () => {
  const [posts, setPost] = useState([])
  const [loading, setLoading] = useState(true);
  const postRef = collection(db, "posts")

  const [searchText, setSearchText] = useState('');
  const [searchTimeout, setSearchTimeout] = useState(null);
  const [searchedResults, setSearchedResults] = useState(null);

  const handleSearchChange = (e) => {
    clearTimeout(searchTimeout);
    setSearchText(e.target.value);

    setSearchTimeout(
      setTimeout(() => {
        const searchResult = posts.filter((item) => item.user.toLowerCase().includes(searchText.toLowerCase()) || item.prompt.toLowerCase().includes(searchText.toLowerCase()));
        setSearchedResults(searchResult);
      }, 500),
    );
  };

  useEffect(() => {
    setLoading(true)
    const getPost = () => {
      getDocs(postRef)
        .then(data => {
          setPost(data.docs.map((docs) => ({ ...docs.data(), id: docs.id })));
          setLoading(false)
        })
    }
    getPost()
  }, [])
  return (
    <section className="max-w-7xl mx-30px-auto">
      <div>
        <h1 className="font-extrabold text-[#222328] text-[32px]">The Community Showcase</h1>
        <p className="mt-2 text-[#666e75] text-[14px] max-w-[500px]">Browse through a collection of imaginative and visually stunning images generated by DALL-E AI</p>
      </div>

      <div className="mt-16">
        <FormField
          labelName="Search posts"
          type="text"
          name="text"
          placeholder="Search something..."
          value={searchText}
          handleChange={handleSearchChange}
        />
      </div>

      <div className="mt-10">
        {loading ? (
          <div className="flex justify-center items-center">
            <CircularIndeterminate />
          </div>
        ) : (
          <>
            {searchText && (
              <h2 className="font-medium text-[#666e75] text-xl mb-3">
                Showing Resuls for <span className="text-[#222328]">{searchText}</span>:
              </h2>
            )}
            <div className="grid lg:grid-cols-4 sm:grid-cols-3 xs:grid-cols-2 grid-cols-1 gap-3">
              {searchText && searchedResults ? (
                searchedResults.map(post=>(
                <DisplayPost
                  post={post}
                />
                ))
              ) : (posts.map(post=>(
                <DisplayPost
                  post={post}
                />
                ))
              )}
            </div>
          </>
        )}
      </div>
    </section>
  )
}

export default Home

Share It With Your Friends

Leave a Reply

Recent Posts

  • All Post
  • A.I.
  • AI
  • c
  • c++
  • computer
  • cryptocurrency
  • database
  • digital marketing
  • finance
  • hacking
  • HTML
  • java
  • Marketing
  • network
  • other
  • programming
  • python
  • react
  • social
  • Tools
  • Uncategorized
  • web devlopment
    •   Back
    • drawing In Python
DIY AI Voice Assistant In Python

September 8, 2023

Build your own AI assistant with Python! Learn to recognize voice commands, generate responses, and more. Create your virtual companion…

share it

Recent Posts

  • All Post
  • A.I.
  • AI
  • c
  • c++
  • computer
  • cryptocurrency
  • database
  • digital marketing
  • finance
  • hacking
  • HTML
  • java
  • Marketing
  • network
  • other
  • programming
  • python
  • react
  • social
  • Tools
  • Uncategorized
  • web devlopment
    •   Back
    • drawing In Python

Additional Content

CodeWithAM

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus luctus.

Products

Automated Chatbot

Data Security

Virtual Reality

Communication

Support

Services

FAQ's

Privacy Policy

Terms & Condition

Team

Contact Us

Company

About Us

Services

Features

Our Pricing

Latest News

© 2023 Codewitham