optimize start up for devchat-view
This commit is contained in:
parent
d81c962960
commit
b1af136111
3
.gitignore
vendored
3
.gitignore
vendored
@ -11,6 +11,3 @@ node_modules
|
|||||||
.chat/prompts.db
|
.chat/prompts.db
|
||||||
|
|
||||||
.vscode/settings.json
|
.vscode/settings.json
|
||||||
|
|
||||||
|
|
||||||
workflows/
|
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
|
|
||||||
import * as path from 'path';
|
|
||||||
import { createTempSubdirectory, runCommandStringAndWriteOutput } from '../util/commonUtil';
|
|
||||||
import { logger } from '../util/logger';
|
|
||||||
|
|
||||||
|
|
||||||
export async function handleRefCommand(ref_command: string) {
|
|
||||||
if (ref_command) {
|
|
||||||
const tempDir = await createTempSubdirectory('devchat/context');
|
|
||||||
const diff_file = path.join(tempDir, 'custom.txt');
|
|
||||||
|
|
||||||
logger.channel()?.info(`custom command: ${ref_command}`);
|
|
||||||
const result = await runCommandStringAndWriteOutput(ref_command, diff_file);
|
|
||||||
logger.channel()?.info(` exit code:`, result.exitCode);
|
|
||||||
|
|
||||||
logger.channel()?.debug(` stdout:`, result.stdout);
|
|
||||||
logger.channel()?.debug(` stderr:`, result.stderr);
|
|
||||||
return `[context|${diff_file}]`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
|
||||||
}
|
|
@ -73,14 +73,14 @@ export function checkDevChatDependency(showError: boolean = true): boolean {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.channel()?.info("devchat has installed.")
|
logger.channel()?.info("devchat has installed.");
|
||||||
return true;
|
return true;
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
const error_status = `Failed to check DevChat dependency due to error: ${error}`;
|
const errorStatus = `Failed to check DevChat dependency due to error: ${error}`;
|
||||||
if (devchatStatus !== error_status && showError) {
|
if (devchatStatus !== errorStatus && showError) {
|
||||||
logger.channel()?.warn(error_status);
|
logger.channel()?.warn(errorStatus);
|
||||||
logger.channel()?.show();
|
logger.channel()?.show();
|
||||||
devchatStatus = error_status;
|
devchatStatus = errorStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -60,13 +60,13 @@ async function isProviderHasSetted() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function configUpdateTo_1115() {
|
async function configUpdateTo1115() {
|
||||||
const support_models = [
|
const supportModels = [
|
||||||
"Model.gpt-3-5-1106",
|
"Model.gpt-3-5-1106",
|
||||||
"Model.gpt-4-turbo",
|
"Model.gpt-4-turbo",
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const model of support_models) {
|
for (const model of supportModels) {
|
||||||
const modelConfig1: any = UiUtilWrapper.getConfiguration("devchat", model);
|
const modelConfig1: any = UiUtilWrapper.getConfiguration("devchat", model);
|
||||||
if (Object.keys(modelConfig1).length === 0) {
|
if (Object.keys(modelConfig1).length === 0) {
|
||||||
let modelConfigNew = {};
|
let modelConfigNew = {};
|
||||||
@ -80,7 +80,7 @@ async function configUpdateTo_1115() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function configUpdateTo_0924() {
|
async function configUpdateTo0924() {
|
||||||
if (await isProviderHasSetted()) {
|
if (await isProviderHasSetted()) {
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
@ -122,7 +122,7 @@ async function configUpdateTo_0924() {
|
|||||||
await vscode.workspace.getConfiguration("devchat").update("Provider.devchat", providerConfigNew, vscode.ConfigurationTarget.Global);
|
await vscode.workspace.getConfiguration("devchat").update("Provider.devchat", providerConfigNew, vscode.ConfigurationTarget.Global);
|
||||||
}
|
}
|
||||||
|
|
||||||
const support_models = [
|
const supportModels = [
|
||||||
"Model.gpt-3-5",
|
"Model.gpt-3-5",
|
||||||
"Model.gpt-3-5-1106",
|
"Model.gpt-3-5-1106",
|
||||||
"Model.gpt-3-5-16k",
|
"Model.gpt-3-5-16k",
|
||||||
@ -136,7 +136,7 @@ async function configUpdateTo_0924() {
|
|||||||
"Model.llama-2-70b-chat"
|
"Model.llama-2-70b-chat"
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const model of support_models) {
|
for (const model of supportModels) {
|
||||||
const modelConfig1: any = UiUtilWrapper.getConfiguration("devchat", model);
|
const modelConfig1: any = UiUtilWrapper.getConfiguration("devchat", model);
|
||||||
if (Object.keys(modelConfig1).length === 0) {
|
if (Object.keys(modelConfig1).length === 0) {
|
||||||
modelConfigNew = {"provider": "devchat"};
|
modelConfigNew = {"provider": "devchat"};
|
||||||
@ -154,19 +154,19 @@ async function configUpdateTo_0924() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function configUpdate0912To_0924() {
|
async function configUpdate0912To0924() {
|
||||||
if (await isProviderHasSetted()) {
|
if (await isProviderHasSetted()) {
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
|
|
||||||
const old_models = [
|
const oldModels = [
|
||||||
"Model.gpt-3-5",
|
"Model.gpt-3-5",
|
||||||
"Model.gpt-3-5-16k",
|
"Model.gpt-3-5-16k",
|
||||||
"Model.gpt-4",
|
"Model.gpt-4",
|
||||||
"Model.claude-2"
|
"Model.claude-2"
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const model of old_models) {
|
for (const model of oldModels) {
|
||||||
const modelConfig: any = UiUtilWrapper.getConfiguration("devchat", model);
|
const modelConfig: any = UiUtilWrapper.getConfiguration("devchat", model);
|
||||||
if (Object.keys(modelConfig).length !== 0) {
|
if (Object.keys(modelConfig).length !== 0) {
|
||||||
let modelProperties: any = {};
|
let modelProperties: any = {};
|
||||||
@ -176,7 +176,7 @@ async function configUpdate0912To_0924() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (modelConfig["api_key"]) {
|
if (modelConfig["api_key"]) {
|
||||||
let providerConfigNew = {}
|
let providerConfigNew = {};
|
||||||
providerConfigNew["access_key"] = modelConfig["api_key"];
|
providerConfigNew["access_key"] = modelConfig["api_key"];
|
||||||
if (modelConfig["api_base"]) {
|
if (modelConfig["api_base"]) {
|
||||||
providerConfigNew["api_base"] = modelConfig["api_base"];
|
providerConfigNew["api_base"] = modelConfig["api_base"];
|
||||||
@ -211,9 +211,9 @@ async function activate(context: vscode.ExtensionContext) {
|
|||||||
logger.init(LoggerChannelVscode.getInstance());
|
logger.init(LoggerChannelVscode.getInstance());
|
||||||
UiUtilWrapper.init(new UiUtilVscode());
|
UiUtilWrapper.init(new UiUtilVscode());
|
||||||
|
|
||||||
await configUpdateTo_0924();
|
await configUpdateTo0924();
|
||||||
await configUpdate0912To_0924();
|
await configUpdate0912To0924();
|
||||||
await configUpdateTo_1115();
|
await configUpdateTo1115();
|
||||||
|
|
||||||
regLanguageContext();
|
regLanguageContext();
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ export async function featureToggle(message: any, panel: vscode.WebviewPanel|vsc
|
|||||||
}
|
}
|
||||||
|
|
||||||
regInMessage({command: 'featureToggles'});
|
regInMessage({command: 'featureToggles'});
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
regOutMessage({command: 'featureToggles', features: {'feature name': true}});
|
regOutMessage({command: 'featureToggles', features: {'feature name': true}});
|
||||||
export async function getFeatureToggles(message: any, panel: vscode.WebviewPanel|vscode.WebviewView): Promise<void> {
|
export async function getFeatureToggles(message: any, panel: vscode.WebviewPanel|vscode.WebviewView): Promise<void> {
|
||||||
const featureTaggles = FTs();
|
const featureTaggles = FTs();
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { ChatContextManager } from '../context/contextManager';
|
|
||||||
import { MessageHandler } from './messageHandler';
|
import { MessageHandler } from './messageHandler';
|
||||||
import { regInMessage, regOutMessage } from '../util/reg_messages';
|
import { regInMessage, regOutMessage } from '../util/reg_messages';
|
||||||
import { ApiKeyManager } from '../util/apiKey';
|
import { ApiKeyManager } from '../util/apiKey';
|
||||||
import { UiUtilWrapper } from '../util/uiUtil';
|
|
||||||
|
|
||||||
|
|
||||||
regInMessage({command: 'regModelList'});
|
regInMessage({command: 'regModelList'});
|
||||||
|
@ -6,31 +6,7 @@ import { UiUtilWrapper } from '../util/uiUtil';
|
|||||||
|
|
||||||
|
|
||||||
const functionRegistry: any = {
|
const functionRegistry: any = {
|
||||||
"/hellox": {
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
"keys": [],
|
|
||||||
"handler": async () => {
|
|
||||||
return "111222";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/hellox2": {
|
|
||||||
"keys": ["a", "b"],
|
|
||||||
"handler": async (a: string, b: string) => {
|
|
||||||
return a+b;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/hellox3": {
|
|
||||||
"keys": [],
|
|
||||||
"handler": async () => {
|
|
||||||
return {
|
|
||||||
"name": "v1",
|
|
||||||
"age": 20,
|
|
||||||
"others": {
|
|
||||||
"address": "sh",
|
|
||||||
"phone": "123456789"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/get_lsp_brige_port": {
|
"/get_lsp_brige_port": {
|
||||||
"keys": [],
|
"keys": [],
|
||||||
"handler": async () => {
|
"handler": async () => {
|
||||||
@ -106,6 +82,7 @@ export async function startRpcServer() {
|
|||||||
responseResult['error'] = "Function not found";
|
responseResult['error'] = "Function not found";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||||
res.end(JSON.stringify(responseResult));
|
res.end(JSON.stringify(responseResult));
|
||||||
}
|
}
|
||||||
|
@ -42,15 +42,18 @@ export function createChatDirectoryAndCopyInstructionsSync(extensionUri: vscode.
|
|||||||
const chatWorkflowsDirPath = path.join(workspaceRoot, '.chat', 'workflows');
|
const chatWorkflowsDirPath = path.join(workspaceRoot, '.chat', 'workflows');
|
||||||
const instructionsSrcPath = path.join(extensionUri.fsPath, 'workflows');
|
const instructionsSrcPath = path.join(extensionUri.fsPath, 'workflows');
|
||||||
|
|
||||||
|
// if workflows directory exists, return
|
||||||
|
if (fs.existsSync(chatWorkflowsDirPath)) {
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 检查 .chat 目录是否存在,如果不存在,则创建它
|
|
||||||
if (!fs.existsSync(chatWorkflowsDirPath)) {
|
if (!fs.existsSync(chatWorkflowsDirPath)) {
|
||||||
fs.mkdirSync(chatWorkflowsDirPath, {recursive: true});
|
fs.mkdirSync(chatWorkflowsDirPath, {recursive: true});
|
||||||
} else {
|
} else {
|
||||||
// return;
|
// return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将 workflows 目录复制到 .chat 目录中
|
|
||||||
copyDirSync(instructionsSrcPath, chatWorkflowsDirPath);
|
copyDirSync(instructionsSrcPath, chatWorkflowsDirPath);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.channel()?.error('Error occurred while creating the .chat directory and copying workflows:', error);
|
logger.channel()?.error('Error occurred while creating the .chat directory and copying workflows:', error);
|
||||||
|
@ -1,87 +0,0 @@
|
|||||||
// chatPanel.ts
|
|
||||||
|
|
||||||
import * as vscode from 'vscode';
|
|
||||||
import * as path from 'path';
|
|
||||||
import '../handler/handlerRegister';
|
|
||||||
import handleMessage from '../handler/messageHandler';
|
|
||||||
import WebviewManager from './webviewManager';
|
|
||||||
|
|
||||||
import { createChatDirectoryAndCopyInstructionsSync } from '../init/chatConfig';
|
|
||||||
import { UiUtilWrapper } from '../util/uiUtil';
|
|
||||||
|
|
||||||
export default class ChatPanel {
|
|
||||||
private static _instance: ChatPanel | undefined;
|
|
||||||
private readonly _panel: vscode.WebviewPanel;
|
|
||||||
private _webviewManager: WebviewManager;
|
|
||||||
private _disposables: vscode.Disposable[] = [];
|
|
||||||
|
|
||||||
public static createOrShow(extensionUri: vscode.Uri) {
|
|
||||||
// 创建 .chat 目录并复制 workflows
|
|
||||||
createChatDirectoryAndCopyInstructionsSync(extensionUri);
|
|
||||||
|
|
||||||
const workspaceDir = UiUtilWrapper.workspaceFoldersFirstPath();
|
|
||||||
if (workspaceDir) {
|
|
||||||
const workflowsDir = path.join(workspaceDir!, '.chat', 'workflows');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ChatPanel._instance) {
|
|
||||||
ChatPanel._instance._panel.reveal();
|
|
||||||
} else {
|
|
||||||
const panel = ChatPanel.createWebviewPanel(extensionUri);
|
|
||||||
ChatPanel._instance = new ChatPanel(panel, extensionUri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static currentPanel(): ChatPanel | undefined {
|
|
||||||
return ChatPanel._instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new webview panel
|
|
||||||
private static createWebviewPanel(extensionUri: vscode.Uri): vscode.WebviewPanel {
|
|
||||||
return vscode.window.createWebviewPanel(
|
|
||||||
'chatPanel',
|
|
||||||
'Chat',
|
|
||||||
vscode.ViewColumn.Beside,
|
|
||||||
{
|
|
||||||
enableScripts: true,
|
|
||||||
localResourceRoots: [vscode.Uri.joinPath(extensionUri, 'dist')],
|
|
||||||
retainContextWhenHidden: true
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {
|
|
||||||
this._panel = panel;
|
|
||||||
this._webviewManager = new WebviewManager(panel.webview, extensionUri);
|
|
||||||
this.registerEventListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
public panel(): vscode.WebviewPanel {
|
|
||||||
return this._panel;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register event listeners for the panel and webview
|
|
||||||
private registerEventListeners() {
|
|
||||||
this._panel.onDidDispose(() => this.dispose(), null, this._disposables);
|
|
||||||
|
|
||||||
this._panel.webview.onDidReceiveMessage(
|
|
||||||
async (message) => {
|
|
||||||
handleMessage(message, this._panel);
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
this._disposables
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dispose the panel and clean up resources
|
|
||||||
public dispose() {
|
|
||||||
ChatPanel._instance = undefined;
|
|
||||||
this._panel.dispose();
|
|
||||||
while (this._disposables.length) {
|
|
||||||
const disposable = this._disposables.pop();
|
|
||||||
if (disposable) {
|
|
||||||
disposable.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -81,16 +81,4 @@ export class DevChatViewProvider implements vscode.WebviewViewProvider {
|
|||||||
// this.updateWebviewContent();
|
// this.updateWebviewContent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// public dispose() {
|
|
||||||
// ChatPanel._instance = undefined;
|
|
||||||
// this._panel.dispose();
|
|
||||||
// while (this._disposables.length) {
|
|
||||||
// const disposable = this._disposables.pop();
|
|
||||||
// if (disposable) {
|
|
||||||
// disposable.dispose();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
@ -53,9 +53,8 @@ export function createStatusBarItem(context: vscode.ExtensionContext): vscode.St
|
|||||||
progressBar.update(`Checking dependencies: Success`, 0);
|
progressBar.update(`Checking dependencies: Success`, 0);
|
||||||
progressBar.end();
|
progressBar.end();
|
||||||
|
|
||||||
// execute command: DevChat.InstallCommands
|
// download workflows from github or gitlab
|
||||||
await vscode.commands.executeCommand('DevChat.InstallCommands');
|
await vscode.commands.executeCommand('DevChat.InstallCommands');
|
||||||
ExtensionContextHolder.provider?.reloadWebview();
|
|
||||||
vscode.commands.executeCommand('DevChat.InstallCommandPython');
|
vscode.commands.executeCommand('DevChat.InstallCommandPython');
|
||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -4,9 +4,13 @@ import { logger } from "./logger";
|
|||||||
type Action = {
|
type Action = {
|
||||||
action: "delete" | "insert" | "modify";
|
action: "delete" | "insert" | "modify";
|
||||||
content?: string;
|
content?: string;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
insert_after?: string;
|
insert_after?: string;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
insert_before?: string;
|
insert_before?: string;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
original_content?: string;
|
original_content?: string;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
new_content?: string;
|
new_content?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ const featureTogglesJson = `
|
|||||||
const featureToggles = JSON.parse(featureTogglesJson);
|
const featureToggles = JSON.parse(featureTogglesJson);
|
||||||
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
export function FT(feature: string): boolean {
|
export function FT(feature: string): boolean {
|
||||||
const betaInvitationCode = vscode.workspace.getConfiguration('DevChat').get<string>('betaInvitationCode');
|
const betaInvitationCode = vscode.workspace.getConfiguration('DevChat').get<string>('betaInvitationCode');
|
||||||
const expectedInvitationCode = 'WELCOMEADDTODEVCHAT';
|
const expectedInvitationCode = 'WELCOMEADDTODEVCHAT';
|
||||||
@ -18,6 +19,7 @@ export function FT(feature: string): boolean {
|
|||||||
return betaInvitationCode === expectedInvitationCode || featureToggles[feature] === true;
|
return betaInvitationCode === expectedInvitationCode || featureToggles[feature] === true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
export function FTs(): any {
|
export function FTs(): any {
|
||||||
// visited features
|
// visited features
|
||||||
let newFeatureToggles = {};
|
let newFeatureToggles = {};
|
||||||
|
@ -7,6 +7,7 @@ export interface LogChannel {
|
|||||||
show(): void;
|
show(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
export class logger {
|
export class logger {
|
||||||
private static _channel: LogChannel | undefined;
|
private static _channel: LogChannel | undefined;
|
||||||
public static init(channel: LogChannel): void {
|
public static init(channel: LogChannel): void {
|
||||||
|
@ -40,7 +40,7 @@ export async function createEnvByMamba(pkgName: string, pkgVersion: string, pyth
|
|||||||
|
|
||||||
export async function createEnvByConda(pkgName: string, pkgVersion: string, pythonVersion: string) : Promise<string> {
|
export async function createEnvByConda(pkgName: string, pkgVersion: string, pythonVersion: string) : Promise<string> {
|
||||||
// install conda
|
// install conda
|
||||||
logger.channel()?.info('Install conda ...')
|
logger.channel()?.info('Install conda ...');
|
||||||
const condaCommand = await installConda();
|
const condaCommand = await installConda();
|
||||||
if (!condaCommand) {
|
if (!condaCommand) {
|
||||||
logger.channel()?.error('Install conda failed');
|
logger.channel()?.error('Install conda failed');
|
||||||
@ -86,7 +86,7 @@ export async function appInstall(pkgName: string, pkgVersion: string, pythonVers
|
|||||||
logger.channel()?.info(`Create env success: ${pythonCommand}`);
|
logger.channel()?.info(`Create env success: ${pythonCommand}`);
|
||||||
|
|
||||||
// install devchat in the env
|
// install devchat in the env
|
||||||
logger.channel()?.info('Install python packages ...')
|
logger.channel()?.info('Install python packages ...');
|
||||||
let isInstalled = false;
|
let isInstalled = false;
|
||||||
// try 3 times
|
// try 3 times
|
||||||
for (let i = 0; i < 4; i++) {
|
for (let i = 0; i < 4; i++) {
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "ask_codebase",
|
|
||||||
"description": "Ask question about codebase.",
|
|
||||||
"type": ["question"],
|
|
||||||
"args": [{
|
|
||||||
"name": "question",
|
|
||||||
"description": "selected question",
|
|
||||||
"type": "string",
|
|
||||||
"from": "content.content.question"
|
|
||||||
}],
|
|
||||||
"action": "ask_codebase",
|
|
||||||
"handler": ["${PythonVirtualEnv}", "${CurDir}/handler.py", "${question}"]
|
|
||||||
}
|
|
@ -1,76 +0,0 @@
|
|||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
def get_app_data_dir(app_name):
|
|
||||||
home = os.path.expanduser("~")
|
|
||||||
if os.name == "nt": # For Windows
|
|
||||||
appPath = os.path.join(home, "AppData", "Roaming", app_name)
|
|
||||||
else: # For Unix and Linux
|
|
||||||
appPath = os.path.join(home, ".local", "share", app_name)
|
|
||||||
|
|
||||||
if not os.path.exists(appPath):
|
|
||||||
os.makedirs(appPath)
|
|
||||||
return appPath
|
|
||||||
|
|
||||||
supportedFileTypes = []
|
|
||||||
|
|
||||||
STORAGE_FILE = os.path.join(get_app_data_dir("devchat"), "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)
|
|
@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "finish_task",
|
|
||||||
"description": "Flag task as finished",
|
|
||||||
"type": [
|
|
||||||
"task"
|
|
||||||
],
|
|
||||||
"args": [
|
|
||||||
],
|
|
||||||
"action": "finish_task",
|
|
||||||
"handler": [
|
|
||||||
"echo",
|
|
||||||
"Task finished"
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "get_project_tree",
|
|
||||||
"description": "Get project file list.",
|
|
||||||
"type": ["project"],
|
|
||||||
"action": "get_project_tree",
|
|
||||||
"args": [
|
|
||||||
],
|
|
||||||
"handler": ["python", "${CurDir}/handler.py"]
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
"""
|
|
||||||
get project files by "git ls-files" command
|
|
||||||
如果项目文件数超出100,那么结束执行,退出码为1,并且输出英文:”文件数太多,需要通过ls命令逐层查看各个目录中的文件、目录结构信息“
|
|
||||||
"""
|
|
||||||
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
def get_project_tree():
|
|
||||||
"""
|
|
||||||
Get project files by "git ls-files" command
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
output = subprocess.check_output(["git", "ls-files"]).decode("utf-8").split("\n")
|
|
||||||
if len(output) > 100:
|
|
||||||
sys.stderr.write("Error: Too many files, you need to view the files and directory structure in each directory through the 'ls' command.\n")
|
|
||||||
sys.exit(1)
|
|
||||||
return output
|
|
||||||
except Exception as e:
|
|
||||||
sys.stderr.write(f"Error: {str(e)}\n")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
print(get_project_tree())
|
|
||||||
sys.exit(0)
|
|
@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "load_file",
|
|
||||||
"description": "Load text file content.",
|
|
||||||
"type": ["file"],
|
|
||||||
"action": "load_file",
|
|
||||||
"args": [
|
|
||||||
{
|
|
||||||
"name": "fileName",
|
|
||||||
"description": "Specify the file, which content will be loaded",
|
|
||||||
"type": "string",
|
|
||||||
"from": "content.content.fileName"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "startLine",
|
|
||||||
"description": "Specify the start line of content. It is not required if load the whole file.",
|
|
||||||
"type": "string",
|
|
||||||
"from": "content.content.startLine"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "endLine",
|
|
||||||
"description": "Specify the end line of content. It is not required if load the whole file.",
|
|
||||||
"type": "string",
|
|
||||||
"from": "content.content.endLine"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"handler": ["python", "${CurDir}/handler.py", "${fileName}", "${startLine}", "${endLine}"]
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
"""
|
|
||||||
Load content in file.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
def load_file_content(file_name, start_line=0, end_line=1000):
|
|
||||||
"""
|
|
||||||
Load content in file from start_line to end_line.
|
|
||||||
If start_line and end_line are not provided, load the whole file.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
with open(file_name, 'r') as file:
|
|
||||||
lines = file.readlines()
|
|
||||||
if start_line < 0 or end_line <= start_line:
|
|
||||||
sys.stderr.write("Error: start line must be greater than or equal to 0 and end line must be greater than start line.\n")
|
|
||||||
sys.exit(1)
|
|
||||||
content = "".join(lines[int(start_line):int(end_line)])
|
|
||||||
if len(content.split('\n')) > 500:
|
|
||||||
sys.stderr.write("Error: The content is too large, please set a reasonable reading range.\n")
|
|
||||||
sys.exit(1)
|
|
||||||
return content
|
|
||||||
except Exception as e:
|
|
||||||
sys.stderr.write(f"Error: {str(e)}\n")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
file_name = sys.argv[1]
|
|
||||||
start_line = int(sys.argv[2]) if sys.argv[2] != '${startLine}' else 0
|
|
||||||
end_line = int(sys.argv[3]) if sys.argv[3] != '${endLine}' else 1000
|
|
||||||
|
|
||||||
print(load_file_content(file_name, start_line, end_line))
|
|
||||||
sys.exit(0)
|
|
@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "new_file",
|
|
||||||
"description": "create new file or replace file with new content",
|
|
||||||
"type": [
|
|
||||||
"*"
|
|
||||||
],
|
|
||||||
"args": [
|
|
||||||
{
|
|
||||||
"name": "fileName",
|
|
||||||
"description": "target file name to create",
|
|
||||||
"type": "string",
|
|
||||||
"from": "content.fileName"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "content",
|
|
||||||
"description": "content to write to file",
|
|
||||||
"type": "string",
|
|
||||||
"as": "file",
|
|
||||||
"from": "content.content"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"action": "new_file",
|
|
||||||
"handler": ["python", "${CurDir}/handler.py", "${content}", "${fileName}"]
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
"""
|
|
||||||
Create new file.
|
|
||||||
arg:
|
|
||||||
content: current file name with content
|
|
||||||
fileName: new file name.
|
|
||||||
Rename content to fileName.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
def create_new_file(content_file, new_file):
|
|
||||||
"""
|
|
||||||
Create new file or replace file with new content.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
if os.path.exists(new_file):
|
|
||||||
os.remove(new_file)
|
|
||||||
# Create the parent directories for the new file if they don't exist.
|
|
||||||
os.makedirs(os.path.dirname(new_file), exist_ok=True)
|
|
||||||
|
|
||||||
shutil.move(content_file, new_file)
|
|
||||||
except Exception as e:
|
|
||||||
sys.stderr.write(f"Error: {str(e)}\n")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
content_file = sys.argv[1]
|
|
||||||
new_file = sys.argv[2]
|
|
||||||
create_new_file(content_file, new_file)
|
|
||||||
sys.exit(0)
|
|
@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "run_shell",
|
|
||||||
"description": "run shell script",
|
|
||||||
"type": [
|
|
||||||
"shell-singleline"
|
|
||||||
],
|
|
||||||
"args": [
|
|
||||||
{
|
|
||||||
"name": "script",
|
|
||||||
"description": "shell command to run, for example: [\"ls\", \"/tmp\"]",
|
|
||||||
"type": "string",
|
|
||||||
"from": "content.content"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"action": "run_shell",
|
|
||||||
"handler": [
|
|
||||||
"${script}"
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "run_shell_file",
|
|
||||||
"description": "run shell script file",
|
|
||||||
"type": [
|
|
||||||
"shell"
|
|
||||||
],
|
|
||||||
"args": [
|
|
||||||
{
|
|
||||||
"name": "script_file",
|
|
||||||
"description": "shell script file to run",
|
|
||||||
"type": "string",
|
|
||||||
"as": "file",
|
|
||||||
"from": "content.content"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"action": "run_shell",
|
|
||||||
"handler": [
|
|
||||||
"bash",
|
|
||||||
"${script_file}"
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "search_text",
|
|
||||||
"description": "Search text in all files within project. Search text with match whole word. Text search is an alternative to finding symbol references, mainly for scenarios where symbol references cannot be used, such as searching for references to a specific string.",
|
|
||||||
"type": ["none"],
|
|
||||||
"args": [{
|
|
||||||
"name": "text",
|
|
||||||
"description": "text to search",
|
|
||||||
"type": "string",
|
|
||||||
"from": "content.content.text"
|
|
||||||
}, {
|
|
||||||
"name": "include_files",
|
|
||||||
"description": "search text within setting include files, support multi pattern. The parameter format is based on the corresponding configuration in vscode search.",
|
|
||||||
"type": "string",
|
|
||||||
"from": "content.content.include_files"
|
|
||||||
}, {
|
|
||||||
"name": "exclude_files",
|
|
||||||
"description": "search text not within setting exclude files, support multi pattern. The parameter format is based on the corresponding configuration in vscode search.",
|
|
||||||
"type": "string",
|
|
||||||
"from": "content.content.exclude_files"
|
|
||||||
}],
|
|
||||||
"action": "search_text",
|
|
||||||
"handler": ["python", "${CurDir}/handler.py", "${text}", "${include_files}", "${exclude_files}"]
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
"""
|
|
||||||
Search text in all files within project. Search text with match whole word mode.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
import fnmatch
|
|
||||||
import re
|
|
||||||
|
|
||||||
def search_text(text, include_files=None, exclude_files=None):
|
|
||||||
"""
|
|
||||||
Search text in all files within project. Search text with match whole word mode.
|
|
||||||
"""
|
|
||||||
# Get the current working directory
|
|
||||||
cwd = os.getcwd()
|
|
||||||
|
|
||||||
# Prepare the include and exclude patterns
|
|
||||||
include_patterns = include_files.split(',') if include_files else ['*']
|
|
||||||
exclude_patterns = exclude_files.split(',') if exclude_files else []
|
|
||||||
|
|
||||||
# Initialize a flag to check if the text is found
|
|
||||||
found = 0
|
|
||||||
|
|
||||||
# Walk through the directory
|
|
||||||
search_result = []
|
|
||||||
for dirpath, dirnames, filenames in os.walk(cwd):
|
|
||||||
for filename in filenames:
|
|
||||||
filename = os.path.join(dirpath, filename)
|
|
||||||
relFileName = os.path.relpath(filename, cwd)
|
|
||||||
# Check if the file matches any of the include patterns
|
|
||||||
if any(fnmatch.fnmatch(relFileName, pattern) for pattern in include_patterns):
|
|
||||||
# Check if the file matches any of the exclude patterns
|
|
||||||
if not any(fnmatch.fnmatch(relFileName, pattern) for pattern in exclude_patterns):
|
|
||||||
# Open the file and search for the text
|
|
||||||
try:
|
|
||||||
with open(filename, 'r') as file:
|
|
||||||
for line_no, line in enumerate(file, 1):
|
|
||||||
if re.search(r'\b' + re.escape(text) + r'\b', line):
|
|
||||||
search_result.append(f'Found "{text}" in file {relFileName} on line {line_no-1}: {line.strip()}')
|
|
||||||
found += len(line.strip())
|
|
||||||
if (len(search_result) > 100 or found > 5000):
|
|
||||||
sys.stderr.write("The search text is too long, try to shorten it.\n")
|
|
||||||
sys.exit(1)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Check if the text was found
|
|
||||||
if found == 0:
|
|
||||||
sys.stderr.write("Optimize the search text content, make sure the search text exists in the file.\n")
|
|
||||||
sys.exit(1)
|
|
||||||
# Print the result
|
|
||||||
print('\n'.join(search_result))
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
# Get the arguments from the command line
|
|
||||||
text = sys.argv[1]
|
|
||||||
include_files = sys.argv[2] if sys.argv[2] != '${include_files}' else None
|
|
||||||
exclude_files = sys.argv[3] if sys.argv[3] != '${exclude_files}' else None
|
|
||||||
|
|
||||||
# Call the search_text function
|
|
||||||
search_text(text, include_files, exclude_files)
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "summary",
|
|
||||||
"description": "Get summary of specified file or direcotry in workspace",
|
|
||||||
"type": ["project"],
|
|
||||||
"action": "summary",
|
|
||||||
"args": [
|
|
||||||
{
|
|
||||||
"name": "path",
|
|
||||||
"description": "The relative path of the specified file or folder, for example, /hello.py, represents the hello.py file in the root directory. This arg is required.",
|
|
||||||
"type": "string",
|
|
||||||
"from": "content.content.path"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"handler": ["${PythonVirtualEnv}", "${CurDir}/handler.py", "${path}"]
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
"""
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
from chat.ask_codebase.indexing.loader.file import FileMetadata, FileSource, simple_file_filter
|
|
||||||
from chat.ask_codebase.indexing.module_summary import SummaryWrapper
|
|
||||||
|
|
||||||
def desc(repo_dir: str, repo_cache_path: str, target_path: str):
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
target_path = target_path.replace(repo_dir, '')
|
|
||||||
sw = SummaryWrapper(repo_cache_path, FileSource(
|
|
||||||
path=repo_dir,
|
|
||||||
rel_root=repo_dir,
|
|
||||||
file_filter=simple_file_filter,
|
|
||||||
))
|
|
||||||
return sw.get_desc(target_path)
|
|
||||||
|
|
||||||
|
|
||||||
def summary():
|
|
||||||
"""
|
|
||||||
Get file or directory 's summary
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
repo_dir = os.getcwd()
|
|
||||||
repo_cache_path = os.path.join(repo_dir, '.chat', '.summary.json')
|
|
||||||
|
|
||||||
target_path = sys.argv[1]
|
|
||||||
return desc(repo_dir, repo_cache_path, target_path)
|
|
||||||
except Exception as e:
|
|
||||||
sys.stderr.write(f"Error: {str(e)}\n")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
print(summary())
|
|
||||||
sys.exit(0)
|
|
@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "update_file",
|
|
||||||
"description": "replace selections of file with specified content",
|
|
||||||
"type": ["update"],
|
|
||||||
"args": [{
|
|
||||||
"name": "fileName",
|
|
||||||
"description": "target file name to update",
|
|
||||||
"type": "string",
|
|
||||||
"from": "content.fileName"
|
|
||||||
}, {
|
|
||||||
"name": "old_content",
|
|
||||||
"description": "old content to replaced",
|
|
||||||
"type": "string",
|
|
||||||
"from": "content.content.old"
|
|
||||||
}, {
|
|
||||||
"name": "content",
|
|
||||||
"description": "content to write to file",
|
|
||||||
"type": "string",
|
|
||||||
"from": "content.content.new"
|
|
||||||
}],
|
|
||||||
"action": "update_file",
|
|
||||||
"handler": ["python", "${CurDir}/handler.py", "${fileName}", "${old_content}", "${content}"]
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
import sys
|
|
||||||
|
|
||||||
def replace_text_in_file(fileName: str, old_content: str, newContent: str) -> None:
|
|
||||||
"""
|
|
||||||
Replace text in a file within the specified range with new content.
|
|
||||||
|
|
||||||
:param fileName: The name of the file to modify.
|
|
||||||
:param startPos: The starting position of the range to replace.
|
|
||||||
:param endPos: The ending position of the range to replace.
|
|
||||||
:param newContent: The new content to replace the specified range with.
|
|
||||||
"""
|
|
||||||
with open(fileName, 'r') as file:
|
|
||||||
content = file.read()
|
|
||||||
|
|
||||||
# how many times old_content occurs in content
|
|
||||||
count = content.count(old_content)
|
|
||||||
# if count is not 1, then we can't replace the text
|
|
||||||
if count != 1:
|
|
||||||
# output error message to stderr and exit
|
|
||||||
print(f"Error: {old_content} occurs {count} times in {fileName}.", file=sys.stderr)
|
|
||||||
exit(-1)
|
|
||||||
|
|
||||||
# replace old_content with new_content
|
|
||||||
modified_content = content.replace(old_content, new_content)
|
|
||||||
|
|
||||||
with open(fileName, 'w') as file:
|
|
||||||
file.write(modified_content)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
try:
|
|
||||||
file_name = sys.argv[1]
|
|
||||||
old_content = sys.argv[2]
|
|
||||||
new_content = sys.argv[3]
|
|
||||||
|
|
||||||
replace_text_in_file(file_name, old_content, new_content)
|
|
||||||
except Exception as e:
|
|
||||||
print(e, file=sys.stderr)
|
|
||||||
exit(-1)
|
|
||||||
exit(0)
|
|
Loading…
x
Reference in New Issue
Block a user