Conversation
📝 WalkthroughWalkthroughAdds comprehensive Text-to-Speech evaluation functionality including new API proxy route handlers, a complete interactive TTS evaluation page with dataset/run/result management, component theme system adoption, and UI refinements across existing evaluations interface. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
📝 Coding Plan
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: 6
🧹 Nitpick comments (4)
app/components/TabNavigation.tsx (1)
23-39: Add tab semantics to match the visual treatment.This now renders like a tablist, but assistive tech still sees a row of generic buttons. Adding
role="tablist"on the container androle="tab"plusaria-selectedon each button will make the active tab discoverable to screen readers.♿ Suggested update
- <div className="border-b flex gap-1 px-4" style={{ backgroundColor: colors.bg.primary, borderColor: colors.border }}> + <div + role="tablist" + className="border-b flex gap-1 px-4" + style={{ backgroundColor: colors.bg.primary, borderColor: colors.border }} + > {tabs.map((tab) => { const isActive = activeTab === tab.id; return ( <button key={tab.id} + role="tab" + aria-selected={isActive} + tabIndex={isActive ? 0 : -1} onClick={() => onTabChange(tab.id)} className="px-4 py-2.5 text-sm font-medium border-b-2 transition-colors" style={{🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/components/TabNavigation.tsx` around lines 23 - 39, The tab UI in TabNavigation renders as buttons but lacks ARIA semantics; update the container (the div in TabNavigation where tabs.map is rendered) to include role="tablist", and update each tab button (inside tabs.map where onClick={() => onTabChange(tab.id)} is defined) to include role="tab" and an aria-selected attribute set to true when activeTab === tab.id (false otherwise); ensure the active styling logic remains unchanged and keep the existing key, onClick, and className props on the button.app/text-to-speech/page.tsx (2)
405-411: Data loading effect dependencies.The
useEffectat lines 405-411 correctly triggers onapiKeysandactiveTabchanges. The load functions (loadLanguages,loadDatasets,loadRuns) are defined in the component body and capture the currentapiKeysstate, so they work correctly. However, ESLint'sexhaustive-depsrule would flag this pattern.Consider wrapping these functions with
useCallbackfor consistency and to satisfy linting rules, though the current implementation is functionally correct.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/text-to-speech/page.tsx` around lines 405 - 411, The effect that calls loadLanguages, loadDatasets, and loadRuns is fine functionally but will trigger ESLint exhaustive-deps because those loaders are declared in the component scope; wrap each loader (loadLanguages, loadDatasets, loadRuns) with useCallback and include their stable identity in the dependency array used by the useEffect (which currently depends on apiKeys and activeTab) so the linter is satisfied while preserving the current behavior when activeTab or apiKeys change.
117-134: Potential performance issue with event listener re-attachment.The
onPlayTogglecallback in the dependency array (line 134) will cause this effect to re-run whenever the parent component re-renders, since the callback at line 1424 is an inline arrow function that's recreated each time. This results in frequent listener detachment/reattachment.Consider using a ref to store the callback to avoid unnecessary effect re-runs:
♻️ Stable callback pattern
function AudioPlayerFromUrl({ signedUrl, isPlaying, onPlayToggle, sampleLabel, durationSeconds, sizeBytes, }: { signedUrl: string; isPlaying: boolean; onPlayToggle: () => void; sampleLabel?: string; durationSeconds?: number | null; sizeBytes?: number | null; }) { const audioRef = useRef<HTMLAudioElement>(null); + const onPlayToggleRef = useRef(onPlayToggle); + onPlayToggleRef.current = onPlayToggle; const [duration, setDuration] = useState(0); const [currentTime, setCurrentTime] = useState(0); useEffect(() => { const audio = audioRef.current; if (!audio) return; const handleLoadedMetadata = () => setDuration(audio.duration); const handleTimeUpdate = () => setCurrentTime(audio.currentTime); - const handleEnded = () => onPlayToggle(); + const handleEnded = () => onPlayToggleRef.current(); audio.addEventListener('loadedmetadata', handleLoadedMetadata); audio.addEventListener('timeupdate', handleTimeUpdate); audio.addEventListener('ended', handleEnded); return () => { audio.removeEventListener('loadedmetadata', handleLoadedMetadata); audio.removeEventListener('timeupdate', handleTimeUpdate); audio.removeEventListener('ended', handleEnded); }; - }, [onPlayToggle]); + }, []);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/text-to-speech/page.tsx` around lines 117 - 134, The effect re-attaches audio event listeners whenever the inline onPlayToggle prop changes; store the callback in a stable ref (e.g., onPlayToggleRef) and update that ref inside a separate effect so the audio event-effect can use onPlayToggleRef.current and keep an empty dependency array (or only audioRef) to avoid re-registering listeners; update the handleEnded closure to call onPlayToggleRef.current() and ensure you set onPlayToggleRef.current = onPlayToggle when the prop changes.app/evaluations/page.tsx (1)
428-447: Partial color system adoption in tooltip elements.The tooltip button and content still use hardcoded hex values (e.g.,
#737373,#fafafa,#ffffff,#e5e5e5,#171717) instead of the centralized color tokens. While these values match the color system definitions, using the tokens directly would ensure consistency if the color scheme changes.♻️ Example refactor for tooltip button
<button onMouseEnter={() => setShowHowItWorksTooltip(true)} onMouseLeave={() => setShowHowItWorksTooltip(false)} className="p-1 rounded-full" style={{ - color: '#737373', - backgroundColor: showHowItWorksTooltip ? '#fafafa' : 'transparent', + color: colors.text.secondary, + backgroundColor: showHowItWorksTooltip ? colors.bg.secondary : 'transparent', transition: 'all 0.15s ease' }} >As per coding guidelines: "Use centralized colors from
/app/lib/colors.tsfor styling, not hardcoded hex values".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/evaluations/page.tsx` around lines 428 - 447, The tooltip button and tooltip content are using hardcoded hex colors; replace these inline hex values with the centralized color tokens exported from /app/lib/colors.ts (use the same tokens that map to `#737373`, `#fafafa`, `#ffffff`, `#e5e5e5`, `#171717`) in the style objects for the button and the tooltip div so the appearance of showHowItWorksTooltip-driven styles (the button element that references showHowItWorksTooltip and the tooltip container div with className "absolute left-0 top-full...") use the shared color constants instead of literal hex strings; update the imports and replace the style properties (color, backgroundColor, borderColor) to use those token names.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/api/evaluations/tts/datasets/route.ts`:
- Around line 3-15: The GET handler in this route proxies an empty X-API-KEY to
the backend instead of rejecting unauthenticated requests; update the GET
function to check request.headers.get('X-API-KEY') (same as POST and the other
GET in evaluations/tts/datasets/[dataset_id]/route.ts) and return a 401
NextResponse when apiKey is missing or falsy, avoiding the backend fetch; only
perform the fetch when apiKey is present and include the header value in the
proxied request.
In `@app/api/evaluations/tts/results/`[result_id]/route.ts:
- Around line 3-19: The GET handler in route.ts currently reads X-API-KEY into
the apiKey variable and forwards an empty string to the backend; update the GET
function to fail fast like PATCH by checking request.headers.get('X-API-KEY')
(the apiKey variable) and if missing return a 401 NextResponse with a JSON error
body immediately, avoiding forwarding empty keys to the backend and keeping GET
and PATCH response shapes consistent.
In `@app/api/evaluations/tts/runs/`[run_id]/route.ts:
- Around line 8-23: The handler currently reads apiKey via
request.headers.get('X-API-KEY') and forwards an empty string to backend;
instead, in the route handler (before building backendUrlWithParams and calling
fetch) check if apiKey is falsy and immediately return a 401 Unauthorized
response; update the logic around apiKey and the fetch call (symbols: apiKey,
request.headers.get, backendUrlWithParams, fetch) so unauthenticated requests
short-circuit locally rather than proxying to the backend.
In `@app/api/evaluations/tts/runs/route.ts`:
- Around line 3-15: The GET handler currently forwards an empty X-API-KEY header
instead of enforcing the same auth guard as the POST; update the GET function to
read apiKey via request.headers.get('X-API-KEY') and if it's missing/empty
return a 401 NextResponse (mirroring the POST behavior) before calling fetch;
only when apiKey is present should you call
fetch(`${backendUrl}/api/v1/evaluations/tts/runs`, { headers: { 'X-API-KEY':
apiKey } }) and return NextResponse.json with the upstream response.
In `@app/components/DetailedResultsTable.tsx`:
- Around line 120-124: The table header order in DetailedResultsTable.tsx was
changed to "Question → Ground Truth → Answer" but the CSV export in
app/evaluations/[id]/page.tsx still writes rows as "Question,Answer,Ground
Truth", causing a mismatch; update the CSV row generation in that page.tsx (the
code that builds/writes the CSV rows where you currently emit "Question,Answer,
Ground Truth") to emit columns in the same order as the UI: "Question,Ground
Truth,Answer" (or alternatively revert the DetailedResultsTable header to the
original order) so both the table display and the individual CSV export match
exactly.
In `@app/text-to-speech/page.tsx`:
- Around line 551-557: The evaluation-creation flow resets the form and reloads
runs but lacks user feedback; update the completion logic in the block that
calls await response.json(), setEvaluationName(''), setSelectedDatasetId(null),
and await loadRuns() to also call toast.success with a concise success message
(mirroring handleCreateDataset's toast.success usage) so users receive
confirmation after starting an evaluation run.
---
Nitpick comments:
In `@app/components/TabNavigation.tsx`:
- Around line 23-39: The tab UI in TabNavigation renders as buttons but lacks
ARIA semantics; update the container (the div in TabNavigation where tabs.map is
rendered) to include role="tablist", and update each tab button (inside tabs.map
where onClick={() => onTabChange(tab.id)} is defined) to include role="tab" and
an aria-selected attribute set to true when activeTab === tab.id (false
otherwise); ensure the active styling logic remains unchanged and keep the
existing key, onClick, and className props on the button.
In `@app/evaluations/page.tsx`:
- Around line 428-447: The tooltip button and tooltip content are using
hardcoded hex colors; replace these inline hex values with the centralized color
tokens exported from /app/lib/colors.ts (use the same tokens that map to
`#737373`, `#fafafa`, `#ffffff`, `#e5e5e5`, `#171717`) in the style objects for the button
and the tooltip div so the appearance of showHowItWorksTooltip-driven styles
(the button element that references showHowItWorksTooltip and the tooltip
container div with className "absolute left-0 top-full...") use the shared color
constants instead of literal hex strings; update the imports and replace the
style properties (color, backgroundColor, borderColor) to use those token names.
In `@app/text-to-speech/page.tsx`:
- Around line 405-411: The effect that calls loadLanguages, loadDatasets, and
loadRuns is fine functionally but will trigger ESLint exhaustive-deps because
those loaders are declared in the component scope; wrap each loader
(loadLanguages, loadDatasets, loadRuns) with useCallback and include their
stable identity in the dependency array used by the useEffect (which currently
depends on apiKeys and activeTab) so the linter is satisfied while preserving
the current behavior when activeTab or apiKeys change.
- Around line 117-134: The effect re-attaches audio event listeners whenever the
inline onPlayToggle prop changes; store the callback in a stable ref (e.g.,
onPlayToggleRef) and update that ref inside a separate effect so the audio
event-effect can use onPlayToggleRef.current and keep an empty dependency array
(or only audioRef) to avoid re-registering listeners; update the handleEnded
closure to call onPlayToggleRef.current() and ensure you set
onPlayToggleRef.current = onPlayToggle when the prop changes.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: aeeaea44-f3fc-4af4-9144-fc3598f962bf
📒 Files selected for processing (11)
app/api/evaluations/stt/datasets/[dataset_id]/route.tsapp/api/evaluations/tts/datasets/[dataset_id]/route.tsapp/api/evaluations/tts/datasets/route.tsapp/api/evaluations/tts/results/[result_id]/route.tsapp/api/evaluations/tts/runs/[run_id]/route.tsapp/api/evaluations/tts/runs/route.tsapp/components/DetailedResultsTable.tsxapp/components/Sidebar.tsxapp/components/TabNavigation.tsxapp/evaluations/page.tsxapp/text-to-speech/page.tsx
| export async function GET(request: Request) { | ||
| const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000'; | ||
| const apiKey = request.headers.get('X-API-KEY'); | ||
|
|
||
| try { | ||
| const response = await fetch(`${backendUrl}/api/v1/evaluations/tts/datasets`, { | ||
| headers: { | ||
| 'X-API-KEY': apiKey || '', | ||
| }, | ||
| }); | ||
|
|
||
| const data = await response.json(); | ||
| return NextResponse.json(data, { status: response.status }); |
There was a problem hiding this comment.
Reject unauthenticated dataset-list GETs here too.
POST in this file and GET in app/api/evaluations/tts/datasets/[dataset_id]/route.ts already return 401 when X-API-KEY is missing, but this handler still proxies X-API-KEY: '' to the backend. That makes the auth contract inconsistent and turns a local 401 into an extra backend call whose behavior now depends on backend header parsing.
🔐 Suggested fix
export async function GET(request: Request) {
const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000';
const apiKey = request.headers.get('X-API-KEY');
+
+ if (!apiKey) {
+ return NextResponse.json(
+ { success: false, error: 'Unauthorized: Missing API key', data: null },
+ { status: 401 }
+ );
+ }
try {
const response = await fetch(`${backendUrl}/api/v1/evaluations/tts/datasets`, {
headers: {
- 'X-API-KEY': apiKey || '',
+ 'X-API-KEY': apiKey,
},
});🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/api/evaluations/tts/datasets/route.ts` around lines 3 - 15, The GET
handler in this route proxies an empty X-API-KEY to the backend instead of
rejecting unauthenticated requests; update the GET function to check
request.headers.get('X-API-KEY') (same as POST and the other GET in
evaluations/tts/datasets/[dataset_id]/route.ts) and return a 401 NextResponse
when apiKey is missing or falsy, avoiding the backend fetch; only perform the
fetch when apiKey is present and include the header value in the proxied
request.
| export async function GET( | ||
| request: Request, | ||
| { params }: { params: Promise<{ result_id: string }> } | ||
| ) { | ||
| const { result_id } = await params; | ||
| const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000'; | ||
| const apiKey = request.headers.get('X-API-KEY'); | ||
|
|
||
| try { | ||
| const response = await fetch(`${backendUrl}/api/v1/evaluations/tts/results/${result_id}`, { | ||
| headers: { | ||
| 'X-API-KEY': apiKey || '', | ||
| }, | ||
| }); | ||
|
|
||
| const data = await response.json(); | ||
| return NextResponse.json(data, { status: response.status }); |
There was a problem hiding this comment.
Fail fast on missing API keys for result GETs as well.
PATCH already rejects missing X-API-KEY, but GET still forwards an empty value to the backend. Keeping both methods consistent here avoids anonymous proxy calls and gives the client a stable 401 response shape.
🔐 Suggested fix
export async function GET(
request: Request,
{ params }: { params: Promise<{ result_id: string }> }
) {
const { result_id } = await params;
const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000';
const apiKey = request.headers.get('X-API-KEY');
+
+ if (!apiKey) {
+ return NextResponse.json(
+ { success: false, error: 'Unauthorized: Missing API key', data: null },
+ { status: 401 }
+ );
+ }
try {
const response = await fetch(`${backendUrl}/api/v1/evaluations/tts/results/${result_id}`, {
headers: {
- 'X-API-KEY': apiKey || '',
+ 'X-API-KEY': apiKey,
},
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export async function GET( | |
| request: Request, | |
| { params }: { params: Promise<{ result_id: string }> } | |
| ) { | |
| const { result_id } = await params; | |
| const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000'; | |
| const apiKey = request.headers.get('X-API-KEY'); | |
| try { | |
| const response = await fetch(`${backendUrl}/api/v1/evaluations/tts/results/${result_id}`, { | |
| headers: { | |
| 'X-API-KEY': apiKey || '', | |
| }, | |
| }); | |
| const data = await response.json(); | |
| return NextResponse.json(data, { status: response.status }); | |
| export async function GET( | |
| request: Request, | |
| { params }: { params: Promise<{ result_id: string }> } | |
| ) { | |
| const { result_id } = await params; | |
| const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000'; | |
| const apiKey = request.headers.get('X-API-KEY'); | |
| if (!apiKey) { | |
| return NextResponse.json( | |
| { success: false, error: 'Unauthorized: Missing API key', data: null }, | |
| { status: 401 } | |
| ); | |
| } | |
| try { | |
| const response = await fetch(`${backendUrl}/api/v1/evaluations/tts/results/${result_id}`, { | |
| headers: { | |
| 'X-API-KEY': apiKey, | |
| }, | |
| }); | |
| const data = await response.json(); | |
| return NextResponse.json(data, { status: response.status }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/api/evaluations/tts/results/`[result_id]/route.ts around lines 3 - 19,
The GET handler in route.ts currently reads X-API-KEY into the apiKey variable
and forwards an empty string to the backend; update the GET function to fail
fast like PATCH by checking request.headers.get('X-API-KEY') (the apiKey
variable) and if missing return a 401 NextResponse with a JSON error body
immediately, avoiding forwarding empty keys to the backend and keeping GET and
PATCH response shapes consistent.
| const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000'; | ||
| const apiKey = request.headers.get('X-API-KEY'); | ||
|
|
||
| const { searchParams } = new URL(request.url); | ||
| const queryString = searchParams.toString(); | ||
|
|
||
| try { | ||
| const backendUrlWithParams = queryString | ||
| ? `${backendUrl}/api/v1/evaluations/tts/runs/${run_id}?${queryString}` | ||
| : `${backendUrl}/api/v1/evaluations/tts/runs/${run_id}`; | ||
|
|
||
| const response = await fetch(backendUrlWithParams, { | ||
| headers: { | ||
| 'X-API-KEY': apiKey || '', | ||
| }, | ||
| }); |
There was a problem hiding this comment.
Return 401 before proxying unauthenticated run lookups.
This handler currently forwards X-API-KEY: '' when the header is absent, while the dataset-detail proxy already fails fast locally. The mismatch makes GET auth behavior inconsistent across the TTS routes and adds needless backend traffic for anonymous requests.
🔐 Suggested fix
const { run_id } = await params;
const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000';
const apiKey = request.headers.get('X-API-KEY');
+
+ if (!apiKey) {
+ return NextResponse.json(
+ { success: false, error: 'Unauthorized: Missing API key', data: null },
+ { status: 401 }
+ );
+ }
const { searchParams } = new URL(request.url);
const queryString = searchParams.toString();
@@
const response = await fetch(backendUrlWithParams, {
headers: {
- 'X-API-KEY': apiKey || '',
+ 'X-API-KEY': apiKey,
},
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000'; | |
| const apiKey = request.headers.get('X-API-KEY'); | |
| const { searchParams } = new URL(request.url); | |
| const queryString = searchParams.toString(); | |
| try { | |
| const backendUrlWithParams = queryString | |
| ? `${backendUrl}/api/v1/evaluations/tts/runs/${run_id}?${queryString}` | |
| : `${backendUrl}/api/v1/evaluations/tts/runs/${run_id}`; | |
| const response = await fetch(backendUrlWithParams, { | |
| headers: { | |
| 'X-API-KEY': apiKey || '', | |
| }, | |
| }); | |
| const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000'; | |
| const apiKey = request.headers.get('X-API-KEY'); | |
| if (!apiKey) { | |
| return NextResponse.json( | |
| { success: false, error: 'Unauthorized: Missing API key', data: null }, | |
| { status: 401 } | |
| ); | |
| } | |
| const { searchParams } = new URL(request.url); | |
| const queryString = searchParams.toString(); | |
| try { | |
| const backendUrlWithParams = queryString | |
| ? `${backendUrl}/api/v1/evaluations/tts/runs/${run_id}?${queryString}` | |
| : `${backendUrl}/api/v1/evaluations/tts/runs/${run_id}`; | |
| const response = await fetch(backendUrlWithParams, { | |
| headers: { | |
| 'X-API-KEY': apiKey, | |
| }, | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/api/evaluations/tts/runs/`[run_id]/route.ts around lines 8 - 23, The
handler currently reads apiKey via request.headers.get('X-API-KEY') and forwards
an empty string to backend; instead, in the route handler (before building
backendUrlWithParams and calling fetch) check if apiKey is falsy and immediately
return a 401 Unauthorized response; update the logic around apiKey and the fetch
call (symbols: apiKey, request.headers.get, backendUrlWithParams, fetch) so
unauthenticated requests short-circuit locally rather than proxying to the
backend.
| export async function GET(request: Request) { | ||
| const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000'; | ||
| const apiKey = request.headers.get('X-API-KEY'); | ||
|
|
||
| try { | ||
| const response = await fetch(`${backendUrl}/api/v1/evaluations/tts/runs`, { | ||
| headers: { | ||
| 'X-API-KEY': apiKey || '', | ||
| }, | ||
| }); | ||
|
|
||
| const data = await response.json(); | ||
| return NextResponse.json(data, { status: response.status }); |
There was a problem hiding this comment.
Mirror the POST auth guard on the runs GET endpoint.
Right now the list GET proxies X-API-KEY: '' instead of returning 401 like POST does. That makes callers depend on backend behavior for a missing key and weakens the proxy’s own auth boundary.
🔐 Suggested fix
export async function GET(request: Request) {
const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000';
const apiKey = request.headers.get('X-API-KEY');
+
+ if (!apiKey) {
+ return NextResponse.json(
+ { success: false, error: 'Unauthorized: Missing API key', data: null },
+ { status: 401 }
+ );
+ }
try {
const response = await fetch(`${backendUrl}/api/v1/evaluations/tts/runs`, {
headers: {
- 'X-API-KEY': apiKey || '',
+ 'X-API-KEY': apiKey,
},
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export async function GET(request: Request) { | |
| const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000'; | |
| const apiKey = request.headers.get('X-API-KEY'); | |
| try { | |
| const response = await fetch(`${backendUrl}/api/v1/evaluations/tts/runs`, { | |
| headers: { | |
| 'X-API-KEY': apiKey || '', | |
| }, | |
| }); | |
| const data = await response.json(); | |
| return NextResponse.json(data, { status: response.status }); | |
| export async function GET(request: Request) { | |
| const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000'; | |
| const apiKey = request.headers.get('X-API-KEY'); | |
| if (!apiKey) { | |
| return NextResponse.json( | |
| { success: false, error: 'Unauthorized: Missing API key', data: null }, | |
| { status: 401 } | |
| ); | |
| } | |
| try { | |
| const response = await fetch(`${backendUrl}/api/v1/evaluations/tts/runs`, { | |
| headers: { | |
| 'X-API-KEY': apiKey, | |
| }, | |
| }); | |
| const data = await response.json(); | |
| return NextResponse.json(data, { status: response.status }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/api/evaluations/tts/runs/route.ts` around lines 3 - 15, The GET handler
currently forwards an empty X-API-KEY header instead of enforcing the same auth
guard as the POST; update the GET function to read apiKey via
request.headers.get('X-API-KEY') and if it's missing/empty return a 401
NextResponse (mirroring the POST behavior) before calling fetch; only when
apiKey is present should you call
fetch(`${backendUrl}/api/v1/evaluations/tts/runs`, { headers: { 'X-API-KEY':
apiKey } }) and return NextResponse.json with the upstream response.
| <th className="px-4 py-3 text-left text-xs font-semibold uppercase" style={{ color: '#171717', width: '25%' }}> | ||
| Answer | ||
| Ground Truth | ||
| </th> | ||
| <th className="px-4 py-3 text-left text-xs font-semibold uppercase" style={{ color: '#171717', width: '25%' }}> | ||
| Ground Truth | ||
| Answer |
There was a problem hiding this comment.
Keep the individual table and CSV column order aligned.
This reorders the row view to Question → Ground Truth → Answer, but the individual export in app/evaluations/[id]/page.tsx, Lines 283-300, still writes Question,Answer,Ground Truth. That mismatch makes it easy to misread columns when users compare the UI with the downloaded CSV. Please update both surfaces together or keep the existing order here.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/components/DetailedResultsTable.tsx` around lines 120 - 124, The table
header order in DetailedResultsTable.tsx was changed to "Question → Ground Truth
→ Answer" but the CSV export in app/evaluations/[id]/page.tsx still writes rows
as "Question,Answer,Ground Truth", causing a mismatch; update the CSV row
generation in that page.tsx (the code that builds/writes the CSV rows where you
currently emit "Question,Answer, Ground Truth") to emit columns in the same
order as the UI: "Question,Ground Truth,Answer" (or alternatively revert the
DetailedResultsTable header to the original order) so both the table display and
the individual CSV export match exactly.
|
|
||
| await response.json(); | ||
|
|
||
| setEvaluationName(''); | ||
| setSelectedDatasetId(null); | ||
|
|
||
| await loadRuns(); |
There was a problem hiding this comment.
Missing success feedback after starting evaluation.
After successfully creating an evaluation run, the form is reset and runs are reloaded, but no success message is shown to the user. This differs from handleCreateDataset which shows toast.success at line 496.
💡 Proposed fix to add success feedback
await response.json();
+ toast.success('Evaluation started successfully!');
setEvaluationName('');
setSelectedDatasetId(null);
await loadRuns();🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/text-to-speech/page.tsx` around lines 551 - 557, The evaluation-creation
flow resets the form and reloads runs but lacks user feedback; update the
completion logic in the block that calls await response.json(),
setEvaluationName(''), setSelectedDatasetId(null), and await loadRuns() to also
call toast.success with a concise success message (mirroring
handleCreateDataset's toast.success usage) so users receive confirmation after
starting an evaluation run.
Summary by CodeRabbit
New Features
Design
UI Improvements