one lazy ai
All checks were successful
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Successful in 4m5s

This commit is contained in:
2025-12-02 20:28:28 -08:00
parent 0555ae29f5
commit 62c30420fa
2 changed files with 0 additions and 82 deletions

View File

@@ -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 = {

View File

@@ -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