├── app ├── favicon.ico ├── globals.css ├── layout.js ├── api │ └── clerk │ │ └── route.js └── page.jsx ├── assets ├── favicon.ico ├── qrcode.png ├── search_icon.svg ├── delete_icon.svg ├── new_icon.svg ├── menu_icon.svg ├── profile_icon.svg ├── three_dots.svg ├── assets.js ├── phone_icon.svg ├── arrow_icon.svg ├── arrow_icon_dull.svg ├── phone_icon_dull.svg ├── pencil_icon.svg ├── pin_icon.svg ├── like_icon.svg ├── sidebar_close_icon.svg ├── logo_icon.svg ├── deepthink_icon.svg ├── sidebar_icon.svg ├── chat_icon.svg ├── chat_icon_dull.svg ├── dislike_icon.svg ├── copy_icon.svg ├── logo_text.svg └── regenerate_icon.svg ├── jsconfig.json ├── next.config.mjs ├── postcss.config.mjs ├── public ├── vercel.svg ├── window.svg ├── file.svg ├── globe.svg └── next.svg ├── eslint.config.mjs ├── models └── User.js ├── middleware.ts ├── context └── AppContext.jsx ├── config └── db.js ├── .gitignore ├── package.json ├── README.md └── components ├── ChatLabel.jsx ├── PromptBox.jsx ├── Message.jsx └── Sidebar.jsx /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obito8010/DeepSeek-Clone/HEAD/app/favicon.ico -------------------------------------------------------------------------------- /assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obito8010/DeepSeek-Clone/HEAD/assets/favicon.ico -------------------------------------------------------------------------------- /assets/qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obito8010/DeepSeek-Clone/HEAD/assets/qrcode.png -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./*"] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | const config = { 2 | plugins: ["@tailwindcss/postcss"], 3 | }; 4 | 5 | export default config; 6 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/globals.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss"; 2 | 3 | @theme{ 4 | --color-primary: #4d5bfe; 5 | } 6 | 7 | html{ 8 | @apply scroll-smooth; 9 | } 10 | 11 | ::-webkit-scrollbar{ 12 | display: none; 13 | } -------------------------------------------------------------------------------- /public/window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { dirname } from "path"; 2 | import { fileURLToPath } from "url"; 3 | import { FlatCompat } from "@eslint/eslintrc"; 4 | 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = dirname(__filename); 7 | 8 | const compat = new FlatCompat({ 9 | baseDirectory: __dirname, 10 | }); 11 | 12 | const eslintConfig = [...compat.extends("next/core-web-vitals")]; 13 | 14 | export default eslintConfig; 15 | -------------------------------------------------------------------------------- /models/User.js: -------------------------------------------------------------------------------- 1 | import mongoose from "mongoose"; 2 | 3 | const UserSchema = new mongoose.Schema( 4 | { 5 | _id: {type:String, required: true}, 6 | name: {type:String, required: true}, 7 | email: {type:String, required: true}, 8 | image: {type:String, required: false} 9 | }, 10 | {timestamps : true} 11 | ); 12 | const User = mongoose.models.User || mongoose.model("User",UserSchema) 13 | export default User; -------------------------------------------------------------------------------- /middleware.ts: -------------------------------------------------------------------------------- 1 | import { clerkMiddleware } from '@clerk/nextjs/server'; 2 | 3 | export default clerkMiddleware(); 4 | 5 | export const config = { 6 | matcher: [ 7 | // Skip Next.js internals and all static files, unless found in search params 8 | '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)', 9 | // Always run for API routes 10 | '/(api|trpc)(.*)', 11 | ], 12 | }; -------------------------------------------------------------------------------- /context/AppContext.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { useUser } from "@clerk/nextjs"; 3 | import { createContext, useContext } from "react"; 4 | 5 | export const AppContext = createContext(); 6 | 7 | export const useAppContext = () => { 8 | const context = useContext(AppContext); 9 | return useContext(AppContext) 10 | } 11 | 12 | export const AppContextProvider = ({ children }) => { 13 | const {user} = useUser() 14 | const value ={ 15 | user 16 | } 17 | return {children} 18 | } -------------------------------------------------------------------------------- /config/db.js: -------------------------------------------------------------------------------- 1 | import mongoose from "mongoose"; 2 | 3 | let cached = globalThis.mongoose || {conn: null, promise:null}; 4 | 5 | export default async function connectDB(){ 6 | if(cached.conn) return cached.conn; 7 | if(!cached.promise){ 8 | cached.promise = (await mongoose.connect(process.env.MONGODB_URI)).then((mongoose)=>mongoose); 9 | } 10 | try{ 11 | CacheHandler.conn = await cached.promise; 12 | }catch(errpr){ 13 | console.error("Error connecting to mongodb:", error); 14 | } 15 | return cached.conn 16 | } -------------------------------------------------------------------------------- /assets/search_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.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.* 7 | .yarn/* 8 | !.yarn/patches 9 | !.yarn/plugins 10 | !.yarn/releases 11 | !.yarn/versions 12 | 13 | # testing 14 | /coverage 15 | 16 | # next.js 17 | /.next/ 18 | /out/ 19 | 20 | # production 21 | /build 22 | 23 | # misc 24 | .DS_Store 25 | *.pem 26 | 27 | # debug 28 | npm-debug.log* 29 | yarn-debug.log* 30 | yarn-error.log* 31 | .pnpm-debug.log* 32 | 33 | # env files (can opt-in for committing if needed) 34 | .env* 35 | 36 | # vercel 37 | .vercel 38 | 39 | # typescript 40 | *.tsbuildinfo 41 | next-env.d.ts 42 | -------------------------------------------------------------------------------- /assets/delete_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /assets/new_icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/menu_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /assets/profile_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/layout.js: -------------------------------------------------------------------------------- 1 | import { Inter } from "next/font/google"; 2 | import "./globals.css"; 3 | import { ClerkProvider } from "@clerk/nextjs"; 4 | import { AppContextProvider } from "@/context/AppContext"; 5 | 6 | const inter = Inter({ 7 | variable: "--font-inter", 8 | subsets: ["latin"], 9 | }); 10 | 11 | export const metadata = { 12 | title: "DeepSeek", 13 | description: "Full Stack Project Created by Chinmay Saseendran", 14 | }; 15 | 16 | export default function RootLayout({ children }) { 17 | return ( 18 | 19 | 20 | 21 | 24 | {children} 25 | 26 | 27 | 28 | 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deepseek", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev --turbopack", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@clerk/nextjs": "^6.22.0", 13 | "axios": "^1.10.0", 14 | "mongoose": "^8.16.0", 15 | "next": "15.3.1", 16 | "openai": "^5.5.1", 17 | "prismjs": "^1.30.0", 18 | "react": "^19.0.0", 19 | "react-dom": "^19.0.0", 20 | "react-hot-toast": "^2.5.2", 21 | "react-markdown": "^10.1.0", 22 | "svix": "^1.67.0" 23 | }, 24 | "devDependencies": { 25 | "@eslint/eslintrc": "^3", 26 | "@tailwindcss/postcss": "^4", 27 | "eslint": "^9", 28 | "eslint-config-next": "15.3.1", 29 | "tailwindcss": "^4" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /public/globe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/three_dots.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #🔍 DeepSeek Clone – Full-Stack AI Search Engine 2 | This project is a full-stack clone of DeepSeek, built by following the tutorial DeepSeek AI Clone - Full Stack Next.js + AI App. It mimics the functionality and interface of an AI-powered semantic search engine, combining the power of modern web technologies with OpenAI’s capabilities. 3 | 4 | 🚀 Features 5 | 🌐 Full-stack application using Next.js 14 (App Router) and TypeScript 6 | 🎨 Elegant UI with Tailwind CSS 7 | 🧠 AI-powered search with OpenAI API 8 | 🔍 Semantic document search using Vector Embeddings 9 | 🗃️ Upload and index PDF documents for context-aware searching 10 | ⚡ Real-time response streaming (using openai-streams) 11 | 12 | 🛠️ Tech Stack 13 | Frontend: Next.js 14, TypeScript, Tailwind CSS 14 | Backend: OpenAI API, Supabase, Pinecone / Vercel KV 15 | Embeddings: OpenAI Embedding API 16 | Authentication: Clerk (or replace with Auth.js/Auth0 if preferred) 17 | 18 | 📁 Project Status 19 | ✅ In Progress – Actively building and refining features 20 | 21 | #📄 How to Use 22 | 1.Clone the repo 23 | 2.Set up environment variables (.env.local) 24 | 3.Run the dev server with npm run dev 25 | 4.Start uploading PDFs and querying them with smart AI search! 26 | 27 | -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /components/ChatLabel.jsx: -------------------------------------------------------------------------------- 1 | import { assets } from "@/assets/assets" 2 | import Image from "next/image" 3 | import React, { useState } from 'react'; 4 | const ChatLabel = ({openMenu, setOpenMenu}) => { 5 | return ( 6 |
7 |

Chat Name Here

8 |
9 | 10 |
11 |
12 | 13 |

Rename

14 |
15 |
16 | 17 |

Delete

18 |
19 |
20 |
21 |
22 | ) 23 | } 24 | export default ChatLabel -------------------------------------------------------------------------------- /app/api/clerk/route.js: -------------------------------------------------------------------------------- 1 | import {webhook} from "svix"; 2 | import connection from "@/config/db"; 3 | import User from "@/models/User"; 4 | import { headers } from "next/headers"; 5 | import { NextRequest } from "next/server"; 6 | 7 | export async function POST(req){ 8 | const wh = new webhook(process.env.SIGNING_SECRET) 9 | const headerpayload = await headers() 10 | const svixHeaders = { 11 | "svix-id": headerpayload.get("svix-id"), 12 | "svix-timestamp": headerpayload.get("svix-timestamp"), 13 | "svix-signature": headerpayload.get("svix-signature"), 14 | }; 15 | // get the payload 16 | 17 | const payload = await req.json(); 18 | const body = JSON.stringify(payload); 19 | const {data, type} = wh.verify(body, svoxHeaders) 20 | 21 | //prepare user data to be saved in the database 22 | 23 | const userData = { 24 | _id: data.id, 25 | email: data.email_addresses[0].email_address, 26 | name: `${data.first_name} ${data.last_name}`, 27 | image:data.image_url, 28 | }; 29 | await connectionDB(); 30 | 31 | switch(type){ 32 | case 'user.created': 33 | await User.create(userData) 34 | break; 35 | case 'user.updated': 36 | await User.findByIdAndUpdate(data.id, userData) 37 | break; 38 | case 'user.deleted': 39 | await User.findByIdAndDelete(data.id) 40 | break; 41 | default: 42 | break; 43 | } 44 | return NextRequest.json({message:"Event Recived"}); 45 | } -------------------------------------------------------------------------------- /assets/assets.js: -------------------------------------------------------------------------------- 1 | import arrow_icon from "./arrow_icon.svg"; 2 | import arrow_icon_dull from "./arrow_icon_dull.svg"; 3 | import logo_text from "./logo_text.svg"; 4 | import logo_icon from "./logo_icon.svg"; 5 | import menu_icon from "./menu_icon.svg"; 6 | import search_icon from "./search_icon.svg"; 7 | import profile_icon from "./profile_icon.svg"; 8 | import copy_icon from "./copy_icon.svg"; 9 | import deepthink_icon from "./deepthink_icon.svg"; 10 | import chat_icon from "./chat_icon.svg"; 11 | import dislike_icon from "./dislike_icon.svg"; 12 | import like_icon from "./like_icon.svg"; 13 | import phone_icon from "./phone_icon.svg"; 14 | import phone_icon_dull from "./phone_icon_dull.svg"; 15 | import pencil_icon from "./pencil_icon.svg"; 16 | import delete_icon from "./delete_icon.svg"; 17 | import pin_icon from "./pin_icon.svg"; 18 | import regenerate_icon from "./regenerate_icon.svg"; 19 | import sidebar_icon from "./sidebar_icon.svg"; 20 | import sidebar_close_icon from "./sidebar_close_icon.svg"; 21 | import chat_icon_dull from "./chat_icon_dull.svg"; 22 | import qrcode from "./qrcode.png"; 23 | import three_dots from "./three_dots.svg"; 24 | import new_icon from "./new_icon.svg"; 25 | 26 | export const assets = { 27 | arrow_icon, 28 | arrow_icon_dull, 29 | logo_text, 30 | logo_icon, 31 | menu_icon, 32 | search_icon, 33 | profile_icon, 34 | copy_icon, 35 | deepthink_icon, 36 | chat_icon, 37 | dislike_icon, 38 | like_icon, 39 | phone_icon, 40 | phone_icon_dull, 41 | pencil_icon, 42 | delete_icon, 43 | pin_icon, 44 | regenerate_icon, 45 | sidebar_icon, 46 | sidebar_close_icon, 47 | chat_icon_dull, 48 | qrcode, 49 | three_dots, 50 | new_icon, 51 | }; -------------------------------------------------------------------------------- /assets/phone_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/arrow_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /assets/arrow_icon_dull.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/page.jsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { assets } from "@/assets/assets"; 3 | import PromptBox from "@/components/PromptBox"; 4 | import Sidebar from "@/components/Sidebar"; 5 | import Message from "@/components/Message"; 6 | import Image from "next/image"; 7 | import { useState } from "react"; 8 | 9 | export default function Home() { 10 | 11 | const[expand , setExpand] = useState(false); 12 | const[messages , setMessages] = useState([]); 13 | const[isLoading , setIsLoading] = useState(false); 14 | 15 | return ( 16 |
17 |
18 | {/* --sidebar-- */} 19 | 20 |
21 |
22 | (expand ? setExpand(false):setExpand(true))} 23 | className="rotate-180" src={assets.menu_icon} alt=""/> 24 | 25 |
26 | 27 | {messages.length ===0 ? ( 28 | <> 29 |
30 | 31 |

Hi, i am deepseek

32 |
33 |

How can i help you today

34 | 35 | ): 36 | (
) 37 | } 38 | 39 | {/* --prompt box-- */} 40 | 41 |

Ai generated , for reference only

42 | 43 | 44 |
45 |
46 |
47 | ); 48 | } 49 | -------------------------------------------------------------------------------- /assets/phone_icon_dull.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /components/PromptBox.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import Image from "next/image"; 3 | import { assets } from "@/assets/assets"; 4 | 5 | const PromptBox = ({setIsLoading,isLoading}) => { 6 | 7 | const[prompt,setPrompt] = useState(''); 8 | 9 | return( 10 |
12 |