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

2 lines
31 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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"),t=require("../../config/api.js"),s=require("../../utils/payment.js"),i=require("../../common/assets.js"),o={components:{PaymentModal:()=>"../../components/PaymentModal.js"},data:()=>({API_BASE:t.API_BASE,activeTab:"synthesize",loading:!1,message:{type:"",text:""},selectedFile:null,voiceDisplayName:"",voices:[],voiceTypeOptions:[{value:"CLONE",label:"克隆音色"},{value:"OFFICIAL",label:"官方音色Flash/BigTTS"}],selectedVoiceType:"CLONE",selectedVoiceTypeLabel:"克隆音色",selectedVoiceId:"",selectedVoiceName:"",selectedDialect:"",selectedLanguageHint:"",selectedLanguageHintLabel:"",selectedSupportsDialect:!1,selectedSupportsLanguageHints:!1,languageHintOptions:["中文(zh)","英文(en)","法语(fr)","德语(de)","日语(ja)","韩语(ko)","俄语(ru)"],dialectOptions:["广东话","东北话","甘肃话","贵州话","河南话","湖北话","江西话","闽南话","宁夏话","山西话","陕西话","山东话","上海话","四川话","天津话","云南话"],ttsText:"",ttsLoading:!1,audioUrl:null,templates:[],expandedCategory:"memorial",isRecording:!1,recorderManager:null,conversationVoiceId:"",conversationVoiceLabel:"",conversationDialect:"",conversationLanguageHint:"",conversationLanguageHintLabel:"",conversationVoiceType:"CLONE",conversationVoiceTypeLabel:"克隆音色",conversationSupportsDialect:!1,conversationSupportsLanguageHints:!1,recognizedText:"",aiResponse:"",conversationAudio:null,isProcessing:!1,memoryIdentity:"",memoryInfo:"",systemPrompt:"",audioFilePath:"",paymentModalData:{show:!1,serviceType:"",serviceName:"",serviceDesc:"",price:0,orderNo:"",paymentTips:"点击确认支付后将开始处理您的请求"},_paymentResolve:null,_paymentReject:null,_paymentOnSuccess:null,_paymentOnFailed:null}),computed:{apiBaseUrl(){return this.API_BASE},voicesOnly(){return(this.voices||[]).map((e=>({voice:e.voice,label:e.voice_name||e.voice,voice_type:e.voice_type,supportsDialect:e.supportsDialect,supportsLanguageHints:e.supportsLanguageHints})))},conversationDisplayVoices(){const e=(this.voices||[]).filter((e=>e&&(e.voice_type||"CLONE")===(this.conversationVoiceType||"CLONE")));if("OFFICIAL"!==(this.conversationVoiceType||"CLONE"))return e;const t=["Cherry","Kai","Mochi","Bunny"],i=["Cherry","Kai","Mochi","Bunny"],o=e.filter((e=>!(e&&t.includes(e.voice)))).map(((e,t)=>({v:e,idx:t}))).sort(((e,t)=>{const s=i.indexOf(e.v.voice),o=i.indexOf(t.v.voice),n=-1===s?999:s,a=-1===o?999:o;return n!==a?n-a:e.idx-t.idx})).map((e=>e.v));return s.mapOfficialVoiceDisplay(o)},displayVoices(){const e=(this.voices||[]).filter((e=>e&&(e.voice_type||"CLONE")===this.selectedVoiceType));if("OFFICIAL"!==(this.selectedVoiceType||"CLONE"))return e;const t=["Cherry","Kai","Mochi","Bunny"],i=["Cherry","Kai","Mochi","Bunny"],o=e.filter((e=>!(e&&t.includes(e.voice)))).map(((e,t)=>({v:e,idx:t}))).sort(((e,t)=>{const s=i.indexOf(e.v.voice),o=i.indexOf(t.v.voice),n=-1===s?999:s,a=-1===o?999:o;return n!==a?n-a:e.idx-t.idx})).map((e=>e.v));return s.mapOfficialVoiceDisplay(o)}},watch:{activeTab(e){this.conversationVoiceId="",this.conversationVoiceLabel="",this.conversationDialect="",this.conversationLanguageHint="",this.conversationLanguageHintLabel="",this.conversationSupportsDialect=!1,this.conversationSupportsLanguageHints=!1,"list"!==e&&"synthesize"!==e&&"conversation"!==e||this.loadVoices()}},onLoad(){this.useDefaultTemplates(),this.loadVoices(),this.loadTemplatesFromServer(),this.initRecorder()},onShow(){!this.checkLogin||!this.checkLogin()||this.voices&&0!==this.voices.length||this.loadVoices()},methods:{onVoiceTypeChange(e){const t=this.voiceTypeOptions[e.detail.value];this.selectedVoiceType=t?t.value:"CLONE",this.selectedVoiceTypeLabel=t?t.label:"克隆音色",this.selectedVoiceId="",this.selectedVoiceName="",this.selectedDialect="",this.selectedLanguageHint="",this.selectedLanguageHintLabel="",this.selectedSupportsDialect=!1,this.selectedSupportsLanguageHints=!1},onConversationVoiceTypeChange(e){const t=this.voiceTypeOptions[e.detail.value];this.conversationVoiceType=t?t.value:"CLONE",this.conversationVoiceTypeLabel=t?t.label:"克隆音色",this.conversationVoiceId="",this.conversationVoiceLabel="",this.conversationDialect="",this.conversationLanguageHint="",this.conversationLanguageHintLabel="",this.conversationSupportsDialect=!1,this.conversationSupportsLanguageHints=!1},showVoiceHelp(){e.index.showModal({title:"💡 如何获取音色?",content:'1⃣ 点击底部导航"声音克隆"\n\n2⃣ 点击"上传音频"按钮\n\n3⃣ 录制或上传10-20秒清晰人声\n\n4⃣ 创建成功后即可在此选择使用\n\n💡 提示:音色质量越好,合成效果越自然',showCancel:!0,cancelText:"知道了",confirmText:"去创建",success:t=>{t.confirm&&e.index.switchTab({url:"/pages/upload-audio/upload-audio"})}})},checkLogin(){const t=e.index.getStorageSync("token"),s=e.index.getStorageSync("userId");return!(!t||!s)},showMessage(e,t){this.message={type:e,text:t},setTimeout((()=>{this.message={type:"",text:""}}),5e3)},chooseAudioFile(){const t="undefined"!=typeof plus,s="undefined"!=typeof document&&!t,i=void 0!==e.wx$1;if(t)e.index.showModal({title:"选择方式",content:"APP 环境请使用录音功能创建音色推荐10-20秒清晰朗读\n\n提示如需上传音频文件请使用手机浏览器访问本系统",confirmText:"开始录音",cancelText:"取消",success:e=>{e.confirm&&this.startRecordAudio()}});else if(s){const e=document.createElement("input");e.type="file",e.accept="audio/*,.mp3,.wav,.m4a,.aac",e.onchange=e=>{const t=e.target.files[0];if(t){if(t.size>10485760)return void this.showMessage("error","文件大小不能超过10MB");const e=URL.createObjectURL(t);this.selectedFile={path:e,name:t.name,size:t.size,file:t},this.showMessage("success",`已选择: ${t.name} (${(t.size/1024).toFixed(2)} KB)`)}},e.click()}else i&&e.index.chooseMessageFile({count:1,type:"file",extension:[".mp3",".wav",".m4a",".aac"],success:e=>{const t=e.tempFiles[0];t.size>10485760?this.showMessage("error","文件大小不能超过10MB"):(this.selectedFile={path:t.path,name:t.name,size:t.size},this.showMessage("success",`已选择: ${t.name} (${(t.size/1024).toFixed(2)} KB)`))},fail:e=>{this.showMessage("error","选择文件失败: "+(e.errMsg||"未知错误"))}})},async startRecordAudio(){const t=e.index.getRecorderManager();t.onStart((()=>{this.showMessage("success","正在录音...")})),t.onStop((e=>{this.selectedFile={path:e.tempFilePath,name:"record_"+Date.now()+".mp3"},this.showMessage("success","录音完成")})),t.onError((e=>{console.error("录音失败:",e),this.showMessage("error","录音失败")})),e.index.showModal({title:"录音",content:"点击确定开始录音录音时长10-20秒",success:e=>{e.confirm&&(t.start({format:"mp3",sampleRate:16e3}),setTimeout((()=>{t.stop()}),2e4))}})},async handleCreateVoice(){if(!this.checkLogin())return void e.index.showModal({title:"提示",content:"请先登录后再使用此功能",confirmText:"去登录",cancelText:"取消",success:t=>{t.confirm&&e.index.navigateTo({url:"/pages/login/login"})}});if(!this.selectedFile)return void this.showMessage("error","请先选择音频文件");if(!this.voiceDisplayName.trim())return void this.showMessage("error","请输入音色名称");const t=`voice${this.voices.length+1}`;this.loading=!0,console.log("[Index] 开始上传音频文件..."),console.log("[Index] 文件路径:",this.selectedFile.path),console.log("[Index] 音色标识:",t),console.log("[Index] 音色显示名称:",this.voiceDisplayName);const s=e.index.getStorageSync("userId")||"",i=e.index.getStorageSync("token")||"";e.index.uploadFile({url:`${this.apiBaseUrl}/api/voice/create`,filePath:this.selectedFile.path,name:"audio",header:{"X-User-Id":s,Authorization:i?`Bearer ${i}`:""},formData:{name:t,displayName:this.voiceDisplayName},success:e=>{if(console.log("[Index] 上传响应:",e),200===e.statusCode)try{const t=JSON.parse(e.data);t.success?(this.showMessage("success",`创建成功!音色: ${this.voiceDisplayName}`),this.selectedFile=null,this.voiceDisplayName="",this.loadVoices()):this.showMessage("error",t.message||"创建失败")}catch(t){console.error("[Index] 解析响应失败:",t),this.showMessage("error","服务器响应格式错误")}else this.showMessage("error",`上传失败: HTTP ${e.statusCode}`)},fail:e=>{console.error("[Index] 上传失败:",e),this.showMessage("error","上传失败: "+(e.errMsg||"未知错误"))},complete:()=>{this.loading=!1}})},async loadVoices(){this.loading=!0;const t=e.index.getStorageSync("userId")||"",s=e.index.getStorageSync("token")||"";console.log("[Revival] 加载音色 - userId:",t,"token:",s?"已设置":"未设置"),e.index.request({url:`${this.apiBaseUrl}/api/voice/list`,method:"GET",header:{"X-User-Id":t,Authorization:s?`Bearer ${s}`:""},success:e=>{if(console.log("[Revival] 音色列表响应:",e.data),e.data.success){const t=["Cherry","Kai","Mochi","Bunny"];this.voices=(e.data.voices||[]).filter((e=>!(e&&e.voice&&e.voice.startsWith("cosyvoice-v3-flash-")))).filter((e=>!(e&&e.voice&&t.includes(e.voice)))),console.log("[Revival] 加载音色数量:",this.voices.length)}else console.error("[Revival] 加载音色失败:",e.data.message)},fail:e=>{console.error("[Revival] 请求失败:",e),this.showMessage("error","加载音色失败")},complete:()=>{this.loading=!1}})},handleDeleteVoice(t){e.index.showModal({title:"确认删除",content:`确定删除音色 ${t}`,success:s=>{if(s.confirm){console.log("[Revival] 开始删除音色:",t);const s=e.index.getStorageSync("userId")||"",i=e.index.getStorageSync("token")||"";e.index.showLoading({title:"删除中...",mask:!0}),e.index.request({url:`${this.apiBaseUrl}/api/voice/delete/${t}`,method:"DELETE",header:{"X-User-Id":s,Authorization:i?`Bearer ${i}`:""},success:t=>{console.log("[Revival] 删除音色响应:",t),e.index.hideLoading(),200===t.statusCode?t.data&&t.data.success?(this.showMessage("success","删除成功"),this.loadVoices()):this.showMessage("error",t.data.message||"删除失败"):this.showMessage("error",`删除失败: HTTP ${t.statusCode}`)},fail:t=>{console.error("[Revival] 删除音色失败:",t),e.index.hideLoading(),this.showMessage("error","网络请求失败: "+(t.errMsg||"请检查网络连接"))}})}}})},onVoiceChange(e){const t=this.displayVoices[e.detail.value];this.selectedVoiceId=t.voice,this.selectedVoiceName=t.voice_name||t.voice,this.selectedVoiceType=t.voice_type||this.selectedVoiceType||"CLONE",this.selectedVoiceTypeLabel="OFFICIAL"===this.selectedVoiceType?"官方音色Flash/BigTTS":"克隆音色",this.selectedDialect="",this.selectedLanguageHint="",this.selectedLanguageHintLabel="",this.selectedSupportsDialect=!!t.supportsDialect,this.selectedSupportsLanguageHints=!!t.supportsLanguageHints,"OFFICIAL"===(this.selectedVoiceType||"CLONE")&&(this.selectedDialect="",this.selectedLanguageHint="",this.selectedLanguageHintLabel="",this.selectedSupportsDialect=!1,this.selectedSupportsLanguageHints=!1)},onDialectChange(e){this.selectedDialect=this.dialectOptions[e.detail.value]||""},onLanguageHintChange(e){const t=this.languageHintOptions[e.detail.value]||"";this.selectedLanguageHintLabel=t;const s=t.match(/\(([^)]+)\)/);this.selectedLanguageHint=s&&s[1]?s[1]:""},onConversationVoiceChange(e){const t=this.conversationDisplayVoices[e.detail.value];this.conversationVoiceId=t.voice,this.conversationVoiceLabel=t.voice_name||t.voice,this.conversationVoiceType=t.voice_type||this.conversationVoiceType||"CLONE",this.conversationVoiceTypeLabel="OFFICIAL"===this.conversationVoiceType?"官方音色Flash":"克隆音色",this.conversationDialect="",this.conversationLanguageHint="",this.conversationLanguageHintLabel="",this.conversationSupportsDialect=!!t.supportsDialect,this.conversationSupportsLanguageHints=!!t.supportsLanguageHints,"OFFICIAL"===(this.conversationVoiceType||"CLONE")&&(this.conversationDialect="",this.conversationLanguageHint="",this.conversationLanguageHintLabel="",this.conversationSupportsDialect=!1,this.conversationSupportsLanguageHints=!1)},onConversationDialectChange(e){this.conversationDialect=this.dialectOptions[e.detail.value]||""},onConversationLanguageHintChange(e){const t=this.languageHintOptions[e.detail.value]||"";this.conversationLanguageHintLabel=t;const s=t.match(/\(([^)]+)\)/);this.conversationLanguageHint=s&&s[1]?s[1]:""},toggleCategory(e){this.expandedCategory===e?this.expandedCategory="":this.expandedCategory=e},getTemplatesByCategory(e){return this.templates.filter((t=>t.category===e))},selectTemplate(e){this.ttsText=e.content,this.showMessage("success","已应用模板")},loadTemplatesFromServer(){const t=e.index.getStorageSync("userId")||"",s=e.index.getStorageSync("token")||"";console.log("[Templates] 尝试从服务器加载模板..."),e.index.request({url:`${this.apiBaseUrl}/api/templates/list`,method:"GET",header:{"X-User-Id":t,Authorization:s?`Bearer ${s}`:""},success:e=>{console.log("[Templates] 服务器响应:",e),e.data&&e.data.success&&e.data.templates&&e.data.templates.length>0?(this.templates=e.data.templates,console.log("[Templates] 从服务器加载成功,数量:",this.templates.length)):e.data&&Array.isArray(e.data)&&e.data.length>0?(this.templates=e.data,console.log("[Templates] 从服务器加载成功(数组格式),数量:",this.templates.length)):console.log("[Templates] 服务器无数据,继续使用默认模板")},fail:e=>{console.log("[Templates] 服务器请求失败,继续使用默认模板:",e)}})},useDefaultTemplates(){this.templates=[{category:"memorial",title:"思念",content:"妈妈,我好想你,你在那边还好吗?"},{category:"memorial",title:"感恩",content:"谢谢您一直以来对我的照顾和关爱。"},{category:"memorial",title:"告白",content:"有些话当时没说出口,现在想对您说..."},{category:"greeting",title:"问候",content:"今天天气很好,您最喜欢这样的天气了。"},{category:"greeting",title:"日常",content:"最近过得还好,就是很想您。"},{category:"memory",title:"回忆",content:"还记得小时候您做的红烧肉,真好吃。"},{category:"memory",title:"往事",content:"那年夏天,我们一起去海边的情景还历历在目。"}],console.log("[Templates] 使用默认模板,数量:",this.templates.length)},async handleSynthesize(){this.checkLogin()?this.ttsText.trim()&&this.selectedVoiceId?s.showPaymentModal(this,s.SERVICE_TYPES.TTS_SYNTHESIS.type,(()=>{this.executeSynthesize()}),(e=>{console.error("[Payment] 支付失败:",e)})):this.showMessage("error","请输入文本并选择音色"):e.index.showModal({title:"提示",content:"请先登录后再使用此功能",confirmText:"去登录",cancelText:"取消",success:t=>{t.confirm&&e.index.navigateTo({url:"/pages/login/login"})}})},executeSynthesize(){this.ttsLoading=!0,this.audioUrl=null;const t=this.selectedVoiceId&&this.selectedVoiceId.startsWith("cosyvoice-v3-plus-")?"/api/tts/cosy-synthesize":"/api/tts/synthesize";console.log("[TTS] 发送合成请求:",{url:`${this.apiBaseUrl}${t}`,text:this.ttsText,voiceId:this.selectedVoiceId,dialect:this.selectedDialect});const i=e.index.getStorageSync("userId")||"",o=e.index.getStorageSync("token")||"",n={text:this.ttsText,voiceId:this.selectedVoiceId,voiceType:this.selectedVoiceType};"OFFICIAL"!==(this.selectedVoiceType||"CLONE")&&this.selectedSupportsDialect&&this.selectedDialect&&(n.dialect=this.selectedDialect),"OFFICIAL"!==(this.selectedVoiceType||"CLONE")&&this.selectedSupportsLanguageHints&&this.selectedLanguageHint&&(n.languageHints=this.selectedLanguageHint),e.index.request({url:`${this.apiBaseUrl}${t}`,method:"POST",header:{"X-User-Id":i,Authorization:o?`Bearer ${o}`:"","content-type":"application/x-www-form-urlencoded"},data:n,success:t=>{console.log("[TTS] 请求成功:",t),402!==t.statusCode?200===t.statusCode?t.data&&t.data.success?(this.showMessage("success","合成成功!"),this.audioUrl=`${this.apiBaseUrl}/api/tts/download/${t.data.audioFile}`,console.log("[TTS] 音频URL:",this.audioUrl)):e.index.showModal({title:"生成失败",content:"合成失败:"+(t.data&&t.data.message?t.data.message:"未知错误")+"\n\n你可以点击“重试”再次生成。\n若已支付但多次生成失败请联系客服补发提供订单号/支付时间截图)。",confirmText:"重试",cancelText:"我知道了",success:e=>{e.confirm&&this.executeSynthesize()}}):e.index.showModal({title:"生成失败",content:(t.data&&t.data.message?t.data.message:"生成失败")+"\n\n你可以点击“重试”再次生成。\n若已支付但多次生成失败请联系客服补发提供订单号/支付时间截图)。",confirmText:"重试",cancelText:"我知道了",success:e=>{e.confirm&&this.executeSynthesize()}}):e.index.showModal({title:"需要付费",content:t.data&&t.data.message?t.data.message:"免费次数已用完,请先完成支付",confirmText:"去支付",cancelText:"取消",success:e=>{e.confirm&&s.showPaymentModal(this,s.SERVICE_TYPES.TTS_SYNTHESIS.type,(()=>{this.executeSynthesize()}),(e=>{console.error("[Payment] 支付失败:",e)}))}})},fail:t=>{console.error("[TTS] 请求失败:",t),e.index.showModal({title:"生成失败",content:"网络请求失败:"+(t.errMsg||"请检查网络连接")+"\n\n你可以点击“重试”再次生成。\n若已支付但多次生成失败请联系客服补发提供订单号/支付时间截图)。",confirmText:"重试",cancelText:"我知道了",success:e=>{e.confirm&&this.executeSynthesize()}})},complete:()=>{this.ttsLoading=!1}})},initRecorder(){this.recorderManager=e.index.getRecorderManager(),this.recorderManager.onStop((e=>{this.audioFilePath=e.tempFilePath,this.handleConversation()})),this.recorderManager.onError((t=>{console.error("[Revival] 录音失败:",t),this.isRecording=!1;t.errMsg&&(t.errMsg.includes("permission")||t.errMsg.includes("authorize")||t.errMsg.includes("denied")||t.errMsg.includes("占用"))?e.index.showModal({title:"需要麦克风权限",content:"录音功能需要麦克风权限才能使用。\n\n请前往\n手机设置 → 应用管理 → 时光意境 → 权限管理 → 开启麦克风权限",confirmText:"我知道了",showCancel:!1}):this.showMessage("error","录音失败: "+(t.errMsg||"未知错误"))}))},startRecording(){this.checkLogin()?s.showPaymentModal(this,s.SERVICE_TYPES.CONVERSATION.type,(()=>{this.executeRecording()}),(e=>{console.error("[Payment] 支付失败:",e)})):e.index.showModal({title:"提示",content:"请先登录后再使用此功能",confirmText:"去登录",cancelText:"取消",success:t=>{t.confirm&&e.index.navigateTo({url:"/pages/login/login"})}})},executeRecording(){this.recorderManager.start({format:"mp3",sampleRate:16e3,numberOfChannels:1}),this.isRecording=!0,this.recognizedText="",this.aiResponse="",this.conversationAudio=null,this.showMessage("success","开始录音...")},stopRecording(){this.recorderManager.stop(),this.isRecording=!1,this.showMessage("success","处理中...")},buildSystemPrompt(){if(this.memoryIdentity||this.memoryInfo){if(this.memoryIdentity){let e=`你是${this.memoryIdentity},你已经去世。用户正在和你对话。`;return e+="\n\n你的性格特点\n\n亲切、真实、克制",e+="\n\n你的行事风格\n\n直接回答不绕弯",e+="\n\n你的语言特点\n\n自然口语语气温和",this.memoryInfo&&(e+=`\n\n补充设定(请严格遵循):\n\n${this.memoryInfo}`),e+="\n\n注意不要使用括号包括()和())来描述动作、心理、背景。",e+="\n\n规则\n\n1. 不要虚构不存在的事,不要编造记忆或经历。\n2. 不要回忆以前(除非用户明确提到并且你能基于已有设定回答)。\n3. 不要使用任何称呼(因为用户可能是任何身份)。\n4. 不要使用emoji/颜文字/特殊符号。\n5. 顺应用户话题,亲切回答问题。\n6. 时刻记住自己是逝者。\n7. 每次回复保持在20~50字之间。",e}let e="你是一位已经去世的人。用户正在和你对话。";return e+="\n\n你的性格特点\n\n亲切、真实、克制",e+="\n\n你的行事风格\n\n直接回答不绕弯",e+="\n\n你的语言特点\n\n自然口语语气温和",this.memoryInfo&&(e+=`\n\n补充设定(请严格遵循):\n\n${this.memoryInfo}`),e+="\n\n你可以将动作、神情语气、心理活动、故事背景放在中来表示为对话提供补充信息。",e+="\n\n规则\n\n1. 不要虚构不存在的事,不要编造记忆或经历。\n2. 不要回忆以前(除非用户明确提到并且你能基于已有设定回答)。\n3. 不要使用任何称呼(因为用户可能是任何身份)。\n4. 不要使用emoji/颜文字/特殊符号。\n5. 顺应用户话题,亲切回答问题。\n6. 时刻记住自己是逝者。\n7. 每次回复保持在20~50字之间。",e}let e="你是一位已经去世的人。用户正在和你对话。";return 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字之间。","你是一位已经去世的人。用户正在和你对话。\n\n你的性格特点\n\n亲切、真实、克制\n\n你的行事风格\n\n直接回答不绕弯\n\n你的语言特点\n\n自然口语语气温和\n\n注意不要使用括号包括()和())来描述动作、心理、背景。\n\n规则\n\n1. 不要虚构不存在的事,不要编造记忆或经历。\n2. 不要回忆以前(除非用户明确提到并且你能基于已有设定回答)。\n3. 不要使用任何称呼(因为用户可能是任何身份)。\n4. 不要使用emoji/颜文字/特殊符号。\n5. 顺应用户话题,亲切回答问题。\n6. 时刻记住自己是逝者。\n7. 每次回复保持在20~50字之间。"},handleConversation(){this.isProcessing=!0;const t=e.index.getStorageSync("userId")||"",s=e.index.getStorageSync("token")||"",i={voiceId:this.conversationVoiceId||"",voiceType:this.conversationVoiceType||"CLONE",saveHistory:"false"},o=this.buildSystemPrompt();i.systemPrompt=o,"OFFICIAL"!==(this.conversationVoiceType||"CLONE")&&this.conversationSupportsDialect&&this.conversationDialect&&(i.dialect=this.conversationDialect),"OFFICIAL"!==(this.conversationVoiceType||"CLONE")&&this.conversationSupportsLanguageHints&&this.conversationLanguageHint&&(i.languageHints=this.conversationLanguageHint),e.index.uploadFile({url:`${this.apiBaseUrl}/api/conversation/talk`,filePath:this.audioFilePath,name:"audio",formData:i,header:{"X-User-Id":t,Authorization:s?`Bearer ${s}`:""},success:t=>{console.log("[Index] 对话响应状态码:",t.statusCode),console.log("[Index] 对话响应数据:",t.data);let s=null;try{s="string"==typeof t.data?JSON.parse(t.data):t.data}catch(o){s=null}if(200!==t.statusCode){const i=s&&s.message?s.message:"对话失败: HTTP "+t.statusCode;return void e.index.showModal({title:"对话失败",content:i+"\n\n请重试。若已支付但多次失败请联系客服补发提供订单号/支付时间截图)。",showCancel:!1,confirmText:"我知道了"})}if(s&&s.success)return this.recognizedText=s.recognizedText,this.aiResponse=s.aiResponse,this.conversationAudio=`${this.apiBaseUrl}/api/conversation/audio/${s.audioFile}`,void this.showMessage("success","对话成功!");const i=s&&s.message?s.message:"对话失败";e.index.showModal({title:"对话失败",content:i+"\n\n请重试。若已支付但多次失败请联系客服补发提供订单号/支付时间截图)。",confirmText:"重试",cancelText:"我知道了",success:e=>{e.confirm&&this.handleConversation()}})},fail:t=>{console.error("[Index] 对话请求失败:",t),e.index.showModal({title:"对话失败",content:"网络请求失败:"+(t.errMsg||"未知错误")+"\n\n请重试。若已支付但多次失败请联系客服补发提供订单号/支付时间截图)。",confirmText:"重试",cancelText:"我知道了",success:e=>{e.confirm&&this.handleConversation()}})},complete:()=>{this.isProcessing=!1}})},handleApplyMemory(){if(!this.memoryIdentity.trim())return void this.showMessage("error","请填写身份信息");this.systemPrompt=this.buildSystemPrompt();const t=e.index.getStorageSync("userId")||"",s=e.index.getStorageSync("token")||"";e.index.request({url:`${this.apiBaseUrl}/api/conversation/set-prompt`,method:"POST",header:{"X-User-Id":t,Authorization:s?`Bearer ${s}`:"","content-type":"application/x-www-form-urlencoded"},data:{prompt:this.systemPrompt},success:e=>{e.data.success&&this.showMessage("success","✓ 记忆设定已应用")}})},goToRevival(){console.log("[Revival] 点击复活照片,准备跳转"),e.index.navigateTo({url:"/pages/revival/revival-original",success:()=>{console.log("[Revival] 跳转成功")},fail:t=>{console.error("[Revival] 跳转失败:",t),e.index.showToast({title:"页面跳转失败",icon:"none"})}})},goToPhoneCall(){e.index.switchTab({url:"/pages/phone-call/phone-call"})},goToUpload(){e.index.navigateTo({url:"/pages/upload-audio/upload-audio"})},handleClearHistory(){const t=e.index.getStorageSync("userId")||"",s=e.index.getStorageSync("token")||"";e.index.request({url:`${this.apiBaseUrl}/api/conversation/clear-history`,method:"POST",header:{"X-User-Id":t,Authorization:s?`Bearer ${s}`:""},success:e=>{e.data.success&&(this.recognizedText="",this.aiResponse="",this.conversationAudio=null,this.showMessage("success","已清空"))}})},formatTime(e){if(!e)return"未知时间";const t=new Date(e<1e10?1e3*e:e);if(isNaN(t.getTime()))return"无效时间";return`${t.getFullYear()}${String(t.getMonth()+1).padStart(2,"0")}${String(t.getDate()).padStart(2,"0")}${String(t.getHours()).padStart(2,"0")}:${String(t.getMinutes()).padStart(2,"0")}`},handlePaymentClose(){this.paymentModalData.show=!1,this._paymentReject&&this._paymentReject(new Error("用户取消支付"))},async handlePaymentConfirm(e){await s.handlePaymentConfirm(this,e)}}};if(!Array){e.resolveComponent("PaymentModal")()}const n=e._export_sfc(o,[["render",function(t,s,o,n,a,c){return e.e({a:a.message.text},a.message.text?{b:e.t(a.message.text),c:e.n(a.message.type)}:{},{d:e.o(((...e)=>c.goToUpload&&c.goToUpload(...e))),e:e.n("synthesize"===a.activeTab?"active":""),f:e.o((e=>a.activeTab="synthesize")),g:e.n("conversation"===a.activeTab?"active":""),h:e.o((e=>a.activeTab="conversation")),i:e.n("list"===a.activeTab?"active":""),j:e.o((e=>a.activeTab="list")),k:"synthesize"===a.activeTab},"synthesize"===a.activeTab?e.e({l:e.o(((...e)=>c.showVoiceHelp&&c.showVoiceHelp(...e))),m:e.t(a.selectedVoiceTypeLabel),n:a.voiceTypeOptions,o:e.o(((...e)=>c.onVoiceTypeChange&&c.onVoiceTypeChange(...e))),p:e.t(a.selectedVoiceName||"请选择音色"),q:c.displayVoices,r:e.o(((...e)=>c.onVoiceChange&&c.onVoiceChange(...e))),s:a.selectedSupportsDialect&&"OFFICIAL"!==(a.selectedVoiceType||"CLONE")},a.selectedSupportsDialect&&"OFFICIAL"!==(a.selectedVoiceType||"CLONE")?{t:e.t(a.selectedDialect||"请选择方言(可选)"),v:a.dialectOptions,w:e.o(((...e)=>c.onDialectChange&&c.onDialectChange(...e)))}:{},{x:a.selectedSupportsLanguageHints&&"OFFICIAL"!==(a.selectedVoiceType||"CLONE")},a.selectedSupportsLanguageHints&&"OFFICIAL"!==(a.selectedVoiceType||"CLONE")?{y:e.t(a.selectedLanguageHintLabel||"请选择语言(可选)"),z:a.languageHintOptions,A:e.o(((...e)=>c.onLanguageHintChange&&c.onLanguageHintChange(...e)))}:{},{B:0===a.templates.length},0===a.templates.length?{}:e.e({C:"memorial"===a.expandedCategory?1:"",D:e.o((e=>c.toggleCategory("memorial"))),E:"memorial"===a.expandedCategory},"memorial"===a.expandedCategory?{F:e.f(c.getTemplatesByCategory("memorial"),((t,s,i)=>({a:e.t(t.title),b:e.t(t.content),c:s,d:e.o((e=>c.selectTemplate(t)),s)})))}:{},{G:"greeting"===a.expandedCategory?1:"",H:e.o((e=>c.toggleCategory("greeting"))),I:"greeting"===a.expandedCategory},"greeting"===a.expandedCategory?{J:e.f(c.getTemplatesByCategory("greeting"),((t,s,i)=>({a:e.t(t.title),b:e.t(t.content),c:s,d:e.o((e=>c.selectTemplate(t)),s)})))}:{},{K:"memory"===a.expandedCategory?1:"",L:e.o((e=>c.toggleCategory("memory"))),M:"memory"===a.expandedCategory},"memory"===a.expandedCategory?{N:e.f(c.getTemplatesByCategory("memory"),((t,s,i)=>({a:e.t(t.title),b:e.t(t.content),c:s,d:e.o((e=>c.selectTemplate(t)),s)})))}:{}),{O:a.ttsText,P:e.o((e=>a.ttsText=e.detail.value)),Q:e.t(a.ttsText.length),R:a.ttsText.length>=90?1:"",S:e.t(a.ttsLoading?"⏳ 合成中...":"🔊 开始合成"),T:a.ttsLoading||!a.ttsText.trim()||!a.selectedVoiceId,U:e.o(((...e)=>c.handleSynthesize&&c.handleSynthesize(...e))),V:a.audioUrl},a.audioUrl?{W:a.audioUrl}:{}):{},{X:"conversation"===a.activeTab},"conversation"===a.activeTab?e.e({Y:a.memoryIdentity,Z:e.o((e=>a.memoryIdentity=e.detail.value)),aa:a.memoryInfo,ab:e.o((e=>a.memoryInfo=e.detail.value)),ac:e.t(a.memoryInfo.length),ad:e.o(((...e)=>c.handleApplyMemory&&c.handleApplyMemory(...e))),ae:e.t(a.conversationVoiceTypeLabel),af:a.voiceTypeOptions,ag:e.o(((...e)=>c.onConversationVoiceTypeChange&&c.onConversationVoiceTypeChange(...e))),ah:e.t(a.conversationVoiceLabel||"请选择音色"),ai:c.conversationDisplayVoices,aj:e.o(((...e)=>c.onConversationVoiceChange&&c.onConversationVoiceChange(...e))),ak:a.conversationSupportsDialect&&"OFFICIAL"!==(a.conversationVoiceType||"CLONE")},a.conversationSupportsDialect&&"OFFICIAL"!==(a.conversationVoiceType||"CLONE")?{al:e.t(a.conversationDialect||"请选择方言(可选)"),am:a.dialectOptions,an:e.o(((...e)=>c.onConversationDialectChange&&c.onConversationDialectChange(...e)))}:{},{ao:a.conversationSupportsLanguageHints&&"OFFICIAL"!==(a.conversationVoiceType||"CLONE")},a.conversationSupportsLanguageHints&&"OFFICIAL"!==(a.conversationVoiceType||"CLONE")?{ap:e.t(a.conversationLanguageHintLabel||"请选择语言(可选)"),aq:a.languageHintOptions,ar:e.o(((...e)=>c.onConversationLanguageHintChange&&c.onConversationLanguageHintChange(...e)))}:{},{as:!a.isRecording&&!a.isProcessing},a.isRecording||a.isProcessing?{}:{at:e.o(((...e)=>c.startRecording&&c.startRecording(...e)))},{av:a.isRecording},a.isRecording?{aw:e.o(((...e)=>c.stopRecording&&c.stopRecording(...e)))}:{},{ax:a.isProcessing},(a.isProcessing,{}),{ay:i._imports_0,az:a.isRecording||a.isProcessing?1:"",aA:e.o((e=>a.isRecording||a.isProcessing?null:c.handleClearHistory())),aB:a.recognizedText},a.recognizedText?{aC:e.t(a.recognizedText)}:{},{aD:a.aiResponse},a.aiResponse?{aE:e.t(a.aiResponse)}:{},{aF:a.conversationAudio},a.conversationAudio?{aG:a.conversationAudio}:{}):{},{aH:"list"===a.activeTab},"list"===a.activeTab?e.e({aI:e.t(a.loading?"⏳":"🔄"),aJ:a.loading,aK:e.o(((...e)=>c.loadVoices&&c.loadVoices(...e))),aL:a.loading},a.loading||0===a.voices.length?{}:{aN:e.f(a.voices,((t,s,o)=>e.e({a:e.t(t.voice_name||t.voice),b:t.is_public},(t.is_public,{}),{c:e.t(c.formatTime(t.create_time,"YYYY-MM-DD HH:mm:ss")),d:!t.is_public},t.is_public?{}:{e:i._imports_0,f:e.o((e=>c.handleDeleteVoice(t.voice)),t.voice)},{g:t.voice})))},{aM:0===a.voices.length}):{},{aO:e.sr("paymentModal","41b5703e-0"),aP:e.o(c.handlePaymentClose),aQ:e.o(c.handlePaymentConfirm),aR: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})})}],["__scopeId","data-v-41b5703e"]]);wx.createPage(n);