feat(pyqs): add diagram attachments with AI context support#64
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThis PR adds a question-attachment feature for PYQ pages: new types, a filesystem-backed attachment API route, path/validation utilities, image rendering components, AI prompt context injection, page wiring, Next.js image config updates, and enriched BT-104 content JSON with attachment metadata. An unrelated inline theme script is also removed from the root layout. ChangesQuestion Attachment Feature
Estimated code review effort: 3 (Moderate) | ~30 minutes Sequence Diagram(s)sequenceDiagram
participant PaperPage
participant QuestionAttachments
participant AttachmentPathUtils
participant AttachmentImage
participant AttachmentApiRoute
PaperPage->>QuestionAttachments: render(attachments, branch, semester, subject)
QuestionAttachments->>AttachmentPathUtils: getAttachmentPath / attachmentFileExists
AttachmentPathUtils-->>QuestionAttachments: src url / exists boolean
QuestionAttachments->>AttachmentImage: render(src, invalidPath)
AttachmentImage->>AttachmentApiRoute: GET /api/content/attachments/...
AttachmentApiRoute-->>AttachmentImage: file bytes or 404 JSON
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (5)
types/pyq.ts (1)
10-18: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win
title/alt/caption/aiContexttyped as required but treated as optional downstream.
QuestionAttachmentdeclarestitle,alt,caption, andaiContextas requiredstringfields, butlib/content/attachment-utils.ts(getAttachmentAlt,getAttachmentTitle,getAttachmentCaption) accesses them with optional chaining (attachment.alt?.trim()), andisQuestionAttachmentnever validates these fields at runtime. Since attachment data ultimately comes from JSON content files (not statically type-checked), these fields can legitimately be missing at runtime, and the type signature gives false confidence to any consumer that reads them directly without the helper functions.🔧 Suggested fix
export interface QuestionAttachment { id: string; type: QuestionAttachmentType; path: string; - title: string; - alt: string; - caption: string; - aiContext: string; + title?: string; + alt?: string; + caption?: string; + aiContext?: string; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@types/pyq.ts` around lines 10 - 18, QuestionAttachment currently marks title, alt, caption, and aiContext as required even though attachment-utils helpers treat them as optional and runtime JSON may omit them. Update the QuestionAttachment type in pyq.ts to make these fields optional (or otherwise align the interface with the actual runtime shape), and keep isQuestionAttachment and the getAttachmentAlt/getAttachmentTitle/getAttachmentCaption helpers consistent with that contract so consumers do not assume guaranteed string values.next.config.ts (1)
6-13: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRedundant
localPatternsentry.The
"/**"pattern already matches all local paths, including/api/content/attachments/**, so the second entry is dead config. Harmless as-is, but simplify if this list expands later.♻️ Simplify
localPatterns: [ { pathname: "/**", // allow existing local images such as /hl-logo.png }, - { - pathname: "/api/content/attachments/**", - }, ],🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@next.config.ts` around lines 6 - 13, The local image pattern list is redundant because the broad pathname pattern in the config already covers the attachments path. Update the image config to keep only the needed unique entry in the localPatterns array, using the existing localPatterns setup in next.config.ts as the place to simplify and avoid overlapping patterns.app/api/content/attachments/[branch]/[semester]/[subject]/[...path]/route.ts (1)
51-53: 🚀 Performance & Scalability | 🔵 Trivial | ⚖️ Poor tradeoffWhole file buffered into memory via
fs.readFile.For larger attachments (e.g. scanned PDFs), buffering the entire file for every request adds memory pressure. Consider streaming the file (e.g.
fs.createReadStreampiped into the response) if attachment sizes are expected to grow beyond small diagram images.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/api/content/attachments/`[branch]/[semester]/[subject]/[...path]/route.ts around lines 51 - 53, The attachment handler in route.ts is buffering the entire file with fs.readFile, which can create unnecessary memory pressure for larger uploads. Update the file-serving logic in the request handler to stream the attachment instead of loading it all at once, using the existing filePath-based flow and preserving the current content-type/response handling in the route.components/pyqs/question-attachments.tsx (1)
58-81: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueInconsistent logging level between attachment warning paths.
Invalid-path and missing-file warnings (lines 59-61, 78-80) log unconditionally via
console.warn, while malformed/unsupported-type warnings usewarnInDevelopment(dev-only). If this is intentional (ops visibility for missing content in production), consider a brief comment; otherwise align them for consistency.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@components/pyqs/question-attachments.tsx` around lines 58 - 81, The attachment warning paths in question-attachments.tsx use different logging behaviors: the invalid-path and missing-file branches in the attachment rendering flow log with console.warn while the malformed/unsupported-type paths use warnInDevelopment. Update the logging in the AttachmentImage/attachment existence checks so the behavior is consistent with the intended policy, or add a brief inline comment in the relevant branches explaining why these warnings are emitted unconditionally.components/pyqs/attachment-image.tsx (1)
66-75: 🚀 Performance & Scalability | 🔵 Trivial | ⚖️ Poor tradeoffFixed 960×720 intrinsic size can cause layout shift for non-4:3 diagrams.
Hardcoding
width/heightregardless of each diagram's real aspect ratio means the browser reserves a 4:3 box before load; once a differently-shaped image loads, the box resizes, producing CLS. Consider storing actual dimensions per attachment or wrapping in an aspect-ratio-agnostic container (e.g.fillwith a CSSaspect-ratioderived from metadata).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@components/pyqs/attachment-image.tsx` around lines 66 - 75, The fixed 960×720 intrinsic size in AttachmentImage can cause layout shift for images that are not 4:3. Update the Image usage in attachment-image.tsx so it uses the real dimensions for each attachment or a metadata-driven, aspect-ratio-aware layout instead of hardcoded width and height. Locate the logic around AttachmentImage and its Image props, and adjust the component to reserve space based on the actual image aspect ratio while preserving lazy loading and error handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@app/api/content/attachments/`[branch]/[semester]/[subject]/[...path]/route.ts:
- Around line 25-32: The GET handler in the route’s attachment path parsing is
double-decoding the catch-all segments, which can break valid filenames
containing percent characters. Update the logic in GET to stop calling
decodeURIComponent on pathSegments and build attachmentPath directly from
pathSegments.join("/"), keeping the rest of the RouteContext params handling
unchanged.
In `@components/pyqs/attachment-image.tsx`:
- Around line 61-77: The image wrapper in AttachmentImage is hiding meaningful
content from assistive technology because the container is marked
aria-hidden="true" while the Image has a useful alt. Remove aria-hidden from the
wrapper in attachment-image so the diagram and its alt text remain exposed to
the accessibility tree, keeping the existing Image rendering and error handling
intact.
In `@lib/content/attachment-path.ts`:
- Around line 14-16: The path handling in normalizeSegment() and the attachment
path builder is only lowercasing inputs, so unsafe branch/semester/subject
values like path traversal segments can escape the intended content root. Add
validation in the code path that builds diagramsDir and any path.join usage to
reject traversal/absolute segments before combining them, or alternatively
resolve the final path and ensure it is anchored under CONTENT_BASE_DIR. Use the
unique symbols normalizeSegment, diagramsDir, and CONTENT_BASE_DIR to locate the
fix.
---
Nitpick comments:
In
`@app/api/content/attachments/`[branch]/[semester]/[subject]/[...path]/route.ts:
- Around line 51-53: The attachment handler in route.ts is buffering the entire
file with fs.readFile, which can create unnecessary memory pressure for larger
uploads. Update the file-serving logic in the request handler to stream the
attachment instead of loading it all at once, using the existing filePath-based
flow and preserving the current content-type/response handling in the route.
In `@components/pyqs/attachment-image.tsx`:
- Around line 66-75: The fixed 960×720 intrinsic size in AttachmentImage can
cause layout shift for images that are not 4:3. Update the Image usage in
attachment-image.tsx so it uses the real dimensions for each attachment or a
metadata-driven, aspect-ratio-aware layout instead of hardcoded width and
height. Locate the logic around AttachmentImage and its Image props, and adjust
the component to reserve space based on the actual image aspect ratio while
preserving lazy loading and error handling.
In `@components/pyqs/question-attachments.tsx`:
- Around line 58-81: The attachment warning paths in question-attachments.tsx
use different logging behaviors: the invalid-path and missing-file branches in
the attachment rendering flow log with console.warn while the
malformed/unsupported-type paths use warnInDevelopment. Update the logging in
the AttachmentImage/attachment existence checks so the behavior is consistent
with the intended policy, or add a brief inline comment in the relevant branches
explaining why these warnings are emitted unconditionally.
In `@next.config.ts`:
- Around line 6-13: The local image pattern list is redundant because the broad
pathname pattern in the config already covers the attachments path. Update the
image config to keep only the needed unique entry in the localPatterns array,
using the existing localPatterns setup in next.config.ts as the place to
simplify and avoid overlapping patterns.
In `@types/pyq.ts`:
- Around line 10-18: QuestionAttachment currently marks title, alt, caption, and
aiContext as required even though attachment-utils helpers treat them as
optional and runtime JSON may omit them. Update the QuestionAttachment type in
pyq.ts to make these fields optional (or otherwise align the interface with the
actual runtime shape), and keep isQuestionAttachment and the
getAttachmentAlt/getAttachmentTitle/getAttachmentCaption helpers consistent with
that contract so consumers do not assume guaranteed string values.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f1dc1b1e-ab94-4bb1-a7f2-b32dcf35b268
📒 Files selected for processing (25)
app/api/content/attachments/[branch]/[semester]/[subject]/[...path]/route.tsapp/layout.tsxapp/rgpv/[branch]/[semester]/[subject]/pyqs/[paper]/page.tsxcomponents/pyqs/attachment-image.tsxcomponents/pyqs/question-attachments.tsxcontent/rgpv/common/semester-2/bt-104/diagrams/december-2023/Q.1-a-dec-2023.webpcontent/rgpv/common/semester-2/bt-104/diagrams/december-2023/Q.1-b-dec-2023.webpcontent/rgpv/common/semester-2/bt-104/diagrams/december-2024/Q.1-b-dec-2024.webpcontent/rgpv/common/semester-2/bt-104/diagrams/december-2024/Q.2-a-dec-2024.webpcontent/rgpv/common/semester-2/bt-104/diagrams/december-2025/Q.1-b-dec-2025.webpcontent/rgpv/common/semester-2/bt-104/diagrams/december-2025/Q.6-a-dec-2025.webpcontent/rgpv/common/semester-2/bt-104/diagrams/june-2023/Q.1-a-june-2023.webpcontent/rgpv/common/semester-2/bt-104/diagrams/june-2023/Q.1-b-june-2023.webpcontent/rgpv/common/semester-2/bt-104/diagrams/june-2024/Q.2-a-june-2024.webpcontent/rgpv/common/semester-2/bt-104/diagrams/june-2025/Q.1-b-june-2025.webpcontent/rgpv/common/semester-2/bt-104/diagrams/june-2025/Q.2-b-june-2025.webpcontent/rgpv/common/semester-2/bt-104/diagrams/november-2022/Q.1-a-dec-2022.webpcontent/rgpv/common/semester-2/bt-104/diagrams/november-2022/Q.1-b-dec-2022.webpcontent/rgpv/common/semester-2/bt-104/pyqs.jsonlib/ai/prompt-builder.tslib/content/attachment-path.tslib/content/attachment-utils.tslib/content/question-mapper.tsnext.config.tstypes/pyq.ts
💤 Files with no reviewable changes (1)
- app/layout.tsx
🎉 Congratulations @imuniqueshiv!Thank you for contributing to HyperLearningTech. Your pull request has been successfully merged into main. 📦 Merge Summary
🚀 Keep Contributing
Thank you for helping make HyperLearningTech better. Happy Coding! 🚀 |
Pull Request
Summary
Add production-ready diagram attachment support for Previous Year Questions (PYQs), enabling circuit diagrams to be rendered alongside questions and automatically included as structured context for AI-generated answers.
Related Issue
Closes #
Type of Change
What Changed?
attachmentsdata model.content/directory using a dedicated API route.aiContextinto the AI prompt builder so Gemini receives complete circuit information without OCR or Vision API.Screenshots (UI Changes Only)
NA
Testing
Checklist
main.npx prettier --write <file>).npm run format:checkpasses.npm run lintpasses.npm run typecheckpasses.npm run buildpasses.Additional Notes
Architecture Highlights
attachmentssupport for PYQs.content/directory instead ofpublic/.aiContextrather than OCR or image recognition.Future Ready
The attachment architecture is designed to support additional resource types without changing the data model, including:
This implementation is fully backward compatible with the existing PYQ system while providing a scalable foundation for richer educational content.
Summary by CodeRabbit
New Features
Bug Fixes