* Changed prompts to include info about OpenRAG, change status of As Dataframe and As Vector Store to false on OpenSearch component * added markdown to onboarding step * added className to markdown renderer * changed onboarding step to not render span * Added nudges to onboarding content * Added onboarding style for nudges * updated user message and assistant message designs * updated route.ts to handle streaming messages * created new useChatStreaming to handle streaming * changed useChatStreaming to work with the chat page * changed onboarding content to use default messages instead of onboarding steps, and to use the new hook to send messages * added span to the markdown renderer on stream * updated page to use new chat streaming hook * disable animation on completed steps * changed markdown renderer margins * changed css to not display markdown links and texts on white always * added isCompleted to assistant and user messages * removed space between elements on onboarding step to ensure smoother animation * removed opacity 50 on onboarding messages * changed default api to be langflow on chat streaming * added fade in and color transition * added color transition * Rendered onboarding with use-stick-to-bottom * Added use stick to bottom on page * fixed nudges design * changed chat input design * fixed nudges design * made overflow be hidden on main * Added overflow y auto on other pages * Put animate on messages * Add source to types * Adds animate and delay props to messages
142 lines
No EOL
4.2 KiB
TypeScript
142 lines
No EOL
4.2 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server';
|
|
|
|
export async function GET(
|
|
request: NextRequest,
|
|
{ params }: { params: Promise<{ path: string[] }> }
|
|
) {
|
|
return proxyRequest(request, await params);
|
|
}
|
|
|
|
export async function POST(
|
|
request: NextRequest,
|
|
{ params }: { params: Promise<{ path: string[] }> }
|
|
) {
|
|
return proxyRequest(request, await params);
|
|
}
|
|
|
|
export async function PUT(
|
|
request: NextRequest,
|
|
{ params }: { params: Promise<{ path: string[] }> }
|
|
) {
|
|
return proxyRequest(request, await params);
|
|
}
|
|
|
|
export async function DELETE(
|
|
request: NextRequest,
|
|
{ params }: { params: Promise<{ path: string[] }> }
|
|
) {
|
|
return proxyRequest(request, await params);
|
|
}
|
|
|
|
export async function PATCH(
|
|
request: NextRequest,
|
|
{ params }: { params: Promise<{ path: string[] }> }
|
|
) {
|
|
return proxyRequest(request, await params);
|
|
}
|
|
|
|
async function proxyRequest(
|
|
request: NextRequest,
|
|
params: { path: string[] }
|
|
) {
|
|
const backendHost = process.env.OPENRAG_BACKEND_HOST || 'localhost';
|
|
const backendSSL= process.env.OPENRAG_BACKEND_SSL || false;
|
|
const path = params.path.join('/');
|
|
const searchParams = request.nextUrl.searchParams.toString();
|
|
let backendUrl = `http://${backendHost}:8000/${path}${searchParams ? `?${searchParams}` : ''}`;
|
|
if (backendSSL) {
|
|
backendUrl = `https://${backendHost}:8000/${path}${searchParams ? `?${searchParams}` : ''}`;
|
|
}
|
|
|
|
try {
|
|
let body: string | ArrayBuffer | undefined = undefined;
|
|
let willSendBody = false;
|
|
|
|
if (request.method !== 'GET' && request.method !== 'HEAD') {
|
|
const contentType = request.headers.get('content-type') || '';
|
|
const contentLength = request.headers.get('content-length');
|
|
|
|
// For file uploads (multipart/form-data), preserve binary data
|
|
if (contentType.includes('multipart/form-data')) {
|
|
const buf = await request.arrayBuffer();
|
|
if (buf && buf.byteLength > 0) {
|
|
body = buf;
|
|
willSendBody = true;
|
|
}
|
|
} else {
|
|
// For JSON and other text-based content, use text
|
|
const text = await request.text();
|
|
if (text && text.length > 0) {
|
|
body = text;
|
|
willSendBody = true;
|
|
}
|
|
}
|
|
|
|
// Guard against incorrect non-zero content-length when there is no body
|
|
if (!willSendBody && contentLength) {
|
|
// We'll drop content-length/header below
|
|
}
|
|
}
|
|
|
|
const headers = new Headers();
|
|
|
|
// Copy relevant headers from the original request
|
|
for (const [key, value] of request.headers.entries()) {
|
|
const lower = key.toLowerCase();
|
|
if (
|
|
lower.startsWith('host') ||
|
|
lower.startsWith('x-forwarded') ||
|
|
lower.startsWith('x-real-ip') ||
|
|
lower === 'content-length' ||
|
|
(!willSendBody && lower === 'content-type')
|
|
) {
|
|
continue;
|
|
}
|
|
headers.set(key, value);
|
|
}
|
|
|
|
const init: RequestInit = {
|
|
method: request.method,
|
|
headers,
|
|
};
|
|
if (willSendBody) {
|
|
// Convert ArrayBuffer to Uint8Array to satisfy BodyInit in all environments
|
|
const bodyInit: BodyInit = typeof body === 'string' ? body : new Uint8Array(body as ArrayBuffer);
|
|
init.body = bodyInit;
|
|
}
|
|
const response = await fetch(backendUrl, init);
|
|
|
|
const responseHeaders = new Headers();
|
|
|
|
// Copy response headers
|
|
for (const [key, value] of response.headers.entries()) {
|
|
if (!key.toLowerCase().startsWith('transfer-encoding') &&
|
|
!key.toLowerCase().startsWith('connection')) {
|
|
responseHeaders.set(key, value);
|
|
}
|
|
}
|
|
|
|
// For streaming responses, pass the body directly without buffering
|
|
if (response.body) {
|
|
return new NextResponse(response.body, {
|
|
status: response.status,
|
|
statusText: response.statusText,
|
|
headers: responseHeaders,
|
|
});
|
|
} else {
|
|
// Fallback for non-streaming responses
|
|
const responseBody = await response.text();
|
|
return new NextResponse(responseBody, {
|
|
status: response.status,
|
|
statusText: response.statusText,
|
|
headers: responseHeaders,
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error('Proxy error:', error);
|
|
return NextResponse.json(
|
|
{ error: 'Failed to proxy request' },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
} |