Skip to content

Commit 3c27cce

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

File tree

2 files changed

+166
-57
lines changed

2 files changed

+166
-57
lines changed

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

Lines changed: 54 additions & 0 deletions
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

Lines changed: 112 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,9 @@ export const KnowledgeForm: React.FunctionComponent<KnowledgeFormProps> = ({ kno
106106

107107
const [knowledgeDocumentRepositoryUrl, setKnowledgeDocumentRepositoryUrl] = useState<string>('');
108108
const [knowledgeDocumentCommit, setKnowledgeDocumentCommit] = useState<string>('');
109-
// This used to be 'patterns' but I am not totally sure what this variable actually is...
110109
const [documentName, setDocumentName] = useState<string>('');
111110

112111
// Attribution Information
113-
// State
114112
const [titleWork, setTitleWork] = useState<string>('');
115113
const [linkWork, setLinkWork] = useState<string>('');
116114
const [revision, setRevision] = useState<string>('');
@@ -230,9 +228,9 @@ export const KnowledgeForm: React.FunctionComponent<KnowledgeFormProps> = ({ kno
230228
seedExamples.map((seedExample: SeedExample, index: number) =>
231229
index === seedExampleIndex
232230
? {
233-
...seedExample,
234-
context: contextValue
235-
}
231+
...seedExample,
232+
context: contextValue
233+
}
236234
: seedExample
237235
)
238236
);
@@ -243,9 +241,9 @@ export const KnowledgeForm: React.FunctionComponent<KnowledgeFormProps> = ({ kno
243241
seedExamples.map((seedExample: SeedExample, index: number) =>
244242
index === seedExampleIndex
245243
? {
246-
...seedExample,
247-
isContextValid: validateContext(seedExample.context)
248-
}
244+
...seedExample,
245+
isContextValid: validateContext(seedExample.context)
246+
}
249247
: seedExample
250248
)
251249
);
@@ -256,16 +254,16 @@ export const KnowledgeForm: React.FunctionComponent<KnowledgeFormProps> = ({ kno
256254
seedExamples.map((seedExample: SeedExample, index: number) =>
257255
index === seedExampleIndex
258256
? {
259-
...seedExample,
260-
questionAndAnswers: seedExample.questionAndAnswers.map((questionAndAnswerPair: QuestionAndAnswerPair, index: number) =>
261-
index === questionAndAnswerIndex
262-
? {
263-
...questionAndAnswerPair,
264-
question: questionValue
265-
}
266-
: questionAndAnswerPair
267-
)
268-
}
257+
...seedExample,
258+
questionAndAnswers: seedExample.questionAndAnswers.map((questionAndAnswerPair: QuestionAndAnswerPair, index: number) =>
259+
index === questionAndAnswerIndex
260+
? {
261+
...questionAndAnswerPair,
262+
question: questionValue
263+
}
264+
: questionAndAnswerPair
265+
)
266+
}
269267
: seedExample
270268
)
271269
);
@@ -276,16 +274,16 @@ export const KnowledgeForm: React.FunctionComponent<KnowledgeFormProps> = ({ kno
276274
seedExamples.map((seedExample: SeedExample, index: number) =>
277275
index === seedExampleIndex
278276
? {
279-
...seedExample,
280-
questionAndAnswers: seedExample.questionAndAnswers.map((questionAndAnswerPair: QuestionAndAnswerPair, index: number) =>
281-
index === questionAndAnswerIndex
282-
? {
283-
...questionAndAnswerPair,
284-
isQuestionValid: validateQuestion(questionAndAnswerPair.question)
285-
}
286-
: questionAndAnswerPair
287-
)
288-
}
277+
...seedExample,
278+
questionAndAnswers: seedExample.questionAndAnswers.map((questionAndAnswerPair: QuestionAndAnswerPair, index: number) =>
279+
index === questionAndAnswerIndex
280+
? {
281+
...questionAndAnswerPair,
282+
isQuestionValid: validateQuestion(questionAndAnswerPair.question)
283+
}
284+
: questionAndAnswerPair
285+
)
286+
}
289287
: seedExample
290288
)
291289
);
@@ -296,16 +294,16 @@ export const KnowledgeForm: React.FunctionComponent<KnowledgeFormProps> = ({ kno
296294
seedExamples.map((seedExample: SeedExample, index: number) =>
297295
index === seedExampleIndex
298296
? {
299-
...seedExample,
300-
questionAndAnswers: seedExample.questionAndAnswers.map((questionAndAnswerPair: QuestionAndAnswerPair, index: number) =>
301-
index === questionAndAnswerIndex
302-
? {
303-
...questionAndAnswerPair,
304-
answer: answerValue
305-
}
306-
: questionAndAnswerPair
307-
)
308-
}
297+
...seedExample,
298+
questionAndAnswers: seedExample.questionAndAnswers.map((questionAndAnswerPair: QuestionAndAnswerPair, index: number) =>
299+
index === questionAndAnswerIndex
300+
? {
301+
...questionAndAnswerPair,
302+
answer: answerValue
303+
}
304+
: questionAndAnswerPair
305+
)
306+
}
309307
: seedExample
310308
)
311309
);
@@ -316,21 +314,68 @@ export const KnowledgeForm: React.FunctionComponent<KnowledgeFormProps> = ({ kno
316314
seedExamples.map((seedExample: SeedExample, index: number) =>
317315
index === seedExampleIndex
318316
? {
319-
...seedExample,
320-
questionAndAnswers: seedExample.questionAndAnswers.map((questionAndAnswerPair: QuestionAndAnswerPair, index: number) =>
321-
index === questionAndAnswerIndex
322-
? {
323-
...questionAndAnswerPair,
324-
isAnswerValid: validateAnswer(questionAndAnswerPair.answer)
325-
}
326-
: questionAndAnswerPair
327-
)
328-
}
317+
...seedExample,
318+
questionAndAnswers: seedExample.questionAndAnswers.map((questionAndAnswerPair: QuestionAndAnswerPair, index: number) =>
319+
index === questionAndAnswerIndex
320+
? {
321+
...questionAndAnswerPair,
322+
isAnswerValid: validateAnswer(questionAndAnswerPair.answer)
323+
}
324+
: questionAndAnswerPair
325+
)
326+
}
329327
: seedExample
330328
)
331329
);
332330
};
333331

332+
// New function to handle the button click and generate Q&A pairs
333+
const handleGenerateQA = async (seedExampleIndex: number) => {
334+
try {
335+
// Ensure seedExampleIndex is valid
336+
if (seedExampleIndex < 0 || seedExampleIndex >= seedExamples.length) {
337+
throw new Error('Invalid seed example index');
338+
}
339+
340+
const context = seedExamples[seedExampleIndex].context;
341+
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}`;
342+
343+
// Make a request to the server-side route
344+
const response = await fetch('/api/pr/qnaGen', {
345+
method: 'POST',
346+
headers: {
347+
'Content-Type': 'application/json',
348+
},
349+
body: JSON.stringify({ question: prompt, systemRole: 'user' }),
350+
});
351+
352+
if (!response.ok) {
353+
throw new Error('Failed to generate Q&A pairs');
354+
}
355+
356+
const data = await response.json();
357+
358+
// Parse the response to extract Q&A pairs
359+
const updatedQAPairs = seedExamples[seedExampleIndex].questionAndAnswers.map((qaPair, i) => {
360+
const questionMatch = data.match(new RegExp(`Question ${i + 1}: (.*?)(?:Answer|$)`));
361+
const answerMatch = data.match(new RegExp(`Answer ${i + 1}: (.*?)(?:Question|$)`));
362+
363+
return {
364+
...qaPair,
365+
question: questionMatch ? questionMatch[1].trim() : qaPair.question,
366+
answer: answerMatch ? answerMatch[1].trim() : qaPair.answer,
367+
};
368+
});
369+
370+
// Update state with new Q&A pairs
371+
setSeedExamples(seedExamples.map((example, i) =>
372+
i === seedExampleIndex ? { ...example, questionAndAnswers: updatedQAPairs } : example
373+
));
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)