├── .env.example
├── .eslintrc.json
├── public
└── logo.png
├── src
├── app
│ ├── favicon.ico
│ ├── layout.tsx
│ ├── api
│ │ └── predictions
│ │ │ ├── [id]
│ │ │ └── route.ts
│ │ │ └── route.ts
│ ├── globals.css
│ └── page.tsx
└── components
│ ├── Footer.tsx
│ ├── Footer.css
│ ├── Navbar.tsx
│ └── Navbar.css
├── postcss.config.js
├── .vscode
└── settings.json
├── next-env.d.ts
├── .gitignore
├── next.config.js
├── tailwind.config.ts
├── tsconfig.json
├── package.json
└── README.md
/.env.example:
--------------------------------------------------------------------------------
1 | REPLICATE_API_TOKEN =
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/public/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gaureshpai/ggreplicater/HEAD/public/logo.png
--------------------------------------------------------------------------------
/src/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gaureshpai/ggreplicater/HEAD/src/app/favicon.ico
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.codeActionsOnSave": {
3 | "source.fixAll.eslint": "explicit"
4 | },
5 | "eslint.validate": [
6 | "typescript"
7 | ],
8 | "editor.formatOnSave": true
9 | }
--------------------------------------------------------------------------------
/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | // NOTE: This file should not be edited
5 | // see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 | .pnpm-debug.log*
27 |
28 | # local env files
29 | .env*.local
30 | .env
31 | # vercel
32 | .vercel
33 |
34 | .vercel
35 |
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | images: {
4 | remotePatterns: [
5 | {
6 | protocol: "https",
7 | hostname: "replicate.com",
8 | },
9 | {
10 | protocol: 'https',
11 | hostname: 'replicate.delivery',
12 | port: '',
13 | pathname: '/pbxt/**',
14 | },
15 | {
16 | protocol: 'https',
17 | hostname: 'raw.githubusercontent.com',
18 | }
19 | ],
20 | },
21 | }
22 |
23 | module.exports = nextConfig
24 |
--------------------------------------------------------------------------------
/src/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import type { Metadata } from 'next'
2 | import { Inter } from 'next/font/google'
3 | import './globals.css'
4 |
5 | const inter = Inter({ subsets: ['latin'] })
6 |
7 | export const metadata: Metadata = {
8 | title: 'ai replicater',
9 | description: 'Replicate AI Image generator',
10 | }
11 |
12 | export default function RootLayout({
13 | children,
14 | }: {
15 | children: React.ReactNode
16 | }) {
17 | return (
18 |
19 |
{children}
20 |
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/Footer.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import Link from 'next/link';
3 | import './Footer.css';
4 |
5 | export default function Footer() {
6 | return (
7 |
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from 'tailwindcss'
2 |
3 | const config: Config = {
4 | content: [
5 | './src/pages/**/*.{js,ts,jsx,tsx,mdx}',
6 | './src/components/**/*.{js,ts,jsx,tsx,mdx}',
7 | './src/app/**/*.{js,ts,jsx,tsx,mdx}',
8 | ],
9 | theme: {
10 | extend: {
11 | backgroundImage: {
12 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
13 | 'gradient-conic':
14 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
15 | },
16 | },
17 | },
18 | plugins: [],
19 | }
20 | export default config
21 |
--------------------------------------------------------------------------------
/src/app/api/predictions/[id]/route.ts:
--------------------------------------------------------------------------------
1 | import Replicate from "replicate";
2 |
3 | const replicate = new Replicate({
4 | auth: process.env.REPLICATE_API_TOKEN
5 | });
6 |
7 | export async function GET(request: Request,
8 | { params }: { params: { id: string } }) {
9 | const prediction = await replicate.predictions.get(params.id);
10 |
11 | if (prediction?.error) {
12 | return new Response(
13 | JSON.stringify({ detail: prediction.error.detail }),
14 | { status: 500 }
15 | );
16 | }
17 |
18 | return new Response(
19 | JSON.stringify(prediction),
20 | { status: 200 }
21 | );
22 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "noEmit": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "resolveJsonModule": true,
13 | "isolatedModules": true,
14 | "jsx": "preserve",
15 | "incremental": true,
16 | "plugins": [
17 | {
18 | "name": "next"
19 | }
20 | ],
21 | "paths": {
22 | "@/*": ["./src/*"]
23 | }
24 | },
25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
26 | "exclude": ["node_modules"]
27 | }
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ggreplicater",
3 | "version": "1.0.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint",
10 | "test": "npm run lint && npm run build"
11 | },
12 | "dependencies": {
13 | "next": "^14.2.21",
14 | "react": "^18",
15 | "react-dom": "^18",
16 | "replicate": "^0.34.0"
17 | },
18 | "devDependencies": {
19 | "@types/node": "^22",
20 | "@types/react": "^18",
21 | "@types/react-dom": "^18",
22 | "autoprefixer": "^10.4.20",
23 | "eslint": "^8",
24 | "eslint-config-next": "15.1.6",
25 | "postcss": "^8",
26 | "tailwindcss": "^3.4.17",
27 | "typescript": "^5"
28 | }
29 | }
--------------------------------------------------------------------------------
/src/app/api/predictions/route.ts:
--------------------------------------------------------------------------------
1 | import Replicate from "replicate";
2 |
3 | const replicate = new Replicate({
4 | auth: process.env.REPLICATE_API_TOKEN,
5 | });
6 |
7 | export async function POST(req: Request) {
8 |
9 | const data = await req.formData();
10 | if (!process.env.REPLICATE_API_TOKEN) {
11 | throw new Error(
12 | "The REPLICATE_API_TOKEN environment variable is not set. See README.md for instructions on how to set it."
13 | );
14 | }
15 |
16 | const prediction = await replicate.predictions.create({
17 | // Pinned to a specific version of Stable Diffusion
18 | // See https://replicate.com/stability-ai/sdxl
19 | version: "8beff3369e81422112d93b89ca01426147de542cd4684c244b673b105188fe5f",
20 |
21 | // This is the text prompt that will be submitted by a form on the frontend
22 | input: { prompt: data.get("prompt") },
23 | });
24 |
25 | if (prediction?.error) {
26 | return new Response(
27 | JSON.stringify({ detail: prediction.error.detail }),
28 | { status: 500 }
29 | );
30 | }
31 |
32 | return new Response(
33 | JSON.stringify(prediction),
34 | { status: 201 }
35 | );
36 | }
--------------------------------------------------------------------------------
/src/components/Footer.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | :root {
6 | --foreground-color: rgb(0, 0, 0);
7 | --background-start-color: #f3f4f6;
8 | --background-end-color: #ffffff;
9 | --primary-color: #4f46e5;
10 | --hover-color: #6b63ff;
11 | --title-hover-color: #f3f87a;
12 | }
13 |
14 | @media (prefers-color-scheme: dark) {
15 | :root {
16 | --foreground-color: rgb(255, 255, 255);
17 | --background-start-color: #111827;
18 | --background-end-color: #1f2937;
19 | --primary-color: #7c3aed;
20 | --hover-color: #9561e2;
21 | --title-hover-color: #f3f87a;
22 | }
23 | }
24 |
25 | footer {
26 | background-color: var(--primary-color);
27 | color: white;
28 | }
29 |
30 | footer a {
31 | color: white;
32 | text-decoration: none;
33 | }
34 |
35 | footer a:hover {
36 | text-decoration: underline;
37 | }
38 |
39 | .footer-container {
40 | background-color: #4f46e5;
41 | color: white;
42 | padding: 1rem 0;
43 | }
44 |
45 | .footer-box {
46 | text-align: center;
47 | }
48 |
49 | .footer-box p {
50 | margin: 0;
51 | }
52 |
53 | .hehe {
54 | text-decoration: none;
55 | }
--------------------------------------------------------------------------------
/src/components/Navbar.tsx:
--------------------------------------------------------------------------------
1 | import Link from "next/link";
2 | import './Navbar.css'
3 | import Image from "next/image";
4 |
5 | export default function Navbar() {
6 | return (
7 |
35 | );
36 | }
37 |
--------------------------------------------------------------------------------
/src/components/Navbar.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | :root {
6 | --foreground-color: rgb(0, 0, 0);
7 | --background-start-color: #f3f4f6;
8 | --background-end-color: #ffffff;
9 | --primary-color: #4f46e5;
10 | --hover-color: #6b63ff;
11 | --title-hover-color: #f3f87a;
12 | }
13 |
14 | @media (prefers-color-scheme: dark) {
15 | :root {
16 | --foreground-color: rgb(255, 255, 255);
17 | --background-start-color: #111827;
18 | --background-end-color: #1f2937;
19 | --primary-color: #7c3aed;
20 | --hover-color: #9561e2;
21 | --title-hover-color: #f3f87a;
22 | }
23 | }
24 |
25 | .titleb {
26 | display: flex;
27 | align-items: center;
28 | text-decoration: none;
29 | color: white;
30 | font-size: 2rem;
31 | font-weight: bold;
32 | }
33 |
34 | .titleb:hover {
35 | opacity: 0.8;
36 | text-decoration: none;
37 | color: #f3f87a;
38 | }
39 |
40 | .button-container {
41 | display: flex;
42 | flex-direction: column;
43 | align-items: center;
44 | gap: 1rem;
45 | }
46 |
47 | .buttons {
48 | color: white;
49 | text-decoration: none;
50 | padding: 0.5rem 1rem;
51 | border-radius: 0.25rem;
52 | transition: background-color 0.3s ease;
53 | }
54 |
55 | .buttons:hover {
56 | background-color: #4f46e5;
57 | text-decoration: none;
58 | color: #f3f87a;
59 | }
60 |
61 | nav{
62 | background-color: var(--primary-color);
63 | color: white;
64 | padding: 1rem;
65 | }
66 |
67 | nav a{
68 | color: white;
69 | text-decoration: none;
70 | }
71 |
72 | nav a:hover{
73 | text-decoration: underline;
74 | }
75 |
76 | @media (min-width: 768px) {
77 | .button-container {
78 | flex-direction: row;
79 | }
80 |
81 | .buttons {
82 | width: 100%;
83 | }
84 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Welcome to GGReplicater 🚀
2 |
3 | 
4 |
5 | GGReplicater is a web application hosted on Vercel that utilizes Replicate AI to generate images based on user prompts.
6 |
7 | ## 🌟 Features
8 |
9 | - **Generate Images**: Input a prompt and receive an AI-generated image in response.
10 | - **Download Images**: Download the generated image with ease.
11 | - **Open Source**: GGReplicater is built on open-source technologies, encouraging collaboration and innovation.
12 |
13 | ## 🚀 Getting Started
14 |
15 | 1. **Clone the Repository:**
16 |
17 | ```bash
18 | git clone https://github.com/gaureshpai/ggreplicater.git
19 | cd ggreplicater
20 | ```
21 |
22 | 2. **Install Dependencies:**
23 |
24 | ```bash
25 | npm install
26 | ```
27 |
28 | 3. **Run the Application:**
29 |
30 | ```bash
31 | npm run dev
32 | ```
33 |
34 | Open [http://localhost:3000](http://localhost:3000) in your browser to explore GGReplicater.
35 |
36 | ## 🎨 Usage
37 |
38 | Enter a prompt in the provided input field to generate an image. The application will utilize Replicate AI to generate an image based on your prompt. You can then download the generated image for your use.
39 |
40 | ## 🤝 Contributing
41 |
42 | We welcome contributions from the community! If you have ideas for improvements, new features, or bug fixes, please open an issue or submit a pull request.
43 |
44 | ## 🔧 Technologies Used
45 |
46 | - **Next.js**: The foundation for building React applications with server-side rendering.
47 | - **Replicate AI**: Advanced AI algorithms power our image generation.
48 | - **Tailwind CSS**: A utility-first CSS framework for building modern and responsive designs.
49 |
50 | ## 📄 License
51 |
52 | GGReplicater is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
53 |
54 | ## 🙌 Acknowledgments
55 |
56 | GGReplicater is made possible by the contributions of our community and the following technologies:
57 |
58 | - React
59 | - Next.js
60 | - Tailwind CSS
61 | - Replicate AI
62 |
63 | Thank you for using GGReplicater! 🎉
64 |
--------------------------------------------------------------------------------
/src/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | :root {
6 | --foreground-color: rgb(0, 0, 0);
7 | --background-start-color: #f3f4f6;
8 | --background-end-color: #ffffff;
9 | --primary-color: #4f46e5;
10 | --hover-color: #6b63ff;
11 | --title-hover-color: #f3f87a;
12 | }
13 |
14 | @media (prefers-color-scheme: dark) {
15 | :root {
16 | --foreground-color: rgb(255, 255, 255);
17 | --background-start-color: #111827;
18 | --background-end-color: #1f2937;
19 | --primary-color: #7c3aed;
20 | --hover-color: #9561e2;
21 | --title-hover-color: #f3f87a;
22 | }
23 | }
24 |
25 | body {
26 | font-family: 'Arial', sans-serif;
27 | background: linear-gradient(to right, var(--background-start-color), var(--background-end-color));
28 | color: var(--foreground-color);
29 | margin: 0;
30 | padding: 0;
31 | box-sizing: border-box;
32 | }
33 |
34 | input:focus,
35 | button:focus {
36 | outline: none;
37 | }
38 |
39 | nav,
40 | footer {
41 | background-color: var(--primary-color);
42 | color: white;
43 | }
44 |
45 | nav a,
46 | footer a {
47 | color: white;
48 | text-decoration: none;
49 | }
50 |
51 | nav a:hover,
52 | footer a:hover {
53 | text-decoration: underline;
54 | }
55 |
56 | .button {
57 | cursor: pointer;
58 | padding: 8px 16px;
59 | border: none;
60 | border-radius: 4px;
61 | transition: background-color 0.3s ease, box-shadow 0.3s ease;
62 | }
63 |
64 | .button-link {
65 | display: inline-block;
66 | margin-right: 10px;
67 | }
68 |
69 | .button-link:last-child {
70 | margin-right: 0;
71 | }
72 |
73 | .button-link:hover {
74 | box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.2);
75 | }
76 |
77 | main {
78 | flex-grow: 1;
79 | display: flex;
80 | flex-direction: column;
81 | align-items: center;
82 | justify-content: center;
83 | padding: 20px;
84 | }
85 |
86 | .title-link:hover {
87 | color: var(--title-hover-color);
88 | }
89 |
90 | .titleb {
91 | display: flex;
92 | align-items: center;
93 | text-decoration: none;
94 | color: white;
95 | font-size: 2rem;
96 | font-weight: bold;
97 | }
98 |
99 | .titleb:hover {
100 | opacity: 0.8;
101 | text-decoration: none;
102 | color: #f3f87a;
103 | }
104 |
105 | .buttons {
106 | color: white;
107 | text-decoration: none;
108 | padding: 0.5rem 1rem;
109 | border-radius: 0.25rem;
110 | transition: background-color 0.3s ease;
111 | }
112 |
113 | .buttons:hover {
114 | background-color: #4f46e5;
115 | text-decoration: none;
116 | color: #f3f87a;
117 | }
118 |
119 | .button-container {
120 | display: flex;
121 | flex-direction: column;
122 | align-items: center;
123 | gap: 1rem;
124 | }
125 |
126 | .footer-container {
127 | background-color: var(--primary-color);
128 | color: white;
129 | padding: 1rem 0;
130 | }
131 |
132 | .footer-box {
133 | text-align: center;
134 | }
135 |
136 | .footer-box p {
137 | margin: 0;
138 | }
139 |
140 | @media (max-width: 767px) {
141 | .button-container {
142 | flex-direction: column;
143 | align-items: center;
144 | }
145 |
146 | .buttons {
147 | width: 100%;
148 | }
149 | }
--------------------------------------------------------------------------------
/src/app/page.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 | import { useState } from "react";
3 | import Head from "next/head";
4 | import Image from "next/image";
5 | import Navbar from "../components/Navbar";
6 | import Footer from "../components/Footer";
7 |
8 | import { Prediction } from "replicate";
9 | const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
10 |
11 | export default function Home() {
12 | const [prediction, setPrediction] = useState(null);
13 | const [error, setError] = useState(null);
14 |
15 | const handleSubmit = async (e: React.FormEvent) => {
16 | e.preventDefault();
17 |
18 | const response = await fetch("/api/predictions", {
19 | method: "POST",
20 | body: new FormData(e.currentTarget),
21 | });
22 |
23 | let prediction = await response.json();
24 |
25 | if (response.status !== 201) {
26 | setError(prediction.detail);
27 | return;
28 | }
29 | setPrediction(prediction);
30 |
31 | while (prediction?.status !== "succeeded" && prediction?.status !== "failed") {
32 | await sleep(1000);
33 | const response = await fetch("/api/predictions/" + prediction?.id, { cache: "no-store" });
34 | prediction = await response.json();
35 | if (response.status !== 200) {
36 | setError(prediction.detail);
37 | return;
38 | }
39 | setPrediction(prediction);
40 | }
41 | };
42 |
43 | const handleDownload = () => {
44 | if (prediction) {
45 | const downloadLink = document.createElement("a");
46 | downloadLink.href = prediction.output[prediction.output.length - 1];
47 | downloadLink.download = "generated_image.png";
48 | downloadLink.click();
49 | }
50 | };
51 |
52 | return (
53 |
54 |
55 |
The AI Replicater
56 |
57 |
58 |
59 |
60 |
61 |
62 |
Generate Images
63 |
74 |
89 |
90 | {error &&
{error}
}
91 |
92 | {prediction ? (
93 |
94 | {prediction.output && (
95 |
96 |
103 |
109 |
110 | )}
111 |
Status: {prediction.status}
112 |
113 | ) : null}
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 | );
122 | }
--------------------------------------------------------------------------------