Use access key set by command while no valid key

This commit is contained in:
bobo.yang 2023-09-13 10:08:16 +08:00
parent 0ff9870cf6
commit a7bb815df5
7 changed files with 145 additions and 80 deletions

View File

@ -365,17 +365,6 @@
"description": "The max number of tokens of a prompt.", "description": "The max number of tokens of a prompt.",
"when": "DevChat.llmModel == 'OpenAI'" "when": "DevChat.llmModel == 'OpenAI'"
}, },
"DevChat.Access_Key_DevChat": {
"type": "string",
"default": "",
"description": "DevChat's secret key for accessing multiple LLM models"
},
"DevChat.Api_Key_OpenAI": {
"type": "string",
"default": "",
"description": "OpenAI's secret key for accessing LLM models. (Leave blank if using DevChat's key.)",
"when": "DevChat.llmModel == 'OpenAI'"
},
"DevChat.API_ENDPOINT": { "DevChat.API_ENDPOINT": {
"type": "string", "type": "string",
"default": "", "default": "",
@ -489,13 +478,73 @@
"title": "Create Entry" "title": "Create Entry"
}, },
{ {
"command": "DevChat.Api_Key_OpenAI", "command": "DevChat.AccessKey.OpenAI",
"title": "Input OpenAI Api Key", "title": "Input Access Key for OpenAI",
"category": "DevChat" "category": "DevChat"
}, },
{ {
"command": "DevChat.Access_Key_DevChat", "command": "DevChat.AccessKey.Cohere",
"title": "Input DevChat Access Key", "title": "Input Access Key for Cohere",
"category": "DevChat"
},
{
"command": "DevChat.AccessKey.Anthropic",
"title": "Input Access Key for Anthropic",
"category": "DevChat"
},
{
"command": "DevChat.AccessKey.Replicate",
"title": "Input Access Key for Replicate",
"category": "DevChat"
},
{
"command": "DevChat.AccessKey.HuggingFace",
"title": "Input Access Key for HuggingFace",
"category": "DevChat"
},
{
"command": "DevChat.AccessKey.TogetherAI",
"title": "Input Access Key for TogetherAI",
"category": "DevChat"
},
{
"command": "DevChat.AccessKey.OpenRouter",
"title": "Input Access Key for OpenRouter",
"category": "DevChat"
},
{
"command": "DevChat.AccessKey.VertexAI",
"title": "Input Access Key for VertexAI",
"category": "DevChat"
},
{
"command": "DevChat.AccessKey.AI21",
"title": "Input Access Key for AI21",
"category": "DevChat"
},
{
"command": "DevChat.AccessKey.BaseTen",
"title": "Input Access Key for BaseTen",
"category": "DevChat"
},
{
"command": "DevChat.AccessKey.Azure",
"title": "Input Access Key for Azure",
"category": "DevChat"
},
{
"command": "DevChat.AccessKey.SageMaker",
"title": "Input Access Key for SageMaker",
"category": "DevChat"
},
{
"command": "DevChat.AccessKey.Bedrock",
"title": "Input Access Key for Bedrock",
"category": "DevChat"
},
{
"command": "DevChat.AccessKey.DevChat",
"title": "Input Access Key for DevChat",
"category": "DevChat" "category": "DevChat"
}, },
{ {

View File

@ -82,42 +82,39 @@ function registerAskForFileCommand(context: vscode.ExtensionContext) {
context.subscriptions.push(vscode.commands.registerCommand('devchat.askForFile_chinese', callback)); context.subscriptions.push(vscode.commands.registerCommand('devchat.askForFile_chinese', callback));
} }
export function registerOpenAiApiKeySettingCommand(context: vscode.ExtensionContext) { function regAccessKeyCommand(context: vscode.ExtensionContext, provider: string) {
const secretStorage: vscode.SecretStorage = context.secrets;
context.subscriptions.push( context.subscriptions.push(
vscode.commands.registerCommand('DevChat.Api_Key_OpenAI', async () => { vscode.commands.registerCommand(`DevChat.AccessKey.${provider}`, async () => {
const passwordInput: string = await vscode.window.showInputBox({ const passwordInput: string = await vscode.window.showInputBox({
password: true, password: true,
title: "Input OpenAi Api Key", title: `Input ${provider} Access Key`,
placeHolder: "Set OpenAI Api Key.(Leave blank if clearing stored key.)" placeHolder: `Set ${provider} Access Key.(Leave blank if clearing stored key.)`
}) ?? ''; }) ?? '';
if (passwordInput.trim() !== "" && !isValidApiKey(passwordInput)) { if (passwordInput.trim() !== "" && !isValidApiKey(passwordInput)) {
UiUtilWrapper.showErrorMessage("Your api key is invalid!"); UiUtilWrapper.showErrorMessage("Your api key is invalid!");
return ; return ;
} }
ApiKeyManager.writeApiKeySecret(passwordInput, "OpenAI"); await ApiKeyManager.writeApiKeySecret(passwordInput, provider);
}) })
); );
} }
export function registerDevChatApiKeySettingCommand(context: vscode.ExtensionContext) { export function registerAccessKeySettingCommand(context: vscode.ExtensionContext) {
const secretStorage: vscode.SecretStorage = context.secrets; regAccessKeyCommand(context, "OpenAI");
context.subscriptions.push( regAccessKeyCommand(context, "Cohere");
vscode.commands.registerCommand('DevChat.Access_Key_DevChat', async () => { regAccessKeyCommand(context, "Anthropic");
const passwordInput: string = await vscode.window.showInputBox({ regAccessKeyCommand(context, "Replicate");
password: true, regAccessKeyCommand(context, "HuggingFace");
title: "Input DevChat Access Key", regAccessKeyCommand(context, "TogetherAI");
placeHolder: "Set DevChat Access Key.(Leave blank if clearing stored key.)" regAccessKeyCommand(context, "OpenRouter");
}) ?? ''; regAccessKeyCommand(context, "VertexAI");
regAccessKeyCommand(context, "AI21");
if (passwordInput.trim() !== "" && !isValidApiKey(passwordInput)) { regAccessKeyCommand(context, "BaseTen");
UiUtilWrapper.showErrorMessage("Your access key is invalid!"); regAccessKeyCommand(context, "Azure");
return ; regAccessKeyCommand(context, "SageMaker");
} regAccessKeyCommand(context, "Bedrock");
ApiKeyManager.writeApiKeySecret(passwordInput, "DevChat"); regAccessKeyCommand(context, "DevChat");
})
);
} }
export function registerStatusBarItemClickCommand(context: vscode.ExtensionContext) { export function registerStatusBarItemClickCommand(context: vscode.ExtensionContext) {
@ -142,7 +139,7 @@ const topicDeleteCallback = async (item: TopicTreeItem) => {
TopicManager.getInstance().deleteTopic(item.id); TopicManager.getInstance().deleteTopic(item.id);
} }
}; };
;
export function regTopicDeleteCommand(context: vscode.ExtensionContext) { export function regTopicDeleteCommand(context: vscode.ExtensionContext) {
context.subscriptions.push( context.subscriptions.push(

View File

@ -5,8 +5,7 @@ import {
registerAddContextCommand, registerAddContextCommand,
registerAskForCodeCommand, registerAskForCodeCommand,
registerAskForFileCommand, registerAskForFileCommand,
registerOpenAiApiKeySettingCommand, registerAccessKeySettingCommand,
registerDevChatApiKeySettingCommand,
regTopicDeleteCommand, regTopicDeleteCommand,
regAddTopicCommand, regAddTopicCommand,
regDeleteSelectTopicCommand, regDeleteSelectTopicCommand,
@ -45,8 +44,7 @@ function activate(context: vscode.ExtensionContext) {
regDevChatView(context); regDevChatView(context);
regTopicView(context); regTopicView(context);
registerOpenAiApiKeySettingCommand(context); registerAccessKeySettingCommand(context);
registerDevChatApiKeySettingCommand(context);
registerOpenChatPanelCommand(context); registerOpenChatPanelCommand(context);
registerAddContextCommand(context); registerAddContextCommand(context);
registerAskForCodeCommand(context); registerAskForCodeCommand(context);

View File

@ -178,15 +178,7 @@ export async function historyMessagesBase(): Promise<LoadHistoryMessages | undef
} }
export async function onApiKeyBase(apiKey: string): Promise<{ command: string, text: string, hash: string, user: string, date: string, isError: boolean }> { export async function onApiKeyBase(apiKey: string): Promise<{ command: string, text: string, hash: string, user: string, date: string, isError: boolean }> {
if (!isValidApiKey(apiKey)) {
return { command: 'receiveMessage', text: 'Your API key is invalid. We support OpenAI and DevChat keys. Please reset the key.', hash: '', user: 'system', date: '', isError: false };
}
isApiSet = true;
ApiKeyManager.writeApiKeySecret(apiKey);
const welcomeMessageText = welcomeMessage().response;
return { return {
command: 'receiveMessage', text: `Your OPENAI_API_KEY is set. Enjoy DevChat!\n${welcomeMessageText}`, hash: '', user: 'system', date: '', isError: false command: 'receiveMessage', text: `You need config access key for specified llmodel in setting view.`, hash: '', user: 'system', date: '', isError: false
}; };
} }

View File

@ -42,7 +42,7 @@ export function createStatusBarItem(context: vscode.ExtensionContext): vscode.St
if (apiKeyStatus !== 'has valid access key') { if (apiKeyStatus !== 'has valid access key') {
statusBarItem.text = `$(warning)DevChat`; statusBarItem.text = `$(warning)DevChat`;
statusBarItem.tooltip = `${apiKeyStatus}`; statusBarItem.tooltip = `${apiKeyStatus}`;
statusBarItem.command = 'DevChat.Access_Key_DevChat'; statusBarItem.command = 'DevChat.AccessKey.DevChat';
progressBar.update(`Checking devchat dependency environment: ${apiKeyStatus}.`, 0); progressBar.update(`Checking devchat dependency environment: ${apiKeyStatus}.`, 0);
return; return;
} }

View File

@ -120,7 +120,7 @@ class DevChat {
args.push("-p", options.parent); args.push("-p", options.parent);
} }
const llmModelData = ApiKeyManager.llmModel(); const llmModelData = await ApiKeyManager.llmModel();
if (llmModelData && llmModelData.model) { if (llmModelData && llmModelData.model) {
args.push("-m", llmModelData.model); args.push("-m", llmModelData.model);
} }
@ -200,7 +200,7 @@ class DevChat {
} }
async chat(content: string, options: ChatOptions = {}, onData: (data: ChatResponse) => void): Promise<ChatResponse> { async chat(content: string, options: ChatOptions = {}, onData: (data: ChatResponse) => void): Promise<ChatResponse> {
const llmModelData = ApiKeyManager.llmModel(); const llmModelData = await ApiKeyManager.llmModel();
if (!llmModelData) { if (!llmModelData) {
return { return {
"prompt-hash": "", "prompt-hash": "",

View File

@ -3,8 +3,26 @@
import { UiUtilWrapper } from './uiUtil'; import { UiUtilWrapper } from './uiUtil';
export class ApiKeyManager { export class ApiKeyManager {
static toProviderKey(provider: string) : string | undefined {
let providerNameMap = {
"openai": "OpenAI",
"cohere": "Cohere",
"anthropic": "Anthropic",
"replicate": "Replicate",
"huggingface": "HuggingFace",
"together_ai": "TogetherAI",
"openrouter": "OpenRouter",
"vertex_ai": "VertexAI",
"ai21": "AI21",
"baseten": "Baseten",
"azure": "Azure",
"sagemaker": "SageMaker",
"bedrock": "Bedrock"
};
return providerNameMap[provider];
}
static async getApiKey(llmType: string = "OpenAI"): Promise<string | undefined> { static async getApiKey(llmType: string = "OpenAI"): Promise<string | undefined> {
const llmModel = this.llmModel(); const llmModel = await this.llmModel();
if (!llmModel) { if (!llmModel) {
return undefined; return undefined;
} }
@ -12,13 +30,13 @@ export class ApiKeyManager {
return llmModel.api_key; return llmModel.api_key;
} }
static llmModel() { static async llmModel() {
const llmModel = UiUtilWrapper.getConfiguration('devchat', 'defaultModel'); const llmModel = UiUtilWrapper.getConfiguration('devchat', 'defaultModel');
if (!llmModel) { if (!llmModel) {
return undefined; return undefined;
} }
const modelProperties = (modelPropertyName: string, modelName: string) => { const modelProperties = async (modelPropertyName: string, modelName: string) => {
const modelConfig = UiUtilWrapper.getConfiguration("devchat", modelPropertyName); const modelConfig = UiUtilWrapper.getConfiguration("devchat", modelPropertyName);
if (!modelConfig) { if (!modelConfig) {
return undefined; return undefined;
@ -29,26 +47,36 @@ export class ApiKeyManager {
const property = modelConfig![key]; const property = modelConfig![key];
modelProperties[key] = property; modelProperties[key] = property;
} }
if (!modelConfig["provider"]) {
if (!modelConfig["provider"] || !modelConfig["api_key"]) {
return undefined; return undefined;
} }
modelProperties['model'] = modelName; if (!modelConfig["api_key"]) {
const providerName = this.toProviderKey(modelConfig["provider"]);
if (!providerName) {
return undefined;
}
const apiKey = await this.loadApiKeySecret(providerName);
if (!apiKey) {
return undefined;
}
modelProperties["api_key"] = apiKey;
}
modelProperties['model'] = modelName;
return modelProperties; return modelProperties;
}; };
if (llmModel === "gpt-3.5-turbo") { if (llmModel === "gpt-3.5-turbo") {
return modelProperties('Model.gpt-3-5', "gpt-3.5-turbo"); return await modelProperties('Model.gpt-3-5', "gpt-3.5-turbo");
} }
if (llmModel === "gpt-3.5-turbo-16k") { if (llmModel === "gpt-3.5-turbo-16k") {
return modelProperties('Model.gpt-3-5-16k', "gpt-3.5-turbo-16k"); return await modelProperties('Model.gpt-3-5-16k', "gpt-3.5-turbo-16k");
} }
if (llmModel === "gpt-4") { if (llmModel === "gpt-4") {
return modelProperties('Model.gpt-4', "gpt-4"); return await modelProperties('Model.gpt-4', "gpt-4");
} }
if (llmModel === "claude-2") { if (llmModel === "claude-2") {
return modelProperties('Model.claude-2', "claude-2"); return await modelProperties('Model.claude-2', "claude-2");
} }
const customModelConfig: any = UiUtilWrapper.getConfiguration('devchat', 'customModel'); const customModelConfig: any = UiUtilWrapper.getConfiguration('devchat', 'customModel');
@ -68,13 +96,21 @@ export class ApiKeyManager {
modelProperties[key] = property; modelProperties[key] = property;
} }
if (!model["api_key"]) {
return undefined;
}
const modelProvider = model["model"].split('/')[0]; const modelProvider = model["model"].split('/')[0];
const modelName = model["model"].split('/').slice(1).join('/'); const modelName = model["model"].split('/').slice(1).join('/');
if (!model["api_key"]) {
const providerName = this.toProviderKey(modelProvider);
if (!providerName) {
return undefined;
}
const apiKey = await this.loadApiKeySecret(providerName);
if (!apiKey) {
return undefined;
}
modelProperties["api_key"] = apiKey;
}
modelProperties["provider"] = modelProvider; modelProperties["provider"] = modelProvider;
modelProperties["model"] = modelName; modelProperties["model"] = modelName;
@ -96,17 +132,10 @@ export class ApiKeyManager {
} }
static async writeApiKeySecret(apiKey: string, llmType: string = "Unknow"): Promise<void> { static async writeApiKeySecret(apiKey: string, llmType: string = "Unknow"): Promise<void> {
if (apiKey.startsWith("sk-")) { await UiUtilWrapper.storeSecret(`Access_KEY_${llmType}`, apiKey);
await UiUtilWrapper.storeSecret("openai_OPENAI_API_KEY", apiKey); }
} else if (apiKey.startsWith("DC.")) { static async loadApiKeySecret(llmType: string = "Unknow"): Promise<string | undefined> {
await UiUtilWrapper.storeSecret("devchat_OPENAI_API_KEY", apiKey); return await UiUtilWrapper.secretStorageGet(`Access_KEY_${llmType}`);
} else {
if (llmType === "OpenAI") {
await UiUtilWrapper.storeSecret("openai_OPENAI_API_KEY", apiKey);
} else if (llmType === "DevChat") {
await UiUtilWrapper.storeSecret("devchat_OPENAI_API_KEY", apiKey);
}
}
} }
static getEndPoint(apiKey: string | undefined): string | undefined { static getEndPoint(apiKey: string | undefined): string | undefined {