Skip to content

Commit

Permalink
Demo: RAG/Docling/llama-index
Browse files Browse the repository at this point in the history
Signed-off-by: Brent Salisbury <[email protected]>
  • Loading branch information
nerdalert committed Oct 21, 2024
1 parent 67eefbb commit 7937b32
Show file tree
Hide file tree
Showing 11 changed files with 1,420 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use server';

import { NextRequest, NextResponse } from 'next/server';
import fetch from 'node-fetch';

export async function DELETE(req: NextRequest, { params }: { params: { collectionName: string } }) {
const { collectionName } = params;

try {
console.log(`Deleting collection: ${collectionName}`);

// Make the API request to the backend to delete the collection
const response = await fetch(`http://127.0.0.1:8000/collections/${encodeURIComponent(collectionName)}`, {
method: 'DELETE'
});

// Check if the response was successful
if (!response.ok) {
const errorText = await response.text();
console.error(`Failed to delete collection: ${errorText}`);
throw new Error(`Failed to delete collection: ${errorText}`);
}

// Return a success response to the client
console.log(`Collection ${collectionName} deleted successfully.`);
return NextResponse.json({ message: `Collection ${collectionName} deleted successfully.` }, { status: 200 });
} catch (error: any) {
console.error('Error deleting collection:', error.message);
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// src/app/api/playground/ragchat/collections/[collectionName]/documents/file/route.ts
'use server';

import { NextRequest, NextResponse } from 'next/server';
import fetch from 'node-fetch';
import FormData from 'form-data';

export async function POST(req: NextRequest, { params }: { params: { collectionName: string } }) {
const { collectionName } = params;

try {
// Parse the form data from the incoming request
const formData = await req.formData();
const file = formData.get('files') as File | null;

if (!file) {
throw new Error('File is required for upload');
}

// Create FormData for the backend request
const backendFormData = new FormData();

// Convert the file to a Buffer for the Node.js environment
const buffer = Buffer.from(await file.arrayBuffer());

// Append the file buffer to FormData
backendFormData.append('file', buffer, file.name);

// Send the file to the backend service
const backendResponse = await fetch(`http://127.0.0.1:8000/collections/${encodeURIComponent(collectionName)}/documents/file`, {
method: 'POST',
body: backendFormData,
headers: backendFormData.getHeaders()
});

const backendResponseText = await backendResponse.text();

if (!backendResponse.ok) {
throw new Error(`Failed to upload file to backend: ${backendResponseText}`);
}

return NextResponse.json({ message: 'File uploaded successfully', data: backendResponseText }, { status: 200 });
} catch (error: any) {
console.error('Error during file upload:', error.message);
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// src/app/api/playground/ragchat/collections/[collectionName]/documents/url/route.ts
`use server`;

import { NextRequest, NextResponse } from 'next/server';

export async function POST(req: NextRequest, { params }: { params: { collectionName: string } }) {
const { collectionName } = params;

try {
const { http_source } = await req.json();

const response = await fetch(`http://localhost:8000/collections/${encodeURIComponent(collectionName)}/documents/url`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ http_source })
});

const responseText = await response.text();

if (!response.ok) {
throw new Error(`Failed to upload URL: ${responseText}`);
}

return NextResponse.json({ message: 'URL uploaded successfully', data: responseText }, { status: 200 });
} catch (error: any) {
console.error('Error uploading URL:', error.message);
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// src/app/api/playground/ragchat/collections/[collectionName]/query/route.ts
'use server';

import { NextRequest, NextResponse } from 'next/server';
import fetch from 'node-fetch';

export async function POST(req: NextRequest, { params }: { params: { collectionName: string } }) {
const { collectionName } = params;

try {
const { question } = await req.json();

console.log(`Received question: ${question} for collection: ${collectionName}`);

// Make the API request to the backend using node-fetch
const response = await fetch(`http://127.0.0.1:8000/collections/${encodeURIComponent(collectionName)}/query`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ question })
});

// Check if the response was successful
if (!response.ok) {
const errorText = await response.text();
console.error(`Failed to query collection: ${errorText}`);
throw new Error(`Failed to query collection: ${errorText}`);
}

// Parse the backend response
const responseData = await response.json();
console.log('Backend response data:', responseData);

// Extract the 'answer' and 'sources' fields
const { answer, sources } = responseData;

// Return the answer and sources to the client
return NextResponse.json({ answer, sources }, { status: 200 });
} catch (error: any) {
console.error('Error querying collection:', error.message);
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
31 changes: 31 additions & 0 deletions src/app/api/playground/ragchat/collections/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// src/app/api/playground/ragchat/collections/route.ts
'use server';

import { NextRequest, NextResponse } from 'next/server';
import fetch from 'node-fetch';

export async function GET(req: NextRequest) {
console.log('Received request to fetch collections');

try {
console.log('Making fetch call to backend service...');

const response = await fetch('http://127.0.0.1:8000/collections', {
method: 'GET',
headers: {
Accept: 'application/json' // Ensure Accept header is set properly
}
});

const rawText = await response.text();
console.log('Raw response text from backend:', rawText);

const data = JSON.parse(rawText);
console.log('Parsed collections data:', data);

return NextResponse.json(data, { status: 200 });
} catch (error: any) {
console.error('Error fetching collections:', error.message);
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
99 changes: 99 additions & 0 deletions src/app/api/playground/ragchat/index-files/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// src/app/api/playground/ragchat/index-files/route.ts
'use server';

import { NextRequest, NextResponse } from 'next/server';
import fetch from 'node-fetch';

async function authenticate(USERNAME: string, API_KEY: string, DS_HOST: string, retries: number = 3): Promise<string> {
for (let attempt = 0; attempt < retries; attempt++) {
try {
console.log('Starting authentication...');
const authResponse = await fetch(`${DS_HOST}/api/cps/user/v1/user/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Basic ${Buffer.from(`${USERNAME}:${API_KEY}`).toString('base64')}`
},
body: JSON.stringify({})
});

const authText = await authResponse.text();
console.log('Auth response text:', authText);

if (!authResponse.ok) {
throw new Error(authText);
}

const authData = JSON.parse(authText);
console.log('Authentication successful. Token obtained.');
return authData.access_token;
} catch (error) {
console.error(`Authentication attempt ${attempt + 1} failed:`, error.message);
if (attempt < retries - 1) {
console.log('Retrying in 3 seconds...');
await new Promise((resolve) => setTimeout(resolve, 3000));
} else {
throw new Error('Failed to authenticate after multiple attempts');
}
}
}
}

async function fetchDocuments(DS_HOST: string, PROJ_KEY: string, dsIndexKey: string, token: string, retries: number = 3) {
for (let attempt = 0; attempt < retries; attempt++) {
try {
console.log('Fetching documents...');
const response = await fetch(`${DS_HOST}/api/cps/public/v2/project/${PROJ_KEY}/data_indices/${dsIndexKey}/documents/`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`
}
});

console.log('API response status:', response.status);

if (!response.ok) {
const errorText = await response.text();
throw new Error(errorText);
}

const data = await response.json();
console.log('Fetched documents:', data.documents);
return data.documents.filter((doc: any) => doc.status === 'SUCCESS');
} catch (error) {
console.error(`Fetch attempt ${attempt + 1} failed:`, error.message);
if (attempt < retries - 1) {
console.log('Retrying in 3 seconds...');
await new Promise((resolve) => setTimeout(resolve, 3000));
} else {
throw new Error('Failed to fetch documents after multiple attempts');
}
}
}
}

export async function GET(req: NextRequest) {
const { searchParams } = new URL(req.url);
const dsIndexKey = searchParams.get('indexKey');
const USERNAME = process.env.DS_USERNAME;
const API_KEY = process.env.DS_API_KEY;
const DS_HOST = process.env.DS_HOST;
const PROJ_KEY = process.env.DS_PROJ_KEY;

console.log('Received request for data index:', dsIndexKey);

if (!dsIndexKey || !USERNAME || !API_KEY || !DS_HOST || !PROJ_KEY) {
console.error('Missing required parameters or environment variables', { dsIndexKey, USERNAME, API_KEY, DS_HOST, PROJ_KEY });
return NextResponse.json({ error: 'Missing required parameters or environment variables' }, { status: 400 });
}

try {
const token = await authenticate(USERNAME, API_KEY, DS_HOST);
const documents = await fetchDocuments(DS_HOST, PROJ_KEY, dsIndexKey, token);
return NextResponse.json({ documents }, { status: 200 });
} catch (error) {
console.error('Server error:', error.message);
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
107 changes: 107 additions & 0 deletions src/app/api/playground/ragchat/query/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// src/app/api/playground/ragchat/query/route.ts
'use server';

import { NextRequest, NextResponse } from 'next/server';
import fetch from 'node-fetch';
import { dsauthenticate } from '../../../../../utils/dsauthenticate';

async function queryRAG(
DS_HOST: string,
DS_TOKEN: string,
DS_PROJ_KEY: string,
indexKey: string,
question: string,
model_id: string,
doc_hash: string | null
) {
const queryUrl = `${DS_HOST}/api/orchestrator/api/v1/query/run`;
console.log('Querying RAG backend:', queryUrl);

const payload = {
query: {
variables: {},
template: {
version: '1',
tasks: [
{
id: 'QA',
kind: 'SemanticRag',
inputs: {},
parameters: {
question,
model_id,
retr_k: 10,
use_reranker: false,
hybrid_search_text_weight: 0.1,
gen_timeout: 25,
return_prompt: true,
...(doc_hash ? { doc_id: doc_hash } : {}) // doc_hash is added only if the user selects a specific doc to query
},
'@resource': {
type: 'semantic_backend_genai_runner',
proj_key: DS_PROJ_KEY,
index_key: indexKey
}
}
],
outputs: {
answers: {
task_id: 'QA',
output_id: 'answers'
},
retrieval: {
task_id: 'QA',
output_id: 'retrieval'
}
}
}
}
};

try {
const response = await fetch(queryUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Authorization': `Bearer ${DS_TOKEN}`
},
body: JSON.stringify(payload)
});

if (!response.ok) {
const errorText = await response.text();
throw new Error(errorText);
}

const data = await response.json();
console.log('RAG backend response:', data);
return data.result.outputs.answers[0].prompt;
} catch (error) {
console.error('Error querying RAG backend:', error.message);
throw error;
}
}

export async function POST(req: NextRequest) {
const { question, dataIndex, docHash } = await req.json();
const USERNAME = process.env.DS_USERNAME;
const API_KEY = process.env.DS_API_KEY;
const DS_HOST = process.env.DS_HOST;
const DS_PROJ_KEY = process.env.DS_PROJ_KEY;
const DS_MODEL_ID = process.env.DS_MODEL_ID;

if (!USERNAME || !API_KEY || !DS_HOST || !DS_PROJ_KEY || !DS_MODEL_ID) {
console.error('Missing required parameters or environment variables', { USERNAME, API_KEY, DS_HOST, DS_PROJ_KEY, DS_MODEL_ID });
return NextResponse.json({ error: 'Missing required parameters or environment variables' }, { status: 400 });
}

try {
const token = await dsauthenticate(USERNAME, API_KEY, DS_HOST);
const prompt = await queryRAG(DS_HOST, token, DS_PROJ_KEY, dataIndex, question, DS_MODEL_ID, docHash);
console.log('Prompt received:', prompt);
return NextResponse.json({ prompt }, { status: 200 });
} catch (error) {
console.error('Server error:', error.message);
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
Loading

0 comments on commit 7937b32

Please sign in to comment.