重构配置模块以移除ini依赖,增强baseURL支持并汉化AI提示词
This commit is contained in:
@@ -25,7 +25,12 @@ export default command(
|
||||
|
||||
if (mode === 'set') {
|
||||
await setConfigs(
|
||||
keyValues.map((keyValue) => keyValue.split('=') as [string, string])
|
||||
keyValues.map((keyValue) => {
|
||||
const separatorIndex = keyValue.indexOf('=');
|
||||
const key = keyValue.slice(0, separatorIndex);
|
||||
const value = keyValue.slice(separatorIndex + 1);
|
||||
return [key, value] as [string, string];
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import os from 'os';
|
||||
import ini from 'ini';
|
||||
import type { TiktokenModel } from '@dqbd/tiktoken';
|
||||
import { fileExists } from './fs.js';
|
||||
import { KnownError } from './error.js';
|
||||
@@ -117,18 +116,12 @@ const configParsers = {
|
||||
},
|
||||
baseURL(url?: string) {
|
||||
if (!url || url.length === 0) {
|
||||
return 'api.openai.com';
|
||||
return undefined;
|
||||
}
|
||||
|
||||
parseAssert('baseURL', /^https?:\/\/.+/.test(url), 'Must be a valid URL');
|
||||
parseAssert('baseURL', /^https?:\/\//.test(url), 'Must be a valid URL');
|
||||
|
||||
// 如果用户输入完整URL,提取域名部分
|
||||
try {
|
||||
const urlObj = new URL(url);
|
||||
return urlObj.hostname;
|
||||
} catch {
|
||||
return url;
|
||||
}
|
||||
return url;
|
||||
},
|
||||
} as const;
|
||||
|
||||
@@ -151,7 +144,16 @@ const readConfigFile = async (): Promise<RawConfig> => {
|
||||
}
|
||||
|
||||
const configString = await fs.readFile(configPath, 'utf8');
|
||||
return ini.parse(configString);
|
||||
const config = Object.create(null);
|
||||
for (const line of configString.split(/\r?\n/)) {
|
||||
const separatorIndex = line.indexOf('=');
|
||||
if (separatorIndex !== -1) {
|
||||
const key = line.slice(0, separatorIndex);
|
||||
const value = line.slice(separatorIndex + 1);
|
||||
config[key.trim()] = value.trim();
|
||||
}
|
||||
}
|
||||
return config;
|
||||
};
|
||||
|
||||
export const getConfig = async (
|
||||
@@ -189,5 +191,9 @@ export const setConfigs = async (keyValues: [key: string, value: string][]) => {
|
||||
config[key as ConfigKeys] = parsed as any;
|
||||
}
|
||||
|
||||
await fs.writeFile(configPath, ini.stringify(config), 'utf8');
|
||||
const configString = Object.entries(config)
|
||||
.filter(([, value]) => value !== undefined && value !== null)
|
||||
.map(([key, value]) => `${key}=${value}`)
|
||||
.join(os.EOL);
|
||||
await fs.writeFile(configPath, configString, 'utf8');
|
||||
};
|
||||
|
||||
@@ -39,7 +39,7 @@ const httpsPost = async (
|
||||
'Content-Length': Buffer.byteLength(postContent),
|
||||
},
|
||||
timeout,
|
||||
agent: proxy ? createHttpsProxyAgent(proxy) : undefined,
|
||||
agent: (proxy && proxy.trim() !== '') ? createHttpsProxyAgent(proxy) : undefined as any,
|
||||
},
|
||||
(response) => {
|
||||
const body: Buffer[] = [];
|
||||
@@ -74,10 +74,14 @@ const createChatCompletion = async (
|
||||
proxy?: string,
|
||||
baseURL?: string
|
||||
) => {
|
||||
const hostname = baseURL || 'api.openai.com';
|
||||
const url = baseURL ? new URL(baseURL) : new URL('https://api.openai.com/v1/chat/completions');
|
||||
if (url.pathname === '/') {
|
||||
url.pathname = '/v1/chat/completions';
|
||||
}
|
||||
|
||||
const { response, data } = await httpsPost(
|
||||
hostname,
|
||||
'/v1/chat/completions',
|
||||
url.hostname,
|
||||
url.pathname,
|
||||
{
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
},
|
||||
@@ -104,7 +108,19 @@ const createChatCompletion = async (
|
||||
throw new KnownError(errorMessage);
|
||||
}
|
||||
|
||||
return JSON.parse(data) as CreateChatCompletionResponse;
|
||||
try {
|
||||
const json = JSON.parse(data);
|
||||
|
||||
if (json.error) {
|
||||
throw new KnownError(json.error.message);
|
||||
}
|
||||
|
||||
return json as CreateChatCompletionResponse;
|
||||
} catch (error) {
|
||||
throw new KnownError(
|
||||
`Error parsing response: ${error}\n\n${data}`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const sanitizeMessage = (message: string) =>
|
||||
|
||||
@@ -5,7 +5,7 @@ const commitTypeFormats: Record<CommitType, string> = {
|
||||
conventional: '<type>(<optional scope>): <commit message>',
|
||||
};
|
||||
const specifyCommitFormat = (type: CommitType) =>
|
||||
`The output response must be in format:\n${commitTypeFormats[type]}`;
|
||||
`输出响应必须使用以下格式:\n${commitTypeFormats[type]}`;
|
||||
|
||||
const commitTypes: Record<CommitType, string> = {
|
||||
'': '',
|
||||
@@ -18,20 +18,20 @@ const commitTypes: Record<CommitType, string> = {
|
||||
* Conventional Changelog:
|
||||
* https://github.com/conventional-changelog/conventional-changelog/blob/d0e5d5926c8addba74bc962553dd8bcfba90e228/packages/conventional-changelog-conventionalcommits/writer-opts.js#L182-L193
|
||||
*/
|
||||
conventional: `Choose a type from the type-to-description JSON below that best describes the git diff:\n${JSON.stringify(
|
||||
conventional: `从下面的类型到描述的JSON中选择最能描述git差异的类型:\n${JSON.stringify(
|
||||
{
|
||||
docs: 'Documentation only changes',
|
||||
docs: '仅文档更改',
|
||||
style:
|
||||
'Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)',
|
||||
refactor: 'A code change that neither fixes a bug nor adds a feature',
|
||||
perf: 'A code change that improves performance',
|
||||
test: 'Adding missing tests or correcting existing tests',
|
||||
build: 'Changes that affect the build system or external dependencies',
|
||||
ci: 'Changes to our CI configuration files and scripts',
|
||||
chore: "Other changes that don't modify src or test files",
|
||||
revert: 'Reverts a previous commit',
|
||||
feat: 'A new feature',
|
||||
fix: 'A bug fix',
|
||||
'不影响代码含义的更改(空格、格式、缺少分号等)',
|
||||
refactor: '既不修复错误也不添加功能的代码更改',
|
||||
perf: '提高性能的代码更改',
|
||||
test: '添加缺失的测试或更正现有测试',
|
||||
build: '影响构建系统或外部依赖的更改',
|
||||
ci: '对我们的CI配置文件和脚本的更改',
|
||||
chore: '不修改src或测试文件的其他更改',
|
||||
revert: '恢复之前的提交',
|
||||
feat: '新功能',
|
||||
fix: '错误修复',
|
||||
},
|
||||
null,
|
||||
2
|
||||
@@ -44,10 +44,13 @@ export const generatePrompt = (
|
||||
type: CommitType
|
||||
) =>
|
||||
[
|
||||
'Generate a concise git commit message written in present tense for the following code diff with the given specifications below:',
|
||||
`Message language: ${locale}`,
|
||||
`Commit message must be a maximum of ${maxLength} characters.`,
|
||||
'Exclude anything unnecessary such as translation. Your entire response will be passed directly into git commit.',
|
||||
'为以下代码差异生成一个简洁的、使用现在时态的中文git提交消息,并遵循以下规范:',
|
||||
`提交消息使用中文编写。`,
|
||||
`提交消息最多${maxLength}个字符。`,
|
||||
'提交消息包含具体的类名、方法名或其他关键信息,不能过于笼统。',
|
||||
'对于功能添加,应该指明具体的类或模块,如"在UserController中添加了用户权限验证功能"。',
|
||||
'对于代码重构,应该指明重构的具体类或方法,如"重构了PaymentProcessor类的金额计算逻辑"。',
|
||||
'排除任何不必要的内容,如翻译。您的整个响应将直接传递到git提交中。',
|
||||
commitTypes[type],
|
||||
specifyCommitFormat(type),
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user