A full-stack AI chat application built with Next.js 16, featuring real-time streaming, voice input, image generation, and image editing — all in a polished dark/light UI.
| Layer | Choice |
|---|---|
| Framework | Next.js 16 (App Router) |
| Auth | Clerk |
| Database | PostgreSQL + Prisma |
| AI Chat | OpenRouter API |
| Image Gen | HuggingFace Inference API / Pollinations.ai |
| STT | Groq Whisper |
| Storage | Cloudflare R2 (or local fallback) |
| Rate Limiting | Upstash Redis + @upstash/ratelimit |
| UI | Tailwind CSS v4 + shadcn/ui (base-ui) |
| State | Zustand + TanStack Query |
| Animations | Framer Motion |
Zero-config mode: Vizzy Chat runs without any paid API keys. LLM chat and image generation both fall back to free Pollinations.ai endpoints automatically. You only need Clerk + a database to get started.
git clone https://github.com/Damanpreet1313/Vizzy-chat.git
cd Vizzy-chat
npm install
Copy .env.example to .env.local and fill in the values:
cp .env.example .env.local
See Environment Variables below for details on each key.
npx prisma db push
# Chat + UI only
npm run dev
# Chat + image worker (for BullMQ queue)
npm run dev:all
Open http://localhost:3000.
To also run the BullMQ image worker:
npm run dev:all
Create a .env.local file in the project root with the following:
# ── Database ──────────────────────────────────────────────────
# PostgreSQL connection string (e.g. from Neon, Supabase, or local)
DATABASE_URL="postgresql://user:password@host:5432/vizzy"
# ── Clerk Auth ────────────────────────────────────────────────
# Get these from https://dashboard.clerk.com
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="pk_test_..."
CLERK_SECRET_KEY="sk_test_..."
CLERK_WEBHOOK_SECRET="whsec_..." # From Clerk → Webhooks
# Clerk redirect URLs (leave as-is for local dev)
NEXT_PUBLIC_CLERK_SIGN_IN_URL="/sign-in"
NEXT_PUBLIC_CLERK_SIGN_UP_URL="/sign-up"
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL="/"
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL="/"
# ── OpenRouter (AI Chat) ──────────────────────────────────────
# Get your key from https://openrouter.ai/keys
OPENROUTER_API_KEY="sk-or-..."
# ── Groq (Speech-to-Text) ─────────────────────────────────────
# Get your key from https://console.groq.com
GROQ_API_KEY="gsk_..."
# ── HuggingFace (Image Generation) ───────────────────────────
# Get your token from https://huggingface.co/settings/tokens
# Optional — falls back to Pollinations.ai (free, no key needed)
HUGGINGFACE_API_TOKEN="hf_..."
# ── Cloudflare R2 (File Storage) ─────────────────────────────
# Create a bucket at https://dash.cloudflare.com → R2
# Leave blank to use local public/uploads fallback
R2_ACCOUNT_ID=""
R2_ACCESS_KEY_ID=""
R2_SECRET_ACCESS_KEY=""
R2_BUCKET_NAME=""
R2_PUBLIC_URL="" # e.g. https://pub-xxx.r2.dev
# ── Upstash Redis (Rate Limiting) ─────────────────────────────
# Create a database at https://console.upstash.com
UPSTASH_REDIS_REST_URL="https://xxx.upstash.io"
UPSTASH_REDIS_REST_TOKEN="AXxx..."
# Used by BullMQ worker (ioredis format)
UPSTASH_REDIS_URL="rediss://default:xxx@xxx.upstash.io:6379"
| Key | Required | Notes |
|---|---|---|
DATABASE_URL |
✅ Yes | Any PostgreSQL provider works |
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY |
✅ Yes | |
CLERK_SECRET_KEY |
✅ Yes | |
CLERK_WEBHOOK_SECRET |
✅ Yes | Set up webhook in Clerk dashboard |
OPENROUTER_API_KEY |
✅ Yes | Powers the chat |
GROQ_API_KEY |
⚠️ Optional | Voice input won’t work without it |
HUGGINGFACE_API_TOKEN |
⚠️ Optional | Falls back to Pollinations.ai |
R2_* variables |
⚠️ Optional | Falls back to local public/uploads |
UPSTASH_REDIS_REST_URL/TOKEN |
✅ Yes | Required for rate limiting |
UPSTASH_REDIS_URL |
⚠️ Optional | Only needed for the BullMQ worker |
npm run dev # Start Next.js dev server
npm run build # Production build
npm run start # Start production server
npm run lint # ESLint
npm run db:push # Push Prisma schema to database
npm run worker # Start BullMQ image worker (separate process)
npm run dev:all # Run dev server + worker concurrently
src/
├── app/
│ ├── (auth)/ # Sign-in / sign-up pages
│ ├── api/
│ │ ├── chat/ # Streaming chat endpoint
│ │ ├── conversations/
│ │ ├── images/ # Generate + status endpoints
│ │ ├── stt/ # Speech-to-text
│ │ ├── upload/ # Image upload
│ │ └── webhooks/ # Clerk webhook handler
│ ├── globals.css
│ ├── layout.tsx
│ └── page.tsx
├── components/
│ ├── chat/ # ChatInterface, MessageBubble, TypingIndicator
│ ├── images/ # DropzoneUpload, ImageOperationsModal, ImageCompare
│ ├── sidebar/ # Sidebar with mobile Sheet drawer
│ ├── ui/ # shadcn/ui components
│ └── voice/ # VoiceRecorder
├── hooks/ # useImageGeneration
├── lib/
│ ├── clients/ # gemini, groq, huggingface, openrouter, r2
│ ├── db.ts # Prisma client
│ ├── queue.ts # BullMQ queue
│ └── validators.ts # Zod schemas
├── store/ # Zustand stores
└── worker/ # BullMQ image worker
The easiest way to deploy is Vercel:
Note: The BullMQ worker (
npm run worker) is a long-running Node process and cannot run on Vercel’s serverless functions. For production image processing queues, run it on a separate server (Railway, Fly.io, a VPS, etc.) or replace BullMQ with a serverless-compatible queue.
After deploying, set up the Clerk webhook so user records sync to your database:
MIT