Skip to content

TTS Evaluation#58

Merged
AkhileshNegi merged 12 commits intomainfrom
feature/tts-evaluation
Mar 13, 2026
Merged

TTS Evaluation#58
AkhileshNegi merged 12 commits intomainfrom
feature/tts-evaluation

Conversation

@AkhileshNegi
Copy link
Copy Markdown
Contributor

@AkhileshNegi AkhileshNegi commented Mar 9, 2026

Summary

Target issue is #65

  • New Features

    • Full Text-to-Speech Evaluations page: create datasets, run evaluations, view results, and submit per-result feedback.
    • In-page audio playback with signed-URL support and auto-refresh for active runs.
    • Activated Text-to-Speech item in the sidebar.
  • Bug Fixes

    • Backend operations now require an API key and return clear 401/500 JSON responses on auth or proxy failures.
  • Style

    • Updated UI theme, centralized color tokens, and simplified tab/navigation visuals making it consistent across TTS,STT and Text Evaluation

@AkhileshNegi AkhileshNegi self-assigned this Mar 9, 2026
@AkhileshNegi AkhileshNegi added the enhancement New feature or request label Mar 9, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 9, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a Text-to-Speech evaluation UI and multiple Next.js app-router API proxy handlers for TTS dataset/run/result endpoints, plus a small auth-guard tweak to an STT dataset route; proxies forward X-API-KEY, pass query strings, and return backend JSON/status with consistent error payloads.

Changes

Cohort / File(s) Summary
TTS API Proxy — Datasets
app/api/evaluations/tts/datasets/route.ts, app/api/evaluations/tts/datasets/[dataset_id]/route.ts
New collection (GET, POST) and item (GET) handlers proxying to /api/v1/evaluations/tts/datasets; forward X-API-KEY, use NEXT_PUBLIC_BACKEND_URL (fallback http://localhost:8000), mirror backend JSON/status, and return standardized error payloads.
TTS API Proxy — Runs
app/api/evaluations/tts/runs/route.ts, app/api/evaluations/tts/runs/[run_id]/route.ts
New collection (GET, POST) and item (GET) handlers proxying to /api/v1/evaluations/tts/runs; forward X-API-KEY, passthrough query strings, require API key for POST, and mirror backend responses with consistent error handling.
TTS API Proxy — Results
app/api/evaluations/tts/results/[result_id]/route.ts
New GET and PATCH handlers for /api/v1/evaluations/tts/results/{result_id}; PATCH requires X-API-KEY, forwards JSON body, and mirrors backend JSON/status or returns standardized error payloads.
TTS Evaluation Page (Client)
app/text-to-speech/page.tsx
Large new client page (default export) adding Datasets and Evaluations tabs: dataset creation, run creation/polling, results viewing/editing, audio playback via signed URLs, and PATCH-based feedback with error modal handling.
UI Components — Tabs & Sidebar
app/components/TabNavigation.tsx, app/components/Sidebar.tsx
TabNavigation updated to use centralized color tokens and Tab interface now includes label: string; Sidebar re-enabled the Text-to-Speech menu entry.
Evaluations Page Theming
app/evaluations/page.tsx
Replaced hard-coded colors with centralized tokens, adjusted layout/spacing and wording, and updated loading indicators and theming across the evaluations UI.
STT Dataset Route — Auth Guard
app/api/evaluations/stt/datasets/[dataset_id]/route.ts
Added API key guard returning 401 when X-API-KEY is missing and tightened header forwarding to send the exact API key value to backend.

Sequence Diagram

sequenceDiagram
    actor User
    participant Browser as Browser Client
    participant NextAPI as Next.js API Route
    participant Backend as Backend API

    rect rgba(100,150,200,0.5)
    Note over User,Backend: Create Dataset / Run
    User->>Browser: Submit form (includes X-API-KEY)
    Browser->>NextAPI: POST /api/evaluations/tts/... (forward X-API-KEY & JSON)
    NextAPI->>Backend: POST /api/v1/evaluations/tts/... (forward headers & body)
    Backend-->>NextAPI: 200/201 JSON
    NextAPI-->>Browser: Return backend JSON/status
    end

    rect rgba(150,100,200,0.5)
    Note over User,Backend: Polling & Feedback
    Browser->>NextAPI: GET /api/evaluations/tts/runs?...
    NextAPI->>Backend: GET /api/v1/evaluations/tts/runs?...
    Backend-->>NextAPI: runs + results
    NextAPI-->>Browser: return JSON/status
    Browser->>NextAPI: PATCH /api/evaluations/tts/results/{id} (is_correct/comments)
    NextAPI->>Backend: PATCH /api/v1/evaluations/tts/results/{id}
    Backend-->>NextAPI: updated result
    NextAPI-->>Browser: updated JSON/status
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • nishika26

Poem

🐰 I hopped through routes and headers bright,

I forwarded keys beneath the night,
Datasets, runs, and results in tune,
I queued a run and hummed a tune,
🥕🎶

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'TTS Evaluation' directly corresponds to the main feature being introduced—comprehensive Text-to-Speech evaluation functionality with datasets, runs, and results management across multiple new API routes and UI components.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/tts-evaluation

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 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/`[dataset_id]/route.ts:
- Around line 9-16: The handler currently reads const apiKey =
request.headers.get('X-API-KEY') and forwards an empty string to fetch, which
proxies unauthenticated callers; change this to reject missing keys up front by
checking if apiKey is falsy and returning a 401/unauthorized response
immediately (do not call fetch), and only call
fetch(`${backendUrl}/api/v1/evaluations/tts/datasets/${dataset_id}`) with the
'X-API-KEY' header when apiKey is present; also ensure you do not send an empty
header value when apiKey is absent.

In `@app/api/evaluations/tts/datasets/route.ts`:
- Around line 3-15: The GET handler currently proxies even when X-API-KEY is
missing; update the GET function to read the API key via
request.headers.get('X-API-KEY') and fail fast by returning a 401 response (use
NextResponse.json or equivalent) if the header is falsy, matching the POST
behavior, before calling fetch to
`${backendUrl}/api/v1/evaluations/tts/datasets`; ensure the same header value is
forwarded when present.

In `@app/api/evaluations/tts/results/`[result_id]/route.ts:
- Around line 7-19: This handler currently reads apiKey but forwards an empty
header; add an upfront auth check (mirror other GET routes) that returns a 401
via NextResponse.json when apiKey is falsy, and only proceed to call
fetch(`${backendUrl}/api/v1/evaluations/tts/results/${result_id}`) when apiKey
exists; use the apiKey variable name for the check and ensure you do not call
fetch or forward an empty 'X-API-KEY' header when missing.

In `@app/api/evaluations/tts/runs/`[run_id]/route.ts:
- Around line 9-23: The route currently extracts apiKey (const apiKey =
request.headers.get('X-API-KEY')) but still forwards empty headers to the
backend; add an early guard that checks apiKey and returns a 401 response
immediately when missing (before constructing backendUrlWithParams or calling
fetch) so unauthenticated reads are rejected locally; update the handler
surrounding apiKey extraction (in route.ts) to perform this check and
short-circuit with a 401/Unauthorized response if apiKey is falsy.

In `@app/api/evaluations/tts/runs/route.ts`:
- Around line 3-15: The GET handler currently proxies requests even when the
X-API-KEY header is missing; add the same API key validation used by the POST
flow: in the exported async function GET(request: Request) check
request.headers.get('X-API-KEY') (the apiKey variable) and if falsy return a 401
response (e.g., NextResponse.json with a descriptive message and status 401)
before performing the fetch to `${backendUrl}/api/v1/evaluations/tts/runs`; keep
the existing fetch headers logic so valid requests continue to forward the API
key.

In `@app/text-to-speech/page.tsx`:
- Around line 894-900: The updateFeedback function is including is_correct even
when null (causing PATCH to send is_correct: null) — change it to only set
payload.is_correct when the value is a boolean (e.g., typeof isCorrect ===
"boolean") and remove any non-null assertions like result.is_correct!; apply the
same guard to the other feedback update call that currently forces
result.is_correct (the similar block mentioned in the review) so comment-only
updates omit is_correct entirely.
- Around line 305-319: The samples mapping currently drops per-sample language
(validSamples -> samples used in the POST to /api/evaluations/tts/datasets), so
the per-sample language selector is ignored; update the mapping that creates
samples so each sample includes its language (e.g., add a language or
language_id field using getLanguageId(sample.language) or the appropriate
sample.language value) before JSON.stringify in the body sent by the fetch call,
ensuring the API receives per-sample language data alongside text while keeping
existing top-level name/description/language_id fields (refer to validSamples,
samples, getLanguageId, and the fetch body).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c5f5bd98-f233-4bd2-a595-1d9dc4de6525

📥 Commits

Reviewing files that changed from the base of the PR and between a0ada14 and 2f91445.

📒 Files selected for processing (7)
  • app/api/evaluations/tts/datasets/[dataset_id]/route.ts
  • app/api/evaluations/tts/datasets/route.ts
  • app/api/evaluations/tts/results/[result_id]/route.ts
  • app/api/evaluations/tts/runs/[run_id]/route.ts
  • app/api/evaluations/tts/runs/route.ts
  • app/components/Sidebar.tsx
  • app/text-to-speech/page.tsx

Comment on lines +3 to +15
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 });
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Enforce X-API-KEY on GET too.

POST already returns 401 when the header is missing, but GET still proxies the request with an empty API key. Please fail fast here as well so dataset reads follow the same auth boundary.

🤖 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 currently proxies even when X-API-KEY is missing; update the GET
function to read the API key via request.headers.get('X-API-KEY') and fail fast
by returning a 401 response (use NextResponse.json or equivalent) if the header
is falsy, matching the POST behavior, before calling fetch to
`${backendUrl}/api/v1/evaluations/tts/datasets`; ensure the same header value is
forwarded when present.

Comment on lines +7 to +19
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 });
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Mirror the existing GET auth check here.

The rest of the app’s API routes already reject missing X-API-KEY headers up front, but this handler still forwards an empty one. That weakens the API boundary for result reads and should be fixed before release.

🤖 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 7 - 19,
This handler currently reads apiKey but forwards an empty header; add an upfront
auth check (mirror other GET routes) that returns a 401 via NextResponse.json
when apiKey is falsy, and only proceed to call
fetch(`${backendUrl}/api/v1/evaluations/tts/results/${result_id}`) when apiKey
exists; use the apiKey variable name for the check and ensure you do not call
fetch or forward an empty 'X-API-KEY' header when missing.

Comment on lines +9 to +23
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 || '',
},
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Guard unauthenticated run reads locally.

This route should return 401 before the fetch when X-API-KEY is missing. Right now it forwards an empty header and relies on the backend to reject it.

🤖 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 9 - 23, The
route currently extracts apiKey (const apiKey =
request.headers.get('X-API-KEY')) but still forwards empty headers to the
backend; add an early guard that checks apiKey and returns a 401 response
immediately when missing (before constructing backendUrlWithParams or calling
fetch) so unauthenticated reads are rejected locally; update the handler
surrounding apiKey extraction (in route.ts) to perform this check and
short-circuit with a 401/Unauthorized response if apiKey is falsy.

Comment on lines +3 to +15
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 });
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Apply the same 401 check on run listing.

POST rejects missing API keys, but this GET path still proxies anonymous traffic to the backend. Keeping both methods consistent avoids surprising auth behavior.

🤖 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 proxies requests even when the X-API-KEY header is missing; add the
same API key validation used by the POST flow: in the exported async function
GET(request: Request) check request.headers.get('X-API-KEY') (the apiKey
variable) and if falsy return a 401 response (e.g., NextResponse.json with a
descriptive message and status 401) before performing the fetch to
`${backendUrl}/api/v1/evaluations/tts/runs`; keep the existing fetch headers
logic so valid requests continue to forward the API key.

Comment on lines +305 to +319
const samples = validSamples.map(sample => ({
text: sample.text.trim(),
}));

const response = await fetch('/api/evaluations/tts/datasets', {
method: 'POST',
headers: {
'X-API-KEY': apiKeys[0].key,
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: datasetName.trim(),
description: datasetDescription.trim() || undefined,
language_id: getLanguageId(datasetLanguage),
samples,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Per-sample language is collected but never sent.

The form lets users set a language on each sample, but this payload strips every sample down to { text }. That makes the language selector misleading and breaks mixed-language datasets.

Suggested fix
       const samples = validSamples.map(sample => ({
         text: sample.text.trim(),
+        language_id: getLanguageId(sample.language),
       }));
📝 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.

Suggested change
const samples = validSamples.map(sample => ({
text: sample.text.trim(),
}));
const response = await fetch('/api/evaluations/tts/datasets', {
method: 'POST',
headers: {
'X-API-KEY': apiKeys[0].key,
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: datasetName.trim(),
description: datasetDescription.trim() || undefined,
language_id: getLanguageId(datasetLanguage),
samples,
const samples = validSamples.map(sample => ({
text: sample.text.trim(),
language_id: getLanguageId(sample.language),
}));
const response = await fetch('/api/evaluations/tts/datasets', {
method: 'POST',
headers: {
'X-API-KEY': apiKeys[0].key,
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: datasetName.trim(),
description: datasetDescription.trim() || undefined,
language_id: getLanguageId(datasetLanguage),
samples,
🤖 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 305 - 319, The samples mapping
currently drops per-sample language (validSamples -> samples used in the POST to
/api/evaluations/tts/datasets), so the per-sample language selector is ignored;
update the mapping that creates samples so each sample includes its language
(e.g., add a language or language_id field using getLanguageId(sample.language)
or the appropriate sample.language value) before JSON.stringify in the body sent
by the fetch call, ensuring the API receives per-sample language data alongside
text while keeping existing top-level name/description/language_id fields (refer
to validSamples, samples, getLanguageId, and the fetch body).

Comment on lines +894 to +900
const updateFeedback = async (resultId: number, isCorrect: boolean, comment?: string) => {
if (apiKeys.length === 0) return;

try {
const payload: { is_correct?: boolean; comment?: string } = {};
if (isCorrect !== undefined) payload.is_correct = isCorrect;
if (comment !== undefined) payload.comment = comment;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don’t force is_correct on comment-only updates.

Line 1226 uses result.is_correct!, but that field is nullable. If the reviewer types a comment before choosing Yes/No, this PATCH can send is_correct: null and fail or overwrite the existing value unexpectedly. Only include is_correct when it is actually boolean.

Suggested fix
-  const updateFeedback = async (resultId: number, isCorrect: boolean, comment?: string) => {
+  const updateFeedback = async (resultId: number, isCorrect?: boolean | null, comment?: string) => {
     if (apiKeys.length === 0) return;
 
     try {
       const payload: { is_correct?: boolean; comment?: string } = {};
-      if (isCorrect !== undefined) payload.is_correct = isCorrect;
+      if (typeof isCorrect === 'boolean') payload.is_correct = isCorrect;
       if (comment !== undefined) payload.comment = comment;
                               onBlur={(e) => {
                                 if (result.status === 'SUCCESS') {
-                                  updateFeedback(result.id, result.is_correct!, e.target.value);
+                                  updateFeedback(result.id, result.is_correct ?? undefined, e.target.value);
                                 }
                               }}

Also applies to: 1217-1227

🤖 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 894 - 900, The updateFeedback
function is including is_correct even when null (causing PATCH to send
is_correct: null) — change it to only set payload.is_correct when the value is a
boolean (e.g., typeof isCorrect === "boolean") and remove any non-null
assertions like result.is_correct!; apply the same guard to the other feedback
update call that currently forces result.is_correct (the similar block mentioned
in the review) so comment-only updates omit is_correct entirely.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
app/text-to-speech/page.tsx (1)

958-964: ⚠️ Potential issue | 🟠 Major

Still sending is_correct: null on comment-only updates.

Line 1284 can pass null via the non-null assertion, and the guards on Line 963 and Line 978 treat anything except undefined as present. The PATCH proxy forwards that body unchanged, so a comment blur can clear or reject the verdict instead of updating only the comment.

Suggested fix
-  const updateFeedback = async (resultId: number, isCorrect: boolean, comment?: string) => {
+  const updateFeedback = async (resultId: number, isCorrect?: boolean | null, comment?: string) => {
     if (apiKeys.length === 0) return;
 
     try {
       const payload: { is_correct?: boolean; comment?: string } = {};
-      if (isCorrect !== undefined) payload.is_correct = isCorrect;
+      if (typeof isCorrect === 'boolean') payload.is_correct = isCorrect;
       if (comment !== undefined) payload.comment = comment;
@@
       if (!response.ok) throw new Error('Failed to update feedback');
 
       setResults(prev => prev.map(r =>
-        r.id === resultId ? { ...r, ...(isCorrect !== undefined && { is_correct: isCorrect }), ...(comment !== undefined && { comment }) } : r
+        r.id === resultId ? { ...r, ...(typeof isCorrect === 'boolean' && { is_correct: isCorrect }), ...(comment !== undefined && { comment }) } : r
       ));
@@
                               onBlur={(e) => {
                                 if (result.status === 'SUCCESS') {
-                                  updateFeedback(result.id, result.is_correct!, e.target.value);
+                                  updateFeedback(result.id, result.is_correct ?? undefined, e.target.value);
                                 }
                               }}

Also applies to: 977-979, 1282-1285

🤖 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 958 - 964, The updateFeedback
function is incorrectly treating null as a valid value and sending is_correct:
null; change the guard so payload.is_correct is only set when isCorrect is a
boolean (e.g., use typeof isCorrect === 'boolean' or isCorrect !== null &&
isCorrect !== undefined) and keep the comment assignment as only when comment
!== undefined; apply the same strict boolean check to the other similar update
sites referenced (the other payload constructions around the comment update and
the other updateFeedback call sites) so comment-only updates never include
is_correct: null.
🤖 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/text-to-speech/page.tsx`:
- Around line 144-151: Several icon-only buttons (e.g., the play button with
onPlayToggle and the buttons that toggle the sidebar, remove a sample, go back,
and refresh runs) lack accessible names; add an accessible name to each such
button by setting an appropriate aria-label (or aria-labelledby) or by including
a visually-hidden text node (sr-only) inside the button. Locate the buttons
using the existing handler identifiers (onPlayToggle, the sidebar toggle
handler, the sample removal handler, the back navigation handler, and the
refresh runs handler) and add concise, descriptive labels like "Play audio",
"Toggle sidebar", "Remove sample", "Go back", and "Refresh runs" to their button
elements.
- Around line 348-360: The auto-refresh check is case-sensitive and misses
statuses like "RUNNING" or "PENDING"; update the condition inside the useEffect
that checks runs to normalize statuses (e.g., use run.status?.toLowerCase())
before comparing to 'running', 'processing', or 'pending', ensuring you handle
undefined/null safely; keep the surrounding logic (activeTab === 'evaluations',
hasRunningEvals variable, and calling loadRuns/clearInterval) unchanged while
replacing the run.status checks with the normalized comparisons.
- Around line 503-537: The loadResults handler can be overwritten by slower
responses; fix it by tracking and ignoring stale responses: add a persistent
request identifier or AbortController that you update before each call in
loadResults (e.g., increment a latestLoadId ref or set currentAbortController),
include that id/abort in the async fetch, and when the response arrives check
the id still matches (or ensure previous requests are aborted) before calling
setResults or setSelectedRunId; update loadResults to use apiKeys and the fetch
URL as before but gate the final setResults/setSelectedRunId with the id/abort
check so only the most recent response takes effect.

---

Duplicate comments:
In `@app/text-to-speech/page.tsx`:
- Around line 958-964: The updateFeedback function is incorrectly treating null
as a valid value and sending is_correct: null; change the guard so
payload.is_correct is only set when isCorrect is a boolean (e.g., use typeof
isCorrect === 'boolean' or isCorrect !== null && isCorrect !== undefined) and
keep the comment assignment as only when comment !== undefined; apply the same
strict boolean check to the other similar update sites referenced (the other
payload constructions around the comment update and the other updateFeedback
call sites) so comment-only updates never include is_correct: null.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 564a7e82-180f-4c7a-abec-8d73f38de4ca

📥 Commits

Reviewing files that changed from the base of the PR and between 2f91445 and 57b3eee.

📒 Files selected for processing (1)
  • app/text-to-speech/page.tsx

Comment on lines +144 to +151
<button
onClick={onPlayToggle}
className="w-6 h-6 flex items-center justify-center rounded-full flex-shrink-0 border-2"
style={{
borderColor: colors.accent.primary,
backgroundColor: 'transparent',
color: colors.accent.primary,
}}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add accessible names to the icon-only buttons.

Line 145, Line 562, Line 815, Line 1149, and Line 1166 render buttons whose only content is an SVG. Without an accessible name, screen-reader users cannot tell which control plays audio, toggles the sidebar, removes a sample, goes back, or refreshes runs.

Suggested fix
-        <button
+        <button
+          aria-label={isPlaying ? 'Pause audio sample' : 'Play audio sample'}
           onClick={onPlayToggle}
           className="w-6 h-6 flex items-center justify-center rounded-full flex-shrink-0 border-2"
@@
-              <button
+              <button
+                aria-label={sidebarCollapsed ? 'Expand sidebar' : 'Collapse sidebar'}
                 onClick={() => setSidebarCollapsed(!sidebarCollapsed)}
                 className="p-1.5 rounded-md"
@@
-                          <button
+                          <button
+                            aria-label={`Remove sample ${idx + 1}`}
                             onClick={() => removeTextSample(sample.id)}
                             className="p-1 rounded flex-shrink-0"
@@
-                <button
+                <button
+                  aria-label="Back to evaluation runs"
                   onClick={() => setSelectedRunId(null)}
                   className="p-1.5 rounded hover:bg-opacity-10"
@@
-              <button
+              <button
+                aria-label="Refresh evaluation runs"
                 onClick={loadRuns}
                 disabled={isLoadingRuns}
                 className="p-1.5 rounded"

Also applies to: 561-565, 814-817, 1148-1151, 1165-1169

🤖 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 144 - 151, Several icon-only
buttons (e.g., the play button with onPlayToggle and the buttons that toggle the
sidebar, remove a sample, go back, and refresh runs) lack accessible names; add
an accessible name to each such button by setting an appropriate aria-label (or
aria-labelledby) or by including a visually-hidden text node (sr-only) inside
the button. Locate the buttons using the existing handler identifiers
(onPlayToggle, the sidebar toggle handler, the sample removal handler, the back
navigation handler, and the refresh runs handler) and add concise, descriptive
labels like "Play audio", "Toggle sidebar", "Remove sample", "Go back", and
"Refresh runs" to their button elements.

Comment on lines +348 to +360
// Auto-refresh runs every 10 seconds if there are running evaluations
useEffect(() => {
if (activeTab !== 'evaluations') return;

const hasRunningEvals = runs.some(run =>
run.status === 'running' || run.status === 'processing' || run.status === 'pending'
);

if (hasRunningEvals) {
const interval = setInterval(() => {
loadRuns();
}, 10000);
return () => clearInterval(interval);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Normalize run status before deciding whether to poll.

This interval check is case-sensitive, but the same file already uses run.status.toLowerCase() elsewhere. If the API returns RUNNING or PENDING, auto-refresh never starts and the runs list stays stale until a manual refresh.

Suggested fix
-    const hasRunningEvals = runs.some(run =>
-      run.status === 'running' || run.status === 'processing' || run.status === 'pending'
-    );
+    const hasRunningEvals = runs.some(run =>
+      ['running', 'processing', 'pending'].includes(run.status.toLowerCase())
+    );
📝 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.

Suggested change
// Auto-refresh runs every 10 seconds if there are running evaluations
useEffect(() => {
if (activeTab !== 'evaluations') return;
const hasRunningEvals = runs.some(run =>
run.status === 'running' || run.status === 'processing' || run.status === 'pending'
);
if (hasRunningEvals) {
const interval = setInterval(() => {
loadRuns();
}, 10000);
return () => clearInterval(interval);
// Auto-refresh runs every 10 seconds if there are running evaluations
useEffect(() => {
if (activeTab !== 'evaluations') return;
const hasRunningEvals = runs.some(run =>
['running', 'processing', 'pending'].includes(run.status.toLowerCase())
);
if (hasRunningEvals) {
const interval = setInterval(() => {
loadRuns();
}, 10000);
return () => clearInterval(interval);
🤖 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 348 - 360, The auto-refresh check
is case-sensitive and misses statuses like "RUNNING" or "PENDING"; update the
condition inside the useEffect that checks runs to normalize statuses (e.g., use
run.status?.toLowerCase()) before comparing to 'running', 'processing', or
'pending', ensuring you handle undefined/null safely; keep the surrounding logic
(activeTab === 'evaluations', hasRunningEvals variable, and calling
loadRuns/clearInterval) unchanged while replacing the run.status checks with the
normalized comparisons.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/evaluations/page.tsx (1)

451-451: ⚠️ Potential issue | 🟡 Minor

Use appropriate semantic HTML for inline text emphasis.

<blockquote> is intended for extended quotations from external sources and will render as a block element with default margins. For inline emphasis of UI element names, use <code> or a styled <span>.

Proposed fix
-                  <li>Click <blockquote>Run Evaluation </blockquote> to start the evaluation process</li>
+                  <li>Click <code className="px-1 rounded" style={{ backgroundColor: '#f5f5f5' }}>Run Evaluation</code> to start the evaluation process</li>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/evaluations/page.tsx` at line 451, Replace the block-level <blockquote>
used around the inline UI label "Run Evaluation" with appropriate inline
semantics: change the markup in the list item that renders 'Click
<blockquote>Run Evaluation</blockquote> to start the evaluation process' to use
<code> (or a styled <span> with an aria-label if needed) so the text is inline
and semantically appropriate for a UI control name; keep the surrounding <li>
and visible text unchanged.
🧹 Nitpick comments (3)
app/text-to-speech/page.tsx (1)

106-123: Unstable onPlayToggle reference causes effect to re-run on every render.

The onPlayToggle callback is created inline in the parent component, so it changes identity on every render. This causes the useEffect to continuously add/remove event listeners, potentially causing audio playback glitches.

♻️ Proposed fix: Use ref to track callback
+  const onPlayToggleRef = useRef(onPlayToggle);
+  onPlayToggleRef.current = onPlayToggle;
+
   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 106 - 123, The effect is re-running
because onPlayToggle is an unstable inline callback; make the effect depend only
on stable values by storing onPlayToggle in a ref and using that ref in the
event handler: create a ref like onPlayToggleRef = useRef(onPlayToggle), update
onPlayToggleRef.current whenever onPlayToggle changes (e.g., in a separate
useEffect or directly before registering listeners), and change handleEnded to
call onPlayToggleRef.current(); then keep the main useEffect that registers
listeners dependent only on audioRef (not onPlayToggle) so it won't re-run on
every render; reference audioRef, onPlayToggleRef, and handleEnded in your
changes.
app/evaluations/page.tsx (2)

91-119: Consider wrapping loadStoredDatasets in useCallback.

The loadStoredDatasets function is called inside a useEffect but isn't included in the dependency array. While this works because the effect triggers on apiKeys change, wrapping it in useCallback would make the dependency relationship explicit and satisfy the react-hooks/exhaustive-deps rule.

Suggested approach
+  const loadStoredDatasets = useCallback(async () => {
-  const loadStoredDatasets = async () => {
     if (!apiKeys.length) return;
     // ... rest of function
-  };
+  }, [apiKeys]);

   useEffect(() => {
     if (apiKeys.length > 0) {
       loadStoredDatasets();
     }
-  }, [apiKeys]);
+  }, [apiKeys, loadStoredDatasets]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/evaluations/page.tsx` around lines 91 - 119, Wrap the loadStoredDatasets
function in React's useCallback and include apiKeys in its dependency array so
the function identity is stable and the react-hooks/exhaustive-deps rule is
satisfied; replace the current declaration of loadStoredDatasets with a
useCallback(() => { ... }, [apiKeys]) (keeping references to setStoredDatasets
and fetch call intact), ensure useEffect depends on loadStoredDatasets (or keep
[apiKeys, loadStoredDatasets]) and add the useCallback import if not already
present.

417-458: Consider consistent use of color tokens throughout.

The file mixes centralized color tokens (e.g., colors.bg.primary on lines 418-419) with hardcoded hex values (e.g., #737373, #171717, #fafafa on lines 429-431, 442-446). For maintainability and theme consistency, consider using color tokens throughout the entire file.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/evaluations/page.tsx` around lines 417 - 458, The tooltip UI mixes
centralized theme tokens with hardcoded hex colors; replace hardcoded values
used in the tooltip/button (e.g., '#737373', '#fafafa', '#171717', '#e5e5e5',
'#ffffff') with the appropriate properties from the shared colors object used
elsewhere in this component (reference showHowItWorksTooltip state, the button
rendering block and the tooltip div) so styling consistently uses colors.bg,
colors.text, colors.border (or other existing tokens) for backgroundColor, color
and borderColor; update the inline styles in the button
onMouseEnter/onMouseLeave block and the tooltip container and headers to use
those tokens.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@app/evaluations/page.tsx`:
- Line 451: Replace the block-level <blockquote> used around the inline UI label
"Run Evaluation" with appropriate inline semantics: change the markup in the
list item that renders 'Click <blockquote>Run Evaluation</blockquote> to start
the evaluation process' to use <code> (or a styled <span> with an aria-label if
needed) so the text is inline and semantically appropriate for a UI control
name; keep the surrounding <li> and visible text unchanged.

---

Nitpick comments:
In `@app/evaluations/page.tsx`:
- Around line 91-119: Wrap the loadStoredDatasets function in React's
useCallback and include apiKeys in its dependency array so the function identity
is stable and the react-hooks/exhaustive-deps rule is satisfied; replace the
current declaration of loadStoredDatasets with a useCallback(() => { ... },
[apiKeys]) (keeping references to setStoredDatasets and fetch call intact),
ensure useEffect depends on loadStoredDatasets (or keep [apiKeys,
loadStoredDatasets]) and add the useCallback import if not already present.
- Around line 417-458: The tooltip UI mixes centralized theme tokens with
hardcoded hex colors; replace hardcoded values used in the tooltip/button (e.g.,
'#737373', '#fafafa', '#171717', '#e5e5e5', '#ffffff') with the appropriate
properties from the shared colors object used elsewhere in this component
(reference showHowItWorksTooltip state, the button rendering block and the
tooltip div) so styling consistently uses colors.bg, colors.text, colors.border
(or other existing tokens) for backgroundColor, color and borderColor; update
the inline styles in the button onMouseEnter/onMouseLeave block and the tooltip
container and headers to use those tokens.

In `@app/text-to-speech/page.tsx`:
- Around line 106-123: The effect is re-running because onPlayToggle is an
unstable inline callback; make the effect depend only on stable values by
storing onPlayToggle in a ref and using that ref in the event handler: create a
ref like onPlayToggleRef = useRef(onPlayToggle), update onPlayToggleRef.current
whenever onPlayToggle changes (e.g., in a separate useEffect or directly before
registering listeners), and change handleEnded to call
onPlayToggleRef.current(); then keep the main useEffect that registers listeners
dependent only on audioRef (not onPlayToggle) so it won't re-run on every
render; reference audioRef, onPlayToggleRef, and handleEnded in your changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3509bdea-736b-4643-9771-4259a9aa365d

📥 Commits

Reviewing files that changed from the base of the PR and between 57b3eee and 22309ad.

📒 Files selected for processing (3)
  • app/components/TabNavigation.tsx
  • app/evaluations/page.tsx
  • app/text-to-speech/page.tsx

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
app/text-to-speech/page.tsx (2)

106-123: Stabilize the onPlayToggle callback to avoid re-attaching event listeners on every render.

The onPlayToggle prop is included in the dependency array, but if the parent component doesn't wrap it in useCallback, this effect will re-run and re-attach event listeners on every render.

♻️ Suggested fix: Remove onPlayToggle from deps, use a ref
+  const onPlayToggleRef = useRef(onPlayToggle);
+  onPlayToggleRef.current = onPlayToggle;
+
   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 106 - 123, The effect currently
re-attaches audio event listeners whenever the onPlayToggle prop identity
changes; stabilize it by removing onPlayToggle from the dependency array and
instead store the latest callback in a ref (e.g., create onPlayToggleRef.current
and update it inside a useEffect when onPlayToggle changes), then have
handleEnded call onPlayToggleRef.current(); keep audioRef, handleLoadedMetadata,
handleTimeUpdate, and the add/removeEventListener logic the same but with a
stable dependency array (no onPlayToggle) so listeners are not re-attached on
every render.

232-232: Consider using a constant instead of state for leftPanelWidth.

The setter is never used, making useState unnecessary overhead.

♻️ Suggested fix
-  const [leftPanelWidth] = useState(450);
+  const leftPanelWidth = 450;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/text-to-speech/page.tsx` at line 232, Replace the unnecessary React state
for leftPanelWidth with a plain constant: remove the useState call that creates
const [leftPanelWidth] = useState(450) and instead declare a constant (e.g.,
const LEFT_PANEL_WIDTH = 450 or const leftPanelWidth = 450) in page.tsx; also
remove the unused useState import if it becomes unused and update any references
to use the constant name.
🤖 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/text-to-speech/page.tsx`:
- Around line 770-784: The "Add Sample" button currently uses a conditional
onClick and visual styles to appear disabled; instead set the button's disabled
attribute to apiKeys.length === 0, keep onClick bound to addTextSample
unconditionally, and update the style logic to depend on the disabled state (or
apiKeys.length) so the button is non-focusable and not interactive when no API
keys exist; target the button element and the addTextSample and apiKeys symbols
when making this change.

---

Nitpick comments:
In `@app/text-to-speech/page.tsx`:
- Around line 106-123: The effect currently re-attaches audio event listeners
whenever the onPlayToggle prop identity changes; stabilize it by removing
onPlayToggle from the dependency array and instead store the latest callback in
a ref (e.g., create onPlayToggleRef.current and update it inside a useEffect
when onPlayToggle changes), then have handleEnded call
onPlayToggleRef.current(); keep audioRef, handleLoadedMetadata,
handleTimeUpdate, and the add/removeEventListener logic the same but with a
stable dependency array (no onPlayToggle) so listeners are not re-attached on
every render.
- Line 232: Replace the unnecessary React state for leftPanelWidth with a plain
constant: remove the useState call that creates const [leftPanelWidth] =
useState(450) and instead declare a constant (e.g., const LEFT_PANEL_WIDTH = 450
or const leftPanelWidth = 450) in page.tsx; also remove the unused useState
import if it becomes unused and update any references to use the constant name.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 20c8f67d-c974-453d-a642-fd062c402df9

📥 Commits

Reviewing files that changed from the base of the PR and between 22309ad and 310bd82.

📒 Files selected for processing (1)
  • app/text-to-speech/page.tsx

Comment on lines +770 to +784
<button
onClick={apiKeys.length > 0 ? addTextSample : undefined}
className="flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm font-medium"
style={{
backgroundColor: apiKeys.length > 0 ? colors.accent.primary : colors.bg.secondary,
color: apiKeys.length > 0 ? '#fff' : colors.text.secondary,
cursor: apiKeys.length > 0 ? 'pointer' : 'not-allowed',
}}
>
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
</svg>
Add Sample
</button>
</div>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use disabled attribute instead of conditional onClick for the "Add Sample" button.

The button is visually styled as disabled when apiKeys.length === 0, but it remains focusable and interactive because disabled is not set. Keyboard users can still tab to and activate the button (though nothing happens).

🔧 Suggested fix
               <button
-                onClick={apiKeys.length > 0 ? addTextSample : undefined}
+                onClick={addTextSample}
+                disabled={apiKeys.length === 0}
                 className="flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm font-medium"
                 style={{
                   backgroundColor: apiKeys.length > 0 ? colors.accent.primary : colors.bg.secondary,
                   color: apiKeys.length > 0 ? '#fff' : colors.text.secondary,
-                  cursor: apiKeys.length > 0 ? 'pointer' : 'not-allowed',
+                  cursor: apiKeys.length === 0 ? 'not-allowed' : 'pointer',
+                  opacity: apiKeys.length === 0 ? 0.6 : 1,
                 }}
               >
📝 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.

Suggested change
<button
onClick={apiKeys.length > 0 ? addTextSample : undefined}
className="flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm font-medium"
style={{
backgroundColor: apiKeys.length > 0 ? colors.accent.primary : colors.bg.secondary,
color: apiKeys.length > 0 ? '#fff' : colors.text.secondary,
cursor: apiKeys.length > 0 ? 'pointer' : 'not-allowed',
}}
>
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
</svg>
Add Sample
</button>
</div>
<button
onClick={addTextSample}
disabled={apiKeys.length === 0}
className="flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm font-medium"
style={{
backgroundColor: apiKeys.length > 0 ? colors.accent.primary : colors.bg.secondary,
color: apiKeys.length > 0 ? '#fff' : colors.text.secondary,
cursor: apiKeys.length === 0 ? 'not-allowed' : 'pointer',
opacity: apiKeys.length === 0 ? 0.6 : 1,
}}
>
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
</svg>
Add Sample
</button>
🤖 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 770 - 784, The "Add Sample" button
currently uses a conditional onClick and visual styles to appear disabled;
instead set the button's disabled attribute to apiKeys.length === 0, keep
onClick bound to addTextSample unconditionally, and update the style logic to
depend on the disabled state (or apiKeys.length) so the button is non-focusable
and not interactive when no API keys exist; target the button element and the
addTextSample and apiKeys symbols when making this change.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
app/api/evaluations/stt/datasets/[dataset_id]/route.ts (1)

1-1: Unused import: NextRequest.

The NextRequest type is imported but not used—the function parameter uses Request instead. Consider removing the unused import for cleanliness.

🧹 Proposed fix
-import { NextResponse, NextRequest } from 'next/server';
+import { NextResponse } from 'next/server';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/evaluations/stt/datasets/`[dataset_id]/route.ts at line 1, The import
list includes an unused symbol NextRequest from 'next/server' while the handler
uses the global Request type; remove NextRequest from the import (leave
NextResponse) to clean up the unused import in the import declaration at the top
of the module and avoid the unused symbol warning.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@app/api/evaluations/stt/datasets/`[dataset_id]/route.ts:
- Line 1: The import list includes an unused symbol NextRequest from
'next/server' while the handler uses the global Request type; remove NextRequest
from the import (leave NextResponse) to clean up the unused import in the import
declaration at the top of the module and avoid the unused symbol warning.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4cd74793-0aa5-4b53-aa2b-9112e0ab83dc

📥 Commits

Reviewing files that changed from the base of the PR and between 310bd82 and 4565b70.

📒 Files selected for processing (2)
  • app/api/evaluations/stt/datasets/[dataset_id]/route.ts
  • app/api/evaluations/tts/datasets/[dataset_id]/route.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/api/evaluations/tts/datasets/[dataset_id]/route.ts

@AkhileshNegi AkhileshNegi force-pushed the feature/tts-evaluation branch from 773c47b to f32ad58 Compare March 12, 2026 10:44
@AkhileshNegi AkhileshNegi requested a review from nishika26 March 12, 2026 12:48
@AkhileshNegi AkhileshNegi merged commit 39b6e9c into main Mar 13, 2026
1 check passed
@AkhileshNegi AkhileshNegi linked an issue Mar 16, 2026 that may be closed by this pull request
@Ayush8923 Ayush8923 deleted the feature/tts-evaluation branch March 20, 2026 11:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TTS Evaluation

2 participants