Skip to content

Commit

Permalink
WIP: QnA Knowledge Generation PoC
Browse files Browse the repository at this point in the history
Signed-off-by: Brent Salisbury <[email protected]>
  • Loading branch information
nerdalert committed Sep 7, 2024
1 parent 9a367e9 commit 3c27cce
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 57 deletions.
54 changes: 54 additions & 0 deletions src/app/api/pr/qnaGen/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// src/app/api/playground/chat/route.ts
'use server';
import { NextRequest, NextResponse } from 'next/server';
import fetch from 'node-fetch';
import https from 'https';

export async function POST(req: NextRequest) {
try {
const { question, systemRole } = await req.json();

const apiURL = 'https://granite-7b-lab-vllm-openai.apps.fmaas-backend.fmaas.res.ibm.com';
const modelName = 'instructlab/granite-7b-lab';

const messages = [
{ role: 'system', content: systemRole },
{ role: 'user', content: question }
];

const requestData = {
model: modelName,
messages,
stream: false // Disable streaming
};

const agent = new https.Agent({
rejectUnauthorized: false
});

const chatResponse = await fetch(`${apiURL}/v1/chat/completions`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
accept: 'application/json'
},
body: JSON.stringify(requestData),
agent: apiURL.startsWith('https') ? agent : undefined
});

if (!chatResponse.ok) {
return new NextResponse('Failed to fetch chat response', { status: chatResponse.status });
}

const result = await chatResponse.json(); // Wait for the complete response

return new NextResponse(JSON.stringify(result), {
headers: {
'Content-Type': 'application/json'
}
});
} catch (error) {
console.error('Error processing request:', error);
return new NextResponse('Error processing request', { status: 500 });
}
}
169 changes: 112 additions & 57 deletions src/components/Contribute/Knowledge/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,9 @@ export const KnowledgeForm: React.FunctionComponent<KnowledgeFormProps> = ({ kno

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

// Attribution Information
// State
const [titleWork, setTitleWork] = useState<string>('');
const [linkWork, setLinkWork] = useState<string>('');
const [revision, setRevision] = useState<string>('');
Expand Down Expand Up @@ -230,9 +228,9 @@ export const KnowledgeForm: React.FunctionComponent<KnowledgeFormProps> = ({ kno
seedExamples.map((seedExample: SeedExample, index: number) =>
index === seedExampleIndex
? {
...seedExample,
context: contextValue
}
...seedExample,
context: contextValue
}
: seedExample
)
);
Expand All @@ -243,9 +241,9 @@ export const KnowledgeForm: React.FunctionComponent<KnowledgeFormProps> = ({ kno
seedExamples.map((seedExample: SeedExample, index: number) =>
index === seedExampleIndex
? {
...seedExample,
isContextValid: validateContext(seedExample.context)
}
...seedExample,
isContextValid: validateContext(seedExample.context)
}
: seedExample
)
);
Expand All @@ -256,16 +254,16 @@ export const KnowledgeForm: React.FunctionComponent<KnowledgeFormProps> = ({ kno
seedExamples.map((seedExample: SeedExample, index: number) =>
index === seedExampleIndex
? {
...seedExample,
questionAndAnswers: seedExample.questionAndAnswers.map((questionAndAnswerPair: QuestionAndAnswerPair, index: number) =>
index === questionAndAnswerIndex
? {
...questionAndAnswerPair,
question: questionValue
}
: questionAndAnswerPair
)
}
...seedExample,
questionAndAnswers: seedExample.questionAndAnswers.map((questionAndAnswerPair: QuestionAndAnswerPair, index: number) =>
index === questionAndAnswerIndex
? {
...questionAndAnswerPair,
question: questionValue
}
: questionAndAnswerPair
)
}
: seedExample
)
);
Expand All @@ -276,16 +274,16 @@ export const KnowledgeForm: React.FunctionComponent<KnowledgeFormProps> = ({ kno
seedExamples.map((seedExample: SeedExample, index: number) =>
index === seedExampleIndex
? {
...seedExample,
questionAndAnswers: seedExample.questionAndAnswers.map((questionAndAnswerPair: QuestionAndAnswerPair, index: number) =>
index === questionAndAnswerIndex
? {
...questionAndAnswerPair,
isQuestionValid: validateQuestion(questionAndAnswerPair.question)
}
: questionAndAnswerPair
)
}
...seedExample,
questionAndAnswers: seedExample.questionAndAnswers.map((questionAndAnswerPair: QuestionAndAnswerPair, index: number) =>
index === questionAndAnswerIndex
? {
...questionAndAnswerPair,
isQuestionValid: validateQuestion(questionAndAnswerPair.question)
}
: questionAndAnswerPair
)
}
: seedExample
)
);
Expand All @@ -296,16 +294,16 @@ export const KnowledgeForm: React.FunctionComponent<KnowledgeFormProps> = ({ kno
seedExamples.map((seedExample: SeedExample, index: number) =>
index === seedExampleIndex
? {
...seedExample,
questionAndAnswers: seedExample.questionAndAnswers.map((questionAndAnswerPair: QuestionAndAnswerPair, index: number) =>
index === questionAndAnswerIndex
? {
...questionAndAnswerPair,
answer: answerValue
}
: questionAndAnswerPair
)
}
...seedExample,
questionAndAnswers: seedExample.questionAndAnswers.map((questionAndAnswerPair: QuestionAndAnswerPair, index: number) =>
index === questionAndAnswerIndex
? {
...questionAndAnswerPair,
answer: answerValue
}
: questionAndAnswerPair
)
}
: seedExample
)
);
Expand All @@ -316,21 +314,68 @@ export const KnowledgeForm: React.FunctionComponent<KnowledgeFormProps> = ({ kno
seedExamples.map((seedExample: SeedExample, index: number) =>
index === seedExampleIndex
? {
...seedExample,
questionAndAnswers: seedExample.questionAndAnswers.map((questionAndAnswerPair: QuestionAndAnswerPair, index: number) =>
index === questionAndAnswerIndex
? {
...questionAndAnswerPair,
isAnswerValid: validateAnswer(questionAndAnswerPair.answer)
}
: questionAndAnswerPair
)
}
...seedExample,
questionAndAnswers: seedExample.questionAndAnswers.map((questionAndAnswerPair: QuestionAndAnswerPair, index: number) =>
index === questionAndAnswerIndex
? {
...questionAndAnswerPair,
isAnswerValid: validateAnswer(questionAndAnswerPair.answer)
}
: questionAndAnswerPair
)
}
: seedExample
)
);
};

// New function to handle the button click and generate Q&A pairs
const handleGenerateQA = async (seedExampleIndex: number) => {
try {
// Ensure seedExampleIndex is valid
if (seedExampleIndex < 0 || seedExampleIndex >= seedExamples.length) {
throw new Error('Invalid seed example index');
}

const context = seedExamples[seedExampleIndex].context;
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}`;

// Make a request to the server-side route
const response = await fetch('/api/pr/qnaGen', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ question: prompt, systemRole: 'user' }),
});

if (!response.ok) {
throw new Error('Failed to generate Q&A pairs');
}

const data = await response.json();

// Parse the response to extract Q&A pairs
const updatedQAPairs = seedExamples[seedExampleIndex].questionAndAnswers.map((qaPair, i) => {
const questionMatch = data.match(new RegExp(`Question ${i + 1}: (.*?)(?:Answer|$)`));
const answerMatch = data.match(new RegExp(`Answer ${i + 1}: (.*?)(?:Question|$)`));

return {
...qaPair,
question: questionMatch ? questionMatch[1].trim() : qaPair.question,
answer: answerMatch ? answerMatch[1].trim() : qaPair.answer,
};
});

// Update state with new Q&A pairs
setSeedExamples(seedExamples.map((example, i) =>
i === seedExampleIndex ? { ...example, questionAndAnswers: updatedQAPairs } : example
));
} catch (error) {
console.error('Error generating Q&A pairs:', error);
}
};

const onCloseActionGroupAlert = () => {
setActionGroupAlertContent(undefined);
};
Expand Down Expand Up @@ -429,15 +474,25 @@ export const KnowledgeForm: React.FunctionComponent<KnowledgeFormProps> = ({ kno
setFilePath={setFilePath}
/>

<KnowledgeSeedExample
seedExamples={seedExamples}
handleContextInputChange={handleContextInputChange}
handleContextBlur={handleContextBlur}
handleQuestionInputChange={handleQuestionInputChange}
handleQuestionBlur={handleQuestionBlur}
handleAnswerInputChange={handleAnswerInputChange}
handleAnswerBlur={handleAnswerBlur}
/>
{/* Iterate over each seed example and display it */}
{seedExamples.map((seedExample, index) => (
<div key={index}>
<KnowledgeSeedExample
seedExamples={[seedExample]} // Pass each individual seed example
handleContextInputChange={(contextValue) => handleContextInputChange(index, contextValue)}
handleContextBlur={() => handleContextBlur(index)}
handleQuestionInputChange={(qaIndex, questionValue) => handleQuestionInputChange(index, qaIndex, questionValue)}
handleQuestionBlur={(qaIndex) => handleQuestionBlur(index, qaIndex)}
handleAnswerInputChange={(qaIndex, answerValue) => handleAnswerInputChange(index, qaIndex, answerValue)}
handleAnswerBlur={(qaIndex) => handleAnswerBlur(index, qaIndex)}
/>

{/* New Button to Generate Q&A Pairs for each seed example */}
<Button variant="primary" onClick={() => handleGenerateQA(index)}>
Generate Q&A Pairs
</Button>
</div>
))}

<DocumentInformation
reset={reset}
Expand Down

0 comments on commit 3c27cce

Please sign in to comment.