A chat interface powered by Hugging Face's API router, built with React, TypeScript, shadcn/ui, Tailwind CSS v4, and Express.
- 💬 Real-time chat with AI models via Hugging Face
- 🎨 Clean light UI with shadcn/ui components
- 📝 Markdown rendering (tables, code blocks, bold, etc.)
- ⌨️ Send with Enter, new line with Shift+Enter
- 🔒 API key stays secure on the server
- 🧹 Clear conversation history
| Layer | Technology |
|---|---|
| Frontend | React 19 + TypeScript + Vite |
| UI | shadcn/ui + Tailwind CSS v4 |
| Markdown | react-markdown + remark-gfm |
| Backend | Express 5 |
| AI | Hugging Face InferenceClient + Router | | Icons | Lucide React |
- Node.js 18 or higher
- A Hugging Face API token
git clone https://github.com/JustinDouglas16/ai-chat-app-demo.git
cd ai-chat-app-demonpm installCreate a .env file in the root directory:
HF_TOKEN=hf_your_token_here
DATABASE_URL=postgres://postgres:YOUR_PASSWORD@localhost:5432/YOUR_DB_NAME
npm run db:generate
npm run db:migratenpm run devThis starts both the Vite dev server (port 5173) and the Express API (port 3001) concurrently.
Open http://localhost:5173 in your browser.
npm run build
npm startThis builds the React frontend into dist/ and starts the Express
server which serves both the API and the static files.
The server now supports lightweight JSON-based RAG routing. If a user question matches an entry in server/data/unasat_rag.json, the app injects that matched Q/A as context and asks the model to produce a polished final answer. If no match is found, chat behaves normally.
You can extend the file with records in this shape:
[
{
"id": "unasat_001",
"question": "Hoe weet ik in welk lokaal ik moet zijn?",
"answer": "Het lokaal wordt vermeld op het informatiebord bij de grote ingang en in uw rooster op SharePoint.",
"combined_text": "Vraag: ... Antwoord: ...",
"metadata": {}
}
]hf-chat/
├── public/
├── server/
│ └── index.ts # Express API server
├── src/
│ ├── components/
│ │ ├── chat/
│ │ │ ├── ChatContainer.tsx
│ │ │ ├── ChatInput.tsx
│ │ │ └── ChatMessage.tsx
│ │ └── ui/ # shadcn/ui components
│ ├── hooks/
│ │ └── useChat.ts # Chat state management
│ ├── lib/
│ │ ├── types.ts
│ │ └── utils.ts
│ ├── App.tsx
│ ├── main.tsx
│ └── index.css
├── .env # API keys (not committed)
├── .gitignore
├── components.json # shadcn config
├── package.json
├── tsconfig.json
└── vite.config.ts
| Command | Description |
|---|---|
npm run dev |
Start both frontend and backend in dev mode |
npm run build |
Build the frontend for production |
npm start |
Start the production server |
npm run lint |
Run ESLint |
To use a different model, update the model field in
server/index.ts:
const completion = await client.chat.completions.create({
model: "openai/gpt-oss-120b:groq", // Change this
messages,
});Browse available models at huggingface.co/models.
MIT