feat: storage and token limiting

This commit is contained in:
Vasily Zubarev
2025-04-21 13:50:45 +02:00
parent 62bad46e58
commit 73e83221b8
25 changed files with 232 additions and 65 deletions

View File

@@ -2,7 +2,7 @@
import { ActionState } from "@/lib/actions"
import { getCurrentUser } from "@/lib/auth"
import { getDirectorySize, getUserUploadsDirectory, unsortedFilePath } from "@/lib/files"
import { getDirectorySize, getUserUploadsDirectory, isEnoughStorageToUploadFile, unsortedFilePath } from "@/lib/files"
import { createFile } from "@/models/files"
import { updateUser } from "@/models/users"
import { randomUUID } from "crypto"
@@ -24,6 +24,10 @@ export async function uploadFilesAction(formData: FormData): Promise<ActionState
return { success: false, error: "Invalid file" }
}
if (!isEnoughStorageToUploadFile(user, file.size)) {
return { success: false, error: `Insufficient storage to upload this file: ${file.name}` }
}
// Save file to filesystem
const fileUuid = randomUUID()
const relativeFilePath = await unsortedFilePath(fileUuid, file.name)

View File

@@ -38,6 +38,8 @@ export default async function RootLayout({ children }: { children: React.ReactNo
email: user.email,
avatar: user.avatar || undefined,
storageUsed: user.storageUsed || 0,
storageLimit: user.storageLimit || -1,
tokenBalance: user.tokenBalance || 0,
}
return (

View File

@@ -1,4 +1,4 @@
import ProfileSettingsForm from "@/components/settings/profile-settings-form copy"
import ProfileSettingsForm from "@/components/settings/profile-settings-form"
import { getCurrentUser } from "@/lib/auth"
export default async function ProfileSettingsPage() {

View File

@@ -3,7 +3,12 @@
import { transactionFormSchema } from "@/forms/transactions"
import { ActionState } from "@/lib/actions"
import { getCurrentUser } from "@/lib/auth"
import { getDirectorySize, getTransactionFileUploadPath, getUserUploadsDirectory } from "@/lib/files"
import {
getDirectorySize,
getTransactionFileUploadPath,
getUserUploadsDirectory,
isEnoughStorageToUploadFile,
} from "@/lib/files"
import { updateField } from "@/models/fields"
import { createFile, deleteFile } from "@/models/files"
import {
@@ -133,6 +138,11 @@ export async function uploadTransactionFilesAction(formData: FormData): Promise<
const userUploadsDirectory = await getUserUploadsDirectory(user)
const totalFileSize = files.reduce((acc, file) => acc + file.size, 0)
if (!isEnoughStorageToUploadFile(user, totalFileSize)) {
return { success: false, error: `Insufficient storage to upload new files` }
}
const fileRecords = await Promise.all(
files.map(async (file) => {
const fileUuid = randomUUID()

View File

@@ -1,6 +1,6 @@
"use server"
import { analyzeTransaction } from "@/ai/analyze"
import { AnalysisResult, analyzeTransaction } from "@/ai/analyze"
import { AnalyzeAttachment, loadAttachmentsForAI } from "@/ai/attachments"
import { buildLLMPrompt } from "@/ai/prompt"
import { fieldsToJsonSchema } from "@/ai/schema"
@@ -12,6 +12,7 @@ import { getTransactionFileUploadPath, getUserUploadsDirectory } from "@/lib/fil
import { DEFAULT_PROMPT_ANALYSE_NEW_FILE } from "@/models/defaults"
import { deleteFile, getFileById, updateFile } from "@/models/files"
import { createTransaction, updateTransactionFiles } from "@/models/transactions"
import { updateUser } from "@/models/users"
import { Category, Field, File, Project, Transaction } from "@prisma/client"
import { mkdir, rename } from "fs/promises"
import { revalidatePath } from "next/cache"
@@ -23,7 +24,7 @@ export async function analyzeFileAction(
fields: Field[],
categories: Category[],
projects: Project[]
): Promise<ActionState<Record<string, string>>> {
): Promise<ActionState<AnalysisResult>> {
const user = await getCurrentUser()
if (!file || file.userId !== user.id) {
@@ -35,6 +36,10 @@ export async function analyzeFileAction(
return { success: false, error: "OpenAI API key is not set" }
}
if (!config.selfHosted.isEnabled && user.tokenBalance < 0) {
return { success: false, error: "You used all your AI tokens, please upgrade your account" }
}
let attachments: AnalyzeAttachment[] = []
try {
attachments = await loadAttachmentsForAI(user, file)
@@ -56,6 +61,10 @@ export async function analyzeFileAction(
console.log("Analysis results:", results)
if (results.data?.tokensUsed && results.data.tokensUsed > 0) {
await updateUser(user.id, { tokenBalance: { decrement: results.data.tokensUsed } })
}
return results
}