Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: QnA Knowledge Generation PoC #161

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions src/app/api/pr/qnaGen/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// 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 {
console.log('Received POST request');

const { question, systemRole } = await req.json();
console.log('Parsed request JSON:', { question, systemRole });

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
};

console.log('Request data prepared for API call:', requestData);

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
});

console.log('API call made to:', `${apiURL}/v1/chat/completions`);

if (!chatResponse.ok) {
console.error('Failed to fetch chat response. Status:', chatResponse.status);
const errorText = await chatResponse.text();
console.error('Response text:', errorText);
return new NextResponse('Failed to fetch chat response', { status: chatResponse.status });
}

const result = await chatResponse.json(); // Wait for the complete response
console.log('Received response from API:', result);

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 });
}
}
68 changes: 64 additions & 4 deletions src/components/Contribute/Knowledge/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// src/components/Contribute/Knowledge/index.tsx
'use client';
import React, { useEffect, useMemo, useState } from 'react';
import './knowledge.css';
import { Alert, AlertActionCloseButton } from '@patternfly/react-core/dist/dynamic/components/Alert';
import { Modal } from '@patternfly/react-core/dist/esm/components/Modal/Modal';
import { ActionGroup } from '@patternfly/react-core/dist/dynamic/components/Form';
import { Form } from '@patternfly/react-core/dist/dynamic/components/Form';
import { getGitHubUsername } from '../../../utils/github';
Expand Down Expand Up @@ -121,7 +121,8 @@

const [disableAction, setDisableAction] = useState<boolean>(true);
const [reset, setReset] = useState<boolean>(false);

const [modalOpen, setModalOpen] = useState(false);
const [modalContent, setModalContent] = useState('');
const router = useRouter();

const emptySeedExample: SeedExample = {
Expand Down Expand Up @@ -331,6 +332,53 @@
);
};

const handleGenerateQAPairs = async (seedExampleIndex: number) => {
const context = seedExamples[seedExampleIndex].context;
const userContent = `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 then "Question 3" and "Answer 3". Only reply with the question and answers, no other content or commentary. Here is the context: ${context}`;

try {
const response = await fetch('/api/pr/qnaGen', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
question: userContent,
systemRole: 'user'
})
});

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

const result = await response.json();
const generatedContent = result.choices[0].message.content;

// Parse the QNAs from the LLM response
const qaPairs = generatedContent.match(/(Question \d+:.*?Answer \d+:.*?)(?=Question \d+:|$)/gs);

if (qaPairs) {
// Format the QNA pairs
const formattedContent = qaPairs.map((pair, index) => (

Check failure on line 363 in src/components/Contribute/Knowledge/index.tsx

View workflow job for this annotation

GitHub Actions / npm-lint

Parameter 'pair' implicitly has an 'any' type.

Check failure on line 363 in src/components/Contribute/Knowledge/index.tsx

View workflow job for this annotation

GitHub Actions / npm-lint

Parameter 'index' implicitly has an 'any' type.
<div key={index} style={{ marginBottom: '1rem' }}>
<p style={{ fontWeight: 'bold' }}>{pair.split('Answer ')[0].trim()}</p>
<p>{pair.split('Answer ')[1].trim()}</p>
</div>
));
setModalContent(formattedContent);
} else {
setModalContent('Failed to parse the response from the model.');
}

setModalOpen(true);
} catch (error) {
console.error('Error generating Q&A pairs:', error);
setModalContent('Error generating Q&A pairs.');
setModalOpen(true);
}
};

const onCloseActionGroupAlert = () => {
setActionGroupAlertContent(undefined);
};
Expand All @@ -352,8 +400,6 @@
setFilePath('');
setSeedExamples([emptySeedExample, emptySeedExample, emptySeedExample, emptySeedExample, emptySeedExample]);
setDisableAction(true);

// setReset is just reset button, value has no impact.
setReset(reset ? false : true);
};

Expand Down Expand Up @@ -439,6 +485,15 @@
handleAnswerBlur={handleAnswerBlur}
/>

{/* Generate Q&A Button for each Seed Example, TODO: figure out how to nest the buttons under context */}
{seedExamples.map((_, index) => (
<div key={index}>
<Button variant="primary" onClick={() => handleGenerateQAPairs(index)}>
Generate Q&A Pairs
</Button>
</div>
))}

<DocumentInformation
reset={reset}
isEditForm={knowledgeEditFormData?.isEditForm}
Expand Down Expand Up @@ -523,6 +578,11 @@
</ActionGroup>
</Form>
</PageSection>

{/* Modal for Q&A Pair Results */}
<Modal title="Generated Q&A Pairs" isOpen={modalOpen} onClose={() => setModalOpen(false)} variant="small">
<div>{modalContent}</div>
</Modal>
</PageGroup>
);
};
Expand Down
Loading