├── .env.example ├── src ├── assets │ ├── bulb_icon.png │ ├── code_icon.png │ ├── menu_icon.png │ ├── mic_icon.png │ ├── plus_icon.png │ ├── send_icon.png │ ├── user_icon.png │ ├── compass_icon.png │ ├── gallery_icon.png │ ├── gemini_icon.png │ ├── history_icon.png │ ├── message_icon.png │ ├── setting_icon.png │ ├── youtube_icon.png │ ├── gallery_icon2.png │ ├── question_icon.png │ ├── assets.js │ └── favicon.svg ├── index.css ├── App.jsx ├── main.jsx ├── config │ └── gemini.js ├── context │ └── Context.jsx └── components │ ├── Sidebar │ ├── Sidebar.jsx │ └── Sidebar.css │ └── Main │ ├── Main.jsx │ └── Main.css ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── SECURITY.md ├── pull_request_template.md ├── CONTRIBUTING.md └── CODE_OF_CONDUCT.md ├── vite.config.js ├── .gitignore ├── index.html ├── package.json ├── LICENSE └── README.md /.env.example: -------------------------------------------------------------------------------- 1 | GEMINI_API_KEY="*************************************" 2 | -------------------------------------------------------------------------------- /src/assets/bulb_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RanitManik/Gemini-Clone/HEAD/src/assets/bulb_icon.png -------------------------------------------------------------------------------- /src/assets/code_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RanitManik/Gemini-Clone/HEAD/src/assets/code_icon.png -------------------------------------------------------------------------------- /src/assets/menu_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RanitManik/Gemini-Clone/HEAD/src/assets/menu_icon.png -------------------------------------------------------------------------------- /src/assets/mic_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RanitManik/Gemini-Clone/HEAD/src/assets/mic_icon.png -------------------------------------------------------------------------------- /src/assets/plus_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RanitManik/Gemini-Clone/HEAD/src/assets/plus_icon.png -------------------------------------------------------------------------------- /src/assets/send_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RanitManik/Gemini-Clone/HEAD/src/assets/send_icon.png -------------------------------------------------------------------------------- /src/assets/user_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RanitManik/Gemini-Clone/HEAD/src/assets/user_icon.png -------------------------------------------------------------------------------- /src/assets/compass_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RanitManik/Gemini-Clone/HEAD/src/assets/compass_icon.png -------------------------------------------------------------------------------- /src/assets/gallery_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RanitManik/Gemini-Clone/HEAD/src/assets/gallery_icon.png -------------------------------------------------------------------------------- /src/assets/gemini_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RanitManik/Gemini-Clone/HEAD/src/assets/gemini_icon.png -------------------------------------------------------------------------------- /src/assets/history_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RanitManik/Gemini-Clone/HEAD/src/assets/history_icon.png -------------------------------------------------------------------------------- /src/assets/message_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RanitManik/Gemini-Clone/HEAD/src/assets/message_icon.png -------------------------------------------------------------------------------- /src/assets/setting_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RanitManik/Gemini-Clone/HEAD/src/assets/setting_icon.png -------------------------------------------------------------------------------- /src/assets/youtube_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RanitManik/Gemini-Clone/HEAD/src/assets/youtube_icon.png -------------------------------------------------------------------------------- /src/assets/gallery_icon2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RanitManik/Gemini-Clone/HEAD/src/assets/gallery_icon2.png -------------------------------------------------------------------------------- /src/assets/question_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RanitManik/Gemini-Clone/HEAD/src/assets/question_icon.png -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: ranitmanik 4 | patreon: ranitmanik 5 | buy_me_a_coffee: ranitmanik 6 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | * { 2 | padding: 0; 3 | margin: 0; 4 | box-sizing: border-box; 5 | font-family: 'Outfit', sans-serif; 6 | } 7 | 8 | #root { 9 | min-height: 100vh; 10 | display: flex; 11 | } -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Sidebar from "./components/Sidebar/Sidebar.jsx"; 3 | import Main from "./components/Main/Main.jsx"; 4 | 5 | 6 | const App = () => { 7 | return ( 8 | <> 9 | 10 |
11 | 12 | ) 13 | } 14 | 15 | export default App; -------------------------------------------------------------------------------- /src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.jsx' 4 | import './index.css' 5 | import ContextProvider from "./context/Context.jsx"; 6 | 7 | ReactDOM.createRoot(document.getElementById('root')).render( 8 | 9 | 10 | , 11 | ) 12 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import {defineConfig, loadEnv} from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig(({mode}) => { 6 | const env = loadEnv(mode, process.cwd(), ''); 7 | return { 8 | define: { 9 | 'process.env.GEMINI_API_KEY': JSON.stringify(env.GEMINI_API_KEY) 10 | }, 11 | plugins: [react()], 12 | } 13 | }) 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | # Environmental variables 27 | .env 28 | .vercel 29 | .env*.local 30 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Gemini Clone 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | |---------|--------------------| 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gemini-clone", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@google/generative-ai": "^0.11.3", 14 | "marked": "^13.0.0", 15 | "react": "^18.2.0", 16 | "react-dom": "^18.2.0", 17 | "vercel": "^34.2.0" 18 | }, 19 | "devDependencies": { 20 | "@types/react": "^18.2.66", 21 | "@types/react-dom": "^18.2.22", 22 | "@vitejs/plugin-react": "^4.2.1", 23 | "eslint": "^8.57.0", 24 | "eslint-plugin-react": "^7.34.1", 25 | "eslint-plugin-react-hooks": "^4.6.0", 26 | "eslint-plugin-react-refresh": "^0.4.6", 27 | "vite": "^5.2.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /src/assets/assets.js: -------------------------------------------------------------------------------- 1 | import history_icon from './history_icon.png' 2 | import menu_icon from './menu_icon.png' 3 | import plus_icon from './plus_icon.png' 4 | import question_icon from './question_icon.png' 5 | import setting_icon from './setting_icon.png' 6 | import bulb_icon from './bulb_icon.png' 7 | import compass_icon from './compass_icon.png' 8 | import gallery_icon from './gallery_icon.png' 9 | import mic_icon from './mic_icon.png' 10 | import user_icon from './user_icon.png' 11 | import youtube_icon from './youtube_icon.png' 12 | import message_icon from './message_icon.png' 13 | import code_icon from './code_icon.png' 14 | import send_icon from './send_icon.png' 15 | import gemini_icon from './gemini_icon.png' 16 | 17 | export const assets = { 18 | history_icon, 19 | menu_icon, 20 | plus_icon, 21 | question_icon, 22 | setting_icon, 23 | bulb_icon, 24 | compass_icon, 25 | gallery_icon, 26 | mic_icon, 27 | user_icon, 28 | youtube_icon, 29 | message_icon, 30 | code_icon, 31 | send_icon, 32 | gemini_icon 33 | } -------------------------------------------------------------------------------- /src/assets/favicon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Ranit Manik 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Please include a summary of the changes and the related issue. Please also include relevant motivation and context. List 4 | any dependencies that are required for this change. 5 | 6 | Fixes #(issue) 7 | 8 | ## Type of change 9 | 10 | Please delete options that are not relevant. 11 | 12 | - [ ] Bug fix (non-breaking change which fixes an issue) 13 | - [ ] New feature (non-breaking change which adds functionality) 14 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 15 | - [ ] This change requires a documentation update 16 | 17 | ## How Has This Been Tested? 18 | 19 | Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also 20 | list any relevant details for your test configuration. 21 | 22 | - [ ] Test A 23 | - [ ] Test B 24 | 25 | **Test Configuration**: 26 | 27 | * Firmware version: 28 | * Hardware: 29 | * Toolchain: 30 | * SDK: 31 | 32 | ## Checklist: 33 | 34 | - [ ] My code follows the style guidelines of this project 35 | - [ ] I have performed a self-review of my own code 36 | - [ ] I have commented my code, particularly in hard-to-understand areas 37 | - [ ] I have made corresponding changes to the documentation 38 | - [ ] My changes generate no new warnings 39 | - [ ] I have added tests that prove my fix is effective or that my feature works 40 | - [ ] New and existing unit tests pass locally with my changes 41 | - [ ] Any dependent changes have been merged and published in downstream modules -------------------------------------------------------------------------------- /src/config/gemini.js: -------------------------------------------------------------------------------- 1 | const apiKey = process.env.GEMINI_API_KEY; 2 | 3 | /* 4 | * Install the Generative AI SDK 5 | * 6 | * $ npm install @google/generative-ai 7 | * 8 | * See the getting started guide for more information 9 | * https://ai.google.dev/gemini-api/docs/get-started/node 10 | */ 11 | 12 | /*const { 13 | GoogleGenerativeAI, 14 | HarmCategory, 15 | HarmBlockThreshold, 16 | } = require("@google/generative-ai");*/ 17 | 18 | import { 19 | GoogleGenerativeAI, 20 | HarmCategory, 21 | HarmBlockThreshold, 22 | } from "@google/generative-ai"; 23 | 24 | // const apiKey = process.env.GEMINI_API_KEY; 25 | const genAI = new GoogleGenerativeAI(apiKey); 26 | 27 | const model = genAI.getGenerativeModel({ 28 | model: "gemini-2.5-flash-lite", 29 | }); 30 | 31 | const generationConfig = { 32 | temperature: 1, 33 | topP: 0.95, 34 | topK: 64, 35 | maxOutputTokens: 8192, 36 | responseMimeType: "text/plain", 37 | }; 38 | 39 | const safetySettings = [ 40 | { 41 | category: HarmCategory.HARM_CATEGORY_HARASSMENT, 42 | threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, 43 | }, 44 | { 45 | category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, 46 | threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, 47 | }, 48 | { 49 | category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, 50 | threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, 51 | }, 52 | { 53 | category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, 54 | threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, 55 | }, 56 | ]; 57 | 58 | async function run(prompt) { 59 | const chatSession = model.startChat({ 60 | generationConfig, 61 | safetySettings, 62 | history: [], 63 | }); 64 | 65 | const result = await chatSession.sendMessage(prompt); 66 | console.log(result.response.text()); 67 | return result.response.text(); 68 | } 69 | 70 | export default run; 71 | -------------------------------------------------------------------------------- /src/context/Context.jsx: -------------------------------------------------------------------------------- 1 | import {createContext, useState} from "react"; 2 | import runChat from "../config/gemini"; 3 | 4 | export const Context = createContext(); 5 | 6 | const ContextProvider = (props) => { 7 | 8 | const [input, setInput] = useState(""); 9 | const [recentPrompt, setRecentPrompt] = useState(""); 10 | const [prevPrompts, setPrevPrompts] = useState([]); 11 | const [showResult, setShowResult] = useState(false); 12 | const [loading, setLoading] = useState(false); 13 | const [resultData, setResultData] = useState(""); 14 | 15 | const delayPara = (index, nextWord) => { 16 | setTimeout(function () { 17 | setResultData(prev => prev + nextWord) 18 | }, 75 * index); 19 | } 20 | 21 | const newChat = () => { 22 | setLoading(false); 23 | setShowResult(false); 24 | } 25 | 26 | const onSent = async (prompt) => { 27 | 28 | 29 | setResultData(""); 30 | setLoading(true); 31 | setShowResult(true); 32 | let response; 33 | if (prompt !== undefined) { 34 | response = await runChat(prompt); 35 | setRecentPrompt(prompt); 36 | } else { 37 | setPrevPrompts(prev => [...prev, input]); 38 | setRecentPrompt(input); 39 | response = await runChat(input); 40 | } 41 | 42 | let responseArray = response.split("**"); 43 | let newResponse = ""; 44 | for (let i = 0; i < responseArray.length; i++) { 45 | if (i === 0 || i % 2 !== 1) { 46 | newResponse += responseArray[i]; 47 | } else { 48 | newResponse += "" + responseArray[i] + "" 49 | } 50 | 51 | } 52 | let newResponse2 = newResponse.split("*").join("
"); 53 | let newResponseArray = newResponse2.split(" "); 54 | for (let i = 0; i < newResponseArray.length; i++) { 55 | const nextWord = newResponseArray[i]; 56 | delayPara(i, nextWord + " "); 57 | } 58 | setLoading(false); 59 | setInput(""); 60 | } 61 | 62 | const contextValue = { 63 | prevPrompts, 64 | setPrevPrompts, 65 | onSent, 66 | recentPrompt, 67 | setRecentPrompt, 68 | showResult, 69 | loading, 70 | resultData, 71 | input, 72 | setInput, 73 | newChat 74 | } 75 | return ( 76 | 77 | {props.children} 78 | 79 | ) 80 | } 81 | 82 | export default ContextProvider; -------------------------------------------------------------------------------- /src/components/Sidebar/Sidebar.jsx: -------------------------------------------------------------------------------- 1 | import React, {useContext, useState} from 'react'; 2 | import './Sidebar.css'; 3 | import {assets} from '../../assets/assets'; 4 | import {Context} from '../../context/Context'; 5 | 6 | const Sidebar = () => { 7 | const [extended, setExtended] = useState(false); 8 | const {onSent, prevPrompts, setRecentPrompt, newChat} = useContext(Context); 9 | 10 | const loadPrompt = async (prompt) => { 11 | setRecentPrompt(prompt) 12 | await onSent(prompt) 13 | } 14 | return ( 15 | 55 | ); 56 | } 57 | 58 | export default Sidebar; 59 | -------------------------------------------------------------------------------- /src/components/Sidebar/Sidebar.css: -------------------------------------------------------------------------------- 1 | .sidebar { 2 | min-height: 100svh; 3 | display: inline-flex; 4 | flex-direction: column; 5 | justify-content: space-between; 6 | background-color: #f0f4f9; 7 | padding: 25px 15px; 8 | transition: width 0.15s ease, padding 0.3s ease; 9 | z-index: 999; 10 | user-select: none; 11 | } 12 | 13 | @media (max-width: 800px) { 14 | .sidebar { 15 | position: fixed; 16 | } 17 | } 18 | 19 | .sidebar.extended { 20 | width: 250px; 21 | } 22 | 23 | .sidebar.collapsed { 24 | width: 80px; 25 | } 26 | 27 | .sidebar img { 28 | width: 20px; 29 | } 30 | 31 | .menu { 32 | width: 50px; 33 | height: 50px; 34 | display: -ms-grid; 35 | display: grid; 36 | place-items: center; 37 | cursor: pointer; 38 | border-radius: 100svh; 39 | } 40 | 41 | .menu:hover { 42 | background-color: #e8eaed; 43 | } 44 | 45 | .top, .bottom { 46 | display: grid; 47 | gap: 0.5rem; 48 | -ms-flex-line-pack: start; 49 | align-content: start; 50 | -ms-flex-align: center; 51 | align-items: center; 52 | } 53 | 54 | .sidebar .new-chat { 55 | margin-top: 50px; 56 | display: inline-flex; 57 | align-items: center; 58 | gap: 10px; 59 | padding: 10px 15px; 60 | background-color: #e6eaf1; 61 | border-radius: 50px; 62 | font-size: 14px; 63 | color: #505050; 64 | cursor: pointer; 65 | } 66 | 67 | .new-chat:hover { 68 | background-color: #e0e0e5; 69 | } 70 | 71 | .new-chat { 72 | justify-content: center; 73 | width: max-content; 74 | } 75 | 76 | .sidebar .recent-title { 77 | margin-top: 40px; 78 | margin-bottom: 20px; 79 | } 80 | 81 | .sidebar .recent-entry { 82 | display: flex; 83 | justify-content: start; 84 | align-items: start; 85 | gap: 10px; 86 | padding: 10px; 87 | border-radius: 100vh; 88 | color: #282828; 89 | cursor: pointer; 90 | } 91 | 92 | .sidebar .recent-entry:hover { 93 | background-color: #e2e6eb; 94 | } 95 | 96 | .fade { 97 | transition: opacity 1s ease; 98 | } 99 | 100 | .hidden { 101 | opacity: 0; 102 | visibility: hidden; 103 | } 104 | 105 | .visible { 106 | opacity: 1; 107 | visibility: visible; 108 | } 109 | 110 | 111 | @keyframes fadeIn { 112 | from { 113 | opacity: 0; 114 | } 115 | to { 116 | opacity: 1; 117 | } 118 | } 119 | 120 | @keyframes fadeOut { 121 | from { 122 | opacity: 1; 123 | } 124 | to { 125 | opacity: 0; 126 | } 127 | } 128 | 129 | .none { 130 | display: none; 131 | opacity: 0; 132 | animation: fadeOut 1s forwards; 133 | } 134 | 135 | .block { 136 | display: block; 137 | opacity: 0; 138 | animation: fadeIn 1s forwards; 139 | white-space: nowrap; 140 | } 141 | 142 | .centered { 143 | display: -ms-grid; 144 | display: grid; 145 | align-items: center; 146 | justify-content: start; 147 | } 148 | 149 | .recent { 150 | max-height: 300px; 151 | overflow-y: auto; 152 | } 153 | 154 | .recent-entry-p { 155 | white-space: nowrap; 156 | overflow: hidden; 157 | } 158 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidelines 2 | 3 | Thank you for considering contributing to this project! Your help is greatly appreciated. Below are some guidelines to 4 | follow to make the contribution process smooth and effective for everyone involved. 5 | 6 | ## How to Contribute 7 | 8 | 1. **Fork the Repository**: 9 | - Navigate to the repository you want to contribute to. 10 | - Click the "Fork" button at the top right corner of the page. 11 | 12 | 2. **Clone Your Fork**: 13 | - Open your terminal and run: 14 | ```sh 15 | git clone https://github.com/RanitManik/Gemini-Clone.git 16 | ``` 17 | 18 | 3. **Create a Branch**: 19 | - Move into the cloned directory: 20 | ```sh 21 | cd Gemini-Clone 22 | ``` 23 | - Create a new branch for your changes: 24 | ```sh 25 | git checkout -b feature-branch-name 26 | ``` 27 | 28 | 4. **Make Your Changes**: 29 | - Implement your changes in your local repository. 30 | 31 | 5. **Commit Your Changes**: 32 | - Add your changes: 33 | ```sh 34 | git add . 35 | ``` 36 | - Commit your changes with a meaningful message: 37 | ```sh 38 | git commit -m "Description of changes" 39 | ``` 40 | 41 | 6. **Push to Your Fork**: 42 | - Push your changes to your forked repository: 43 | ```sh 44 | git push origin feature-branch-name 45 | ``` 46 | 47 | 7. **Create a Pull Request**: 48 | - Go to the original repository. 49 | - Click the "New Pull Request" button. 50 | - Select the branch you created and click "Create Pull Request". 51 | - Provide a detailed description of your changes in the pull request. 52 | 53 | ## Code Style 54 | 55 | - Follow the coding standards and style guides of the project. 56 | - Write clean, readable, and maintainable code. 57 | - Add comments where necessary to explain complex logic or decisions. 58 | 59 | ## Testing 60 | 61 | - Ensure that your changes do not break any existing functionality. 62 | - Write tests to cover new or changed functionality if applicable. 63 | - Run all tests to confirm that everything works as expected. 64 | 65 | ## Documentation 66 | 67 | - Update the documentation if your changes include new features or modifications. 68 | - Ensure that your documentation is clear, concise, and easy to understand. 69 | 70 | ## Commit Messages 71 | 72 | - Use clear and concise commit messages. 73 | - Follow the format: 74 | ``` 75 | [type]: [subject] 76 | 77 | [body] 78 | 79 | [footer] 80 | ``` 81 | 82 | Example: 83 | ``` 84 | feat: add new feature for user authentication 85 | 86 | Implemented user login and registration functionality. 87 | Added tests for the new feature. 88 | 89 | Closes #123 90 | ``` 91 | 92 | ## Issue Reporting 93 | 94 | - If you find a bug, create an issue before submitting a pull request. 95 | - Provide a detailed description of the bug, including steps to reproduce it. 96 | - If possible, include screenshots or code snippets to help illustrate the issue. 97 | 98 | ## Pull Request Review 99 | 100 | - Be patient and respectful while waiting for your pull request to be reviewed. 101 | - Address any feedback or requested changes promptly and thoughtfully. 102 | - Engage in discussions and provide clarifications if needed. 103 | 104 | ## Code of Conduct 105 | 106 | - Follow the project's code of conduct. 107 | - Be respectful, inclusive, and considerate in your interactions. 108 | - Help create a welcoming and positive environment for all contributors. 109 | 110 | --- 111 | 112 | We appreciate your contribution and look forward to collaborating with you! 113 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | google-gemini-icon 4 | 5 | # Gemini Clone 6 | 7 | ![GitHub Created At](https://img.shields.io/github/created-at/RanitManik/Gemini-Clone) 8 | ![Repo Size](https://img.shields.io/github/repo-size/RanitManik/Gemini-Clone) 9 | ![Discussions](https://img.shields.io/github/discussions/RanitManik/Gemini-Clone) 10 | ![License](https://img.shields.io/github/license/RanitManik/Gemini-Clone) 11 | ![Forks](https://img.shields.io/github/forks/RanitManik/Gemini-Clone?style=default) 12 | ![Stars](https://img.shields.io/github/stars/RanitManik/Gemini-Clone?style=default) 13 | ![Vercel Deploy Status](https://deploy-badge.vercel.app/vercel/Gemini-Clone) 14 | ![Wakatime](https://wakatime.com/badge/github/RanitManik/Gemini-Clone.svg) 15 | 16 |
17 | 18 | ## 🌟 What is Gemini Clone? 19 | 20 | **Gemini Clone** is a simple and clean chatbot web app built using **React**. It connects to the **Google Gemini API** to provide AI-powered answers — just like Google's real Gemini AI. 21 | 22 | This project is perfect for learning how to work with APIs, build chat interfaces, and create React projects. 23 | 24 | --- 25 | 26 | ## 📚 Table of Contents 27 | 28 | * [Overview](#overview) 29 | * [Features](#features) 30 | * [Getting Started](#getting-started) 31 | * [How to Use](#how-to-use) 32 | * [Contribute](#contribute) 33 | * [License](#license) 34 | * [Thanks](#thanks) 35 | 36 | --- 37 | 38 | ## 🧠 Overview 39 | 40 | This web app lets you chat with an AI powered by the **Google Gemini API**. It mimics how the real Gemini chatbot works and responds in real time. 41 | 42 | Whether you're new to coding or just curious about how to build your own AI chatbot, this is a great place to start! 43 | 44 | --- 45 | 46 | ## ✨ Features 47 | 48 | ### 🔹 Core Features 49 | 50 | * **Chat Interface** – A clean and responsive design that works on any screen. 51 | * **Typing Animation** – The bot types responses just like a human would. 52 | * **AI Integration** – Connects directly to the Google Gemini API. 53 | 54 | ### 🔹 Nice-to-Have Features 55 | 56 | * **Built with React** – Uses modern, component-based React code. 57 | * **Custom Styling** – Stylish and beginner-friendly UI. 58 | 59 | ### 🔮 Future Ideas 60 | 61 | * Save previous chats (conversation history) 62 | * Support emojis and avatars 63 | * Add extra tools like image search, language translation, and more! 64 | 65 | --- 66 | 67 | ## ⚙️ Getting Started 68 | 69 | Follow these steps to set it up on your own computer: 70 | 71 | 1. **Clone the project:** 72 | 73 | ```bash 74 | git clone https://github.com/RanitManik/Gemini-Clone.git 75 | ``` 76 | 77 | 2. **Move into the folder:** 78 | 79 | ```bash 80 | cd Gemini-Clone 81 | ``` 82 | 83 | 3. **Install all the required packages:** 84 | 85 | ```bash 86 | npm install 87 | ``` 88 | 89 | 4. **Set up your API key:** 90 | 91 | * Create a file named `.env.local` in the main folder. 92 | * Add this line with your Gemini API key: 93 | 94 | ```env 95 | GEMINI_API_KEY="YOUR_GEMINI_API_KEY" 96 | ``` 97 | 98 | 5. **Run the app:** 99 | 100 | ```bash 101 | vite 102 | ``` 103 | 104 | 6. **Open in your browser:** 105 | 106 | Go to [http://localhost:5173](http://localhost:5173) 107 | 108 | --- 109 | 110 | ## 💬 How to Use 111 | 112 | Once the app is running: 113 | 114 | * Type your question or message in the input box. 115 | * The Gemini AI will respond in a conversational style. 116 | * You can keep chatting and explore different responses. 117 | 118 | --- 119 | 120 | ## 🤝 Contribute 121 | 122 | Want to help make this better? Great! 123 | 124 | 1. Fork this repo 125 | 126 | 2. Create a new branch: 127 | 128 | ```bash 129 | git checkout -b your-feature-name 130 | ``` 131 | 132 | 3. Make your changes and commit: 133 | 134 | ```bash 135 | git commit -m "Add your message here" 136 | ``` 137 | 138 | 4. Push your branch: 139 | 140 | ```bash 141 | git push origin your-feature-name 142 | ``` 143 | 144 | 5. Open a pull request with a short description of what you did. 145 | 146 | --- 147 | 148 | ## 📄 License 149 | 150 | This project is open-source and available under the **MIT License**. 151 | See the [LICENSE](LICENSE) file for more info. 152 | 153 | --- 154 | 155 | ## 🙌 Thanks 156 | 157 | * **[GreatStack](https://www.youtube.com/@GreatStackDev)** for their awesome [Gemini Clone tutorial](https://youtu.be/0yboGn8errU?feature=shared). 158 | * **Google** for providing the Gemini API. 159 | * **Vercel** for free hosting that made this live deployment easy. 160 | * And a big thank you to the **open-source community**! 💖 161 | 162 | --- 163 | 164 |

Thanks for checking out Gemini Clone! Happy coding! 🚀

165 | -------------------------------------------------------------------------------- /src/components/Main/Main.jsx: -------------------------------------------------------------------------------- 1 | import React, {useContext, useEffect, useRef, useState} from 'react'; 2 | import './Main.css'; 3 | import {assets} from "../../assets/assets.js"; 4 | import {Context} from "../../context/Context.jsx"; 5 | 6 | const Main = () => { 7 | const {onSent, recentPrompt, showResult, loading, resultData, setInput, input} = useContext(Context); 8 | const resultRef = useRef(null); 9 | const [rows, setRows] = useState(1); 10 | 11 | useEffect(() => { 12 | const updateRows = () => { 13 | if (window.innerWidth <= 600) { 14 | setRows(2); 15 | } else { 16 | setRows(1); 17 | } 18 | }; 19 | 20 | updateRows(); 21 | window.addEventListener('resize', updateRows); 22 | return () => window.removeEventListener('resize', updateRows); 23 | }, []); 24 | 25 | useEffect(() => { 26 | if (resultRef.current) { 27 | resultRef.current.scrollTop = resultRef.current.scrollHeight; 28 | } 29 | }, [resultData]); 30 | 31 | return ( 32 |
33 | 37 |
38 | 39 | {!showResult 40 | ? <> 41 |
42 |

Hello, Dev

43 |

How can I help you today?

44 |
45 |
46 |
setInput("Suggest beautiful places to see on an upcoming road trip")}> 48 |

Suggest beautiful places to see on an upcoming road trip

49 | 50 |
51 |
setInput("Briefly summarize this concept: urban planning")}> 53 |

Briefly summarize this concept: urban planning

54 | 55 |
56 |
setInput("Brainstorm team bonding activities for our work retreat")}> 58 |

Brainstorm team bonding activities for our work retreat

59 | 60 |
61 |
setInput("Tell me about React js and React native")}> 62 |

Tell me about React js and React native

63 | 64 |
65 |
66 | 67 | : 68 |
69 |
70 | 71 |

{recentPrompt}

72 |
73 |
74 | 75 | {loading ? 76 |
77 |
78 |
79 |
80 |
81 | : 82 |

83 | } 84 |
85 |
86 | } 87 |
88 |
89 |