LINE + ChatGPTで友達(チャットボット)を作る

## 目次
* [概要](#概要)
* [環境](#環境)
* [各種サービスの用意](#各種サービスの用意)
* [構成](#構成)
* [実装内容](#実装内容)
* [実行結果](#実行結果)
* [参考](#参考)

## 概要
ChatGPTとLINEで、友達(チャットボット)を作る一連について記載しています。
ChatGPTのUIで不足ないと思いますが、基本LINE等でコミュニケーションを取ると思うので、UIをLINEに変えることでそれっぽさを出しています。
ソースコードだけ見たい方は[こちら](https://github.com/omoikane245/linebot-example)から。

## 環境
* Kotlin 1.7.22
* Spring Boot 3.0.6
* ngrok 3.2.2

## 各種サービスの用意
アプリ作るだけだと動かないので、動かすために以下の作業が必要です。
* [ngrokのインストールと設定](https://ngrok.com/docs/getting-started/)
* [ChatGPTの登録とAPIKey作成](https://www.a-c-japan.com/solution/chatgpt/chatgpt-api/)
* [LINE Developersへの登録とチャネル設定](https://developers.line.biz/ja/docs/messaging-api/getting-started/)
今回のために作成した、LINEアカウントは以下です。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534209/07878c52-2a27-4b44-51d1-b0891fe669d0.png)

## 構成
来たものをそのまま横流ししています。

```mermaid
sequenceDiagram
    autonumber
    actor 利用者
    participant line as LINE
    participant app as 作るアプリ
    participant chatgpt as ChatGPT
    利用者->>line: メッセージ送信
    line->>app: メッセージ送信
    app->>chatgpt: メッセージ送信
    chatgpt->>app: メッセージ返信
    app->>line: メッセージ返信
    line->>利用者: メッセージ返信
```

## 実装内容
* WebhookController.kt
LINEから公式SDKが用意されているので、[そちら](https://github.com/line/line-bot-sdk-java)を使用しています。
テキストメッセージを受け取り、ChatGPTにそのまま送信し結果を返しています。
```WebhookController.kt
package com.example.linebotexample.controller

import com.example.linebotexample.service.AiService
import com.linecorp.bot.model.event.MessageEvent
import com.linecorp.bot.model.event.message.TextMessageContent
import com.linecorp.bot.model.message.TextMessage
import com.linecorp.bot.spring.boot.annotation.EventMapping
import com.linecorp.bot.spring.boot.annotation.LineMessageHandler
import org.springframework.stereotype.Controller

@Controller
@LineMessageHandler
class WebhookController(
	private val aiService: AiService
) {

	@EventMapping
	fun handleTextMessageEvent(
		event: MessageEvent<TextMessageContent>
	): TextMessage {
		return aiService.handleTextMessageEvent(event)
	}
}
```

* ChatGptClient.kt
ChatGPTと通信するクラス。
通信関係の必要そうな共通の設定は、RestTemplateConfig.ktに記載しています。
```ChatGptClient.kt
package com.example.linebotexample.client

import com.example.linebotexample.client.dto.ChatRequestDto
import com.example.linebotexample.client.dto.ChatResponseDto
import com.example.linebotexample.constant.ChatGptConstant
import com.example.linebotexample.exception.EmptyMessageException
import org.springframework.http.HttpEntity
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpMethod
import org.springframework.http.MediaType
import org.springframework.stereotype.Component
import org.springframework.web.client.RestTemplate
import org.springframework.web.util.UriComponentsBuilder

@Component
class ChatGptClient(
	private val restTemplate: RestTemplate,
	private val chatGptConstant: ChatGptConstant
) {

	fun post(request: ChatRequestDto): ChatResponseDto {
		val uriComponents = UriComponentsBuilder.fromUriString(chatGptConstant.url).build()
		val headers = HttpHeaders()
		headers.set(HttpHeaders.AUTHORIZATION, "Bearer ${chatGptConstant.key}")
		val entity = HttpEntity(request, headers)
		val exchange = restTemplate.exchange(uriComponents.toUriString(), HttpMethod.POST, entity, ChatResponseDto::class.java)
		return exchange.body ?: throw EmptyMessageException("ChatGPTからメッセージを受け取れませんでした。")
	}
}
```

* ChatGptConstant.kt
接続先の情報は、環境変数から取得しています。
```ChatGptConstant.kt
package com.example.linebotexample.constant

import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Configuration

@Configuration
class ChatGptConstant {

	@Value("\${chatgpt.url}")
	val url = ""

	@Value("\${chatgpt.key}")
	val key = ""
}
```

## 実行結果
1. ngrokでHTTPトンネリング
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534209/289169b5-6630-706f-6a95-7746138d4077.png)
2. アプリ起動
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534209/d3a0fc16-1f91-9f9d-3ba7-93674e87069f.png)
3. LINEチャネルに接続先を登録
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534209/fa2579c1-d171-d99d-cfe5-0b6e09123d43.png)
4. メッセージ送信
![IMG_0289.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534209/95f47d11-b2eb-2d32-dc58-98705d1f9ac9.png)

## 参考
https://ngrok.com/
https://qiita.com/accenture_ace/items/14dcd50f0cb0cbc12b6d
https://platform.openai.com/docs/api-reference/chat/create
https://www.a-c-japan.com/solution/chatgpt/chatgpt-api/
https://github.com/line/line-bot-sdk-java