Vercel/app/admin/uploads/[uploadPath]/page.tsx
Sam Becker 59f5c74269
Chromatic sorting (#284)
* Test color palette extraction

* Fix import

* Add hex <> oklch conversions

* Add 'hue' storage to photos

* Consolidate color modules

* Add chromatic config, track missing color data

* Bump deps

* Fix lens text test

* Finalize color storage

* Refactor color imports

* Hide form color data when disabled

* Store all average oklch color components

* Finalize color-config language

* Optimize photo syncing for color data

* Only update color data when syncing if possible

* Build out all color sorts

* Debug image colors

* Improve color debugging

* Improve color logging

* Simplify color sorting

* Bump deps

* Fix color sync logic

* Switch to sort params: ascending, descending

* Fix commandk sort menu

* Update tr-tr sorting language

* Add color capture to all photo extractions

* Add color visualization to photo form

* Standardize photo update language

* Create global debug color update function

* Improve color data capture logging

* Update maximum function duration for admin photos

* Add note to remove maxDuration

* Use AI to generate sorting color

* Conditionally use AI to analyze colors

* Manage AI color analysis batched requests

* Fix color reporting in admin photo table

* Only update color where AI fields are missing

* Temporarily upgrade admin/photos timeout

* Fix pro-based max duration

* Standardize color sorting foundations

* Update color sorting language

* Refactor color calculations

* Restore max duration time

* Update color-based sort menu labels

* Finalize color documentation

* Clean up color test actions

* Round color sort values before submitting to db

* Consolidate color server actions
2025-08-03 19:31:02 -05:00

99 lines
2.6 KiB
TypeScript

import { PARAM_UPLOAD_TITLE, PATH_ADMIN } from '@/app/path';
import { extractImageDataFromBlobPath } from '@/photo/server';
import { redirect } from 'next/navigation';
import {
getUniqueFilmsCached,
getUniqueRecipesCached,
getUniqueTagsCached,
} from '@/photo/cache';
import UploadPageClient from '@/photo/UploadPageClient';
import {
AI_TEXT_AUTO_GENERATED_FIELDS,
AI_CONTENT_GENERATION_ENABLED,
BLUR_ENABLED,
} from '@/app/config';
import ErrorNote from '@/components/ErrorNote';
import { getRecipeTitleForData } from '@/photo/db/query';
export const maxDuration = 60;
interface Params {
params: Promise<{ uploadPath: string }>
searchParams: Promise<Record<string, string | string[] | undefined>>
}
export default async function UploadPage({ params, searchParams }: Params) {
const uploadPath = (await params).uploadPath;
const title = (await searchParams)[PARAM_UPLOAD_TITLE];
const {
blobId,
formDataFromExif,
imageResizedBase64: imageThumbnailBase64,
shouldStripGpsData,
error,
} = await extractImageDataFromBlobPath(uploadPath, {
includeInitialPhotoFields: true,
generateBlurData: BLUR_ENABLED,
generateResizedImage: AI_CONTENT_GENERATION_ENABLED,
});
const isDataMissing =
!formDataFromExif ||
(AI_CONTENT_GENERATION_ENABLED && !imageThumbnailBase64);
if (isDataMissing && !error) {
// Only redirect if there's no error to report
redirect(PATH_ADMIN);
}
const [
uniqueTags,
uniqueRecipes,
uniqueFilms,
recipeTitle,
] = await Promise.all([
getUniqueTagsCached(),
getUniqueRecipesCached(),
getUniqueFilmsCached(),
formDataFromExif?.recipeData && formDataFromExif.film
? getRecipeTitleForData(
formDataFromExif.recipeData,
formDataFromExif.film,
)
: undefined,
]);
const hasAiTextGeneration = AI_CONTENT_GENERATION_ENABLED;
let textFieldsToAutoGenerate = AI_TEXT_AUTO_GENERATED_FIELDS;
if (formDataFromExif) {
if (recipeTitle) {
formDataFromExif.recipeTitle = recipeTitle;
}
if (typeof title === 'string') {
formDataFromExif.title = title;
textFieldsToAutoGenerate = textFieldsToAutoGenerate
.filter(field => field !== 'title');
}
}
return (
!isDataMissing
? <UploadPageClient {...{
blobId,
formDataFromExif,
uniqueTags,
uniqueRecipes,
uniqueFilms,
hasAiTextGeneration,
textFieldsToAutoGenerate,
imageThumbnailBase64,
shouldStripGpsData,
}} />
: <ErrorNote>
{error ?? 'Unknown error'}
</ErrorNote>
);
};