mirror of
https://github.com/Iheuzio/gpt-contextfiles.git
synced 2025-07-19 06:20:48 +00:00
Compare commits
No commits in common. "main" and "0.2.1" have entirely different histories.
21
CHANGELOG.md
21
CHANGELOG.md
@ -4,27 +4,6 @@ Version History
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
## [Release 0.2.3]
|
|
||||||
|
|
||||||
## What's Changed
|
|
||||||
* fix(display-html): html is now properly displayed by @Iheuzio in https://github.com/Iheuzio/gpt-contextfiles/pull/38
|
|
||||||
* Release 0.2.3 by @Iheuzio in https://github.com/Iheuzio/gpt-contextfiles/pull/39
|
|
||||||
|
|
||||||
|
|
||||||
**Full Changelog**: https://github.com/Iheuzio/gpt-contextfiles/compare/0.2.2...0.2.3
|
|
||||||
|
|
||||||
## [Release 0.2.2]
|
|
||||||
|
|
||||||
## What's Changed
|
|
||||||
* Fix/organize files by @Iheuzio in https://github.com/Iheuzio/gpt-contextfiles/pull/32
|
|
||||||
* Fix/style rendered by @Iheuzio in https://github.com/Iheuzio/gpt-contextfiles/pull/33
|
|
||||||
* fix(style-rendered): padding around response by @Iheuzio in https://github.com/Iheuzio/gpt-contextfiles/pull/34
|
|
||||||
* update(readme-fix): added new features to readme by @Iheuzio in https://github.com/Iheuzio/gpt-contextfiles/pull/35
|
|
||||||
* Release 0.2.2 by @Iheuzio in https://github.com/Iheuzio/gpt-contextfiles/pull/36
|
|
||||||
|
|
||||||
|
|
||||||
**Full Changelog**: https://github.com/Iheuzio/gpt-contextfiles/compare/0.2.1...0.2.2
|
|
||||||
|
|
||||||
## [Release 0.2.1]
|
## [Release 0.2.1]
|
||||||
|
|
||||||
## What's Changed
|
## What's Changed
|
||||||
|
@ -10,7 +10,7 @@ https://openai.com/pricing
|
|||||||
|
|
||||||
> However, being orientated with managing files this project defaults to the 16k context with GPT-3.5-turbo-16k
|
> However, being orientated with managing files this project defaults to the 16k context with GPT-3.5-turbo-16k
|
||||||
|
|
||||||
If you wish to change the model, you must change the model in the `./src/gptContext.js` file
|
If you wish to change the model, you must change the model in the extension.js file
|
||||||
|
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
@ -39,8 +39,6 @@ Other features:
|
|||||||

|

|
||||||
- Click copy to to copy the snippet of code into your file for fast coding
|
- Click copy to to copy the snippet of code into your file for fast coding
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
# How it works
|
# How it works
|
||||||
|
|
||||||
We can select two files we want to pass through, however we can uncheck one of them for later debugging and enter our question:
|
We can select two files we want to pass through, however we can uncheck one of them for later debugging and enter our question:
|
||||||
|
@ -1,6 +1,179 @@
|
|||||||
const vscode = require('vscode');
|
const vscode = require('vscode');
|
||||||
const { selectedFiles } = require('./fileDataProvider');
|
const { Configuration, OpenAIApi } = require("openai");
|
||||||
|
|
||||||
|
// move these into the script so that instead of echoing the question and the contents,
|
||||||
|
// it will echo the question, followed by the answer from the response when the submit button is pressed.
|
||||||
|
const configuration = new Configuration({
|
||||||
|
apiKey: process.env.OPENAI_API_KEY,
|
||||||
|
});
|
||||||
|
|
||||||
|
const openai = new OpenAIApi(configuration);
|
||||||
|
|
||||||
|
// Represents a file item in the file explorer
|
||||||
|
class FileItem {
|
||||||
|
constructor(uri, selected = false) {
|
||||||
|
this.uri = uri;
|
||||||
|
this.selected = selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleSelected() {
|
||||||
|
this.selected = !this.selected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Represents the selected files in the file explorer
|
||||||
|
const selectedFiles = [];
|
||||||
|
|
||||||
|
// Tree data provider for the selected files
|
||||||
|
class FileDataProvider {
|
||||||
|
constructor() {
|
||||||
|
this._onDidChangeTreeData = new vscode.EventEmitter();
|
||||||
|
this.onDidChangeTreeData = this._onDidChangeTreeData.event;
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh() {
|
||||||
|
this._onDidChangeTreeData.fire();
|
||||||
|
}
|
||||||
|
|
||||||
|
getTreeItem(element) {
|
||||||
|
return {
|
||||||
|
label: element.uri.fsPath,
|
||||||
|
collapsibleState: vscode.TreeItemCollapsibleState.None
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getChildren(element) {
|
||||||
|
if (element) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return only the selected files
|
||||||
|
return selectedFiles.filter(file => file.selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command for adding files to gpt-contextfiles
|
||||||
|
const addFilesCommand = vscode.commands.registerCommand('extension.addFilesToGPTContext', () => {
|
||||||
|
const editor = vscode.window.activeTextEditor;
|
||||||
|
if (editor) {
|
||||||
|
const uri = editor.document.uri;
|
||||||
|
const existingFileIndex = selectedFiles.findIndex(file => file.uri.fsPath === uri.fsPath);
|
||||||
|
|
||||||
|
if (existingFileIndex !== -1) {
|
||||||
|
// File already exists, remove it from the list
|
||||||
|
selectedFiles.splice(existingFileIndex, 1);
|
||||||
|
} else {
|
||||||
|
// Add the file to the list with selected state
|
||||||
|
selectedFiles.push(new FileItem(uri, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
fileDataProvider.refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const fileDataProvider = new FileDataProvider();
|
||||||
|
|
||||||
|
// Function to handle question submission
|
||||||
|
async function handleQuestionSubmission(panel, question, selectedUris) {
|
||||||
|
// Update the selectedFiles array based on the selectedUris
|
||||||
|
selectedFiles.forEach(file => {
|
||||||
|
file.selected = selectedUris.includes(file.uri.fsPath);
|
||||||
|
});
|
||||||
|
|
||||||
|
fileDataProvider.refresh();
|
||||||
|
|
||||||
|
const fileContents = selectedFiles
|
||||||
|
.filter(file => file.selected)
|
||||||
|
.map(file => {
|
||||||
|
const document = vscode.workspace.textDocuments.find(doc => doc.uri.fsPath === file.uri.fsPath);
|
||||||
|
if (document) {
|
||||||
|
const lines = document.getText().split('\n');
|
||||||
|
const formattedLines = lines.map(line => `\t${line}`).join('\n');
|
||||||
|
return `${file.uri.fsPath}:\n\`\`\`\n${formattedLines}\n\`\`\``;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
})
|
||||||
|
.join('\n\n');
|
||||||
|
|
||||||
|
// Call OpenAI API with the question and file contents
|
||||||
|
try {
|
||||||
|
const chatCompletion = await openai.createChatCompletion({
|
||||||
|
model: "gpt-3.5-turbo-16k",
|
||||||
|
messages: [
|
||||||
|
{ role: "system", content: "Answer the coding questions, only provide the code and documentation, explaining the solution after providing the code." },
|
||||||
|
{ role: "user", content: question + "\n" + fileContents},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Extract the answer from the OpenAI response
|
||||||
|
const answer = chatCompletion.data.choices[0].message.content;
|
||||||
|
|
||||||
|
// Update the webview content to display only the OpenAI response
|
||||||
|
panel.webview.html = getWebviewContent(answer, question);
|
||||||
|
} catch (error) {
|
||||||
|
// Handle any errors from the OpenAI API
|
||||||
|
console.error("Failed to get OpenAI response:", error);
|
||||||
|
panel.webview.html = getWebviewContent(`Failed to get response from OpenAI API. Error: ${error.message}`, question);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command for displaying the webview panel
|
||||||
|
const openGPTContextPanelCommand = vscode.commands.registerCommand('extension.openGPTContextPanel', () => {
|
||||||
|
const panel = vscode.window.createWebviewPanel(
|
||||||
|
'gptContextPanel',
|
||||||
|
'GPT Context',
|
||||||
|
vscode.ViewColumn.One,
|
||||||
|
{
|
||||||
|
enableScripts: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
panel.webview.html = getWebviewContent();
|
||||||
|
|
||||||
|
panel.webview.onDidReceiveMessage(async message => {
|
||||||
|
if (message.command === 'submitQuestion') {
|
||||||
|
await handleQuestionSubmission(panel, message.text, message.selectedUris);
|
||||||
|
} else if (message.command === 'toggleFileSelection') {
|
||||||
|
const uri = message.uri;
|
||||||
|
const file = selectedFiles.find(file => file.uri.fsPath === uri);
|
||||||
|
if (file) {
|
||||||
|
file.toggleSelected();
|
||||||
|
fileDataProvider.refresh();
|
||||||
|
}
|
||||||
|
} else if (message.command === 'clearSelectedFiles') {
|
||||||
|
const clearedFiles = selectedFiles.filter(file => file.selected === false);
|
||||||
|
selectedFiles.length = 0; // Clear the array
|
||||||
|
clearedFiles.forEach(file => {
|
||||||
|
fileDataProvider.refresh();
|
||||||
|
});
|
||||||
|
panel.webview.html = getWebviewContent();
|
||||||
|
} else if (message.command === 'refreshFiles') {
|
||||||
|
fileDataProvider.refresh();
|
||||||
|
panel.webview.html = getWebviewContent();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Command for refreshing the selected files
|
||||||
|
const refreshSelectedFilesCommand = vscode.commands.registerCommand('extension.refreshSelectedFiles', () => {
|
||||||
|
fileDataProvider.refresh();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Command for clearing the selected files
|
||||||
|
const clearSelectedFilesCommand = vscode.commands.registerCommand('extension.clearSelectedFiles', () => {
|
||||||
|
selectedFiles.forEach(file => {
|
||||||
|
file.selected = false;
|
||||||
|
});
|
||||||
|
fileDataProvider.refresh();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Command for refreshing all files
|
||||||
|
const refreshFilesCommand = vscode.commands.registerCommand('extension.refreshFiles', () => {
|
||||||
|
fileDataProvider.refresh();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Helper function to generate the HTML content for the webview panel
|
||||||
function getWebviewContent(apiResponse = '', question = '') {
|
function getWebviewContent(apiResponse = '', question = '') {
|
||||||
const fileList = selectedFiles
|
const fileList = selectedFiles
|
||||||
.map(
|
.map(
|
||||||
@ -55,13 +228,11 @@ function getWebviewContent(apiResponse = '', question = '') {
|
|||||||
|
|
||||||
#response {
|
#response {
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
background: #343434;
|
|
||||||
border-radius: 5px;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#file-list {
|
#file-list {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
|
border
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-group {
|
.form-group {
|
||||||
@ -164,7 +335,7 @@ function getWebviewContent(apiResponse = '', question = '') {
|
|||||||
color: #d4d4d4;
|
color: #d4d4d4;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
width: 98%;
|
width: 100%;
|
||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
@ -188,12 +359,12 @@ function getWebviewContent(apiResponse = '', question = '') {
|
|||||||
display: none;
|
display: none;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background-color: #f1f1f1;
|
background-color: #f1f1f1;
|
||||||
width: 98%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content p {
|
.content p {
|
||||||
|
margin-top: 0;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
margin: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.active,
|
.active,
|
||||||
@ -232,7 +403,6 @@ function getWebviewContent(apiResponse = '', question = '') {
|
|||||||
border: 1px solid white;
|
border: 1px solid white;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
color: white;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#question-rep {
|
#question-rep {
|
||||||
@ -241,8 +411,6 @@ function getWebviewContent(apiResponse = '', question = '') {
|
|||||||
word-wrap: wrap;
|
word-wrap: wrap;
|
||||||
border: 1px solid white;
|
border: 1px solid white;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: 10px;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
div#api-response.content.active {
|
div#api-response.content.active {
|
||||||
@ -251,6 +419,7 @@ function getWebviewContent(apiResponse = '', question = '') {
|
|||||||
|
|
||||||
#code-block {
|
#code-block {
|
||||||
padding: 10px 0 10px 10px;
|
padding: 10px 0 10px 10px;
|
||||||
|
padding-
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
background-color: black;
|
background-color: black;
|
||||||
border: none;
|
border: none;
|
||||||
@ -258,7 +427,7 @@ function getWebviewContent(apiResponse = '', question = '') {
|
|||||||
color: inherit;
|
color: inherit;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
outline: inherit;
|
outline: inherit;
|
||||||
width: 98%;
|
width: 100%;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -304,19 +473,13 @@ function getWebviewContent(apiResponse = '', question = '') {
|
|||||||
</div>
|
</div>
|
||||||
<div class="content" id="api-response">
|
<div class="content" id="api-response">
|
||||||
<div id="question-rep">
|
<div id="question-rep">
|
||||||
<p>${
|
<p>${question ? '> ' + question : null}</p>
|
||||||
question = question.replace(/</g, '<').replace(/>/g, '>'),
|
|
||||||
question ? '> ' + question : null
|
|
||||||
}</p>
|
|
||||||
</div>
|
</div>
|
||||||
${
|
${
|
||||||
apiResponse ? `
|
apiResponse ? `
|
||||||
<div id="rendered">
|
<div id="rendered">
|
||||||
<p id="responses">
|
<p id="responses">
|
||||||
<pre id="response">${
|
<pre id="response">${apiResponse.replace(/```([^```]+)```/g, '<div id="code-block"><code>$1</code><button onclick="copyCode(event)" id="copy-button">copy</button></div>')}</pre>
|
||||||
apiResponse = apiResponse.replace(/</g, '<').replace(/>/g, '>'),
|
|
||||||
apiResponse.replace(/```([^```]+)```/g, '<div id="code-block"><code>$1</code><button onclick="copyCode(event)" id="copy-button">copy</button></div>')
|
|
||||||
}</pre>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
` : null
|
` : null
|
||||||
@ -421,6 +584,53 @@ function getWebviewContent(apiResponse = '', question = '') {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
getWebviewContent
|
|
||||||
};
|
// Activates the extension
|
||||||
|
function activate(context) {
|
||||||
|
context.subscriptions.push(addFilesCommand);
|
||||||
|
context.subscriptions.push(openGPTContextPanelCommand);
|
||||||
|
context.subscriptions.push(refreshSelectedFilesCommand);
|
||||||
|
context.subscriptions.push(clearSelectedFilesCommand);
|
||||||
|
context.subscriptions.push(refreshFilesCommand);
|
||||||
|
vscode.window.registerTreeDataProvider('selectedFiles', fileDataProvider);
|
||||||
|
|
||||||
|
const provider = {
|
||||||
|
resolveWebviewView(webviewView) {
|
||||||
|
webviewView.webview.options = {
|
||||||
|
enableScripts: true
|
||||||
|
};
|
||||||
|
webviewView.webview.html = getWebviewContent();
|
||||||
|
webviewView.webview.onDidReceiveMessage(async message => {
|
||||||
|
if (message.command === 'toggleFileSelection') {
|
||||||
|
const uri = message.uri;
|
||||||
|
const file = selectedFiles.find(file => file.uri.fsPath === uri);
|
||||||
|
if (file) {
|
||||||
|
file.toggleSelected();
|
||||||
|
fileDataProvider.refresh();
|
||||||
|
}
|
||||||
|
} else if (message.command === 'clearSelectedFiles') {
|
||||||
|
const clearedFiles = selectedFiles.filter(file => file.selected === false);
|
||||||
|
selectedFiles.length = 0; // Clear the array
|
||||||
|
clearedFiles.forEach(file => {
|
||||||
|
fileDataProvider.refresh();
|
||||||
|
});
|
||||||
|
webviewView.webview.html = getWebviewContent();
|
||||||
|
} else if (message.command === 'refreshFiles') {
|
||||||
|
fileDataProvider.refresh();
|
||||||
|
webviewView.webview.html = getWebviewContent();
|
||||||
|
} else if (message.command === 'submitQuestion') {
|
||||||
|
await handleQuestionSubmission(webviewView, message.text, message.selectedUris);
|
||||||
|
} else if (message.command === 'codeCopied') {
|
||||||
|
vscode.window.showInformationMessage('Code copied to clipboard');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
context.subscriptions.push(vscode.window.registerWebviewViewProvider('gpt-context-sidebar', provider));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
exports.activate = activate;
|
Binary file not shown.
Before Width: | Height: | Size: 12 MiB |
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "gpt-contextfiles",
|
"name": "gpt-contextfiles",
|
||||||
"version": "0.2.3",
|
"version": "0.2.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "gpt-contextfiles",
|
"name": "gpt-contextfiles",
|
||||||
"version": "0.2.3",
|
"version": "0.2.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"openai": "^3.3.0"
|
"openai": "^3.3.0"
|
||||||
},
|
},
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"name": "gpt-contextfiles",
|
"name": "gpt-contextfiles",
|
||||||
"displayName": "GPT-ContextFiles",
|
"displayName": "GPT-ContextFiles",
|
||||||
"description": "Choose the files to pass into GPT to provide a question with multiple files",
|
"description": "Choose the files to pass into GPT to provide a question with multiple files",
|
||||||
"version": "0.2.3",
|
"version": "0.2.1",
|
||||||
"engines": {
|
"engines": {
|
||||||
"vscode": "^1.79.0"
|
"vscode": "^1.79.0"
|
||||||
},
|
},
|
||||||
@ -39,7 +39,7 @@
|
|||||||
"onCommand:extension.openGPTContextPanel",
|
"onCommand:extension.openGPTContextPanel",
|
||||||
"onCommand:extension.gpt-context-sidebar"
|
"onCommand:extension.gpt-context-sidebar"
|
||||||
],
|
],
|
||||||
"main": "./src/extension.js",
|
"main": "./extension.js",
|
||||||
"contributes": {
|
"contributes": {
|
||||||
"commands": [
|
"commands": [
|
||||||
{
|
{
|
||||||
|
@ -1,84 +0,0 @@
|
|||||||
const vscode = require('vscode');
|
|
||||||
const { selectedFiles, fileDataProvider, handleQuestionSubmission } = require('./gptContext');
|
|
||||||
const FileItem = require('./fileItem');
|
|
||||||
const { getWebviewContent } = require('./webviewPanel');
|
|
||||||
|
|
||||||
const addFilesCommand = vscode.commands.registerCommand('extension.addFilesToGPTContext', () => {
|
|
||||||
const editor = vscode.window.activeTextEditor;
|
|
||||||
if (editor) {
|
|
||||||
const uri = editor.document.uri;
|
|
||||||
const existingFileIndex = selectedFiles.findIndex(file => file.uri.fsPath === uri.fsPath);
|
|
||||||
|
|
||||||
if (existingFileIndex !== -1) {
|
|
||||||
// File already exists, remove it from the list
|
|
||||||
selectedFiles.splice(existingFileIndex, 1);
|
|
||||||
} else {
|
|
||||||
// Add the file to the list with selected state
|
|
||||||
selectedFiles.push(new FileItem(uri, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
fileDataProvider.refresh();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const openGPTContextPanelCommand = vscode.commands.registerCommand('extension.openGPTContextPanel', () => {
|
|
||||||
const panel = vscode.window.createWebviewPanel(
|
|
||||||
'gptContextPanel',
|
|
||||||
'GPT Context',
|
|
||||||
vscode.ViewColumn.One,
|
|
||||||
{
|
|
||||||
enableScripts: true
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
panel.webview.html = getWebviewContent();
|
|
||||||
|
|
||||||
panel.webview.onDidReceiveMessage(async message => {
|
|
||||||
if (message.command === 'submitQuestion') {
|
|
||||||
await handleQuestionSubmission(panel, message.text, message.selectedUris);
|
|
||||||
} else if (message.command === 'toggleFileSelection') {
|
|
||||||
const uri = message.uri;
|
|
||||||
const file = selectedFiles.find(file => file.uri.fsPath === uri);
|
|
||||||
if (file) {
|
|
||||||
file.toggleSelected();
|
|
||||||
fileDataProvider.refresh();
|
|
||||||
}
|
|
||||||
} else if (message.command === 'clearSelectedFiles') {
|
|
||||||
const clearedFiles = selectedFiles.filter(file => file.selected === false);
|
|
||||||
selectedFiles.length = 0; // Clear the array
|
|
||||||
clearedFiles.forEach(file => {
|
|
||||||
fileDataProvider.refresh();
|
|
||||||
});
|
|
||||||
panel.webview.html = getWebviewContent();
|
|
||||||
} else if (message.command === 'refreshFiles') {
|
|
||||||
fileDataProvider.refresh();
|
|
||||||
panel.webview.html = getWebviewContent();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const refreshSelectedFilesCommand = vscode.commands.registerCommand('extension.refreshSelectedFiles', () => {
|
|
||||||
fileDataProvider.refresh();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Command for clearing the selected files
|
|
||||||
const clearSelectedFilesCommand = vscode.commands.registerCommand('extension.clearSelectedFiles', () => {
|
|
||||||
selectedFiles.forEach(file => {
|
|
||||||
file.selected = false;
|
|
||||||
});
|
|
||||||
fileDataProvider.refresh();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Command for refreshing all files
|
|
||||||
const refreshFilesCommand = vscode.commands.registerCommand('extension.refreshFiles', () => {
|
|
||||||
fileDataProvider.refresh();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
addFilesCommand,
|
|
||||||
openGPTContextPanelCommand,
|
|
||||||
refreshSelectedFilesCommand,
|
|
||||||
clearSelectedFilesCommand,
|
|
||||||
refreshFilesCommand
|
|
||||||
};
|
|
@ -1,52 +0,0 @@
|
|||||||
const vscode = require('vscode');
|
|
||||||
const { addFilesCommand, openGPTContextPanelCommand, refreshSelectedFilesCommand, clearSelectedFilesCommand, refreshFilesCommand } = require('./commands');
|
|
||||||
const { getWebviewContent } = require('./webviewPanel');
|
|
||||||
const { selectedFiles, fileDataProvider, handleQuestionSubmission } = require('./gptContext');
|
|
||||||
|
|
||||||
function activate(context) {
|
|
||||||
context.subscriptions.push(addFilesCommand);
|
|
||||||
context.subscriptions.push(openGPTContextPanelCommand);
|
|
||||||
context.subscriptions.push(refreshSelectedFilesCommand);
|
|
||||||
context.subscriptions.push(clearSelectedFilesCommand);
|
|
||||||
context.subscriptions.push(refreshFilesCommand);
|
|
||||||
vscode.window.registerTreeDataProvider('selectedFiles', fileDataProvider);
|
|
||||||
|
|
||||||
const provider = {
|
|
||||||
resolveWebviewView(webviewView) {
|
|
||||||
webviewView.webview.options = {
|
|
||||||
enableScripts: true
|
|
||||||
};
|
|
||||||
webviewView.webview.html = getWebviewContent();
|
|
||||||
webviewView.webview.onDidReceiveMessage(async message => {
|
|
||||||
if (message.command === 'toggleFileSelection') {
|
|
||||||
const uri = message.uri;
|
|
||||||
const file = selectedFiles.find(file => file.uri.fsPath === uri);
|
|
||||||
if (file) {
|
|
||||||
file.toggleSelected();
|
|
||||||
fileDataProvider.refresh();
|
|
||||||
}
|
|
||||||
} else if (message.command === 'clearSelectedFiles') {
|
|
||||||
const clearedFiles = selectedFiles.filter(file => file.selected === false);
|
|
||||||
selectedFiles.length = 0; // Clear the array
|
|
||||||
clearedFiles.forEach(file => {
|
|
||||||
fileDataProvider.refresh();
|
|
||||||
});
|
|
||||||
webviewView.webview.html = getWebviewContent();
|
|
||||||
} else if (message.command === 'refreshFiles') {
|
|
||||||
fileDataProvider.refresh();
|
|
||||||
webviewView.webview.html = getWebviewContent();
|
|
||||||
} else if (message.command === 'submitQuestion') {
|
|
||||||
await handleQuestionSubmission(webviewView, message.text, message.selectedUris);
|
|
||||||
} else if (message.command === 'codeCopied') {
|
|
||||||
vscode.window.showInformationMessage('Code copied to clipboard');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
context.subscriptions.push(vscode.window.registerWebviewViewProvider('gpt-context-sidebar', provider));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
exports.activate = activate;
|
|
@ -1,38 +0,0 @@
|
|||||||
const vscode = require('vscode');
|
|
||||||
const FileItem = require('./fileItem.js');
|
|
||||||
|
|
||||||
// Represents the selected files in the file explorer
|
|
||||||
const selectedFiles = [];
|
|
||||||
|
|
||||||
// Tree data provider for the selected files
|
|
||||||
class FileDataProvider {
|
|
||||||
constructor() {
|
|
||||||
this._onDidChangeTreeData = new vscode.EventEmitter();
|
|
||||||
this.onDidChangeTreeData = this._onDidChangeTreeData.event;
|
|
||||||
}
|
|
||||||
|
|
||||||
refresh() {
|
|
||||||
this._onDidChangeTreeData.fire();
|
|
||||||
}
|
|
||||||
|
|
||||||
getTreeItem(element) {
|
|
||||||
return {
|
|
||||||
label: element.uri.fsPath,
|
|
||||||
collapsibleState: vscode.TreeItemCollapsibleState.None
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
getChildren(element) {
|
|
||||||
if (element) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return only the selected files
|
|
||||||
return selectedFiles.filter(file => file.selected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
FileDataProvider,
|
|
||||||
selectedFiles
|
|
||||||
};
|
|
@ -1,12 +0,0 @@
|
|||||||
class FileItem {
|
|
||||||
constructor(uri, selected = false) {
|
|
||||||
this.uri = uri;
|
|
||||||
this.selected = selected;
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleSelected() {
|
|
||||||
this.selected = !this.selected;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = FileItem;
|
|
@ -1,63 +0,0 @@
|
|||||||
const vscode = require('vscode');
|
|
||||||
const { Configuration, OpenAIApi } = require("openai");
|
|
||||||
const FileDataProvider = require('./fileDataProvider');
|
|
||||||
const { getWebviewContent } = require('./webviewPanel');
|
|
||||||
|
|
||||||
|
|
||||||
const configuration = new Configuration({
|
|
||||||
apiKey: process.env.OPENAI_API_KEY,
|
|
||||||
});
|
|
||||||
|
|
||||||
const openai = new OpenAIApi(configuration);
|
|
||||||
|
|
||||||
const selectedFiles = FileDataProvider.selectedFiles;
|
|
||||||
const fileDataProvider = new FileDataProvider.FileDataProvider();
|
|
||||||
|
|
||||||
async function handleQuestionSubmission(panel, question, selectedUris) {
|
|
||||||
// Update the selectedFiles array based on the selectedUris
|
|
||||||
selectedFiles.forEach(file => {
|
|
||||||
file.selected = selectedUris.includes(file.uri.fsPath);
|
|
||||||
});
|
|
||||||
|
|
||||||
fileDataProvider.refresh();
|
|
||||||
|
|
||||||
const fileContents = selectedFiles
|
|
||||||
.filter(file => file.selected)
|
|
||||||
.map(file => {
|
|
||||||
const document = vscode.workspace.textDocuments.find(doc => doc.uri.fsPath === file.uri.fsPath);
|
|
||||||
if (document) {
|
|
||||||
const lines = document.getText().split('\n');
|
|
||||||
const formattedLines = lines.map(line => `\t${line}`).join('\n');
|
|
||||||
return `${file.uri.fsPath}:\n\`\`\`\n${formattedLines}\n\`\`\``;
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
})
|
|
||||||
.join('\n\n');
|
|
||||||
|
|
||||||
// Call OpenAI API with the question and file contents
|
|
||||||
try {
|
|
||||||
const chatCompletion = await openai.createChatCompletion({
|
|
||||||
model: "gpt-3.5-turbo-16k",
|
|
||||||
messages: [
|
|
||||||
{ role: "system", content: "Answer the coding questions, only provide the code and documentation, explaining the solution after providing the code. Put codeblocks inside ``` code ``` with file names above each snippet." },
|
|
||||||
{ role: "user", content: question + "\n" + fileContents},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
// Extract the answer from the OpenAI response
|
|
||||||
const answer = chatCompletion.data.choices[0].message.content;
|
|
||||||
|
|
||||||
// Update the webview content to display only the OpenAI response
|
|
||||||
panel.webview.html = getWebviewContent(answer, question);
|
|
||||||
} catch (error) {
|
|
||||||
// Handle any errors from the OpenAI API
|
|
||||||
console.error("Failed to get OpenAI response:", error);
|
|
||||||
panel.webview.html = getWebviewContent(`Failed to get response from OpenAI API. Error: ${error.message}`, question);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
handleQuestionSubmission,
|
|
||||||
fileDataProvider,
|
|
||||||
selectedFiles
|
|
||||||
};
|
|
Loading…
Reference in New Issue
Block a user