feat: max-length config (#194)
Co-authored-by: Hiroki Osame <hiroki.osame@gmail.com>
This commit is contained in:
@@ -37,9 +37,8 @@ export default async (
|
||||
throw new KnownError('No staged changes found. Stage your changes manually, or automatically stage all changes with the `--all` flag.');
|
||||
}
|
||||
|
||||
detectingFiles.stop(`${getDetectedMessage(staged.files)}:\n${
|
||||
staged.files.map(file => ` ${file}`).join('\n')
|
||||
}`);
|
||||
detectingFiles.stop(`${getDetectedMessage(staged.files)}:\n${staged.files.map(file => ` ${file}`).join('\n')
|
||||
}`);
|
||||
|
||||
const { env } = process;
|
||||
const config = await getConfig({
|
||||
@@ -58,6 +57,7 @@ export default async (
|
||||
config.locale,
|
||||
staged.diff,
|
||||
config.generate,
|
||||
config['max-length'],
|
||||
config.timeout,
|
||||
config.proxy,
|
||||
);
|
||||
|
||||
@@ -45,6 +45,7 @@ export default () => (async () => {
|
||||
config.locale,
|
||||
staged!.diff,
|
||||
config.generate,
|
||||
config['max-length'],
|
||||
config.timeout,
|
||||
config.proxy,
|
||||
);
|
||||
|
||||
@@ -36,7 +36,6 @@ const configParsers = {
|
||||
|
||||
parseAssert('locale', locale, 'Cannot be empty');
|
||||
parseAssert('locale', /^[a-z-]+$/i.test(locale), 'Must be a valid locale (letters and dashes/underscores). You can consult the list of codes in: https://wikipedia.org/wiki/List_of_ISO_639-1_codes');
|
||||
|
||||
return locale;
|
||||
},
|
||||
generate(count?: string) {
|
||||
@@ -78,6 +77,18 @@ const configParsers = {
|
||||
const parsed = Number(timeout);
|
||||
parseAssert('timeout', parsed >= 500, 'Must be greater than 500ms');
|
||||
|
||||
return parsed;
|
||||
},
|
||||
'max-length'(maxLength?: string) {
|
||||
if (!maxLength) {
|
||||
return 50;
|
||||
}
|
||||
|
||||
parseAssert('max-length', /^\d+$/.test(maxLength), 'Must be an integer');
|
||||
|
||||
const parsed = Number(maxLength);
|
||||
parseAssert('max-length', parsed >= 20, 'Must be greater than 20 characters');
|
||||
|
||||
return parsed;
|
||||
},
|
||||
} as const;
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import https from 'https';
|
||||
import type { ClientRequest, IncomingMessage } from 'http';
|
||||
import type { CreateChatCompletionRequest, CreateChatCompletionResponse } from 'openai';
|
||||
import { type TiktokenModel } from '@dqbd/tiktoken';
|
||||
import {
|
||||
TiktokenModel,
|
||||
// eslint-disable-next-line camelcase
|
||||
encoding_for_model,
|
||||
} from '@dqbd/tiktoken';
|
||||
import createHttpsProxyAgent from 'https-proxy-agent';
|
||||
import { KnownError } from './error.js';
|
||||
|
||||
@@ -100,7 +104,24 @@ const sanitizeMessage = (message: string) => message.trim().replace(/[\n\r]/g, '
|
||||
|
||||
const deduplicateMessages = (array: string[]) => Array.from(new Set(array));
|
||||
|
||||
const getPrompt = (locale: string, diff: string) => `Write a git commit message in present tense for the following diff without prefacing it with anything. Do not be needlessly verbose and make sure the answer is concise and to the point. The response must be in the language ${locale}:\n${diff}`;
|
||||
const getPrompt = (locale: string, diff: string, length: number) => `Write a git commit message in present tense for the following diff without prefacing it with anything. Do not be needlessly verbose and make sure the answer is concise and to the point. The response must be no longer than ${length} characters. The response must be in the language ${locale}:\n${diff}`;
|
||||
|
||||
const generateStringFromLength = (length: number) => {
|
||||
let result = '';
|
||||
const highestTokenChar = 'z';
|
||||
for (let i = 0; i < length; i += 1) {
|
||||
result += highestTokenChar;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
const getTokens = (prompt: string, model: TiktokenModel) => {
|
||||
const encoder = encoding_for_model(model);
|
||||
const tokens = encoder.encode(prompt).length;
|
||||
// Free the encoder to avoid possible memory leaks.
|
||||
encoder.free();
|
||||
return tokens;
|
||||
};
|
||||
|
||||
export const generateCommitMessage = async (
|
||||
apiKey: string,
|
||||
@@ -108,10 +129,17 @@ export const generateCommitMessage = async (
|
||||
locale: string,
|
||||
diff: string,
|
||||
completions: number,
|
||||
length: number,
|
||||
timeout: number,
|
||||
proxy?: string,
|
||||
) => {
|
||||
const prompt = getPrompt(locale, diff);
|
||||
const prompt = getPrompt(locale, diff, length);
|
||||
|
||||
// Padded by 5 for more room for the completion.
|
||||
const stringFromLength = generateStringFromLength(length + 5);
|
||||
|
||||
// The token limit is shared between the prompt and the completion.
|
||||
const maxTokens = getTokens(stringFromLength + prompt, model);
|
||||
|
||||
try {
|
||||
const completion = await createChatCompletion(
|
||||
@@ -126,7 +154,7 @@ export const generateCommitMessage = async (
|
||||
top_p: 1,
|
||||
frequency_penalty: 0,
|
||||
presence_penalty: 0,
|
||||
max_tokens: 200,
|
||||
max_tokens: maxTokens,
|
||||
stream: false,
|
||||
n: completions,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user