feat: use new gpt-3.5-turbo model (#123)

Co-authored-by: Hiroki Osame <hiroki.osame@gmail.com>
This commit is contained in:
Jason Tarver
2023-03-10 07:41:10 -06:00
committed by GitHub
parent fed577b960
commit afad8210fc
3 changed files with 26 additions and 17 deletions

View File

@@ -49,6 +49,10 @@ export default async (
); );
s.stop('Changes analyzed'); s.stop('Changes analyzed');
if (messages.length === 0) {
throw new KnownError('No commit messages were generated. Try again.');
}
let message: string; let message: string;
if (messages.length === 1) { if (messages.length === 1) {
[message] = messages; [message] = messages;

View File

@@ -1,6 +1,6 @@
import https from 'https'; import https from 'https';
import type { ClientRequest, IncomingMessage } from 'http'; import type { ClientRequest, IncomingMessage } from 'http';
import type { CreateCompletionRequest, CreateCompletionResponse } from 'openai'; import type { CreateChatCompletionRequest, CreateChatCompletionResponse } from 'openai';
import { encoding_for_model as encodingForModel } from '@dqbd/tiktoken'; import { encoding_for_model as encodingForModel } from '@dqbd/tiktoken';
import { KnownError } from './error.js'; import { KnownError } from './error.js';
@@ -50,13 +50,13 @@ const httpsPost = async (
request.end(); request.end();
}); });
const createCompletion = async ( const createChatCompletion = async (
apiKey: string, apiKey: string,
json: CreateCompletionRequest, json: CreateChatCompletionRequest,
) => { ) => {
const { response, data } = await httpsPost( const { response, data } = await httpsPost(
'api.openai.com', 'api.openai.com',
'/v1/completions', '/v1/chat/completions',
{ {
Authorization: `Bearer ${apiKey}`, Authorization: `Bearer ${apiKey}`,
}, },
@@ -81,7 +81,7 @@ const createCompletion = async (
throw new KnownError(errorMessage); throw new KnownError(errorMessage);
} }
return JSON.parse(data) as CreateCompletionResponse; return JSON.parse(data) as CreateChatCompletionResponse;
}; };
const sanitizeMessage = (message: string) => message.trim().replace(/[\n\r]/g, '').replace(/(\w)\.$/, '$1'); const sanitizeMessage = (message: string) => message.trim().replace(/[\n\r]/g, '').replace(/(\w)\.$/, '$1');
@@ -90,8 +90,9 @@ const deduplicateMessages = (array: string[]) => Array.from(new Set(array));
const getPrompt = (locale: string, diff: string) => `Write an insightful but concise Git commit message in a complete sentence in present tense for the following diff without prefacing it with anything, the response must be in the language ${locale}:\n${diff}`; const getPrompt = (locale: string, diff: string) => `Write an insightful but concise Git commit message in a complete sentence in present tense for the following diff without prefacing it with anything, the response must be in the language ${locale}:\n${diff}`;
const model = 'text-davinci-003'; const model = 'gpt-3.5-turbo';
const encoder = encodingForModel(model); // TODO: update for the new gpt-3.5 model
const encoder = encodingForModel('text-davinci-003');
export const generateCommitMessage = async ( export const generateCommitMessage = async (
apiKey: string, apiKey: string,
@@ -110,9 +111,12 @@ export const generateCommitMessage = async (
} }
try { try {
const completion = await createCompletion(apiKey, { const completion = await createChatCompletion(apiKey, {
model, model,
prompt, messages: [{
role: 'user',
content: prompt,
}],
temperature: 0.7, temperature: 0.7,
top_p: 1, top_p: 1,
frequency_penalty: 0, frequency_penalty: 0,
@@ -124,7 +128,8 @@ export const generateCommitMessage = async (
return deduplicateMessages( return deduplicateMessages(
completion.choices completion.choices
.map(choice => sanitizeMessage(choice.text!)), .filter(choice => choice.message?.content)
.map(choice => sanitizeMessage(choice.message!.content)),
); );
} catch (error) { } catch (error) {
const errorAsAny = error as any; const errorAsAny = error as any;

View File

@@ -3,9 +3,6 @@ import { createFixture } from 'fs-fixture';
import { createAicommits, createGit } from '../utils.js'; import { createAicommits, createGit } from '../utils.js';
const { OPENAI_KEY } = process.env; const { OPENAI_KEY } = process.env;
if (!OPENAI_KEY) {
throw new Error('process.env.OPENAI_KEY is necessary to run these tests');
}
export default testSuite(({ describe }) => { export default testSuite(({ describe }) => {
if (process.platform === 'win32') { if (process.platform === 'win32') {
@@ -14,6 +11,11 @@ export default testSuite(({ describe }) => {
return; return;
} }
if (!OPENAI_KEY) {
console.warn('⚠️ process.env.OPENAI_KEY is necessary to run these tests. Skipping...');
return;
}
describe('CLI', async ({ test }) => { describe('CLI', async ({ test }) => {
const data: Record<string, string> = { const data: Record<string, string> = {
firstName: 'Hiroki', firstName: 'Hiroki',
@@ -94,10 +96,8 @@ export default testSuite(({ describe }) => {
if (stdout.match('└')) { if (stdout.match('└')) {
const countChoices = stdout.match(/ {2}[●○]/g)?.length ?? 0; const countChoices = stdout.match(/ {2}[●○]/g)?.length ?? 0;
// 2 choices or less should be generated // 2 choices should be generated
// pretty common for it to return 2 results that are the same expect(countChoices).toBe(2);
// which gets de-duplicated
expect(countChoices <= 2).toBe(true);
committing.stdin!.write('\r'); committing.stdin!.write('\r');
committing.stdin!.end(); committing.stdin!.end();