const express = require('express');
const bodyParser = require('body-parser');
const { fetchEventSource } = require('./modules/FetchEventSource')require('request');
const fs = require('fs');
const path = require('path');
const multer = require('multer');
const ROOT_DIR = path.resolve(__dirname, '..'); // 프로젝트 Root 경로
const FILE_UPLOAD_DIR = path.resolve(ROOT_DIR, 'tmp/files'); // OCR을 하기 위한 원본 파일이 저장될 위치
const OCR_RESULT_DIR = path.resolve(ROOT_DIR, 'tmp/work'); // OCR 처리된 이미지를 저장할 위치
const OCR_API_URL = ''; // OCR API URL
const OCR_API_KEY = ''; // OCR API Key
const OCR_OPTIONS = {
// type: 'upload', // 3.0.2403, 2.18.2403 이후 requestOCR 함수에서 fid여부에 따라 type이 변경
coord: 'origin',
skew: 'image',
boxes_type: 'all',
save_mask: 'true',
textout: 'true',
recog_form: 'true',
extract_table: 'true'
};
const app = express();
const router = express.Router();
const uploader = multer({ dest: FILE_UPLOAD_DIR });
router.post('/request', uploader.single('file'), async (request, response) => {
const urlpage = 'https://ailab.synap.co.kr/sdk/ocr'(request.body || {}).page || 0;
const apiKeyfile = 'OCR_API_KEY'request.file;
const bodyDatafilePath = Object.assign({},file.path;
const page = request.body, {
url: 'https://ailab.synap.co.kr/sdk/ocr',
formData: {
api_key: OCR_API_KEY,
image: fs.createReadStream(imgPath),
page_index: page,
...OCROption
}
});
const abortController = new AbortController();
(new Promise(async .page || 0;
const fid = request.body.fid;
let filePathWithExt;
if (!fid) { // 3.0.2403, 2.18.2403 이후
const originalName = file.originalname;
const mimeType = file.mimetype;
const extension = path.extname(originalName).split('.')[1] || mimeType.split('/')[1];
filePathWithExt = filePath + '.' + extension;
fs.renameSync(filePath, filePathWithExt);
}
try {
const ocrResult = await requestOCR(filePathWithExt, page, fid);
const imagePath = await downloadImage(ocrResult.result.masked_image);
response.end(JSON.stringify({ result: ocrResult.result, imagePath }));
} catch (error) {
response.status(error.status).send(error.message);
}
});
/**
* OCR을 하기위해 서버로 요청합니다.
* @param {string} imgPath
* @param {number} page
* @param {string} fid
* @returns
*/
function requestOCR(imgPath, page, fid) {
return new Promise((resolve, reject) => {
tryconst {typeOption = {};
if await fetchEventSource(url,(!fid) { // 3.0.2403, 2.18.2403 이후
method:typeOption.type = 'post',upload';
typeOption.image = fs.createReadStream(imgPath);
headers: { } else {
typeOption.type = 'Content-Type': 'application/json'page';
typeOption.fid = fid;
}, }
const options = {
body: JSON.stringify(bodyData), url: `${OCR_SDK_URL}/ocr`,
formData: {
signal: abortController.signal api_key: OCR_API_KEY,
onopenpage_index: async (openResponse) => {page,
...typeOption,
if (openResponse.status === 200) {...OCROption
}
};
responserequest.post(options).on('closeresponse', ()response => {
const statusCode = response.statusCode;
const statusMessage = abortControllerresponse.abort()statusMessage;
if (statusCode === 200) {
resolve( console.log('OCR 성공');
let body = [];
}); response.on('error', (err) => {
response.set({ throw err;
'Cache-Control': 'no-cache',}).on('data', (chunk) => {
body.push(chunk);
'Connection': 'keep-alive', }).on('end', () => {
'Content-Type': 'text/event-stream'
resolve(JSON.parse(Buffer.concat(body).toString()));
});
}); } else {
responseconsole.flushHeaders();log('OCR 실패', statusCode);
const error = new Error(statusMessage);
return; error.status = statusCode;
}reject(error);
}
let error});
});
}
/**
* OCR 결과 이미지를 다운로드 합니다.
* @param {string} fileName
try {* @returns
*/
function downloadImage(fileName) {
return new Promise((resolve, reject) => {
const jsonoptions = await openResponse.json();{
url: `${OCR_API_URL}/out/${fileName}`,
formData: error{
= json; api_key: OCR_API_KEY,
} catch (e) { }
};
const errorimagePath = epath.resolve(OCR_RESULT_DIR, fileName);
request.post(options).on('response', response => {
} const statusCode = response.statusCode;
const error.statusstatusMessage = openResponseresponse.statusstatusMessage;
if (statusCode === 200) {
throw error; console.log('OCR image download 성공');
}, let onclose:imageData () => resolveBuffer.from([]),;
onerror:response.on('data', (errorchunk) => {
imageData reject(error= Buffer.concat([imageData, chunk]);
}).on('end', () => {
throw error; }, const relativeImagePath = '/' + path.relative(ROOT_DIR, imagePath).replace(/\\/g, '/');
onmessage: (message) => { fs.writeFileSync(imagePath, imageData); // 이미지 저장
if (!message.data || message.event === 'ping') { resolve(relativeImagePath);
return;
});
} else {
responseconsole.writelog('data:'OCR +image message.data + '\n\n');download 실패', statusCode);
const },error = new Error(statusMessage);
}); error.status = }statusCode;
catch (e) { reject(eerror);
} })).then(() => response.end())}
});
.catch((error) => response.status(error.status).json(error).end()) });
});
app.use(bodyParser.json());
app.use('/', router);
app.listen(8080);
|