115 lines
4.1 KiB
Swift
115 lines
4.1 KiB
Swift
|
|
//
|
|||
|
|
// IMHelperUtil.swift
|
|||
|
|
// Crush
|
|||
|
|
//
|
|||
|
|
// Created by Leon on 2025/8/31.
|
|||
|
|
//
|
|||
|
|
|
|||
|
|
import Foundation
|
|||
|
|
|
|||
|
|
// MARK: - IMHelperUtil
|
|||
|
|
class IMHelperUtil{
|
|||
|
|
static func getAIIdByConversationId(_ conversationId: String?) -> Int?{
|
|||
|
|
guard let imConversationId = conversationId else{return nil}
|
|||
|
|
|
|||
|
|
let stings = imConversationId.components(separatedBy: "|")
|
|||
|
|
guard let last = stings.last else{return nil}
|
|||
|
|
// let accountId = last
|
|||
|
|
let strings2 = last.components(separatedBy:"@")
|
|||
|
|
if let userIdStr = strings2.first {
|
|||
|
|
if let userid = Int(userIdStr) {
|
|||
|
|
return userid
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// MARK: - IMAudioHelper
|
|||
|
|
class IMAudioHelper{
|
|||
|
|
/// 提取用于语音的文本(去除括号内容和 emoji)
|
|||
|
|
func extractTextForVoice(_ text: String) -> String {
|
|||
|
|
var result = text
|
|||
|
|
|
|||
|
|
// 去除括号内容(中英文括号)
|
|||
|
|
let bracketPattern = #"\(.*?\)|(.*?)"#
|
|||
|
|
if let regex = try? NSRegularExpression(pattern: bracketPattern, options: []) {
|
|||
|
|
result = regex.stringByReplacingMatches(in: result, options: [], range: NSRange(location: 0, length: result.utf16.count), withTemplate: "")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 去除 emoji
|
|||
|
|
// 使用 unicode 范围匹配 emoji
|
|||
|
|
let emojiPattern = "[\\p{Emoji}]"
|
|||
|
|
if let regex = try? NSRegularExpression(pattern: emojiPattern, options: []) {
|
|||
|
|
result = regex.stringByReplacingMatches(in: result, options: [], range: NSRange(location: 0, length: result.utf16.count), withTemplate: "")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return result.trimmingCharacters(in: .whitespacesAndNewlines)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// 计算文本的预估音频时长
|
|||
|
|
/// - Parameters:
|
|||
|
|
/// - text: 文本内容
|
|||
|
|
/// - speechRate: 语速设置 (-50 到 50,默认为 0)
|
|||
|
|
/// - baseWordsPerMinute: 基础语速(每分钟字数),默认为 200
|
|||
|
|
/// - Returns: 预估的音频时长(秒,TimeInterval)
|
|||
|
|
func calculateAudioDuration(
|
|||
|
|
text: String,
|
|||
|
|
speechRate: Int = 0,
|
|||
|
|
baseWordsPerMinute: Double = 200.0
|
|||
|
|
) -> TimeInterval {
|
|||
|
|
guard !text.isEmpty else { return 0 }
|
|||
|
|
|
|||
|
|
let voiceText = extractTextForVoice(text)
|
|||
|
|
guard !voiceText.isEmpty else { return 0 }
|
|||
|
|
|
|||
|
|
// 中文字符数
|
|||
|
|
let chineseRegex = try! NSRegularExpression(pattern: "[\\u4e00-\\u9fff]")
|
|||
|
|
let chineseCharCount = chineseRegex.numberOfMatches(in: voiceText, range: NSRange(location: 0, length: voiceText.utf16.count))
|
|||
|
|
|
|||
|
|
// 英文单词数(先去掉中文,再按单词匹配)
|
|||
|
|
let textWithoutChinese = chineseRegex.stringByReplacingMatches(in: voiceText, range: NSRange(location: 0, length: voiceText.utf16.count), withTemplate: " ")
|
|||
|
|
let wordRegex = try! NSRegularExpression(pattern: "\\b\\w+\\b")
|
|||
|
|
let englishWordCount = wordRegex.numberOfMatches(in: textWithoutChinese, range: NSRange(location: 0, length: textWithoutChinese.utf16.count))
|
|||
|
|
|
|||
|
|
let totalWordCount = chineseCharCount + englishWordCount
|
|||
|
|
if totalWordCount == 0 { return 0 }
|
|||
|
|
|
|||
|
|
// 根据语速调整基础语速
|
|||
|
|
let speedMultiplier = 1.0 + (Double(speechRate) / 100.0) // -50 → 0.5, 50 → 1.5
|
|||
|
|
let adjustedWordsPerMinute = baseWordsPerMinute * speedMultiplier
|
|||
|
|
|
|||
|
|
// 计算时长(分钟 → 秒)
|
|||
|
|
let durationInMinutes = Double(totalWordCount) / adjustedWordsPerMinute
|
|||
|
|
let durationInSeconds = durationInMinutes * 60.0
|
|||
|
|
|
|||
|
|
return max(0.5, durationInSeconds)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// /// 格式化音频时长显示
|
|||
|
|
// /// - Parameter durationInSeconds: 时长(秒)
|
|||
|
|
// /// - Returns: 格式化的时长字符串,如 "2''" 或 "1'23''"
|
|||
|
|
// func formatAudioDuration(_ durationInSeconds: Double) -> String {
|
|||
|
|
// if durationInSeconds < 1 {
|
|||
|
|
// return "1''"
|
|||
|
|
// }
|
|||
|
|
//
|
|||
|
|
// let totalSeconds = Int(round(durationInSeconds))
|
|||
|
|
//
|
|||
|
|
// if totalSeconds < 60 {
|
|||
|
|
// return "\(totalSeconds)''"
|
|||
|
|
// }
|
|||
|
|
//
|
|||
|
|
// let minutes = totalSeconds / 60
|
|||
|
|
// let seconds = totalSeconds % 60
|
|||
|
|
//
|
|||
|
|
// if seconds == 0 {
|
|||
|
|
// return "\(minutes)'"
|
|||
|
|
// }
|
|||
|
|
//
|
|||
|
|
// return String(format: "%d'%02d''", minutes, seconds)
|
|||
|
|
// }
|
|||
|
|
|
|||
|
|
}
|