Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -217,23 +217,28 @@ const realApi = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 영수증 OCR (백엔드가 Google Vision 호출 → 전체 텍스트 반환) — AI 폴백용
|
// 영수증 OCR (백엔드가 Google Vision 호출 → 전체 텍스트 반환) — AI 폴백용
|
||||||
|
// suppressNetError: runOcr 이 자체 formError 로 안내하므로 전역 배너 억제
|
||||||
ocrReceipt(blob) {
|
ocrReceipt(blob) {
|
||||||
const fd = new FormData()
|
const fd = new FormData()
|
||||||
fd.append('image', blob, 'receipt.jpg')
|
fd.append('image', blob, 'receipt.jpg')
|
||||||
return http.post('/account/ocr/receipt', fd, {
|
return http.post('/account/ocr/receipt', fd, {
|
||||||
headers: { 'Content-Type': 'multipart/form-data' },
|
headers: { 'Content-Type': 'multipart/form-data' },
|
||||||
timeout: 30000,
|
timeout: 30000,
|
||||||
|
suppressNetError: true,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
// 영수증 AI 구조화 (Claude Vision) — 금액·상호·날짜·분류·계좌를 한 번에. 사용자 후보 목록을 함께 전달
|
// 영수증 AI 구조화 (Claude Vision) — 금액·상호·날짜·분류·계좌를 한 번에. 사용자 후보 목록을 함께 전달
|
||||||
|
// 비전 처리가 느릴 수 있어 타임아웃 상향, 실패 시 OCR 폴백이 있으므로 전역 배너 억제
|
||||||
parseReceiptAi(blob, { categoryHints = [], walletHints = [] } = {}) {
|
parseReceiptAi(blob, { categoryHints = [], walletHints = [] } = {}) {
|
||||||
const fd = new FormData()
|
const fd = new FormData()
|
||||||
fd.append('image', blob, 'receipt.jpg')
|
fd.append('image', blob, 'receipt.jpg')
|
||||||
categoryHints.forEach((c) => fd.append('categoryHints', c))
|
// 멀티파트 파트 수 제한(Tomcat 기본 10) 회피: 후보를 각각 한 파트에 줄바꿈으로 합쳐 전송
|
||||||
walletHints.forEach((w) => fd.append('walletHints', w))
|
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, {
|
return http.post('/account/ocr/receipt-ai', fd, {
|
||||||
headers: { 'Content-Type': 'multipart/form-data' },
|
headers: { 'Content-Type': 'multipart/form-data' },
|
||||||
timeout: 30000,
|
timeout: 60000,
|
||||||
|
suppressNetError: true,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -34,8 +34,9 @@ http.interceptors.response.use(
|
|||||||
} else if (status === 403 && error.response?.data?.code === 'PREMIUM_REQUIRED') {
|
} else if (status === 403 && error.response?.data?.code === 'PREMIUM_REQUIRED') {
|
||||||
// 유료 전용 API 를 무료 회원이 호출(우회/직접 접근) — 업그레이드 안내
|
// 유료 전용 API 를 무료 회원이 호출(우회/직접 접근) — 업그레이드 안내
|
||||||
window.dispatchEvent(new CustomEvent('premium:required'))
|
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'))
|
window.dispatchEvent(new CustomEvent('net:error'))
|
||||||
}
|
}
|
||||||
return Promise.reject(error)
|
return Promise.reject(error)
|
||||||
|
|||||||
Reference in New Issue
Block a user