-
Notifications
You must be signed in to change notification settings - Fork 0
Assessment: Assessment Pipeline #122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
52a2ea4
4b0e674
5d8d9bc
0471dab
fcbf161
4c43136
fd34470
c5640ad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import { NextRequest, NextResponse } from "next/server"; | ||
| import { | ||
| assessmentApiFetch, | ||
| safeParseJson, | ||
| toDownloadResponse, | ||
| } from "@/app/api/assessment/utils"; | ||
|
|
||
| export async function GET( | ||
| request: NextRequest, | ||
| { params }: { params: Promise<{ assessment_id: string }> }, | ||
| ) { | ||
| try { | ||
| const { assessment_id } = await params; | ||
| const queryParams = new URLSearchParams(request.nextUrl.searchParams); | ||
| queryParams.set("get_trace_info", "true"); | ||
|
|
||
| const response = await assessmentApiFetch( | ||
| request, | ||
| `/api/v1/assessment/assessments/${assessment_id}/results?${queryParams.toString()}`, | ||
| { method: "GET" }, | ||
| ); | ||
|
|
||
| const downloadResponse = await toDownloadResponse(response); | ||
| if (downloadResponse) { | ||
| return downloadResponse; | ||
| } | ||
|
|
||
| const data = await safeParseJson(response); | ||
| return NextResponse.json(data, { status: response.status }); | ||
| } catch (error: unknown) { | ||
| console.error("Assessment results proxy error:", error); | ||
| return NextResponse.json( | ||
| { | ||
| error: "Failed to forward request", | ||
| }, | ||
| { status: 500 }, | ||
| ); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| import { NextRequest, NextResponse } from "next/server"; | ||
| import { apiClient } from "@/app/lib/apiClient"; | ||
|
|
||
| interface RouteContext { | ||
| params: Promise<{ assessment_id: string }>; | ||
| } | ||
|
|
||
| export async function POST(request: NextRequest, context: RouteContext) { | ||
| try { | ||
| const { assessment_id } = await context.params; | ||
| const { status, data } = await apiClient( | ||
| request, | ||
| `/api/v1/assessment/assessments/${assessment_id}/retry`, | ||
| { method: "POST" }, | ||
| ); | ||
|
|
||
| return NextResponse.json(data, { status }); | ||
| } catch (error: unknown) { | ||
| console.error("Assessment retry proxy error:", error); | ||
| return NextResponse.json( | ||
| { | ||
| error: "Failed to forward assessment retry request", | ||
| }, | ||
| { status: 500 }, | ||
| ); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| import { NextRequest, NextResponse } from "next/server"; | ||
| import { apiClient } from "@/app/lib/apiClient"; | ||
|
|
||
| export async function GET(request: NextRequest) { | ||
| try { | ||
| const queryString = request.nextUrl.searchParams.toString(); | ||
| const endpoint = `/api/v1/assessment/assessments${ | ||
| queryString ? `?${queryString}` : "" | ||
| }`; | ||
|
|
||
| const { status, data } = await apiClient(request, endpoint, { | ||
| method: "GET", | ||
| }); | ||
|
|
||
| return NextResponse.json(data, { status }); | ||
| } catch (error: unknown) { | ||
| console.error("Assessment list proxy error:", error); | ||
| return NextResponse.json( | ||
| { | ||
| error: "Failed to forward request to backend", | ||
| }, | ||
| { status: 500 }, | ||
| ); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,95 @@ | ||||||||||||||||||||||||||||||||||||||
| import { NextRequest, NextResponse } from "next/server"; | ||||||||||||||||||||||||||||||||||||||
| import { apiClient } from "@/app/lib/apiClient"; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| export async function GET( | ||||||||||||||||||||||||||||||||||||||
| request: NextRequest, | ||||||||||||||||||||||||||||||||||||||
| { params }: { params: Promise<{ dataset_id: string }> }, | ||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||
| const { dataset_id } = await params; | ||||||||||||||||||||||||||||||||||||||
| const fetchContent = | ||||||||||||||||||||||||||||||||||||||
| request.nextUrl.searchParams.get("fetch_content") === "true"; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| // Always request signed URL when fetch_content is needed | ||||||||||||||||||||||||||||||||||||||
| const backendParams = new URLSearchParams(request.nextUrl.searchParams); | ||||||||||||||||||||||||||||||||||||||
| if (fetchContent) { | ||||||||||||||||||||||||||||||||||||||
| backendParams.set("include_signed_url", "true"); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| const endpoint = `/api/v1/assessment/datasets/${dataset_id}${ | ||||||||||||||||||||||||||||||||||||||
| backendParams.toString() ? `?${backendParams.toString()}` : "" | ||||||||||||||||||||||||||||||||||||||
| }`; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const { status, data } = await apiClient(request, endpoint, { | ||||||||||||||||||||||||||||||||||||||
| method: "GET", | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| if (status >= 400) { | ||||||||||||||||||||||||||||||||||||||
| return NextResponse.json(data, { status }); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| // Download file from S3 server-side and return as base64 | ||||||||||||||||||||||||||||||||||||||
| if (fetchContent) { | ||||||||||||||||||||||||||||||||||||||
| const signedUrl = | ||||||||||||||||||||||||||||||||||||||
| (data as { data?: { signed_url?: string }; signed_url?: string })?.data | ||||||||||||||||||||||||||||||||||||||
| ?.signed_url || | ||||||||||||||||||||||||||||||||||||||
| (data as { data?: { signed_url?: string }; signed_url?: string }) | ||||||||||||||||||||||||||||||||||||||
| ?.signed_url; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| if (!signedUrl) { | ||||||||||||||||||||||||||||||||||||||
| return NextResponse.json( | ||||||||||||||||||||||||||||||||||||||
| { error: "No signed URL available" }, | ||||||||||||||||||||||||||||||||||||||
| { status: 404 }, | ||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const fileResponse = await fetch(signedUrl); | ||||||||||||||||||||||||||||||||||||||
| if (!fileResponse.ok) { | ||||||||||||||||||||||||||||||||||||||
| return NextResponse.json( | ||||||||||||||||||||||||||||||||||||||
| { error: "Failed to fetch file from storage" }, | ||||||||||||||||||||||||||||||||||||||
| { status: 502 }, | ||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const arrayBuffer = await fileResponse.arrayBuffer(); | ||||||||||||||||||||||||||||||||||||||
| const base64 = Buffer.from(arrayBuffer).toString("base64"); | ||||||||||||||||||||||||||||||||||||||
| return NextResponse.json( | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+45
to
+55
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cap This path buffers the entire object into memory and then expands it again as base64. A single large dataset can spike memory hard enough to take the route down. Either return the signed URL to the client or enforce a strict size cap before Possible guardrail const fileResponse = await fetch(signedUrl);
if (!fileResponse.ok) {
return NextResponse.json(
{ error: "Failed to fetch file from storage" },
{ status: 502 },
);
}
+ const contentLength = Number(
+ fileResponse.headers.get("content-length") || "0",
+ );
+ const MAX_EMBEDDED_BYTES = 5 * 1024 * 1024;
+ if (contentLength > MAX_EMBEDDED_BYTES) {
+ return NextResponse.json(
+ { error: "Dataset file is too large to embed in the response" },
+ { status: 413 },
+ );
+ }
+
const arrayBuffer = await fileResponse.arrayBuffer();
const base64 = Buffer.from(arrayBuffer).toString("base64");🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
| { ...(data as Record<string, unknown>), file_content: base64 }, | ||||||||||||||||||||||||||||||||||||||
| { status: 200 }, | ||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| return NextResponse.json(data, { status }); | ||||||||||||||||||||||||||||||||||||||
| } catch (error: unknown) { | ||||||||||||||||||||||||||||||||||||||
| console.error("Assessment dataset details proxy error:", error); | ||||||||||||||||||||||||||||||||||||||
| return NextResponse.json( | ||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||
| error: "Failed to forward request to backend", | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
| { status: 500 }, | ||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| export async function DELETE( | ||||||||||||||||||||||||||||||||||||||
| request: NextRequest, | ||||||||||||||||||||||||||||||||||||||
| { params }: { params: Promise<{ dataset_id: string }> }, | ||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||
| const { dataset_id } = await params; | ||||||||||||||||||||||||||||||||||||||
| const { status, data } = await apiClient( | ||||||||||||||||||||||||||||||||||||||
| request, | ||||||||||||||||||||||||||||||||||||||
| `/api/v1/assessment/datasets/${dataset_id}`, | ||||||||||||||||||||||||||||||||||||||
| { method: "DELETE" }, | ||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| return NextResponse.json(data, { status }); | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+79
to
+85
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle 204 deletes without If the backend returns Suggested fix const { status, data } = await apiClient(
request,
`/api/v1/assessment/datasets/${dataset_id}`,
{ method: "DELETE" },
);
+ if (status === 204) {
+ return new NextResponse(null, { status });
+ }
+
return NextResponse.json(data, { status });📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
| } catch (error: unknown) { | ||||||||||||||||||||||||||||||||||||||
| console.error("Assessment dataset delete proxy error:", error); | ||||||||||||||||||||||||||||||||||||||
| return NextResponse.json( | ||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||
| error: "Failed to forward request to backend", | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
| { status: 500 }, | ||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| import { NextRequest, NextResponse } from "next/server"; | ||
| import { apiClient } from "@/app/lib/apiClient"; | ||
|
|
||
| export async function GET(request: NextRequest) { | ||
| try { | ||
| const { status, data } = await apiClient( | ||
| request, | ||
| "/api/v1/assessment/datasets", | ||
| { method: "GET" }, | ||
| ); | ||
|
|
||
| return NextResponse.json(data, { status }); | ||
| } catch (error: unknown) { | ||
| console.error("Assessment datasets list proxy error:", error); | ||
| return NextResponse.json( | ||
| { | ||
| error: "Failed to forward request to backend", | ||
| }, | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| { status: 500 }, | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| export async function POST(request: NextRequest) { | ||
| try { | ||
| const formData = await request.formData(); | ||
|
|
||
| const { status, data } = await apiClient( | ||
| request, | ||
| "/api/v1/assessment/datasets", | ||
| { | ||
| method: "POST", | ||
| body: formData, | ||
| }, | ||
| ); | ||
|
|
||
| return NextResponse.json(data, { status }); | ||
| } catch (error: unknown) { | ||
| console.error("Assessment datasets create proxy error:", error); | ||
| return NextResponse.json( | ||
| { | ||
| error: "Failed to forward request to backend", | ||
| }, | ||
| { status: 500 }, | ||
| ); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import { NextRequest, NextResponse } from "next/server"; | ||
| import { | ||
| assessmentApiFetch, | ||
| safeParseJson, | ||
| toDownloadResponse, | ||
| } from "@/app/api/assessment/utils"; | ||
|
|
||
| export async function GET( | ||
| request: NextRequest, | ||
| { params }: { params: Promise<{ evaluation_id: string }> }, | ||
| ) { | ||
| try { | ||
| const { evaluation_id } = await params; | ||
| const queryString = request.nextUrl.searchParams.toString(); | ||
| const endpoint = `/api/v1/assessment/evaluations/${evaluation_id}/results${ | ||
| queryString ? `?${queryString}` : "" | ||
| }`; | ||
|
|
||
| const response = await assessmentApiFetch(request, endpoint, { | ||
| method: "GET", | ||
| }); | ||
|
|
||
| const downloadResponse = await toDownloadResponse(response); | ||
| if (downloadResponse) { | ||
| return downloadResponse; | ||
| } | ||
|
|
||
| const data = await safeParseJson(response); | ||
| return NextResponse.json(data, { status: response.status }); | ||
| } catch (error: unknown) { | ||
| console.error("Assessment evaluation results proxy error:", error); | ||
| return NextResponse.json( | ||
| { | ||
| error: "Failed to forward request", | ||
| }, | ||
| { status: 500 }, | ||
| ); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| import { NextRequest, NextResponse } from "next/server"; | ||
| import { apiClient } from "@/app/lib/apiClient"; | ||
|
|
||
| interface RouteContext { | ||
| params: Promise<{ evaluation_id: string }>; | ||
| } | ||
|
|
||
| export async function POST(request: NextRequest, context: RouteContext) { | ||
| try { | ||
| const { evaluation_id } = await context.params; | ||
| const { status, data } = await apiClient( | ||
| request, | ||
| `/api/v1/assessment/evaluations/${evaluation_id}/retry`, | ||
| { method: "POST" }, | ||
| ); | ||
|
|
||
| return NextResponse.json(data, { status }); | ||
| } catch (error: unknown) { | ||
| console.error("Assessment evaluation retry proxy error:", error); | ||
| return NextResponse.json( | ||
| { | ||
| error: "Failed to forward evaluation retry request", | ||
| }, | ||
| { status: 500 }, | ||
| ); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| import { NextRequest, NextResponse } from "next/server"; | ||
| import { apiClient } from "@/app/lib/apiClient"; | ||
|
|
||
| export async function GET(request: NextRequest) { | ||
| try { | ||
| const queryString = request.nextUrl.searchParams.toString(); | ||
| const endpoint = `/api/v1/assessment/evaluations${ | ||
| queryString ? `?${queryString}` : "" | ||
| }`; | ||
|
|
||
| const { status, data } = await apiClient(request, endpoint, { | ||
| method: "GET", | ||
| }); | ||
|
|
||
| return NextResponse.json(data, { status }); | ||
| } catch (error: unknown) { | ||
| console.error("Assessment evaluations list proxy error:", error); | ||
| return NextResponse.json( | ||
| { | ||
| error: "Failed to forward request to backend", | ||
| }, | ||
| { status: 500 }, | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| export async function POST(request: NextRequest) { | ||
| try { | ||
| const body = await request.json(); | ||
|
|
||
| const { status, data } = await apiClient( | ||
| request, | ||
| "/api/v1/assessment/evaluations", | ||
| { | ||
| method: "POST", | ||
| body: JSON.stringify(body), | ||
| }, | ||
| ); | ||
|
|
||
| return NextResponse.json(data, { status }); | ||
| } catch (error: unknown) { | ||
| console.error("Assessment evaluations create proxy error:", error); | ||
| return NextResponse.json( | ||
| { | ||
| error: "Failed to forward request to backend", | ||
| }, | ||
| { status: 500 }, | ||
| ); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update the code also as per this comment: https://github.com/ProjectTech4DevAI/kaapi-frontend/pull/122/changes#r3153720284