Skip to content

Commit 185fc65

Browse files
committed
feat: RAG complete
1 parent d6c1412 commit 185fc65

16 files changed

Lines changed: 236 additions & 394 deletions

File tree

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,26 @@ jobs:
2626
platforms: linux/arm64
2727
push: true
2828
tags: sunjay195/chatty-ai-backend:latest
29+
worker:
30+
runs-on: ubuntu-24.04-arm
31+
timeout-minutes: 10
32+
steps:
33+
- uses: actions/checkout@v4
34+
35+
- name: Set up Docker Buildx
36+
uses: docker/setup-buildx-action@v3
37+
38+
- name: Docker Hub Login
39+
uses: docker/login-action@v3
40+
with:
41+
username: ${{ secrets.DOCKER_USERNAME }}
42+
password: ${{ secrets.DOCKER_PASSWORD }}
43+
44+
- name: Build & Push worker
45+
uses: docker/build-push-action@v5
46+
with:
47+
context: .
48+
file: worker/Dockerfile
49+
platforms: linux/arm64
50+
push: true
51+
tags: sunjay195/chatty-ai-worker:latest

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

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ on:
88

99
jobs:
1010
changes:
11-
runs-on: ubuntu-latest
11+
runs-on: ubuntu-24.04-arm
1212
timeout-minutes: 5
1313
outputs:
1414
backend: ${{ steps.set-filters.outputs.backend }}
15+
worker: ${{ steps.set-filters.outputs.worker }}
1516
steps:
1617
- uses: actions/checkout@v4
1718

@@ -24,18 +25,21 @@ jobs:
2425
backend:
2526
- 'backend/**'
2627
- 'shared/**'
28+
worker:
29+
- 'worker/**'
2730
2831
- name: Force all outputs on manual run
2932
if: github.event_name == 'workflow_dispatch'
3033
id: force-filter
3134
run: |
3235
echo "backend=true" >> $GITHUB_OUTPUT
33-
echo "jobrunner=true" >> $GITHUB_OUTPUT
36+
echo "worker=true" >> $GITHUB_OUTPUT
3437
3538
- name: Set outputs depending on trigger
3639
id: set-filters
3740
run: |
3841
echo "backend=${{ steps.path-filter.outputs.backend || 'true' }}" >> $GITHUB_OUTPUT
42+
echo "worker=${{ steps.path-filter.outputs.worker || 'true' }}" >> $GITHUB_OUTPUT
3943
4044
backend:
4145
needs: changes
@@ -74,3 +78,41 @@ jobs:
7478
git_commit_sha=${{ github.sha }}
7579
git_commit_short=${{ steps.meta.outputs.short_sha }}
7680
git_commit_msg=${{ steps.meta.outputs.short_msg }}
81+
82+
worker:
83+
needs: changes
84+
if: needs.changes.outputs.worker == 'true'
85+
runs-on: ubuntu-24.04-arm
86+
timeout-minutes: 10
87+
steps:
88+
- uses: actions/checkout@v4
89+
90+
- name: Set up Docker Buildx
91+
uses: docker/setup-buildx-action@v3
92+
93+
- name: Prepare metadata
94+
id: meta
95+
run: |
96+
msg=$(echo "${{ github.event.head_commit.message }}" | head -n1)
97+
msg=${msg// /_}
98+
echo "short_msg=$msg" >> $GITHUB_OUTPUT
99+
echo "short_sha=$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT
100+
101+
- name: Docker Hub Login
102+
uses: docker/login-action@v3
103+
with:
104+
username: ${{ secrets.DOCKER_USERNAME }}
105+
password: ${{ secrets.DOCKER_PASSWORD }}
106+
107+
- name: Build & Push worker
108+
uses: docker/build-push-action@v5
109+
with:
110+
context: .
111+
file: worker/Dockerfile
112+
platforms: linux/arm64
113+
push: true
114+
tags: sunjay195/chatty-ai-worker:latest
115+
labels: |
116+
git_commit_sha=${{ github.sha }}
117+
git_commit_short=${{ steps.meta.outputs.short_sha }}
118+
git_commit_msg=${{ steps.meta.outputs.short_msg }}

backend/src/config/queue.config.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Queue } from "bullmq";
1+
import { Queue, QueueEvents } from "bullmq";
2+
import prisma from "./prisma.config.js";
23

34
export const fileIngestQueue = new Queue("file-ingest", {
45
connection: {
@@ -8,3 +9,35 @@ export const fileIngestQueue = new Queue("file-ingest", {
89
attempts: 2,
910
},
1011
});
12+
13+
const queueEvents = new QueueEvents("file-ingest", {
14+
connection: {
15+
url: process.env.REDIS_URL as string,
16+
},
17+
});
18+
19+
queueEvents.on("completed", async ({ jobId }) => {
20+
const job = await fileIngestQueue.getJob(jobId);
21+
22+
if (job) {
23+
const { chatId } = job.data;
24+
25+
await prisma.chat.update({
26+
where: { id: chatId },
27+
data: { ragStatus: "COMPLETED", isRag: true },
28+
});
29+
}
30+
});
31+
32+
queueEvents.on("failed", async ({ jobId }) => {
33+
const job = await fileIngestQueue.getJob(jobId);
34+
35+
if (job) {
36+
const { chatId } = job.data;
37+
38+
await prisma.chat.update({
39+
where: { id: chatId },
40+
data: { ragStatus: "FAILED" },
41+
});
42+
}
43+
});

backend/src/controllers/webHook.controllers.ts

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -37,27 +37,3 @@ export async function handleClerkWebHook(c: Context) {
3737
return c.json({ ok: true }, 200);
3838
}
3939

40-
export async function handleRagWebhook(c: Context) {
41-
const secret = c.req.header("x-internal-secret");
42-
if (secret !== process.env.INTERNAL_SECRET) {
43-
return c.json({ error: "Unauthorized" }, 401);
44-
}
45-
46-
const { chatId, status } = await c.req.json();
47-
48-
if (!chatId || !status) {
49-
return c.json({ error: "Missing required fields" }, 400);
50-
}
51-
52-
const dataToUpdate: any = { ragStatus: status };
53-
if (status === "COMPLETED") {
54-
dataToUpdate.isRag = true;
55-
}
56-
57-
await prisma.chat.update({
58-
where: { id: chatId },
59-
data: dataToUpdate,
60-
});
61-
62-
return c.json({ success: true }, 200);
63-
}

backend/src/prompts/system.prompt.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { UserPreference } from "../generated/prisma/client.js";
22
import { Memories } from "../utils/model.utils.js";
33

4-
export const systemPrompt = (preferences: UserPreference, memories: Memories[], timezone: string) => {
4+
export const systemPrompt = (preferences: UserPreference, memories: Memories[], timezone: string, isRag: boolean = false) => {
55
const { nickname, occupation, about, customInstructions } = preferences;
66

77
const dateTimeString = new Date().toLocaleString("en-US", {
@@ -60,9 +60,18 @@ ${memoryContext.length ? `### KNOWN FACTS ABOUT THE USER\n${memoryContext.join("
6060
**1. Math & Currency**
6161
- Inline math: ONLY use double dollar signs \`$$...$$\` for inline math equations so they render correctly via KaTeX. DO NOT use single dollar signs \`$...\` for math.
6262
- Block math: Use double dollar signs \`$$...$$\` on separate lines.
63-
- Currency: Write currency normally like \`$37,000\`. It will render as normal text because single-dollar math parsing is disabled.
63+
- Currency & Numbers: Use commas as thousands separators for all numbers greater than 999 (e.g., $37,000, 1,250, Rs 38,880) to improve readability. This applies to both normal text and math equations.
64+
- Currency Formatting: Write currency normally like \`$37,000\`. It will render as normal text because single-dollar math parsing is disabled.
6465
6566
**2. Markdown Tables**
6667
- Do NOT use multi-line code blocks inside tables, place it **outside** the table..
67-
- Use single backticks for inline code.`;
68+
- Use single backticks for inline code.
69+
${isRag
70+
? `
71+
### DOCUMENT SEARCH CAPABILITY (ACTIVE)
72+
- **YOU HAVE ACCESS TO DOCUMENTS**: The user has uploaded files to this chat.
73+
- **USE ragSearch TOOL**: When the user asks about the content of their documents, or if your internal knowledge is insufficient regarding the specific files they've uploaded, you MUST use the \`ragSearch\` tool.
74+
- **CONTEXTUAL ANSWERS**: Use the information retrieved from the documents to provide accurate, grounded responses. Identify the source if multiple documents are present.`
75+
: ""
76+
}`;
6877
};
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { Hono } from "hono";
2-
import { handleClerkWebHook, handleRagWebhook } from "../controllers/webHook.controllers.js";
2+
import { handleClerkWebHook } from "../controllers/webHook.controllers.js";
33
import { verifyClerkWebhook } from "../middlewares/clerk.middlewares.js";
44
const router = new Hono();
55

66
router.post("/clerk", verifyClerkWebhook, handleClerkWebHook);
7-
router.post("/rag-status", handleRagWebhook);
87

98
export default router;

backend/src/utils/model.utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ type Props = {
2424
};
2525

2626
export async function* generateAIResponse({ query, threadId, modelName, preferences, memories, timezone, isRag }: Props) {
27-
const agent = createGroqAgent(modelName, systemPrompt(preferences, memories, timezone), isRag);
27+
const agent = createGroqAgent(modelName, systemPrompt(preferences, memories, timezone, isRag), isRag);
2828

2929
const config = { configurable: { thread_id: threadId } };
3030

docker-compose.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,17 @@ services:
2222
- "3000:3000"
2323
restart: always
2424

25+
worker:
26+
build:
27+
context: .
28+
dockerfile: ./worker/Dockerfile
29+
container_name: worker
30+
env_file:
31+
- ./worker/.env
32+
depends_on:
33+
- redis
34+
restart: always
35+
2536
frontend:
2637
build:
2738
context: .

frontend/src/components/messages/UserMessage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export default memo(function UserMessage({ message, isCopied, onCopy }: Props) {
7171
)}
7272

7373
{text && (
74-
<div className="user-message-color text-primary border border-gray-300/20 px-4 py-3 sm:px-3 sm:py-2.5 rounded-tr-none rounded-2xl max-w-[85%] sm:max-w-lg relative transition-all">
74+
<div className="user-message-color text-primary border border-gray-300/20 px-3 py-2.5 rounded-tr-none rounded-2xl max-w-[85%] sm:max-w-lg relative transition-all">
7575
{isLongText && (
7676
<button
7777
onClick={() => setIsExpanded(!isExpanded)}

frontend/src/components/sidebars/Sidebar.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,7 @@ export default function Sidebar({ chats, isFetchingChats, onDeleteRequest, onRen
8181
return (
8282
<>
8383
{isMobile && !collapsed && <div className="fixed inset-0 bg-black/40 z-20" onClick={() => setCollapsed(true)} />}
84-
<aside
85-
ref={sidebarRef}
86-
className="fixed md:relative h-dvh w-[68%] sm:w-64 rounded-r-3xl sm:rounded-r-none bg-dark border-r border-gray-500/20 flex flex-col z-30 shrink-0"
87-
>
84+
<aside ref={sidebarRef} className="fixed md:relative h-dvh w-[68%] sm:w-64 bg-dark border-r border-gray-500/20 flex flex-col z-30 shrink-0">
8885
<div className={`px-4 py-3 flex items-center justify-between ${scrolled ? "border-b border-gray-400/20" : ""}`}>
8986
<img className="w-9 h-7.5" src="/logo.webp" alt="Sleek AI Logo" />
9087
<button
@@ -145,7 +142,7 @@ export default function Sidebar({ chats, isFetchingChats, onDeleteRequest, onRen
145142
}}
146143
className={({ isActive }) =>
147144
[
148-
"group relative flex items-center justify-between px-2 py-1 rounded-lg text-xs hover:bg-gray-200/60 active:bg-gray-200/60",
145+
"group relative flex items-center justify-between px-2 py-1.5 sm:py-1 rounded-lg text-xs hover:bg-gray-200/60 active:bg-gray-200/60",
149146
isActive ? "font-medium bg-gray-200/60" : "",
150147
].join(" ")
151148
}

0 commit comments

Comments
 (0)