Skip to content

Commit

Permalink
feat: finish first step summary every file, meet some error
Browse files Browse the repository at this point in the history
  • Loading branch information
Song Aihua committed Apr 7, 2023
1 parent af7f0e8 commit 9abece7
Show file tree
Hide file tree
Showing 15 changed files with 1,749 additions and 110 deletions.
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"cSpell.words": [
"huskygpt"
]
}
9 changes: 8 additions & 1 deletion bin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const runTypes = ['test', 'review', 'commit'];
program
.version(packageJson.version, '-v, --version', 'output the current version')
.description('Generate unit tests or review your code by chatgpt 4')
.argument('<runType>', 'run type: test or review')
.argument('<runType>', `run type: ${runTypes.join(', ')}`)
.option('-k, --api-key <key>', 'Set the OpenAI API key')
.option(
'-t, --openai-session-token <token>',
Expand Down Expand Up @@ -61,6 +61,10 @@ program
'-w, --review-report-webhook <url>',
'Webhook URL to send review report',
)
.option(
'--commit-diff <name>',
'commit diff file path, example: .git/foo.diff',
)
.action((runType, options) => {
if (!runTypes.includes(runType)) {
// exit with error
Expand Down Expand Up @@ -99,6 +103,9 @@ program
...(options.openAIProxyUrl && {
openAIProxyUrl: options.openAIProxyUrl,
}),
...(options.commitDiff && {
commitDiff: options.commitDiff,
}),
};

main(userOptions);
Expand Down
12 changes: 9 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,15 @@
},
"jest": {
"transform": {
".ts": "ts-jest"
".ts": "ts-jest"
},
"moduleNameMapper": {
"^src/(.*)$": "<rootDir>/src/$1"
},
"testRegex": "(/test/.*|\\.(test|spec))\\.(ts)$",
"moduleFileExtensions": ["ts", "js"]
"moduleFileExtensions": [
"ts",
"js"
]
}
}
}
14 changes: 1 addition & 13 deletions prompt/summarize_file_diff.txt
Original file line number Diff line number Diff line change
@@ -1,21 +1,9 @@
You are an expert programmer summarizing a git diff.
Reminders about the git diff format:
For every file, there are a few metadata lines, like (for example):
```
diff --git a/lib/index.js b/lib/index.js
index aadf691..bfef603 100644
--- a/lib/index.js
+++ b/lib/index.js
```
This means that `lib/index.js` was modified in this commit. Note that this is only an example.
Then there is a specifier of the lines that were modified.
A line starting with `+` means it was added.
A line that starting with `-` means that line was deleted.
A line that starts with neither `+` nor `-` is code given for context and better understanding.
It is not part of the diff.
After the git diff of the first file, there will be an empty line, and then the git diff of the next file.

Do not include the file name as another part of the comment.
Do not use the characters `[` or `]` in the summary.
Write every summary comment in a new line.
Comments should be in a bullet point list, each line starting with a `-`.
Expand All @@ -40,7 +28,7 @@ Do not include parts of the example in your summary.
It is given only as an example of appropriate comments.


THE GIT DIFF TO BE SUMMARIZED:
THE GIT DIFF TO BE SUMMARIZED
```
{{ file_diff }}
```
Expand Down
24 changes: 22 additions & 2 deletions src/chatgpt/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export class ChatgptProxyAPI {
/**
* Log the review info
*/
private oraStart(text = ''): ora.Ora {
oraStart(text = ''): ora.Ora {
return ora({
text,
spinner: {
Expand All @@ -69,7 +69,7 @@ export class ChatgptProxyAPI {
/**
* Run the OpenAI API
*/
private async sendMessage(
async sendMessage(
prompt: string,
prevMessage?: Partial<ChatMessage>,
): Promise<ChatMessage> {
Expand Down Expand Up @@ -130,6 +130,26 @@ export class ChatgptProxyAPI {
return messageArray;
}

async sendPrompts(prompts: string[]): Promise<string[]> {
const [systemPrompt, ...codePrompts] = prompts;
if (!codePrompts.length) return [];

const messageArray: string[] = [];
let message = await this.sendMessage(systemPrompt);
console.log('finish step ', message);

for (const prompt of codePrompts) {
message = await this.sendMessage(prompt, {
conversationId: message?.conversationId,
parentMessageId: message?.id,
});
console.log('finish step ', message);
messageArray.push(message.text);
}

return messageArray;
}

/**
* Start the huskygpt process
*/
Expand Down
4 changes: 1 addition & 3 deletions src/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ import { HuskyGPTTypeEnum, IUserOptions, ReadTypeEnum } from './types';
export const OPENAI_API_KEY_NAME = 'OPENAI_API_KEY';
export const OPENAI_SESSION_TOKEN_NAME = 'OPENAI_SESSION_TOKEN';

export const ROOT_SRC_DIR_PATH = path.join(
new URL('.', import.meta.url).pathname,
);
export const ROOT_SRC_DIR_PATH = path.join(__dirname, '..');

class UserOptionsClass {
options: IUserOptions;
Expand Down
43 changes: 36 additions & 7 deletions src/huskygpt/commit.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,50 @@
import { IReadFileResult } from 'src/types';
import fs from 'fs';
import path from 'path';
import { ROOT_SRC_DIR_PATH, userOptions } from 'src/constant';
import { CommitRead, IFileDiff } from 'src/reader/commit-read';
import { ChatgptProxyAPI } from 'src/chatgpt';
import chalk from 'chalk';

import HuskyGPTBase from './base';
enum PromptFile {
summarize_file_diff = 'summarize_file_diff',
}

/**
* Review code for a given file path
*/
class HuskyGPTCommit extends HuskyGPTBase {
class HuskyGPTCommit {
private openai: ChatgptProxyAPI;
private read: CommitRead;
constructor() {
super();
this.openai = new ChatgptProxyAPI();
this.read = new CommitRead();
}

/**
* Generate a test case for a given file
*/
public async run(fileResult: IReadFileResult): Promise<void> {
const message = await this.openai.run(fileResult);
console.log(message);
public async run(): Promise<void> {
const diffFile = userOptions.options.commitDiff;
const params = this.read.getFileDiffParams(diffFile);
if (!params || !params.length) {
console.error('No file diff found, skip commit message summary');
return;
}
const reviewSpinner = this.openai.oraStart(
chalk.cyan(
`[huskygpt] start ask ChatGPT to summary commit message... \n`,
),
);

const messages = await this.openai.sendPrompts(params);

console.log(messages);

reviewSpinner.succeed(
chalk.green(
`🎉🎉 [huskygpt] ${userOptions.huskyGPTType} code successfully! 🎉🎉\n `,
),
);
}
}

Expand Down
7 changes: 3 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { userOptions } from './constant';
import { HuskyGPTReview, HuskyGPTTest } from './huskygpt';
import ReadFiles from './reader';
import { HuskyGPTTypeEnum, IUserOptions } from './types';
import { CommitRead } from './reader/commit-read';
import HuskyGPTCommit from './huskygpt/commit';

const runMap: Record<HuskyGPTTypeEnum, () => void> = {
[HuskyGPTTypeEnum.Test]: async () => {
Expand All @@ -29,9 +29,8 @@ const runMap: Record<HuskyGPTTypeEnum, () => void> = {
huskygpt.publishNotice();
},
[HuskyGPTTypeEnum.Commit]: async () => {
const commitRead = new CommitRead();
const ret = commitRead.getFileList();
console.log(ret);
const huskygpt = new HuskyGPTCommit();
await huskygpt.run();
},
};

Expand Down
65 changes: 63 additions & 2 deletions src/reader/commit-read.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { execSync } from 'child_process';
import fs from 'fs';
import path from 'path';
import { ROOT_SRC_DIR_PATH } from 'src/constant';

const filterEmpty = (line: string) => line.trim().length > 0;
enum EFileDiffType {
Expand All @@ -8,6 +10,26 @@ enum EFileDiffType {
DELETE = 'delete',
RENAME = 'rename',
}
export interface IFileDiff {
source: string;
filename: string;
mode: EFileDiffType;
diff: string;
add: number;
del: number;
}

const PriorityFileTypes = {
'.ts': 10000,
'.tsx': 10000,
'.js': 10000,
'.less': 100,
'.json': 100,
}

enum PromptFile {
summarize_file_diff = 'summarize_file_diff',
}
export class CommitRead {
private read(diffFile?: string) {
if (diffFile && fs.existsSync(diffFile)) {
Expand All @@ -23,7 +45,7 @@ export class CommitRead {
return files;
}

private parseFile(file: string) {
private parseFile(file: string): IFileDiff {
const lines = file.split('\n');
const [source, target] = lines[0].split(' ').filter(filterEmpty);
const addLines = lines.filter((line) => line.startsWith('+')).length;
Expand Down Expand Up @@ -57,9 +79,48 @@ export class CommitRead {
}
}

private sortAndFilter(files: IFileDiff[]) {
const sortedFiles = files.sort((a, b) => {
const aExt = path.extname(a.filename).slice(1);
const bExt = path.extname(b.filename).slice(1);
const priorityA = PriorityFileTypes[aExt] || 1;
const priorityB = PriorityFileTypes[bExt] || 1;
// delete should be last
if (a.mode === EFileDiffType.DELETE) {
return 1;
}
if (b.mode === EFileDiffType.DELETE) {
return -1;
}
return (b.add + b.del) * priorityB - (a.add + a.del) * priorityA;
});

return sortedFiles;
}

getFileList(diffFile?: string) {
const fileString = this.read(diffFile);
const files = ('\n' + fileString).split('\ndiff --git ').filter(filterEmpty);
return files.map((file) => this.parseFile(file));
const sorted = this.sortAndFilter(files.map((file) => this.parseFile(file)));
return sorted;
}

getFileDiffParams(diffFile?: string) {
const files = this.getFileList(diffFile);
const prompt = this.getPrompt(PromptFile.summarize_file_diff);
// no more than 5 files
return files.slice(0, 5).map((file, i) => {
if (i === 0)
return prompt.replace('{{ file_diff }}', file.diff);
return `This is anther git diff, please summarize: \n${file.diff}`;
});
}

private getPrompt(filename: PromptFile) {
const prompt = fs.readFileSync(
path.join(ROOT_SRC_DIR_PATH, './prompt', `${filename}.txt`),
'utf-8',
);
return prompt.toString();
}
}
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,6 @@ export interface IUserOptions {
* Huskygpt review options
*/
reviewReportWebhook?: string;
// commit diff file path
commitDiff?: string;
}
Loading

0 comments on commit 9abece7

Please sign in to comment.