// // RolePublishController.swift // Crush // // Created by Leon on 2025/7/20. // import UIKit import Combine import TZImagePickerController /// 生成角色页面 /// 选参考图 class RolePublishController: RoleCreateBaseController { weak var viewModel: RoleCreateViewModel! // @Published var image: UIImage? private var cancellables = Set() var isAllImagesOK: Bool = false override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. setupViews() setupDatas() setupEvents() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) disabledFullScreenPan() } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) enabledFullScreenPan() } private func setupViews() { container.container.scrollView.delegate = self } private func setupDatas(){ // if let editAIInfo = viewModel.editAIInfo, let url = editAIInfo.imageUrl{ // var usingImage = AIUserImageQuery() // usingImage.imageUrl = url // usingImage.status = .completed // container.appearanceResult.usingFigureImage = usingImage // } if let editAIInfo = viewModel.editAIInfo{ viewModel.requestParams.aiUserExt?.imageDesc = editAIInfo.aiUserExt?.imageDesc viewModel.requestParams.aiUserExt?.imageStyleCode = editAIInfo.aiUserExt?.imageStyleCode } // -- 文案 var title = "Create" var bottomButtonTitle = "Create" if viewModel.editAIInfo != nil { title = "Modify" bottomButtonTitle = "Modify" } navigationView.alpha0Title = title container.titleView.title = title container.bottomButton.setTitle(bottomButtonTitle, for: .normal) } private func setupEvents(){ container.backButton.addTarget(self, action: #selector(tapBackButton), for: .touchUpInside) container.bottomButton.addTarget(self, action: #selector(bottomButtonTapped), for: .touchUpInside) container.generate1Button.addTarget(self, action: #selector(tapAIGeneratedIntroductionButton), for: .touchUpInside) container.appearanceResult.generateButton.addTarget(self, action: #selector(tapRegenerateFigureButton), for: .touchUpInside) container.uploadImageView.bgTapBlock = {[weak self] in //self?.pickAppearance() self?.goCreateAIGeneratePics() } viewModel.$batchNo.sink {[weak self] result in self?.container.showQueryGeneratedImages(generating: !result.isEmpty) self?.loadingGeneratingResults(batchNo: result) }.store(in: &cancellables) container.$introductionContent.sink {[weak self] string in self?.viewModel.requestParams.introduction = string }.store(in: &cancellables) if viewModel.editAIInfo == nil{ doGenerate() }else{ restoreEditInfo(aiInfo: viewModel.editAIInfo) } } private func restoreEditInfo(aiInfo: AIUserModel?) { guard let info = aiInfo else { return } container.privacyPublic = (info.permission ?? 2) == 1 container.introductionContent = info.introduction ?? "" container.showQueryGeneratedImages(generating: true) // 图片 let last = AIUserImageQuery() last.imageUrl = info.imageUrl last.status = .completed container.appearanceResult.usingFigureImage = last container.appearanceResult.selectImageUrl = info.imageUrl ?? "" //头像 let photo = UploadPhotoM() photo.setupValidImageUrl(url: info.headImg) container.avatarModel = photo } // MARK: - Functions func loadingGeneratingResults(batchNo : String?){ if isAllImagesOK { return } guard let queryNo = batchNo, queryNo.isEmpty == false else{ dlog("❌batchNo is nil") return } container.appearanceResult.setupLastGenerateProcessStart() dlog("📖查询图片生成中...") AICowProvider.request(.imageGeneratedQuery(batchNo: queryNo), modelType: [AIUserImageQuery].self) { [weak self] result in switch result { case .success(let success): guard let queryDatas = success else{ return } self?.container.appearanceResult.config(success) var ok = true if(queryDatas.count < 6){ ok = false }else{ for per in queryDatas { if per.status == .pending{ ok = false } } } self?.isAllImagesOK = ok if ok == false{ DispatchQueue.main.asyncAfter(deadline: .now() + 6) {[weak self] in self?.loadingGeneratingResults(batchNo: self?.viewModel.batchNo) } }else{ // ✅ self?.container.appearanceResult.setupLastGenerateProcessEnd() } case .failure: break } } } /// 创建时免费生成图像 private func goCreateAIGeneratePics(){ let vc = RoleFigureGenerateController() vc.viewModel = viewModel navigationController?.pushViewController(vc, animated: true) vc.generatedBatchNoAction = {[weak self] batchNo, imageStyleCode,description, referenceBase64 in self?.viewModel.requestParams.aiUserExt?.imageStyleCode = imageStyleCode self?.viewModel.requestParams.aiUserExt?.imageDesc = description // 新图片 if batchNo.count > 0{ self?.isAllImagesOK = false self?.container.appearanceResult.config([], reset: true) // 先loading着 self?.container.showQueryGeneratedImages(generating: true) self?.loadingGeneratingResults(batchNo: batchNo) } } } /// 编辑额外生成图片 private func goEditAIRegeneratePics(){ let vc = RolePhotoGenerateController(type: .figure) vc.aiId = viewModel.requestParams.aiId vc.introduction = container.introductionContent vc.sex = viewModel.requestParams.sex vc.birthdayString = viewModel.requestParams.birthday vc.preSelectstyleCode = viewModel.requestParams.aiUserExt?.imageStyleCode // "IS0020"// vc.prePhotoDesc = viewModel.requestParams.aiUserExt?.imageDesc presentNaviRootVc(vc: vc) vc.confirmSelectAction = {[weak self] imageStyleCode, desc, imgs in self?.viewModel.requestParams.aiUserExt?.imageStyleCode = imageStyleCode self?.viewModel.requestParams.aiUserExt?.imageDesc = desc guard let image = imgs?.first else {return} self?.container.loadDataAndSelect(image) } } private func judgeAlertToPublishNewAIRole(){ // Alert.showAIRoleCreateSuccessAlert { // Hud.hideIndicator() // } confirmAction: {[weak self] in // self?.doPublishRole() // } if viewModel.editAIInfo != nil{ // 编辑AI doPublishRole() }else{ // 创建AI Role if UserCore.shared.user?.canCreateAIRole() ?? false{ // 能创建 Alert.showAIRoleCreateSuccessAlert { Hud.hideIndicator() } confirmAction: {[weak self] in self?.doPublishRole() } } else { if UserCore.shared.user?.isMember == false{ // 去订VIP Hud.hideIndicator() let sheet = VIPSubscribeSheet() sheet.show() }else { // #warning("是否主动Alert 到底创建限制") Alert.showAIRoleCreateSuccessAlert { Hud.hideIndicator() } confirmAction: {[weak self] in self?.doPublishRole() } } } } } private func doPublishRole(){ //#warning("test") // guard let aiId = viewModel.requestParams.aiId else{ // return // } // AppRouter.goBackRootController(jumpIndex: .me) // DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) { // AppRouter.goChatVC(aiId: aiId) // AppRouter.alertCreateAlbumsToRoleHome(aiId: aiId) // } // view.hideToastActivity() // return // close(dismissFirst: true) // AppRouter.goBackRootController(jumpIndex: .me) // close(dismissFirst: true) { // let vc = UIWindow.getTopViewController() // if let current = UIWindow.getTopViewController(), current.isKind(of: RoleHomePagerController.self){ // // Stay in RoleHomePagerController // }else{ // AppRouter.goBackRootController(jumpIndex: .me) // } // dlog("🔥current vc: \(String(describing: vc))") // } // return guard let avatar = container.avatarModel?.remoteFullPath else { dlog("invalid ai role avatar") return } viewModel.requestParams.headImg = avatar viewModel.requestParams.introduction = container.introductionContent viewModel.requestParams.permission = container.privacyPublic ? 1 : 2 var params = viewModel.requestParams.toNonNilDictionary() let editAIInfo = viewModel.editAIInfo params.updateValue(container.appearanceResult.selectImageUrl, forKey: "imageUrl") //dlog("🔥当前params: \(params)") //Hud.showIndicator() AIRoleProvider.request(.aiUserCreateEdit(params: params), modelType: AICreateResponse.self) {[weak self] result in Hud.hideIndicator() switch result { case let .success(success): NotificationCenter.post(name: .aiRoleCreatedOrDelete) NotificationCenter.post(name: .aiRoleInfoChanged) if editAIInfo != nil{ dlog("编辑AI 退出") // 编辑保存成功 self?.close(dismissFirst: true) { // _ = UIWindow.getTopViewController() if let current = UIWindow.getTopViewController(), current.isKind(of: RoleHomePagerController.self){ // Stay in RoleHomePagerController }else{ AppRouter.goBackRootController(jumpIndex: .me) } } }else{ // 新建用户 dlog("新建AI 退出") AppRouter.goBackRootController(jumpIndex: .me) DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) { AppRouter.goChatVC(aiId: success?.aiId) AppRouter.alertCreateAlbumsToRoleHome(aiId: success?.aiId) } } case .failure: break } } } @objc private func tapAIGeneratedIntroductionButton(){ if container.introductionContent.count > 0{ let alert = Alert(title: "内容覆盖", text: "AI创建的内容会覆盖你已经填写的内容,请确认是否继续?") let action1 = AlertAction(title: "继续", actionStyle: .confirm) {[weak self] in self?.doGenerate() } let action2 = AlertAction(title: "Cancel", actionStyle: .cancel) alert.addAction(action1) alert.addAction(action2) alert.show() }else{ doGenerate() } } private func doGenerate(){ var params = viewModel.requestParams.toPartialDictionary(keys: ["nickname", "sex", "birthday", "characterCode", "tagCode", "introduction"]) /// 形象描述 params.updateValue("GEN_INTRODUCTION", forKey: "ptType") if container.introductionContent.count > 0{ params.updateValue(container.introductionContent, forKey: "content") } if let dialogue = viewModel.requestParams.aiUserExt?.dialogueStyle{ params.updateValue(dialogue, forKey: "dialogue") } if let figure = viewModel.requestParams.aiUserExt?.profile{ params.updateValue(figure, forKey: "figure") } Hud.showIndicator() AICowProvider.request(.aiContentGenerate(params: params), modelType: AIUserContentGenResponse.self) {[weak self] result in Hud.hideIndicator() switch result { case .success(let success): if let content = success?.content{ self?.container.contentAIGenerated = content } case .failure: return } } } @objc private func tapRegenerateFigureButton(){ // 尝试重新生成图片 if viewModel.requestParams.aiId != nil{ goEditAIRegeneratePics() }else{ goCreateAIGeneratePics() } } @objc private func bottomButtonTapped(){ // 头像是否已上传? if container.avatarModel?.remoteFullPath != nil{ Hud.showIndicator() judgeAlertToPublishNewAIRole() }else{ // 头像上传... guard let photo = container.avatarModel else { return } Hud.showIndicator() CloudStorage.shared.s3BatchAddPhotos([photo], bucket: .ROLE) {[weak self] result in if result{ //self?.doPublishRole() self?.judgeAlertToPublishNewAIRole() }else{ Hud.hideIndicator() } } } } @objc private func tapBackButton() { close() } } extension RolePublishController: UIScrollViewDelegate{ func scrollViewDidScroll(_ scrollView: UIScrollView) { NaviAlphaHandle.changeNaviTitleAlpha(scrollView: scrollView, titleLabel: navigationView.titleLabel) } }