Skip to content

Commit

Permalink
refactor: organize prompt generation to its own file
Browse files Browse the repository at this point in the history
  • Loading branch information
privatenumber committed May 3, 2023
1 parent eda3462 commit dda7f8d
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 67 deletions.
79 changes: 12 additions & 67 deletions src/utils/openai.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
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,
} from '@dqbd/tiktoken';
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,
Expand Down Expand Up @@ -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 '<type>(<optional scope>): <commit message>';
}

return '<commit message>';
};

/**
* 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';
Expand Down Expand Up @@ -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,
Expand Down
48 changes: 48 additions & 0 deletions src/utils/prompt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import type { CommitType } from './config.js';

const commitTypeFormats: Record<CommitType, string> = {
'': '<commit message>',
conventional: '<type>(<optional scope>): <commit message>',
};
const specifyCommitFormat = (type: CommitType) => `The output response must be in format:\n${commitTypeFormats[type]}`;

const commitTypes: Record<CommitType, string> = {
'': '',

/**
* 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');

0 comments on commit dda7f8d

Please sign in to comment.