🍜

iOSアプリにサッとChatGPTを組み込んで試す(Swift)

2023/05/22に公開

前段

2023年はアプリにAIを組み込む企画が走りそうな気配があります。

まずは企画メンバーに触ってもらって理解を深めてもらいたいということで、ライブラリを組み合わせた簡易版をサッと作ってみました。

(だいたい2時間程度で作れました)

手順

環境: Xcode14.3 / iOS16.4.1

1. ChatGPTのAPI Keyをゲットする

OpenAIのページでAPI keyを作成します。
(API利用にはクレジットカード登録&利用に応じた料金が発生するので注意※2023年5月18日時点)

2. Swift Package Manager でライブラリを組み込む

利用するのは以下の2つ

  • OpenAISwift
    • OpenAI APIのラッパーライブラリ
      • クライアントから直接OpenAIのAPIを利用できるものです。今回はデモアプリなので使用していますが、プロダクションとして提供するアプリではバックエンドを介してAPIを利用する方が望ましいです。
  • MessageKit
    • チャットUIのライブラリ

3. 画面を作る

  1. MessageKitMessagesViewController を継承したUIViewControllerを作ります
import MessageKit

class ChatViewController: MessagesViewController {
...
}
  1. protocol MessageTypeSenderType の型を定義する
struct MyAppSender: SenderType {
    var senderId: String
    var displayName: String
}

struct MyAppMessage: MessageType {
    var sender: MessageKit.SenderType
    var messageId: String
    var sentDate: Date
    var kind: MessageKit.MessageKind
}
  1. MessagesDataSource MessagesLayoutDelegate を実装する
class ChatViewController: MessagesViewController {
    private var messages = [MyAppMessage]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        messagesCollectionView.messagesDataSource = self
        messagesCollectionView.messagesLayoutDelegate = self
        
        DispatchQueue.main.async {
            self.messagesCollectionView.reloadData()
            self.messagesCollectionView.scrollToLastItem(animated: false)
        }
    }
}

extension ChatViewController: MessagesDataSource {

    var currentSender: MessageKit.SenderType {
        MyAppSender(senderId: "you", displayName: "あなた")
    }

    func messageForItem(at indexPath: IndexPath, in messagesCollectionView: MessageKit.MessagesCollectionView) -> MessageKit.MessageType {
        // チャットの吹き出しがrowでなくsectionで表現されることに注意
        messages[indexPath.section]
    }

    func numberOfSections(in messagesCollectionView: MessageKit.MessagesCollectionView) -> Int {
        messages.count
    }
}

(レイアウトは特にこだわりがなかったので MessageKit のexampleをそのまま使っています)

extension ChatViewController: MessagesLayoutDelegate {

    func cellTopLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView)
      -> CGFloat {
        18
    }

    func cellBottomLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
        17
    }

    func messageTopLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
        20
    }

    func messageBottomLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
        16
    }
}

4. 送信処理とメッセージ表示を実装する

  1. 送信ボタンタップ
    MessagesViewController のプロパティ messageInputBar.sendButton が送信ボタンです。UIButtonを継承しているのでお好きなイベントハンドリングを実装してください。

  2. ChatGPTへの質問送信処理を実装

チャット形式で回答を得るには↓

import OpenAISwift

let openAI = OpenAISwift(authToken: "XXXX") // API Key

openAI.sendChat(
	with: [ChatMessage(role: .user, content: text)],
	completionHandler: { result in
	    switch result {
	    case let .success(messageResult):
		print(messageResult)
	    case let .failure(error):
		print(error)
	    }
	}
)

※API Keyはgit管理に含めないほうが賢明です

  1. 質問文とレスポンスを MyAppMessage に変換し、配列に追加した後messagesCollectionView.reloadData() を実行する

その他

チャットUIの細かいところは MessageKitExample が参考になります。

  • テキスト入力フォームのプレースホルダ文言を変えたい
    • messageInputBar.inputTextView.placeholder
  • 送信ボタンのタイトルを変えたい
    • messageInputBar.sendButton.title
  • メッセージにアイコンなどのアバターを表示したい
    • MessagesDisplayDelegate ↓を実装
extension ChatViewController: MessagesDisplayDelegate {
    func configureAvatarView(_ avatarView: AvatarView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) {
            avatarView.set(avatar: Avatar(image: UIImage(systemName: "face.smiling")))
    }
}
東急URBAN HACKS

Discussion