A complete production-level ChatGPT clone featuring:
- β‘ Real-time AI chat (Socket.io)
- π Web Scraping (Cheerio + Puppeteer)
- π§ Hybrid Memory (STM + LTM via Pinecone)
- π Auth with JWT + Cookies
- β» Auto WebSocket reconnect + polling fallback
- π¨ ChatGPT-level UI/UX (almost identical)
- π¦ Parallel optimized LLM pipeline (Promise.all)
- π§΅ Hidden prompt engineering (avoids Gemini system-role limitations)
- Static websites β Cheerio
- Dynamic JS-rendered β Puppeteer
- React + Vite
- TailwindCSS
- Axios
- Socket.io-client
- Node.js
- Express.js
- Socket.io
- MongoDB + Mongoose
- Pinecone Vector DB
- Gemini 2.0 Flash API
- Cheerio
- Puppeteer
- JWT
- Cookie-parser
- CORS
| Purpose | Package |
|---|---|
| Real-time chat | socket.io |
| Frontend socket | socket.io-client |
| Static scraping | cheerio |
| JS-rendered scraping | puppeteer |
| Vector memory | @pinecone-database/pinecone |
| AI model | @google/genai |
| Auth | jsonwebtoken, bcryptjs |
| Cookies | cookie-parser |
| Backend | express, cors |
| DB | mongoose |
- Last 10 messages of the current chat
- Controls conversation flow
- Stored in MongoDB
- Stored in Pinecone
- Every user message & bot response becomes a vector
- On each new message:
topMatches = pinecone.query(vectors) - Returned top 3 relevant memories
Hidden Context Merging (Gemini-safe)
Gemini does NOT allow system-role messages.
So we merge STM + LTM + scraped content inside a hidden user role prompt:
{ role: "user", text: hiddenContext + "User asked: " + userMessage }
The model sees memory + scraped content.
User sees only the answer.
axios.get(url)
cheerio.load(html)
extract & clean text
puppeteer.launch()
page.goto(url, waitUntil:"networkidle0")
extract page content
Automatically selects Cheerio β Puppeteer fallback.
Used throughout the backend:
const [message, vectors] = await Promise.all([
messageModel.create(...),
aiService.generateVector(...)
])DB + vector embedding run simultaneously, reducing latency by 40β60%.
Render sometimes kills WebSocket connections.
Solution:
transports: ["websocket", "polling"]
reconnection: true
reconnectionAttempts: Infinity
Flawless stability.
- User stays logged in after refresh
httpOnly + secure + sameSite=none- Accessible via both REST & Socket.io
1. User logs in β HTTP cookie set
2. React loads chats via REST (cookie auto-sent)
3. User sends message β socket.emit("ai-message")
4. Backend:
a) Detect URL
b) Scrape (Cheerio/Puppeteer)
c) Save message
d) Generate vector
e) Store vector in Pinecone
f) Query STM + LTM
g) Merge into hidden prompt
h) Generate response using Gemini
i) Save response + vector
5. Backend β emits "ai-response"
6. Frontend updates in real-time
- Create chat
- Load all chats
- Load messages
- Delete chat
- Auto-select next chat
- Prevent sending messages if no chat exists
- Fully responsive
- ChatGPT-like sidebar
- New chat popup
- Floating AI shimmer loading bubble
- Dark theme
- Fixed input bar
- Environment variables:
MONGO_URI=
JWT_SECRET=
GEMINI_API_KEY=
PINECONE_API_KEY=
- Build command:
npm install - Start command:
node server.js
Update Axios base URL:
https://your-backend.onrender.com
If you like this project, β the repository.