Skip to content

Commit d3d0813

Browse files
committed
feat: health check for worker
1 parent 80ea1f2 commit d3d0813

15 files changed

Lines changed: 68 additions & 50 deletions

File tree

.github/workflows/docker-build-manual.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Manual Build, Push & Deploy Docker Images
1+
name: manual-ci
22

33
on:
44
workflow_dispatch:

.github/workflows/docker-build-push.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Build, Push & Deploy Docker Images
1+
name: ci
22

33
on:
44
push:

README.md

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
# Sleek AI
22

3-
A full-stack AI chat application featuring real-time messaging, file ingestion, and vector search capabilities. Built with modern web technologies for performance and scalability.
3+
![Sleek AI Preview](./assets/preview.webp)
44

5-
## Features
5+
[![ci](https://github.com/sunjay-dev/sleek-ai/actions/workflows/docker-build-push.yaml/badge.svg)](https://github.com/sunjay-dev/sleek-ai/actions/workflows/docker-build-push.yaml)
6+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7+
[![Last Commit](https://img.shields.io/github/last-commit/sunjay-dev/sleek-ai)](https://github.com/sunjay-dev/sleek-ai/commits/main)
8+
9+
A full-stack AI chat application featuring real-time messaging, file ingestion, and vector search capabilities. Optimized for speed, reliability, and seamless AI interactions.
610

11+
## Features
712
- **AI Chat Interface**: Interactive chat with AI models.
813
- **File Ingestion**: Upload and process documents (PDF, Docx, TXT) for context-aware responses.
914
- **Vector Search**: Semantic search powered by Pinecone and Google Gemini embeddings.
@@ -13,7 +18,11 @@ A full-stack AI chat application featuring real-time messaging, file ingestion,
1318

1419
## Tech Stack
1520

16-
![React](https://img.shields.io/badge/React-20232A?style=for-the-badge&logo=react&logoColor=61DAFB) ![Tailwind CSS](https://img.shields.io/badge/Tailwind_CSS-38B2AC?style=for-the-badge&logo=tailwind-css&logoColor=white) ![Lucide-React](https://img.shields.io/badge/Lucide--React-000000.svg?style=for-the-badge&logo=lucide&logoColor=white) ![Clerk](https://img.shields.io/badge/Clerk-6C47FF?style=for-the-badge&logo=clerk&logoColor=white) ![Hono](https://img.shields.io/badge/Hono-ff5018?style=for-the-badge&logo=hono&logoColor=white) ![Bun](https://img.shields.io/badge/Bun-000000?style=for-the-badge&logo=bun&logoColor=white) ![PostgreSQL](https://img.shields.io/badge/PostgreSQL-316192?style=for-the-badge&logo=postgresql&logoColor=white) ![Prisma](https://img.shields.io/badge/Prisma-3982CE?style=for-the-badge&logo=Prisma&logoColor=white) ![Redis](https://img.shields.io/badge/redis-%23DD0031.svg?&style=for-the-badge&logo=redis&logoColor=white) ![BullMQ](https://img.shields.io/badge/BullMQ-000000?style=for-the-badge&logo=bullmq&logoColor=white) ![Cloudinary](https://img.shields.io/badge/Cloudinary-3448C5?style=for-the-badge&logo=cloudinary&logoColor=white) ![PNPM](https://img.shields.io/badge/pnpm-%234a4a4a.svg?style=for-the-badge&logo=pnpm&logoColor=f69220) ![Zod](https://img.shields.io/badge/Zod-7C3AED.svg?style=for-the-badge&logo=zod&logoColor=white) ![Pino](https://img.shields.io/badge/Pino-4B9E5F.svg?style=for-the-badge&logo=pino&logoColor=white) ![LangChain](https://img.shields.io/badge/LangChain.js-1C3C3C?style=for-the-badge&logo=langchain&logoColor=white) ![Pinecone](https://img.shields.io/badge/Pinecone-2C3E50?style=for-the-badge&logo=pinecone&logoColor=white) ![Docker](https://img.shields.io/badge/Docker-2496ED?style=for-the-badge&logo=docker&logoColor=white) ![Grafana](https://img.shields.io/badge/Grafana-%23F46800.svg?style=for-the-badge&logo=grafana&logoColor=white) ![Prometheus](https://img.shields.io/badge/Prometheus-%23E6522C.svg?style=for-the-badge&logo=prometheus&logoColor=white)
21+
![React](https://img.shields.io/badge/React-20232A?style=for-the-badge&logo=react&logoColor=61DAFB) ![Tailwind CSS](https://img.shields.io/badge/Tailwind_CSS-38B2AC?style=for-the-badge&logo=tailwind-css&logoColor=white) ![Lucide-React](https://img.shields.io/badge/Lucide--React-000000.svg?style=for-the-badge&logo=lucide&logoColor=white) ![Clerk](https://img.shields.io/badge/Clerk-6C47FF?style=for-the-badge&logo=clerk&logoColor=white) ![Hono](https://img.shields.io/badge/Hono-ff5018?style=for-the-badge&logo=hono&logoColor=white) ![Bun](https://img.shields.io/badge/Bun-000000?style=for-the-badge&logo=bun&logoColor=FBF0DF) ![PostgreSQL](https://img.shields.io/badge/PostgreSQL-316192?style=for-the-badge&logo=postgresql&logoColor=white) ![Prisma](https://img.shields.io/badge/Prisma-3982CE?style=for-the-badge&logo=Prisma&logoColor=white) ![Redis](https://img.shields.io/badge/redis-%23DD0031.svg?&style=for-the-badge&logo=redis&logoColor=white) ![BullMQ](https://img.shields.io/badge/BullMQ-E03E2F?style=for-the-badge&logo=bullmq&logoColor=white) ![Cloudinary](https://img.shields.io/badge/Cloudinary-3448C5?style=for-the-badge&logo=cloudinary&logoColor=white) ![PNPM](https://img.shields.io/badge/pnpm-%234a4a4a.svg?style=for-the-badge&logo=pnpm&logoColor=f69220) ![Zod](https://img.shields.io/badge/Zod-7C3AED.svg?style=for-the-badge&logo=zod&logoColor=white) ![Pino](https://img.shields.io/badge/Pino-4B9E5F.svg?style=for-the-badge&logo=pino&logoColor=white) ![LangChain](https://img.shields.io/badge/LangChain.js-1C3C3C?style=for-the-badge&logo=langchain&logoColor=white) ![Pinecone](https://img.shields.io/badge/Pinecone-2C3E50?style=for-the-badge&logo=pinecone&logoColor=white) ![Groq](https://img.shields.io/badge/Groq-F55036?style=for-the-badge&logo=groq&logoColor=white) ![Gemini](https://img.shields.io/badge/Gemini-1A73E8?style=for-the-badge&logo=google-gemini&logoColor=white) ![Docker](https://img.shields.io/badge/Docker-2496ED?style=for-the-badge&logo=docker&logoColor=white) ![Grafana](https://img.shields.io/badge/Grafana-%23F46800.svg?style=for-the-badge&logo=grafana&logoColor=white) ![Prometheus](https://img.shields.io/badge/Prometheus-%23E6522C.svg?style=for-the-badge&logo=prometheus&logoColor=white)
22+
23+
## Architecture
24+
25+
![Architecture Diagram](./assets/architecture_diagram.png)
1726

1827
## Prerequisites
1928

@@ -38,11 +47,10 @@ A full-stack AI chat application featuring real-time messaging, file ingestion,
3847

3948
3. **Environment Configuration**
4049

41-
Copy the `.env.example` files to `.env` in `backend`, `frontend`, and `worker` directories and fill in your secrets.
50+
Copy the `.env.example` files to `.env` in `backend` and `worker` directories and fill in your secrets.
4251

4352
```bash
4453
cp backend/.env.example backend/.env
45-
cp frontend/.env.example frontend/.env
4654
cp worker/.env.example worker/.env
4755
```
4856

@@ -65,6 +73,15 @@ A full-stack AI chat application featuring real-time messaging, file ingestion,
6573
```
6674
This will start the specialized dev scripts defined in the root `package.json`.
6775

76+
## Project Structure
77+
78+
This is a monorepo containing:
79+
80+
- **`frontend/`**: Vite-based React application with Tailwind CSS and Shadcn UI.
81+
- **`backend/`**: Hono.js API server handling chat logic, authentication, and job dispatching.
82+
- **`worker/`**: BullMQ-based background worker for processing file metadata and vector embeddings.
83+
- **`shared/`**: Shared TypeScript types and utility functions used across packages.
84+
6885
## Contribution
6986

7087
See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines on how to contribute to this project.

assets/architecture_diagram.png

178 KB
Loading

assets/preview.webp

324 KB
Loading

backend/src/controllers/message.controllers.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export async function handleUserMessageResponse(c: Context) {
2020
let finalQuery = query;
2121

2222
finalQuery += await handleImageExtraction(messageFiles, stream);
23+
if (!finalQuery.trim()) finalQuery = "Please summarize or describe the uploaded document.";
2324

2425
try {
2526
const [chat, preferences, memories] = await Promise.all([
@@ -78,7 +79,7 @@ export async function handleUserMessageResponse(c: Context) {
7879
include: { messages: { include: { messageFiles: true } } },
7980
});
8081

81-
scheduleMemoryExtraction(userId, query, memories);
82+
if (query.trim()) scheduleMemoryExtraction(userId, query, memories);
8283
} catch (error: any) {
8384
logger.error({
8485
message: "Streaming error",

backend/src/middlewares/validate.middlewares.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Context, Next } from "hono";
22
import { z, ZodError } from "@app/shared/src/index.js";
33
import { BadRequestError } from "../utils/appError.utils.js";
44

5-
export function validate(schema: z.ZodObject<any, any>) {
5+
export function validate(schema: z.ZodTypeAny) {
66
return async (c: Context, next: Next) => {
77
try {
88
const data = schema.parse(await c.req.json());

frontend/src/hooks/useMessage.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export default function useMessages({ moveChatToTop, setChats }: Props) {
3131
const justCreatedChatRef = useRef<string | null>(null);
3232

3333
const sendMessage = async (text: string, model: string, messageFiles?: UploadedFile[] | null, optimisticFiles?: UploadedFile[]) => {
34-
if (!text.trim()) return;
34+
if (!text.trim() && !messageFiles?.length) return;
3535

3636
const token = await getToken();
3737
if (!token) throw new Error("You must be logged in to send message.");
@@ -134,9 +134,9 @@ export default function useMessages({ moveChatToTop, setChats }: Props) {
134134
prev.map((m) =>
135135
m.id === assistantId
136136
? {
137-
...m,
138-
text: err.name === "AbortError" ? "Generation stopped." : err.message || "Something went wrong.",
139-
}
137+
...m,
138+
text: err.name === "AbortError" ? "Generation stopped." : err.message || "Something went wrong.",
139+
}
140140
: m,
141141
),
142142
);
@@ -156,7 +156,7 @@ export default function useMessages({ moveChatToTop, setChats }: Props) {
156156
"Content-Type": "application/json",
157157
Authorization: `Bearer ${token}`,
158158
},
159-
body: JSON.stringify({ query: text }),
159+
body: JSON.stringify({ query: text || "Shared a file" }),
160160
signal: controller.signal,
161161
});
162162

frontend/src/page/AuthPage.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export default function AuthPage() {
2828
<div className="relative z-10 flex min-h-screen w-full">
2929
<div className="hidden w-1/2 flex-col justify-between p-12 md:flex">
3030
<div className="flex items-center gap-2 font-semibold tracking-tighter text-xl">
31-
<img src="/logo.webp" alt="Sleek AI Logo" className="w-9 h-8" />
31+
<img src="/logo.webp" alt="Sleek AI Logo" className="w-10 h-8" />
3232
Sleek AI
3333
</div>
3434
<div className="max-w-lg mb-20">
@@ -50,7 +50,7 @@ export default function AuthPage() {
5050
<div className="flex w-full flex-col items-center justify-center p-4 md:w-1/2">
5151
<div className="md:hidden flex flex-col items-center mb-8 text-center space-y-2">
5252
<div className="flex items-center gap-1.5 font-semibold sm:font-bold tracking-tighter text-2xl">
53-
<img src="./logo.webp" alt="Sleek AI Logo" className="w-9 h-8" />
53+
<img src="./logo.webp" alt="Sleek AI Logo" className="w-10 h-8" />
5454
Sleek AI
5555
</div>
5656
<p className="text-sm text-neutral-500">Turn ideas into reality with an AI partner.</p>

frontend/src/styles/modelMessage.css

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
line-height: 0.8;
55
}
66

7-
.markdown :not(pre)>code {
7+
.markdown :not(pre) > code {
88
font-family: Inter, sans-serif;
99
-webkit-font-smoothing: antialiased;
1010
font-size: 0.875em;
@@ -52,13 +52,13 @@
5252
white-space: normal;
5353
}
5454

55-
.markdown li>p {
55+
.markdown li > p {
5656
display: inline;
5757
margin: 0;
5858
padding: 0;
5959
}
6060

61-
.markdown li+li {
61+
.markdown li + li {
6262
margin-top: 0.25rem;
6363
}
6464

@@ -68,15 +68,17 @@
6868
line-height: 0;
6969
}
7070

71-
.markdown ol li {
71+
.markdown ol li,
72+
.markdown ul li {
7273
margin-bottom: 0.22rem;
73-
line-height: 1.4;
74+
line-height: 1.8;
7475
}
7576

76-
.markdown ol li::marker {
77+
.markdown ol li::marker,
78+
.markdown ul li::marker {
7779
color: #1c1c1c;
7880
font-weight: 600;
79-
font-size: 0.9em;
81+
font-size: 0.95em;
8082
}
8183

8284
.markdown ol ol {
@@ -90,16 +92,6 @@
9092
line-height: 0.1;
9193
}
9294

93-
.markdown ul li {
94-
margin-bottom: 0.22rem;
95-
line-height: 1.4;
96-
}
97-
98-
.markdown ul li::marker {
99-
color: rgba(28, 28, 28, 0.8);
100-
font-size: 0.95em;
101-
}
102-
10395
.markdown ul ul {
10496
list-style-type: circle;
10597
padding-left: 1rem;
@@ -147,7 +139,7 @@
147139
font-size: 1rem;
148140
}
149141

150-
.markdown>*:first-child {
142+
.markdown > *:first-child {
151143
margin-top: 0 !important;
152144
}
153145

@@ -313,7 +305,10 @@
313305
opacity: 1;
314306
transition: all 0.2s ease;
315307

316-
font-family: system-ui, -apple-system, sans-serif;
308+
font-family:
309+
system-ui,
310+
-apple-system,
311+
sans-serif;
317312
font-size: 0.85em;
318313
line-height: 1;
319314
}
@@ -323,15 +318,14 @@
323318
transform: translate(1px, -1px);
324319
}
325320

326-
.streamingCursor>*:last-child::after {
321+
.streamingCursor > *:last-child::after {
327322
content: "▋";
328323
display: inline-block;
329324
margin-left: 4px;
330325
animation: pulse 1s cubic-bezier(0.4, 0, 0.6, 1) infinite;
331326
}
332327

333328
@keyframes pulse {
334-
335329
0%,
336330
100% {
337331
opacity: 1;
@@ -357,7 +351,6 @@
357351
}
358352

359353
@keyframes pulse-opacity {
360-
361354
0%,
362355
100% {
363356
opacity: 1;
@@ -370,8 +363,7 @@
370363

371364
/* Mobile responsive adjustments */
372365
@media (max-width: 640px) {
373-
374-
.markdown li+li {
366+
.markdown li + li {
375367
margin-top: 0.3rem;
376368
}
377369

@@ -389,4 +381,4 @@
389381
margin-top: 1.25rem;
390382
margin-bottom: 0.5rem;
391383
}
392-
}
384+
}

0 commit comments

Comments
 (0)