You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中实现按钮点击同时触发JokesAPI文本获取与Google Text-To-Speech语音合成的技术问询

解决方案:实现按钮点击时获取笑话并转换为语音

首先得指出你现有ChatBotAPI里的几个关键问题:Google Text-to-Speech的API端点不正确,而且请求方式应该是POST(需要提交文本、语音配置等参数),不是你当前使用的GET请求。咱们一步步修正并实现完整功能:


步骤1:修复Google TTS API的调用逻辑

替换原有的ChatBotAPI实现,改成符合Google TTS API要求的POST请求,同时处理音频数据的解码与播放:

import Foundation
import AVFoundation

class ChatBotAPI {
    private let API_KEY = "你的Google API密钥" // 替换成你实际的API密钥
    private let audioSession = AVAudioSession.sharedInstance()
    
    // 将文本转换为语音并播放
    func convertTextToSpeech(text: String, completion: @escaping (Bool) -> Void) {
        // 构造Google TTS要求的请求体
        let requestBody: [String: Any] = [
            "input": ["text": text],
            "voice": [
                "languageCode": "en-US",
                "name": "en-US-Standard-C" // 可根据需求更换语音模型
            ],
            "audioConfig": [
                "audioEncoding": "MP3" // 指定音频编码格式
            ]
        ]
        
        guard let url = URL(string: "https://texttospeech.googleapis.com/v1/text:synthesize?key=\(API_KEY)") else {
            completion(false)
            return
        }
        
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        
        // 序列化请求体
        do {
            request.httpBody = try JSONSerialization.data(withJSONObject: requestBody)
        } catch {
            print("请求体序列化失败:\(error)")
            completion(false)
            return
        }
        
        let task = URLSession.shared.dataTask(with: request) { [weak self] data, response, error in
            guard let self = self else { return }
            
            if let error = error {
                print("API请求错误:\(error.localizedDescription)")
                completion(false)
                return
            }
            
            guard let data = data else {
                print("无返回数据")
                completion(false)
                return
            }
            
            // 解析Google TTS的响应(返回base64编码的音频内容)
            do {
                let ttsResponse = try JSONDecoder().decode(TTSResponse.self, from: data)
                guard let audioData = Data(base64Encoded: ttsResponse.audioContent) else {
                    print("音频数据解码失败")
                    completion(false)
                    return
                }
                
                // 播放解码后的音频
                self.playAudio(from: audioData)
                completion(true)
            } catch {
                print("响应解析失败:\(error)")
                completion(false)
            }
        }
        task.resume()
    }
    
    // 播放音频数据
    private func playAudio(from data: Data) {
        do {
            // 配置音频会话
            try audioSession.setCategory(.playback, mode: .default)
            try audioSession.activate()
            
            let audioPlayer = try AVAudioPlayer(data: data)
            audioPlayer.play()
        } catch {
            print("音频播放失败:\(error)")
        }
    }
}

// 对应Google TTS的响应模型
struct TTSResponse: Decodable {
    let audioContent: String
}

步骤2:修改按钮点击事件,串联两个操作

在你的ViewController里,先调用fetchJokes获取笑话文本,拿到有效文本后再触发语音合成:

// 假设你的fetchJokes方法已实现,这里补充带completion的版本(用于异步返回笑话文本)
func fetchJokes(completion: @escaping (String?, Error?) -> Void) {
    // 替换为你实际的JokesAPI端点
    guard let url = URL(string: "https://api.your-jokes-source.com/random-joke") else {
        completion(nil, NSError(domain: "InvalidURL", code: 0, userInfo: [NSLocalizedDescriptionKey: "无效的笑话API地址"]))
        return
    }
    
    URLSession.shared.dataTask(with: url) { data, response, error in
        if let error = error {
            completion(nil, error)
            return
        }
        
        guard let data = data else {
            completion(nil, NSError(domain: "NoData", code: 0, userInfo: [NSLocalizedDescriptionKey: "未获取到笑话数据"]))
            return
        }
        
        // 解析JokesAPI的响应(替换为你实际的数据模型)
        do {
            let jokeResponse = try JSONDecoder().decode(Joke.self, from: data)
            completion(jokeResponse.content, nil)
        } catch {
            completion(nil, error)
        }
    }.resume()
}

// 按钮点击事件
@IBAction func didPressBtn() {
    // 1. 先异步获取笑话文本
    fetchJokes { [weak self] jokeText, error in
        guard let self = self else { return }
        
        if let error = error {
            print("获取笑话失败:\(error.localizedDescription)")
            // 这里可以添加UI提示,比如弹出alert告诉用户失败原因
            return
        }
        
        guard let jokeText = jokeText, !jokeText.isEmpty else {
            print("未获取到有效笑话内容")
            return
        }
        
        // 2. 拿到笑话后,调用Google TTS转语音
        let ttsAPI = ChatBotAPI()
        ttsAPI.convertTextToSpeech(text: jokeText) { success in
            DispatchQueue.main.async {
                // 可以在这里添加UI反馈,比如按钮状态变化、提示文本
                if success {
                    print("语音合成并播放成功")
                } else {
                    print("语音合成失败")
                }
            }
        }
    }
}

// 假设你的JokesAPI数据模型
struct Joke: Decodable {
    let content: String // 替换为你API返回的笑话字段名
}

关键说明

  • API端点修正:Google TTS的正确合成端点是https://texttospeech.googleapis.com/v1/text:synthesize,必须携带你的API密钥作为URL参数
  • 请求方式:必须使用POST请求,提交包含input(文本内容)、voice(语音配置)、audioConfig(音频格式)的JSON请求体
  • 音频处理:Google TTS返回的是base64编码的音频字符串,需要解码成Data后用AVAudioPlayer播放,同时要配置好音频会话确保播放正常
  • 异步串联:按钮点击时先异步获取笑话,拿到结果后再触发语音合成,保证两个操作按顺序执行(先有文本,再转语音)

内容的提问来源于stack exchange,提问作者Richard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 06:51:36