From 150c2e0d30dc09e2c9dfb2d0448cd7f3f081d905 Mon Sep 17 00:00:00 2001 From: Shiv Date: Tue, 7 Jul 2026 15:03:23 +0530 Subject: [PATCH] feat(pyqs): add diagram attachments with AI context support --- .../[semester]/[subject]/[...path]/route.ts | 73 ++++++++ app/layout.tsx | 7 - .../[subject]/pyqs/[paper]/page.tsx | 22 ++- components/pyqs/attachment-image.tsx | 91 ++++++++++ components/pyqs/question-attachments.tsx | 130 ++++++++++++++ .../december-2023/Q.1-a-dec-2023.webp | Bin 0 -> 47596 bytes .../december-2023/Q.1-b-dec-2023.webp | Bin 0 -> 38856 bytes .../december-2024/Q.1-b-dec-2024.webp | Bin 0 -> 34052 bytes .../december-2024/Q.2-a-dec-2024.webp | Bin 0 -> 18888 bytes .../december-2025/Q.1-b-dec-2025.webp | Bin 0 -> 8942 bytes .../december-2025/Q.6-a-dec-2025.webp | Bin 0 -> 30240 bytes .../diagrams/june-2023/Q.1-a-june-2023.webp | Bin 0 -> 47158 bytes .../diagrams/june-2023/Q.1-b-june-2023.webp | Bin 0 -> 39998 bytes .../diagrams/june-2024/Q.2-a-june-2024.webp | Bin 0 -> 44688 bytes .../diagrams/june-2025/Q.1-b-june-2025.webp | Bin 0 -> 8418 bytes .../diagrams/june-2025/Q.2-b-june-2025.webp | Bin 0 -> 14926 bytes .../november-2022/Q.1-a-dec-2022.webp | Bin 0 -> 24602 bytes .../november-2022/Q.1-b-dec-2022.webp | Bin 0 -> 35074 bytes .../rgpv/common/semester-2/bt-104/pyqs.json | 169 ++++++++++++++++-- lib/ai/prompt-builder.ts | 15 ++ lib/content/attachment-path.ts | 115 ++++++++++++ lib/content/attachment-utils.ts | 61 +++++++ lib/content/question-mapper.ts | 28 +-- next.config.ts | 8 + types/pyq.ts | 45 +++++ 25 files changed, 712 insertions(+), 52 deletions(-) create mode 100644 app/api/content/attachments/[branch]/[semester]/[subject]/[...path]/route.ts create mode 100644 components/pyqs/attachment-image.tsx create mode 100644 components/pyqs/question-attachments.tsx create mode 100644 content/rgpv/common/semester-2/bt-104/diagrams/december-2023/Q.1-a-dec-2023.webp create mode 100644 content/rgpv/common/semester-2/bt-104/diagrams/december-2023/Q.1-b-dec-2023.webp create mode 100644 content/rgpv/common/semester-2/bt-104/diagrams/december-2024/Q.1-b-dec-2024.webp create mode 100644 content/rgpv/common/semester-2/bt-104/diagrams/december-2024/Q.2-a-dec-2024.webp create mode 100644 content/rgpv/common/semester-2/bt-104/diagrams/december-2025/Q.1-b-dec-2025.webp create mode 100644 content/rgpv/common/semester-2/bt-104/diagrams/december-2025/Q.6-a-dec-2025.webp create mode 100644 content/rgpv/common/semester-2/bt-104/diagrams/june-2023/Q.1-a-june-2023.webp create mode 100644 content/rgpv/common/semester-2/bt-104/diagrams/june-2023/Q.1-b-june-2023.webp create mode 100644 content/rgpv/common/semester-2/bt-104/diagrams/june-2024/Q.2-a-june-2024.webp create mode 100644 content/rgpv/common/semester-2/bt-104/diagrams/june-2025/Q.1-b-june-2025.webp create mode 100644 content/rgpv/common/semester-2/bt-104/diagrams/june-2025/Q.2-b-june-2025.webp create mode 100644 content/rgpv/common/semester-2/bt-104/diagrams/november-2022/Q.1-a-dec-2022.webp create mode 100644 content/rgpv/common/semester-2/bt-104/diagrams/november-2022/Q.1-b-dec-2022.webp create mode 100644 lib/content/attachment-path.ts create mode 100644 lib/content/attachment-utils.ts create mode 100644 types/pyq.ts diff --git a/app/api/content/attachments/[branch]/[semester]/[subject]/[...path]/route.ts b/app/api/content/attachments/[branch]/[semester]/[subject]/[...path]/route.ts new file mode 100644 index 0000000..107171a --- /dev/null +++ b/app/api/content/attachments/[branch]/[semester]/[subject]/[...path]/route.ts @@ -0,0 +1,73 @@ +import fs from "fs/promises"; +import path from "path"; +import { NextRequest, NextResponse } from "next/server"; +import { resolveAttachmentFilesystemPath } from "@/lib/content/attachment-path"; + +const MIME_TYPES: Record = { + ".webp": "image/webp", + ".png": "image/png", + ".jpg": "image/jpeg", + ".jpeg": "image/jpeg", + ".gif": "image/gif", + ".svg": "image/svg+xml", + ".pdf": "application/pdf", +}; + +interface RouteContext { + params: Promise<{ + branch: string; + semester: string; + subject: string; + path: string[]; + }>; +} + +export async function GET(_request: NextRequest, context: RouteContext) { + const { + branch, + semester, + subject, + path: pathSegments, + } = await context.params; + const attachmentPath = pathSegments.map(decodeURIComponent).join("/"); + + const filePath = resolveAttachmentFilesystemPath({ + branch, + semester, + subject, + attachmentPath, + }); + + if (!filePath) { + console.warn( + `[attachments] Invalid attachment path requested: ${branch}/${semester}/${subject}/${attachmentPath}` + ); + return NextResponse.json( + { error: "Invalid attachment path" }, + { status: 400 } + ); + } + + try { + const fileBuffer = await fs.readFile(filePath); + const extension = path.extname(filePath).toLowerCase(); + const contentType = MIME_TYPES[extension] ?? "application/octet-stream"; + + return new NextResponse(fileBuffer, { + status: 200, + headers: { + "Content-Type": contentType, + "Cache-Control": "public, max-age=31536000, immutable", + }, + }); + } catch (error) { + console.warn( + `[attachments] File not found: ${branch}/${semester}/${subject}/${attachmentPath}`, + error + ); + return NextResponse.json( + { error: "Attachment not found" }, + { status: 404 } + ); + } +} diff --git a/app/layout.tsx b/app/layout.tsx index f7a8222..265c29c 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -109,13 +109,6 @@ export default function RootLayout({ }) { return ( - -