Skip to content

Commit 968e9aa

Browse files
♻️ refactor: reorganize AI provider and SCM integration
- Consolidates AI provider configuration into a single streamlined interface - Improves SCM integration with better Git and SVN support - Adds proper provider model selection and management - Updates configuration keys for better clarity and consistency - Implements proper provider reinitialization on config changes - Enhances error handling and progress reporting Part of the AI commit message generation improvement initiative
1 parent 870326e commit 968e9aa

29 files changed

+821
-763
lines changed

.vscode/launch.json

+14-15
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,18 @@
33
// Hover to view descriptions of existing attributes.
44
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
55
{
6-
"version": "0.2.0",
7-
"configurations": [
8-
{
9-
"name": "Run Extension",
10-
"type": "extensionHost",
11-
"request": "launch",
12-
"args": [
13-
"--extensionDevelopmentPath=${workspaceFolder}"
14-
],
15-
"outFiles": [
16-
"${workspaceFolder}/out/**/*.js"
17-
],
18-
"preLaunchTask": "${defaultBuildTask}"
19-
}
20-
]
6+
"version": "0.2.0",
7+
"configurations": [
8+
{
9+
"name": "Run Extension",
10+
"type": "extensionHost",
11+
"request": "launch",
12+
"args": [
13+
// "--disable-extensions",
14+
"--extensionDevelopmentPath=${workspaceFolder}"
15+
],
16+
"outFiles": ["${workspaceFolder}/out/**/*.js"],
17+
"preLaunchTask": "${defaultBuildTask}"
18+
}
19+
]
2120
}

README.md

+9-11
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
{
2525
"dish-ai-commit.OPENAI_API_KEY": "你的 OpenAI API 密钥",
2626
"dish-ai-commit.OLLAMA_BASE_URL": "Ollama 服务地址",
27-
"dish-ai-commit.defaultProvider": "选择默认 AI 提供商 (openai/ollama)",
27+
"dish-ai-commit.provider": "选择默认 AI 提供商 (openai/ollama)",
2828
"dish-ai-commit.language": "生成的提交信息语言"
2929
}
3030
```
@@ -51,30 +51,28 @@
5151
### 功能特性(补充)
5252

5353
- [ ] **🔄 多语言支持**
54-
支持生成提交信息的多语言版本,用户可以选择使用不同的语言(如中文、英文、法语等)生成提交信息。
54+
支持生成提交信息的多语言版本,用户可以选择使用不同的语言(如中文、英文、法语等)生成提交信息。
5555

5656
- [ ] **🧠 深度分析和建议**
57-
提供更智能的提交信息建议,不仅仅是基于 SVN 变更,还可以根据项目上下文提供改进意见(例如:建议更改某些功能名称,或者指出可能的代码风格改进)。
57+
提供更智能的提交信息建议,不仅仅是基于 SVN 变更,还可以根据项目上下文提供改进意见(例如:建议更改某些功能名称,或者指出可能的代码风格改进)。
5858

5959
- [ ] **🔄 自动同步 AI 模型**
60-
当新模型可用时,自动更新模型列表,无需用户手动刷新。
60+
当新模型可用时,自动更新模型列表,无需用户手动刷新。
6161

6262
- [ ] **📈 统计与报告**
63-
提供提交统计功能,如提交频率、类型分析、提交信息的质量评分等,帮助开发者更好地了解自己的提交习惯。
63+
提供提交统计功能,如提交频率、类型分析、提交信息的质量评分等,帮助开发者更好地了解自己的提交习惯。
6464

6565
- [ ] **🎨 自定义提交模板**
66-
允许用户自定义提交信息的模板格式(如:包括关联的 Jira 票号、功能描述等),AI 会根据模板生成符合要求的提交信息。
66+
允许用户自定义提交信息的模板格式(如:包括关联的 Jira 票号、功能描述等),AI 会根据模板生成符合要求的提交信息。
6767

6868
- [ ] **⚙️ 深度配置选项**
69-
提供更多的配置项,比如是否启用 AI 生成的建议,生成提交信息的详细程度,是否自动修改现有提交信息等。
69+
提供更多的配置项,比如是否启用 AI 生成的建议,生成提交信息的详细程度,是否自动修改现有提交信息等。
7070

7171
- [ ] **🧩 支持 Git-SVN 混合工作流**
72-
对于需要同时使用 Git 和 SVN 的项目,提供混合工作流支持,让用户在 Git 和 SVN 之间无缝切换。
72+
对于需要同时使用 Git 和 SVN 的项目,提供混合工作流支持,让用户在 Git 和 SVN 之间无缝切换。
7373

7474
- [ ] **🔒 安全性功能**
75-
加密存储 API 密钥,确保敏感信息不被泄露,并提供额外的身份验证机制来提高安全性。
76-
77-
75+
加密存储 API 密钥,确保敏感信息不被泄露,并提供额外的身份验证机制来提高安全性。
7876

7977
## 📄 许可证
8078

package.json

+31-20
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"name": "dish-ai-commit",
3-
"displayName": "Dish Commit Gen",
3+
"displayName": "Dish AI Commit Gen",
44
"description": "",
5-
"version": "0.0.3",
5+
"version": "0.0.4",
66
"engines": {
77
"vscode": "^1.95.0"
88
},
@@ -16,8 +16,12 @@
1616
"keywords": [
1717
"OpenAI",
1818
"ChatGPT",
19+
"Ollama",
20+
"Vscode",
1921
"GitEmoji",
22+
"SvnEmoji",
2023
"Git Commit",
24+
"Svn Commit",
2125
"Conventional Commits",
2226
"Commitizen",
2327
"Commit Message",
@@ -40,11 +44,17 @@
4044
"commands": [
4145
{
4246
"command": "extension.dish-ai-commit",
43-
"title": "Dish AI Commit"
47+
"title": "Dish AI Commit",
48+
"category": "SVN",
49+
"icon": "/images/icon.svg"
4450
},
4551
{
46-
"command": "dish-ai-commit.showAvailableModels",
47-
"title": "Show Available AI Models"
52+
"command": "dish-ai-commit.selectModel",
53+
"title": "Select AI Model for Commit Generation",
54+
"category": "[Dish AI Commit]",
55+
"icon": "/images/icon.svg",
56+
"description": "选择用于生成提交信息的AI模型(OpenAI/Ollama/VS Code Provided)",
57+
"when": "(config.svn.enabled && svnOpenRepositoryCount > 0) || (config.git.enabled && gitOpenRepositoryCount > 0)"
4858
}
4959
],
5060
"configuration": {
@@ -102,7 +112,7 @@
102112
"default": "",
103113
"description": "Custom system prompt for generating commit messages"
104114
},
105-
"dish-ai-commit.defaultProvider": {
115+
"dish-ai-commit.provider": {
106116
"type": "string",
107117
"enum": [
108118
"OpenAI",
@@ -112,6 +122,11 @@
112122
"default": "OpenAI",
113123
"description": "默认的 AI 提供商"
114124
},
125+
"dish-ai-commit.model": {
126+
"type": "string",
127+
"default": "gpt-3.5-turbo",
128+
"description": "AI模型选择"
129+
},
115130
"dish-ai-commit.openai.apiKey": {
116131
"type": "string",
117132
"description": "OpenAI API 密钥"
@@ -121,48 +136,44 @@
121136
"default": "https://api.openai.com/v1",
122137
"description": "OpenAI API 基础 URL"
123138
},
124-
"dish-ai-commit.openai.model": {
125-
"type": "string",
126-
"default": "gpt-3.5-turbo",
127-
"description": "OpenAI 模型"
128-
},
129139
"dish-ai-commit.ollama.baseUrl": {
130140
"type": "string",
131141
"default": "http://localhost:11434",
132142
"description": "Ollama API 基础 URL"
133-
},
134-
"dish-ai-commit.ollama.model": {
135-
"type": "string",
136-
"default": "llama2",
137-
"description": "Ollama 模型"
138143
}
139144
}
140145
},
141146
"menus": {
142147
"scm/title": [
143148
{
144149
"command": "extension.dish-ai-commit",
150+
"when": "scmProvider =~ /(git|svn)/",
145151
"group": "navigation"
146152
}
147153
],
148154
"scm/resourceState/context": [
149155
{
150156
"command": "extension.dish-ai-commit",
151-
"when": "scmProvider == svn",
157+
"when": "((config.svn.enabled && scmProvider == svn) || (config.git.enabled && scmProvider == git)) && scmResourceGroup != unversioned && scmResourceGroup != external && scmResourceGroup != conflicts && scmResourceGroup != remotechanges",
152158
"group": "1_modification"
153159
}
154160
],
155161
"scm/resourceFolder/context": [
156162
{
157163
"command": "extension.dish-ai-commit",
158-
"when": "scmProvider == svn",
164+
"when": "scmProvider =~ /(git|svn)/",
159165
"group": "inline"
160166
}
161167
],
162168
"commandPalette": [
163169
{
164-
"command": "svn.commit",
165-
"when": "config.svn.enabled && svnOpenRepositoryCount != 0"
170+
"command": "extension.dish-ai-commit",
171+
"when": "(config.svn.enabled && svnOpenRepositoryCount > 0) || (config.git.enabled && gitOpenRepositoryCount > 0)"
172+
},
173+
{
174+
"command": "dish-ai-commit.selectModel",
175+
"group": "navigation",
176+
"when": "(config.svn.enabled && svnOpenRepositoryCount > 0) || (config.git.enabled && gitOpenRepositoryCount > 0)"
166177
}
167178
]
168179
}

src/ai/AIProviderFactory.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@ export class AIProviderFactory {
1212
// 如果未指定类型,使用默认提供商
1313
const providerType =
1414
type ||
15-
ConfigurationManager.getInstance().getConfig<string>(
16-
"DEFAULT_PROVIDER"
17-
) ||
15+
ConfigurationManager.getInstance().getConfig<string>("PROVIDER") ||
1816
AIProvider.OPENAI;
1917

2018
let provider = this.providers.get(providerType);
@@ -43,4 +41,11 @@ export class AIProviderFactory {
4341
// 返回所有可用的 AI Provider 实例
4442
return [new OpenAIProvider(), new OllamaProvider(), new VSCodeProvider()];
4543
}
44+
45+
public static reinitializeProvider(providerId: string): void {
46+
const provider = this.providers.get(providerId);
47+
if (provider && "reinitialize" in provider) {
48+
(provider as any).reinitialize();
49+
}
50+
}
4651
}

src/ai/interfaces/IAIProvider.ts

-7
This file was deleted.

src/ai/providers/OllamaProvider.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export class OllamaProvider implements AIProvider {
4141
const { language } = params;
4242
const model =
4343
params.model ||
44-
ConfigurationManager.getInstance().getConfig<string>("OLLAMA_MODEL");
44+
ConfigurationManager.getInstance().getConfig<string>("MODEL");
4545

4646
const response = await this.ollama.chat({
4747
model,

src/ai/providers/OpenAIProvider.ts

+32-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
import OpenAI from "openai";
2-
import { createOpenAIApi, getOpenAIConfig } from "../../api/openai";
32
import { ChatCompletionMessageParam } from "openai/resources";
43
import { ConfigurationManager } from "../../config/ConfigurationManager";
5-
import { ConfigKeys } from "../../config/types";
64
import { AIProvider, AIRequestParams, AIResponse } from "../types";
75
import { NotificationHandler } from "../../utils/NotificationHandler";
86
import { generateCommitMessageSystemPrompt } from "../../prompt/prompt";
97
import { DEFAULT_CONFIG } from "../../config/default";
108

11-
// : OpenAIModel[]
129
const provider = { id: "openai", name: "OpenAI" } as const;
1310
const models = [
1411
{
@@ -171,7 +168,37 @@ export class OpenAIProvider implements AIProvider {
171168
private openai: OpenAI;
172169

173170
constructor() {
174-
this.openai = createOpenAIApi();
171+
this.openai = new OpenAI(this.getOpenAIConfig());
172+
}
173+
174+
private getOpenAIConfig() {
175+
const configManager = ConfigurationManager.getInstance();
176+
const apiKey = configManager.getConfig<string>("OPENAI_API_KEY", false);
177+
const baseURL = configManager.getConfig<string>("OPENAI_BASE_URL", false);
178+
const apiVersion = configManager.getConfig<string>("MODEL", false);
179+
180+
const config: {
181+
apiKey: string;
182+
baseURL?: string;
183+
defaultQuery?: { "api-version": string };
184+
defaultHeaders?: { "api-key": string };
185+
} = {
186+
apiKey,
187+
};
188+
189+
if (baseURL) {
190+
config.baseURL = baseURL;
191+
if (apiVersion) {
192+
config.defaultQuery = { "api-version": apiVersion };
193+
config.defaultHeaders = { "api-key": apiKey };
194+
}
195+
}
196+
197+
return config;
198+
}
199+
200+
public reinitialize(): void {
201+
this.openai = new OpenAI(this.getOpenAIConfig());
175202
}
176203

177204
async generateResponse(params: AIRequestParams): Promise<AIResponse> {
@@ -212,7 +239,7 @@ export class OpenAIProvider implements AIProvider {
212239

213240
async isAvailable(): Promise<boolean> {
214241
try {
215-
const config = getOpenAIConfig();
242+
const config = this.getOpenAIConfig();
216243
return !!config.apiKey;
217244
} catch {
218245
return false;

src/ai/providers/VscodeProvider.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export class VSCodeProvider implements AIProvider {
5555
async getModels(): Promise<string[]> {
5656
const models = await vscode.lm.selectChatModels();
5757
// name: `${capitalize(model.vendor)} ${model.name}`,
58-
return models.map((model) => `${model.vendor}:${model.family}`);
58+
return models.map((model) => `${model.family}`);
5959
}
6060

6161
async isAvailable(): Promise<boolean> {

src/ai/types.ts

+2-30
Original file line numberDiff line numberDiff line change
@@ -32,24 +32,6 @@ export interface AIProvider {
3232
getId(): string;
3333
}
3434

35-
export type AnthropicModels =
36-
| "claude-3-5-sonnet-latest"
37-
| "claude-3-5-sonnet-20241022"
38-
| "claude-3-5-sonnet-20240620"
39-
| "claude-3-5-haiku-20241022"
40-
| "claude-3-5-haiku-latest"
41-
| "claude-3-opus-latest"
42-
| "claude-3-opus-20240229"
43-
| "claude-3-sonnet-20240229"
44-
| "claude-3-haiku-20240307"
45-
| "claude-2.1";
46-
47-
export type GeminiModels =
48-
| "gemini-1.5-pro-latest"
49-
| "gemini-1.5-flash-latest"
50-
| "gemini-1.5-flash-8b"
51-
| "gemini-1.0-pro";
52-
5335
export type GitHubModels =
5436
| "gpt-4o"
5537
| "gpt-4o-mini"
@@ -60,13 +42,6 @@ export type GitHubModels =
6042
| "AI21-Jamba-1.5-Large"
6143
| "AI21-Jamba-1.5-Mini";
6244

63-
export type HuggingFaceModels =
64-
| "meta-llama/Llama-3.2-11B-Vision-Instruct"
65-
| "Qwen/Qwen2.5-72B-Instruct"
66-
| "NousResearch/Hermes-3-Llama-3.1-8B"
67-
| "mistralai/Mistral-Nemo-Instruct-2407"
68-
| "microsoft/Phi-3.5-mini-instruct";
69-
7045
export type OpenAIModels =
7146
| "o1-preview"
7247
| "o1-preview-2024-09-12"
@@ -96,18 +71,15 @@ export type VSCodeAIModels = `${string}:${string}`;
9671

9772
export type AIProviders = "anthropic" | "github" | "openai" | "vscode";
9873
export type AIModels<Provider extends AIProviders = AIProviders> =
99-
Provider extends "anthropic"
100-
? AnthropicModels
101-
: Provider extends "github"
74+
Provider extends "github"
10275
? GitHubModels
10376
: Provider extends "openai"
10477
? OpenAIModels
10578
: Provider extends "vscode"
10679
? VSCodeAIModels
107-
: AnthropicModels | OpenAIModels;
80+
: OpenAIModels;
10881

10982
export type SupportedAIModels =
110-
| `anthropic:${AIModels<"anthropic">}`
11183
| `github:${AIModels<"github">}`
11284
| `openai:${AIModels<"openai">}`
11385
| "vscode";

0 commit comments

Comments
 (0)