🐙

ChatGPT APIを使ったGrinderコマンドを作成する

2023/03/15に公開

はじめに

TwitterでChatGPTにコミットメッセージを考えさせるみたいなツイートを見かけて、そういうことをするGrinderコマンドを作ってみました。

事前情報

Grinder

Dartで書いたタスクをターミナルやCIで実行できるパッケージです。導入方法等は以下を参照

https://zenn.dev/k9i/articles/bcfa83b08e56d6

dart_openai

ChatGPT APIを叩くのには、こちらの記事でも紹介したdart_openaiを使います。
https://zenn.dev/toridori/articles/25c310b2dad300

コマンドの紹介

早速コマンドの紹介です。

コミットメッセージを生成する例)

以下の処理を実行しています。

  1. git diffコマンドを実行
  2. .envからAPIキーを取得
  3. dart_openaiでChatGPT AIを叩く
  4. 結果をクリップボードにコピー
tool/grind.dart
import 'dart:io';

import 'package:dart_openai/openai.dart';
import 'package:dotenv/dotenv.dart';
import 'package:grinder/grinder.dart';

void main(List<String> args) => grind(args);

('コミットメッセージを生成する')
Future<void> commitMessage() async {
  final diffCommandResult = Process.runSync('git', ['diff'], runInShell: true);
  if (diffCommandResult.exitCode != 0) {
    throw Exception(
      'git diff command failed with exit code ${diffCommandResult.exitCode}',
    );
  }
  final diff = diffCommandResult.stdout.toString();
  log(diff);

  // .envファイルを読み込む
  final env = DotEnv()..load();
  final apiKey = env['OPEN_AI_API_KEY']!;
  OpenAI.apiKey = apiKey;
  final chatGptResult = await OpenAI.instance.chat.create(
    model: 'gpt-3.5-turbo',
    messages: [
      OpenAIChatCompletionChoiceMessageModel(
        content: '''
あなたはgitのコミットメッセージを考えるアシスタントです。gitの差分を入力されたら、そこからコミットメッセージを考えてください。

考慮事項
- 日本語でお願いします
- 返答はコミットメッセージの内容だけを返してください
- +ではじまる行が追加された行、-ではじまる行が削除された行です

例
- 機能追加:ユーザー登録画面の実装
- 修正:検索結果のページネーションの不具合を解消
- リファクタリング:無駄なコードの削除と整理
- テスト追加:新規APIエンドポイントのテストケースを作成
- ドキュメント更新:README.mdに使用方法を追記
''',
        role: 'system',
      ),
      OpenAIChatCompletionChoiceMessageModel(
        content: diff,
        role: 'user',
      ),
    ],
  );
  final commitMessage = chatGptResult.choices.first.message.content;
  log(commitMessage);
  await Process.run(
    'zsh',
    ['-c', 'echo $commitMessage | pbcopy'],
    runInShell: true,
  );
}

ポイント

  • systemロールでChatGPTに考慮事項等を伝えています。その後、userロールのメッセージでdiffを送ってます。
  • メッセージに例を載せているのはプロンプトエンジニアリングのIn-context Learning (ICL)という手法です。これによりコミットメッセージの精度が体感あがりました。

実行例

以下のような差分の場合

  diff --git a/lib/features/settings/settings_repository.dart b/lib/features/settings/settings_repository.dart
  index 9aadf82..16fc76b 100644
  --- a/lib/features/settings/settings_repository.dart
  +++ b/lib/features/settings/settings_repository.dart
  @@ -29,4 +29,6 @@ class SettingsRepository {
           .read(sharedPreferencesProvider)
           .setInt(SharedPreferencesKeys.themeMode.name, themeMode.index);
     }
  +
  +  bool get isDarkMode => themeMode == ThemeMode.dark;
   }

返答は「更新:isDarkModeプロパティを追加しました。」でした。
何回か試しましたが、ガチャみたいで楽しかったです。

まとめ

  • GrinderでChatGPTを使ったコマンドを実装する方法の紹介でした。
  • プロンプトを工夫すれば、gitmojiに対応させたりとか色々できそうです。
  • Flutter開発と相性がいいAIコマンドのアイデアが思いついた人は、ぜひコメント欄に書いてください🥳(Youtube風誘導)

おまけ

以下のリポジトリでgrind.dartファイルを公開しています。
https://github.com/K9i-0/flutter_k9i_portfolio

GitHubで編集を提案

Discussion