Conversation
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
Greptile SummaryThis PR successfully connects the frontend UI to the backend study pack generation endpoint, enabling end-to-end functionality for generating study materials from user notes. Key Changes:
Issues Found:
Confidence Score: 3/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant Frontend as Frontend (page.tsx)
participant API as API Layer (api.ts)
participant Backend as Backend (/generate-study-pack)
participant Gemini as Gemini AI Service
User->>Frontend: Enter notes and click "Generate study pack"
Frontend->>Frontend: Validate input (not empty, not loading)
Frontend->>Frontend: Clear previous study pack & errors
Frontend->>Frontend: Set loading state
Frontend->>API: generateStudyPack(notes)
API->>Backend: POST /generate-study-pack {text}
Backend->>Backend: Validate text (10-10000 chars)
Backend->>Gemini: call_gemini(prompt)
Gemini-->>Backend: JSON response with summary & quiz
Backend->>Backend: clean_response() - Remove markdown
Backend->>Backend: validate_data() - Verify structure
Backend-->>API: GenerateResponse {summary, quiz}
API-->>Frontend: Study pack data
Frontend->>Frontend: Set studyPack state
Frontend->>User: Display summary & interactive quiz
Note over API,Backend: Error Handling
Backend--xAPI: 422 Validation Error (detail[0].msg)
Backend--xAPI: 500 Server Error (detail string)
API--xFrontend: Throw Error with message
Frontend->>Frontend: Set error message
Frontend->>User: Display error alert
Last reviewed commit: e700b92 |
frontend/src/lib/api.ts
Outdated
| const error = await response.json().catch(()=>({})); | ||
| throw new Error( | ||
| error.detail[0].msg || `Request failed with status ${response.status}` | ||
| ); |
There was a problem hiding this comment.
accessing error.detail[0].msg will crash if the error response doesn't have this nested structure
| const error = await response.json().catch(()=>({})); | |
| throw new Error( | |
| error.detail[0].msg || `Request failed with status ${response.status}` | |
| ); | |
| const error = await response.json().catch(()=>({})); | |
| const errorMessage = error.detail?.[0]?.msg || error.detail || `Request failed with status ${response.status}`; | |
| throw new Error(errorMessage); |
Greptile SummaryThis PR connects the frontend to the
Confidence Score: 3/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant PageTSX as page.tsx
participant ApiTS as api.ts
participant Backend as /generate-study-pack
participant Gemini as GeminiService
User->>PageTSX: Click "Generate study pack"
PageTSX->>PageTSX: setLoading(true), clear errors
PageTSX->>ApiTS: generateStudyPack(notes)
ApiTS->>Backend: POST /generate-study-pack {text}
Backend->>Backend: Validate GenerateRequest (empty, length)
alt Validation fails
Backend-->>ApiTS: 422 {detail: [{msg: "..."}]}
ApiTS-->>PageTSX: throw Error(detail[0].msg)
PageTSX-->>User: Show error alert
else Validation passes
Backend->>Gemini: call_gemini(prompt)
alt Gemini unavailable
Gemini-->>Backend: None
Backend-->>ApiTS: 500 {detail: "Failed to generate..."}
ApiTS-->>PageTSX: throw Error(detail)
PageTSX-->>User: Show error alert
else Gemini responds
Gemini-->>Backend: JSON string
Backend->>Backend: clean_response + validate_data
Backend-->>ApiTS: 200 {summary[], quiz[]}
ApiTS-->>PageTSX: GenerateResponse
PageTSX->>PageTSX: setStudyPack(response)
PageTSX-->>User: Render summary + quiz UI
end
end
Last reviewed commit: b428fa5 |
frontend/src/tests/home.test.tsx
Outdated
| render(<Home />); | ||
|
|
||
| fireEvent.change(screen.getByRole("textbox"), { | ||
| target: {value: "q".repeat} |
There was a problem hiding this comment.
"q".repeat passes the function, not a string
"q".repeat is a reference to the String.prototype.repeat function itself, not a call to it. The textarea value will be set to the string representation of the function (something like "function repeat() { [native code] }"), not a 10001-character string. This means the test is not actually testing the long-text scenario — it's setting a short unrelated string.
| target: {value: "q".repeat} | |
| target: {value: "q".repeat(10001)} |
| @field_validator("text") | ||
| @classmethod | ||
| def text_length_constraint(cls, v: str) -> str: | ||
| stripped = v.strip() | ||
| # validate length | ||
| if len(stripped) < 10: | ||
| raise ValueError(f"text must not be less than 10 characters") | ||
| if len(stripped) > 10000: | ||
| raise ValueError("text must not be more than 10000 characters") | ||
| return v |
There was a problem hiding this comment.
Length constraints now apply to /api/v1/generate too
Before this PR, GenerateRequest only validated that text was non-empty. Adding text_length_constraint here means the /api/v1/generate endpoint now also enforces min 10 / max 10,000 character limits — a breaking change for any existing callers that send short notes (< 10 chars) or very long notes (> 10,000 chars).
If this is intentional, the docstring for /api/v1/generate (line 141) should document the new constraints. If unintentional, consider keeping the length validator only in a subclass or applying it selectively to the /generate-study-pack route.
frontend/src/app/page.tsx
Outdated
| const [showAnswer, setShowAnswer] = useState(false); | ||
|
|
||
| // correct answer if selected answer = answer to question | ||
| const correctAnswer = selectedAnswer === question.answer; |
There was a problem hiding this comment.
Unused variable correctAnswer
correctAnswer is assigned but never read. The component uses option === question.answer and option === selectedAnswer inline instead. This will trigger a lint warning and should be removed or used.
| const correctAnswer = selectedAnswer === question.answer; |
Greptile SummaryThis PR successfully integrates the frontend with the Key changes:
Issues found:
Confidence Score: 3/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant Frontend as page.tsx
participant API as api.ts
participant Backend as /generate-study-pack
participant Gemini as Gemini Service
User->>Frontend: Enter notes & click Generate
Frontend->>Frontend: Clear previous studyPack & errors
Frontend->>API: generateStudyPack(notes)
API->>Backend: POST /generate-study-pack {text}
Backend->>Backend: Validate StudyPackRequest (10-10000 chars)
alt Validation fails
Backend-->>API: 422 {detail: [{msg}]}
API-->>Frontend: throw Error(msg)
Frontend->>Frontend: setErrorMessage(user-friendly)
Frontend-->>User: Display error alert
else Validation passes
Backend->>Gemini: call_gemini(prompt)
alt Gemini unavailable
Gemini-->>Backend: null
Backend-->>API: 500 {detail: "Gemini unavailable"}
API-->>Frontend: throw Error
Frontend-->>User: Display error alert
else Gemini success
Gemini-->>Backend: JSON response
Backend->>Backend: clean_response & validate_data
Backend-->>API: 200 {summary, quiz}
API-->>Frontend: {summary, quiz}
Frontend->>Frontend: setStudyPack(response)
Frontend-->>User: Display summary & interactive quiz
end
end
Last reviewed commit: 55e5232 |
| class StudyPackRequest(GenerateRequest): | ||
| """ | ||
| Request body for POST /generate-study-pack | ||
| - text: The user's study notes to process | ||
| """ | ||
| @field_validator("text") | ||
| @classmethod | ||
| def text_length_constraint(cls, v: str) -> str: | ||
| stripped = v.strip() | ||
| # validate length | ||
| if len(stripped) < 10: | ||
| raise ValueError(f"text must not be less than 10 characters") | ||
| if len(stripped) > 10000: | ||
| raise ValueError("text must not be more than 10000 characters") | ||
| return v |
There was a problem hiding this comment.
Child validator overrides parent's empty check
In Pydantic v2, StudyPackRequest.text_length_constraint completely replaces GenerateRequest.text_must_not_be_empty instead of running both. Empty/whitespace text will pass through StudyPackRequest validation unchecked.
| class StudyPackRequest(GenerateRequest): | |
| """ | |
| Request body for POST /generate-study-pack | |
| - text: The user's study notes to process | |
| """ | |
| @field_validator("text") | |
| @classmethod | |
| def text_length_constraint(cls, v: str) -> str: | |
| stripped = v.strip() | |
| # validate length | |
| if len(stripped) < 10: | |
| raise ValueError(f"text must not be less than 10 characters") | |
| if len(stripped) > 10000: | |
| raise ValueError("text must not be more than 10000 characters") | |
| return v | |
| class StudyPackRequest(GenerateRequest): | |
| """ | |
| Request body for POST /generate-study-pack | |
| - text: The user's study notes to process | |
| """ | |
| @field_validator("text") | |
| @classmethod | |
| def text_length_constraint(cls, v: str) -> str: | |
| # Must re-check emptiness since child validators override parent | |
| stripped = v.strip() | |
| if not v or not stripped: | |
| raise ValueError("text must not be empty") | |
| # validate length | |
| if len(stripped) < 10: | |
| raise ValueError(f"text must not be less than 10 characters") | |
| if len(stripped) > 10000: | |
| raise ValueError("text must not be more than 10000 characters") | |
| return v |
Greptile SummaryThis PR successfully integrates the frontend UI with the backend Major Changes:
Issues Found:
Confidence Score: 4/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant Frontend as page.tsx
participant API as api.ts
participant Backend as /generate-study-pack
participant Gemini as Gemini API
User->>Frontend: Enter notes & click submit
Frontend->>Frontend: setStudyPack(null)<br/>setErrorMessage(null)<br/>setLoading(true)
Frontend->>API: generateStudyPack(notes)
API->>Backend: POST /generate-study-pack<br/>{text: notes}
alt Validation fails (empty, <10, >10000 chars)
Backend-->>API: 422 {detail: [{msg: "..."}]}
API-->>Frontend: throw Error(detail[0].msg)
Frontend->>Frontend: setErrorMessage()<br/>setLoading(false)
Frontend-->>User: Display error message
else Gemini unavailable
Backend->>Gemini: Generate study pack
Gemini-->>Backend: null
Backend-->>API: 500 {detail: "Gemini unavailable..."}
API-->>Frontend: throw Error(detail)
Frontend->>Frontend: setErrorMessage()<br/>setLoading(false)
Frontend-->>User: Display error message
else Success
Backend->>Gemini: Generate study pack
Gemini-->>Backend: JSON response
Backend->>Backend: clean_response()<br/>validate_data()
Backend-->>API: 200 {summary: [...], quiz: [...]}
API-->>Frontend: Return response
Frontend->>Frontend: setStudyPack(response)<br/>setLoading(false)
Frontend-->>User: Display summary & quiz
end
Last reviewed commit: 641ba13 |
🎉 New feature (Extends application, non-breaking feature)
PR Summary
This PR connects the frontend UI to the backend study pack generation endpoint. It enables the application to send user notes to the backend, receive a structured study pack response, and handle errors gracefully without crashing the page.
Overview
What feature/problem does this PR address?
Previously, the frontend was not connected to the backend study generation endpoint. Users could not generate study packs directly from the UI.
What approach was taken?
frontend/src/lib/api.tsto include a newgenerateStudyPack()function that wraps the POST request to the backend endpoint.frontend/src/app/page.tsxso that the page callsgenerateStudyPack()when the submit button is clicked.Any important design decisions or trade-offs?
backend/main.pyto remove redundant duplicate request classes and ensure clean API responses so both/api/v1/generateand/generate-study-packuseGenerateRequest.Checklist
Unit Test Evidence
Additional Notes
How to Test
Jira Ticket
Jira Ticket(s) - [SOC-16]```