Skip to content

Commit d708190

Browse files
♻️ refactor(commands): 重构命令处理逻辑并优化错误处理
- 【基础】在 BaseCommand 中添加统一的错误处理方法 handleError - 【重构】将模型选择器逻辑抽取到独立的 ModelPickerService 服务 - 【优化】重构 GenerateCommitCommand 中的配置处理逻辑,提取至独立方法 - 【改进】简化 SelectModelCommand 中的模型选择器实现 - 【错误处理】统一使用本地化的错误消息展示
1 parent fa072f1 commit d708190

File tree

3 files changed

+46
-147
lines changed

3 files changed

+46
-147
lines changed

src/commands/BaseCommand.ts

+10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as vscode from "vscode";
22
import { NotificationHandler } from "../utils/NotificationHandler";
33
import { ConfigurationManager } from "../config/ConfigurationManager";
4+
import { LocalizationManager } from '../utils/LocalizationManager'
45

56
export abstract class BaseCommand {
67
constructor(protected readonly context: vscode.ExtensionContext) {}
@@ -13,5 +14,14 @@ export abstract class BaseCommand {
1314
return true;
1415
}
1516

17+
protected async handleError(error: unknown, errorMessage: string): Promise<void> {
18+
console.error(errorMessage, error);
19+
if (error instanceof Error) {
20+
await NotificationHandler.error(
21+
LocalizationManager.getInstance().format(errorMessage, error.message)
22+
);
23+
}
24+
}
25+
1626
abstract execute(...args: any[]): Promise<void>;
1727
}

src/commands/GenerateCommitCommand.ts

+34-85
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { getProviderModelConfig } from "../config/types";
99
import { DISPLAY_NAME } from "../constants";
1010
import { getMaxCharacters } from "../ai/types";
1111
import { LocalizationManager } from "../utils/LocalizationManager";
12+
import { ModelPickerService } from "../services/ModelPickerService";
1213

1314
export class GenerateCommitCommand extends BaseCommand {
1415
private async showConfigWizard(): Promise<boolean> {
@@ -135,12 +136,38 @@ export class GenerateCommitCommand extends BaseCommand {
135136
return { provider: modelSelection.provider, model: modelSelection.model };
136137
}
137138

138-
async execute(resources: vscode.SourceControlResourceState[]): Promise<void> {
139-
const locManager = LocalizationManager.getInstance();
139+
private async handleConfiguration(): Promise<
140+
{ provider: string; model: string } | undefined
141+
> {
140142
if (!(await this.ensureConfiguration()) || !(await this.validateConfig())) {
141143
return;
142144
}
143145

146+
const config = ConfigurationManager.getInstance();
147+
const configuration = config.getConfiguration();
148+
let { provider, model } = configuration;
149+
150+
if (!provider || !model) {
151+
const result = await this.selectAndUpdateModelConfiguration(
152+
provider,
153+
model
154+
);
155+
if (!result) {
156+
return;
157+
}
158+
return result;
159+
}
160+
161+
return { provider, model };
162+
}
163+
164+
async execute(resources: vscode.SourceControlResourceState[]): Promise<void> {
165+
const configResult = await this.handleConfiguration();
166+
if (!configResult) {
167+
return;
168+
}
169+
170+
const locManager = LocalizationManager.getInstance();
144171
try {
145172
// 检测当前 SCM 类型
146173
const scmProvider = await SCMFactory.detectSCM();
@@ -160,24 +187,6 @@ export class GenerateCommitCommand extends BaseCommand {
160187

161188
// 如果没有配置提供商或模型,提示用户选择
162189
if (!provider || !model) {
163-
// const modelSelection = await this.showModelPicker(
164-
// provider || "Ollama",
165-
// model || "Ollama"
166-
// );
167-
168-
// if (!modelSelection) {
169-
// return;
170-
// }
171-
172-
// // 使用新的封装方法更新配置
173-
// await config.updateAIConfiguration(
174-
// modelSelection.provider,
175-
// modelSelection.model
176-
// );
177-
178-
// provider = modelSelection.provider;
179-
// model = modelSelection.model;
180-
181190
const { provider: newProvider, model: newModel } =
182191
await this.selectAndUpdateModelConfiguration(provider, model);
183192

@@ -244,12 +253,13 @@ export class GenerateCommitCommand extends BaseCommand {
244253
}
245254
if (response?.content) {
246255
try {
247-
// 统一使用 setCommitInput 写入提交信息
248256
await scmProvider.setCommitInput(response.content);
249257
await NotificationHandler.info(
250258
locManager.format(
251259
"commit.message.generated",
252-
scmProvider.type.toUpperCase()
260+
scmProvider.type.toUpperCase(),
261+
provider,
262+
model
253263
)
254264
);
255265
} catch (error) {
@@ -312,68 +322,7 @@ export class GenerateCommitCommand extends BaseCommand {
312322
];
313323
}
314324

315-
private async showModelPicker(
316-
currentProvider: string,
317-
currentModel: string
318-
): Promise<{ provider: string; model: string } | undefined> {
319-
const locManager = LocalizationManager.getInstance();
320-
try {
321-
const providers = AIProviderFactory.getAllProviders();
322-
const modelsMap = new Map<string, string[]>();
323-
324-
await Promise.all(
325-
providers.map(async (provider) => {
326-
if (await provider.isAvailable()) {
327-
const models = await provider.getModels();
328-
modelsMap.set(
329-
provider.getName(),
330-
models.map((model) => model.name)
331-
);
332-
}
333-
})
334-
);
335-
336-
const items: vscode.QuickPickItem[] = [];
337-
for (const [provider, models] of modelsMap) {
338-
items.push({
339-
label: provider,
340-
kind: vscode.QuickPickItemKind.Separator,
341-
});
342-
models.forEach((model) => {
343-
items.push({
344-
label: model,
345-
description: provider,
346-
picked: provider === currentProvider && model === currentModel,
347-
});
348-
});
349-
}
350-
351-
const quickPick = vscode.window.createQuickPick();
352-
quickPick.items = items;
353-
quickPick.title = locManager.getMessage("ai.model.picker.title");
354-
quickPick.placeholder = locManager.getMessage(
355-
"ai.model.picker.placeholder"
356-
);
357-
quickPick.ignoreFocusOut = true;
358-
359-
const result = await new Promise<vscode.QuickPickItem | undefined>(
360-
(resolve) => {
361-
quickPick.onDidAccept(() => resolve(quickPick.selectedItems[0]));
362-
quickPick.onDidHide(() => resolve(undefined));
363-
quickPick.show();
364-
}
365-
);
366-
367-
quickPick.dispose();
368-
369-
if (result && result.description) {
370-
return { provider: result.description, model: result.label };
371-
}
372-
return undefined;
373-
} catch (error) {
374-
console.error("获取模型列表失败:", error);
375-
await NotificationHandler.error("获取模型列表失败");
376-
return undefined;
377-
}
325+
private async showModelPicker(currentProvider: string, currentModel: string) {
326+
return ModelPickerService.showModelPicker(currentProvider, currentModel);
378327
}
379328
}

src/commands/SelectModelCommand.ts

+2-62
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { NotificationHandler } from "../utils/NotificationHandler";
55
import { AIProviderFactory } from "../ai/AIProviderFactory";
66
import { getProviderModelConfig } from "../config/types";
77
import { LocalizationManager } from "../utils/LocalizationManager";
8+
import { ModelPickerService } from "../services/ModelPickerService";
89

910
export class SelectModelCommand extends BaseCommand {
1011
async execute(): Promise<void> {
@@ -30,68 +31,7 @@ export class SelectModelCommand extends BaseCommand {
3031
}
3132
}
3233

33-
// 从原来的 CommandManager 移动过来的 showModelPicker 方法
3434
private async showModelPicker(currentProvider: string, currentModel: string) {
35-
try {
36-
const providers = AIProviderFactory.getAllProviders();
37-
const modelsMap = new Map<string, string[]>();
38-
39-
await Promise.all(
40-
providers.map(async (provider) => {
41-
if (await provider.isAvailable()) {
42-
const models = await provider.getModels();
43-
modelsMap.set(
44-
provider.getName(),
45-
models.map((model) => model.name)
46-
);
47-
}
48-
})
49-
);
50-
51-
const items: vscode.QuickPickItem[] = [];
52-
for (const [provider, models] of modelsMap) {
53-
items.push({
54-
label: provider,
55-
kind: vscode.QuickPickItemKind.Separator,
56-
});
57-
models.forEach((model) => {
58-
items.push({
59-
label: model,
60-
description: provider,
61-
picked: provider === currentProvider && model === currentModel,
62-
});
63-
});
64-
}
65-
66-
const quickPick = vscode.window.createQuickPick();
67-
quickPick.items = items;
68-
quickPick.title =
69-
LocalizationManager.getInstance().getMessage("model.picker.title");
70-
quickPick.placeholder = LocalizationManager.getInstance().getMessage(
71-
"model.picker.placeholder"
72-
);
73-
quickPick.ignoreFocusOut = true;
74-
75-
const result = await new Promise<vscode.QuickPickItem | undefined>(
76-
(resolve) => {
77-
quickPick.onDidAccept(() => resolve(quickPick.selectedItems[0]));
78-
quickPick.onDidHide(() => resolve(undefined));
79-
quickPick.show();
80-
}
81-
);
82-
83-
quickPick.dispose();
84-
85-
console.log('result:', result);
86-
87-
if (result && result.description) {
88-
return { provider: result.description, model: result.label };
89-
}
90-
return undefined;
91-
} catch (error) {
92-
console.error("获取模型列表失败:", error);
93-
await NotificationHandler.error("model.list.failed");
94-
return undefined;
95-
}
35+
return ModelPickerService.showModelPicker(currentProvider, currentModel);
9636
}
9737
}

0 commit comments

Comments
 (0)