// // TTSManager.swift // AIGrammar // // Created by oscar on 2024/8/29. // import Foundation import AVFAudio class TTSManager: NSObject, QCloudTTSEngineDelegate { static let shared = TTSManager() // 单例模式 private var synthesizer: QCloudTTSEngine? private var audioPlayer: AVAudioPlayer? private var onSuccess: (() -> Void)? private var onFailure: ((String) -> Void)? // 设定个非会员每天的使用上限 private let dailyLimit = 100 private let userDefaults = UserDefaults.standard private override init() { super.init() setupSynthesizer() } private func setupSynthesizer() { synthesizer = QCloudTTSEngine.getShareInstance() as? QCloudTTSEngine synthesizer?.engineInit(.TTS_MODE_ONLINE, delegate: self) synthesizer?.setOnlineAuthParam(1300230265, secretId: "AKIDmcetGuREGiDOBeIJVm4Kd1ZOUqFdD1CQ", secretKey: "UwhP3XrJfrx8IQUfpMvRznYTK5lM4rhR", token: nil) } func synthesizeAndPlay(text: String, isVIP: Bool, onSuccess: @escaping () -> Void, onFailure: @escaping (String) -> Void) { if !isVIP { let currentDate = Date() let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd" let currentDateString = dateFormatter.string(from: currentDate) let lastDateString = userDefaults.string(forKey: "LastCallDate") ?? "" var callCount = userDefaults.integer(forKey: "CallCount") if currentDateString != lastDateString { // 如果日期变化,重置计数器 callCount = 0 userDefaults.set(currentDateString, forKey: "LastCallDate") } logger.info("nonVIP check limit, cnt: \(callCount), limit: \(dailyLimit)") if callCount >= dailyLimit { onFailure("Daily limit reached. Please try again tomorrow.") return } else { // 增加调用计数 callCount += 1 userDefaults.set(callCount, forKey: "CallCount") } } guard let synthesizer = synthesizer else { onFailure("Synthesizer is not initialized.") return } self.onSuccess = onSuccess self.onFailure = onFailure let error = synthesizer.synthesize(text, utteranceId: "test") if let error = error { onFailure("Synthesis error: \(error)") } } // MARK: - QCloudTTSEngineDelegate func onSynthesizeData(_ data: Data?, utteranceId: String?, text: String?, engineType: Int, requestId: String?, respJson: String?) { guard let data = data else { onFailure?("Synthesis failed with no data.") return } do { audioPlayer = try AVAudioPlayer(data: data) audioPlayer?.prepareToPlay() audioPlayer?.play() onSuccess?() } catch { onFailure?("Failed to play synthesized audio: \(error)") } } func onError(_ error: TtsError?, utteranceId: String?, text: String?) { if let error = error { onFailure?("Synthesis error: \(error)") } } func onOfflineAuthInfo(_ OfflineAuthInfo: QCloudOfflineAuthInfo) { // 处理离线授权信息,如果需要 } }