@@ -25,6 +25,7 @@ import { RequestWithUser } from '../../auth/auth.middleware';
2525import { Readable } from 'stream' ;
2626import { S3Client , GetObjectCommand } from '@aws-sdk/client-s3' ;
2727import { ConfigService } from '@nestjs/config' ;
28+ import { ProcessingStatus } from '../../reports/models/report.model' ;
2829
2930@Controller ( 'document-processor' )
3031export class DocumentProcessorController {
@@ -38,7 +39,7 @@ export class DocumentProcessorController {
3839
3940 @Post ( 'upload' )
4041 @UseInterceptors ( FileInterceptor ( 'file' ) )
41- async processDocument (
42+ async uploadAndProcessReport (
4243 @UploadedFile ( ) file : Express . Multer . File ,
4344 @Body ( 'userId' ) userId : string ,
4445 @Body ( 'debug' ) debug ?: string ,
@@ -114,12 +115,12 @@ export class DocumentProcessorController {
114115 }
115116
116117 @Post ( 'process-file' )
117- async processFileFromPath (
118- @Body ( 'filePath ' ) filePath : string ,
118+ async processReport (
119+ @Body ( 'reportId ' ) reportId : string ,
119120 @Req ( ) request : RequestWithUser ,
120- ) : Promise < ProcessedDocumentResult | any > {
121- if ( ! filePath ) {
122- throw new BadRequestException ( 'No filePath provided' ) ;
121+ ) : Promise < any > {
122+ if ( ! reportId ) {
123+ throw new BadRequestException ( 'No reportId provided' ) ;
123124 }
124125
125126 // Extract userId from the request (attached by auth middleware)
@@ -128,25 +129,74 @@ export class DocumentProcessorController {
128129 throw new UnauthorizedException ( 'User ID not found in request' ) ;
129130 }
130131
131- this . logger . log ( `Processing document from file path : ${ filePath } ` ) ;
132+ this . logger . log ( `Queueing document for processing, report ID : ${ reportId } ` ) ;
132133
133134 try {
134- // Fetch the associated report record from DynamoDB
135- const report = await this . reportsService . findByFilePath ( filePath , userId ) ;
135+ // Fetch the associated report record from DynamoDB using findOne method
136+ const report = await this . reportsService . findOne ( reportId , userId ) ;
136137 if ( ! report ) {
137- throw new NotFoundException ( `Report with filePath ${ filePath } not found` ) ;
138+ throw new NotFoundException ( `Report with ID ${ reportId } not found` ) ;
139+ }
140+
141+ // Make sure we have a filePath to retrieve the file
142+ if ( ! report . filePath ) {
143+ throw new BadRequestException ( `Report with ID ${ reportId } has no associated file` ) ;
138144 }
139145
146+ // Update report status to IN_PROGRESS before starting async processing
147+ report . processingStatus = ProcessingStatus . IN_PROGRESS ;
148+ report . updatedAt = new Date ( ) . toISOString ( ) ;
149+ await this . reportsService . updateReport ( report ) ;
150+
151+ // Start async processing in background
152+ this . processReportAsync ( reportId , userId , report . filePath ) . catch ( error => {
153+ this . logger . error ( `Async processing failed for report ${ reportId } : ${ error . message } ` ) ;
154+ } ) ;
155+
156+ return {
157+ success : true ,
158+ reportId : report . id ,
159+ status : ProcessingStatus . IN_PROGRESS ,
160+ message : 'Document processing started. Check the report status to know when it completes.' ,
161+ } ;
162+ } catch ( error : unknown ) {
163+ this . logger . error (
164+ `Error queueing document for report ID ${ reportId } : ${ error instanceof Error ? error . message : 'Unknown error' } ` ,
165+ ) ;
166+ throw error ;
167+ }
168+ }
169+
170+ /**
171+ * Processes a report file asynchronously
172+ * @param reportId - ID of the report to process
173+ * @param userId - ID of the user who owns the report
174+ * @param filePath - S3 path to the file
175+ */
176+ private async processReportAsync (
177+ reportId : string ,
178+ userId : string ,
179+ filePath : string ,
180+ ) : Promise < void > {
181+ try {
182+ this . logger . log ( `Started async processing for report: ${ reportId } ` ) ;
183+
140184 // Get the file from S3
141185 const fileBuffer = await this . getFileFromS3 ( filePath ) ;
142186
143187 // Process the document
144188 const result = await this . documentProcessorService . processDocument ( fileBuffer , userId ) ;
145189
190+ // Fetch the report again to ensure we have the latest version
191+ const report = await this . reportsService . findOne ( reportId , userId ) ;
192+ if ( ! report ) {
193+ throw new Error ( `Report ${ reportId } not found during async processing` ) ;
194+ }
195+
146196 // Update the report with analysis results
147197 report . title = result . analysis . title || 'Untitled Report' ;
148198 report . category = result . analysis . category || 'general' ;
149- report . isProcessed = true ;
199+ report . processingStatus = ProcessingStatus . PROCESSED ;
150200
151201 // Extract lab values
152202 report . labValues = result . analysis . labValues || [ ] ;
@@ -162,13 +212,26 @@ export class DocumentProcessorController {
162212 // Update the report in DynamoDB
163213 await this . reportsService . updateReport ( report ) ;
164214
165- return {
166- success : true ,
167- reportId : report . id ,
168- } ;
169- } catch ( error : unknown ) {
215+ this . logger . log ( `Completed async processing for report: ${ reportId } ` ) ;
216+ } catch ( error ) {
217+ // If processing fails, update the report status to indicate failure
218+ try {
219+ const report = await this . reportsService . findOne ( reportId , userId ) ;
220+ if ( report ) {
221+ report . processingStatus = ProcessingStatus . FAILED ;
222+ report . updatedAt = new Date ( ) . toISOString ( ) ;
223+ await this . reportsService . updateReport ( report ) ;
224+ }
225+ } catch ( updateError : unknown ) {
226+ this . logger . error (
227+ `Failed to update report status after processing error: ${
228+ updateError instanceof Error ? updateError . message : 'Unknown error'
229+ } `,
230+ ) ;
231+ }
232+
170233 this . logger . error (
171- `Error processing document from path ${ filePath } : ${ error instanceof Error ? error . message : 'Unknown error' } ` ,
234+ `Error during async processing for report ${ reportId } : ${ error instanceof Error ? error . message : 'Unknown error' } ` ,
172235 ) ;
173236 throw error ;
174237 }
@@ -606,4 +669,39 @@ export class DocumentProcessorController {
606669
607670 res . type ( 'text/html' ) . send ( html ) ;
608671 }
672+
673+ @Get ( 'report-status/:reportId' )
674+ async getReportStatus ( @Req ( ) request : RequestWithUser ) : Promise < any > {
675+ // Get reportId from path parameter
676+ const reportId = request . params . reportId ;
677+
678+ if ( ! reportId ) {
679+ throw new BadRequestException ( 'No reportId provided' ) ;
680+ }
681+
682+ // Extract userId from the request (attached by auth middleware)
683+ const userId = request . user ?. sub ;
684+ if ( ! userId ) {
685+ throw new UnauthorizedException ( 'User ID not found in request' ) ;
686+ }
687+
688+ try {
689+ // Fetch the associated report record from DynamoDB
690+ const report = await this . reportsService . findOne ( reportId , userId ) ;
691+ if ( ! report ) {
692+ throw new NotFoundException ( `Report with ID ${ reportId } not found` ) ;
693+ }
694+
695+ return {
696+ reportId : report . id ,
697+ status : report . processingStatus ,
698+ isComplete : report . processingStatus === ProcessingStatus . PROCESSED ,
699+ } ;
700+ } catch ( error : unknown ) {
701+ this . logger . error (
702+ `Error fetching report status for ${ reportId } : ${ error instanceof Error ? error . message : 'Unknown error' } ` ,
703+ ) ;
704+ throw error ;
705+ }
706+ }
609707}
0 commit comments