feat: adds PDF import with conversion to JSON 1.0
- Accept only PDF and JSON files in import modal and API - Convert PDF statements to JSON 1.0 via LLM (OpenAI-compatible) - Use multipart/form-data for file upload (multer, 15 MB limit) - Add LLM_API_KEY and LLM_API_BASE_URL for configurable LLM endpoint - Update ImportModal to validate type and send FormData - Add postFormData to API client for file upload
This commit is contained in:
@@ -1,13 +1,81 @@
|
||||
import { Router } from 'express';
|
||||
import multer from 'multer';
|
||||
import { asyncHandler } from '../utils';
|
||||
import { importStatement, isValidationError } from '../services/import';
|
||||
import {
|
||||
convertPdfToStatement,
|
||||
isPdfConversionError,
|
||||
} from '../services/pdfToStatement';
|
||||
|
||||
const upload = multer({
|
||||
storage: multer.memoryStorage(),
|
||||
limits: { fileSize: 15 * 1024 * 1024 },
|
||||
});
|
||||
|
||||
function isPdfFile(file: { mimetype: string; originalname: string }): boolean {
|
||||
const name = file.originalname.toLowerCase();
|
||||
return (
|
||||
file.mimetype === 'application/pdf' ||
|
||||
name.endsWith('.pdf')
|
||||
);
|
||||
}
|
||||
|
||||
function isJsonFile(file: { mimetype: string; originalname: string }): boolean {
|
||||
const name = file.originalname.toLowerCase();
|
||||
return (
|
||||
file.mimetype === 'application/json' ||
|
||||
name.endsWith('.json')
|
||||
);
|
||||
}
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.post(
|
||||
'/statement',
|
||||
upload.single('file'),
|
||||
asyncHandler(async (req, res) => {
|
||||
const result = await importStatement(req.body);
|
||||
const file = req.file;
|
||||
if (!file) {
|
||||
res.status(400).json({
|
||||
error: 'BAD_REQUEST',
|
||||
message: 'Файл не загружен',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isPdfFile(file) && !isJsonFile(file)) {
|
||||
res.status(400).json({
|
||||
error: 'BAD_REQUEST',
|
||||
message: 'Допустимы только файлы PDF или JSON',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let body: unknown;
|
||||
|
||||
if (isPdfFile(file)) {
|
||||
const converted = await convertPdfToStatement(file.buffer);
|
||||
if (isPdfConversionError(converted)) {
|
||||
res.status(converted.status).json({
|
||||
error: converted.error,
|
||||
message: converted.message,
|
||||
});
|
||||
return;
|
||||
}
|
||||
body = converted;
|
||||
} else {
|
||||
try {
|
||||
body = JSON.parse(file.buffer.toString('utf-8'));
|
||||
} catch {
|
||||
res.status(400).json({
|
||||
error: 'BAD_REQUEST',
|
||||
message: 'Некорректный JSON-файл',
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const result = await importStatement(body);
|
||||
if (isValidationError(result)) {
|
||||
res.status((result as { status: number }).status).json({
|
||||
error: (result as { error: string }).error,
|
||||
|
||||
Reference in New Issue
Block a user