Skip to content

Commit 6a8178d

Browse files
committed
refactor: add improvements to the genai routes with zod validation
1 parent af74aca commit 6a8178d

File tree

8 files changed

+52
-48
lines changed

8 files changed

+52
-48
lines changed

src/common/middlewares/body-validation.middleware.ts

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,36 @@
1-
import { NextFunction, Request, Response } from 'express'
1+
import { NextFunction, Request } from 'express'
22
import { z, ZodError } from 'zod'
3+
import { AppResponse } from '../types'
34

4-
const userSchema = z.object({
5+
export const userSchema = z.object({
56
email: z.string().email('Invalid email address'),
67
password: z.string().min(6, 'Password must be at least 6 characters long'),
78
name: z.string().optional(),
89
})
910

10-
const userCredentialsSchema = z.object({
11+
export const userCredentialsSchema = z.object({
1112
email: z.string().email('Invalid email address'),
1213
})
1314

14-
const validateRequestBody = (schema: z.ZodSchema<any>) => {
15-
return (req: Request, res: Response, next: NextFunction) => {
15+
export const translateTextSchema = z.object({
16+
text: z.string().min(1, 'text field is required'),
17+
language: z.string().min(1, 'language field is required'),
18+
})
19+
20+
export const validateRequestBody = (schema: z.ZodSchema<any>) => {
21+
return (req: Request, res: AppResponse, next: NextFunction) => {
1622
try {
1723
schema.parse(req.body)
1824
return next()
1925
} catch (error) {
2026
if (error instanceof ZodError) {
21-
return res
22-
.status(400)
23-
.json({ data: null, errors: error.errors.map((e) => e.message) })
27+
return res.status(400).json({
28+
success: false,
29+
error: { message: error.errors.map((e) => e.message) },
30+
})
2431
}
2532

2633
return next(error)
2734
}
2835
}
2936
}
30-
31-
export { userCredentialsSchema, userSchema, validateRequestBody }

src/common/types/network.types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ export interface AppRequest<
1616
export type AppResponse<T = any> = Response<{
1717
success: boolean
1818
data?: T
19-
error?: { message: string; code?: string }
19+
error?: { message: string | string[]; code?: string }
2020
}>

src/di/index.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
import { PrismaClient } from '@prisma/client'
22

3-
import {
4-
ChatMemory,
5-
DocumentsService,
6-
LLMService,
7-
} from '@/modules/genai/adapters'
3+
import { DocumentsService, LLMService } from '@/modules/genai/adapters'
84

95
import {
106
SearchInDocumentUseCase,
@@ -17,15 +13,13 @@ import { UserDataProvider } from '@/modules/users/adapters/dataproviders/user.da
1713
import { UsersController } from '@/modules/users/application/controllers/users.controller'
1814

1915
// Common
20-
const chatMemory = new ChatMemory()
2116
const llmService = new LLMService()
2217
const prismaClient = new PrismaClient()
2318

2419
// Gen AI Module
2520
const genAIController = new GenAIController()
2621
const documentService = new DocumentsService(llmService)
2722
const searchInDocumentUseCase = new SearchInDocumentUseCase(
28-
chatMemory,
2923
llmService,
3024
documentService,
3125
)
@@ -41,7 +35,6 @@ const authController = new AuthController(userDatProvider)
4135

4236
export {
4337
authController,
44-
chatMemory,
4538
documentService,
4639
genAIController,
4740
llmService,

src/modules/genai/adapters/dataproviders/chat-memory/chat-memory.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import { RedisChatMessageHistory } from '@langchain/redis'
22
import { BufferMemory } from 'langchain/memory'
33

44
export class ChatMemory {
5-
constructor() {
5+
constructor(private userId: string) {
66
this._memory = new BufferMemory({
77
chatHistory: new RedisChatMessageHistory({
8-
sessionId: 'a168c61a-c431-4ef8-bc1c-fedd808d45ea',
8+
sessionId: userId,
99
sessionTTL: 3600,
1010
config: {
1111
url: process.env['REDIS_URL'],

src/modules/genai/application/controllers/gen-ai.controller.ts

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,33 @@
1-
import { Request, Response } from 'express'
2-
3-
import { searchInDocumentUseCase, translateUseCase } from '@/di'
4-
import { upload } from '../../core'
1+
import { AppRequest, AppResponse } from '@/common/types';
2+
import { searchInDocumentUseCase, translateUseCase } from '@/di';
3+
import { upload } from '../../core';
54

65
export class GenAIController {
76
async translateText(
8-
req: Request<any, any, { text: string; language: string }>,
9-
res: Response,
7+
req: AppRequest<any, any, { text: string; language: string }>,
8+
res: AppResponse,
109
) {
1110
const { text, language } = req.body
12-
13-
if (language === undefined || text === undefined) {
14-
return res.status(400).send({
15-
message: 'Invalid request, set language and text in the request body!',
16-
})
17-
}
18-
1911
const result = await translateUseCase.invoke({ text, language })
20-
return res.send(result)
12+
return res.send({ success: true, data: result })
2113
}
2214

2315
async searchInDocument(
24-
req: Request<any, any, { query: string }>,
25-
res: Response,
16+
req: AppRequest<any, any, { query: string }>,
17+
res: AppResponse,
2618
) {
2719
upload(req, res, async (err) => {
2820
if (err) {
2921
return res
3022
.status(500)
31-
.json({ message: 'File upload failed!', error: err })
23+
.json({ success: false, error: { message: 'File upload failed!' } })
3224
}
3325

3426
if (!req.file) {
35-
return res.status(400).json({ message: 'Please provide a valid file!' })
27+
return res.status(400).json({
28+
success: false,
29+
error: { message: 'Please provide a valid file!' },
30+
})
3631
}
3732

3833
const query = req.body.query
@@ -41,12 +36,12 @@ export class GenAIController {
4136
const { result } = await searchInDocumentUseCase.invoke({
4237
query,
4338
filePath,
39+
userId: req.user!.id,
4440
})
4541

4642
return res.json({
47-
message: 'File and query received successfully!',
48-
data: { query, filePath },
49-
result,
43+
success: true,
44+
data: result,
5045
})
5146
})
5247
}

src/modules/genai/application/routes/index.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
11
import express from 'express'
22

3-
import { isAuthenticated } from '@/common/middlewares'
3+
import {
4+
isAuthenticated,
5+
translateTextSchema,
6+
validateRequestBody,
7+
} from '@/common/middlewares'
8+
49
import { genAIController } from '@/di'
510

611
const router = express.Router()
712

8-
router.post('/translate', isAuthenticated, genAIController.translateText)
13+
router.post(
14+
'/translate',
15+
isAuthenticated,
16+
validateRequestBody(translateTextSchema),
17+
genAIController.translateText,
18+
)
919

1020
router.post(
1121
'/search-in-document',

src/modules/genai/core/usecases/search-in-document/search-in-document.usecase.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@ import {
2626

2727
export class SearchInDocumentUseCase implements UseCase<Result, Params> {
2828
constructor(
29-
private _memory: ChatMemory,
3029
private _llmService: LLMService,
3130
private _documentService: DocumentsService,
3231
) {}
3332

34-
async invoke({ filePath, query }: Params): Promise<Result> {
33+
async invoke({ filePath, query, userId }: Params): Promise<Result> {
34+
const chatMemory = new ChatMemory(userId)
3535
const llmModel = this._llmService.llm
3636
const docs = await this._documentService.loadDocument(filePath)
3737
const { retriever } = await this._documentService.initializeVectorStore(
@@ -75,13 +75,13 @@ export class SearchInDocumentUseCase implements UseCase<Result, Params> {
7575
new StringOutputParser(),
7676
])
7777

78-
const history = await this._memory.retrieveMemoryHistory()
78+
const history = await chatMemory.retrieveMemoryHistory()
7979
const result = await retrievalChain.invoke({
8080
question: query,
8181
chat_history: history,
8282
})
8383

84-
this._memory.saveChatHistory(query, result)
84+
chatMemory.saveChatHistory(query, result)
8585
return { result }
8686
}
8787
}

src/modules/genai/core/usecases/search-in-document/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export type Params = {
2+
userId: string
23
query: string
34
filePath: string
45
}

0 commit comments

Comments
 (0)