๊ธฐ์กด์ ๋ค๋ฅธ ์ฌ๋์ด ํ๋ ํ๋ก์ ํธ๋ฅผ ๋งก๊ฒ ๋์์ง๋ง ๋ง์ ๊ธฐ๋ฅ๋ค์ด ์ ๋๋ก ๊ตฌํ๋์ง ์์ ์ฑ๋ก ๋ฐฉ์น๋์ด ์์๋ค. ๊ทธ ์ค ์ด๋ฒ์ ํด๋ณผ ์ฃผ์ ๋ OCR์ด๋ค.
OCR์ด๋?
OCR์ Optical Character Recognition์ ์ฝ์๋ก, ๊ดํ ๋ฌธ์ ์ธ์์ ์ฝ์์ด๋ค. OCR์ ์ด๋ฏธ์ง์์ ๋ฌธ์(ํ ์คํธ)๋ฅผ ์ถ์ถํ๋ ๊ธฐ์ ๋ก, ์ค์บ๋ ๋ฌธ์, ์ฌ์ง, ์๊ธ์จ ๋ฑ์ ์ด๋ฏธ์ง๋ฅผ ๋ถ์ํ์ฌ ๊ธฐ๊ณ๊ฐ ์ฝ์ ์ ์๋ ๋ฌธ์ ๋ฐ์ดํฐ๋ก ๋ณํํ๋ ๊ธฐ์ ์ด๋ค.
OCR์ ์๋ฆฌ
OCR์ ํฌ๊ฒ ์ ์ฒ๋ฆฌ โ ๋ฌธ์ ์ธ์ โ ํ์ฒ๋ฆฌ ๊ณผ์ ์ผ๋ก ๋๋๋ค.
์ ์ฒ๋ฆฌ (Preprocessing)
์ด๋ฏธ์ง๋ฅผ OCR๋ก ๋ถ์ํ๊ธฐ ์ ์ ์ต์ ํํ๋ ๊ณผ์ ์ด๋ค. ํด๋น ๊ณผ์ ์์๋
- ์ด์งํ(Binary Thresholding): ์ปฌ๋ฌ ๋๋ ๊ทธ๋ ์ด์ค์ผ์ผ ์ด๋ฏธ์ง๋ฅผ ํ๋ฐฑ์ผ๋ก ๋ณํํ์ฌ ๋ช ํํ ์ค๊ณฝ์ ์์ฑ
- ๋ ธ์ด์ฆ ์ ๊ฑฐ(Denoising): ๋ฐฐ๊ฒฝ ์ ๊ฑฐ, ํ๋ฆฐ ์ด๋ฏธ์ง ๊ฐ์ , ๋ฌธ์์ ๋ช ํ๋ ์ฆ๊ฐ
- ๊ธฐ์ธ๊ธฐ ๋ณด์ (Deskewing): ๋ฌธ์๊ฐ ๊ธฐ์ธ์ด์ง ๊ฒฝ์ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ ฌ
- ์์ญ ๋ถํ (Segmentation): ๋ฌธ์์์ ํ ์คํธ๊ฐ ํฌํจ๋ ์์ญ์ ์ฐพ์ ๊ฐ๋ณ ๋ฌธ์ ๋๋ ๋จ์ด๋ก ๋ถํ
๋ฑ์ ์ํํ๋ค.
๋ฌธ์ ์ธ์ (Character Recognition)
์ ์ฒ๋ฆฌ๊ฐ ๋๋ ์ด๋ฏธ์ง์์ ๋ฌธ์๋ฅผ ์ธ์ํ๋ ๋จ๊ณ๋ก, ํจํด ๋งค์นญ ๋ฐฉ์๊ณผ ๊ธฐ๊ณ ํ์ต ๋ฐฉ์์ด ์๋ค.
- ํจํด ๋งค์นญ (Template Matching)
- ๋ฏธ๋ฆฌ ์ ์ฅ๋ ๊ธ์ ํจํด๊ณผ ๋น๊ตํ์ฌ ๋ฌธ์ ์๋ณ
- ํฐํธ๊ฐ ์ผ์ ํ๊ณ ๊ท์น์ ์ธ ๋ฌธ์์์ ํจ๊ณผ์
- ๋ค์ํ ํฐํธ๋ ์๊ธ์จ ์ธ์์๋ ์ฝํจ
- ๊ธฐ๊ณ ํ์ต (Machine Learning & Deep Learning)
- ์ด๋ฏธ์ง ๋ฐ์ดํฐ๋ฅผ ํ์ตํ ๋ชจ๋ธ์ด ๋ฌธ์๋ฅผ ํ๋ณ
- ๋ฅ๋ฌ๋ ๊ธฐ๋ฐ์ CNN(Convolutional Neural Network)๊ณผ RNN(Recurrent Neural Network)์ ํ์ฉํ์ฌ ๋ฌธ๋งฅ๊น์ง ๋ถ์ ๊ฐ๋ฅ
- ๋ค์ํ ํฐํธ ๋ฐ ์๊ธ์จ ์ธ์์ ๊ฐํจ
ํ์ฒ๋ฆฌ (Postprocessing)
์ธ์๋ ํ ์คํธ๋ฅผ ๋ ์ ์ ํ๊ณ ์ ํ๋๋ฅผ ๋์ด๋ ๊ณผ์ ์ด๋ค.
- ๋ฌธ๋งฅ ๋ถ์(Context Analysis): ๋ฌธ์ฅ ๊ตฌ์กฐ๋ฅผ ๊ณ ๋ คํ์ฌ ์ค๋ฅ ์์
- ์ฌ์ ๊ธฐ๋ฐ ๋ณด์ (Dictionary Correction): ๋ฌธ๋ฒ์ ์ผ๋ก ์ด์ํ ๋จ์ด๋ฅผ ์ฌ์ ์ ๋ง์ถฐ ์์
- ๊ธ์ ์ฐ๊ฒฐ ๋ฐ ๋์ด์ฐ๊ธฐ ๋ณด์
๋ฑ์ ๊ณผ์ ์ ํตํด ํ ์คํธ์ ํ์ง์ ๋ณด๋ค ๋์ด๋ ๊ณผ์ ์ ๊ฑฐ์น๋ฉฐ ๊ฒฐ๊ณผ๋ฌผ์ด ๋์ค๊ฒ ๋๋ค.
Clova OCR
OCR ๋ชจ๋ธ์๋ ์ฌ๋ฌ ๊ฐ์ง๊ฐ ์์ง๋ง, ์ด๋ฒ์ ์ฌ์ฉํด๋ณผ ๊ฒ์ NCP(Naver Cloud Platform)์ OCR ๋ชจ๋ธ์ด๋ค.
CLOVA OCR์ ์ ์ธ๊ณ์ ์ผ๋ก ๊ฐ์ฅ ๊ถ์ ์๋ ๊ธ๋ก๋ฒ ์ฑ๋ฆฐ์ง์ธ ICDAR 2019 4๊ฐ ๋ถ์ผ์์ 1์, CVPR ๋ฐ ICCV ๊ตญ์ ํํ ๋
ผ๋ฌธ์ผ๋ก ์ ์ ๋๋ ๋ฑ ๋
๋ณด์ ์ธ ๊ธฐ์ ๋ ฅ์ ์๋ํฉ๋๋ค. ํนํ ์ฝ๋ ์์์ ๋ฐฉํฅ์ ์ถ์ ํด ์ด๋ฏธ์ง ์ ๋ฌธ์๋ฅผ ์ธ์ํ๋ฉฐ, ๊ณก์ ์ผ๋ก ๋ฐฐ์ด๋๊ฑฐ๋ ๊ธฐ์ธ์ด์ง ๋ฌธ์, ํ๊ธฐ์ฒด๊น์ง ์ธ์ํ ์ ์์ด ๋์ฑ ์ ํํ๊ฒ ๋ฐ์ดํฐ๋ฅผ ์ถ์ถํ ์ ์์ต๋๋ค.
๋ผ๊ณ ์๋น์ค์ ์ ํํ ๋ฐ์ดํฐ ์ถ์ถ ๋ฅ๋ ฅ์ ๊ฐ์กฐํ๋ค.
์ฌ์ค ์ฐ๊ฒ ๋ ์ด์ ๋ ๋ด๊ฐ NCP ํฌ๋ ๋ง์ด ๋ง์ด ๋จ์์์ด๊ธฐ๋ ํ์ง๋ง.. ์ถ๊ฐ์ ์ผ๋ก Document OCR์ด๋ผ๋ ๊ธฐ๋ฅ์ ์ง์ํ๋๋ฐ, ํด๋น ๊ธฐ๋ฅ์ ๋๋์ ํ์ต ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก CLOVA AI ๊ธฐ์ ์ ์ ์ฉํ์ฌ ํนํ ๋ฌธ์์ ์ฃผ์ ์ ๋ณด๋ฅผ ์ถ์ถํด๋ด๋ ๋ฅ๋ ฅ์ ๊ฐ์ง๊ณ ์๋ค. Document OCR์๋ ์์์ฆ, ์ ์ฉ์นด๋, ์ฌ์ ์๋ฑ๋ก์ฆ ๋ฑ๋ฑ ํ์คํ๋ ๋ฌธ์ ์์์ ๋ํด์ ๋ฏธ๋ฆฌ document๋ฅผ ์ง์ ํ๊ณ , ํด๋น document์ ํนํ๋ ๋ชจ๋ธ์ ์ฌ์ฉํ์ฌ ๋ฌธ์๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์ ๋ณด๋ค ์ ๋ขฐ์ฑ์ด ๋์ ๊ฒ ๊ฐ์์ ์ ํํ ์ด์ ๋ ์๋ค.
๋ฌผ๋ก ๋์ ๋ด์ผํ๋ค
๊ธฐ๋ณธ ์๊ธ์ด ์๋ค๋๊ฒ ์ด์ง ํน๋ฐ์ง๋ง, ๊ทธ๋งํผ์ ๊ฐ์ด์น๋ฅผ ํ๋ค๋ฉด์ผ ํฌ๋ ๋ง ์ฌ์ฉํด๋ ์๊ด์ ์์ ๊ฒ ๊ฐ๋ค.
Clova OCR์ Document OCR์ ์ฌ์ฉํ๋ ค๋ฉด ๋ฏผ๊ฐ ์ ๋ณด๊ฐ ๋ง์ document๋ค์ ์ฒ๋ฆฌํ๋ค ๋ณด๋ ์ฌ์ ์น์ธ์ด ํ์ํ๋ค. ๋ฏธ๋ฆฌ ์ ์ฒญํด๋๋ ๊ฒ์ ์ถ์ฒํ๋ค.

์ ์ฒญ์ ํ ๋ค API Gateway๋ ํ๋ ์ด์ด ํด๋ผ์ด์ธํธ ์ธก์์ ์ฌ์ฉํ ์ ์๋๋ก ํด์ฃผ์๋ค.

๋ค๋ฅธ ํด๋ผ์ฐ๋ ์๋น์ค๋ ๋ง์ฐฌ๊ฐ์ง๊ฒ ์ง๋ง, ํด๋ผ์ฐ๋ ์๋น์ค์ API๋ฅผ ์ฌ์ฉํ ๋๋ ๋จผ์ ์์ฒญ ๋ฐ๋์ ์๋ต ์ฝ๋ ๋ฑ์ ๋ํด์ ๋ฏธ๋ฆฌ ์์งํ๊ณ ์๋ ๊ฒ์ด ์ข๋ค. ํ์ ์ ์ ๊ณตํ์ง ์๊ธฐ ๋๋ฌธ์ ๋ณด๋ฉด์ ํด๋จผ ์๋ฌ๊ฐ ๋์ง ์๋๋ก ํด์ผํ๋ค. ๋ํ ๋จผ์ postman ๋ฑ์ผ๋ก API๋ฅผ ํ ์คํธํ ํ์ ์ ๋๋ก ์๋ํ๋์ง ํ์ธํ๊ณ ์ฌ์ฉํ ๊ฒ์ ์ถ์ฒํ๋ค. ํด๋ผ์ด์ธํธ์์ ์๋ฌ ์ฒดํฌํ๋ ๊ฒ๋ณด๋ค postman์์ ๋ณด๋๊ฒ ํจ ๋ณด๊ธฐ ํธํ๋ค.

๊ทผ๋ฐ ์ด์ํ๊ฒ requestId์ UUID ๋ฃ์ผ๋ผ ํด์ postman์์ ์ง์ํ๋ randomUUID๋ฅผ ๋ฃ์๋๋ฐ 0011 ์ฝ๋๋ก ๋ ์๋ฌ๊ฐ ๋ด๋ค
๊ณ์ ์ฌ์ง ์ค๋ฅ์ธ๊ฐ ํ๊ณ ์ฐพ์๋ดค์ง๋ง ๊ฒฐ๊ตญ requestId๋ฅผ ์์ ๊ฐ์ด UUID๊ฐ ์๋ ์์์ ๊ฐ์ผ๋ก ํด์ฃผ๋ ๋์๋ค(?)
UUID๋ผ๊ณ ํ์ง๋ฅผ ๋ง๋๊ฐ..
๊ทธ๋ฌ๋ ์ต๋ํ API ์์ฒญ ์์๋ฅผ ๋ณด๊ณ ๋ฐ๋ผํ ์ ์๋ ๋ถ๋ถ์ ๋ฐ๋ผํ๋ ๊ฒ์ ์ถ์ฒํ๋ค.
API ์ค๊ณํ๊ธฐ - ์๋ฌ ์ฒ๋ฆฌ๋ฅผ ๊ณ๋ค์ธ
Postman์ผ๋ก ํ ์คํธ๊น์ง ๋์๋ค๋ฉด ์๋ต ๊ฐ์ฒด๊ฐ ์ด๋ป๊ฒ ๋์ด์๋์ง clova api ๋ฌธ์์ ๋น๊ตํ๋ฉด์ ํ์ธ๊น์ง ๋์์ ๊ฒ์ด๋ค. ๊ทธ๋ ๋ค๋ฉด ์ด์ ์ด api๋ฅผ ์ด๋ป๊ฒ ํธ์ถํ๊ณ , ์ด๋ป๊ฒ ์์์ฆ ์ธ์ฆ์ ์ผ๋ฌด์ง๊ฒ ํ ์ ์์๊น๋ฅผ ์๊ฐํด๋ด์ผ ํ๋ค.
์๋๋๋ก api ํธ์ถ์ด๋ผ ํจ์
function receiptValidation() {
const {data} = axios.post(API_URL, BODY);
return data
}์ด๋ฐ ์์ผ๋ก ์์ฒญ์ ๋ณด๋ด๊ฑฐ๋
function receiptValidation() {
try{
const {data} = axios.post(API_URL, BODY);
return data
}catch(error){
throw error;
}
}์ด๋ฐ ์์ผ๋ก api ํธ์ถ ํจ์์๋ try-catch๋ฌธ์ ์ฌ์ฉํ ๊ฒ์ด๋ค.
ํ์ง๋ง http ์์ฒญ์ ํ๋ ํจ์์์ try-catch๋ฌธ์ ๊ฑธ๊ณ ๋ค์ ๋์ง๋ ์ฝ๋๋ ๊ทธ๋ ๊ฒ ์ข์ ์ฝ๋๊ฐ ์๋๋ผ๊ณ ์๊ฐํ๋ค.
์๋๋ฉด ๋๋ถ๋ถ ํด๋น ํจ์๋ฅผ importํ ๋ค์ ํด๋น ํจ์๋ฅผ ์คํ์ํค๋ ๋ถ๋ถ์์๋ try-catch๋ฅผ ํตํด ์๋ฌ ์ ํ๋ฅผ ์ก์์ค์ผ ํ ํ
๋ฐ ๊ทธ๋ ๊ฒ ๋๋ฉด http ์์ฒญ๋ถ์์ ์คํ๋ ํจ์์ catch๋ฌธ์ ๊ทธ์ ๋ฐ์์ ๋ค์ ๋์ง๋ ์ญํ ๋ฐ์ ๋์ง ์๋๋ค.
๊ณต๋์ง๊ธฐ ๋์ด๋ฅผ ๋๋ช
์ด์ ํ๊ณ ์๋ค๊ฐ ํ๋ช
์ด ์ฌ์ด์ ๋ผ์ด ๋ค์ด๊ฐ์ ๊ณต์ ๊ทธ์ ๋ฐ์๋ค๊ฐ ๋ค์ ์ฃผ๋..๋๋์ด๋๊น..
๋ฌผ๋ก ์ ๊ธฐ์์ ๊ทธ์ ๋์ง๋๊ฒ ์๋๋ผ ๊ฐ๊ฐ ์๋ฌ ๋ก๊น ์ ํด์ callstack์ ํ์ธํ๊ธฐ ์ํด์๋ผ๋ ์ฉ๋๋ก๋ ์ฐ์ด๋ ๊ฒ ๊ฐ์ง๋ง ๋๋ ๊ตณ์ด ๊ทธ๋ ๊ฒ ํด์ผํ๋ ์ถ์๋ค.

์ถ๊ฐ์ ์ผ๋ก ์ฌ๊ธฐ์์๋ http ์์ฒญ์ ๋ ๋ ธ์ ๋, Bad Request๋ผ๋๊ฐ 400๋ฒ๋ ์๋ฌ์ ํด๋นํ๋ ๊ฒ๋ค์ ์๋ฌ๋ก ๋์์ค์ง๋ง clova ocr์ด ์ฌ์ง์ ์ธ์ํ๊ณ ์๋ต์ ๋ณด๋ด๋ ๊ณผ์ ์์ ์ฌ์ง์ด ์ ๋๋ก ์ธ์๋์ง ์์ ์๋ฌ์ ๊ฐ์ ๋ถ๋ถ์ ์ ์์ ์ธ ์๋ต์ ์ด๋ฏธ์ง ๊ฐ์ฒด์ inferResult๋ก ์ค๊ฒ ๋๋ค.

๋ฐ๋ผ์ ์ด๋ ๊ฒ ์ ๋๋ก ์ธ์์ด ๋ ๊ฒฝ์ฐ์ ๋์ง ์์ ๊ฒฝ์ฐ๋ฅผ ๋๋์ด ๊ฐ๊ฐ ์๋ฌ์ฒ๋ฆฌ๋ฅผ ํด์ค์ผ ํ๋ค.
์ปค์คํ ์๋ฌ๋ก ์๋ฌ ํธ๋ค๋งํ๊ธฐ
๋ด๊ฐ ์ ํํ ์๋ฌ ํธ๋ค๋ง์ axiosError์ ์ปค์คํ
์๋ฌ๋ฅผ ํผํฉํ ๋ฐฉ์์ด๋ค.
gateway api๋ก ๋ณด๋ธ ์์ฒญ์์ 400๋ฒ๋ ์๋ฌ๊ฐ ์ค๊ฒ ๋๋ฉด, 400๋ฒ๋ ์๋ฌ๊ฐ ์จ๋ค. ์ด๋ ์์ฐ์ค๋ฝ๊ฒ axiosError๋ก catch์์ ์กํ๊ฒ ๋๋ค.
ํ์ง๋ง ์์์ ๋งํ ๊ฒ์ฒ๋ผ ์๋ต์ ์ ์์ ์ผ๋ก ์ค์ง๋ง ์ด๋ฏธ์ง ์ธ์์ ์คํจํ ๊ฒฝ์ฐ๋ผ๋ฉด?
์ด ๊ฒฝ์ฐ์ ๊ทธ๋ฅ Error๋ก ๋ณด๋ด๊ฒ ๋๋ค๋ฉด ์ด ์๋ฌ๊ฐ ์ด๋ฏธ์ง ์ธ์์ ์คํจํด์ ๋๋ ์๋ฌ์ธ์ง, ์ฝ๋๋จ์์ ๋ญ๊ฐ ์๋ชป๋ผ์ ๋์ค๋ ์๋ฌ์ธ์ง ์ ๋๋ก ๊ตฌ๋ถํ๊ธฐ ์ฝ์ง ์๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์๋ฌ๋ฅผ ๋ณด๋ค ๋ช
ํํ ํ๊ธฐ ์ํด์ ๋๋ ์ปค์คํ
์๋ฌ๋ฅผ ์ถ๊ฐํ๋ ๋ฐฉ์์ ์ ํํ๋ค.
class Error {
constructor(message) {
this.message = message;
this.name = "Error"; // (name์ ๋ด์ฅ ์๋ฌ ํด๋์ค๋ง๋ค ๋ค๋ฆ
๋๋ค.)
this.stack = <call stack>; // stack์ ํ์ค์ ์๋์ง๋ง, ๋๋ค์ ํ๊ฒฝ์ด ์ง์ํฉ๋๋ค.
}
}๊ธฐ์กด ์๋ฌ๋ ์ด๋ฐ ์์ผ๋ก ๊ตฌ์ฑ๋์ด ์๋ค.
๋๋ ํด๋น ์๋ฌ๋ฅผ ์์๋ฐ์ ์๋ก์ด ์ปค์คํ ์๋ฌ๋ฅผ ๋ง๋ค๋ฉด ๋๋ค. ๋ฌผ๋ก ์๋ฌ๋ฅผ ๊ตณ์ด ์์๋ฐ์ง ์์๋ ๋์ง๊ธฐ๋ง ํ๋ฉด catch์์ ์กํ๊ธด ํ์ง๋ง, ํด๋นํ๋ ๋ถ๋ถ์ด ์๋ฌ๋ผ๋ ๊ฒ์ ๋ช ํํ ํ ์ ์์ผ๋ฉฐ ๊ฐ์ง๊ณ ์๋ Error์ stack๊ณผ ๊ฐ์ ์์ฑ๋ค๋ ๋ชจ๋ ์๋ฌ๋ฅผ ์ถ์ ํ๋๋ฐ ํ์ํ ์์์ด๊ธฐ ๋๋ฌธ์ ์์ํด์ฃผ์๋ค.
export class ValidationError extends Error {
constructor(message: string) {
super(message);
this.name = 'ValidationError';
}
}๊ทธ๋ผ ์ด์ ์ด๊ฑธ ๊ฐ์ง๊ณ ์ด๋ป๊ฒ ์ฌ์ฉํ ์ ์์๊น? ๋จผ์ ocr ํจ์์ ๊ฒ์ฆ๋ถ๋ฅผ ๋ณด์.
const REQUEST_ID = 'hospitalReceiptValidation';
const MIN_HOSPITAL_PRICE = 1000;
export const receiptValidationCheck = async (
base64EncodedImage: string,
hospitalName: string,
) => {
const config = {
headers: {
'Content-Type': 'application/json',
'X-OCR-SECRET': NAVER_CLOUD_PLATFORM_OCR_SECRET,
},
};
const { data } = await axios.post(
NAVER_CLOUD_PLATFORM_OCR_URL,
{
version: 'V2',
requestId: REQUEST_ID,
timestamp: Date.now(),
images: [
{
format: 'jpg',
name: 'ocrImage',
data: base64EncodedImage,
},
],
enableTableDetection: false,
},
config,
);
if (
data.images[0].inferResult === 'FAILURE' ||
data.images[0].inferResult === 'ERROR'
)
throw new ValidationError(
'์ด๋ฏธ์ง ํ์ธ์ด ์ ๋๋ก ๋์ง ์์์ต๋๋ค. ๋ค์ ์ฐ์ด์ฃผ์ธ์.',
);
if (
data.images[0].receipt.result.storeInfo.name === hospitalName &&
+data.images[0].receipt.result.totalPrice.price.formatted >= MIN_HOSPITAL_PRICE
)
return +data.images[0].receipt.result.totalPrice.price.formatted;
throw new ValidationError('์์์ฆ ๊ฒ์ฆ์ ์คํจํ์ต๋๋ค. ๋ค์ ์ฐ์ด์ฃผ์ธ์.');
};์ฌ๊ธฐ์ base64Encoded ์ด๋ฏธ์ง์ ๋ํ ์ ํจ์ฑ ๊ฒ์ฌ๋ ํด๋น ํจ์๋ฅผ Promise Chaining์ ํตํด ๋๊ฒจ์ฃผ๋ ๊ณผ์ ์์ ์งํ๋๋ฉฐ, hospitalName์ ๋ํ ์ ํจ๊ฐ ๋ํ ๋ฏธ๋ฆฌ ๊ฒ์ฆํ๊ธฐ ๋๋ฌธ์ ๋ฐ๋ก ๊ฒ์ฆ์ ํด๋น ํจ์์์๋ ์์ผ์ฃผ์ง ์์๋ค.
header์ ํ์ํ ๊ฐ์ ๋ฃ์ด์ฃผ๊ณ post์ ํ์ํ ๊ฐ๋ค์ ๋ฃ์ด์ฃผ์๋ค.
๊ทธ๋ฆฌ๊ณ axios๋ฅผ ํตํด post ์์ฒญ์ ๋ณด๋ด๊ฒ ๋๋ฉด data๊ฐ ์ฌ ๊ฒ์ด๋ผ ๊ฐ์ ํ๋ค. data๊ฐ ์ค์ง ์์ data is undefined์ ๊ฐ์ ์ค๋ฅ๊ฐ ๋จ๊ฒ ๋๋ค๋ฉด ํด๋น ์ค๋ฅ๋ ๋น์ ์์ ์ธ ์ค๋ฅ๋ก ๊ฐ์ฃผํ๋ค. gateway api์ชฝ์์ ๋ณด๋ด๋ ์ค๋ฅ๋ axiosError๋ก ๋์ ธ์ง ๊ฒ์ด๊ณ ๊ทธ๊ฒ ์๋๋ผ๋ฉด ๊ฐ์ฒด๊ฐ ๋ฌด์กฐ๊ฑด ์ค๊ฒ ๋์ด์๋๋ฐ ๋ง์ฝ์ ์ค์ง ์๋ ์ค๋ฅ๋ ๋น์ ์์ ์ธ ์ค๋ฅ์ด๊ธฐ ๋๋ฌธ์ด๋ค. ๋ฐ๋ผ์ ์ด๋ฐ ์ค๋ฅ๋ ๊ทธ๋ฅ ์์ธ์ ์ ์ ์๋ ์ค๋ฅ๋ก ๋ณด๊ณ catch๋จ์์ ์ ์ ์๋ ์ค๋ฅ๋ผ๊ณ ๋ด๋ณด๋ด๊ฒ๋ ํ๋ค.
๋ด๊ฐ ValidationError๋ฅผ ๊ฑด ๊ฒฝ์ฐ๋ ๋ ๊ฐ์ง ๊ฒฝ์ฐ์ด๋ค.
- image์ InferResult ๋ก ์ค๋ ๊ฐ์ด
ERROR์ด๊ฑฐ๋FAILURE์ผ ๋- ์ธ์์ด ์คํจํ์ ๋ ์ค๋ ์ค๋ฅ๋ฅผ ์ก์์ ๋์ง๋ค
- ์ด ๊ฒฝ์ฐ์๋ ์ธ์์ด ์ ๋๋ก ๋์ง ์์๋ค๋ ๊ฒ์ด ๋ช ํํ๊ธฐ ๋๋ฌธ์ ๋ค์๊ธ ์ฌ์ง์ ์ฐ๋๋ก ์ ๋ํ๋ฉด ๋๋ค.
- ๋ณ์ ์ด๋ฆ๊ณผ ๊ฐ๊ฒฉ์ ๋ํ ์ ํจ์ฑ ๊ฒ์ฌ๊ฐ ๋๋๊ณ ๋ ์์ง return๋์ง ์์์ ๊ฒฝ์ฐ
- ํด๋น ๊ฒฝ์ฐ๋ ๋ญ ์ด๋ป๊ฒ ๋๋ ์ธ์ ํ์ ์ ๋๋ก ์ ํจ์ฑ ๊ฒ์ฌ๊ฐ ๋์ง ์์ ๊ฒฝ์ฐ๋ผ๊ณ ํ๋จํ๋ค.
- ๋ณ์์์ 1000์ ์ดํ ๋์์ ๋
- ๋ณ์ ์ด๋ฆ์ด ์ผ์นํ์ง ์์ ๋
- ์ ๊ฒฝ์ฐ๊ฐ ์๋์ throw๋ฌธ์ผ๋ก ๊ฐ ๊ฒ์ด๋ค. ์ฌ๊ธฐ๊น์ง ์ค๊ณ ๋ ์๋๋ก ๊ฐ๊ฒ ๋๋ฉด ๊ฒ์ฆ์ด ์ ๋๋ก ๋์ง ์์๋ค๋ ์๋ฏธ์ด๊ธฐ ๋๋ฌธ์ ๋ง์ง๋ง์
ValidationError๋ฅผthrow์์ผ์ฃผ์๋ค.
- ํด๋น ๊ฒฝ์ฐ๋ ๋ญ ์ด๋ป๊ฒ ๋๋ ์ธ์ ํ์ ์ ๋๋ก ์ ํจ์ฑ ๊ฒ์ฌ๊ฐ ๋์ง ์์ ๊ฒฝ์ฐ๋ผ๊ณ ํ๋จํ๋ค.
ํด๋น ์ค๋ฅ๋ค์ ๋ด๊ฐ ์ธ์งํ๋ ์์ธ์ํฉ์ด๊ธฐ ๋๋ฌธ์ ๋ฉ์ธ์ง๋ฅผ ์ง์ ๋ฃ์ด์ค์ผ๋ก์จ ํด๋น ์๋ฌ์ ๋ฉ์ธ์ง๋ฅผ ๊ทธ๋๋ก ๋ชจ๋ฌ๋ก ๋์ ๋ณด๋ด๋ ๋๋๋ก ํ์๋ค.
ํ์ง๋ง ์ด์ธ์ ๊ฒฝ์ฐ๋ ๋ด๊ฐ ์์ํ์ง ๋ชปํ๋ ์์ธ ์ํฉ์ด๊ธฐ ๋๋ฌธ์ ์ด๋ฐ ๋ถ๋ถ์ ์ค๋ฅ ๋ฉ์ธ์ง๋ฅผ ๊ทธ๋๋ก ๋ชจ๋ฌ์ ๋์์ฃผ๊ฒ ๋๋ค๋ฉด ์ฌ์ฉ์๋ ์ด๊ฒ ๋ฌด์จ ๋ง์ด์ง? ์ถ์ ๊ฒ์ด๋ค.
๊ทธ๋ฌ๋ฏ๋ก ๋ค๋ฅธ ์๋ฌ์ ๋ํด์๋ ํต์ผ๋ ์์์น ๋ชปํ ์ค๋ฅ ์๋ด ๋ชจ๋ฌ์ ๋์์ฃผ๋ฉด ๋๋ค.
try {
...
} catch (error) {
if (error instanceof ValidationError) {
pushError(error.message);
} else if (axios.isAxiosError(error)){
pushError(
'์๋ฒ์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค. ๋ค์ ์๋ํด ์ฃผ์ธ์.',
);
} else{
pushError(
'์์์น ๋ชปํ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค. ์ง์๋๋ค๋ฉด ๊ณ ๊ฐ์ผํฐ์ ๋ฌธ์ํด์ฃผ์ธ์.',
);
}
}์ด๋ฐ ์์ผ๋ก ์๋ฌ ์ฒ๋ฆฌ๋ฅผ ํ๊ฒ ๋๋ฉด ๋ณด๋ค ์ธ๋ถ์ ์ผ๋ก ์๋ฌ๋ฅผ ๊ด๋ฆฌํ ์ ์๊ฒ ๋๊ณ , ์ด๋ฅผ ํตํด ๋ณด๋ค ๋์ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํ ์ ์๋ค!
ํ๊ณ
์ฌ์ค ์ด๊ฑด ๋ฆฌํฉํ ๋ง์ด ์๋๋ผ ์ฒ์๋ถํฐ ๋ค์ ์ง ์ฝ๋๊ฐ ์ข ๋ ๋ง๋ ํํ๊ฐ๊ธฐ๋..
OCR์ ๋์
ํ๊ณ , ๊ฒ์ฆ ๊ณผ์ ์ ๋ค์ ๋ฆฌํฉํ ๋ง ํ๋ฉด์ ์ฝ๋๋ฅผ ๋ดค์ ๋ ์๋ ์๋ ์๋ฌด์๊ฐ์์ด ๊ทธ์ ๋ณด๊ธฐ๋ง ํ์๋๋ฐ ์ด์ ๋ ๊ทธ๋๋ ์ฝ๋์ ๋ญ๊ฐ ๋ถ์กฑํ ๊น๋ฅผ ๋ง์ด ์๊ฐํ๋ฉด์ ๋ณด๋ ๊ฒ ๊ฐ๋ค.
ํนํ ์ค์ ๋ก ์ด์๋ ์๋น์ค์ธ ๋งํผ, ์์ธ ์ฒ๋ฆฌ๋ ์์ ์ฒ๋ผ ๋ฌด์ง์ฑ์ผ๋ก catch๋ฌธ์ ์ฝ์๋ง ์ฐ๋ ํ์๋ฅผ ํ์ง ์๊ฒ ๋์๋ค. ์ฌ์ฉ์์๊ฒ ๋ํ ์์ธ์ ๋ํด ์๋ด๋ฅผ ํ ์ ์์ด์ผ ์ข์ ์ฌ์ฉ์๊ฒฝํ์ ์ ๊ณตํ ์ ์์ผ๋ฉฐ ๋ค๋ฅธ ์ฌ๋๋ค ๋ํ ํด๋น ์ฝ๋๋ฅผ ์ ์ง๋ณด์ ํ ์๋ ์๋ค๊ณ ์๊ฐํ๋ค๋ณด๋ ์ฌ๋ฌ๊ฐ์ง ๋ฐฉ์์ ์๊ฐํ๊ฒ ๋๊ณ , ์ด๋ ๊ฒ ๊ณ ๋ฏผํ๋ ๊ณผ์ ์ ํตํด ๋ณด๋ค ์ฝ๋์ ํ์ง์ด ํฅ์๋๋ค๊ณ ์๊ฐํ๋ค.
ํญ์ UX์ DX๋ฅผ ๋ชจ๋ ๊ณ ๋ คํ๋ฉด์ ์ฝ๋๋ฅผ ์ง๋๋ก ์ต๊ดํํ์!