Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions app/api/collections/[collection_id]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { NextResponse } from 'next/server';

const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000';

// GET /api/collections/[collection_id] - Get a specific collection
export async function GET(
request: Request,
{ params }: { params: Promise<{ collection_id: string }> }
) {
const { collection_id } = await params;
const apiKey = request.headers.get('X-API-KEY');

if (!apiKey) {
return NextResponse.json(
{ error: 'Missing X-API-KEY header' },
{ status: 401 }
);
}

try {
const response = await fetch(
`${backendUrl}/api/v1/collections/${collection_id}?include_docs=true`,
{
headers: {
'X-API-KEY': apiKey,
},
}
);

const text = await response.text();
const data = text ? JSON.parse(text) : {};

if (!response.ok) {
return NextResponse.json(data, { status: response.status });
}

return NextResponse.json(data, { status: response.status });
} catch (error: any) {
return NextResponse.json(
{ success: false, error: error.message, data: null },
{ status: 500 }
);
}
}

// DELETE /api/collection/[collection_id] - Delete a collection
export async function DELETE(
request: Request,
{ params }: { params: Promise<{ collection_id: string }> }
) {
const { collection_id } = await params;
const apiKey = request.headers.get('X-API-KEY');

if (!apiKey) {
return NextResponse.json(
{ error: 'Missing X-API-KEY header' },
{ status: 401 }
);
}

try {
const response = await fetch(
`${backendUrl}/api/v1/collections/${collection_id}`,
{
method: 'DELETE',
headers: {
'X-API-KEY': apiKey,
},
}
);

const text = await response.text();
const data = text ? JSON.parse(text) : { success: true };

if (!response.ok) {
return NextResponse.json(data, { status: response.status });
}

return NextResponse.json(data, { status: response.status });
} catch (error: any) {
return NextResponse.json(
{ success: false, error: error.message, data: null },
{ status: 500 }
);
}
}
44 changes: 44 additions & 0 deletions app/api/collections/jobs/[job_id]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { NextResponse } from 'next/server';

const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000';

// GET /api/collections/jobs/[job_id] - Get collection job status
export async function GET(
request: Request,
{ params }: { params: Promise<{ job_id: string }> }
) {
const { job_id } = await params;
const apiKey = request.headers.get('X-API-KEY');

if (!apiKey) {
return NextResponse.json(
{ error: 'Missing X-API-KEY header' },
{ status: 401 }
);
}

try {
const response = await fetch(
`${backendUrl}/api/v1/collections/jobs/${job_id}`,
{
headers: {
'X-API-KEY': apiKey,
},
}
);

const text = await response.text();
const data = text ? JSON.parse(text) : {};

if (!response.ok) {
return NextResponse.json(data, { status: response.status });
}

return NextResponse.json(data, { status: response.status });
} catch (error: any) {
return NextResponse.json(
{ success: false, error: error.message, data: null },
{ status: 500 }
);
}
}
84 changes: 84 additions & 0 deletions app/api/collections/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { NextRequest, NextResponse } from 'next/server';


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(
{ error: 'Missing X-API-KEY header' },
{ status: 401 }
);
}

try {
const response = await fetch(`${backendUrl}/api/v1/collections/`, {
headers: {
'X-API-KEY': apiKey,
},
});

// Handle empty responses (204 No Content, etc.)
const text = await response.text();
const data = text ? JSON.parse(text) : [];

if (!response.ok) {
return NextResponse.json(data, { status: response.status });
}

return NextResponse.json(data, { status: response.status });
} catch (error: any) {
return NextResponse.json(
{ success: false, error: error.message, data: null },
{ status: 500 }
);
}
}

export async function POST(request: NextRequest) {
try {
// Get the API key from request headers
const apiKey = request.headers.get('X-API-KEY');

if (!apiKey) {
return NextResponse.json(
{ error: 'Missing X-API-KEY header' },
{ status: 401 }
);
}

// Get the JSON body from the request
const body = await request.json();

// Get backend URL from environment variable
const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000';

// Forward the request to the actual backend
const response = await fetch(`${backendUrl}/api/v1/collections/`, {
method: 'POST',
body: JSON.stringify(body),
headers: {
'X-API-KEY': apiKey,
'Content-Type': 'application/json',
},
});

// Handle empty responses (204 No Content, etc.)
const text = await response.text();
const data = text ? JSON.parse(text) : { success: true };

// Return the response with the same status code
if (!response.ok) {
return NextResponse.json(data, { status: response.status });
}

return NextResponse.json(data, { status: response.status });
} catch (error: any) {
console.error('Proxy error:', error);
return NextResponse.json(
{ error: 'Failed to forward request to backend', details: error.message },
{ status: 500 }
);
}
}
1 change: 1 addition & 0 deletions app/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export default function Sidebar({ collapsed, activeRoute = '/evaluations' }: Sid
]
},
{ name: 'Documents', route: '/document' },
{ name: 'Knowledge Base', route: '/knowledge-base' },
// { name: 'Model Testing', route: '/model-testing', comingSoon: true },
// { name: 'Guardrails', route: '/guardrails', comingSoon: true },
// { name: 'Redteaming', route: '/redteaming', comingSoon: true },
Expand Down
25 changes: 18 additions & 7 deletions app/components/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,25 @@
/**
* Converts a date string to IST timezone and formats it
* @param dateString - Date string from backend (in IST format but without timezone info)
* @returns Formatted date string in en-GB locale with 12-hour format
* @returns Formatted date string (e.g., "15 Jan 2024, 14:30")
*/
export const formatDate = (dateString: string): string => {
// Parse the date string and treat it as IST time
const date = new Date(dateString);
// Add 5.5 hours (IST offset) since the input is already in IST but parsed as UTC
const istDate = new Date(date.getTime() + (5.5 * 60 * 60 * 1000));
return istDate.toLocaleString('en-GB', { hour12: true });
export const formatDate = (dateString?: string): string => {
if (!dateString) return 'N/A';
try {
const date = new Date(dateString);
if (Number.isNaN(date.getTime())) {
return dateString;
}
const istDate = new Date(date.getTime() + (5.5 * 60 * 60 * 1000));
const day = istDate.getDate();
const month = istDate.toLocaleDateString('en-US', { month: 'short' });
const year = istDate.getFullYear();
const hours = String(istDate.getHours()).padStart(2, '0');
const minutes = String(istDate.getMinutes()).padStart(2, '0');
return `${day} ${month} ${year}, ${hours}:${minutes}`;
} catch {
return dateString;
}
};

/**
Expand Down
36 changes: 2 additions & 34 deletions app/document/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useRouter } from 'next/navigation'
import { APIKey, STORAGE_KEY } from '../keystore/page';
import Sidebar from '../components/Sidebar';
import { useToast } from '../components/Toast';
import { formatDate } from '../components/utils';

// Backend response interface
export interface Document {
Expand Down Expand Up @@ -298,7 +299,7 @@ export default function DocumentPage() {
{/* Content Area - Split View */}
<div className="flex-1 overflow-hidden flex" style={{ backgroundColor: '#fafafa' }}>
{/* Left Side: Document List */}
<div className="w-2/5 border-r overflow-y-auto" style={{ borderColor: 'hsl(0, 0%, 85%)' }}>
<div className="w-1/3 border-r overflow-y-auto" style={{ borderColor: 'hsl(0, 0%, 85%)' }}>
<DocumentListing
documents={currentDocuments}
selectedDocument={selectedDocument}
Expand Down Expand Up @@ -367,22 +368,6 @@ function DocumentListing({
currentPage,
onPageChange,
}: DocumentListingProps) {
const formatDate = (dateString?: string) => {
if (!dateString) return 'N/A';
try {
const date = new Date(dateString);
const istDate = new Date(date.getTime() + (5.5 * 60 * 60 * 1000));
const day = istDate.getDate();
const month = istDate.toLocaleDateString('en-US', { month: 'short' });
const year = istDate.getFullYear();
const hours = String(istDate.getHours()).padStart(2, '0');
const minutes = String(istDate.getMinutes()).padStart(2, '0');
return `${day} ${month} ${year}, ${hours}:${minutes}`;
} catch {
return dateString;
}
};

return (
<div className="h-full flex flex-col">
<div className="p-4 border-b" style={{ backgroundColor: 'hsl(0, 0%, 100%)', borderColor: 'hsl(0, 0%, 85%)' }}>
Expand Down Expand Up @@ -594,23 +579,6 @@ function DocumentPreview({ document, isLoading }: DocumentPreviewProps) {
setImageLoadError(false);
}, [document?.id]);

const formatDate = (dateString?: string) => {
if (!dateString) return 'N/A';
try {
const date = new Date(dateString);
// Add 5.5 hours (IST offset) since the input is already in IST but parsed as UTC
const istDate = new Date(date.getTime() + (5.5 * 60 * 60 * 1000));
const day = istDate.getDate();
const month = istDate.toLocaleDateString('en-US', { month: 'short' });
const year = istDate.getFullYear();
const hours = String(istDate.getHours()).padStart(2, '0');
const minutes = String(istDate.getMinutes()).padStart(2, '0');
return `${day} ${month} ${year}, ${hours}:${minutes}`;
} catch {
return dateString;
}
};

const getFileExtension = (filename: string) => {
const parts = filename.split('.');
return parts.length > 1 ? parts[parts.length - 1].toLowerCase() : '';
Expand Down
Loading