概要
こんにちは!
GPT君は文脈を読み取る力みたいなのが非常に優れているので、「React歴2年以上の案件メールだけ確認したい」みたいなことができるのは。と思ったのでSpringBootで試してみました。
前提
- Googleアカウント開設済み
- OpenAIのAPI keysを取得済み
Gmail APIの設定
GmailのAPIを利用するため、以下の手順が必要になります。
- Google Cloudでプロジェクトの作成
- Gmail APIの有効化
- OAuth 2.0 クライアントの設定
Google Cloudでプロジェクトを作成する
https://console.cloud.google.com/cloud-resource-manager にログインし、プロジェクトを作成します。
プロジェクト名は適当にgmail-aiとかにしました。
Gmail APIの有効化
https://console.developers.google.com/apis/library にアクセスし、「Gmail API」で検索→Gmail-apiを有効化する。
OAuth 2.0 クライアントの作成
https://console.cloud.google.com/apis/credentials にアクセスし、認証情報を作成→OAuthクライアントIDを選択する。
ウェブアプリケーションを選択し、名前は適当に「gmailai」、承認済みのリダイレクトURIに「http://localhost:5555/Callback 」を入力→保存する。
秘密鍵をJSONでダウンロード。後に実装で使います。
実装
構成はこんな感じ
先ほど取得した秘密鍵JSONは/resources
に配置。OpenAiのAPI_Keyはopen-api-secret.propatiesに書いています。
まずはbuild.gradleにTheoKanning/openai-javaを追加
implementation group: 'com.theokanning.openai-gpt3-java', name: 'service', version: '0.12.0'
ちなみに
implementation group: 'com.theokanning.openai-gpt3-java', name: 'client', version: '0.12.0'
もありますが、後にOpenAiServiceクラス
を使うためにはサービスモジュールの必要があるため前者の方にして下さい。
今回はGMailのAPIを使うので以下も追加します。
implementation 'com.google.apis:google-api-services-gmail:v1-rev20220404-1.32.1'
implementation group: 'com.google.api-client', name: 'google-api-client', version: '1.32.1'
implementation group: 'com.google.oauth-client', name: 'google-oauth-client-jetty', version: '1.32.1'
認証
認証のためのコーディングをしていきます。大体のコードは以下記事を参考にしています。
// Json処理
JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();
// スコープ
List<String> SCOPES = Collections.singletonList(GmailScopes.GMAIL_READONLY);
// 認証周りの設定ファイルの格納フォルダ
String CREDENTIALS_FOLDER = "credentials";
String path = "/client-secret.json";
try (InputStream is = getClass().getResourceAsStream(path);
InputStreamReader streamReader = new InputStreamReader(is, StandardCharsets.UTF_8);
BufferedReader br = new BufferedReader(streamReader);
) {
// HTTP通信
NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
System.out.println(HTTP_TRANSPORT.toString());
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, streamReader);
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY,
clientSecrets, SCOPES)
.setDataStoreFactory(new FileDataStoreFactory(new java.io.File(CREDENTIALS_FOLDER)))
.setAccessType("offline").build();
// 認証を行う
LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(5555).build();
Credential credential = new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
// Gmailのサービスを作成
// アプリケーション名
String APPLICATION_NAME = "gmailai";
// Gmailにアクセス
Gmail service = new Gmail.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential).setApplicationName(APPLICATION_NAME)
.build();
}
まずは定数の説明
JSON_FACTORY : JSONを処理するためのオブジェクト。APIの返ってくるデータはJSON形式なので。
SCOPES : APIをつかってGmailにどこまでのアクセスを許可するか。GmailScopesクラスに定数で全部あるはずなのでそれから適切なものを選んでつかいましょう。今回やるようなことはGMAIL_READONLYを選んでおけば全部できるはずなので、それを選んでおきましょう。
CLIENT_SECRET_DIR : 秘密鍵のファイルのパス。今回は直下に「client_secret.json」という名前でいれたので、"client_secret.json"でOKです。
CREDENTIALS_FOLDER : 秘密鍵を使って取得した認証まわりのファイルを保存するフォルダのパス。上で作ったフォルダを設定。
HTTP_TRANSPORT : HTTP通信をするためのオブジェクト。
メール本文の取得
先程取得したGmailのサービスのオブジェクトをもとに、以下の雑な処理でメール本文を取得し、String型に変換していきます。
public String getGMail(Gmail service) {
// ユーザ
String USER = "me";
// メールIDを全て取得
ListMessagesResponse messagesResponse = getMessagesResponse(service, USER);
List<Message> messageList = messagesResponse.getMessages();
// 今回は最新のメールだけ取得
Message targetMessage = getFullMessage(service, USER, messageList.get(0));
// 本文の取得(Base64)
String bodyBase64 = targetMessage.getPayload().getParts().get(0).getBody().get("data").toString();
// Base64からデコード(byte列)
byte[] bodyBytes = BaseEncoding.base64Url().decode(bodyBase64);
// byte列からStringに変換
try {
String body = new String(bodyBytes, "UTF-8");
// 本文を返却
return body;
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
ちなみに取得した本文サンプルはこんな感じ。かなり適当です。
突然のメール失礼いたします。
株式会社ホゲホゲ営業担当の斎藤と申します。
貴社の公式サイトを拝見し、SESの人員を募集しているとのことでしたので、ご紹介したいエンジニアがございます。
【名前】
田中 太郎
【経歴】
2018年 株式会社banに入社 プログラマーとして勤務
2022年 Boo株式会社に転職 プロジェクトマネージャーとして従事
【スキル】
Java歴 3年
React歴 1年
Vue歴 2年
Rust歴 1年
いずれも実務での経験年数になります
ご興味がありましたら、こちらのメールアドレス(abc@mail .com)にご返信ください。
GPT君の出番
やっとGPT君の出番が回ってきました。
今回はメール本文から、田中太郎さんのスキルを抽出してもらいましょう。
public void summaryForGpt(String mailBody) { // 先程取得したメール本文
ResourceBundle config = ResourceBundle.getBundle("open-api-secret"); // resources/open-api-secret.properties
String token = config.getString("token");
String prompt = "次の文章は営業メールです。文章の内容を読み取って、紹介されている人物の持っているスキルを全て抽出して下さい。\n" + mailBody;
OpenAiService service = new OpenAiService(token);
ChatCompletionRequest completionRequest = ChatCompletionRequest.builder()
.messages(Arrays.asList(new ChatMessage("system", prompt)))
.model("gpt-4")
.maxTokens(256)
.stream(false)
.build();
List<ChatCompletionChoice> completionResult = service.createChatCompletion(completionRequest).getChoices();
for (ChatCompletionChoice choice : completionResult) {
System.out.println(choice.getMessage().getContent());
}
}
Java、React、Vue、Rust
ちなみにメール本文の【スキル】
を【技術】
とかにしてもちゃんと取得してくれました。
できそうなこと
メールの受信時にメール本文のGPTに読み込ませる→任意の項目を抽出(スキルや職種など)→DBに保存。みたいなことすれば、高度なメールフィルター機能をもつサービスとか作れそうだな~と思いました。
あとは、メールの内容的にスパムっぽいやつは全自動でゴミ箱へシュートする機能とかもできそうな気がします。
他にもこんなことできそう!みたいな案がありましたら、コメント頂けると嬉しいです!!
参考文献