Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
finwise-miniapp-fe
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ThinhNC
finwise-miniapp-fe
Commits
57d7b4b7
Commit
57d7b4b7
authored
Oct 07, 2026
by
ThinhNC
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix(guest): fix receipt extraction crash and add defensive normalization in ReceiptScannerView
parent
941d4805
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
47 additions
and
13 deletions
+47
-13
guest-mock.ts
src/lib/guest-mock.ts
+18
-1
ReceiptScannerView.tsx
src/pages/ai-assistant/components/ReceiptScannerView.tsx
+29
-12
No files found.
src/lib/guest-mock.ts
View file @
57d7b4b7
...
...
@@ -1528,11 +1528,28 @@ export function handleGuestRequest(config: InternalAxiosRequestConfig): AxiosRes
responseData
=
{
success
:
true
,
data
:
{
merchant
:
"Siêu thị Co.opmart"
,
merchantName
:
"Siêu thị Co.opmart"
,
totalAmount
:
"250000"
,
currency
:
"VND"
,
taxAmount
:
"20000"
,
transactionDate
:
todayStr
,
category
:
{
id
:
"cat-expense-1"
,
name
:
"Ăn uống"
,
icon
:
"utensils"
,
color
:
"#EF4444"
,
},
lineItems
:
[
{
name
:
"Sữa chua hoa quả"
,
quantity
:
2
,
unitPrice
:
"35000"
,
totalAmount
:
"70000"
},
{
name
:
"Sữa chua hoa quả Co.op"
,
quantity
:
2
,
unitPrice
:
"35000"
,
totalAmount
:
"70000"
},
{
name
:
"Bánh mì sandwich bơ"
,
quantity
:
1
,
unitPrice
:
"45000"
,
totalAmount
:
"45000"
},
{
name
:
"Nước ép cam ép tươi 1L"
,
quantity
:
2
,
unitPrice
:
"55000"
,
totalAmount
:
"110000"
},
{
name
:
"Khăn giấy ướt cao cấp"
,
quantity
:
1
,
unitPrice
:
"25000"
,
totalAmount
:
"25000"
},
],
rawText
:
`SIEU THI CO.OPMART\nNgay:
${
todayStr
}
\n1. Sua chua hoa qua: 70.000\n2. Banh mi sandwich: 45.000\n3. Nuoc ep cam: 110.000\n4. Khan giay: 25.000\nTong tien: 250.000 VND\nVAT 8%: 20.000 VND`
,
confidence
:
0.96
,
warnings
:
[
"Hóa đơn mẫu mô phỏng trong Chế độ Dùng thử (100% xử lý tại máy, không tốn token AI thật)."
,
],
},
};
...
...
src/pages/ai-assistant/components/ReceiptScannerView.tsx
View file @
57d7b4b7
...
...
@@ -65,7 +65,20 @@ export const ReceiptScannerView: React.FC<ReceiptScannerViewProps> = ({ onTransa
{
onSuccess
:
(
res
)
=>
{
if
(
res
.
success
&&
res
.
data
)
{
setExtractedData
(
res
.
data
);
const
raw
=
res
.
data
as
any
;
const
normalizedData
:
ExtractReceiptData
=
{
merchant
:
raw
.
merchant
||
raw
.
merchantName
||
null
,
transactionDate
:
raw
.
transactionDate
||
null
,
totalAmount
:
raw
.
totalAmount
||
null
,
currency
:
raw
.
currency
||
"VND"
,
taxAmount
:
raw
.
taxAmount
||
null
,
category
:
raw
.
category
||
null
,
lineItems
:
Array
.
isArray
(
raw
.
lineItems
)
?
raw
.
lineItems
:
[],
rawText
:
raw
.
rawText
||
""
,
confidence
:
typeof
raw
.
confidence
===
"number"
?
raw
.
confidence
:
0.95
,
warnings
:
Array
.
isArray
(
raw
.
warnings
)
?
raw
.
warnings
:
[],
};
setExtractedData
(
normalizedData
);
}
},
}
...
...
@@ -98,19 +111,22 @@ export const ReceiptScannerView: React.FC<ReceiptScannerViewProps> = ({ onTransa
const
handleConfirmTransaction
=
()
=>
{
if
(
!
extractedData
)
return
;
const
lineItemsCount
=
Array
.
isArray
(
extractedData
.
lineItems
)
?
extractedData
.
lineItems
.
length
:
0
;
const
merchantName
=
extractedData
.
merchant
||
(
extractedData
as
any
).
merchantName
||
""
;
const
prefillData
=
{
amount
:
extractedData
.
totalAmount
||
""
,
type
:
"EXPENSE"
as
const
,
categoryId
:
extractedData
.
category
?.
id
||
""
,
date
:
extractedData
.
transactionDate
||
""
,
description
:
extractedData
.
merchant
?
`
${
extractedData
.
merchant
}${
extractedData
.
lineItems
.
length
>
0
?
` (
${
t
(
"ai.ocr.itemCount"
,
{
count
:
extractedData
.
lineItems
.
length
})}
)`
description
:
merchantName
?
`
${
merchantName
}${
lineItemsCount
>
0
?
` (
${
t
(
"ai.ocr.itemCount"
,
{
count
:
lineItemsCount
})}
)`
:
""
}
`
:
""
,
location
:
extractedData
.
merchant
||
""
,
location
:
merchantName
,
};
onTransactionPrefill
(
prefillData
,
selectedFile
);
...
...
@@ -125,10 +141,11 @@ export const ReceiptScannerView: React.FC<ReceiptScannerViewProps> = ({ onTransa
if
(
fileInputRef
.
current
)
fileInputRef
.
current
.
value
=
""
;
};
const
confidence
=
typeof
extractedData
?.
confidence
===
"number"
?
extractedData
.
confidence
:
0.95
;
const
confidenceClassName
=
extractedData
?
extractedData
.
confidence
>=
0.8
?
confidence
>=
0.8
?
"border-clay-income/30 bg-clay-income/20 text-clay-income"
:
extractedData
.
confidence
>=
0.5
:
confidence
>=
0.5
?
"border-clay-warning/30 bg-clay-warning/20 text-clay-warning"
:
"border-clay-expense/30 bg-clay-expense/20 text-clay-expense"
:
""
;
...
...
@@ -263,7 +280,7 @@ export const ReceiptScannerView: React.FC<ReceiptScannerViewProps> = ({ onTransa
{
t
(
"ai.ocr.resultTitle"
)
}
</
h4
>
<
span
className=
{
`shrink-0 rounded-full border px-3 py-1 font-baloo text-xs font-bold shadow-clay-pressed ${confidenceClassName}`
}
>
{
t
(
"ai.ocr.confidence"
)
}
:
{
formatNumber
(
extractedData
.
confidence
,
{
{
t
(
"ai.ocr.confidence"
)
}
:
{
formatNumber
(
confidence
,
{
style
:
"percent"
,
maximumFractionDigits
:
0
,
})
}
...
...
@@ -276,7 +293,7 @@ export const ReceiptScannerView: React.FC<ReceiptScannerViewProps> = ({ onTransa
{
t
(
"ai.ocr.merchant"
)
}
</
span
>
<
span
className=
"break-words font-nunito text-sm font-bold text-clay-text"
>
{
extractedData
.
merchant
||
"—"
}
{
extractedData
.
merchant
||
(
extractedData
as
any
).
merchantName
||
"—"
}
</
span
>
</
div
>
...
...
@@ -318,7 +335,7 @@ export const ReceiptScannerView: React.FC<ReceiptScannerViewProps> = ({ onTransa
</
div
>
{
/* Line Items Table */
}
{
extractedData
.
lineItems
.
length
>
0
&&
(
{
Array
.
isArray
(
extractedData
.
lineItems
)
&&
extractedData
.
lineItems
.
length
>
0
&&
(
<
div
className=
"mt-2 border-t border-clay-highlight/40 pt-3"
>
<
h5
className=
"mb-2 font-nunito text-xs font-bold text-clay-text"
>
{
t
(
"ai.ocr.lineItems"
)
}
(
{
extractedData
.
lineItems
.
length
}
)
...
...
@@ -368,7 +385,7 @@ export const ReceiptScannerView: React.FC<ReceiptScannerViewProps> = ({ onTransa
)
}
{
/* Warnings */
}
{
extractedData
.
warnings
.
length
>
0
&&
(
{
Array
.
isArray
(
extractedData
.
warnings
)
&&
extractedData
.
warnings
.
length
>
0
&&
(
<
div
className=
"mt-4 rounded-clay-sm bg-clay-warning/10 p-3 border border-clay-warning/30 text-xs font-medium text-clay-text space-y-1"
>
<
span
className=
"block font-bold text-clay-warning"
>
{
t
(
"ai.ocr.warnings"
)
}
:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment