diff --git a/src/app/(app)/memories/page.tsx b/src/app/(app)/memories/page.tsx index 4a4675f..03ba0f9 100644 --- a/src/app/(app)/memories/page.tsx +++ b/src/app/(app)/memories/page.tsx @@ -563,9 +563,9 @@ function MemoryTile({ memory, folder, onClick }: { memory: Memory; folder: Folde {memory.processingStatus === "processing" && ( -
- Processing… -
+ + ⏳ + )} {memory.isPrivate && 🔒} diff --git a/src/app/api/img/route.ts b/src/app/api/img/route.ts index 6999d01..32b2986 100644 --- a/src/app/api/img/route.ts +++ b/src/app/api/img/route.ts @@ -1,7 +1,7 @@ import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3"; import { NextRequest, NextResponse } from "next/server"; -const ALLOWED_PREFIXES = ["avatars/", "profiles/", "memories/", "thumbnails/"]; +const ALLOWED_PREFIXES = ["avatars/", "profiles/", "memories/", "thumbnails/", "families/"]; export async function GET(req: NextRequest) { const key = req.nextUrl.searchParams.get("key"); diff --git a/src/app/api/memories/[id]/confirm/route.ts b/src/app/api/memories/[id]/confirm/route.ts index 2262b04..3989c25 100644 --- a/src/app/api/memories/[id]/confirm/route.ts +++ b/src/app/api/memories/[id]/confirm/route.ts @@ -84,10 +84,12 @@ export async function POST(req: NextRequest, { params }: { params: Promise<{ id: } } - // Mark as processing and start the media pipeline + // Mark as processing and start the media pipeline. + // thumbnail failure is non-fatal — always proceed to vision, which marks 'ready'. await sql`UPDATE memories SET processing_status = 'processing', updated_at = now() WHERE id = ${id}`; generateThumbnail(id) + .catch(e => console.error(`[thumbnail] id=${id}`, e)) // swallow so vision always runs .then(() => processMemoryVision(id)) .catch(e => console.error(`[memory pipeline] id=${id}`, e)); diff --git a/src/lib/ai/vision.ts b/src/lib/ai/vision.ts index b36547e..4576015 100644 --- a/src/lib/ai/vision.ts +++ b/src/lib/ai/vision.ts @@ -125,7 +125,9 @@ export async function processMemoryVision(memoryId: string): Promise { `; } catch (e) { console.error(`[vision] Failed for memory ${memoryId}:`, e); - await sql`UPDATE memories SET processing_status = 'failed', updated_at = now() WHERE id = ${memoryId}`; + // Vision is optional — mark as ready so the image is still visible. + // Only the confirm step (HeadObject failure) should mark as 'failed'. + await sql`UPDATE memories SET processing_status = 'ready', updated_at = now() WHERE id = ${memoryId}`; await logAudit({ action: "vision_processing_failed", metadata: { memoryId, error: String(e) },