mirror of
https://github.com/spliit-app/spliit.git
synced 2026-03-08 05:09:05 +01:00
* environment variable * random category draft * get category from ai * input limit and documentation * use watch * use field.name * prettier * presigned upload, readme warning, category to string util * prettier * check whether feature is enabled * use process.env * improved prompt to return id only * remove console.debug * show loader * share class name * prettier * use template literals * rename format util * prettier
51 lines
1.8 KiB
TypeScript
51 lines
1.8 KiB
TypeScript
'use server'
|
||
import { getCategories } from '@/lib/api'
|
||
import { env } from '@/lib/env'
|
||
import { formatCategoryForAIPrompt } from '@/lib/utils'
|
||
import OpenAI from 'openai'
|
||
import { ChatCompletionCreateParamsNonStreaming } from 'openai/resources/index.mjs'
|
||
|
||
const openai = new OpenAI({ apiKey: env.OPENAI_API_KEY })
|
||
|
||
export async function extractExpenseInformationFromImage(imageUrl: string) {
|
||
'use server'
|
||
const categories = await getCategories()
|
||
|
||
const body: ChatCompletionCreateParamsNonStreaming = {
|
||
model: 'gpt-4-vision-preview',
|
||
messages: [
|
||
{
|
||
role: 'user',
|
||
content: [
|
||
{
|
||
type: 'text',
|
||
text: `
|
||
This image contains a receipt.
|
||
Read the total amount and store it as a non-formatted number without any other text or currency.
|
||
Then guess the category for this receipt amoung the following categories and store its ID: ${categories.map(
|
||
(category) => formatCategoryForAIPrompt(category),
|
||
)}.
|
||
Guess the expense’s date and store it as yyyy-mm-dd.
|
||
Guess a title for the expense.
|
||
Return the amount, the category, the date and the title with just a comma between them, without anything else.`,
|
||
},
|
||
],
|
||
},
|
||
{
|
||
role: 'user',
|
||
content: [{ type: 'image_url', image_url: { url: imageUrl } }],
|
||
},
|
||
],
|
||
}
|
||
const completion = await openai.chat.completions.create(body)
|
||
|
||
const [amountString, categoryId, date, title] = completion.choices
|
||
.at(0)
|
||
?.message.content?.split(',') ?? [null, null, null, null]
|
||
return { amount: Number(amountString), categoryId, date, title }
|
||
}
|
||
|
||
export type ReceiptExtractedInfo = Awaited<
|
||
ReturnType<typeof extractExpenseInformationFromImage>
|
||
>
|