From 93be5cbce3263c5565d051483db37ff20d29d14c Mon Sep 17 00:00:00 2001 From: Christopher Date: Sun, 18 Jun 2023 16:30:57 -0400 Subject: [PATCH 01/10] fix(gpt-context): Fixes the layout and the options with the selected files --- extension.js | 221 +++++++++++++++++++++++---------------------------- 1 file changed, 99 insertions(+), 122 deletions(-) diff --git a/extension.js b/extension.js index 11c844e..6c36368 100644 --- a/extension.js +++ b/extension.js @@ -1,11 +1,14 @@ const vscode = require('vscode'); -const path = require('path'); // Represents a file item in the file explorer class FileItem { - constructor(uri, checked) { + constructor(uri, selected = false) { this.uri = uri; - this.checked = checked || false; + this.selected = selected; + } + + toggleSelected() { + this.selected = !this.selected; } } @@ -14,79 +17,53 @@ const selectedFiles = []; // Tree data provider for the selected files class FileDataProvider { - constructor() { - this._onDidChangeTreeData = new vscode.EventEmitter(); - this.onDidChangeTreeData = this._onDidChangeTreeData.event; - this.filterPatterns = ['*.*']; // Default filter pattern - } + constructor() { + this._onDidChangeTreeData = new vscode.EventEmitter(); + this.onDidChangeTreeData = this._onDidChangeTreeData.event; + } - refresh() { - this._onDidChangeTreeData.fire(); - } + refresh() { + this._onDidChangeTreeData.fire(); + } - getTreeItem(element) { - return { - label: element.uri.fsPath, - collapsibleState: vscode.TreeItemCollapsibleState.None, - checked: element.checked - }; - } + getTreeItem(element) { + return { + label: element.uri.fsPath, + collapsibleState: vscode.TreeItemCollapsibleState.None + }; + } - getChildren(element) { - if (element) { - return []; - } - return selectedFiles; - } + getChildren(element) { + if (element) { + return []; + } - setFilter(filter) { - this.filterPatterns = filter.split(',').map(pattern => pattern.trim()); - this.refresh(); - } - - filterFiles(files) { - return files.filter(file => { - const extension = path.extname(file.uri.fsPath); - return this.filterPatterns.some(pattern => { - const regex = new RegExp(pattern.replace(/\./g, '\\.').replace(/\*/g, '.*')); - return regex.test(extension); - }); - }); - } + // 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 workspaceFolders = vscode.workspace.workspaceFolders; - if (workspaceFolders && workspaceFolders.length > 0) { - const workspacePath = workspaceFolders[0].uri.fsPath; - vscode.workspace.findFiles('**/*', '', 1000).then(files => { - const fileItems = files.map(file => new FileItem(file)); - selectedFiles.splice(0, selectedFiles.length, ...fileItems); - fileDataProvider.refresh(); - }); - } + 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(); + } }); -// Refresh the file list when workspace changes (file creation, deletion, renaming) -vscode.workspace.onDidChangeWorkspaceFolders(() => { - vscode.commands.executeCommand('extension.addFilesToGPTContext'); -}); - -vscode.workspace.onDidCreateFiles(() => { - vscode.commands.executeCommand('extension.addFilesToGPTContext'); -}); - -vscode.workspace.onDidDeleteFiles(() => { - vscode.commands.executeCommand('extension.addFilesToGPTContext'); -}); - -vscode.workspace.onDidRenameFiles(() => { - vscode.commands.executeCommand('extension.addFilesToGPTContext'); -}); - - - const fileDataProvider = new FileDataProvider(); // Command for displaying the webview panel @@ -105,46 +82,52 @@ const openGPTContextPanelCommand = vscode.commands.registerCommand('extension.op panel.webview.onDidReceiveMessage(message => { if (message.command === 'submitQuestion') { const question = message.text; - const selectedFilePaths = selectedFiles - .filter(file => file.checked) - .map(file => file.uri.fsPath); - - const fileContents = selectedFilePaths - .map(filePath => { - const document = vscode.workspace.textDocuments.find(doc => doc.uri.fsPath === filePath); + const fileContents = selectedFiles + .map(file => { + const document = vscode.workspace.textDocuments.find(doc => doc.uri.fsPath === file.uri.fsPath); if (document) { const lines = document.getText().split('\n'); - return `${filePath}\n${lines.join('\n')}`; + return `${file.uri.fsPath}\n${lines.join('\n')}`; } return ''; }) .join('\n\n'); panel.webview.html = getWebviewContent(fileContents, question); - } else if (message.command === 'fileSelectionChanged') { - const { filePath, checked } = message; - const file = selectedFiles.find(file => file.uri.fsPath === filePath); + } else if (message.command === 'toggleFileSelection') { + const uri = message.uri; + const file = selectedFiles.find(file => file.uri.fsPath === uri); if (file) { - file.checked = checked; + file.toggleSelected(); + fileDataProvider.refresh(); } - } else if (message.command === 'filterFiles') { - const { filter } = message; - fileDataProvider.setFilter(filter); + } else if (message.command === 'clearSelectedFiles') { + selectedFiles.forEach(file => { + file.selected = false; + }); + selectedFiles.length = 0; // Clear the array + fileDataProvider.refresh(); + } else if (message.command === 'refreshSelectedFiles') { + fileDataProvider.refresh(); } }); }); +// Command for refreshing the selected files +const refreshSelectedFilesCommand = vscode.commands.registerCommand('extension.refreshSelectedFiles', () => { + fileDataProvider.refresh(); +}); + // Helper function to generate the HTML content for the webview panel function getWebviewContent(fileContents, question) { - const fileItems = fileDataProvider - .filterFiles(selectedFiles) - .map(file => ` -
- - -
- `) - .join('\n'); + const fileList = selectedFiles + .map( + file => + `
${file.uri.fsPath}
` + ) + .join(''); return ` @@ -154,23 +137,39 @@ function getWebviewContent(fileContents, question) { + + -
-

Select Files:

-
- - - -
- ${fileItems} -
${ fileContents ? `
${fileContents}
` : '' } +
+

Selected Files:

+ ${fileList} +
${question ? question : ''}
@@ -217,6 +193,7 @@ function activate(context) { // Register the commands context.subscriptions.push(addFilesCommand); context.subscriptions.push(openGPTContextPanelCommand); + context.subscriptions.push(refreshSelectedFilesCommand); // Refresh the file data provider when a file is added or removed from the workspace vscode.workspace.onDidChangeWorkspaceFolders(() => { From fbeb0cc7036edd590753b52a0b9a098d6f9123e5 Mon Sep 17 00:00:00 2001 From: Christopher Date: Sun, 18 Jun 2023 16:57:05 -0400 Subject: [PATCH 02/10] fix(context-window): FIxed the clear and refresh and updated the commands. Now the buttons will clear the items and refresh correctly. --- extension.js | 73 +++++++++++++++++++++++++++++++--------------------- package.json | 26 ++++++++++++------- 2 files changed, 61 insertions(+), 38 deletions(-) diff --git a/extension.js b/extension.js index 6c36368..e87ad09 100644 --- a/extension.js +++ b/extension.js @@ -17,34 +17,32 @@ const selectedFiles = []; // Tree data provider for the selected files class FileDataProvider { - constructor() { - this._onDidChangeTreeData = new vscode.EventEmitter(); - this.onDidChangeTreeData = this._onDidChangeTreeData.event; - } + constructor() { + this._onDidChangeTreeData = new vscode.EventEmitter(); + this.onDidChangeTreeData = this._onDidChangeTreeData.event; + } - refresh() { - this._onDidChangeTreeData.fire(); - } + refresh() { + this._onDidChangeTreeData.fire(); + } - getTreeItem(element) { - return { - label: element.uri.fsPath, - collapsibleState: vscode.TreeItemCollapsibleState.None - }; - } + getTreeItem(element) { + return { + label: element.uri.fsPath, + collapsibleState: vscode.TreeItemCollapsibleState.None + }; + } - getChildren(element) { - if (element) { - return []; - } + getChildren(element) { + if (element) { + return []; + } - // Return only the selected files - return selectedFiles.filter(file => file.selected); - } + // 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; @@ -102,20 +100,35 @@ const openGPTContextPanelCommand = vscode.commands.registerCommand('extension.op fileDataProvider.refresh(); } } else if (message.command === 'clearSelectedFiles') { - selectedFiles.forEach(file => { - file.selected = false; - }); + 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(); - } else if (message.command === 'refreshSelectedFiles') { - fileDataProvider.refresh(); + panel.webview.html = getWebviewContent(); } }); }); // Command for refreshing the selected files const refreshSelectedFilesCommand = vscode.commands.registerCommand('extension.refreshSelectedFiles', () => { - fileDataProvider.refresh(); + 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 @@ -166,7 +179,7 @@ function getWebviewContent(fileContents, question) { function refreshSelectedFiles() { vscode.postMessage({ - command: 'refreshSelectedFiles' + command: 'refreshFiles' }); } @@ -194,6 +207,8 @@ function activate(context) { context.subscriptions.push(addFilesCommand); context.subscriptions.push(openGPTContextPanelCommand); context.subscriptions.push(refreshSelectedFilesCommand); + context.subscriptions.push(clearSelectedFilesCommand); + context.subscriptions.push(refreshFilesCommand); // Refresh the file data provider when a file is added or removed from the workspace vscode.workspace.onDidChangeWorkspaceFolders(() => { diff --git a/package.json b/package.json index ca048b2..1d40b67 100644 --- a/package.json +++ b/package.json @@ -16,15 +16,23 @@ "main": "./extension.js", "contributes": { "commands": [ - { - "command": "extension.addFilesToGPTContext", - "title": "Add Files to GPT Context", - "category": "Explorer" - }, - { - "command": "extension.openGPTContextPanel", - "title": "Open GPT Context Panel" - } + { + "command": "extension.addFilesToGPTContext", + "title": "Add Files to GPT Context", + "category": "Explorer" + }, + { + "command": "extension.openGPTContextPanel", + "title": "Open GPT Context Panel" + }, + { + "command": "extension.refreshSelectedFiles", + "title": "Refresh Selected Files" + }, + { + "command": "extension.clearSelectedFiles", + "title": "Clear Selected Files" + } ], "menus": { "explorer/context": [ From c441505506af24f5ce85d5c19752bbfca01c6543 Mon Sep 17 00:00:00 2001 From: Christopher Date: Sun, 18 Jun 2023 17:09:15 -0400 Subject: [PATCH 03/10] fix(format-queries): Now the question is displayed atop the files and the file contents are formatted to display the contents of the files. --- extension.js | 130 +++++++++++++++++++++++++++++---------------------- 1 file changed, 73 insertions(+), 57 deletions(-) diff --git a/extension.js b/extension.js index e87ad09..0382d94 100644 --- a/extension.js +++ b/extension.js @@ -133,71 +133,87 @@ const refreshFilesCommand = vscode.commands.registerCommand('extension.refreshFi // Helper function to generate the HTML content for the webview panel function getWebviewContent(fileContents, question) { - const fileList = selectedFiles - .map( - file => - `
${file.uri.fsPath}
` - ) - .join(''); + const fileList = selectedFiles + .map( + file => + `
${file.uri.fsPath}
` + ) + .join(''); - return ` - - -

GPT Context

-
- - - - - -
- ${ - fileContents ? `
${fileContents}
` : '' - } -
-

Selected Files:

- ${fileList} -
-
${question ? question : ''}
- - - - `; + function refreshSelectedFiles() { + vscode.postMessage({ + command: 'refreshFiles' + }); + } + + const form = document.getElementById('questionForm'); + form.addEventListener('submit', event => { + event.preventDefault(); + const question = document.getElementById('question').value; + vscode.postMessage({ + command: 'submitQuestion', + text: question + }); + }); + + + + `; } + // Activates the extension function activate(context) { // Register the file data provider From 6d99c75447f1ae893e4a3b432d711d03aa84b688 Mon Sep 17 00:00:00 2001 From: Christopher Date: Sun, 18 Jun 2023 17:39:01 -0400 Subject: [PATCH 04/10] fix(syntax) --- extension.js | 130 +++++++++++++++++++++++++++++---------------------- 1 file changed, 73 insertions(+), 57 deletions(-) diff --git a/extension.js b/extension.js index e87ad09..0382d94 100644 --- a/extension.js +++ b/extension.js @@ -133,71 +133,87 @@ const refreshFilesCommand = vscode.commands.registerCommand('extension.refreshFi // Helper function to generate the HTML content for the webview panel function getWebviewContent(fileContents, question) { - const fileList = selectedFiles - .map( - file => - `
${file.uri.fsPath}
` - ) - .join(''); + const fileList = selectedFiles + .map( + file => + `
${file.uri.fsPath}
` + ) + .join(''); - return ` - - -

GPT Context

-
- - - - - -
- ${ - fileContents ? `
${fileContents}
` : '' - } -
-

Selected Files:

- ${fileList} -
-
${question ? question : ''}
- - - - `; + function refreshSelectedFiles() { + vscode.postMessage({ + command: 'refreshFiles' + }); + } + + const form = document.getElementById('questionForm'); + form.addEventListener('submit', event => { + event.preventDefault(); + const question = document.getElementById('question').value; + vscode.postMessage({ + command: 'submitQuestion', + text: question + }); + }); + + + + `; } + // Activates the extension function activate(context) { // Register the file data provider From d5b11ddcd1ea9132b208d60064908c59d30a3fcd Mon Sep 17 00:00:00 2001 From: Christopher Date: Mon, 19 Jun 2023 22:59:56 -0400 Subject: [PATCH 05/10] fix(selected-files): User can now select individual files to print their contents --- extension.js | 82 +++++++++++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/extension.js b/extension.js index 0382d94..94b0770 100644 --- a/extension.js +++ b/extension.js @@ -80,7 +80,17 @@ const openGPTContextPanelCommand = vscode.commands.registerCommand('extension.op panel.webview.onDidReceiveMessage(message => { if (message.command === 'submitQuestion') { const question = message.text; + const selectedUris = message.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) { @@ -133,28 +143,29 @@ const refreshFilesCommand = vscode.commands.registerCommand('extension.refreshFi // Helper function to generate the HTML content for the webview panel function getWebviewContent(fileContents, question) { - const fileList = selectedFiles - .map( - file => - `
${file.uri.fsPath}
` - ) - .join(''); + const fileList = selectedFiles + .map( + file => + `
${file.uri.fsPath}
` + ) + .join(''); - const formattedContents = selectedFiles - .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'); + const formattedContents = 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'); - return ` + return `

GPT Context

@@ -202,9 +213,18 @@ function getWebviewContent(fileContents, question) { form.addEventListener('submit', event => { event.preventDefault(); const question = document.getElementById('question').value; + const checkboxes = document.querySelectorAll('input[type="checkbox"]'); + const selectedUris = []; + checkboxes.forEach(checkbox => { + if (checkbox.checked) { + const uri = checkbox.getAttribute('data-uri'); + selectedUris.push(uri); + } + }); vscode.postMessage({ command: 'submitQuestion', - text: question + text: question, + selectedUris: selectedUris }); }); @@ -213,30 +233,14 @@ function getWebviewContent(fileContents, question) { `; } - // Activates the extension function activate(context) { - // Register the file data provider - vscode.window.registerTreeDataProvider('gpt-contextfiles', fileDataProvider); - - // Register the commands context.subscriptions.push(addFilesCommand); context.subscriptions.push(openGPTContextPanelCommand); context.subscriptions.push(refreshSelectedFilesCommand); context.subscriptions.push(clearSelectedFilesCommand); context.subscriptions.push(refreshFilesCommand); - - // Refresh the file data provider when a file is added or removed from the workspace - vscode.workspace.onDidChangeWorkspaceFolders(() => { - fileDataProvider.refresh(); - }); - - // Refresh the file data provider when a file is created, deleted, or renamed within the workspace - vscode.workspace.onDidChangeTextDocument(() => { - fileDataProvider.refresh(); - }); + vscode.window.registerTreeDataProvider('selectedFiles', fileDataProvider); } -module.exports = { - activate -}; +exports.activate = activate; From 8e2e90c729ba17a4a8349f3e520bdc441378cb7f Mon Sep 17 00:00:00 2001 From: Christopher Date: Wed, 21 Jun 2023 11:45:34 -0400 Subject: [PATCH 06/10] feature(openai-api): Allows the user to submit the question and contents through to the model. Untested --- extension.js | 45 +++++++++++++++++++++- package-lock.json | 95 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 42 +++++++++++---------- 3 files changed, 160 insertions(+), 22 deletions(-) diff --git a/extension.js b/extension.js index 1f15f87..496eb90 100644 --- a/extension.js +++ b/extension.js @@ -1,4 +1,24 @@ const vscode = require('vscode'); +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); + +async function getChatCompletion() { + const chatCompletion = await openai.createChatCompletion({ + model: "gpt-3.5-turbo", + messages: [{role: "user", content: "Hello world"}], + }); + console.log(chatCompletion.data.choices[0].message); +} + +getChatCompletion(); +// // Represents a file item in the file explorer class FileItem { @@ -77,7 +97,7 @@ const openGPTContextPanelCommand = vscode.commands.registerCommand('extension.op panel.webview.html = getWebviewContent(); - panel.webview.onDidReceiveMessage(message => { + panel.webview.onDidReceiveMessage(async message => { if (message.command === 'submitQuestion') { const question = message.text; const selectedUris = message.selectedUris; @@ -101,7 +121,27 @@ const openGPTContextPanelCommand = vscode.commands.registerCommand('extension.op }) .join('\n\n'); - panel.webview.html = getWebviewContent(fileContents, question); + // Call OpenAI API with the question and file contents + try { + const chatCompletion = await openai.createChatCompletion({ + model: "gpt-3.5-turbo", + 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 }, + { role: "assistant", content: fileContents } + ], + }); + + // Extract the answer from the OpenAI response + const answer = chatCompletion.data.choices[0].message.content; + + // Update the webview content to display only the question and 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); + // My tokens ran out so I cannot develop further. + } } else if (message.command === 'toggleFileSelection') { const uri = message.uri; const file = selectedFiles.find(file => file.uri.fsPath === uri); @@ -123,6 +163,7 @@ const openGPTContextPanelCommand = vscode.commands.registerCommand('extension.op }); }); + // Command for refreshing the selected files const refreshSelectedFilesCommand = vscode.commands.registerCommand('extension.refreshSelectedFiles', () => { fileDataProvider.refresh(); diff --git a/package-lock.json b/package-lock.json index a4bb790..ce8b9b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,9 @@ "": { "name": "gpt-contextfiles", "version": "0.0.1", + "dependencies": { + "openai": "^3.3.0" + }, "devDependencies": { "@types/glob": "^8.1.0", "@types/mocha": "^10.0.1", @@ -305,6 +308,19 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "dependencies": { + "follow-redirects": "^1.14.8" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -453,6 +469,17 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -514,6 +541,14 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/diff": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", @@ -800,6 +835,38 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -1203,6 +1270,25 @@ "node": ">=10" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -1371,6 +1457,15 @@ "wrappy": "1" } }, + "node_modules/openai": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-3.3.0.tgz", + "integrity": "sha512-uqxI/Au+aPRnsaQRe8CojU0eCR7I0mBiKjD3sNMzY6DaC1ZVrc85u98mtJW6voDug8fgGN+DIZmTDxTthxb7dQ==", + "dependencies": { + "axios": "^0.26.0", + "form-data": "^4.0.0" + } + }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", diff --git a/package.json b/package.json index 1d40b67..f4ee1b0 100644 --- a/package.json +++ b/package.json @@ -17,31 +17,31 @@ "contributes": { "commands": [ { - "command": "extension.addFilesToGPTContext", - "title": "Add Files to GPT Context", - "category": "Explorer" + "command": "extension.addFilesToGPTContext", + "title": "Add Files to GPT Context", + "category": "Explorer" }, { - "command": "extension.openGPTContextPanel", - "title": "Open GPT Context Panel" + "command": "extension.openGPTContextPanel", + "title": "Open GPT Context Panel" }, { - "command": "extension.refreshSelectedFiles", - "title": "Refresh Selected Files" + "command": "extension.refreshSelectedFiles", + "title": "Refresh Selected Files" }, { - "command": "extension.clearSelectedFiles", - "title": "Clear Selected Files" + "command": "extension.clearSelectedFiles", + "title": "Clear Selected Files" } ], "menus": { - "explorer/context": [ - { - "when": "resourceLangId == javascript", - "command": "extension.addFilesToGPTContext", - "group": "navigation" - } - ] + "explorer/context": [ + { + "when": "resourceLangId == javascript", + "command": "extension.addFilesToGPTContext", + "group": "navigation" + } + ] } }, "scripts": { @@ -50,15 +50,17 @@ "test": "node ./test/runTest.js" }, "devDependencies": { - "@types/vscode": "^1.79.0", "@types/glob": "^8.1.0", "@types/mocha": "^10.0.1", "@types/node": "20.2.5", + "@types/vscode": "^1.79.0", + "@vscode/test-electron": "^2.3.2", "eslint": "^8.41.0", "glob": "^8.1.0", "mocha": "^10.2.0", - "typescript": "^5.1.3", - "@vscode/test-electron": "^2.3.2" + "typescript": "^5.1.3" + }, + "dependencies": { + "openai": "^3.3.0" } - } From ff0f12953db71974ca59d53311d3ce2f5da6f84c Mon Sep 17 00:00:00 2001 From: Christopher Date: Wed, 21 Jun 2023 12:38:51 -0400 Subject: [PATCH 07/10] fix(api-error): Fixed adding files and the error code displayed, if encountered --- extension.js | 32 ++++---------------------------- 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/extension.js b/extension.js index 496eb90..a801838 100644 --- a/extension.js +++ b/extension.js @@ -9,17 +9,6 @@ const configuration = new Configuration({ const openai = new OpenAIApi(configuration); -async function getChatCompletion() { - const chatCompletion = await openai.createChatCompletion({ - model: "gpt-3.5-turbo", - messages: [{role: "user", content: "Hello world"}], - }); - console.log(chatCompletion.data.choices[0].message); -} - -getChatCompletion(); -// - // Represents a file item in the file explorer class FileItem { constructor(uri, selected = false) { @@ -135,12 +124,12 @@ const openGPTContextPanelCommand = vscode.commands.registerCommand('extension.op // Extract the answer from the OpenAI response const answer = chatCompletion.data.choices[0].message.content; - // Update the webview content to display only the question and OpenAI response + // 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); - // My tokens ran out so I cannot develop further. + panel.webview.html = getWebviewContent(`Failed to get response from OpenAI API. Error: ${error.message}`, question); } } else if (message.command === 'toggleFileSelection') { const uri = message.uri; @@ -183,7 +172,7 @@ const refreshFilesCommand = vscode.commands.registerCommand('extension.refreshFi }); // Helper function to generate the HTML content for the webview panel -function getWebviewContent(fileContents, question) { +function getWebviewContent(apiResponse = '', question = '') { const fileList = selectedFiles .map( file => @@ -193,19 +182,6 @@ function getWebviewContent(fileContents, question) { ) .join(''); - const formattedContents = 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'); - return ` @@ -221,7 +197,7 @@ function getWebviewContent(fileContents, question) {
${question ? question : ''}
${ - fileContents ? `
${formattedContents}
` : '' + apiResponse ? `
${apiResponse}
` : '' }
From 2f6570514d079472a598c83b3881142e8230034a Mon Sep 17 00:00:00 2001 From: Iheuzio <97270760+Iheuzio@users.noreply.github.com> Date: Wed, 21 Jun 2023 12:53:46 -0400 Subject: [PATCH 08/10] Update README.md --- README.md | 76 ++++++++++++++++++++----------------------------------- 1 file changed, 27 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index 6004d4f..f14f384 100644 --- a/README.md +++ b/README.md @@ -1,65 +1,43 @@ -# gpt-contextfiles README +# gpt-contextfiles -This is the README for your extension "gpt-contextfiles". After writing up a brief description, we recommend including the following sections. +** currently in development, if you'll like to contribute or provide any feedback check out the [link](https://github.com/Iheuzio/gpt-contextfiles/issues) ** -## Features +I was annoyed with copying responses into chatgpt and other LLMs for debugging my code across files, so I decided to make an extension that will do that. -Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file. +You simply right click each file you want to pass through, check or uncheck the checkbox, then enter your question and pass along the response over the api to your LLM. -For example if there is an image subfolder under your extension project workspace: +# Installation -\!\[feature X\]\(images/feature-x.png\) +Add your api key to `OPENAI_API_KEY` for your windows/linux environment variable (tested with system variable) -> Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow. +# Features -## Requirements +Clear -> Clears the files currently available -If you have any requirements or dependencies, add a section describing those and how to install and configure them. +Submit -> Submits the query to the api -## Extension Settings +Refresh -> refreshes the window so that all new files will be available for that session. -Include if your extension adds any VS Code settings through the `contributes.configuration` extension point. +User must ctrl+shift+p and click on the `Open GPT Context Window` option and then add files (before or after), then input the question. -For example: +# Examples -This extension contributes the following settings: +We can select two files we want to pass through, however we can uncheck one of them for later debugging and enter our question: -* `myExtension.enable`: Enable/disable this extension. -* `myExtension.thing`: Set to `blah` to do something. +``` +What does this do? +c:\dev\test\gpt-contextfiles-test\program.js: +\``` + window.alert("Hello World!") +\``` -## Known Issues +Selected Files: +[x] c:\dev\test\gpt-contextfiles-test\program.js +[ ] c:\dev\test\gpt-contextfiles-test\program2.js +``` -Calling out known issues can help limit users opening duplicate issues against your extension. +Expected Ouput: -## Release Notes - -Users appreciate release notes as you update your extension. - -### 1.0.0 - -Initial release of ... - -### 1.0.1 - -Fixed issue #. - -### 1.1.0 - -Added features X, Y, and Z. - ---- - -## Working with Markdown - -You can author your README using Visual Studio Code. Here are some useful editor keyboard shortcuts: - -* Split the editor (`Cmd+\` on macOS or `Ctrl+\` on Windows and Linux) -* Toggle preview (`Shift+Cmd+V` on macOS or `Shift+Ctrl+V` on Windows and Linux) -* Press `Ctrl+Space` (Windows, Linux, macOS) to see a list of Markdown snippets - -## For more information - -* [Visual Studio Code's Markdown Support](http://code.visualstudio.com/docs/languages/markdown) -* [Markdown Syntax Reference](https://help.github.com/articles/markdown-basics/) - -**Enjoy!** +``` +The window.alert() method is a built-in JavaScript function that displays an alert box with a specified message and an OK button. In this case, the message is "Hello World!". +``` From 3e2a18d773f67d4065eb7c7fbd7ed0f5fe801598 Mon Sep 17 00:00:00 2001 From: Iheuzio <97270760+Iheuzio@users.noreply.github.com> Date: Wed, 21 Jun 2023 12:54:07 -0400 Subject: [PATCH 09/10] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f14f384..f65cb49 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Submit -> Submits the query to the api Refresh -> refreshes the window so that all new files will be available for that session. -User must ctrl+shift+p and click on the `Open GPT Context Window` option and then add files (before or after), then input the question. +User must ctrl+shift+p and click on the `Open GPT Context Panel` option and then add files (before or after), then input the question. # Examples From 6de20e93e70c7d7d983be2b3c5762989c88fb741 Mon Sep 17 00:00:00 2001 From: Christopher Date: Wed, 21 Jun 2023 13:14:31 -0400 Subject: [PATCH 10/10] fix(formatting): Files now formatted like it was previously when passed through --- extension.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extension.js b/extension.js index a801838..366328b 100644 --- a/extension.js +++ b/extension.js @@ -104,7 +104,8 @@ const openGPTContextPanelCommand = vscode.commands.registerCommand('extension.op const document = vscode.workspace.textDocuments.find(doc => doc.uri.fsPath === file.uri.fsPath); if (document) { const lines = document.getText().split('\n'); - return `${file.uri.fsPath}\n${lines.join('\n')}`; + const formattedLines = lines.map(line => `\t${line}`).join('\n'); + return `${file.uri.fsPath}:\n\`\`\`\n${formattedLines}\n\`\`\``; } return ''; })