ai-clone/frontend-ai/unpackage/dist/build/mp-weixin/pages/video-call-new/video-call-new.js
2026-03-06 18:05:51 +08:00

2 lines
46 KiB
JavaScript
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.

"use strict";const e=require("../../common/vendor.js"),o=require("../../config/api.js"),i=require("../../utils/payment.js"),t={components:{PaymentModal:()=>"../../components/PaymentModal.js"},data:()=>({API_BASE:o.API_BASE,loadOptions:null,lastUserId:null,loading:!1,videos:[],selectedVideoId:"",selectedVideoName:"",selectedVideoUrl:"",selectedPhotoUrl:"",selectedVoiceId:"",selectedDialect:"",selectedLanguageHint:"",selectedLanguageHintLabel:"",languageHintOptions:["中文(zh)","英文(en)","法语(fr)","德语(de)","日语(ja)","韩语(ko)","俄语(ru)"],dialectOptions:["广东话","东北话","甘肃话","贵州话","河南话","湖北话","江西话","闽南话","宁夏话","山西话","陕西话","山东话","上海话","四川话","天津话","云南话"],isConnecting:!1,connectingText:"正在接通...",videoCache:{},downloadingVideos:{},localVideoUrl:"",cacheProgress:{},preCachingInProgress:!1,videoPreloadStatus:{},callStarted:!1,callStatus:"视频通话中",callDuration:"00:00",callStartTime:null,durationTimer:null,messages:[],recognizingText:"",scrollTop:0,isRecording:!1,isProcessing:!1,isSpeaking:!1,processingText:"正在聆听...",recorderManager:null,audioFilePath:"",recordingStartTime:null,autoListen:!1,autoLoopTimer:null,longPressTimer:null,isTouching:!1,stopFallbackTimer:null,stopFallbackRetries:0,stopFallbackActive:!1,vadEnabled:!0,vadVoiceThreshold:.004,vadSilenceMs:600,vadMaxDurationMs:15e3,vadSpeaking:!1,vadSilenceStart:null,vadMaxTimer:null,vadLastSoundTime:null,vadLastFrameTime:null,vadWatchTimer:null,audioContext:null,audioCacheKey:"",currentAudioSrc:"",pendingAudioUrl:"",audioTriedFallback:!1,audioSessionId:0,audioPlayedInSession:!1,audioPlayStartAt:0,audioTriedRedownload:!1,audioTriedRecreateContext:!1,audioPlayInvokedInSession:!1,audioPlayTargetSessionId:0,audioDiagnosedInSession:!1,videoContext:null,audioContextActivated:!1,videoInitialPlayed:!1,processingTimeout:null,showSettingsDialog:!1,dialogMemoryIdentity:"",dialogMemoryInfo:"",dialogMemoryCatchphrase:"",systemPrompt:"",paymentModalData:{show:!1,serviceType:"",serviceName:"",serviceDesc:"",price:0,orderNo:"",paymentTips:"点击确认支付后将开始视频通话"},_paymentResolve:null,_paymentReject:null,_paymentOnSuccess:null,_paymentOnFailed:null}),async onLoad(o){console.log("[VideoCallNew] 页面加载",o),this.loadOptions=o;const i=e.index.getStorageSync("userId");this.lastUserId=i,await this.loadVideoCache(),o&&o.videoId?(this.selectedVideoId=o.videoId,this.selectedVideoName=decodeURIComponent(o.videoName||"复活视频"),this.selectedVideoUrl=decodeURIComponent(o.videoUrl||""),this.selectedVoiceId=o.voiceId||"",this.selectedDialect="",console.log("[VideoCallNew] 从URL参数加载视频信息"),console.log("[VideoCallNew] 视频ID:",this.selectedVideoId),console.log("[VideoCallNew] 视频名称:",this.selectedVideoName),console.log("[VideoCallNew] 视频URL:",this.selectedVideoUrl),console.log("[VideoCallNew] 音色ID:",this.selectedVoiceId),await this.checkAndLoadLocalVideo(this.selectedVideoId,this.selectedVideoUrl),this.initRecorder(),this.initAudioContext(),this.initVideoContext(),this.startAutoLoop(),setTimeout((()=>{this.startVideoCallDirect()}),300)):(this.loadVideos(),this.initRecorder(),this.initAudioContext(),this.initVideoContext(),this.startAutoLoop())},onShow(){console.log("[VideoCallNew] 页面显示");const o=e.index.getStorageSync("userId");o!==this.lastUserId&&(console.log("[VideoCallNew] 检测到用户切换"),console.log("[VideoCallNew] 上次用户ID:",this.lastUserId,"当前用户ID:",o),this.lastUserId=o),this.callStarted||this.loadOptions&&this.loadOptions.videoId||(console.log("[VideoCallNew] 页面重新显示,刷新视频列表"),this.loadVideos())},onUnload(){this.cleanup()},methods:{isVideoUsableForCall(e){if(!e)return!1;const o=e.edited_video_url||e.videoUrl||e.local_video_path||e.video_url||e.localVideoPath,i=e.voice_id||e.voiceId;return!!o&&!!i},async loadVideos(){this.loading=!0;const o=e.index.getStorageSync("userId")||"",i=e.index.getStorageSync("token")||"";await this.loadVideoCache(),e.index.request({url:`${this.API_BASE}/api/photo-revival/videos`,method:"GET",header:{"X-User-Id":o,Authorization:i?`Bearer ${i}`:""},success:e=>{if(console.log("[VideoCallNew] 视频列表响应:",e.data),200===e.statusCode){let o=[];Array.isArray(e.data)?o=e.data:e.data&&Array.isArray(e.data.data)?o=e.data.data:(e.data&&e.data.videos&&Array.isArray(e.data.videos)||e.data&&e.data.success&&Array.isArray(e.data.videos))&&(o=e.data.videos),this.videos=(o||[]).filter((e=>this.isVideoUsableForCall(e))),console.log("[VideoCallNew] 加载视频列表成功:",this.videos.length)}},fail:o=>{console.error("[VideoCallNew] 加载视频列表失败:",o),e.index.showToast({title:"加载失败",icon:"none"})},complete:()=>{this.loading=!1}})},selectVideo(e){this.selectedVideoId=e.id,this.selectedVideoName=e.name||"复活视频",this.selectedVideoUrl=e.edited_video_url||e.videoUrl||e.local_video_path||e.video_url||e.localVideoPath,this.selectedPhotoUrl=e.photoUrl||e.photo_url||e.photoPath||"",this.selectedVoiceId=e.voice_id||e.voiceId,this.selectedDialect="",this.selectedLanguageHint="",this.selectedLanguageHintLabel="",console.log("[VideoCallNew] 选择视频:",this.selectedVideoId),console.log("[VideoCallNew] 视频URL:",this.selectedVideoUrl),console.log("[VideoCallNew] 照片URL:",this.selectedPhotoUrl),console.log("[VideoCallNew] 音色ID:",this.selectedVoiceId)},async startVideoCall(o){this.selectVideo(o),this.selectedVideoId&&this.selectedVoiceId?this.selectedVideoUrl?(console.log("[VideoCallNew] 准备视频通话视频ID:",this.selectedVideoId),console.log("[VideoCallNew] 视频URL:",this.selectedVideoUrl),await this.checkAndLoadLocalVideo(this.selectedVideoId,this.selectedVideoUrl),i.showPaymentModal(this,i.SERVICE_TYPES.VIDEO_CALL.type,(()=>{this.showCallSettings()}),(e=>{console.error("[Payment] 支付失败:",e)}))):e.index.showToast({title:"视频地址不存在",icon:"none"}):e.index.showToast({title:"该视频无法进行通话",icon:"none"})},async startVideoCallDirect(){return this.selectedVideoId&&this.selectedVoiceId?this.selectedVideoUrl?(console.log("[VideoCallNew] 直接开始视频通话"),console.log("[VideoCallNew] 视频ID:",this.selectedVideoId),console.log("[VideoCallNew] 当前使用URL:",this.localVideoUrl||this.selectedVideoUrl),void i.showPaymentModal(this,i.SERVICE_TYPES.VIDEO_CALL.type,(()=>{this.showCallSettings()}),(o=>{console.error("[Payment] 支付失败:",o),setTimeout((()=>{e.index.navigateBack()}),1e3)}))):(e.index.showToast({title:"视频地址不存在",icon:"none"}),void setTimeout((()=>{e.index.navigateBack()}),1500)):(e.index.showToast({title:"视频信息不完整",icon:"none"}),void setTimeout((()=>{e.index.navigateBack()}),1500))},showCallSettings(){this.dialogMemoryIdentity="",this.dialogMemoryInfo="",this.dialogMemoryCatchphrase="",this.showSettingsDialog=!0},closeSettingsDialog(){this.showSettingsDialog=!1},confirmSettings(){if(console.log("[VideoCallNew] 开始视频通话"),console.log("[VideoCallNew] 使用视频的音色ID:",this.selectedVoiceId),this.showSettingsDialog=!1,this.videoInitialPlayed=!1,this.isConnecting=!0,this.connectingText="正在接通...",this.dialogMemoryIdentity||this.dialogMemoryInfo)if(this.dialogMemoryIdentity){let e=`你是${this.dialogMemoryIdentity},你已经去世。用户正在和你对话。`;e+="\n\n你的性格特点\n\n亲切、真实、克制",e+="\n\n你的行事风格\n\n直接回答不绕弯",e+="\n\n你的语言特点\n\n自然口语语气温和",this.dialogMemoryInfo&&(e+=`\n\n补充设定(请严格遵循):\n\n${this.dialogMemoryInfo}`),e+="\n\n注意不要使用括号包括()和())来描述动作、心理、背景。",e+="\n\n规则\n\n1. 不要虚构不存在的事,不要编造记忆或经历。\n2. 不要回忆以前(除非用户明确提到并且你能基于已有设定回答)。\n3. 不要使用任何称呼(因为用户可能是任何身份)。\n4. 不要使用emoji/颜文字/特殊符号。\n5. 顺应用户话题,亲切回答问题。\n6. 时刻记住自己是逝者。\n7. 每次回复保持在20~50字之间。",this.systemPrompt=e}else{let e="你是一位已经去世的人。用户正在和你对话。";e+="\n\n你的性格特点\n\n亲切、真实、克制",e+="\n\n你的行事风格\n\n直接回答不绕弯",e+="\n\n你的语言特点\n\n自然口语语气温和",this.dialogMemoryInfo&&(e+=`\n\n补充设定(请严格遵循):\n\n${this.dialogMemoryInfo}`),e+="\n\n注意不要使用括号包括()和())来描述动作、心理、背景。",e+="\n\n规则\n\n1. 不要虚构不存在的事,不要编造记忆或经历。\n2. 不要回忆以前(除非用户明确提到并且你能基于已有设定回答)。\n3. 不要使用任何称呼(因为用户可能是任何身份)。\n4. 不要使用emoji/颜文字/特殊符号。\n5. 顺应用户话题,亲切回答问题。\n6. 时刻记住自己是逝者。\n7. 每次回复保持在20~50字之间。",this.systemPrompt=e}else{let e="你是一位已经去世的人。用户正在和你对话。";e+="\n\n你的性格特点\n\n亲切、真实、克制",e+="\n\n你的行事风格\n\n直接回答不绕弯",e+="\n\n你的语言特点\n\n自然口语语气温和",e+="\n\n注意不要使用括号包括()和())来描述动作、心理、背景。",e+="\n\n规则\n\n1. 不要虚构不存在的事,不要编造记忆或经历。\n2. 不要回忆以前(除非用户明确提到并且你能基于已有设定回答)。\n3. 不要使用任何称呼(因为用户可能是任何身份)。\n4. 不要使用emoji/颜文字/特殊符号。\n5. 顺应用户话题,亲切回答问题。\n6. 时刻记住自己是逝者。\n7. 每次回复保持在20~50字之间。",this.systemPrompt=e}console.log("[VideoCallNew] 系统提示词:",this.systemPrompt),this.callStarted=!0,this.startCallTimer(),this.$nextTick((()=>{this.videoContext=e.index.createVideoContext("callVideo",this),console.log("[VideoCallNew] 重新初始化视频上下文"),console.log("[VideoCallNew] 当前视频URL:",this.localVideoUrl||this.selectedVideoUrl)}))},startCallTimer(){this.callStartTime=Date.now(),this.durationTimer=setInterval((()=>{const e=Math.floor((Date.now()-this.callStartTime)/1e3),o=Math.floor(e/60).toString().padStart(2,"0"),i=(e%60).toString().padStart(2,"0");this.callDuration=`${o}:${i}`,e>=600&&(console.log("[VideoCallNew] 通话时长已达10分钟自动挂断"),this.autoEndCall())}),1e3)},initRecorder(){this.recorderManager=e.index.getRecorderManager(),console.log("[VAD] RecorderManager 对象:",this.recorderManager),console.log("[VAD] onFrameRecorded 方法存在:",typeof this.recorderManager.onFrameRecorded),this.recorderManager.onStart((()=>{console.log("[VideoCallNew] 开始录音")})),this.recorderManager.onStop((e=>{console.log("[VideoCallNew] 录音完成:",e.tempFilePath),this.isRecording=!1,this.isTouching=!1,this.longPressTimer&&(clearTimeout(this.longPressTimer),this.longPressTimer=null),this.stopFallbackTimer&&(clearTimeout(this.stopFallbackTimer),this.stopFallbackTimer=null),this.stopFallbackActive=!1,this.stopFallbackRetries=0,this.resetVADState();if((e.duration||Date.now()-(this.recordingStartTime||Date.now()))<400)return console.warn("[VideoCallNew] 录音过短,已忽略"),this.isProcessing=!1,void(this.callStatus="通话中");this.audioFilePath=e.tempFilePath,this.processConversation()})),"function"==typeof this.recorderManager.onFrameRecorded?(console.log("[VAD] ✅ onFrameRecorded 支持,已绑定帧回调"),this.recorderManager.onFrameRecorded((e=>{console.log("[VAD] 🎯 收到帧数据!大小:",e.frameBuffer?e.frameBuffer.byteLength:0,"bytes"),this.vadEnabled&&!this.isProcessing?this.handleVADFrame(e.frameBuffer):console.log("[VAD] VAD已禁用或正在处理跳过")}))):(console.error("[VAD] ❌ onFrameRecorded 不支持VAD功能将无法使用"),console.error("[VAD] recorderManager 类型:",typeof this.recorderManager),console.error("[VAD] 可用方法:",Object.keys(this.recorderManager)),this.vadEnabled=!1),this.recorderManager.onError((o=>{console.error("[VideoCallNew] 录音失败:",o),this.isRecording=!1,this.resetVADState();o.errMsg&&(o.errMsg.includes("permission")||o.errMsg.includes("authorize")||o.errMsg.includes("denied")||o.errMsg.includes("占用"))?e.index.showModal({title:"需要麦克风权限",content:"录音功能需要麦克风权限才能使用。\n\n请前往\n手机设置 → 应用管理 → 时光意境 → 权限管理 → 开启麦克风权限",confirmText:"我知道了",showCancel:!1}):e.index.showToast({title:"录音失败: "+(o.errMsg||"未知错误"),icon:"none",duration:3e3})}))},initVideoContext(){this.videoContext=e.index.createVideoContext("callVideo",this)},initAudioContext(){if(!this.audioContext){this.audioContext=e.index.createInnerAudioContext(),this.audioContext.volume=1;try{this.audioContext.obeyMuteSwitch=!1}catch(o){console.warn("[VideoCallNew] 设置obeyMuteSwitch失败:",o)}console.log("[VideoCallNew] 🔊 音频上下文初始化完成,音量设置为最大"),this.audioContext.onCanplay((()=>{console.log("[VideoCallNew] ✅ 音频已准备好,可以播放"),this.tryPlayAudioForSession("canplay")})),this.audioContext.onEnded((()=>{console.log("[VideoCallNew] AI回复播放完成"),this.isSpeaking=!1,this.callStatus="通话中",this.videoContext&&this.videoContext.pause()})),this.audioContext.onError((i=>{this.isSpeaking&&!this.audioDiagnosedInSession&&this.pendingAudioUrl&&(this.audioDiagnosedInSession=!0,this.diagnoseAudioUrl(this.pendingAudioUrl));const t=!(!i||!(67===i.errCode||i.errMsg&&String(i.errMsg).includes("decode"))),s=!(!this.pendingAudioUrl||this.currentAudioSrc!==this.pendingAudioUrl&&this.audioContext.src!==this.pendingAudioUrl);if(this.isSpeaking&&!this.audioTriedFallback&&t&&s&&this.pendingAudioUrl&&this.audioContext){this.audioTriedFallback=!0,console.warn("[VideoCallNew] 音频播放失败尝试回退本地重试一次。errCode=",i.errCode,"errMsg=",i.errMsg);const e=this.audioSessionId;return void this.downloadAudioTemp(this.pendingAudioUrl).then((i=>{if(e===this.audioSessionId&&i&&this.audioContext&&this.isSpeaking&&i!==this.pendingAudioUrl&&i!==this.currentAudioSrc&&i!==this.audioContext.src){try{this.audioContext.stop()}catch(o){}this.currentAudioSrc=i,this.audioContext.src=i,setTimeout((()=>{if(e===this.audioSessionId&&this.audioContext&&this.isSpeaking)try{this.audioContext.play(),console.log("[VideoCallNew] ✅ 已使用本地音频回退重试播放")}catch(o){}}),150)}}))}if(this.isSpeaking&&t&&!this.audioTriedRecreateContext&&this.audioContext){this.audioTriedRecreateContext=!0;const e=this.audioSessionId,i=this.currentAudioSrc||this.audioContext&&this.audioContext.src||this.pendingAudioUrl;return console.warn("[VideoCallNew] decode fail尝试重建音频上下文并重试一次"),void this.recreateAudioContext().then((()=>{e===this.audioSessionId&&this.audioContext&&this.isSpeaking&&i&&(this.audioContext.src=i,this.currentAudioSrc=i,setTimeout((()=>{if(e===this.audioSessionId&&this.audioContext&&this.isSpeaking)try{this.audioContext.play(),console.log("[VideoCallNew] ✅ 已重建音频上下文并重试播放")}catch(o){}}),200))}))}const a=!!(this.audioContext&&this.audioContext.src&&String(this.audioContext.src).startsWith("wxfile://store_"));if(this.isSpeaking&&t&&!this.audioTriedRedownload&&a&&this.pendingAudioUrl&&this.audioContext){this.audioTriedRedownload=!0;const e=this.audioSessionId;return console.warn("[VideoCallNew] 本地缓存音频解码失败,清缓存并重新下载临时文件重试一次"),void this.clearAudioCacheForUrl(this.pendingAudioUrl).finally((()=>{this.downloadAudioTemp(this.pendingAudioUrl).then((i=>{if(e===this.audioSessionId&&i&&this.audioContext&&this.isSpeaking){try{this.audioContext.stop()}catch(o){}this.currentAudioSrc=i,this.audioContext.src=i,setTimeout((()=>{if(e===this.audioSessionId&&this.audioContext&&this.isSpeaking)try{this.audioContext.play(),console.log("[VideoCallNew] ✅ 已使用重新下载的临时音频重试播放")}catch(o){}}),200)}}))}))}console.error("[VideoCallNew] ❌ 音频播放失败:",JSON.stringify(i)),console.error("[VideoCallNew] 错误详情 - errMsg:",i.errMsg,"errCode:",i.errCode),this.isSpeaking=!1,this.callStatus="通话中",this.isProcessing=!1,e.index.showToast({title:"音频播放失败",icon:"none",duration:2e3}),this.videoContext&&this.videoContext.pause()})),this.audioContext.onPlay((()=>{console.log("[VideoCallNew] ▶️ 音频播放事件触发"),this.audioPlayedInSession=!0,this.audioPlayStartAt=Date.now(),this.videoContext&&this.videoContext.play()})),this.audioContext.onPause((()=>{console.log("[VideoCallNew] ⏸️ 音频暂停事件触发"),this.isSpeaking&&(console.warn("[VideoCallNew] ⚠️ AI说话时音频被暂停尝试恢复播放..."),setTimeout((()=>{if(this.isSpeaking&&this.audioContext)try{this.audioContext.play(),console.log("[VideoCallNew] ✅ 音频已恢复播放")}catch(o){console.error("[VideoCallNew] ❌ 恢复音频播放失败:",o)}}),100))})),this.audioContext.onWaiting((()=>{console.log("[VideoCallNew] ⏳ 音频加载中...")})),this.audioContext.onStop((()=>{console.log("[VideoCallNew] 音频停止事件触发")})),this.audioContext.onWaiting((()=>{console.log("[VideoCallNew] 音频等待加载")})),this.audioContext.onCanplay((()=>{console.log("[VideoCallNew] 音频可以播放"),this.tryPlayAudioForSession("canplay2")}))}},tryPlayAudioForSession(e){const o=this.audioPlayTargetSessionId;if(o&&o===this.audioSessionId&&this.audioContext&&this.isSpeaking&&!this.audioPlayInvokedInSession){this.audioPlayInvokedInSession=!0;try{this.audioContext.play(),console.log("[VideoCallNew] ✅ 已触发音频播放(",e,")")}catch(i){console.error("[VideoCallNew] ❌ 触发音频播放失败(",e,"):",i)}}},recreateAudioContext(){return new Promise((e=>{try{if(this.audioContext){try{this.audioContext.stop()}catch(o){}try{this.audioContext.destroy()}catch(o){}}}catch(o){}this.audioContext=null,this.initAudioContext(),setTimeout((()=>e()),50)}))},diagnoseAudioUrl(o){if(o){console.log("[VideoCallNew] 🔍 音频诊断开始下载以检测是否为有效mp3",o);try{e.index.request({url:o,method:"HEAD",timeout:2e4,success:e=>{console.log("[VideoCallNew] 🔍 音频诊断HEAD statusCode=",e.statusCode),console.log("[VideoCallNew] 🔍 音频诊断HEAD headers=",e.header||{})},fail:e=>{console.log("[VideoCallNew] 🔍 音频诊断HEAD失败",e)}})}catch(i){}e.index.downloadFile({url:o,timeout:2e4,success:o=>{if(console.log("[VideoCallNew] 🔍 音频诊断downloadFile statusCode=",o.statusCode),200===o.statusCode&&o.tempFilePath)try{const t=e.index.getFileSystemManager();try{t.readFile({filePath:o.tempFilePath,position:0,length:16,success:e=>{let o="";try{const i=new Uint8Array(e.data);o=Array.from(i).map((e=>e.toString(16).padStart(2,"0"))).join(" ")}catch(i){o=""}console.log("[VideoCallNew] 🔍 音频诊断file header(16 bytes)=",o)},fail:e=>{console.log("[VideoCallNew] 🔍 音频诊断readFile失败",e)}})}catch(i){}t.getFileInfo({filePath:o.tempFilePath,success:e=>{console.log("[VideoCallNew] 🔍 音频诊断tempFile size=",e.size,"path=",o.tempFilePath)},fail:e=>{console.log("[VideoCallNew] 🔍 音频诊断getFileInfo失败",e)}})}catch(i){console.log("[VideoCallNew] 🔍 音频诊断异常:",i)}},fail:e=>{console.log("[VideoCallNew] 🔍 音频诊断downloadFile失败",e)}})}},generateAudioCacheKey(e){if(!e)return"";let o=0;for(let i=0;i<e.length;i++){o=(o<<5)-o+e.charCodeAt(i),o&=o}return"audiocache_"+Math.abs(o)},getPlayableAudioSrc(o){return new Promise((i=>{if(!o)return void i("");const t=this.generateAudioCacheKey(o);this.audioCacheKey=t;const s=e.index.getStorageSync(t);s?e.index.getSavedFileInfo({filePath:s,success:()=>{i(s)},fail:()=>{try{e.index.removeStorageSync(t)}catch(o){}i("")}}):e.index.downloadFile({url:o,timeout:6e4,success:o=>{200===o.statusCode?e.index.saveFile({tempFilePath:o.tempFilePath,success:o=>{try{e.index.setStorageSync(t,o.savedFilePath)}catch(s){}i(o.savedFilePath)},fail:()=>{i(o.tempFilePath)}}):i("")},fail:()=>{i("")}})}))},clearAudioCacheForUrl(o){return new Promise((i=>{try{const s=this.generateAudioCacheKey(o),a=e.index.getStorageSync(s);try{e.index.removeStorageSync(s)}catch(t){}if(a)return void e.index.removeSavedFile({filePath:a,complete:()=>{i()}})}catch(t){}i()}))},downloadAudioTemp:o=>new Promise((i=>{o?e.index.downloadFile({url:o,timeout:2e4,success:e=>{200===e.statusCode&&e.tempFilePath?i(e.tempFilePath):i("")},fail:()=>{i("")}}):i("")})),handleTouchStart(e){console.log("[VideoCallNew] ========== 触摸开始 =========="),console.log("[VideoCallNew] 事件对象:",e),console.log("[VideoCallNew] isProcessing:",this.isProcessing,"isRecording:",this.isRecording),this.isProcessing||this.isRecording?console.log("[VideoCallNew] 跳过:正在处理或录音中"):(this.isTouching=!0,this.longPressTimer=setTimeout((()=>{this.isTouching&&(console.log("[VideoCallNew] 长按触发,开始录音"),this.startRecording(!0))}),300))},handleTouchEnd(e){console.log("[VideoCallNew] ========== 触摸结束 =========="),console.log("[VideoCallNew] 事件对象:",e),this.isTouching=!1,this.longPressTimer&&(clearTimeout(this.longPressTimer),this.longPressTimer=null),this.isRecording&&(console.log("[VideoCallNew] 松开手指,发送录音"),this.stopRecordingInternal("manual"))},onDialectChange(e){this.selectedDialect=this.dialectOptions[e.detail.value]||""},onLanguageHintChange(e){const o=this.languageHintOptions[e.detail.value]||"";this.selectedLanguageHintLabel=o;const i=o.match(/\(([^)]+)\)/);this.selectedLanguageHint=i&&i[1]?i[1]:""},handleTouchCancel(o){console.log("[VideoCallNew] ========== 触摸取消 =========="),console.log("[VideoCallNew] 事件对象:",o),this.isTouching=!1,this.longPressTimer&&(clearTimeout(this.longPressTimer),this.longPressTimer=null),this.isRecording&&(console.log("[VideoCallNew] 触摸取消,停止录音"),this.isRecording=!1,this.recorderManager.stop(),this.resetVADState(),e.index.showToast({title:"已取消录音",icon:"none",duration:1500}))},handleGlobalTouchEnd(e){console.log("[VideoCallNew] ========== 全局触摸结束兜底 ==========",e),this.isTouching=!1,this.longPressTimer&&(clearTimeout(this.longPressTimer),this.longPressTimer=null),this.isRecording&&this.stopRecordingInternal("manual")},handleGlobalTouchCancel(o){console.log("[VideoCallNew] ========== 全局触摸取消兜底 ==========",o),this.isTouching=!1,this.longPressTimer&&(clearTimeout(this.longPressTimer),this.longPressTimer=null),this.isRecording&&(this.isRecording=!1,this.recorderManager.stop(),this.resetVADState(),e.index.showToast({title:"已取消录音",icon:"none",duration:1500}))},startRecording(e=!1){if(this.isProcessing)return;if(this.isSpeaking&&!e)return;this.resetVADState(),this.recordingStartTime=Date.now(),this.vadLastSoundTime=this.recordingStartTime,this.vadLastFrameTime=this.recordingStartTime,this.isRecording=!0,console.log("[VAD] 开始录音,时间:",(new Date).toLocaleTimeString());this.vadEnabled&&!e&&(this.vadMaxTimer=setTimeout((()=>{console.log("[VAD] 达到最大录音时长15秒强制停止"),this.stopRecordingInternal("max_duration")}),this.vadMaxDurationMs),this.vadWatchTimer=setInterval((()=>{if(!this.isRecording)return;const e=Date.now(),o=e-(this.recordingStartTime||e),i=e-(this.vadLastSoundTime||e);return e-(this.vadLastFrameTime||e)>8e3?(console.log("[VAD] 无帧回调超时,停止录音"),void this.stopRecordingInternal("no_frame")):!this.vadSpeaking&&o>2500?(console.log("[VAD] 未检测到语音,自动停止录音"),void this.stopRecordingInternal("no_speech")):o>500&&this.vadSpeaking&&i>this.vadSilenceMs?(console.log("[VAD] 检测到静音超时"),console.log("[VAD] 录音总时长:",o,"ms, 静音时长:",i,"ms"),void this.stopRecordingInternal("silence")):void 0}),150));const o={format:"mp3",sampleRate:16e3,numberOfChannels:1,encodeBitRate:32e3};e&&(o.duration=6e5),this.vadEnabled&&this.recorderManager.onFrameRecorded&&(o.frameSize=200,console.log("[VAD] 启用帧回调frameSize: 200ms")),console.log("[VAD] 录音参数:",JSON.stringify(o)),this.recorderManager.start(o),this.callStatus="正在录音(自动识别说话)"},stopRecording(){this.isRecording&&this.stopRecordingInternal("manual")},stopRecordingInternal(o="manual"){if(this.isRecording){if(this.isRecording=!1,this.recorderManager.stop(),this.stopFallbackActive=!0,this.stopFallbackRetries=0,this.stopFallbackTimer&&(clearTimeout(this.stopFallbackTimer),this.stopFallbackTimer=null),this.stopFallbackTimer=setTimeout((()=>{this.retryStopRecording()}),1200),this.isProcessing=!0,this.processingText="正在聆听...",this.callStatus="处理中...",this.recognizingText="",this.resetVADState(),console.log("[VideoCallNew] 停止录音,原因:",o),!this.audioContextActivated)try{const o=e.index.createInnerAudioContext();o.src="data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQAAAAA=",o.volume=0,setTimeout((()=>{o.destroy()}),100),this.audioContextActivated=!0,console.log("[VideoCallNew] 音频上下文已激活")}catch(i){console.warn("[VideoCallNew] 激活音频上下文失败:",i)}this.processingTimeout=setTimeout((()=>{this.isProcessing&&(console.warn("[VideoCallNew] 处理超时,重置状态"),this.isProcessing=!1,this.callStatus="通话中",e.index.showToast({title:"处理超时,请重试",icon:"none"}))}),3e4)}},retryStopRecording(){if(this.stopFallbackActive&&this.recorderManager){if(this.stopFallbackRetries+=1,this.stopFallbackRetries>2)return this.stopFallbackActive=!1,this.stopFallbackTimer=null,this.isProcessing=!1,void(this.callStatus="通话中");try{this.recorderManager.stop()}catch(e){}this.stopFallbackTimer=setTimeout((()=>{this.retryStopRecording()}),1200)}},resetVADState(){this.vadSpeaking=!1,this.vadSilenceStart=null,this.vadLastSoundTime=null,this.vadLastFrameTime=null,this.vadMaxTimer&&(clearTimeout(this.vadMaxTimer),this.vadMaxTimer=null),this.vadWatchTimer&&(clearInterval(this.vadWatchTimer),this.vadWatchTimer=null)},handleVADFrame(e){if(!e||0===e.byteLength)return;this.vadLastFrameTime=Date.now();const o=this.calculateRms(e);if(o>this.vadVoiceThreshold)return this.vadSpeaking||console.log("[VAD] 检测到语音开始,音量:",o.toFixed(4)),this.vadSpeaking=!0,this.vadSilenceStart=null,void(this.vadLastSoundTime=Date.now());this.vadSpeaking?this.vadSilenceStart||(this.vadSilenceStart=Date.now(),console.log("[VAD] 检测到静音开始,音量:",o.toFixed(4))):Math.random()<.1&&console.log("[VAD] 等待语音中,当前音量:",o.toFixed(4),"阈值:",this.vadVoiceThreshold)},calculateRms(e){const o=new DataView(e),i=o.byteLength/2;if(0===i)return 0;let t=0;for(let s=0;s<i;s++){const e=o.getInt16(2*s,!0);t+=e*e}return Math.sqrt(t/i)/32768},startAutoLoop(){this.autoListen&&(this.autoLoopTimer&&clearInterval(this.autoLoopTimer),this.autoLoopTimer=setInterval((()=>{this.callStarted&&this.autoListen&&(this.isSpeaking||this.isRecording||this.isProcessing||this.startRecording(!1))}),2e3))},async processConversation(){try{this.processingText="正在识别...";const o=e.index.getStorageSync("userId")||"",i=e.index.getStorageSync("token")||"";setTimeout((()=>{this.isProcessing&&(this.processingText="正在思考...")}),800),setTimeout((()=>{this.isProcessing&&(this.processingText="正在回复...")}),2e3),e.index.uploadFile({url:`${this.API_BASE}/api/conversation/talk`,filePath:this.audioFilePath,name:"audio",header:{"X-User-Id":o,Authorization:i?`Bearer ${i}`:""},formData:(()=>{const e=this.selectedVoiceId,o=(()=>{const o=(e||"").trim();if(!o)return"CLONE";return["Cherry","Kai","Mochi","Bunny","Jada","Dylan","Li","Marcus","Roy","Peter","Sunny","Eric","Rocky","Kiki"].includes(o)||o.startsWith("BV")||o.endsWith("_streaming")||o.endsWith("_offline")||o.endsWith("_bigtts")?"OFFICIAL":"CLONE"})(),i={voiceId:e,voiceType:o,serviceType:"VIDEO_CALL",systemPrompt:this.systemPrompt||"",saveHistory:"false"};return this.selectedDialect&&(i.dialect=this.selectedDialect),this.selectedLanguageHint&&(i.languageHints=this.selectedLanguageHint),i})(),success:o=>{if(this.processingTimeout&&(clearTimeout(this.processingTimeout),this.processingTimeout=null),console.log("[VideoCallNew] 对话响应:",o),200===o.statusCode){const i=JSON.parse(o.data);if(i.success)this.addMessage("user",i.recognizedText),this.addMessage("ai",i.aiResponse),this.playAIResponse(i.audioFile);else{const o=i.message||"未识别到语音内容";console.error("[VideoCallNew] 识别失败:",o),e.index.showModal({title:"对话失败",content:o+"\n\n请重试。若已支付但多次失败请联系客服补发提供订单号/支付时间截图)。",showCancel:!1,confirmText:"我知道了"}),this.isProcessing=!1,this.callStatus="通话中"}}else{console.error("[VideoCallNew] 请求失败,状态码:",o.statusCode);let t=null;try{t=JSON.parse(o.data)}catch(i){t=null}const s=t&&t.message?t.message:"对话请求失败: HTTP "+o.statusCode;e.index.showModal({title:"对话失败",content:s+"\n\n请重试。若已支付但多次失败请联系客服补发提供订单号/支付时间截图)。",showCancel:!1,confirmText:"我知道了"}),this.isProcessing=!1,this.callStatus="通话中"}},fail:o=>{this.processingTimeout&&(clearTimeout(this.processingTimeout),this.processingTimeout=null),console.error("[VideoCallNew] 对话失败:",o),e.index.showModal({title:"对话失败",content:"网络请求失败:"+(o.errMsg||"未知错误")+"\n\n请重试。若已支付但多次失败请联系客服补发提供订单号/支付时间截图)。",showCancel:!1,confirmText:"我知道了"}),this.isProcessing=!1,this.callStatus="通话中"}})}catch(o){this.processingTimeout&&(clearTimeout(this.processingTimeout),this.processingTimeout=null),console.error("[VideoCallNew] 对话失败:",o),e.index.showModal({title:"对话失败",content:(o.message||"未知错误")+"\n\n请重试。若已支付但多次失败请联系客服补发提供订单号/支付时间截图)。",showCancel:!1,confirmText:"我知道了"}),this.isProcessing=!1,this.callStatus="通话中"}},async playAIResponse(o){if(!o)return console.error("[VideoCallNew] ❌ 音频文件为空"),e.index.showToast({title:"音频文件缺失",icon:"none"}),this.isProcessing=!1,void(this.callStatus="通话中");this.processingText="正在回复...";const i=`${this.API_BASE}/api/conversation/audio/${o}`;if(console.log("[VideoCallNew] 🎵 准备播放音频:",i),console.log("[VideoCallNew] 📁 音频文件名:",o),this.audioContext)try{console.log("[VideoCallNew] 停止之前的音频..."),this.audioContext.stop()}catch(a){console.warn("[VideoCallNew] 停止音频实例失败:",a)}else console.log("[VideoCallNew] 初始化音频上下文..."),this.initAudioContext();this.audioSessionId+=1;const t=this.audioSessionId;this.audioPlayedInSession=!1,this.audioPlayStartAt=0,this.audioTriedRedownload=!1,this.audioTriedRecreateContext=!1,this.audioPlayInvokedInSession=!1,this.audioPlayTargetSessionId=t,this.audioDiagnosedInSession=!1,this.pendingAudioUrl=i,this.audioTriedFallback=!1;let s=i;try{const e=await this.downloadAudioTemp(i);t===this.audioSessionId&&e&&(s=e)}catch(a){}if(t===this.audioSessionId&&this.audioContext){this.currentAudioSrc=s,this.audioContext.src=s,this.audioContext.volume=1;try{this.audioContext.obeyMuteSwitch=!1}catch(a){console.warn("[VideoCallNew] 设置obeyMuteSwitch失败:",a)}console.log("[VideoCallNew] 🔊 音频源已设置:",this.audioContext.src),console.log("[VideoCallNew] 🔊 音频音量:",this.audioContext.volume),console.log("[VideoCallNew] 📢 如果声音过小请检查1.手机系统音量 2.媒体音量 3.静音开关"),console.log("[VideoCallNew] 🎬 AI开始回复从第1秒开始循环播放视频"),this.isSpeaking=!0,this.callStatus="对方正在说话...",this.videoContext&&(this.videoContext.seek(1),setTimeout((()=>{this.videoContext&&this.videoContext.play()}),100)),console.log("[VideoCallNew] ▶️ 开始播放音频..."),setTimeout((()=>{t===this.audioSessionId&&this.tryPlayAudioForSession("timer")}),500),this.isProcessing=!1}},addMessage(e,o){const i=new Date,t=`${i.getHours()}:${i.getMinutes().toString().padStart(2,"0")}`;this.messages.push({role:e,content:o,time:t}),this.$nextTick((()=>{this.scrollTop=999999}))},handleClearHistory(o){console.log("[VideoCallNew] ========== 清空按钮被点击 =========="),console.log("[VideoCallNew] 事件对象:",o),e.index.showToast({title:"清空按钮已点击",icon:"none",duration:1e3}),e.index.showModal({title:"确认清空",content:"确定要清空对话历史吗?",confirmColor:"#8B7355",success:e=>{e.confirm&&this.clearHistory()}})},clearHistory(){const o=e.index.getStorageSync("userId")||"",i=e.index.getStorageSync("token")||"";e.index.request({url:`${this.API_BASE}/api/conversation/clear-history`,method:"POST",header:{"X-User-Id":o,Authorization:i?`Bearer ${i}`:""},success:o=>{var i;o.data&&o.data.success?(this.messages=[],e.index.showToast({title:"已清空",icon:"success"})):e.index.showToast({title:(null==(i=o.data)?void 0:i.message)||"清空失败",icon:"none"})},fail:o=>{console.error("[VideoCallNew] 清空历史失败:",o),e.index.showToast({title:"清空失败,请稍后重试",icon:"none"})}})},autoEndCall(){this.durationTimer&&(clearInterval(this.durationTimer),this.durationTimer=null),this.cleanup(),e.index.showModal({title:"通话已结束",content:"您本次通话已达10分钟时长上限通话已自动结束。",showCancel:!1,confirmText:"好的",confirmColor:"#8B7355",success:o=>{o.confirm&&e.index.reLaunch({url:"/pages/index/index"})}})},endCall(o){console.log("[VideoCallNew] ========== 挂断按钮被点击 =========="),console.log("[VideoCallNew] 事件对象:",o),e.index.showToast({title:"挂断按钮已点击",icon:"none",duration:1e3}),e.index.showModal({title:"结束通话",content:`通话时长:${this.callDuration}\n确定要结束通话吗?`,confirmColor:"#eb3349",success:o=>{o.confirm&&(e.index.showLoading({title:"正在挂断...",mask:!0}),setTimeout((()=>{e.index.hideLoading(),this.cleanup(),e.index.showToast({title:"通话已结束",icon:"success",duration:1500}),setTimeout((()=>{e.index.reLaunch({url:"/pages/index/index"})}),1500)}),800))}})},goBack(){this.callStarted?this.endCall():e.index.navigateBack()},goToRevival(){console.log("[VideoCallNew] 跳转到复活照片页面"),e.index.navigateTo({url:"/pages/revival/revival-original",fail:e=>{console.error("[VideoCallNew] 跳转失败:",e)}})},onVideoMetadataLoaded(){console.log("[VideoCallNew] 视频元数据加载完成,可以开始播放"),this.isConnecting&&(this.connectingText="已接通",setTimeout((()=>{this.isConnecting=!1,e.index.showToast({title:"通话已接通",icon:"success",duration:1500})}),300))},onVideoLoaded(){console.log("[VideoCallNew] 视频数据加载成功"),console.log("[VideoCallNew] 当前视频URL:",this.selectedVideoUrl)},onVideoPreloaded(e){console.log("[VideoCallNew] 视频预加载完成:",e),this.videoPreloadStatus[e]=!0,this.$forceUpdate()},onVideoPlay(){console.log("[VideoCallNew] 视频开始播放")},onVideoPause(){console.log("[VideoCallNew] 视频已暂停")},onVideoTimeUpdate(e){},onVideoError(o){console.error("[VideoCallNew] 视频加载失败:",o),console.error("[VideoCallNew] 视频URL:",this.selectedVideoUrl),console.error("[VideoCallNew] 错误详情:",JSON.stringify(o)),e.index.showToast({title:"视频加载失败",icon:"none",duration:3e3})},async loadVideoCache(){try{const o=e.index.getStorageSync("videoCache");console.log("[VideoCallNew] 💾 读取缓存数据:",o),o?(this.videoCache=JSON.parse(o),console.log("[VideoCallNew] ✅ 加载视频缓存信息:",Object.keys(this.videoCache).length,"个视频"),console.log("[VideoCallNew] 缓存详情:",this.videoCache)):(console.log("[VideoCallNew] ⚠️ 未找到缓存数据"),this.videoCache={})}catch(o){console.error("[VideoCallNew] ❌ 加载视频缓存失败:",o),this.videoCache={}}},async saveVideoCache(){try{const o=JSON.stringify(this.videoCache);e.index.setStorageSync("videoCache",o),console.log("[VideoCallNew] 💾 保存视频缓存信息成功"),console.log("[VideoCallNew] 保存内容:",o);e.index.getStorageSync("videoCache")?console.log("[VideoCallNew] ✅ 验证保存成功"):console.error("[VideoCallNew] ❌ 验证保存失败,数据未持久化")}catch(o){console.error("[VideoCallNew] ❌ 保存视频缓存失败:",o)}},async checkAndLoadLocalVideo(e,o){if(e&&o){if(console.log("[VideoCallNew] 🔍 开始检查视频缓存"),console.log("[VideoCallNew] 视频ID:",e),console.log("[VideoCallNew] 当前缓存对象:",this.videoCache),console.log("[VideoCallNew] 缓存中是否有该ID:",e in this.videoCache),this.videoCache[e]){const o=this.videoCache[e];console.log("[VideoCallNew] 📝 发现缓存记录,验证文件:",o);const i=await this.checkFileExists(o);if(console.log("[VideoCallNew] 文件存在性检查结果:",i),i)return this.localVideoUrl=o,console.log("[VideoCallNew] ✅ 本地视频文件存在,使用缓存"),void console.log("[VideoCallNew] 已设置 localVideoUrl:",this.localVideoUrl);console.warn("[VideoCallNew] ⚠️ 缓存记录存在但文件丢失,清除缓存"),delete this.videoCache[e],await this.saveVideoCache()}else console.log("[VideoCallNew] ❌ 缓存中未找到视频ID:",e);console.log("[VideoCallNew] <20> 未找到缓存先使用原始URL播放同时后台下载"),this.localVideoUrl="",this.startBackgroundDownload(o,e)}else console.warn("[VideoCallNew] ⚠️ 视频ID或URL为空")},async preloadAllVideos(){if(this.preCachingInProgress)return void console.log("[VideoCallNew] 预缓存已在进行中,跳过");this.preCachingInProgress=!0,console.log("[VideoCallNew] 🚀 开始预缓存所有视频");const e=[...this.videos].sort(((e,o)=>{const i=e.created_at||e.createdAt||0;return(o.created_at||o.createdAt||0)-i}));let o=0,i=0;for(const t of e){const s=t.id,a=t.edited_video_url||t.videoUrl||t.local_video_path||t.video_url||t.localVideoPath;if(s&&a){if(this.videoCache[s]){const e=this.videoCache[s];if(await this.checkFileExists(e)){o++,this.cacheProgress[s]={progress:100,status:"completed"},console.log(`[VideoCallNew] ✅ 视频已缓存: ${t.name||s}`);continue}delete this.videoCache[s],await this.saveVideoCache()}i++,console.log(`[VideoCallNew] 📥 开始预缓存 [${i}/${e.length-o}]: ${t.name||s}`),this.cacheProgress[s]={progress:0,status:"downloading"},this.startBackgroundDownload(a,s,t.name).catch((e=>{console.error(`[VideoCallNew] 预缓存失败: ${t.name}`,e),this.cacheProgress[s]={progress:0,status:"failed"}})),await new Promise((e=>setTimeout(e,200)))}else console.warn("[VideoCallNew] 视频缺少ID或URL跳过:",t.name)}console.log(`[VideoCallNew] 🎉 预缓存启动完成: 已缓存 ${o} 个,正在下载 ${i}`),this.preCachingInProgress=!1},async startBackgroundDownload(o,i,t=""){if(!o||!i)return;if(this.downloadingVideos[i])return void console.log("[VideoCallNew] 视频已在下载队列中");console.log(`[VideoCallNew] 📥 开始后台下载视频: ${t||i}`,o);const s=new Promise(((s,a)=>{e.index.downloadFile({url:o,success:o=>{200===o.statusCode?(console.log("[VideoCallNew] 视频下载成功,临时路径:",o.tempFilePath),e.index.saveFile({tempFilePath:o.tempFilePath,success:o=>{console.log(`[VideoCallNew] ✅ 视频保存成功 ${t||i}:`,o.savedFilePath),this.videoCache[i]=o.savedFilePath,this.selectedVideoId===i&&(this.localVideoUrl=o.savedFilePath,console.log("[VideoCallNew] 🎯 当前视频缓存完成,已更新播放源"),this.callStarted&&e.index.showToast({title:"已切换到本地播放",icon:"success",duration:1500})),this.saveVideoCache(),this.cacheProgress[i]&&(this.cacheProgress[i]={progress:100,status:"completed"}),console.log("[VideoCallNew] 💾 缓存已更新,下次启动将直接使用"),delete this.downloadingVideos[i],s(o.savedFilePath)},fail:e=>{console.error(`[VideoCallNew] 视频保存失败 ${t||i}:`,e),this.selectedVideoId===i&&(this.localVideoUrl=o.tempFilePath),this.cacheProgress[i]&&(this.cacheProgress[i]={progress:100,status:"failed"}),delete this.downloadingVideos[i],s(o.tempFilePath)}})):(console.error(`[VideoCallNew] 视频下载失败 ${t||i},状态码:`,o.statusCode),this.cacheProgress[i]&&(this.cacheProgress[i]={progress:0,status:"failed"}),delete this.downloadingVideos[i],a(new Error("下载失败")))},fail:e=>{console.error(`[VideoCallNew] 视频下载失败 ${t||i}:`,e),this.cacheProgress[i]&&(this.cacheProgress[i]={progress:0,status:"failed"}),delete this.downloadingVideos[i],a(e)}}).onProgressUpdate((e=>{const o=e.progress||0;this.cacheProgress[i]&&(this.cacheProgress[i].progress=o),o%20==0&&console.log(`[VideoCallNew] 下载进度 ${t||i}: ${o}%`)}))}));this.downloadingVideos[i]=s;try{await s}catch(a){console.error("[VideoCallNew] 下载视频异常:",a)}},checkFileExists:async o=>new Promise((i=>{try{if("function"!=typeof e.index.getFileSystemManager)return console.log("[VideoCallNew] 💡 当前平台不支持FileSystemManager信任缓存记录"),void i(!0);e.index.getFileSystemManager().access({path:o,success:()=>{console.log("[VideoCallNew] ✅ 文件存在验证通过"),i(!0)},fail:()=>{console.warn("[VideoCallNew] ❌ 文件不存在"),i(!1)}})}catch(t){console.warn("[VideoCallNew] ⚠️ 检查文件存在性异常:",t),console.log("[VideoCallNew] 💡 异常情况下信任缓存记录"),i(!0)}})),cleanup(){if(console.log("[VideoCallNew] 开始清理资源"),this.durationTimer&&(clearInterval(this.durationTimer),this.durationTimer=null),this.processingTimeout&&(clearTimeout(this.processingTimeout),this.processingTimeout=null),this.stopFallbackTimer&&(clearTimeout(this.stopFallbackTimer),this.stopFallbackTimer=null),this.stopFallbackActive=!1,this.stopFallbackRetries=0,this.longPressTimer&&(clearTimeout(this.longPressTimer),this.longPressTimer=null),this.audioContext){try{this.audioContext.stop(),this.audioContext.destroy()}catch(e){console.warn("[VideoCallNew] 清理音频上下文失败:",e)}this.audioContext=null}if(this.recorderManager){try{this.isRecording&&this.recorderManager.stop()}catch(e){console.warn("[VideoCallNew] 清理录音管理器失败:",e)}this.recorderManager=null}this.vadMaxTimer&&(clearTimeout(this.vadMaxTimer),this.vadMaxTimer=null),this.vadWatchTimer&&(clearInterval(this.vadWatchTimer),this.vadWatchTimer=null),this.autoLoopTimer&&(clearInterval(this.autoLoopTimer),this.autoLoopTimer=null),console.log("[VideoCallNew] 资源清理完成")},formatTime(e){if(!e)return"";const o=new Date(e);return`${o.getFullYear()}-${String(o.getMonth()+1).padStart(2,"0")}-${String(o.getDate()).padStart(2,"0")} ${String(o.getHours()).padStart(2,"0")}:${String(o.getMinutes()).padStart(2,"0")}`},handlePaymentClose(){this.paymentModalData.show=!1,this._paymentReject&&this._paymentReject(new Error("用户取消支付"))},async handlePaymentConfirm(e){await i.handlePaymentConfirm(this,e)}}};if(!Array){e.resolveComponent("PaymentModal")()}const s=e._export_sfc(t,[["render",function(o,i,t,s,a,l){return e.e({a:!a.callStarted},a.callStarted?e.e({f:a.isConnecting},a.isConnecting?e.e({g:a.selectedPhotoUrl},a.selectedPhotoUrl?{h:a.selectedPhotoUrl}:{},{i:a.selectedPhotoUrl},a.selectedPhotoUrl?{j:a.selectedPhotoUrl}:{},{k:e.t(a.selectedVideoName),l:e.t(a.connectingText)}):{},{m:a.selectedVideoUrl},a.selectedVideoUrl?{n:a.localVideoUrl||a.selectedVideoUrl,o:e.o(((...e)=>l.onVideoError&&l.onVideoError(...e))),p:e.o(((...e)=>l.onVideoLoaded&&l.onVideoLoaded(...e))),q:e.o(((...e)=>l.onVideoMetadataLoaded&&l.onVideoMetadataLoaded(...e))),r:e.o(((...e)=>l.onVideoPlay&&l.onVideoPlay(...e))),s:e.o(((...e)=>l.onVideoPause&&l.onVideoPause(...e)))}:{},{t:a.isConnecting?1:"",v:e.t(a.selectedVideoName),w:e.t(a.callDuration),x:a.isRecording||a.isProcessing},(a.isRecording||a.isProcessing,{}),{y:a.selectedVoiceId&&a.selectedVoiceId.startsWith("cosyvoice-v3-plus-")},a.selectedVoiceId&&a.selectedVoiceId.startsWith("cosyvoice-v3-plus-")?{z:e.t(a.selectedDialect||"请选择方言(可选)"),A:a.dialectOptions,B:e.o(((...e)=>l.onDialectChange&&l.onDialectChange(...e)))}:{},{C:a.selectedVoiceId&&a.selectedVoiceId.startsWith("cosyvoice-v3-plus-")},a.selectedVoiceId&&a.selectedVoiceId.startsWith("cosyvoice-v3-plus-")?{D:e.t(a.selectedLanguageHintLabel||"请选择语言(可选)"),E:a.languageHintOptions,F:e.o(((...e)=>l.onLanguageHintChange&&l.onLanguageHintChange(...e)))}:{},{G:e.o(((...e)=>l.handleClearHistory&&l.handleClearHistory(...e))),H:a.isRecording},(a.isRecording,{}),{I:a.isRecording},(a.isRecording,{}),{J:!a.isRecording&&!a.isProcessing},(a.isRecording||a.isProcessing,{}),{K:a.isRecording},(a.isRecording,{}),{L:a.isProcessing},(a.isProcessing,{}),{M:a.isRecording?1:"",N:a.isProcessing?1:"",O:e.t(a.isRecording?"松开发送":a.isProcessing?"聆听中...":"长按说话"),P:a.isRecording?1:"",Q:e.o(((...e)=>l.handleTouchStart&&l.handleTouchStart(...e))),R:e.o(((...e)=>l.handleTouchEnd&&l.handleTouchEnd(...e))),S:e.o(((...e)=>l.handleTouchCancel&&l.handleTouchCancel(...e))),T:e.o(((...e)=>l.endCall&&l.endCall(...e)))}):e.e({b:a.loading},a.loading?{}:a.videos.length>0?{d:e.t(a.videos.length),e:e.f(a.videos,((o,i,t)=>e.e({a:o.photo_url},o.photo_url?{b:o.photo_url}:{},{c:o.edited_video_url||o.videoUrl||o.local_video_path||o.video_url||o.localVideoPath},o.edited_video_url||o.videoUrl||o.local_video_path||o.video_url||o.localVideoPath?{d:"preload-video-"+o.id,e:o.edited_video_url||o.videoUrl||o.local_video_path||o.video_url||o.localVideoPath,f:e.o((e=>l.onVideoPreloaded(o.id)),o.id)}:{},{g:e.t(o.name||"复活视频"),h:a.videoPreloadStatus[o.id]},a.videoPreloadStatus[o.id]?{}:a.cacheProgress[o.id]?e.e({j:"completed"===a.cacheProgress[o.id].status},"completed"===a.cacheProgress[o.id].status?{}:"downloading"===a.cacheProgress[o.id].status?{l:e.t(a.cacheProgress[o.id].progress)}:{},{k:"downloading"===a.cacheProgress[o.id].status}):{},{i:a.cacheProgress[o.id],m:e.t(o.text||"暂无描述"),n:o.id,o:e.o((e=>l.startVideoCall(o)),o.id)})))}:{},{c:a.videos.length>0}),{U:a.showSettingsDialog},a.showSettingsDialog?{V:e.o(((...e)=>l.closeSettingsDialog&&l.closeSettingsDialog(...e))),W:a.dialogMemoryIdentity,X:e.o((e=>a.dialogMemoryIdentity=e.detail.value)),Y:a.dialogMemoryInfo,Z:e.o((e=>a.dialogMemoryInfo=e.detail.value)),aa:e.o(((...e)=>l.closeSettingsDialog&&l.closeSettingsDialog(...e))),ab:e.o(((...e)=>l.confirmSettings&&l.confirmSettings(...e))),ac:e.o((()=>{})),ad:e.o(((...e)=>l.closeSettingsDialog&&l.closeSettingsDialog(...e)))}:{},{ae:e.sr("paymentModal","5a549494-0"),af:e.o(l.handlePaymentClose),ag:e.o(l.handlePaymentConfirm),ah:e.p({show:a.paymentModalData.show,serviceType:a.paymentModalData.serviceType,serviceName:a.paymentModalData.serviceName,serviceDesc:a.paymentModalData.serviceDesc,price:a.paymentModalData.price,orderNo:a.paymentModalData.orderNo,paymentTips:a.paymentModalData.paymentTips}),ai:e.o(((...e)=>l.handleGlobalTouchEnd&&l.handleGlobalTouchEnd(...e))),aj:e.o(((...e)=>l.handleGlobalTouchCancel&&l.handleGlobalTouchCancel(...e)))})}],["__scopeId","data-v-5a549494"]]);wx.createPage(s);