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); // 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 = '') { const fileList = selectedFiles .map( file => `