見出し画像

iOS (Swift) で Gemini API を試す

「iOS (Swift)」で「Gemini API」を試したので、まとめました。

・Xcode 15


1. Gemini API

Gemini API」は、「Google DeepMind」が開発したマルチモーダル大規模言語モデル「Gemini」を利用するためのAPIです。

2. Gemini API の利用料金

「Gemini API」の利用料金は、以下を参照。

3. Gemini API の準備

「iOS (Swift)」での「Gemini API」の準備手順は、次のとおりです。

3-1. プロジェクトの作成

(1) XcodeでiOSのプロジェクトを作成。
「iOS」の「App」テンプレートでプロジェクトを作成します。

3-2. APIキーの準備

「APIキー」はバージョン管理システム (gitなど) に入れないことが推奨されています。「GenerativeAI-Info.plist」に保存して、バージョン管理から除外してください。

(1) プロジェクトに「GenerativeAI-Info.plist」(Propaty List) を追加。

(2) 「GenerativeAI-Info.plist」を右クリック「Open As → Source Code」で開き、以下のように記述。
_API_KEY_ には「Google AI Studio」から取得したAPIキーを指定してください。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>API_KEY</key>
    <string>_API_KEY_</string>
</dict>
</plist>

(3) プロジェクトに「APIKey.swift」を追加。
GenerativeAI-Info.plist」からAPIキーを取得するコードになります。

・APIKey.swift

import Foundation

// APIキー
enum APIKey {
    static var `default`: String {
        guard let filePath = Bundle.main.path(forResource: "GenerativeAI-Info", ofType: "plist")
        else {
            fatalError("Couldn't find file 'GenerativeAI-Info.plist'.")
        }
        let plist = NSDictionary(contentsOfFile: filePath)
        guard let value = plist?.object(forKey: "API_KEY") as? String else {
            fatalError("Couldn't find key 'API_KEY' in 'GenerativeAI-Info.plist'.")
        }
        if value.starts(with: "_") {
            fatalError(
                "Follow the instructions at https://ai.google.dev/tutorials/setup to get an API key."
            )
        }
        return value
    }
}

3-3. generative-ai-swiftパッケージの追加

(1) プロジェクトナビゲータのプロジェクト名を右クリックし、「Add Package Dependencies」をクリック。

(2) 左上の検索ボックスで「https://github.com/google/generative-ai-swift」を検索し、「Add  Package」ボタンを押す。

(3) 「Add Package」ボタンを押す。

4. テキスト生成の実行

4-1. テキスト生成

(1) 「ContentView.swift」を以下のようにコード編集。

・ContentView.swift

import SwiftUI
import GoogleGenerativeAI  // パッケージの追加

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        }
        .padding()
        .onAppear() {
            Task {
                await runGemini()
            }
        }
    }
    
    func runGemini() async {
        // モデルの準備
        let model = GenerativeModel(
            name: "models/gemini-pro",
            apiKey: APIKey.default
        )
        
        // 推論の実行
        do {
            let response = try await model.generateContent("日本一高い山は?")
            if let text = response.text {
                print(text)
            }
        } catch {
            print("Error: \(error)")
        }
    }
}

#Preview {
    ContentView()
}

(2) アプリの実行。
推論の実行結果がコンソールに出力されます。

富士山

4-2. ストリーミング

(1) 「ContentView.swift」を以下のようにコード編集。

・ContentView.swift の一部

    func runGemini() async {
        // モデルの準備
        let model = GenerativeModel(
            name: "models/gemini-pro",
            apiKey: APIKey.default
        )
        
        // 推論の実行
        do {
            let contentStream =  model.generateContentStream("富士山を説明してください")
            for try await chunk in contentStream {
                if let text = chunk.text {
                    print(text)
                    print("----")
                }
            }
        } catch {
            print("Error: \(error)")
        }
    }

(2) アプリの実行。

**富士山**

富士山は日本の象徴的な火山であり、世界で最も有名な
----
山の1つです。標高3,776メートルの富士山は、日本列島の最高峰です。

**地理**

富士山は
----
本州の中部に位置し、静岡県と山梨県の境界にあります。麓の直径は約120キロメートルで、山頂までの距離は約18キロメートルです。富士山は独立した火山で、周囲の山脈とは隔離されています。

**地質**

富士山は、第四紀の
----

約10万年前に噴火によって形成された成層火山です。溶岩流、火砕物、火山灰が何層にも重なって円錐形を形成しています。富士山は現在も活動中ですが、最後に噴火したのは1707年です。

**生態**

富士山の麓には、広葉樹林や針葉樹林が生い茂っています。山頂付近には、高山植物や低木が見られます。富士山には、ツキノワグマ、ニホンジカ、ニホンザルなどの野生動物が生息しています。

**文化的重要性**

富士山は、
----

日本文化において神聖な山として知られています。古くから信仰の対象とされ、多くの神社や寺院が麓に建てられています。富士山は日本の芸術や文学にも頻繁に登場し、何世紀にもわたってインスピレーションを与えてきました。

**世界遺産**

1936年、富士山は日本の国立公園に指定されました。2013年には、「富士山-信仰の対象と芸術の源泉」としてユネスコの世界文化遺産に登録されました。

**観光**

富士山は世界でも人気の観光地です。毎年何百万人もの人々が、山頂へのハイキング、麓の探索、温泉でのリラクゼーションを楽しんでいます。富士山周辺には、五合目、河口湖、富士五湖など、多くの観光スポットがあります。

**その他の詳細**

* 山の形状は、ほぼ左右対称の円錐形をしています。
* 富士山には5つの噴火口があり、「山頂火口」と呼ばれています。
* 富士山の溶岩流は、周囲の村や農業地帯を形成しています。
* 富士山は、日本の最高地点であるだけでなく、世界で最も標高の高い島の山でもあります。
----

4-3. チャット

(1) 「ContentView.swift」を以下のようにコード編集。

・ContentView.swift の一部

    func runGemini() async {
        // モデルの準備
        let model = GenerativeModel(
            name: "models/gemini-pro",
            apiKey: APIKey.default
        )
        
        // チャットの準備
        let chat = model.startChat(history: [])

        do {
            // 質問応答 (1ターン目)
            let response1 = try await chat.sendMessage("日本一高い山は?")
            if let text = response1.text {
                print(text)
            }

            // 質問応答 (2ターン目)
            let response2 = try await chat.sendMessage("その山は何県にある?")
            if let text = response2.text {
                print(text)
            }
            
            // 会話履歴の表示
            print(chat.history)
        } catch {
            print("Error: \(error)")
        }
    }

(2) アプリの実行。

富士山

静岡県と山梨県
[GoogleGenerativeAI.ModelContent(role: Optional("user"), parts: [GoogleGenerativeAI.ModelContent.Part.text("日本一高い山は?")]), GoogleGenerativeAI.ModelContent(role: Optional("model"), parts: [GoogleGenerativeAI.ModelContent.Part.text("富士山")]), GoogleGenerativeAI.ModelContent(role: Optional("user"), parts: [GoogleGenerativeAI.ModelContent.Part.text("その山は何県にある?")]), GoogleGenerativeAI.ModelContent(role: Optional("model"), parts: [GoogleGenerativeAI.ModelContent.Part.text("静岡県と山梨県")])]

5. Visionの実行

5-1. Visionの実行 (画像入力)

(1) 画像を「Assets.xcassets」に「cat.jpg」を追加。

・cat.jpg

(2) 「ContentView.swift」を以下のようにコード編集。

・ContentView.swift の一部

    func runGemini() async {
        // モデルの準備
        let model = GenerativeModel(
            name: "models/gemini-pro-vision",
            apiKey: APIKey.default
        )
        
        // 画像の準備
        let image = UIImage(named: "cat")!
        
        // 推論の実行
        do {
            let response = try await model.generateContent(image)
            if let text = response.text {
              print(text)
            }
        } catch {
            print("Error: \(error)")
        }
    }

(3) アプリの実行。

「邪魔しないでほしいニャ」

5-2. Visionの実行 (テキスト・画像入力)

(1) 「ContentView.swift」を以下のようにコード編集。

・ContentView.swift の一部

    func runGemini() async {
        // モデルの準備
        let model = GenerativeModel(
            name: "models/gemini-pro-vision",
            apiKey: APIKey.default
        )
        
        // 画像の準備
        let image = UIImage(named: "cat")!
        
        // 推論の実行
        do {
            let response = try await model.generateContent(
                "これは何の画像ですか?", 
                image
            )
            if let text = response.text {
              print(text)
            }
        } catch {
            print("Error: \(error)")
        }
    }

(2) アプリの実行。

これは猫の画像です。猫はテレビとゲーム機の前に座っています。

6. 生成パラメータ

GenerativeModel()、model.generateContent()、chat.sendMessage()で、生成パラメータとセーフティセッティングを指定できます。

(1) 推論の実行 (生成パラメータあり)

    func runGemini() async {
        // モデルの準備
        let config = GenerationConfig(
            temperature: 1.0,
            topP: 0.1,
            topK: 16,
            maxOutputTokens: 400,
            stopSequences: ["x"]
        )
        let model = GenerativeModel(
            name: "models/gemini-pro",
            apiKey: APIKey.default,
            generationConfig: config
        )
        
        // 推論の実行
        do {
            let response = try await model.generateContent("魔法のアンパンの話をしてください。")
            if let text = response.text {
                print(text)
            }
        } catch {
            print("Error: \(error)")
        }
    }

昔々、遠い森の奥深くに、魔法のアンパンがありました。このアンパンは、普通のアンパンとは異なり、特別な力を持っていました。
    :

7. セーフティセッティング

(1) 推論の実行 (セーフティセッティングなし)。
ユーザー入力が不適切と判断された場合、ブロックされます。

    func runGemini() async {
        // モデルの準備
        let model = GenerativeModel(
            name: "models/gemini-pro",
            apiKey: APIKey.default
        )
                
        // 推論の実行
        do {
            let response = try await model.generateContent("お前は愚か者だ")
            if let text = response.text {
              print(text)
            }
        } catch {
            print("Error: \(error)")
        }
    }
Error: promptBlocked(
    response: GoogleGenerativeAI.GenerateContentResponse(
        candidates: [], 
        promptFeedback: Optional(GoogleGenerativeAI.PromptFeedback(blockReason: Optional(GoogleGenerativeAI.PromptFeedback.BlockReason.safety), 
        safetyRatings: [
            GoogleGenerativeAI.SafetyRating(category: GoogleGenerativeAI.SafetySetting.HarmCategory.sexuallyExplicit, probability: GoogleGenerativeAI.SafetyRating.HarmProbability.negligible), 
            GoogleGenerativeAI.SafetyRating(category: GoogleGenerativeAI.SafetySetting.HarmCategory.hateSpeech, probability: GoogleGenerativeAI.SafetyRating.HarmProbability.negligible), 
            GoogleGenerativeAI.SafetyRating(category: GoogleGenerativeAI.SafetySetting.HarmCategory.harassment, probability: GoogleGenerativeAI.SafetyRating.HarmProbability.high), 
            GoogleGenerativeAI.SafetyRating(category: GoogleGenerativeAI.SafetySetting.HarmCategory.dangerousContent, probability: GoogleGenerativeAI.SafetyRating.HarmProbability.negligible)
        ]
    )))
)

(2) セーフティセッティング付きの質問応答
「block_none」を指定することで、応答が返される場合があります。

    func runGemini() async {
        // モデルの準備
        let model = GenerativeModel(
            name: "models/gemini-pro",
            apiKey: APIKey.default,
            safetySettings: [
              SafetySetting(harmCategory: .harassment, threshold: .blockNone)
            ]
        )
                
        // 推論の実行 (セーフティセッティングあり)
        do {
            let response = try await model.generateContent("お前は愚か者だ")
            if let text = response.text {
              print(text)
            }
        } catch {
            print("Error: \(error)")
        }
    }

申し訳ありませんが、そのように感じさせてしまったとは思いません。私の目的は人々を助けることであり、それには間違いや間違いを犯した人々を助けることも含まれます。私は他者を思いやり、理解を持って接するよう努めており、自分の過ちから学び、成長したいと常に願っています。

8. サンプルアプリ

generative-ai-swift/Examples/GenerativeAISample/

関連



この記事が気に入ったらサポートをしてみませんか?