CognxSafeTrack commited on
Commit
a59f28c
·
1 Parent(s): dced83b

feat: add Dockerfile and script for Hugging Face Spaces

Browse files
Dockerfile ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM node:18-alpine
2
+
3
+ WORKDIR /app
4
+
5
+ # Install pnpm and global dependencies
6
+ RUN npm install -g pnpm turbo
7
+
8
+ # Copy root package files
9
+ COPY package.json pnpm-workspace.yaml turbo.json ./
10
+
11
+ # Copy package configurations
12
+ COPY packages/tsconfig packages/tsconfig
13
+ COPY packages/database packages/database
14
+ COPY packages/shared-types packages/shared-types
15
+
16
+ # Copy app configurations
17
+ COPY apps/api/package.json apps/api/package.json
18
+ COPY apps/whatsapp-worker/package.json apps/whatsapp-worker/package.json
19
+ COPY apps/api/tsconfig.json apps/api/tsconfig.json
20
+ COPY apps/whatsapp-worker/tsconfig.json apps/whatsapp-worker/tsconfig.json
21
+
22
+ # Install dependencies
23
+ RUN pnpm install
24
+
25
+ # Copy source code
26
+ COPY packages/database packages/database
27
+ COPY packages/shared-types packages/shared-types
28
+ COPY apps/api apps/api
29
+ COPY apps/whatsapp-worker apps/whatsapp-worker
30
+ COPY scripts/start-backend.sh scripts/start-backend.sh
31
+
32
+ # Generate Prisma Client
33
+ RUN pnpm db:generate
34
+
35
+ # Build packages and apps
36
+ RUN pnpm build --filter=api --filter=whatsapp-worker...
37
+
38
+ # Make script executable
39
+ RUN chmod +x scripts/start-backend.sh
40
+
41
+ # Expose port (HF Spaces uses 7860)
42
+ EXPOSE 7860
43
+ ENV PORT=7860
44
+
45
+ # Start command
46
+ CMD ["./scripts/start-backend.sh"]
apps/api/src/index.ts CHANGED
@@ -17,8 +17,9 @@ server.get('/health', async (request, reply) => {
17
 
18
  const start = async () => {
19
  try {
20
- await server.listen({ port: 3001, host: '0.0.0.0' });
21
- console.log('Server listening on http://localhost:3001');
 
22
  } catch (err) {
23
  server.log.error(err);
24
  process.exit(1);
 
17
 
18
  const start = async () => {
19
  try {
20
+ const port = parseInt(process.env.PORT || '3001');
21
+ await server.listen({ port, host: '0.0.0.0' });
22
+ console.log(`Server listening on http://0.0.0.0:${port}`);
23
  } catch (err) {
24
  server.log.error(err);
25
  process.exit(1);
apps/api/src/services/queue.ts ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Queue } from 'bullmq';
2
+
3
+ const connection = {
4
+ host: process.env.REDIS_HOST || 'localhost',
5
+ port: parseInt(process.env.REDIS_PORT || '6379'),
6
+ };
7
+
8
+ export const whatsappQueue = new Queue('whatsapp-queue', { connection });
9
+
10
+ export async function scheduleMessage(userId: string, text: string, delayMs: number = 0) {
11
+ await whatsappQueue.add('send-message', {
12
+ userId,
13
+ text
14
+ }, {
15
+ delay: delayMs
16
+ });
17
+ }
18
+
19
+ export async function scheduleTrackDay(userId: string, trackId: string, dayNumber: number, delayMs: number = 0) {
20
+ await whatsappQueue.add('send-content', {
21
+ userId,
22
+ trackId,
23
+ dayNumber
24
+ }, {
25
+ delay: delayMs
26
+ });
27
+ }
apps/api/src/services/whatsapp.ts CHANGED
@@ -77,9 +77,11 @@ export class WhatsAppService {
77
 
78
  console.log(`User ${user.id} enrolled in ${defaultTrack.title}`);
79
 
80
- // TODO: Send Day 1 Content immediately
81
- // const day1 = await prisma.trackDay.findFirst(...)
82
- // await sendMessage(phone, day1.textContent);
 
 
83
  } else {
84
  console.log('Unknown command, sending menu...');
85
  // TODO: Send "Envoyez INSCRIPTION pour commencer"
 
77
 
78
  console.log(`User ${user.id} enrolled in ${defaultTrack.title}`);
79
 
80
+ // Schedule Day 1 Content immediately (or short delay)
81
+ // Import dynamically to avoid circular deps if necessary, or just import at top
82
+ const { scheduleTrackDay } = await import('./queue');
83
+ await scheduleTrackDay(user.id, defaultTrack.id, 1, 0);
84
+
85
  } else {
86
  console.log('Unknown command, sending menu...');
87
  // TODO: Send "Envoyez INSCRIPTION pour commencer"
apps/whatsapp-worker/src/index.ts CHANGED
@@ -1,18 +1,52 @@
1
- import { Worker } from 'bullmq';
2
  import dotenv from 'dotenv';
 
3
 
4
  dotenv.config();
5
 
 
 
6
  const connection = {
7
  host: process.env.REDIS_HOST || 'localhost',
8
  port: parseInt(process.env.REDIS_PORT || '6379'),
9
  };
10
 
11
- const worker = new Worker('whatsapp-queue', async job => {
12
- console.log('Processing job:', job.id, job.data);
13
- // Simulating work
14
- await new Promise(resolve => setTimeout(resolve, 1000));
15
- console.log('Job completed:', job.id);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  }, { connection });
17
 
18
  console.log('WhatsApp Worker started...');
 
1
+ import { Worker, Job } from 'bullmq';
2
  import dotenv from 'dotenv';
3
+ import { PrismaClient } from '@prisma/client';
4
 
5
  dotenv.config();
6
 
7
+ const prisma = new PrismaClient();
8
+
9
  const connection = {
10
  host: process.env.REDIS_HOST || 'localhost',
11
  port: parseInt(process.env.REDIS_PORT || '6379'),
12
  };
13
 
14
+ const worker = new Worker('whatsapp-queue', async (job: Job) => {
15
+ console.log('Processing job:', job.name, job.id);
16
+
17
+ try {
18
+ if (job.name === 'send-message') {
19
+ const { userId, text } = job.data;
20
+ // TODO: Call WhatsApp Cloud API to send text
21
+ console.log(`[MOCK SEND] To User ${userId}: "${text}"`);
22
+ }
23
+ else if (job.name === 'send-content') {
24
+ const { userId, trackId, dayNumber } = job.data;
25
+
26
+ const trackDay = await prisma.trackDay.findFirst({
27
+ where: { trackId, dayNumber }
28
+ });
29
+
30
+ if (trackDay && trackDay.textContent) {
31
+ // TODO: Call WhatsApp Cloud API
32
+ console.log(`[MOCK SEND CONTENT] To User ${userId}: "${trackDay.textContent}"`);
33
+
34
+ // Update enrollment progress
35
+ await prisma.enrollment.updateMany({
36
+ where: { userId, trackId },
37
+ data: {
38
+ currentDay: dayNumber,
39
+ lastActivityAt: new Date()
40
+ }
41
+ });
42
+ } else {
43
+ console.error(`Content not found for Track ${trackId} Day ${dayNumber}`);
44
+ }
45
+ }
46
+ } catch (error) {
47
+ console.error(`Job ${job.id} failed:`, error);
48
+ throw error;
49
+ }
50
  }, { connection });
51
 
52
  console.log('WhatsApp Worker started...');
scripts/start-backend.sh ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/sh
2
+
3
+ # Migrate database
4
+ echo "Running database migrations..."
5
+ pnpm db:push
6
+
7
+ # Start Worker in background
8
+ echo "Starting WhatsApp Worker..."
9
+ node apps/whatsapp-worker/dist/index.js &
10
+
11
+ # Start API in foreground
12
+ echo "Starting API..."
13
+ node apps/api/dist/index.js