From e23a694675c478bd4d03b335f1a43866a14684d5 Mon Sep 17 00:00:00 2001 From: sb Date: Sun, 5 Jul 2026 14:46:44 +0900 Subject: [PATCH] =?UTF-8?q?fix(account):=20=EC=98=81=EC=88=98=EC=A6=9D=20A?= =?UTF-8?q?I=20=ED=9E=8C=ED=8A=B8=EB=A5=BC=20=EB=8B=A8=EC=9D=BC=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=EB=A1=9C=20=EC=A0=84=EC=86=A1(=EB=A9=80?= =?UTF-8?q?=ED=8B=B0=ED=8C=8C=ED=8A=B8=20=ED=8C=8C=ED=8A=B8=EC=88=98=20?= =?UTF-8?q?=EC=A0=9C=ED=95=9C=20=ED=9A=8C=ED=94=BC)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- src/api/accountApi.js | 11 ++++++++--- src/api/http.js | 3 ++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/api/accountApi.js b/src/api/accountApi.js index f112c90..e16fdf0 100644 --- a/src/api/accountApi.js +++ b/src/api/accountApi.js @@ -217,23 +217,28 @@ const realApi = { }, // 영수증 OCR (백엔드가 Google Vision 호출 → 전체 텍스트 반환) — AI 폴백용 + // suppressNetError: runOcr 이 자체 formError 로 안내하므로 전역 배너 억제 ocrReceipt(blob) { const fd = new FormData() fd.append('image', blob, 'receipt.jpg') return http.post('/account/ocr/receipt', fd, { headers: { 'Content-Type': 'multipart/form-data' }, timeout: 30000, + suppressNetError: true, }) }, // 영수증 AI 구조화 (Claude Vision) — 금액·상호·날짜·분류·계좌를 한 번에. 사용자 후보 목록을 함께 전달 + // 비전 처리가 느릴 수 있어 타임아웃 상향, 실패 시 OCR 폴백이 있으므로 전역 배너 억제 parseReceiptAi(blob, { categoryHints = [], walletHints = [] } = {}) { const fd = new FormData() fd.append('image', blob, 'receipt.jpg') - categoryHints.forEach((c) => fd.append('categoryHints', c)) - walletHints.forEach((w) => fd.append('walletHints', w)) + // 멀티파트 파트 수 제한(Tomcat 기본 10) 회피: 후보를 각각 한 파트에 줄바꿈으로 합쳐 전송 + if (categoryHints.length) fd.append('categoryHints', categoryHints.join('\n')) + if (walletHints.length) fd.append('walletHints', walletHints.join('\n')) return http.post('/account/ocr/receipt-ai', fd, { headers: { 'Content-Type': 'multipart/form-data' }, - timeout: 30000, + timeout: 60000, + suppressNetError: true, }) }, } diff --git a/src/api/http.js b/src/api/http.js index 5d33df8..65105b6 100644 --- a/src/api/http.js +++ b/src/api/http.js @@ -34,8 +34,9 @@ http.interceptors.response.use( } else if (status === 403 && error.response?.data?.code === 'PREMIUM_REQUIRED') { // 유료 전용 API 를 무료 회원이 호출(우회/직접 접근) — 업그레이드 안내 window.dispatchEvent(new CustomEvent('premium:required')) - } else if (!error.response && error.code !== 'ERR_CANCELED') { + } else if (!error.response && error.code !== 'ERR_CANCELED' && !error.config?.suppressNetError) { // 응답 자체가 없음 = 네트워크 오류(오프라인/타임아웃/서버 연결 불가). 취소 요청은 제외. + // suppressNetError: 자체 폴백/에러표시가 있는 호출(예: 영수증 AI)은 전역 배너를 띄우지 않음. window.dispatchEvent(new CustomEvent('net:error')) } return Promise.reject(error)