iPhone版 話して!(その2)

OpenAIのGPT-4を使ってApp Inventor 2日本語版のチュートリアルにあるアプリと同じように動くiPhoneアプリを作ります。iPhoneアプリを作るにはMacで動くXcodeという開発環境が必要です。ここではmacOS 13.2.1上でXcode 14.3を使っています。このアプリではスマホを振るというジェスチャーを使うので、動作確認にはiPhone 11実機(iOS 16.4.1)を使いました。

準備

iPhone版 話して!(その1)を動くようにする

iPhone版 話して!(その1)のコードはiOSシミュレータでは動くもののiPhone 11実機では声が聞こえなかったので、以下のようにコードを修正しました。AVAudioSessionをリセットする部分を追加しています。GPT-4に聞いたのですが日本語ではなかなか動くコードを作れなかったので、英語でいろいろ試して最終的にこのコードで動きました。

import SwiftUI
import AVFoundation
struct ContentView: View {
    @State private var speechSynthesizer = AVSpeechSynthesizer()
    var body: some View {
        VStack {
            Button(action: {
                self.configureAudioSession()
                self.speakText("今日は新宿で映画を見よう")
            }) {
                Text("話して!")
                    .font(.title)
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }
        }
    }
    func configureAudioSession() {
        let audioSession = AVAudioSession.sharedInstance()
        do {
            try audioSession.setCategory(.playback, mode: .spokenAudio, options: [])
            try audioSession.setActive(true, options: [])
        } catch {
            print("Failed to configure audio session: \(error.localizedDescription)")
        }
    }
    func speakText(_ text: String) {
        let utterance = AVSpeechUtterance(string: text)
        utterance.voice = AVSpeechSynthesisVoice(language: "ja-JP")
        speechSynthesizer.speak(utterance)
    }
}

iPhoneの振るジェスチャーを無効にする

iPhoneではデフォルトで振るジェスチャーは入力取り消しをするので、これを以下の手順で無効にします。

iPhoneの設定->アクセシビリティ->タッチ->シェイクで取り消しをOFF

GPT-4とのやり取り

プロンプト

このコードにスマホを振るとテキストフィールドに入力された言葉を話す機能を追加して

import SwiftUI
import AVFoundation
struct ContentView: View {
    @State private var speechSynthesizer = AVSpeechSynthesizer()
    var body: some View {
        VStack {
            Button(action: {
                self.configureAudioSession()
                self.speakText("今日は新宿で映画を見よう")
            }) {
                Text("話して!")
                    .font(.title)
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }
        }
    }
    func configureAudioSession() {
        let audioSession = AVAudioSession.sharedInstance()
        do {
            try audioSession.setCategory(.playback, mode: .spokenAudio, options: [])
            try audioSession.setActive(true, options: [])
        } catch {
            print("Failed to configure audio session: \(error.localizedDescription)")
        }
    }
    func speakText(_ text: String) {
        let utterance = AVSpeechUtterance(string: text)
        utterance.voice = AVSpeechSynthesisVoice(language: "ja-JP")
        speechSynthesizer.speak(utterance)
    }
}

返答

以下のコードは、スマホを振ることでテキストフィールドに入力された言葉を話す機能が追加されたものです。CoreMotionフレームワークを使用し、加速度センサーのデータを取得してスマホが振られたかどうかを判断します。


import SwiftUI
import AVFoundation
import CoreMotion

struct ContentView: View {
    @State private var speechSynthesizer = AVSpeechSynthesizer()
    @State private var motionManager = CMMotionManager()
    @State private var text = ""

    var body: some View {
        VStack {
            TextField("ここにテキストを入力してください", text: $text)
                .padding()
                .textFieldStyle(RoundedBorderTextFieldStyle())

            Button(action: {
                self.configureAudioSession()
                self.speakText(text)
            }) {
                Text("話して!")
                    .font(.title)
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }
            .onAppear {
                self.startMonitoringShakeGesture()
            }
            .onDisappear {
                self.stopMonitoringShakeGesture()
            }
        }
    }

    func configureAudioSession() {
        let audioSession = AVAudioSession.sharedInstance()
        do {
            try audioSession.setCategory(.playback, mode: .spokenAudio, options: [])
            try audioSession.setActive(true, options: [])
        } catch {
            print("Failed to configure audio session: \(error.localizedDescription)")
        }
    }

    func speakText(_ text: String) {
        let utterance = AVSpeechUtterance(string: text)
        utterance.voice = AVSpeechSynthesisVoice(language: "ja-JP")
        speechSynthesizer.speak(utterance)
    }

    func startMonitoringShakeGesture() {
        guard motionManager.isAccelerometerAvailable else { return }
        motionManager.accelerometerUpdateInterval = 0.1

        motionManager.startAccelerometerUpdates(to: OperationQueue.current!) { (data, error) in
            guard let data = data, error == nil else { return }
            if abs(data.acceleration.x) > 2.5 || abs(data.acceleration.y) > 2.5 || abs(data.acceleration.z) > 2.5 {
                self.configureAudioSession()
                self.speakText(text)
            }
        }
    }

    func stopMonitoringShakeGesture() {
        motionManager.stopAccelerometerUpdates()
    }
}

このコードは、入力されたテキストを話す機能と、スマホを振るとテキストを話す機能を含んでいます。テキストフィールドが追加され、startMonitoringShakeGesture()およびstopMonitoringShakeGesture()を使って、画面が表示される時と消える時にシェイクジェスチャーの監視を開始および停止します。

プロンプト

ボタンをクリックしたら「今日は新宿で映画を見よう」と話して、スマホを振ったらテキストフィールドのテキストを話すように変更して。

返答

以下のコードは、ボタンをクリックすると「今日は新宿で映画を見よう」と話し、スマホを振るとテキストフィールドに入力された言葉を話すように変更されています。

import SwiftUI
import AVFoundation
import CoreMotion

struct ContentView: View {
    @State private var speechSynthesizer = AVSpeechSynthesizer()
    @State private var motionManager = CMMotionManager()
    @State private var text = ""

    var body: some View {
        VStack {
            TextField("ここにテキストを入力してください", text: $text)
                .padding()
                .textFieldStyle(RoundedBorderTextFieldStyle())

            Button(action: {
                self.configureAudioSession()
                self.speakText("今日は新宿で映画を見よう")
            }) {
                Text("話して!")
                    .font(.title)
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }
            .onAppear {
                self.startMonitoringShakeGesture()
            }
            .onDisappear {
                self.stopMonitoringShakeGesture()
            }
        }
    }

    func configureAudioSession() {
        let audioSession = AVAudioSession.sharedInstance()
        do {
            try audioSession.setCategory(.playback, mode: .spokenAudio, options: [])
            try audioSession.setActive(true, options: [])
        } catch {
            print("Failed to configure audio session: \(error.localizedDescription)")
        }
    }

    func speakText(_ text: String) {
        let utterance = AVSpeechUtterance(string: text)
        utterance.voice = AVSpeechSynthesisVoice(language: "ja-JP")
        speechSynthesizer.speak(utterance)
    }

    func startMonitoringShakeGesture() {
        guard motionManager.isAccelerometerAvailable else { return }
        motionManager.accelerometerUpdateInterval = 0.1

        motionManager.startAccelerometerUpdates(to: OperationQueue.current!) { (data, error) in
            guard let data = data, error == nil else { return }
            if abs(data.acceleration.x) > 2.5 || abs(data.acceleration.y) > 2.5 || abs(data.acceleration.z) > 2.5 {
                self.configureAudioSession()
                self.speakText(text)
            }
        }
    }

    func stopMonitoringShakeGesture() {
        motionManager.stopAccelerometerUpdates()
    }
}

この変更により、ボタンをクリックすると「今日は新宿で映画を見よう」と話し、スマホを振るとテキストフィールドに入力された言葉を話すようになります。

XcodeでiPhoneアプリを作る

プロジェクトの作成

Xcodeを起動してTalkToMe-2という名前のiOS Appプロジェクトを作ります。InterfaceはSwiftUIでLanguageはSwiftにします。

swiftコードの貼り付け

GPT-4が作ってくれたswiftのコードをContentView.swiftに貼り付けます。

調整としてstartMonitoringShakeGestureの中の2.5をすべて2.0に変更します。

実行

実行結果はこの通り。下の画像をクリックしてYouTubeデモビデオを見てください。

iPhoneアプリ