Skip to content

Commit 7937b32

Browse files
committed
Demo: RAG/Docling/llama-index
Signed-off-by: Brent Salisbury <bsalisbu@redhat.com>
1 parent 67eefbb commit 7937b32

File tree

11 files changed

+1420
-1
lines changed

11 files changed

+1420
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
'use server';
2+
3+
import { NextRequest, NextResponse } from 'next/server';
4+
import fetch from 'node-fetch';
5+
6+
export async function DELETE(req: NextRequest, { params }: { params: { collectionName: string } }) {
7+
const { collectionName } = params;
8+
9+
try {
10+
console.log(`Deleting collection: ${collectionName}`);
11+
12+
// Make the API request to the backend to delete the collection
13+
const response = await fetch(`http://127.0.0.1:8000/collections/${encodeURIComponent(collectionName)}`, {
14+
method: 'DELETE'
15+
});
16+
17+
// Check if the response was successful
18+
if (!response.ok) {
19+
const errorText = await response.text();
20+
console.error(`Failed to delete collection: ${errorText}`);
21+
throw new Error(`Failed to delete collection: ${errorText}`);
22+
}
23+
24+
// Return a success response to the client
25+
console.log(`Collection ${collectionName} deleted successfully.`);
26+
return NextResponse.json({ message: `Collection ${collectionName} deleted successfully.` }, { status: 200 });
27+
} catch (error: any) {
28+
console.error('Error deleting collection:', error.message);
29+
return NextResponse.json({ error: error.message }, { status: 500 });
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// src/app/api/playground/ragchat/collections/[collectionName]/documents/file/route.ts
2+
'use server';
3+
4+
import { NextRequest, NextResponse } from 'next/server';
5+
import fetch from 'node-fetch';
6+
import FormData from 'form-data';
7+
8+
export async function POST(req: NextRequest, { params }: { params: { collectionName: string } }) {
9+
const { collectionName } = params;
10+
11+
try {
12+
// Parse the form data from the incoming request
13+
const formData = await req.formData();
14+
const file = formData.get('files') as File | null;
15+
16+
if (!file) {
17+
throw new Error('File is required for upload');
18+
}
19+
20+
// Create FormData for the backend request
21+
const backendFormData = new FormData();
22+
23+
// Convert the file to a Buffer for the Node.js environment
24+
const buffer = Buffer.from(await file.arrayBuffer());
25+
26+
// Append the file buffer to FormData
27+
backendFormData.append('file', buffer, file.name);
28+
29+
// Send the file to the backend service
30+
const backendResponse = await fetch(`http://127.0.0.1:8000/collections/${encodeURIComponent(collectionName)}/documents/file`, {
31+
method: 'POST',
32+
body: backendFormData,
33+
headers: backendFormData.getHeaders()
34+
});
35+
36+
const backendResponseText = await backendResponse.text();
37+
38+
if (!backendResponse.ok) {
39+
throw new Error(`Failed to upload file to backend: ${backendResponseText}`);
40+
}
41+
42+
return NextResponse.json({ message: 'File uploaded successfully', data: backendResponseText }, { status: 200 });
43+
} catch (error: any) {
44+
console.error('Error during file upload:', error.message);
45+
return NextResponse.json({ error: error.message }, { status: 500 });
46+
}
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// src/app/api/playground/ragchat/collections/[collectionName]/documents/url/route.ts
2+
`use server`;
3+
4+
import { NextRequest, NextResponse } from 'next/server';
5+
6+
export async function POST(req: NextRequest, { params }: { params: { collectionName: string } }) {
7+
const { collectionName } = params;
8+
9+
try {
10+
const { http_source } = await req.json();
11+
12+
const response = await fetch(`http://localhost:8000/collections/${encodeURIComponent(collectionName)}/documents/url`, {
13+
method: 'POST',
14+
headers: {
15+
'Content-Type': 'application/json'
16+
},
17+
body: JSON.stringify({ http_source })
18+
});
19+
20+
const responseText = await response.text();
21+
22+
if (!response.ok) {
23+
throw new Error(`Failed to upload URL: ${responseText}`);
24+
}
25+
26+
return NextResponse.json({ message: 'URL uploaded successfully', data: responseText }, { status: 200 });
27+
} catch (error: any) {
28+
console.error('Error uploading URL:', error.message);
29+
return NextResponse.json({ error: error.message }, { status: 500 });
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// src/app/api/playground/ragchat/collections/[collectionName]/query/route.ts
2+
'use server';
3+
4+
import { NextRequest, NextResponse } from 'next/server';
5+
import fetch from 'node-fetch';
6+
7+
export async function POST(req: NextRequest, { params }: { params: { collectionName: string } }) {
8+
const { collectionName } = params;
9+
10+
try {
11+
const { question } = await req.json();
12+
13+
console.log(`Received question: ${question} for collection: ${collectionName}`);
14+
15+
// Make the API request to the backend using node-fetch
16+
const response = await fetch(`http://127.0.0.1:8000/collections/${encodeURIComponent(collectionName)}/query`, {
17+
method: 'POST',
18+
headers: {
19+
'Content-Type': 'application/json'
20+
},
21+
body: JSON.stringify({ question })
22+
});
23+
24+
// Check if the response was successful
25+
if (!response.ok) {
26+
const errorText = await response.text();
27+
console.error(`Failed to query collection: ${errorText}`);
28+
throw new Error(`Failed to query collection: ${errorText}`);
29+
}
30+
31+
// Parse the backend response
32+
const responseData = await response.json();
33+
console.log('Backend response data:', responseData);
34+
35+
// Extract the 'answer' and 'sources' fields
36+
const { answer, sources } = responseData;
37+
38+
// Return the answer and sources to the client
39+
return NextResponse.json({ answer, sources }, { status: 200 });
40+
} catch (error: any) {
41+
console.error('Error querying collection:', error.message);
42+
return NextResponse.json({ error: error.message }, { status: 500 });
43+
}
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// src/app/api/playground/ragchat/collections/route.ts
2+
'use server';
3+
4+
import { NextRequest, NextResponse } from 'next/server';
5+
import fetch from 'node-fetch';
6+
7+
export async function GET(req: NextRequest) {
8+
console.log('Received request to fetch collections');
9+
10+
try {
11+
console.log('Making fetch call to backend service...');
12+
13+
const response = await fetch('http://127.0.0.1:8000/collections', {
14+
method: 'GET',
15+
headers: {
16+
Accept: 'application/json' // Ensure Accept header is set properly
17+
}
18+
});
19+
20+
const rawText = await response.text();
21+
console.log('Raw response text from backend:', rawText);
22+
23+
const data = JSON.parse(rawText);
24+
console.log('Parsed collections data:', data);
25+
26+
return NextResponse.json(data, { status: 200 });
27+
} catch (error: any) {
28+
console.error('Error fetching collections:', error.message);
29+
return NextResponse.json({ error: error.message }, { status: 500 });
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// src/app/api/playground/ragchat/index-files/route.ts
2+
'use server';
3+
4+
import { NextRequest, NextResponse } from 'next/server';
5+
import fetch from 'node-fetch';
6+
7+
async function authenticate(USERNAME: string, API_KEY: string, DS_HOST: string, retries: number = 3): Promise<string> {
8+
for (let attempt = 0; attempt < retries; attempt++) {
9+
try {
10+
console.log('Starting authentication...');
11+
const authResponse = await fetch(`${DS_HOST}/api/cps/user/v1/user/token`, {
12+
method: 'POST',
13+
headers: {
14+
'Content-Type': 'application/json',
15+
Authorization: `Basic ${Buffer.from(`${USERNAME}:${API_KEY}`).toString('base64')}`
16+
},
17+
body: JSON.stringify({})
18+
});
19+
20+
const authText = await authResponse.text();
21+
console.log('Auth response text:', authText);
22+
23+
if (!authResponse.ok) {
24+
throw new Error(authText);
25+
}
26+
27+
const authData = JSON.parse(authText);
28+
console.log('Authentication successful. Token obtained.');
29+
return authData.access_token;
30+
} catch (error) {
31+
console.error(`Authentication attempt ${attempt + 1} failed:`, error.message);
32+
if (attempt < retries - 1) {
33+
console.log('Retrying in 3 seconds...');
34+
await new Promise((resolve) => setTimeout(resolve, 3000));
35+
} else {
36+
throw new Error('Failed to authenticate after multiple attempts');
37+
}
38+
}
39+
}
40+
}
41+
42+
async function fetchDocuments(DS_HOST: string, PROJ_KEY: string, dsIndexKey: string, token: string, retries: number = 3) {
43+
for (let attempt = 0; attempt < retries; attempt++) {
44+
try {
45+
console.log('Fetching documents...');
46+
const response = await fetch(`${DS_HOST}/api/cps/public/v2/project/${PROJ_KEY}/data_indices/${dsIndexKey}/documents/`, {
47+
method: 'GET',
48+
headers: {
49+
'Content-Type': 'application/json',
50+
Authorization: `Bearer ${token}`
51+
}
52+
});
53+
54+
console.log('API response status:', response.status);
55+
56+
if (!response.ok) {
57+
const errorText = await response.text();
58+
throw new Error(errorText);
59+
}
60+
61+
const data = await response.json();
62+
console.log('Fetched documents:', data.documents);
63+
return data.documents.filter((doc: any) => doc.status === 'SUCCESS');
64+
} catch (error) {
65+
console.error(`Fetch attempt ${attempt + 1} failed:`, error.message);
66+
if (attempt < retries - 1) {
67+
console.log('Retrying in 3 seconds...');
68+
await new Promise((resolve) => setTimeout(resolve, 3000));
69+
} else {
70+
throw new Error('Failed to fetch documents after multiple attempts');
71+
}
72+
}
73+
}
74+
}
75+
76+
export async function GET(req: NextRequest) {
77+
const { searchParams } = new URL(req.url);
78+
const dsIndexKey = searchParams.get('indexKey');
79+
const USERNAME = process.env.DS_USERNAME;
80+
const API_KEY = process.env.DS_API_KEY;
81+
const DS_HOST = process.env.DS_HOST;
82+
const PROJ_KEY = process.env.DS_PROJ_KEY;
83+
84+
console.log('Received request for data index:', dsIndexKey);
85+
86+
if (!dsIndexKey || !USERNAME || !API_KEY || !DS_HOST || !PROJ_KEY) {
87+
console.error('Missing required parameters or environment variables', { dsIndexKey, USERNAME, API_KEY, DS_HOST, PROJ_KEY });
88+
return NextResponse.json({ error: 'Missing required parameters or environment variables' }, { status: 400 });
89+
}
90+
91+
try {
92+
const token = await authenticate(USERNAME, API_KEY, DS_HOST);
93+
const documents = await fetchDocuments(DS_HOST, PROJ_KEY, dsIndexKey, token);
94+
return NextResponse.json({ documents }, { status: 200 });
95+
} catch (error) {
96+
console.error('Server error:', error.message);
97+
return NextResponse.json({ error: error.message }, { status: 500 });
98+
}
99+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// src/app/api/playground/ragchat/query/route.ts
2+
'use server';
3+
4+
import { NextRequest, NextResponse } from 'next/server';
5+
import fetch from 'node-fetch';
6+
import { dsauthenticate } from '../../../../../utils/dsauthenticate';
7+
8+
async function queryRAG(
9+
DS_HOST: string,
10+
DS_TOKEN: string,
11+
DS_PROJ_KEY: string,
12+
indexKey: string,
13+
question: string,
14+
model_id: string,
15+
doc_hash: string | null
16+
) {
17+
const queryUrl = `${DS_HOST}/api/orchestrator/api/v1/query/run`;
18+
console.log('Querying RAG backend:', queryUrl);
19+
20+
const payload = {
21+
query: {
22+
variables: {},
23+
template: {
24+
version: '1',
25+
tasks: [
26+
{
27+
id: 'QA',
28+
kind: 'SemanticRag',
29+
inputs: {},
30+
parameters: {
31+
question,
32+
model_id,
33+
retr_k: 10,
34+
use_reranker: false,
35+
hybrid_search_text_weight: 0.1,
36+
gen_timeout: 25,
37+
return_prompt: true,
38+
...(doc_hash ? { doc_id: doc_hash } : {}) // doc_hash is added only if the user selects a specific doc to query
39+
},
40+
'@resource': {
41+
type: 'semantic_backend_genai_runner',
42+
proj_key: DS_PROJ_KEY,
43+
index_key: indexKey
44+
}
45+
}
46+
],
47+
outputs: {
48+
answers: {
49+
task_id: 'QA',
50+
output_id: 'answers'
51+
},
52+
retrieval: {
53+
task_id: 'QA',
54+
output_id: 'retrieval'
55+
}
56+
}
57+
}
58+
}
59+
};
60+
61+
try {
62+
const response = await fetch(queryUrl, {
63+
method: 'POST',
64+
headers: {
65+
'Content-Type': 'application/json',
66+
'X-Authorization': `Bearer ${DS_TOKEN}`
67+
},
68+
body: JSON.stringify(payload)
69+
});
70+
71+
if (!response.ok) {
72+
const errorText = await response.text();
73+
throw new Error(errorText);
74+
}
75+
76+
const data = await response.json();
77+
console.log('RAG backend response:', data);
78+
return data.result.outputs.answers[0].prompt;
79+
} catch (error) {
80+
console.error('Error querying RAG backend:', error.message);
81+
throw error;
82+
}
83+
}
84+
85+
export async function POST(req: NextRequest) {
86+
const { question, dataIndex, docHash } = await req.json();
87+
const USERNAME = process.env.DS_USERNAME;
88+
const API_KEY = process.env.DS_API_KEY;
89+
const DS_HOST = process.env.DS_HOST;
90+
const DS_PROJ_KEY = process.env.DS_PROJ_KEY;
91+
const DS_MODEL_ID = process.env.DS_MODEL_ID;
92+
93+
if (!USERNAME || !API_KEY || !DS_HOST || !DS_PROJ_KEY || !DS_MODEL_ID) {
94+
console.error('Missing required parameters or environment variables', { USERNAME, API_KEY, DS_HOST, DS_PROJ_KEY, DS_MODEL_ID });
95+
return NextResponse.json({ error: 'Missing required parameters or environment variables' }, { status: 400 });
96+
}
97+
98+
try {
99+
const token = await dsauthenticate(USERNAME, API_KEY, DS_HOST);
100+
const prompt = await queryRAG(DS_HOST, token, DS_PROJ_KEY, dataIndex, question, DS_MODEL_ID, docHash);
101+
console.log('Prompt received:', prompt);
102+
return NextResponse.json({ prompt }, { status: 200 });
103+
} catch (error) {
104+
console.error('Server error:', error.message);
105+
return NextResponse.json({ error: error.message }, { status: 500 });
106+
}
107+
}

0 commit comments

Comments
 (0)