🙌

【本日解禁】Gemini Proを体験してみよう

2023/12/14に公開

Gemini Pro

本日Googleが企業と開発者向けに新しい生成AIモデル「Gemini」のミドルサイズ「Gemini Pro」の提供を開始しました。

私自身、AIに関して詳しくはありませんが、軽くですが触ってみたので、体験してみたい人に向け記事を残そうと思います。

まずはGoogle AI StudioでAPIキーを作成してください。
「Create API key in new project」でOKです。

次にXcodeでプロジェクトを作成し、SPMで以下のパッケージを追加してください。
https://github.com/google/generative-ai-swift

その後は以下のコードのAPI keyをご自身のものに置き換えることでGemini Proを体験できます。
Modelを作成し、generateContentでプロンプトを渡すだけで簡単にレスポンスが取得できます。
※ レスポンスの取得まで数秒かかります。

import SwiftUI
import GoogleGenerativeAI

struct ContentView: View {
    let model = GenerativeModel(name: "gemini-pro", apiKey: "APIキー")
    @State private var promptText = ""
    @State private var responseText = ""
    var body: some View {
        VStack {
            Text(responseText)
                .frame(height: 100)
                 .frame(maxWidth: .infinity)
                 .border(Color(.systemGray4))
             
             TextField("prompt", text: $promptText)
                 .textFieldStyle(.roundedBorder)
            
            Button("Generate") {
                Task {
                    let response = try await model.generateContent(promptText)
                    if let text = response.text {
                      responseText = text
                    }
                }
            }
            .buttonStyle(.borderedProminent)
        }
        .padding(.horizontal)
    }
}

#Preview {
    ContentView()
}

試しに質問をしてみた時の回答がこちらです。

同じ質問をChatGPTに投げた時の回答はこちらです。

Geminiの回答はChatGPTに比べてかなり淡白なものでした。
今回はGoogleのクイックスタートで説明されている「テキストのみの入力からテキストを生成する(Generate text from text-only input)」というやり方でテキストを生成したので、その影響かもしれません。
明確な答えのある質問に対しては、一問一答のような答えを提示します。「〇〇とはなんですか?」や「〇〇について教えてください。」と質問すると、丁寧な答えを提示してくれます。

追記1

Twitterに載せた動画のコードはこちらです。少しだけそれっぽくしてあります。

https://twitter.com/3MB_JP/status/1735644402629128390

struct Chat: Identifiable {
    let id = UUID()
    let question: String
    let answer: String

    init(question: String, answer: String) {
        self.question = "Q. " + question
        self.answer = "A. " + answer
    }
}

struct ContentView: View {
    let model = GenerativeModel(name: "gemini-pro", apiKey: apiKey)
    @State private var chats: [Chat] = []
    @State private var text = ""
    @State private var isGenerating = false

    var body: some View {
        NavigationStack {
            ZStack {
                Color(.systemGray6).ignoresSafeArea()
                ScrollView {
                    VStack(alignment: .leading) {
                        ForEach(chats) { chat in
                            Text(chat.question)
                                .fontWeight(.semibold)
                            Text(chat.answer)
                                .padding(.top, 5)
                            Divider()
                                .padding(.vertical)
                        }

                        if isGenerating {
                            ProgressView("generating...")
                                .frame(maxWidth: .infinity)
                        }
                    }
                    .padding()
                }

                TextField("Placeholder", text: $text)
                    .textFieldStyle(.roundedBorder)
                    .padding(.horizontal)
                    .padding(.bottom)
                    .frame(maxHeight: .infinity, alignment: .bottom)
                    .onSubmit {
                        guard !text.isEmpty else { return }
                        Task {
                            isGenerating = true
                            defer {
                                isGenerating = false
                            }
                            let question = text
                            text.removeAll()
                            let response = try? await model.generateContent(question)
                            guard let answer = response?.text else {
                                print("response is nil.")
                                return
                            }
                            withAnimation {
                                chats.append(Chat(question: question, answer: answer))
                            }
                        }
                    }
            }
            .navigationTitle("Q & A")
            .navigationBarTitleDisplayMode(.inline)
        }
    }
}

追記2

チャットモード?はこんな感じです。

struct ContentView: View {
    private let model: GenerativeModel
    @State private var chat: Chat
    @State private var text = ""
    @State private var isGenerating = false

    init() {
        self.model = GenerativeModel(name: "gemini-pro", apiKey: apiKey)
        self.chat = model.startChat()
    }

    var body: some View {
        NavigationStack {
            ZStack {
                Color(.systemGray6).ignoresSafeArea()
                ScrollView {
                    VStack(alignment: .leading) {
                        ForEach(chat.history.indices, id: \.self) { i in
                            Text(chat.history[i].role ?? "unknown")
                                .fontWeight(.semibold)
                            Text(chat.history[i].parts[0].text ?? "text is nil.")
                                .padding(.top, 5)
                            Divider()
                                .padding(.vertical)
                        }
                        if isGenerating {
                            ProgressView("generating...")
                                .frame(maxWidth: .infinity)
                        }
                    }
                    .padding()
                }
                TextField("message", text: $text)
                    .textFieldStyle(.roundedBorder)
                    .disabled(isGenerating)
                    .padding(.horizontal)
                    .padding(.bottom)
                    .frame(maxHeight: .infinity, alignment: .bottom)
                    .onSubmit {
                        guard !text.isEmpty else { return }
                        Task {
                            isGenerating = true
                            defer {
                                isGenerating = false
                                text.removeAll()
                            }
                            let _ = try? await chat.sendMessage(text)
                        }
                    }
            }
            .navigationTitle("Chat with Gemini Pro")
            .navigationBarTitleDisplayMode(.inline)
        }
    }
}

Discussion