SwiftUIでChatGPTのような会話アプリをサクッと試す

OpenAI の API（をラップしたライブラリ OpenAISwift ）を利用して、SwiftUI で ChatGPT のような会話アプリをサクッと試す方法を紹介します。

# 完成イメージ

![20230404_182427.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1170961/61b9e8f8-61a7-cba4-8e5a-dec9f9208e1d.gif)

# 使うもの

- OpenAI の API key
- OpenAISwift
    - OpenAI導入ライブラリ
    - [adamrushy/OpenAISwift: This is a wrapper library around the ChatGPT and OpenAI HTTP API](https://github.com/adamrushy/OpenAISwift)

# 開発環境

- Xcode 14.2
- iOS 16.2
- OpenAISwift 1.2.0

# 手順

- はじめに OpenAI の API key を取得しておく
    - キーの取得方法は以下が参考になります
    - [OpenAI | APIキーを取得する方法 | ONE NOTES](https://1-notes.com/openai-get-api-key/)
- Xcode で新規プロジェクトを作成する
    - プロジェクト名：適当に「TestGPT」とか
    - interface：「SwiftUI」
- Swift Package Manager で OpenAISwift をインポートする
    - File/Add Packages … を選択
    - 検索窓から「OpenAISwift」と入力
    - 一覧から OpenAISwift を選んで「Add Package」ボタンをタップ
- ContentView.swift を開いて、以下のソースと差し替える
    
    ```swift
    import SwiftUI
    import OpenAISwift
    
    struct Message: Hashable {
        let text: String
        let isUserMessage: Bool
    }
    
    struct ContentView: View {
        
        @State private var inputText = ""
        @State private var chatHistory: [Message] = []
        
        private var chatClient = OpenAISwift(authToken: "ここにAPIキーを記載")
        
        var body: some View {
            NavigationView {
                VStack {
                    ScrollViewReader { scrollView in
                        ScrollView {
                            ForEach(chatHistory, id: \.self) { message in
                                HStack {
                                    if message.isUserMessage {
                                        Spacer()
                                        Text(message.text)
                                            .padding(8)
                                            .foregroundColor(.white)
                                            .background(Color.blue)
                                            .cornerRadius(8)
                                    } else {
                                        Text(message.text)
                                            .padding(8)
                                            .foregroundColor(.white)
                                            .background(Color.green)
                                            .cornerRadius(8)
                                        Spacer()
                                    }
                                }
                                .padding(4)
                                .id(message)
                            }
                        }
                        .onChange(of: chatHistory) { _ in
                            withAnimation {
                                scrollView.scrollTo(chatHistory.last, anchor: .bottom)
                            }
                        }
                    }
                    HStack {
                        TextField("Type your message here...", text: $inputText)
                            .textFieldStyle(RoundedBorderTextFieldStyle())
                            .padding(.horizontal)
                        Button(action: sendMessage) {
                            Text("Send")
                        }
                        .padding(.trailing)
                    }
                }
                .navigationBarTitle("Chat with ChatGPT")
            }
        }
        
        func sendMessage() {
            if inputText.isEmpty { return }
            
            chatHistory.append(Message(text: inputText, isUserMessage: true))
            
            chatClient.sendCompletion(with: inputText, maxTokens: 500, completionHandler: { result in
                switch result {
                case .success(let model):
                    DispatchQueue.main.async {
                        let output = model.choices.first?.text ?? ""
                        chatHistory.append(Message(text: output, isUserMessage: false))
                        self.inputText = ""
                    }
                case .failure(let error):
                    print(error.localizedDescription)
                    break
                }
            })
        }
    }
    
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView()
        }
    }
    ```
    
- ソースコードに OpenAI の API キーを入力する
    - `"ここにAPIキーを記載"`の””の中にAPIキーを入力する
- 後はビルドするだけ

# ソースコード

https://github.com/YokohamaHori/TestGPT

手早く動かしたい方は、ここで使うソースコードを GitHub に上げておいたので、そちらを Clone してお使いください。（APIキーは差し替えて下さい）
`git clone https://github.com/YokohamaHori/TestGPT.git`


# 参考サイト

- [【Xcode/Swift】SwiftUIでChatGPTを使う方法 | iOS-Docs](https://ios-docs.dev/swiftui-chatgpt/)
- [iOSアプリでサクッとChatGPT APIを利用する方法 | DevelopersIO](https://dev.classmethod.jp/articles/ios-chatgpt-api-daccha/)

# 終わりに

ChatGPT と話しながら、サクッとお試しアプリを作っただけなので、アプリの品質はかなり粗い仕上がりになってます。とりあえず、軽く試すには丁度良いぐらい。実務で使うにはAPIリファレンスを読み込んでからにしたいと思います。

個人的には、最近はデータ分析に力を入れていた（本業はアプリエンジニア）が、これからは ChatGPT があれば分析作業がとても楽になるので、衝撃を受けてます。Python コードは ChatGPT に任せて、分析者は分析にフォーカス出来るようになる。

初めて ChatGPT に触れた時は「私の仕事がなくなるかもしれない！」と、かなり恐れ慄いたが、最近はアプリエンジニアもデータサイエンティストも不要になることはない、と思い始めてきた。むしろ、正しく ChatGPT を扱えることがエンジニアの条件になってくるので、理解を深めていかなくては生き残れないかもしれないと焦ってます。