diff --git a/src/api/accountApi.js b/src/api/accountApi.js index e16fdf0..a2f4f22 100644 --- a/src/api/accountApi.js +++ b/src/api/accountApi.js @@ -15,6 +15,10 @@ const realApi = { categoryStats({ type, year, month } = {}) { return http.get('/account/category-stats', { params: { type, year, month } }) }, + // 통계 화면 집계 → AI 재무 코멘트(유료). 실패해도 화면을 막지 않도록 전역 배너 억제 + aiComment(payload) { + return http.post('/account/ai-comment', payload, { timeout: 30000, suppressNetError: true }) + }, netWorthTrend({ months, weeks, unit } = {}) { return http.get('/account/networth/trend', { params: { months, weeks, unit } }) }, @@ -262,7 +266,7 @@ const DEMO_WRITES = new Set([ 'createRecurring', 'updateRecurring', 'removeRecurring', 'runRecurrings', 'createWallet', 'updateWallet', 'removeWallet', 'reorderWallets', 'createCategory', 'updateCategory', 'removeCategory', 'reorderCategories', 'importCategories', - 'createTag', 'updateTag', 'removeTag', 'reorderTags', 'confirmEntry', 'ocrReceipt', 'parseReceiptAi', 'restore', + 'createTag', 'updateTag', 'removeTag', 'reorderTags', 'confirmEntry', 'ocrReceipt', 'parseReceiptAi', 'aiComment', 'restore', 'createBudget', 'updateBudget', 'removeBudget', 'setExpectedIncome', 'createHolding', 'updateHolding', 'removeHolding', 'addTrade', 'updateTrade', 'removeTrade', 'refreshPrices', 'refreshAllPrices', diff --git a/src/views/account/AccountDashboardView.vue b/src/views/account/AccountDashboardView.vue index c55a61c..ea58d1c 100644 --- a/src/views/account/AccountDashboardView.vue +++ b/src/views/account/AccountDashboardView.vue @@ -24,6 +24,8 @@ const catType = ref('EXPENSE') // 분류별 파이차트 구분 const catData = ref([]) // [{category, total}] const categoryList = ref([]) // 분류 목록(대/소분류 매핑용) const trendData = ref([]) // [{month, netWorth}] +const aiBullets = ref([]) // AI 재무 코멘트 문장들 +const aiLoading = ref(false) const periodLabel = computed(() => `${year.value}년 ${String(month.value).padStart(2, '0')}월`) @@ -264,6 +266,7 @@ async function load() { monthIncome.value = summary.totalIncome monthExpense.value = summary.totalExpense prevMonthExpense.value = prevSummary.totalExpense + loadAiComment() // 집계가 준비된 뒤 AI 코멘트 생성(비동기, 화면 로딩 막지 않음) } catch (e) { error.value = e.response?.data?.message || '불러오지 못했습니다.' } finally { @@ -271,6 +274,29 @@ async function load() { } } +// 이번 달 집계만 백엔드로 보내 AI 재무 코멘트를 받는다(거래 원문 미전송, 실패해도 무중단) +async function loadAiComment() { + aiLoading.value = true + aiBullets.value = [] + try { + const res = await accountApi.aiComment({ + year: year.value, + month: month.value, + income: monthIncome.value, + expense: monthExpense.value, + prevExpense: prevMonthExpense.value, + budget: budgetTotal.value, + spent: spentTotal.value, + categories: (catData.value || []).slice(0, 8).map((c) => ({ category: c.category, total: c.total })), + }) + aiBullets.value = res?.bullets || [] + } catch { + aiBullets.value = [] + } finally { + aiLoading.value = false + } +} + function setUnit(u) { unit.value = u loadBar() @@ -335,6 +361,15 @@ onMounted(async () => {

불러오는 중...