Visual_Novel_iOS/crush/Crush/Src/Modules/Chat/Model/SessionBaseModel.swift

188 lines
6.1 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// SessionBaseModel.swift
// Crush
//
// Created by Leon on 2025/8/18.
//
import UIKit
import Foundation
import NIMSDK
protocol SessionCellContentDelegate {
/// contentView
func contentSize(model: SessionBaseModel) -> CGSize
/// cell(
func cellInsets(model: SessionBaseModel) -> UIEdgeInsets
/// contentViewbubble
func contentInsets(model: SessionBaseModel) -> UIEdgeInsets
/// contentView false true
func onlyShowContent(model: SessionBaseModel) -> Bool
/// conten View
func contentViewClass(model: SessionBaseModel) -> IMContentBaseView.Type
}
enum SessionCellType: String, Codable {
case unknown
case text //
case aimsg // AI Msg
case image //
case timeStamp //
case create //
case keyword //
case tips //
case gift //
case phonecall // im phone call
case aiLoading
}
class SessionBaseModel: CustomStringConvertible, CustomDebugStringConvertible{
/// content
static let maxBubbleContentWidth = floor(UIScreen.width * 0.65)
/// content
static let maxContentWidth = UIScreen.width - 32
var cellType: SessionCellType = .unknown
/// Seconds timestam;
var timeStamp: TimeInterval = 0
var v2msg: V2NIMMessage?
/// message
var baseRemoteInfo: IMBaseRemoteInfo?
/// model cellcell NO
var isDeriveModel = false
/// view
var shouldShowCardView = false
/// tips
var shouldShowTips = false
///
var shouldShowLeft = false
/// YES
var shouldShowBubble = true
///
var cacheCellHeight: CGFloat = 0
/// content
var config: IMContentBaseConfig!
var speechModel : SpeechModel?
var autoPlayAudioOnce: Bool = false
var autoPlayAlreadyPlayed : Bool = false //
///
public func clearCacheData() {
cacheCellHeight = 0
}
public func cellHeight() -> CGFloat {
if cacheCellHeight > 0 {
return cacheCellHeight
}
// content
let size = config.contentSize(model: self)
let cellInsets = config.cellInsets(model: self)
let contentInsets = config.contentInsets(model: self)
//
let height: CGFloat = size.height + cellInsets.top + cellInsets.bottom + contentInsets.top + contentInsets.bottom
cacheCellHeight = height
return height
}
// MARK: Audio About
func prepareAudio(info: IMAIUserInfo?, completion:((_ model: SpeechModel?)-> Void)?){
guard cellType == .aimsg, let text = v2msg?.text, text.count > 0, let voiceType = info?.voiceType else{
return
}
guard AudioPlayTool.audioChannelFreeToUse() else{
dlog("Audio Channel 不可用")
return
}
if let path = self.speechModel?.path, path.count > 0 {
completion?(self.speechModel)
return
}
let saywords = String.removeBracketContents(from: text)
guard saywords.count > 0 else{
return
}
let speechRate = info?.dialogueSpeechRate ?? "0"
let loudnessRate = info?.dialoguePitch ?? "0"
var params = [String: Any]()
params.updateValue(saywords, forKey: "text")
params.updateValue(voiceType, forKey: "voiceType")
params.updateValue(speechRate, forKey: "speechRate")
params.updateValue(loudnessRate, forKey: "pitchRate")
if let aiId = IMAIViewModel.shared.aiIMInfo?.aiId{
params.updateValue(aiId, forKey: "aiId")
}
AICowProvider.request(.voiceTts(params: params), modelType: String.self) {[weak self] result in
switch result {
case .success(let model):
if let audioString = model{
self?.speechModel = SpeechModel.modelWithBase64String(audioString)
//self?.speechModel?.refreshPath(path: audioString)
completion?(self?.speechModel)
}
case .failure:
completion?(nil)
}
}
}
// MARK: - Static
// MARK: Equatable
static func == (lhs: SessionBaseModel, rhs: SessionBaseModel) -> Bool {
return lhs === rhs
}
///
public static func getContentConfigClass(type: SessionCellType) -> IMContentBaseConfig.Type {
switch type {
case .unknown:
return IMContentBaseConfig.self
case .text:
return IMTextContentConfig.self
case .aimsg:
return IMAIMsgContentConfig.self
case .timeStamp:
return IMTimeStampContentConfig.self
case .image:
return IMImageContentConfig.self
case .tips, .create, .keyword:
return IMTipsContentConfig.self
case .gift:
return IMGiftContentConfig.self
case .phonecall:
return IMPhoneCallConfig.self
case .aiLoading:
return IMAIMsgLoadingConfig.self
// default:
// return IMContentBaseConfig.self
}
}
// MARK: - Other Debug
var description: String {
var attchmentString = ""
if let attchmentRaw = v2msg?.attachment?.raw{
attchmentString = attchmentRaw
}
var icon = (v2msg?.isSelf ?? false) ? "✉️" :"💌"
return "\(icon)[\(cellType.rawValue)] 『\(v2msg?.text ?? "-")』raw:\(attchmentString)"
}
var debugDescription: String {
return "[\(cellType.rawValue)] 『\(v2msg?.text ?? "-")"
}
}