feat: 영수증 OCR을 Google Vision(백엔드) 방식으로 전환
CI / build (push) Failing after 14m1s

- 이미지를 백엔드(/account/ocr/receipt)로 업로드 → Vision 텍스트 → 금액·날짜·상호 파싱
- 업로드 전 이미지 축소(최대 1600px JPEG), Tesseract.js 의존성 제거
- 진행률 표시 제거(인식 중…), 정확도·속도 대폭 개선

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
ByungCheol
2026-06-03 17:37:35 +09:00
parent 715dae70ab
commit 68dd926cce
5 changed files with 36 additions and 216 deletions
+7 -7
View File
@@ -2,7 +2,7 @@
import { computed, onMounted, reactive, ref } from 'vue'
import { accountApi } from '@/api/accountApi'
import IconBtn from '@/components/ui/IconBtn.vue'
import { scanReceipt } from '@/utils/receiptOcr'
import { imageToBlob, parseReceiptText } from '@/utils/receiptOcr'
import { Capacitor } from '@capacitor/core'
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera'
@@ -59,7 +59,6 @@ const formError = ref(null)
// 영수증 OCR (온디바이스)
const receiptInput = ref(null)
const ocrRunning = ref(false)
const ocrProgress = ref(0)
const ocrResult = ref(null) // { amount, date, store }
async function pickReceipt() {
ocrResult.value = null
@@ -91,11 +90,12 @@ async function onReceiptFile(e) {
}
async function runOcr(image) {
ocrRunning.value = true
ocrProgress.value = 0
ocrResult.value = null
formError.value = null
try {
const r = await scanReceipt(image, (p) => (ocrProgress.value = p))
const blob = await imageToBlob(image)
const { text } = await accountApi.ocrReceipt(blob)
const r = parseReceiptText(text)
// 추출값이 있을 때만 폼에 채움 (메모는 비어있을 때만)
if (r.amount) form.amount = r.amount
if (r.date) form.entryDate = r.date
@@ -104,8 +104,8 @@ async function runOcr(image) {
if (!r.amount && !r.date) {
formError.value = '영수증에서 정보를 충분히 인식하지 못했습니다. 직접 입력하거나 더 선명한 사진으로 다시 시도하세요.'
}
} catch {
formError.value = '영수증 인식에 실패했습니다. 다시 시도해 주세요.'
} catch (e) {
formError.value = e.response?.data?.message || '영수증 인식에 실패했습니다. 다시 시도해 주세요.'
} finally {
ocrRunning.value = false
}
@@ -541,7 +541,7 @@ onMounted(async () => {
type="button" class="receipt-btn"
:disabled="submitting || ocrRunning" @click="pickReceipt"
>📷 영수증 스캔</button>
<span v-if="ocrRunning" class="receipt-status">인식 {{ ocrProgress }}%</span>
<span v-if="ocrRunning" class="receipt-status">인식 </span>
<span v-else-if="ocrResult" class="receipt-status ok">
<template v-if="ocrResult.amount">{{ won(ocrResult.amount) }}</template>
<template v-if="ocrResult.date"> · {{ ocrResult.date }}</template>