diff --git a/frontend/bun.lockb b/frontend/bun.lockb index 0003d238..9a025fd7 100755 Binary files a/frontend/bun.lockb and b/frontend/bun.lockb differ diff --git a/frontend/hooks/use-image-compression.ts b/frontend/hooks/use-image-compression.ts new file mode 100644 index 00000000..d74db6b4 --- /dev/null +++ b/frontend/hooks/use-image-compression.ts @@ -0,0 +1,34 @@ +// hooks/useImageCompression.ts +import { useState } from 'react'; +import imageCompression from 'browser-image-compression'; + +interface UseImageCompressionOptions { + maxSizeMB?: number; + maxWidthOrHeight?: number; +} + +export const useImageCompression = (options: UseImageCompressionOptions = {}) => { + const [compressionError, setError] = useState(null); + + const compressImage = async (file: File) => { + try { + setError(null); + const compressedBlob = await imageCompression(file, { + maxSizeMB: options.maxSizeMB || 1, + maxWidthOrHeight: options.maxWidthOrHeight || 1024, + useWebWorker: true, + }); + + const compressedFile = new File([compressedBlob], file.name, { + type: compressedBlob.type, + lastModified: new Date().getTime(), + }); + return compressedFile; + } catch (err) { + setError(err instanceof Error ? err : new Error('Compression failed')); + throw err; + } + }; + + return { compressImage, compressionError }; +}; diff --git a/frontend/hooks/use-upload-file.ts b/frontend/hooks/use-upload-file.ts index 39510a40..48fddae1 100644 --- a/frontend/hooks/use-upload-file.ts +++ b/frontend/hooks/use-upload-file.ts @@ -2,6 +2,7 @@ import * as React from 'react'; import { toast } from 'sonner'; import { getAuthToken } from '@/actions/token'; import { NEXT_PUBLIC_VECTOR_HOST } from '@/lib/client_env'; +import { useImageCompression } from '@/hooks/use-image-compression'; export interface UploadedFile { name: string; @@ -64,6 +65,7 @@ async function uploadSingleFile(file: File): Promise { export function useUploadFile() { const [uploadedFiles, setUploadedFiles] = React.useState(); const [isUploading, setIsUploading] = React.useState(false); + const { compressImage, compressionError } = useImageCompression({}); const indexLocalFile = async (files: File[]) => { const endpoint = `${NEXT_PUBLIC_VECTOR_HOST}/api/index/local-file`; @@ -96,7 +98,11 @@ export function useUploadFile() { const results = await Promise.all( files.map(async (file) => { try { - return await uploadSingleFile(file); + let compressedFile = await compressImage(file); + if (compressionError) { + compressedFile = file; + } + return await uploadSingleFile(compressedFile); } catch (error) { console.error(`Error uploading ${file.name}:`, error); toast.error(`Failed to upload ${file.name}`); @@ -108,7 +114,6 @@ export function useUploadFile() { if (successfulUploads.length > 0) { setUploadedFiles((prev) => (prev ? [...prev, ...successfulUploads] : successfulUploads)); } - console.log('successfulUploads', successfulUploads); } else { const res = await indexLocalFile(files); setUploadedFiles((prev) => (prev ? [...prev, ...res] : res)); @@ -118,7 +123,6 @@ export function useUploadFile() { setUploadedFiles([]); toast.error('Something went wrong, please try again later.'); } finally { - console.log('uploadedFiles', uploadedFiles); setIsUploading(false); } } diff --git a/frontend/package.json b/frontend/package.json index e520005b..c3abb318 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,133 +1,134 @@ { - "private": true, - "scripts": { - "build": "next build", - "analyze": "ANALYZE=true next build", - "dev": "next dev", - "lint": "next lint", - "prettier": "prettier --write --ignore-unknown .", - "prettier:check": "prettier --check --ignore-unknown .", - "start": "next start", - "test": "jest" - }, - "dependencies": { - "@ai-sdk/anthropic": "^1.0.2", - "@ai-sdk/google": "^0.0.35", - "@ai-sdk/openai": "^0.0.44", - "@auth/upstash-redis-adapter": "^2.4.1", - "@axiomhq/js": "^1.0.0", - "@babel/plugin-transform-modules-commonjs": "^7.25.7", - "@babel/preset-react": "^7.25.7", - "@babel/preset-typescript": "^7.25.7", - "@babel/standalone": "^7.25.8", - "@emotion/is-prop-valid": "^1.3.1", - "@microsoft/fetch-event-source": "^2.0.1", - "@monaco-editor/react": "^4.6.0", - "@radix-ui/react-accordion": "^1.1.2", - "@radix-ui/react-alert-dialog": "^1.1.1", - "@radix-ui/react-aspect-ratio": "^1.1.0", - "@radix-ui/react-avatar": "^1.0.4", - "@radix-ui/react-checkbox": "^1.1.2", - "@radix-ui/react-dialog": "^1.1.2", - "@radix-ui/react-dropdown-menu": "^2.0.6", - "@radix-ui/react-hover-card": "^1.1.0", - "@radix-ui/react-icons": "^1.3.0", - "@radix-ui/react-label": "^2.0.2", - "@radix-ui/react-navigation-menu": "^1.1.4", - "@radix-ui/react-popover": "^1.0.7", - "@radix-ui/react-progress": "^1.1.0", - "@radix-ui/react-radio-group": "^1.2.1", - "@radix-ui/react-scroll-area": "^1.0.5", - "@radix-ui/react-select": "^2.1.1", - "@radix-ui/react-separator": "^1.1.0", - "@radix-ui/react-slider": "^1.2.1", - "@radix-ui/react-slot": "^1.1.0", - "@radix-ui/react-switch": "^1.1.1", - "@radix-ui/react-tabs": "^1.0.4", - "@radix-ui/react-toast": "^1.1.5", - "@radix-ui/react-toggle": "^1.0.3", - "@radix-ui/react-toggle-group": "^1.0.4", - "@radix-ui/react-tooltip": "^1.1.2", - "@types/node": "20.5.7", - "@upstash/ratelimit": "^1.2.1", - "@upstash/redis": "^1.31.6", - "ai": "^4.0.4", - "aws4fetch": "^1.0.20", - "class-variance-authority": "^0.7.0", - "clsx": "^2.1.1", - "cmdk": "0.2.0", - "contentlayer2": "^0.4.6", - "date-fns": "^3.0.0", - "exa-js": "^1.0.14", - "framer-motion": "^11.11.9", - "google-auth-library": "^9.4.1", - "heic2any": "^0.0.4", - "html2canvas": "^1.4.1", - "lucide-react": "^0.452.0", - "markmap-lib": "^0.17.0", - "markmap-view": "^0.17.0", - "next": "14.2.15", - "next-auth": "^5.0.0-beta.17", - "next-contentlayer2": "^0.4.6", - "next-intl": "^3.19.0", - "next-themes": "^0.3.0", - "postcss": "8.4.31", - "react": "^18.3.1", - "react-day-picker": "8.10.1", - "react-dom": "^18.3.1", - "react-dropzone": "^14.2.3", - "react-hook-form": "^7.51.4", - "react-markdown": "^9.0.1", - "react-resizable-panels": "^2.1.4", - "react-textarea-autosize": "^8.5.3", - "recharts": "^2.13.0", - "rehype-highlight": "^6.0.0", - "rehype-katex": "^6.0.3", - "remark-math": "^6.0.0", - "resend": "^3.1.0", - "sonner": "^1.4.41", - "stripe": "^15.4.0", - "typescript": "5.2.2", - "uuid": "^10.0.0", - "vaul": "^0.9.1", - "zod": "^3.23.8", - "zustand": "^4.5.2" - }, - "devDependencies": { - "@next/bundle-analyzer": "^14.2.12", - "@tailwindcss/line-clamp": "^0.4.4", - "@tailwindcss/typography": "^0.5.13", - "@testing-library/dom": "^10.4.0", - "@testing-library/jest-dom": "^6.6.2", - "@testing-library/react": "^16.0.1", - "@types/google-one-tap": "^1.2.6", - "@types/jest": "^29.5.14", - "@types/react": "18.2.21", - "@types/react-dom": "18.2.14", - "@vercel/style-guide": "^5.0.1", - "autoprefixer": "10.4.15", - "dotenv": "^16.3.1", - "eslint": "^8.52.0", - "eslint-config-next": "^14.0.0", - "eslint-config-prettier": "9.0.0", - "eslint-plugin-tailwindcss": "^3.15.1", - "jest": "^29.7.0", - "jest-environment-jsdom": "^29.7.0", - "mdast-util-toc": "^7.0.1", - "patch-package": "^8.0.0", - "prettier": "^3.0.3", - "prettier-plugin-tailwindcss": "^0.5.14", - "rehype-autolink-headings": "^7.1.0", - "rehype-pretty-code": "^0.13.1", - "rehype-slug": "^6.0.0", - "remark": "^15.0.1", - "remark-gfm": "^4.0.0", - "tailwind-merge": "^2.3.0", - "tailwindcss": "^3.4.3", - "tailwindcss-animate": "^1.0.7", - "ts-jest": "^29.2.5" - }, - "engines": { - "node": ">=18.17.0" - } + "private": true, + "scripts": { + "build": "next build", + "analyze": "ANALYZE=true next build", + "dev": "next dev", + "lint": "next lint", + "prettier": "prettier --write --ignore-unknown .", + "prettier:check": "prettier --check --ignore-unknown .", + "start": "next start", + "test": "jest" + }, + "dependencies": { + "@ai-sdk/anthropic": "^1.0.2", + "@ai-sdk/google": "^0.0.35", + "@ai-sdk/openai": "^0.0.44", + "@auth/upstash-redis-adapter": "^2.4.1", + "@axiomhq/js": "^1.0.0", + "@babel/plugin-transform-modules-commonjs": "^7.25.7", + "@babel/preset-react": "^7.25.7", + "@babel/preset-typescript": "^7.25.7", + "@babel/standalone": "^7.25.8", + "@emotion/is-prop-valid": "^1.3.1", + "@microsoft/fetch-event-source": "^2.0.1", + "@monaco-editor/react": "^4.6.0", + "@radix-ui/react-accordion": "^1.1.2", + "@radix-ui/react-alert-dialog": "^1.1.1", + "@radix-ui/react-aspect-ratio": "^1.1.0", + "@radix-ui/react-avatar": "^1.0.4", + "@radix-ui/react-checkbox": "^1.1.2", + "@radix-ui/react-dialog": "^1.1.2", + "@radix-ui/react-dropdown-menu": "^2.0.6", + "@radix-ui/react-hover-card": "^1.1.0", + "@radix-ui/react-icons": "^1.3.0", + "@radix-ui/react-label": "^2.0.2", + "@radix-ui/react-navigation-menu": "^1.1.4", + "@radix-ui/react-popover": "^1.0.7", + "@radix-ui/react-progress": "^1.1.0", + "@radix-ui/react-radio-group": "^1.2.1", + "@radix-ui/react-scroll-area": "^1.0.5", + "@radix-ui/react-select": "^2.1.1", + "@radix-ui/react-separator": "^1.1.0", + "@radix-ui/react-slider": "^1.2.1", + "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-switch": "^1.1.1", + "@radix-ui/react-tabs": "^1.0.4", + "@radix-ui/react-toast": "^1.1.5", + "@radix-ui/react-toggle": "^1.0.3", + "@radix-ui/react-toggle-group": "^1.0.4", + "@radix-ui/react-tooltip": "^1.1.2", + "@types/node": "20.5.7", + "@upstash/ratelimit": "^1.2.1", + "@upstash/redis": "^1.31.6", + "ai": "^4.0.4", + "aws4fetch": "^1.0.20", + "browser-image-compression": "^2.0.2", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "cmdk": "0.2.0", + "contentlayer2": "^0.4.6", + "date-fns": "^3.0.0", + "exa-js": "^1.0.14", + "framer-motion": "^11.11.9", + "google-auth-library": "^9.4.1", + "heic2any": "^0.0.4", + "html2canvas": "^1.4.1", + "lucide-react": "^0.452.0", + "markmap-lib": "^0.17.0", + "markmap-view": "^0.17.0", + "next": "14.2.15", + "next-auth": "^5.0.0-beta.17", + "next-contentlayer2": "^0.4.6", + "next-intl": "^3.19.0", + "next-themes": "^0.3.0", + "postcss": "8.4.31", + "react": "^18.3.1", + "react-day-picker": "8.10.1", + "react-dom": "^18.3.1", + "react-dropzone": "^14.2.3", + "react-hook-form": "^7.51.4", + "react-markdown": "^9.0.1", + "react-resizable-panels": "^2.1.4", + "react-textarea-autosize": "^8.5.3", + "recharts": "^2.13.0", + "rehype-highlight": "^6.0.0", + "rehype-katex": "^6.0.3", + "remark-math": "^6.0.0", + "resend": "^3.1.0", + "sonner": "^1.4.41", + "stripe": "^15.4.0", + "typescript": "5.2.2", + "uuid": "^10.0.0", + "vaul": "^0.9.1", + "zod": "^3.23.8", + "zustand": "^4.5.2" + }, + "devDependencies": { + "@next/bundle-analyzer": "^14.2.12", + "@tailwindcss/line-clamp": "^0.4.4", + "@tailwindcss/typography": "^0.5.13", + "@testing-library/dom": "^10.4.0", + "@testing-library/jest-dom": "^6.6.2", + "@testing-library/react": "^16.0.1", + "@types/google-one-tap": "^1.2.6", + "@types/jest": "^29.5.14", + "@types/react": "18.2.21", + "@types/react-dom": "18.2.14", + "@vercel/style-guide": "^5.0.1", + "autoprefixer": "10.4.15", + "dotenv": "^16.3.1", + "eslint": "^8.52.0", + "eslint-config-next": "^14.0.0", + "eslint-config-prettier": "9.0.0", + "eslint-plugin-tailwindcss": "^3.15.1", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "mdast-util-toc": "^7.0.1", + "patch-package": "^8.0.0", + "prettier": "^3.0.3", + "prettier-plugin-tailwindcss": "^0.5.14", + "rehype-autolink-headings": "^7.1.0", + "rehype-pretty-code": "^0.13.1", + "rehype-slug": "^6.0.0", + "remark": "^15.0.1", + "remark-gfm": "^4.0.0", + "tailwind-merge": "^2.3.0", + "tailwindcss": "^3.4.3", + "tailwindcss-animate": "^1.0.7", + "ts-jest": "^29.2.5" + }, + "engines": { + "node": ">=18.17.0" + } }