Fix amount preview for scanned receipts (#227)

* no division of amount

* use gpt-4-turbo

* testing setup and naive test

* test multiple variants

* document

* correct locale names

* test large amounts

* test wth strings

* prettier
This commit is contained in:
Mert Demir
2024-09-29 07:39:01 +09:00
committed by GitHub
parent 50b3a2e431
commit 9a5674e239
6 changed files with 4123 additions and 55 deletions

18
jest.config.ts Normal file
View File

@@ -0,0 +1,18 @@
import type { Config } from 'jest'
import nextJest from 'next/jest.js'
const createJestConfig = nextJest({
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
dir: './',
})
// Add any custom config to be passed to Jest
const config: Config = {
coverageProvider: 'v8',
testEnvironment: 'jsdom',
// Add more setup options before each test is run
// setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
}
// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
export default createJestConfig(config)

4080
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,8 @@
"prettier": "prettier -w src", "prettier": "prettier -w src",
"postinstall": "prisma migrate deploy && prisma generate", "postinstall": "prisma migrate deploy && prisma generate",
"build-image": "./scripts/build-image.sh", "build-image": "./scripts/build-image.sh",
"start-container": "docker compose --env-file container.env up" "start-container": "docker compose --env-file container.env up",
"test": "jest"
}, },
"dependencies": { "dependencies": {
"@formatjs/intl-localematcher": "^0.5.4", "@formatjs/intl-localematcher": "^0.5.4",
@@ -62,8 +63,12 @@
"zod": "^3.22.4" "zod": "^3.22.4"
}, },
"devDependencies": { "devDependencies": {
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.4.8",
"@testing-library/react": "^16.0.0",
"@total-typescript/ts-reset": "^0.5.1", "@total-typescript/ts-reset": "^0.5.1",
"@types/content-disposition": "^0.5.8", "@types/content-disposition": "^0.5.8",
"@types/jest": "^29.5.12",
"@types/negotiator": "^0.6.3", "@types/negotiator": "^0.6.3",
"@types/node": "^20", "@types/node": "^20",
"@types/pg": "^8.10.9", "@types/pg": "^8.10.9",
@@ -74,10 +79,13 @@
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"eslint": "^8", "eslint": "^8",
"eslint-config-next": "^14.1.0", "eslint-config-next": "^14.1.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"postcss": "^8", "postcss": "^8",
"prettier": "^3.0.3", "prettier": "^3.0.3",
"prettier-plugin-organize-imports": "^3.2.3", "prettier-plugin-organize-imports": "^3.2.3",
"tailwindcss": "^3", "tailwindcss": "^3",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0", "tsconfig-paths": "^4.2.0",
"typescript": "^5.3.3" "typescript": "^5.3.3"
} }

View File

@@ -12,7 +12,7 @@ export async function extractExpenseInformationFromImage(imageUrl: string) {
const categories = await getCategories() const categories = await getCategories()
const body: ChatCompletionCreateParamsNonStreaming = { const body: ChatCompletionCreateParamsNonStreaming = {
model: 'gpt-4-vision-preview', model: 'gpt-4-turbo',
messages: [ messages: [
{ {
role: 'user', role: 'user',

66
src/lib/utils.test.ts Normal file
View File

@@ -0,0 +1,66 @@
import { formatCurrency } from './utils'
describe('formatCurrency', () => {
const currency = 'CUR'
/** For testing decimals */
const partialAmount = 1.23
/** For testing small full amounts */
const smallAmount = 1
/** For testing large full amounts */
const largeAmount = 10000
/** Non-breaking space */
const nbsp = '\xa0'
interface variation {
amount: number
locale: string
result: string
}
/**
* Variations to be tested, chosen as follows
* - `en-US` is a very common i18n fallback
* - `de-DE` exhibited faulty behavior in previous versions
*/
const variations: variation[] = [
{
amount: partialAmount,
locale: `en-US`,
result: `${currency}1.23`,
},
{
amount: smallAmount,
locale: `en-US`,
result: `${currency}1.00`,
},
{
amount: largeAmount,
locale: `en-US`,
result: `${currency}10,000.00`,
},
{
amount: partialAmount,
locale: `de-DE`,
result: `1,23${nbsp}${currency}`,
},
{
amount: smallAmount,
locale: `de-DE`,
result: `1,00${nbsp}${currency}`,
},
{
amount: largeAmount,
locale: `de-DE`,
result: `10.000,00${nbsp}${currency}`,
},
]
for (const variation of variations) {
it(`formats ${variation.amount} in ${variation.locale}`, () => {
expect(formatCurrency(currency, variation.amount, variation.locale)).toBe(
variation.result,
)
})
}
})

View File

@@ -40,7 +40,7 @@ export function formatCurrency(
// '€' will be placed in correct position // '€' will be placed in correct position
currency: 'EUR', currency: 'EUR',
}) })
const formattedAmount = format.format(amount / 100) const formattedAmount = format.format(amount)
return formattedAmount.replace('€', currency) return formattedAmount.replace('€', currency)
} }