bgbye routing fix

This commit is contained in:
makearmy 2025-10-15 19:05:56 -04:00
parent 3c76ab69e5
commit c1fbdc843c
4 changed files with 56 additions and 50 deletions

View file

@ -2,6 +2,7 @@
# Public (used by client-side dropdown fetches)
# ─────────────────────────────────────────────
NEXT_PUBLIC_API_BASE_URL=https://forms.lasereverything.net
BG_BYE_UPSTREAM=https://makearmy.io/bgbye/process
# ─────────────────────────────────────────────
# Server-side Directus

View file

@ -0,0 +1,47 @@
export const runtime = "nodejs";
import { NextResponse } from "next/server";
/**
* Proxies multipart POSTs (file + method) to the bgbye upstream.
* Set BG_BYE_UPSTREAM to the FULL endpoint that accepts the form:
* e.g. http://127.0.0.1:8010/process
* http://localhost:8010/api/removebg
*/
export async function POST(req: Request) {
const upstream = process.env.BG_BYE_UPSTREAM;
if (!upstream) {
return NextResponse.json(
{ error: "BG_BYE_UPSTREAM is not configured on the server" },
{ status: 500 }
);
}
try {
const form = await req.formData();
// Forward the form as-is to the upstream
const ures = await fetch(upstream, {
method: "POST",
body: form,
// Let undici set boundary; don't set Content-Type manually
});
const contentType = ures.headers.get("content-type") || "application/octet-stream";
const status = ures.status;
// Stream/buffer back to the client preserving content-type
const ab = await ures.arrayBuffer();
return new Response(Buffer.from(ab), {
status,
headers: {
"content-type": contentType,
// Allow the client to see error text if upstream returns text
"cache-control": "no-store",
},
});
} catch (err: any) {
const msg = err?.message || String(err);
return NextResponse.json({ error: `Proxy error: ${msg}` }, { status: 502 });
}
}

View file

@ -1,43 +0,0 @@
// /app/api/bgremove/route.ts
import { NextResponse } from "next/server";
export const runtime = "nodejs";
export const dynamic = "force-dynamic";
const BGBYE_URL =
process.env.BGBYE_URL ||
process.env.BG_BYE_URL ||
process.env.BGREMOVER_BASE_URL || // <-- support your existing env var
"http://bgbye:7001";
export async function POST(req: Request) {
try {
const inForm = await req.formData();
const method = String(inForm.get("method") || "");
const file = inForm.get("file") as any;
// Loosen the guard: some Node/undici builds return a File-like Blob from a different realm
if (!file || !method) {
return NextResponse.json({ error: "file and method are required" }, { status: 400 });
}
const outForm = new FormData();
const filename = (file as any).name || "upload";
outForm.set("method", method);
outForm.set("file", file, filename);
const res = await fetch(`${BGBYE_URL}/remove_background/`, { method: "POST", body: outForm });
const buf = await res.arrayBuffer();
return new NextResponse(buf, {
status: res.status,
headers: {
"content-type": res.headers.get("content-type") || "application/octet-stream",
"cache-control": "no-store",
},
});
} catch (err: any) {
return NextResponse.json({ error: String(err?.message || err) }, { status: 500 });
}
}

View file

@ -194,7 +194,8 @@ export default function BackgroundRemoverPage() {
fd.append("file", blobToSend);
fd.append("method", key);
const res = await fetch("/api/bgremove", { method: "POST", body: fd });
// CHANGED: call local proxy instead of a hardcoded service
const res = await fetch("/api/bgbye/process", { method: "POST", body: fd });
if (!res.ok) {
const txt = await res.text().catch(() => "");
const retryable = /out of memory|onnxruntime|cuda|allocate|500/i.test(txt);
@ -320,7 +321,8 @@ export default function BackgroundRemoverPage() {
const fd = new FormData();
fd.append("file", file);
fd.append("method", active);
const res = await fetch("/api/bgremove", { method: "POST", body: fd });
// CHANGED: call local proxy instead of a hardcoded service
const res = await fetch("/api/bgbye/process", { method: "POST", body: fd });
if (!res.ok) throw new Error(await res.text());
const outBlob = await res.blob();
const ms = performance.now() - t0;
@ -373,10 +375,10 @@ export default function BackgroundRemoverPage() {
{file?.name ?? <span className="italic"> none </span>}
</div>
{/* Preview frame */}
{/* Preview frame (border removed per your note) */}
<div
ref={frameRef}
className="app-frame checkerboard relative w-full rounded-2xl border border-zinc-800/80 shadow-inner"
className="app-frame checkerboard relative w-full rounded-2xl shadow-inner"
style={{ aspectRatio: `${aspect}`, maxWidth: "1200px", maxHeight: "80vh", marginInline: "auto" }}
onDragOver={(e) => e.preventDefault()}
onDrop={onDrop}
@ -475,7 +477,7 @@ export default function BackgroundRemoverPage() {
{pendingCount > 0 ? `Running… ${doneCount}/${METHODS.length}` : "Run all methods"}
</button>
{/* GPU-safe toggle: sits next to Run All on mobile; keeps position naturally on larger screens */}
{/* GPU-safe toggle */}
<label className="flex items-center gap-2 text-sm text-zinc-300 cursor-pointer select-none order-1">
<input type="checkbox" checked={gpuSafe} onChange={(e) => setGpuSafe(e.target.checked)} /> GPU-safe mode
</label>
@ -494,7 +496,7 @@ export default function BackgroundRemoverPage() {
)}
</div>
{/* Right-side controls collapse under on mobile */}
{/* Right-side controls */}
<div className="sm:ml-auto flex items-center gap-3 w-full sm:w-auto order-3">
<input
type="range"
@ -536,4 +538,3 @@ export default function BackgroundRemoverPage() {
</div>
);
}