Skip to content

Commit 04c6e20

Browse files
committed
WIP: QnA Knowledge Generation PoC
Signed-off-by: Brent Salisbury <[email protected]>
1 parent 9a367e9 commit 04c6e20

File tree

2 files changed

+118
-9
lines changed

2 files changed

+118
-9
lines changed

src/app/api/pr/qnaGen/route.ts

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// src/app/api/playground/chat/route.ts
2+
'use server';
3+
import { NextRequest, NextResponse } from 'next/server';
4+
import fetch from 'node-fetch';
5+
import https from 'https';
6+
7+
export async function POST(req: NextRequest) {
8+
try {
9+
const { question, systemRole } = await req.json();
10+
11+
const apiURL = 'https://granite-7b-lab-vllm-openai.apps.fmaas-backend.fmaas.res.ibm.com';
12+
const modelName = 'instructlab/granite-7b-lab';
13+
14+
const messages = [
15+
{ role: 'system', content: systemRole },
16+
{ role: 'user', content: question }
17+
];
18+
19+
const requestData = {
20+
model: modelName,
21+
messages,
22+
stream: false // Disable streaming
23+
};
24+
25+
const agent = new https.Agent({
26+
rejectUnauthorized: false
27+
});
28+
29+
const chatResponse = await fetch(`${apiURL}/v1/chat/completions`, {
30+
method: 'POST',
31+
headers: {
32+
'Content-Type': 'application/json',
33+
accept: 'application/json'
34+
},
35+
body: JSON.stringify(requestData),
36+
agent: apiURL.startsWith('https') ? agent : undefined
37+
});
38+
39+
if (!chatResponse.ok) {
40+
return new NextResponse('Failed to fetch chat response', { status: chatResponse.status });
41+
}
42+
43+
const result = await chatResponse.json(); // Wait for the complete response
44+
45+
return new NextResponse(JSON.stringify(result), {
46+
headers: {
47+
'Content-Type': 'application/json'
48+
}
49+
});
50+
} catch (error) {
51+
console.error('Error processing request:', error);
52+
return new NextResponse('Error processing request', { status: 500 });
53+
}
54+
}

src/components/Contribute/Knowledge/index.tsx

+64-9
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,51 @@ export const KnowledgeForm: React.FunctionComponent<KnowledgeFormProps> = ({ kno
331331
);
332332
};
333333

334+
// New function to handle the button click and generate Q&A pairs
335+
const handleGenerateQA = async (seedExampleIndex: number) => {
336+
try {
337+
// Ensure seedExampleIndex is valid
338+
if (seedExampleIndex < 0 || seedExampleIndex >= seedExamples.length) {
339+
throw new Error('Invalid seed example index');
340+
}
341+
342+
const context = seedExamples[seedExampleIndex].context;
343+
const prompt = `Generate 3 question and answer pairs from the provided context. The output should be in the form of "Question 1" and "Answer 1" and next "Question 2" and "Answer 2" and so on. Here is the context:\n${context}`;
344+
345+
// Make a request to the server-side route
346+
const response = await fetch('/api/pr/qnaGen', {
347+
method: 'POST',
348+
headers: {
349+
'Content-Type': 'application/json'
350+
},
351+
body: JSON.stringify({ question: prompt, systemRole: 'user' })
352+
});
353+
354+
if (!response.ok) {
355+
throw new Error('Failed to generate Q&A pairs');
356+
}
357+
358+
const data = await response.json();
359+
360+
// Parse the response to extract Q&A pairs
361+
const updatedQAPairs = seedExamples[seedExampleIndex].questionAndAnswers.map((qaPair, i) => {
362+
const questionMatch = data.match(new RegExp(`Question ${i + 1}: (.*?)(?:Answer|$)`));
363+
const answerMatch = data.match(new RegExp(`Answer ${i + 1}: (.*?)(?:Question|$)`));
364+
365+
return {
366+
...qaPair,
367+
question: questionMatch ? questionMatch[1].trim() : qaPair.question,
368+
answer: answerMatch ? answerMatch[1].trim() : qaPair.answer
369+
};
370+
});
371+
372+
// Update state with new Q&A pairs
373+
setSeedExamples(seedExamples.map((example, i) => (i === seedExampleIndex ? { ...example, questionAndAnswers: updatedQAPairs } : example)));
374+
} catch (error) {
375+
console.error('Error generating Q&A pairs:', error);
376+
}
377+
};
378+
334379
const onCloseActionGroupAlert = () => {
335380
setActionGroupAlertContent(undefined);
336381
};
@@ -429,15 +474,25 @@ export const KnowledgeForm: React.FunctionComponent<KnowledgeFormProps> = ({ kno
429474
setFilePath={setFilePath}
430475
/>
431476

432-
<KnowledgeSeedExample
433-
seedExamples={seedExamples}
434-
handleContextInputChange={handleContextInputChange}
435-
handleContextBlur={handleContextBlur}
436-
handleQuestionInputChange={handleQuestionInputChange}
437-
handleQuestionBlur={handleQuestionBlur}
438-
handleAnswerInputChange={handleAnswerInputChange}
439-
handleAnswerBlur={handleAnswerBlur}
440-
/>
477+
{/* Iterate over each seed example and display it */}
478+
{seedExamples.map((seedExample, index) => (
479+
<div key={index}>
480+
<KnowledgeSeedExample
481+
seedExamples={[seedExample]} // Pass each individual seed example
482+
handleContextInputChange={(contextValue) => handleContextInputChange(index, contextValue)}
483+
handleContextBlur={() => handleContextBlur(index)}
484+
handleQuestionInputChange={(qaIndex, questionValue) => handleQuestionInputChange(index, qaIndex, questionValue)}
485+
handleQuestionBlur={(qaIndex) => handleQuestionBlur(index, qaIndex)}
486+
handleAnswerInputChange={(qaIndex, answerValue) => handleAnswerInputChange(index, qaIndex, answerValue)}
487+
handleAnswerBlur={(qaIndex) => handleAnswerBlur(index, qaIndex)}
488+
/>
489+
490+
{/* New Button to Generate Q&A Pairs for each seed example */}
491+
<Button variant="primary" onClick={() => handleGenerateQA(index)}>
492+
Generate Q&A Pairs
493+
</Button>
494+
</div>
495+
))}
441496

442497
<DocumentInformation
443498
reset={reset}

0 commit comments

Comments
 (0)