Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
637f80f
ADD transcriptionJob model to prisma schema
SergioNR Dec 12, 2025
56d9658
ADD npm package AWS transcribe
SergioNR Dec 12, 2025
7ec6f1f
RENAME updateAnalysisEntryInDb to markAnalysisEntryAsSubmitted for cl…
SergioNR Dec 12, 2025
6906c00
ADD transcription normalizer util
SergioNR Dec 12, 2025
34a2999
ADD functionality to get S3 objects from AWS S3
SergioNR Dec 12, 2025
c9cd86c
ADD cronjob to get completedTranscriptionJobs
SergioNR Dec 12, 2025
8d410ca
UPDATE prisma schema to include language code
SergioNR Dec 13, 2025
48cdbc2
ADD analysisService layer
SergioNR Dec 13, 2025
18e6982
ADD transcriptionModel - WIP
SergioNR Dec 13, 2025
c5002b8
ADD AWS Transcribe logic
SergioNR Dec 13, 2025
699cda8
REFACTOR analysisEntry controller to favor internal functions vs queues
SergioNR Dec 13, 2025
fc8df48
UPDATE swagger & REMOVE "success" attribute from PATCH analysisEntry
SergioNR Dec 13, 2025
a8101ef
ADD logic to update the transcriptJob after successful AWS transcribe…
SergioNR Dec 13, 2025
42c08ad
REMOVE queue-related transcription model functions
SergioNR Dec 20, 2025
6e9b646
REFACTOR transcription model from microservice to monolith
SergioNR Dec 20, 2025
31725c5
ADD no-plusplus rule exception to eslint
SergioNR Dec 20, 2025
b618c75
ADD no-await-in-loop rule exception in eslint
SergioNR Dec 20, 2025
fb3ce07
REMOVE lavinMQ implementation
SergioNR Dec 21, 2025
6a7666d
ADD error logging to completedTranscriptionJobScheduler CRON job
SergioNR Dec 21, 2025
5bb51e6
FIX typo in transcription job creation function
SergioNR Dec 21, 2025
3d5aa70
REMOVE mediaType attribute & remove requirement for analysisId
SergioNR Dec 21, 2025
610fa72
ADD logging to transcription request job
SergioNR Dec 22, 2025
8b75d68
ADD logic to handle completed transcription jobs
SergioNR Dec 22, 2025
765db4b
ADD no-restricted-syntax rule to eslint exceptions
SergioNR Dec 22, 2025
aedb52e
COMPLETE logic for requesting & processing transcription jobs
SergioNR Dec 22, 2025
8bf9d84
UPDATE db to include transcriptionJob table
SergioNR Dec 22, 2025
fdd9ef2
FIX typo in Transcribe.js
SergioNR Dec 22, 2025
e1030ca
ADD proper error logging to transcription function
SergioNR Dec 22, 2025
0e52887
REFACTOR transcription job retrieval logic for more clarity
SergioNR Dec 22, 2025
db31a5c
ADD prisma schema formatting
SergioNR Dec 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,3 @@ AWS_SECRET_ACCESS_KEY=
AWS_ACCESS_KEY_ID=
AWS_REGION=
AWS_BUCKET=

LAVINMQ_HOST=
3 changes: 3 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,8 @@ module.exports = {
'import/no-relative-packages': 'off',
'no-case-declarations': 'off',
'max-len': 'off',
'no-plusplus': 'off',
'no-await-in-loop': 'off',
'no-restricted-syntax': 'off',
},
};
3 changes: 0 additions & 3 deletions .kilocode/rules/memory-bank/tech.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,6 @@ TELEGRAM_BOT_API_KEY=your-bot-token

# Frontend
FRONT_WEB_APP_ORIGIN_URL=http://localhost:5173

# Message Queue
LAVINMQ_HOST=localhost
```

### Local Development Commands
Expand Down
1 change: 0 additions & 1 deletion compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ services:
AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
AWS_BUCKET: dev-analysis-entry-storage
AWS_REGION: ${AWS_REGION}
LAVINMQ_HOST: ${LAVINMQ_HOST}

ports:
- 3000:3000
Expand Down
471 changes: 434 additions & 37 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
},
"dependencies": {
"@aws-sdk/client-s3": "^3.936.0",
"@aws-sdk/client-transcribe": "^3.948.0",
"@aws-sdk/s3-request-presigner": "^3.936.0",
"@cloudamqp/amqp-client": "^3.4.0",
"@getbrevo/brevo": "^3.0.1",
"@prisma/client": "^6.19.0",
"@quixo3/prisma-session-store": "^3.1.13",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
-- CreateEnum
CREATE TYPE "TranscriptionJobStatus" AS ENUM ('PENDING', 'IN_PROGRESS', 'COMPLETED');

-- CreateTable
CREATE TABLE "TranscriptionJob" (
"id" SERIAL NOT NULL,
"analysis_entry_id" TEXT NOT NULL,
"status" "TranscriptionJobStatus" NOT NULL DEFAULT 'PENDING',
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"language_code" TEXT NOT NULL,

CONSTRAINT "TranscriptionJob_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "TranscriptionJob_id_key" ON "TranscriptionJob"("id");

-- CreateIndex
CREATE UNIQUE INDEX "TranscriptionJob_analysis_entry_id_key" ON "TranscriptionJob"("analysis_entry_id");

-- AddForeignKey
ALTER TABLE "TranscriptionJob" ADD CONSTRAINT "TranscriptionJob_analysis_entry_id_fkey" FOREIGN KEY ("analysis_entry_id") REFERENCES "AnalysisEntry"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
77 changes: 47 additions & 30 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,18 @@ model Company {
}

model ParticipantProfile {
id Int @id @default(autoincrement())
name String?
last_name String?
age String? // String to allow for prefer not to say option
gender Genders?
invited_by String?
country String?
devices String[] @default([])
created_at DateTime @default(now())
updated_at DateTime @default(now()) @updatedAt
User User @relation(fields: [user_id], references: [id])
user_id String @unique
id Int @id @default(autoincrement())
name String?
last_name String?
age String? // String to allow for prefer not to say option
gender Genders?
invited_by String?
country String?
devices String[] @default([])
created_at DateTime @default(now())
updated_at DateTime @default(now()) @updatedAt
User User @relation(fields: [user_id], references: [id])
user_id String @unique
AnalysisEntry AnalysisEntry[]
}

Expand Down Expand Up @@ -85,11 +85,11 @@ model Session {
}

model Subscription {
id String @id @unique @default(uuid())
company_id String @unique
Company Company @relation(fields: [company_id], references: [id])
created_at DateTime @default(now())
updated_at DateTime @default(now()) @updatedAt
id String @id @unique @default(uuid())
company_id String @unique
Company Company @relation(fields: [company_id], references: [id])
created_at DateTime @default(now())
updated_at DateTime @default(now()) @updatedAt
expires_at DateTime?
}

Expand All @@ -105,30 +105,47 @@ model Analysis {

tasks Json
url String
status AnalysisStatus @default(draft)
created_at DateTime @default(now())
updated_at DateTime @default(now()) @updatedAt
status AnalysisStatus @default(draft)
created_at DateTime @default(now())
updated_at DateTime @default(now()) @updatedAt
max_number_of_participants Int
AnalysisEntry AnalysisEntry[]
AnalysisEntry AnalysisEntry[]

@@index([owner_company_id]) // Not a unique field, but requires an index
}

model AnalysisEntry {
id String @id @default(uuid())
Analysis Analysis @relation(fields: [analysis_id], references: [id])
analysis_id String
ParticipantProfile ParticipantProfile? @relation(fields: [user_id], references: [user_id])
user_id String?
status AnalysisEntryCompletionStatus @default(in_progress)
created_at DateTime @default(now())
updated_at DateTime @default(now()) @updatedAt
id String @id @default(uuid())
Analysis Analysis @relation(fields: [analysis_id], references: [id])
analysis_id String
ParticipantProfile ParticipantProfile? @relation(fields: [user_id], references: [user_id])
user_id String?
status AnalysisEntryCompletionStatus @default(in_progress)
created_at DateTime @default(now())
updated_at DateTime @default(now()) @updatedAt
transcription_segments Json?
full_transcript String?
full_transcript String?
transcriptionJob TranscriptionJob?

@@index([analysis_id, status])
}

model TranscriptionJob {
id Int @id @unique @default(autoincrement())
AnalysisEntry AnalysisEntry @relation(fields: [analysis_entry_id], references: [id])
analysis_entry_id String @unique
status TranscriptionJobStatus @default(PENDING)
created_at DateTime @default(now())
updated_at DateTime @default(now()) @updatedAt
language_code String
}

enum TranscriptionJobStatus {
PENDING
IN_PROGRESS
COMPLETED
}

enum Genders {
male
female
Expand Down
4 changes: 1 addition & 3 deletions server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { slowLimiter } from './middlewares/express-slow-down.js';
import { startCronJobs } from './cron/jobsContainer.js';
import { globalErrorHandler } from './middlewares/globalErrorHandler.js';
import { webhookRouter } from './webhooks/webhooksRouter.js';
import { connectToMessageBroker } from './config/messageBroker/LavinMQ.js';

const app = express();
const server = createServer(app);
Expand Down Expand Up @@ -47,10 +46,9 @@ app.use(globalErrorHandler);
//* Start the server
server.listen(process.env.PORT, () => {
// eslint-disable-next-line no-console
console.log(`Server running at http://localhost:${process.env.PORT}/`);
console.log('Server running');
});

connectToMessageBroker();
startCronJobs();

const gracefulShutdown = () => {
Expand Down
131 changes: 0 additions & 131 deletions server/config/messageBroker/LavinMQ.js

This file was deleted.

30 changes: 10 additions & 20 deletions server/controllers/analysisEntryController.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { logError } from '../config/loggerFunctions.js';
import { publishToTranscriptionRequestedQueue } from '../config/messageBroker/LavinMQ.js';
import { generateS3GetPresignedUrl, generateS3PutPresignedUrl } from '../integrations/aws/s3.js';
import { createAnalysisEntryInDb, getAnalysisEntryDetailsById, updateAnalysisEntryInDb } from '../models/analysisEntryModel.js';
import { createAnalysisEntryInDb, getAnalysisEntryDetailsById, markAnalysisEntryAsSubmitted } from '../models/analysisEntryModel.js';
import { processTranscriptionRequest } from '../services/analysisService.js';

export const createAnalysisEntry = async (req, res) => {
const { analysisId } = req.body;
Expand All @@ -16,28 +15,19 @@ export const createAnalysisEntry = async (req, res) => {
};

export const updateAnalysisEntry = async (req, res) => {
const { analysisEntryId, analysisEntryStatus, analysisId } = req.body;
const { analysisEntryId } = req.body;

await updateAnalysisEntryInDb(analysisEntryId, analysisEntryStatus);
const updatedAnalysisEntry = await markAnalysisEntryAsSubmitted(analysisEntryId);

try {
const message = {
analysisEntryId: analysisEntryId,
analysisId: analysisId,
timestamp: new Date().toISOString(),
mediaType: 'video',
languageCode: 'es-ES',
};
const transcriptionRequest = {
analysisEntryId: analysisEntryId,
analysisId: updatedAnalysisEntry.analysis_id,
languageCode: 'es-ES',
};

const stringifiedMessage = JSON.stringify(message);

await publishToTranscriptionRequestedQueue(stringifiedMessage);
} catch (error) {
logError(`Error sending transcription request analysisEntry ${analysisEntryId}`, error);
}
processTranscriptionRequest(transcriptionRequest); // Fire-and-forget

return res.status(200).json({
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ WARNING: Hardcoded language code

The language code is hardcoded to 'es-ES'. This should be configurable based on the analysis requirements or user preferences.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No - Will only be in es-ES for the time being - its more efficient to hardcore for now

success: true,
message: 'Analysis entry updated successfully',
});
};
Expand Down
12 changes: 12 additions & 0 deletions server/cron/getCompletedTranscriptionJobsScheduler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { CronJob } from 'cron';
import { handleCompletedVideoTranscriptionJobs } from '../services/analysisService.js';
import { logError, logInfo } from '../config/loggerFunctions.js';

export const getCompletedTranscriptionJobsScheduler = new CronJob('15 * * * *', async () => {
try {
logInfo('Checking transcription job status');
await handleCompletedVideoTranscriptionJobs();
} catch (error) {
logError('Error checking transcription job status', error);
}
});
Loading