one lazy ai
All checks were successful
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Successful in 4m5s
All checks were successful
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Successful in 4m5s
This commit is contained in:
@@ -58,48 +58,6 @@ describe('AI Routes (/api/ai)', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST /process-flyer', () => {
|
||||
it('should process an uploaded flyer image and return extracted data', async () => {
|
||||
// Arrange:
|
||||
// 1. Define the mock data the AI service will "extract".
|
||||
const mockExtractedData = {
|
||||
store_name: 'Test Store',
|
||||
items: [{ item: 'Test Item', price_display: '$1.99' }],
|
||||
} as Awaited<ReturnType<typeof aiService.extractCoreDataFromFlyerImage>>;
|
||||
mockedAiService.extractCoreDataFromFlyerImage.mockResolvedValue(mockExtractedData);
|
||||
|
||||
// 2. Define the other form fields that are sent along with the file.
|
||||
const mockMasterItems = [{ master_item_id: 1, item_name: 'Milk' }];
|
||||
|
||||
// 3. Define the path to a dummy file to upload.
|
||||
// The path is resolved from the current file's directory (`src/routes`) to the assets directory.
|
||||
const imagePath = path.resolve(__dirname, '../tests/assets/test-flyer-image.jpg');
|
||||
|
||||
// Act:
|
||||
// Use supertest to build the multipart/form-data request.
|
||||
const response = await supertest(app)
|
||||
.post('/api/ai/process-flyer')
|
||||
.field('masterItems', JSON.stringify(mockMasterItems)) // Attach regular form fields
|
||||
.attach('flyerImages', imagePath); // Attach the file for upload
|
||||
|
||||
// Assert:
|
||||
// 1. Check for a successful HTTP status.
|
||||
expect(response.status).toBe(200);
|
||||
|
||||
// 2. Verify the AI service was called correctly by the route handler.
|
||||
// Multer adds properties like 'path' to the file object. We check that the service
|
||||
// received an array of files with these properties.
|
||||
expect(mockedAiService.extractCoreDataFromFlyerImage).toHaveBeenCalledTimes(1);
|
||||
expect(mockedAiService.extractCoreDataFromFlyerImage).toHaveBeenCalledWith(
|
||||
expect.arrayContaining([expect.objectContaining({ mimetype: 'image/jpeg' })]),
|
||||
mockMasterItems
|
||||
);
|
||||
|
||||
// 3. Ensure the response body contains the data we mocked.
|
||||
expect(response.body.data).toEqual(mockExtractedData);
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST /flyers/process', () => {
|
||||
const imagePath = path.resolve(__dirname, '../tests/assets/test-flyer-image.jpg');
|
||||
const mockDataPayload = {
|
||||
|
||||
@@ -127,47 +127,7 @@ router.get('/jobs/:jobId/status', async (req, res) => {
|
||||
res.json({ id: job.id, state, progress, returnValue, failedReason });
|
||||
});
|
||||
|
||||
/**
|
||||
* This endpoint processes a flyer using AI. It uses `optionalAuth` middleware to allow
|
||||
* both authenticated and anonymous users to upload flyers.
|
||||
*/
|
||||
router.post('/process-flyer', optionalAuth, uploadToDisk.array('flyerImages'), async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const files = req.files as Express.Multer.File[];
|
||||
const totalSize = files ? files.reduce((acc, file) => acc + file.size, 0) : 0;
|
||||
const totalSizeMB = (totalSize / (1024 * 1024)).toFixed(2);
|
||||
|
||||
// --- AI ROUTE DEBUG LOGGING ---
|
||||
logger.debug('[API /ai/process-flyer] Request received.');
|
||||
logger.debug(`[API /ai/process-flyer] Files received: ${files ? files.length : 0}. Total size: ${totalSizeMB} MB.`);
|
||||
// --- END DEBUG LOGGING ---
|
||||
|
||||
if (!req.files || !Array.isArray(req.files) || req.files.length === 0) {
|
||||
return res.status(400).json({ message: 'Flyer image files are required.' });
|
||||
}
|
||||
|
||||
const masterItems = JSON.parse(req.body.masterItems);
|
||||
const imagePaths = (req.files as Express.Multer.File[]).map(file => ({
|
||||
path: file.path,
|
||||
mimetype: file.mimetype
|
||||
}));
|
||||
|
||||
logger.debug(`[API /ai/process-flyer] Processing image paths:`, { imagePaths });
|
||||
|
||||
const user = req.user as UserProfile | undefined;
|
||||
const logIdentifier = user ? `user ID: ${user.user_id}` : 'anonymous user';
|
||||
|
||||
logger.info(`Starting AI flyer data extraction for ${imagePaths.length} image(s) for ${logIdentifier}.`);
|
||||
|
||||
const extractedData = await aiService.extractCoreDataFromFlyerImage(imagePaths, masterItems);
|
||||
logger.info(`Completed AI flyer data extraction. Found ${extractedData.items.length} items.`);
|
||||
|
||||
res.status(200).json({ data: extractedData });
|
||||
} catch (error) {
|
||||
logger.error('Error in /api/ai/process-flyer endpoint:', { error });
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* This endpoint saves the processed flyer data to the database. It is the final step
|
||||
|
||||
Reference in New Issue
Block a user