101 lines
3.3 KiB
Swift
101 lines
3.3 KiB
Swift
//
|
||
// 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) {
|
||
// 处理离线授权信息,如果需要
|
||
}
|
||
}
|