Files
TaxHacker_s23/app/(app)/unsorted/actions.ts
2025-04-04 14:52:48 +02:00

118 lines
4.1 KiB
TypeScript

"use server"
import { analyzeTransaction } from "@/ai/analyze"
import { AnalyzeAttachment, loadAttachmentsForAI } from "@/ai/attachments"
import { buildLLMPrompt } from "@/ai/prompt"
import { fieldsToJsonSchema } from "@/ai/schema"
import { transactionFormSchema } from "@/forms/transactions"
import { getCurrentUser } from "@/lib/auth"
import config from "@/lib/config"
import { getTransactionFileUploadPath, getUserUploadsDirectory } from "@/lib/files"
import { DEFAULT_PROMPT_ANALYSE_NEW_FILE } from "@/models/defaults"
import { deleteFile, getFileById, updateFile } from "@/models/files"
import { createTransaction, updateTransactionFiles } from "@/models/transactions"
import { Category, Field, File, Project } from "@prisma/client"
import { mkdir, rename } from "fs/promises"
import { revalidatePath } from "next/cache"
import path from "path"
export async function analyzeFileAction(
file: File,
settings: Record<string, string>,
fields: Field[],
categories: Category[],
projects: Project[]
): Promise<{ success: boolean; data?: Record<string, any>; error?: string }> {
const user = await getCurrentUser()
if (!file || file.userId !== user.id) {
return { success: false, error: "File not found or does not belong to the user" }
}
const apiKey = settings.openai_api_key || config.ai.openaiApiKey || ""
if (!apiKey) {
return { success: false, error: "OpenAI API key is not set" }
}
let attachments: AnalyzeAttachment[] = []
try {
attachments = await loadAttachmentsForAI(user, file)
} catch (error) {
console.error("Failed to retrieve files:", error)
return { success: false, error: "Failed to retrieve files: " + error }
}
const prompt = buildLLMPrompt(
settings.prompt_analyse_new_file || DEFAULT_PROMPT_ANALYSE_NEW_FILE,
fields,
categories,
projects
)
const schema = fieldsToJsonSchema(fields)
const results = await analyzeTransaction(prompt, schema, attachments, apiKey)
console.log("Analysis results:", results)
return results
}
export async function saveFileAsTransactionAction(prevState: any, formData: FormData) {
try {
const user = await getCurrentUser()
const validatedForm = transactionFormSchema.safeParse(Object.fromEntries(formData.entries()))
if (!validatedForm.success) {
return { success: false, error: validatedForm.error.message }
}
// Get the file record
const fileId = formData.get("fileId") as string
const file = await getFileById(fileId, user.id)
if (!file) throw new Error("File not found")
// Create transaction
const transaction = await createTransaction(user.id, validatedForm.data)
// Move file to processed location
const userUploadsDirectory = await getUserUploadsDirectory(user)
const originalFileName = path.basename(file.path)
const newRelativeFilePath = await getTransactionFileUploadPath(file.id, originalFileName, transaction)
// Move file to new location and name
const oldFullFilePath = path.join(userUploadsDirectory, path.normalize(file.path))
const newFullFilePath = path.join(userUploadsDirectory, path.normalize(newRelativeFilePath))
await mkdir(path.dirname(newFullFilePath), { recursive: true })
await rename(path.resolve(oldFullFilePath), path.resolve(newFullFilePath))
// Update file record
await updateFile(file.id, user.id, {
path: newRelativeFilePath,
isReviewed: true,
})
await updateTransactionFiles(transaction.id, user.id, [file.id])
revalidatePath("/unsorted")
revalidatePath("/transactions")
return { success: true, transactionId: transaction.id }
} catch (error) {
console.error("Failed to save transaction:", error)
return { success: false, error: `Failed to save transaction: ${error}` }
}
}
export async function deleteUnsortedFileAction(prevState: any, fileId: string) {
try {
const user = await getCurrentUser()
await deleteFile(fileId, user.id)
revalidatePath("/unsorted")
return { success: true }
} catch (error) {
console.error("Failed to delete file:", error)
return { success: false, error: "Failed to delete file" }
}
}