From b837365427641108ccf30fbad6b40a40ed79fcbf Mon Sep 17 00:00:00 2001 From: "bobo.yang" Date: Mon, 21 Aug 2023 11:52:00 +0800 Subject: [PATCH] Add PythonVirtualEnv configuration and improve error handling - Added PythonVirtualEnv configuration to customAction.ts. - Improved error handling in doCommand.ts by using logger instead of console.error. - Updated sendMessage.ts to handle askCode command and improved error handling. - Added environment variables for OPENAI_API_KEY and OPENAI_API_BASE in commonUtil.ts. - Created new action 'query_data' in _setting_.json and its handler in handler.py. --- src/action/customAction.ts | 6 ++ src/handler/doCommand.ts | 8 +-- src/handler/sendMessage.ts | 26 ++++++-- src/util/commonUtil.ts | 41 +++++++++++- .../action/query_data/_setting_.json | 13 ++++ .../auto_command/action/query_data/handler.py | 63 +++++++++++++++++++ 6 files changed, 146 insertions(+), 11 deletions(-) create mode 100644 workflows/auto_command/action/query_data/_setting_.json create mode 100644 workflows/auto_command/action/query_data/handler.py diff --git a/src/action/customAction.ts b/src/action/customAction.ts index a7f9938..0d94fd5 100644 --- a/src/action/customAction.ts +++ b/src/action/customAction.ts @@ -83,6 +83,12 @@ export class CustomActions { const tempDir = await createTempSubdirectory('devchat/action'); const tempFile = path.join(tempDir, 'apply.json'); + if (UiUtilWrapper.getConfiguration('DevChat', 'PythonVirtualEnv')) { + args['PythonVirtualEnv'] = UiUtilWrapper.getConfiguration('DevChat', 'PythonVirtualEnv')!; + } else { + args['PythonVirtualEnv'] = 'python'; + } + const contextMap = { 'codeBlock': args, 'workspaceDir': UiUtilWrapper.workspaceFoldersFirstPath(), diff --git a/src/handler/doCommand.ts b/src/handler/doCommand.ts index cf2fd31..2264bab 100644 --- a/src/handler/doCommand.ts +++ b/src/handler/doCommand.ts @@ -3,9 +3,8 @@ execute vscode command */ import * as vscode from 'vscode'; -import DtmWrapper from '../toolwrapper/dtm'; import { regInMessage, regOutMessage } from '../util/reg_messages'; -import { runCommandAndWriteOutput } from '../util/commonUtil'; +import { logger } from '../util/logger'; regInMessage({command: 'doCommand', content: ['command', 'arg1', 'arg2']}); export async function doCommand(message: any, panel: vscode.WebviewPanel|vscode.WebviewView): Promise { @@ -15,7 +14,8 @@ export async function doCommand(message: any, panel: vscode.WebviewPanel|vscode. try { await vscode.commands.executeCommand(message.content[0], ...message.content.slice(1)); } catch (error) { - console.error(`Failed to execute command ${message.content[0]}: ${error}`); - } + logger.channel()?.error(`Failed to execute command ${message.content[0]}: ${error}`); + logger.channel()?.show(); + } return; } \ No newline at end of file diff --git a/src/handler/sendMessage.ts b/src/handler/sendMessage.ts index 320fbc4..7c0b126 100644 --- a/src/handler/sendMessage.ts +++ b/src/handler/sendMessage.ts @@ -35,12 +35,24 @@ export function deleteTempFiles(fileName: string): void { regInMessage({command: 'askCode', text: '', parent_hash: undefined}); regOutMessage({ command: 'receiveMessage', text: 'xxxx', hash: 'xxx', user: 'xxx', date: 'xxx'}); export async function askCode(message: any, panel: vscode.WebviewPanel|vscode.WebviewView): Promise { - _lastMessage = message; + _lastMessage = [message]; + _lastMessage[0]['askCode'] = true; - const pythonVirtualEnv: string|undefined = vscode.workspace.getConfiguration('DevChat').get('PythonVirtualEnv'); + let pythonVirtualEnv: string|undefined = vscode.workspace.getConfiguration('DevChat').get('PythonVirtualEnv'); if (!pythonVirtualEnv) { - MessageHandler.sendMessage(panel, { "command": "systemMessage", "text": "请先设置DevChat.PythonVirtualEnv" }); - return ; + try { + await vscode.commands.executeCommand('DevChat.AskCodeIndexStart'); + } catch (error) { + logger.channel()?.error(`Failed to execute command ${message.content[0]}: ${error}`); + logger.channel()?.show(); + return; + } + + pythonVirtualEnv = vscode.workspace.getConfiguration('DevChat').get('PythonVirtualEnv'); + if (!pythonVirtualEnv) { + MessageHandler.sendMessage(panel, { command: 'receiveMessage', text: "Index code fail.", hash: "", user: "", date: 0, isError: true }); + return ; + } } let envs = {}; @@ -157,7 +169,11 @@ regInMessage({command: 'regeneration'}); export async function regeneration(message: any, panel: vscode.WebviewPanel|vscode.WebviewView): Promise { // call sendMessage to send last message again if (_lastMessage) { - sendMessage(_lastMessage[0], panel, _lastMessage[1]); + if (_lastMessage[0]['askCode']) { + await askCode(_lastMessage[0], panel); + } else { + await sendMessage(_lastMessage[0], panel, _lastMessage[1]); + } } } diff --git a/src/util/commonUtil.ts b/src/util/commonUtil.ts index 1b4512e..ed1e857 100644 --- a/src/util/commonUtil.ts +++ b/src/util/commonUtil.ts @@ -8,6 +8,7 @@ import { parseArgsStringToArgv } from 'string-argv'; import { logger } from './logger'; import { spawn, exec } from 'child_process'; import { UiUtilWrapper } from './uiUtil'; +import { ApiKeyManager } from './apiKey'; export function createTempSubdirectory(subdir: string): string { // 获取系统临时目录 @@ -113,9 +114,21 @@ export async function runCommandAndWriteOutput( args: string[], outputFile: string | undefined ): Promise { + let envs = {} + let openaiApiKey = await ApiKeyManager.getApiKey(); + if (openaiApiKey) { + envs['OPENAI_API_KEY'] = openaiApiKey; + } + + const openAiApiBase = ApiKeyManager.getEndPoint(openaiApiKey); + if (openAiApiBase) { + envs['OPENAI_API_BASE'] = openAiApiBase; + } + const run = new CommandRun(); const options = { cwd: UiUtilWrapper.workspaceFoldersFirstPath() || '.', + env: envs }; return run.spawnAsync(command, args, options, undefined, undefined, undefined, outputFile); @@ -125,9 +138,21 @@ export async function runCommandStringAndWriteOutput( commandString: string, outputFile: string | undefined ): Promise { + let envs = {} + let openaiApiKey = await ApiKeyManager.getApiKey(); + if (openaiApiKey) { + envs['OPENAI_API_KEY'] = openaiApiKey; + } + + const openAiApiBase = ApiKeyManager.getEndPoint(openaiApiKey); + if (openAiApiBase) { + envs['OPENAI_API_BASE'] = openAiApiBase; + } + const run = new CommandRun(); const options = { - cwd: UiUtilWrapper.workspaceFoldersFirstPath() || '.' + cwd: UiUtilWrapper.workspaceFoldersFirstPath() || '.', + env: envs }; // Split the commandString into command and args array using string-argv @@ -150,9 +175,21 @@ export async function runCommandStringArrayAndWriteOutput( commandStringList: string[], outputFile: string ): Promise { + let envs = {}; + let openaiApiKey = await ApiKeyManager.getApiKey(); + if (openaiApiKey) { + envs['OPENAI_API_KEY'] = openaiApiKey; + } + + const openAiApiBase = ApiKeyManager.getEndPoint(openaiApiKey); + if (openAiApiBase) { + envs['OPENAI_API_BASE'] = openAiApiBase; + } + const run = new CommandRun(); const options = { - cwd: UiUtilWrapper.workspaceFoldersFirstPath() || '.' + cwd: UiUtilWrapper.workspaceFoldersFirstPath() || '.', + env: envs }; const commandString = commandStringList[0]; diff --git a/workflows/auto_command/action/query_data/_setting_.json b/workflows/auto_command/action/query_data/_setting_.json new file mode 100644 index 0000000..cae6524 --- /dev/null +++ b/workflows/auto_command/action/query_data/_setting_.json @@ -0,0 +1,13 @@ +{ + "name": "query_data", + "description": "Search for content information related to the problem from the vector database", + "type": ["question"], + "args": [{ + "name": "question", + "description": "selected question", + "type": "string", + "from": "content.content.question" + }], + "action": "query_data", + "handler": ["${PythonVirtualEnv}", "${CurDir}/handler.py", "${question}"] +} \ No newline at end of file diff --git a/workflows/auto_command/action/query_data/handler.py b/workflows/auto_command/action/query_data/handler.py new file mode 100644 index 0000000..a54563b --- /dev/null +++ b/workflows/auto_command/action/query_data/handler.py @@ -0,0 +1,63 @@ +import os +import re +import sys +import json +import tempfile +import uuid + +from chat.ask_codebase.store.qdrant import QdrantWrapper as Q, get_client +from chat.ask_codebase.indexing.embedding import EmbeddingWrapper as E + +from langchain.embeddings import HuggingFaceEmbeddings +from chat.ask_codebase.indexing.loader.file import ( + FileLoader, + FileSource, + gen_local_reference_maker, +) +from chat.util.misc import is_source_code +from chat.ask_codebase.chains.simple_qa import SimpleQA +from chat.ask_codebase.chains.stuff_dc_qa import StuffDocumentCodeQa + + +STORAGE_FILE = os.path.join(tempfile.gettempdir(), "qdrant_storage2") +SOURCE_NAME = "" + + +def query(question: str): + try: + client = get_client(mode=STORAGE_FILE) + q = Q.reuse( + source_name=SOURCE_NAME, + embedding_cls=HuggingFaceEmbeddings, + client=client, + ) + + chain = StuffDocumentCodeQa(q) + + _, docs = chain.run(question) + + for d in docs: + print(d.metadata.get('filepath')) + print(d.page_content) + + sys.exit(0) + except Exception as e: + print(e) + sys.exit(1) + + +if __name__ == "__main__": + try: + if os.path.exists(".chat/askcode.json"): + with open(".chat/askcode.json", "r") as f: + askcode_data = json.load(f) + SOURCE_NAME = askcode_data.get("SOURCE_NAME", str(uuid.uuid4())) + else: + SOURCE_NAME = str(uuid.uuid4()) + with open(".chat/askcode.json", "w+") as f: + json.dump({"SOURCE_NAME": SOURCE_NAME}, f) + query(sys.argv[1]) + sys.exit(0) + except Exception as e: + print(e) + sys.exit(1) \ No newline at end of file