Skip to content

Commit

Permalink
♻️ refactor: reorganize AI provider and SCM integration
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
littleCareless committed Dec 6, 2024
1 parent 870326e commit 968e9aa
Show file tree
Hide file tree
Showing 29 changed files with 821 additions and 763 deletions.
29 changes: 14 additions & 15 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,18 @@
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
{
"version": "0.2.0",
"configurations": [
{
"name": "Run Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/out/**/*.js"
],
"preLaunchTask": "${defaultBuildTask}"
}
]
"version": "0.2.0",
"configurations": [
{
"name": "Run Extension",
"type": "extensionHost",
"request": "launch",
"args": [
// "--disable-extensions",
"--extensionDevelopmentPath=${workspaceFolder}"
],
"outFiles": ["${workspaceFolder}/out/**/*.js"],
"preLaunchTask": "${defaultBuildTask}"
}
]
}
20 changes: 9 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
{
"dish-ai-commit.OPENAI_API_KEY": "你的 OpenAI API 密钥",
"dish-ai-commit.OLLAMA_BASE_URL": "Ollama 服务地址",
"dish-ai-commit.defaultProvider": "选择默认 AI 提供商 (openai/ollama)",
"dish-ai-commit.provider": "选择默认 AI 提供商 (openai/ollama)",
"dish-ai-commit.language": "生成的提交信息语言"
}
```
Expand All @@ -51,30 +51,28 @@
### 功能特性(补充)

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

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

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

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

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

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

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

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


加密存储 API 密钥,确保敏感信息不被泄露,并提供额外的身份验证机制来提高安全性。

## 📄 许可证

Expand Down
51 changes: 31 additions & 20 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"name": "dish-ai-commit",
"displayName": "Dish Commit Gen",
"displayName": "Dish AI Commit Gen",
"description": "",
"version": "0.0.3",
"version": "0.0.4",
"engines": {
"vscode": "^1.95.0"
},
Expand All @@ -16,8 +16,12 @@
"keywords": [
"OpenAI",
"ChatGPT",
"Ollama",
"Vscode",
"GitEmoji",
"SvnEmoji",
"Git Commit",
"Svn Commit",
"Conventional Commits",
"Commitizen",
"Commit Message",
Expand All @@ -40,11 +44,17 @@
"commands": [
{
"command": "extension.dish-ai-commit",
"title": "Dish AI Commit"
"title": "Dish AI Commit",
"category": "SVN",
"icon": "/images/icon.svg"
},
{
"command": "dish-ai-commit.showAvailableModels",
"title": "Show Available AI Models"
"command": "dish-ai-commit.selectModel",
"title": "Select AI Model for Commit Generation",
"category": "[Dish AI Commit]",
"icon": "/images/icon.svg",
"description": "选择用于生成提交信息的AI模型(OpenAI/Ollama/VS Code Provided)",
"when": "(config.svn.enabled && svnOpenRepositoryCount > 0) || (config.git.enabled && gitOpenRepositoryCount > 0)"
}
],
"configuration": {
Expand Down Expand Up @@ -102,7 +112,7 @@
"default": "",
"description": "Custom system prompt for generating commit messages"
},
"dish-ai-commit.defaultProvider": {
"dish-ai-commit.provider": {
"type": "string",
"enum": [
"OpenAI",
Expand All @@ -112,6 +122,11 @@
"default": "OpenAI",
"description": "默认的 AI 提供商"
},
"dish-ai-commit.model": {
"type": "string",
"default": "gpt-3.5-turbo",
"description": "AI模型选择"
},
"dish-ai-commit.openai.apiKey": {
"type": "string",
"description": "OpenAI API 密钥"
Expand All @@ -121,48 +136,44 @@
"default": "https://api.openai.com/v1",
"description": "OpenAI API 基础 URL"
},
"dish-ai-commit.openai.model": {
"type": "string",
"default": "gpt-3.5-turbo",
"description": "OpenAI 模型"
},
"dish-ai-commit.ollama.baseUrl": {
"type": "string",
"default": "http://localhost:11434",
"description": "Ollama API 基础 URL"
},
"dish-ai-commit.ollama.model": {
"type": "string",
"default": "llama2",
"description": "Ollama 模型"
}
}
},
"menus": {
"scm/title": [
{
"command": "extension.dish-ai-commit",
"when": "scmProvider =~ /(git|svn)/",
"group": "navigation"
}
],
"scm/resourceState/context": [
{
"command": "extension.dish-ai-commit",
"when": "scmProvider == svn",
"when": "((config.svn.enabled && scmProvider == svn) || (config.git.enabled && scmProvider == git)) && scmResourceGroup != unversioned && scmResourceGroup != external && scmResourceGroup != conflicts && scmResourceGroup != remotechanges",
"group": "1_modification"
}
],
"scm/resourceFolder/context": [
{
"command": "extension.dish-ai-commit",
"when": "scmProvider == svn",
"when": "scmProvider =~ /(git|svn)/",
"group": "inline"
}
],
"commandPalette": [
{
"command": "svn.commit",
"when": "config.svn.enabled && svnOpenRepositoryCount != 0"
"command": "extension.dish-ai-commit",
"when": "(config.svn.enabled && svnOpenRepositoryCount > 0) || (config.git.enabled && gitOpenRepositoryCount > 0)"
},
{
"command": "dish-ai-commit.selectModel",
"group": "navigation",
"when": "(config.svn.enabled && svnOpenRepositoryCount > 0) || (config.git.enabled && gitOpenRepositoryCount > 0)"
}
]
}
Expand Down
11 changes: 8 additions & 3 deletions src/ai/AIProviderFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ export class AIProviderFactory {
// 如果未指定类型,使用默认提供商
const providerType =
type ||
ConfigurationManager.getInstance().getConfig<string>(
"DEFAULT_PROVIDER"
) ||
ConfigurationManager.getInstance().getConfig<string>("PROVIDER") ||
AIProvider.OPENAI;

let provider = this.providers.get(providerType);
Expand Down Expand Up @@ -43,4 +41,11 @@ export class AIProviderFactory {
// 返回所有可用的 AI Provider 实例
return [new OpenAIProvider(), new OllamaProvider(), new VSCodeProvider()];
}

public static reinitializeProvider(providerId: string): void {
const provider = this.providers.get(providerId);
if (provider && "reinitialize" in provider) {
(provider as any).reinitialize();
}
}
}
7 changes: 0 additions & 7 deletions src/ai/interfaces/IAIProvider.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/ai/providers/OllamaProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export class OllamaProvider implements AIProvider {
const { language } = params;
const model =
params.model ||
ConfigurationManager.getInstance().getConfig<string>("OLLAMA_MODEL");
ConfigurationManager.getInstance().getConfig<string>("MODEL");

const response = await this.ollama.chat({
model,
Expand Down
37 changes: 32 additions & 5 deletions src/ai/providers/OpenAIProvider.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import OpenAI from "openai";
import { createOpenAIApi, getOpenAIConfig } from "../../api/openai";
import { ChatCompletionMessageParam } from "openai/resources";
import { ConfigurationManager } from "../../config/ConfigurationManager";
import { ConfigKeys } from "../../config/types";
import { AIProvider, AIRequestParams, AIResponse } from "../types";
import { NotificationHandler } from "../../utils/NotificationHandler";
import { generateCommitMessageSystemPrompt } from "../../prompt/prompt";
import { DEFAULT_CONFIG } from "../../config/default";

// : OpenAIModel[]
const provider = { id: "openai", name: "OpenAI" } as const;
const models = [
{
Expand Down Expand Up @@ -171,7 +168,37 @@ export class OpenAIProvider implements AIProvider {
private openai: OpenAI;

constructor() {
this.openai = createOpenAIApi();
this.openai = new OpenAI(this.getOpenAIConfig());
}

private getOpenAIConfig() {
const configManager = ConfigurationManager.getInstance();
const apiKey = configManager.getConfig<string>("OPENAI_API_KEY", false);
const baseURL = configManager.getConfig<string>("OPENAI_BASE_URL", false);
const apiVersion = configManager.getConfig<string>("MODEL", false);

const config: {
apiKey: string;
baseURL?: string;
defaultQuery?: { "api-version": string };
defaultHeaders?: { "api-key": string };
} = {
apiKey,
};

if (baseURL) {
config.baseURL = baseURL;
if (apiVersion) {
config.defaultQuery = { "api-version": apiVersion };
config.defaultHeaders = { "api-key": apiKey };
}
}

return config;
}

public reinitialize(): void {
this.openai = new OpenAI(this.getOpenAIConfig());
}

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

async isAvailable(): Promise<boolean> {
try {
const config = getOpenAIConfig();
const config = this.getOpenAIConfig();
return !!config.apiKey;
} catch {
return false;
Expand Down
2 changes: 1 addition & 1 deletion src/ai/providers/VscodeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export class VSCodeProvider implements AIProvider {
async getModels(): Promise<string[]> {
const models = await vscode.lm.selectChatModels();
// name: `${capitalize(model.vendor)} ${model.name}`,
return models.map((model) => `${model.vendor}:${model.family}`);
return models.map((model) => `${model.family}`);
}

async isAvailable(): Promise<boolean> {
Expand Down
32 changes: 2 additions & 30 deletions src/ai/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,24 +32,6 @@ export interface AIProvider {
getId(): string;
}

export type AnthropicModels =
| "claude-3-5-sonnet-latest"
| "claude-3-5-sonnet-20241022"
| "claude-3-5-sonnet-20240620"
| "claude-3-5-haiku-20241022"
| "claude-3-5-haiku-latest"
| "claude-3-opus-latest"
| "claude-3-opus-20240229"
| "claude-3-sonnet-20240229"
| "claude-3-haiku-20240307"
| "claude-2.1";

export type GeminiModels =
| "gemini-1.5-pro-latest"
| "gemini-1.5-flash-latest"
| "gemini-1.5-flash-8b"
| "gemini-1.0-pro";

export type GitHubModels =
| "gpt-4o"
| "gpt-4o-mini"
Expand All @@ -60,13 +42,6 @@ export type GitHubModels =
| "AI21-Jamba-1.5-Large"
| "AI21-Jamba-1.5-Mini";

export type HuggingFaceModels =
| "meta-llama/Llama-3.2-11B-Vision-Instruct"
| "Qwen/Qwen2.5-72B-Instruct"
| "NousResearch/Hermes-3-Llama-3.1-8B"
| "mistralai/Mistral-Nemo-Instruct-2407"
| "microsoft/Phi-3.5-mini-instruct";

export type OpenAIModels =
| "o1-preview"
| "o1-preview-2024-09-12"
Expand Down Expand Up @@ -96,18 +71,15 @@ export type VSCodeAIModels = `${string}:${string}`;

export type AIProviders = "anthropic" | "github" | "openai" | "vscode";
export type AIModels<Provider extends AIProviders = AIProviders> =
Provider extends "anthropic"
? AnthropicModels
: Provider extends "github"
Provider extends "github"
? GitHubModels
: Provider extends "openai"
? OpenAIModels
: Provider extends "vscode"
? VSCodeAIModels
: AnthropicModels | OpenAIModels;
: OpenAIModels;

export type SupportedAIModels =
| `anthropic:${AIModels<"anthropic">}`
| `github:${AIModels<"github">}`
| `openai:${AIModels<"openai">}`
| "vscode";
Loading

0 comments on commit 968e9aa

Please sign in to comment.