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