From dda7f8d424d39fe87f2500811e24440146749f19 Mon Sep 17 00:00:00 2001 From: Hiroki Osame Date: Wed, 3 May 2023 23:10:15 +0900 Subject: [PATCH] refactor: organize prompt generation to its own file --- src/utils/openai.ts | 79 +++++++-------------------------------------- src/utils/prompt.ts | 48 +++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 67 deletions(-) create mode 100644 src/utils/prompt.ts diff --git a/src/utils/openai.ts b/src/utils/openai.ts index ac34bcc5..9dd31514 100644 --- a/src/utils/openai.ts +++ b/src/utils/openai.ts @@ -1,6 +1,6 @@ import https from 'https'; import type { ClientRequest, IncomingMessage } from 'http'; -import type { ChatCompletionRequestMessage, CreateChatCompletionRequest, CreateChatCompletionResponse } from 'openai'; +import type { CreateChatCompletionRequest, CreateChatCompletionResponse } from 'openai'; import { type TiktokenModel, // encoding_for_model, @@ -8,6 +8,7 @@ import { import createHttpsProxyAgent from 'https-proxy-agent'; import { KnownError } from './error.js'; import type { CommitType } from './config.js'; +import { generatePrompt } from './prompt.js'; const httpsPost = async ( hostname: string, @@ -104,52 +105,6 @@ const sanitizeMessage = (message: string) => message.trim().replace(/[\n\r]/g, ' const deduplicateMessages = (array: string[]) => Array.from(new Set(array)); -const getBasePrompt = ( - locale: string, - maxLength: number, -) => `${[ - '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.', -].join('\n')}`; - -const getCommitMessageFormatOutputExample = (type: CommitType) => `The output response must be in format:\n${getCommitMessageFormat(type)}`; - -const getCommitMessageFormat = (type: CommitType) => { - if (type === 'conventional') { - return '(): '; - } - - return ''; -}; - -/** - * References: - * Commitlint: - * https://github.com/conventional-changelog/commitlint/blob/18fbed7ea86ac0ec9d5449b4979b762ec4305a92/%40commitlint/config-conventional/index.js#L40-L100 - * - * Conventional Changelog: - * https://github.com/conventional-changelog/conventional-changelog/blob/d0e5d5926c8addba74bc962553dd8bcfba90e228/packages/conventional-changelog-conventionalcommits/writer-opts.js#L182-L193 - */ -const getExtraContextForConventionalCommits = () => ( - `Choose a type from the type-to-description JSON below that best describes the git diff:\n${ - JSON.stringify({ - docs: 'Documentation only changes', - 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', - }, null, 2) - }` -); - // const generateStringFromLength = (length: number) => { // let result = ''; // const highestTokenChar = 'z'; @@ -178,31 +133,21 @@ export const generateCommitMessage = async ( timeout: number, proxy?: string, ) => { - const prompt = getBasePrompt(locale, maxLength); - - const conventionalCommitsExtraContext = type === 'conventional' - ? getExtraContextForConventionalCommits() - : ''; - - const commitMessageFormatOutputExample = getCommitMessageFormatOutputExample(type); - - const messages: ChatCompletionRequestMessage[] = [ - { - role: 'system', - content: `${prompt}\n${conventionalCommitsExtraContext}\n${commitMessageFormatOutputExample}`, - }, - { - role: 'user', - content: diff, - }, - ]; - try { const completion = await createChatCompletion( apiKey, { model, - messages, + messages: [ + { + role: 'system', + content: generatePrompt(locale, maxLength, type), + }, + { + role: 'user', + content: diff, + }, + ], temperature: 0.7, top_p: 1, frequency_penalty: 0, diff --git a/src/utils/prompt.ts b/src/utils/prompt.ts new file mode 100644 index 00000000..f2518d87 --- /dev/null +++ b/src/utils/prompt.ts @@ -0,0 +1,48 @@ +import type { CommitType } from './config.js'; + +const commitTypeFormats: Record = { + '': '', + conventional: '(): ', +}; +const specifyCommitFormat = (type: CommitType) => `The output response must be in format:\n${commitTypeFormats[type]}`; + +const commitTypes: Record = { + '': '', + + /** + * References: + * Commitlint: + * https://github.com/conventional-changelog/commitlint/blob/18fbed7ea86ac0ec9d5449b4979b762ec4305a92/%40commitlint/config-conventional/index.js#L40-L100 + * + * 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({ + docs: 'Documentation only changes', + 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', + }, null, 2) + }`, +}; + +export const generatePrompt = ( + locale: string, + maxLength: number, + 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.', + commitTypes[type], + specifyCommitFormat(type), +].filter(Boolean).join('\n');