<template>
  <div class="voice-interview-page">
    <!-- 顶部状态栏 -->
    <div class="interview-header">
      <h1 class="interview-title">智能语音面试</h1>
      <div class="progress-bar">
        <span class="progress-text">问题 {{ currentQuestionIndex }}/{{ totalQuestions }}</span>
        <el-progress 
          :percentage="(currentQuestionIndex / totalQuestions) * 100" 
          :show-text="false"
          stroke-width="8"
        />
      </div>
    </div>

    <!-- 主要内容区域 -->
    <div class="interview-main">
      <el-row :gutter="20">
        <!-- 左侧:视频录制部分 -->
        <el-col :span="8">
          <div class="video-section">
            <div class="video-card">
              <h2 class="video-title">
                <i class="el-icon-video-camera"></i>
                视频录制
              </h2>
              <p class="video-tip">系统将自动录制您回答问题的过程</p>
              <VideoRecorder
                ref="videoRecorderRef"
                :session-id="sessionId"
                :question-index="currentQuestionIndex"
                :auto-start="true"
                @video-submitted="handleVideoSubmitted"
                @video-upload-failed="handleVideoUploadFailed"
              />
            </div>
          </div>
        </el-col>

        <!-- 中间:数字人区域 -->
        <el-col :span="8">
          <div class="avatar-section">
            <div class="avatar-card">
<!--              <h2 class="avatar-title">
                <i class="el-icon-user"></i>
                数字人面试官
              </h2>-->
              <div class="avatar-container">
                <div class="weather rain" id="wrapper"></div>
<!--                <div class="avatar-controls">
                  <span>透明度</span>
                  <input type="range" id="opacityRange" min="0" max="1" step="0.1" value="1">
                </div>-->
              </div>
            </div>
          </div>
        </el-col>

        <!-- 右侧:语音交互部分 -->
        <el-col :span="8">
          <!-- 状态指示器 -->
          <div class="status-indicator">
            <div v-if="isReadingQuestion" class="status-item reading">
              <div class="status-icon">
                <i class="el-icon-s-promotion"></i>
              </div>
              <div class="status-content">
                <h3>正在播报题目</h3>
                <p>请仔细聆听面试问题...</p>
              </div>
            </div>
            
            <div v-else-if="isRecording" class="status-item recording">
              <div class="status-icon recording-pulse">
                <i class="el-icon-microphone"></i>
              </div>
              <div class="status-content">
                <h3>请开始回答</h3>
                <p>录音时间: {{ formatTime(recordingTime) }}</p>
              </div>
            </div>
            
            <div v-else-if="isProcessing" class="status-item processing">
              <div class="status-icon">
                <i class="el-icon-loading"></i>
              </div>
              <div class="status-content">
                <h3>正在处理</h3>
                <p>请稍候,正在提交您的回答...</p>
              </div>
            </div>
            
            <div v-else class="status-item ready">
              <div class="status-icon">
                <i class="el-icon-check"></i>
              </div>
              <div class="status-content">
                <h3>准备就绪</h3>
                <p>点击开始按钮开始面试</p>
              </div>
            </div>
          </div>

          <!-- 题目显示区域 -->
          <div class="question-display">
            <div class="question-card">
              <h2 class="question-title">面试问题</h2>
              <div class="question-content">
                <p>{{ currentQuestion }}</p>
              </div>

            </div>
          </div>

          <!-- 实时转录显示区域 -->
          <div class="transcription-display" v-if="isRecording || transcriptionResult">
            <div class="transcription-card">
              <h3 class="transcription-title">
                <i class="el-icon-chat-line-round"></i>
                {{ isRecording ? '实时转录' : '您的回答' }}
              </h3>
              <div class="transcription-content">
                <div class="transcription-text" v-if="transcriptionResult">
                  {{ transcriptionResult }}
                </div>
                <div class="transcription-placeholder" v-else>
                  <i class="el-icon-microphone"></i>
                  <p>请开始说话,系统将实时转录您的回答...</p>
                </div>
              </div>
              
              <!-- 录音控制按钮 -->
              <div class="transcription-actions" v-if="isRecording">
                <el-button 
                  type="success" 
                  size="large"
                  @click="finishAnswer"
                  :disabled="!transcriptionResult">
                  <i class="el-icon-check"></i>
                  完成回答
                </el-button>
                <el-button 
                  type="danger" 
                  size="large"
                  @click="cancelRecording">
                  <i class="el-icon-close"></i>
                  取消录音
                </el-button>
              </div>
              
              <!-- 提交按钮 -->
              <div class="transcription-actions" v-if="!isRecording && transcriptionResult && !isProcessing">
                <el-button 
                  type="primary" 
                  size="large"
                  @click="submitAnswer">
                  <i class="el-icon-right"></i>
                  {{ currentQuestionIndex < totalQuestions ? '下一题' : '完成面试' }}
                </el-button>
                <el-button 
                  size="large"
                  @click="retryAnswer">
                  <i class="el-icon-refresh"></i>
                  重新回答
                </el-button>
              </div>
            </div>
          </div>
        </el-col>
      </el-row>

      <!-- 评估结果显示 -->
      <!-- 移除整个评估结果显示区域 -->
      <!-- 删除以下代码块:
      <div class="evaluation-display" v-if="currentEvaluation">
        <div class="evaluation-card">
          <h3 class="evaluation-title">
            <i class="el-icon-trophy"></i>
            本题评估
          </h3>
          <div class="evaluation-content">
            <div class="evaluation-score">
              <el-progress 
                type="circle" 
                :percentage="evaluationScore" 
                :color="scoreColor"
                :width="80">
                <template #default="{ percentage }">
                  <span class="score-text">{{ percentage }}</span>
                </template>
              </el-progress>
            </div>
            <div class="evaluation-details">
              <div class="evaluation-section" v-if="currentEvaluation.strengths?.length">
                <h4>优点</h4>
                <ul>
                  <li v-for="(strength, index) in currentEvaluation.strengths" :key="index">
                    {{ strength }}
                  </li>
                </ul>
              </div>
              <div class="evaluation-section" v-if="currentEvaluation.suggestions">
                <h4>建议</h4>
                <p>{{ currentEvaluation.suggestions }}</p>
              </div>
            </div>
          </div>
        </div>
      </div>
      -->
    </div>

    <!-- 隐藏的录音组件 -->
    <AudioRecorder 
      ref="audioRecorderRef"
      :session-id="sessionId"
      @transcription-update="handleTranscriptionUpdate"
      @transcription-complete="handleTranscriptionComplete"
      style="display: none;"
    />

    <!-- 面试完成对话框 -->
    <el-dialog
      v-model="showCompletionDialog"
      title="面试完成"
      width="500px"
      :close-on-click-modal="false"
      :close-on-press-escape="false">
      <div class="completion-content">
        <div class="completion-icon">
          <i class="el-icon-success"></i>
        </div>
        <h3>恭喜您完成了本次面试!</h3>
        <p>系统正在生成您的面试报告,请稍候...</p>
      </div>
      <template #footer>
        <el-button type="primary" @click="viewResults">
          查看面试结果
        </el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, reactive,computed, onMounted, onUnmounted, watch ,onBeforeUnmount} from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { ElMessage, ElMessageBox } from 'element-plus';
import { interviewAPI } from '../services/api';
import AudioRecorder from '../components/AudioRecorder.vue';
import VideoRecorder from '../components/VideoRecorder.vue';
import XfyunTTSService from '../services/xfyunTTS.js';
import { TTS_CONFIG } from '../config/tts.js';
import AvatarPlatform, {PlayerEvents, SDKEvents,} from "../vm-sdk/avatar-sdk-web_3.1.1.1011/index.js";


const route = useRoute();
const router = useRouter();
const sessionId = route.params.sessionId;

// 基础状态
const currentQuestion = ref('正在加载面试问题...');
const currentQuestionIndex = ref(1);
const totalQuestions = ref(5);
const transcriptionResult = ref('');
const currentEvaluation = ref(null);
const showCompletionDialog = ref(false);

// 流程状态
const isReadingQuestion = ref(false);
const isRecording = ref(false);
const isProcessing = ref(false);
const recordingTime = ref(0);
const recordingTimer = ref(null);

// 组件引用
const audioRecorderRef = ref(null);
const videoRecorderRef = ref(null);
const ttsService = new XfyunTTSService();


// 全局变量
let avatarPlatform2 = null
let recorder = null

// 响应式数据
const SetApiInfodialog = ref(false)
const SetGlobalParamsdialog = ref(false)
const textarea = ref("")
const vc = ref("")
const recorderbutton = ref(false)
const nlp = ref(false)
const emotion = ref(0)
const action = ref("A_RH_hello_O")
const volume = ref(100)
const formLabelWidth = ref("120px")

// 表单数据
const form = reactive({
  appid: "2e96547f", // 到交互平台-接口服务中获取
  apikey: "98e4b25f7fe16f861124b62789d4cb2a", // 到交互平台-接口服务中获取
  apisecret: "YjM2Nzc1NjM2ZDMwNTdhZDZjY2UzNWVm", // 到交互平台-接口服务中获取
  sceneid: "193755375642742784", // 到交互平台-接口服务中获取,即"接口服务ID"
  serverurl: "wss://avatar.cn-huadong-1.xf-yun.com/v1/interact", // 接口地址,无需更改
})

// 全局参数表单数据
const setglobalparamsform = reactive({
  stream: {
    protocol: "xrtc", // (必传)实时视频协议,支持webrtc/xrtc/rtmp,其中只有xrtc支持透明背景,需参数alpha传1
    fps: 25, // (非必传)视频刷新率,值越大,越流畅,取值范围0-25,默认25即可
    bitrate: 1000000, // (非必传)视频码率,值越大,越清晰,对网络要求越高,默认1000000即可
    alpha: true, // (非必传)是否开启透明背景,0关闭1开始,需配合protocol=xrtc使用
  },
  avatar: {
    avatar_id: "110332017", // (必传)授权的形象资源id,请到交互平台-接口服务-形象列表中获取
    width: 1080, // (非必传)视频分辨率宽(不是画布的宽,调整画布大小需调整名为wrapper的div宽)
    height: 1920, // (非必传)视频分辨率高(不是画布的高,调整画布大小需调整名为wrapper的div高)
    mask_region: "[0,0,1080,1920]", // (非必传)形象裁剪参数,[从左到右,从上到下,从右到左,从下到上]
    scale: 1, // (非必传)形象缩放比例,取值范围0.1-1
    move_h: 0, // (非必传)形象左右移动
    move_v: 0, // (非必传)形象上下移动
    audio_format: 1, // (非必传)音频采样率,传1即可
  },
  tts: {
    vcn: "x4_lingxiaoying_assist", // (必传)授权的声音资源id,请到交互平台-接口服务-声音列表中获取
    speed: 50, // (非必传)语速
    pitch: 50, // (非必传)语调
    volume: 100, // (非必传)音量
    emotion: 13, // (非必传)情感系数,仅带有情感能力的超拟人音色支持该能力,普通音色不支持
  },
  avatar_dispatch: {
    interactive_mode: 1, // (非必传)0追加模式,1打断模式
  },
  subtitle: {
    subtitle: 1, // (非必传)开启字幕,2D形象支持字幕,透明背景不支持字幕,3D形象不支持字幕(3D形象多为卡通形象,2D多为真人形象)
    font_color: "#FFFFFF", // (非必传)字体颜色
    font_name: "Sanji.Suxian.Simple", // (非必传)不支持自定义字体,若不想使用默认提供的
    // 字体,那么可以设置asr和nlp监听事件,去获取语音识别和语义理解的文本,自己前端贴字体。
    // 支持一下字体:'Sanji.Suxian.Simple','Honglei.Runninghand.Sim','Hunyuan.Gothic.Bold',
    // 'Huayuan.Gothic.Regular','mainTitle'
    position_x: 100, // (非必传)设置字幕水平位置,必须配置width、height一起使用,否则字幕不显示
    position_y: 0, // (非必传)设置字幕竖向位置,必须配置width、height一起使用,否则字幕不显示
    font_size: 10, // (非必传)设置字幕字体大小,取值范围:1-10
    width: 100, // (非必传)设置字幕宽
    height: 100, // (非必传)设置字幕高
  },
  enable: false, // demo中用来控制是否开启背景的参数,与虚拟人参数无关
  background: {
    type: "res_key", // (非必传)上传图片的类型,支持url以及res_key。(res_key请到交互平台-素材管理-背景中上传获取)
    data: "22SLM2teIw+aqR6Xsm2JbH6Ng310kDam2NiCY/RQ9n6dw47gMO+7gGUJfWWfkqD3IxsU/HMK1uJTTxxF2llcKSM4dlSdBy0Piag/DndHocqs32kTOwXUw6lkyggYQBXF0uwTv9jVFm1ZjZgSehV3kpx5RTvizZ9MqEI8lotCRvokC9HLI0pGfKtSmlKgCKL+OUoc9QI5HW3wLtYbLersumd4UCKEPk/uWAdKEh4ntSJiW2km8waGFsg/VSNFj5vaDK3LC4PxfsRvi1a2veZW7JUs/VOleE9wwgTH+A/oqPPcyksBY7aQ4TxYjvS9Qj9LtXkvOwttQMgPGwoxlqBEBhR/xLUwmecHkHzgjACFtxE=", // (非必传)图片的值,当type='url'时,data='http://xxx/xxx.png',当type='res_key'时,data='res_key值'(res_key请到交互平台-素材管理-背景中上传获取)
  }
})

// 计算属性
const evaluationScore = computed(() => {
  if (!currentEvaluation.value?.score) return 0;
  return Math.min(Math.round(currentEvaluation.value.score * 10), 100);
});

const scoreColor = computed(() => {
  const score = evaluationScore.value;
  if (score >= 80) return '#67C23A';
  if (score >= 60) return '#E6A23C';
  return '#F56C6C';
});

// TTS 服务配置
ttsService.onPlay(() => {
  isReadingQuestion.value = true;
});

ttsService.onStop(() => {
  isReadingQuestion.value = false;
  // 播报完成后自动开始录音
  setTimeout(() => {
    startRecording();
  }, 1000);
});

ttsService.onError((error) => {
  console.error('TTS错误:', error);
  isReadingQuestion.value = false;
  ElMessage.error('语音播报失败,请手动开始录音');
});

// 格式化时间
const formatTime = (seconds) => {
  const mins = Math.floor(seconds / 60);
  const secs = seconds % 60;
  return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
};

// 开始问题流程(播报题目)
const startQuestionFlow = async () => {
  if (!currentQuestion.value || currentQuestion.value === '正在加载面试问题...') {
    ElMessage.warning('题目尚未加载完成');
    return;
  }

  try {
    // 清空之前的转录结果
    transcriptionResult.value = '';
    currentEvaluation.value = null;
    
    // 开始播报题目
    /*await ttsService.speak(currentQuestion.value, {
      ...TTS_CONFIG.DEFAULT_OPTIONS,
      vcn: 'xiaoyan',
      speed: 45,
      volume: 80
    });*/
    writeText();


  } catch (error) {
    console.error('播报题目失败:', error);
    ElMessage.error('语音播报失败,请手动开始录音');
    isReadingQuestion.value = false;
  }
};

// 开始录音
const startRecording = async () => {
  try {
    isRecording.value = true;
    recordingTime.value = 0;
    
    // 启动录音计时器
    recordingTimer.value = setInterval(() => {
      recordingTime.value += 1;
    }, 1000);
    
    // 启动录音组件
    await audioRecorderRef.value?.startRealTimeTranscription();
    
    ElMessage.success('开始录音,请回答问题');
  } catch (error) {
    console.error('启动录音失败:', error);
    ElMessage.error('启动录音失败,请检查麦克风权限');
    isRecording.value = false;
    clearInterval(recordingTimer.value);
  }
};

// 完成回答
const finishAnswer = () => {
  if (!transcriptionResult.value) {
    ElMessage.warning('请先回答问题');
    return;
  }
  
  // 停止录音
  audioRecorderRef.value?.stopRealTimeTranscription();
  isRecording.value = false;
  clearInterval(recordingTimer.value);
  
  ElMessage.success('录音完成,请检查您的回答');
};

// 取消录音
const cancelRecording = async () => {
  try {
    const result = await ElMessageBox.confirm(
      '确定要取消当前录音吗?录音内容将丢失。',
      '确认取消',
      {
        confirmButtonText: '确定',
        cancelButtonText: '继续录音',
        type: 'warning'
      }
    );
    
    if (result === 'confirm') {
      audioRecorderRef.value?.stopRealTimeTranscription();
      isRecording.value = false;
      transcriptionResult.value = '';
      clearInterval(recordingTimer.value);
      ElMessage.info('已取消录音');
    }
  } catch {
    // 用户点击了取消,继续录音
  }
};

// 重新回答
const retryAnswer = () => {
  transcriptionResult.value = '';
  currentEvaluation.value = null;
  startRecording();
};

// 提交答案
// 修改 submitAnswer 方法
const submitAnswer = async () => {
  if (!transcriptionResult.value?.trim()) {
    ElMessage.warning('请先录音回答问题');
    return;
  }

  isProcessing.value = true;

  try {
    // 停止录音
    if (isRecording.value) {
      await stopVoiceRecognition();
    }

    // 处理视频录制
    if (videoRecorderRef.value && videoRecorderRef.value.isRecording) {
      try {
        await videoRecorderRef.value.stopRecording();
        await videoRecorderRef.value.submitVideo();
      } catch (videoError) {
        console.error('处理视频录制时出错:', videoError);
        // 继续提交答案,不阻止流程
      }
    }

    const response = await interviewAPI.answerQuestion(sessionId, transcriptionResult.value);

    // 不处理评估结果显示,直接处理下一题逻辑
    // 移除评估相关代码

    // 更新问题计数
    if (response.data.questionCount) {
      currentQuestionIndex.value = response.data.questionCount;
    }

    // 检查面试是否完成
    if (response.data.isComplete) {
      showCompletionDialog.value = true;
      // 如果面试完成,关闭摄像头
      if (videoRecorderRef.value) {
        videoRecorderRef.value.stopCamera();
      }
    } else {
      // 自动准备下一题
      currentQuestion.value = response.data.nextQuestion || response.data.question;
      
      // 清空转录结果
      transcriptionResult.value = '';
      // clearTranscription(); // 删除这一行
      
      // 延迟一下再自动开始下一题,给用户一个缓冲
      setTimeout(() => {
        startQuestionFlow();
      }, 1000);
    }

  } catch (error) {
    console.error('提交答案失败:', error);
    ElMessage.error('提交答案失败,请重试');
  } finally {
    isProcessing.value = false;
  }
};

// 处理视频提交成功事件
const handleVideoSubmitted = (videoUrl) => {
  console.log('视频提交成功:', videoUrl);
};

// 处理视频提交失败事件
const handleVideoUploadFailed = (error) => {
  console.error('视频提交失败:', error);
};

// 处理转录更新
const handleTranscriptionUpdate = (data) => {
  transcriptionResult.value = data.text;
};

// 处理转录完成
const handleTranscriptionComplete = (text) => {
  transcriptionResult.value = text;
};

// 查看结果
const viewResults = () => {
  router.push(`/results/${sessionId}`);
};

// 初始化面试
const initializeInterview = async () => {
  try {
    if (route.query.initialQuestion) {
      currentQuestion.value = route.query.initialQuestion;
      if (route.query.questionCount) {
        totalQuestions.value = parseInt(route.query.questionCount);
      }
    } else {
      const response = await interviewAPI.getInterviewResults(sessionId);
      
      if (response.data.current_question) {
        currentQuestion.value = response.data.current_question;
      } else if (response.data.questions && response.data.questions.length > 0) {
        currentQuestion.value = response.data.questions[0];
      } else {
        ElMessage.warning('无法获取面试问题,请从设置页面开始面试');
        setTimeout(() => router.push('/setup'), 2000);
        return;
      }

      if (response.data.question_count_limit) {
        totalQuestions.value = response.data.question_count_limit;
      }

      if (response.data.isComplete) {
        ElMessage.info('此面试会话已完成');
        showCompletionDialog.value = true;
        return;
      }
    }

    // 自动开始第一题
    setTimeout(() => {
      startQuestionFlow();
    }, 2000);
    
  } catch (error) {
    console.error('获取面试问题失败:', error);
    ElMessage.warning('无法获取面试问题,请从设置页面开始面试');
    setTimeout(() => router.push('/setup'), 2000);
  }
};


//数字人部分
const initSDK = () => {
  // 必须先实例化SDK,再去调用其挂载的方法
  avatarPlatform2 = new AvatarPlatform()
  if (avatarPlatform2 != null) {
    open2("实例化SDK成功")
  }
}

const createRecoder = () => {
  if (avatarPlatform2 != null) {
    recorder = avatarPlatform2.createRecorder()
    open2("创建录音器成功")
  } else {
    alert("请实例化SDK实例")
  }
}

const setSDKEvenet = () => {
  // 绑定SDK事件
  if (avatarPlatform2 != null) {
    avatarPlatform2
        .on(SDKEvents.connected, function (initResp) {
          console.log("SDKEvent.connect:initResp:", initResp)
        })
        .on(SDKEvents.stream_start, function () {
          console.log("stream_start")
        })
        .on(SDKEvents.disconnected, function (err) {
          console.log("SDKEvent.disconnected:", err)
          if (err) {
            // 因为异常 而导致的断开! 此处可以进行 提示通知等
            console.error("ws link disconnected because of Error")
            console.error(err.code, err.message, err.name, err.stack)
          }
        })
        .on(SDKEvents.nlp, function (nlpData) {
          console.log("语义理解内容nlp:", nlpData)
        })
        .on(SDKEvents.frame_start, function (frame_start) {
          console.log(
              "推流开始(可以看作一段文本开始播报时间点)frame_start:",
              frame_start
          )
        })
        .on(SDKEvents.frame_stop, function (frame_stop) {
          console.log(
              "推流结束(可以看作一段文本结束播报时间点)frame_stop:",
              frame_stop
          )
          if (isReadingQuestion.value) {
            isReadingQuestion.value = false;
            setTimeout(() => {
              startRecording();
            }, 1000);
          }
        })
        .on(SDKEvents.error, function (error) {
          console.log("错误信息error:", error)
        })
        .on(SDKEvents.connected, function () {
          console.log("connected")
        })
        .on(SDKEvents.asr, function (asrData) {
          console.log("语音识别数据asr:", asrData)
        })
        .on(SDKEvents.tts_duration, function (ttsData) {
          console.log("语音合成用时tts:", ttsData)
        })
        .on(SDKEvents.subtitle_info, function (subtitleData) {
          console.log("subtitleData:", subtitleData)
        })
        .on(SDKEvents.action_start, function (action_start) {
          console.log(
              "动作推流开始(可以看作动作开始时间节点)action_start:",
              action_start
          )
        })
        .on(SDKEvents.action_stop, function (action_stop) {
          console.log(
              "动作推流结束(可以看作动作结束时间点)action_stop:",
              action_stop
          )
        })
    open2("监听SDK事件成功")
  } else {
    alert("请先实例化SDK")
  }
}

const setPlayerEvenet = () => {
  if (avatarPlatform2 != null) {
    // 绑定播放器事件
    const player = avatarPlatform2.createPlayer()
    player
        .on(PlayerEvents.play, function () {
          console.log("paly")
        })
        .on(PlayerEvents.playing, function () {
          console.log("playing")
        })
        .on(PlayerEvents.waiting, function () {
          console.log("waiting")
        })
        .on(PlayerEvents.stop, function () {
          console.log("stop")
        })
        .on(PlayerEvents.playNotAllowed, function () {
          console.log(
              "playNotAllowed:触发了游览器限制自动播放策略,播放前必须与游览器产生交互(例如点击页面或者dom组件),触发该事件后调用avatarPlatform2.player.resume()方法来接触限制"
          )
          player.resume()
        })
    open2("监听播放器事件成功")
  } else {
    alert("请先实例化SDK")
  }
}

const SetApiInfo2 = () => {
  if (avatarPlatform2 == null) {
    alert("请先实例化SDK")
  } else {
    console.log("设置setApiInfo")
    const params = {
      appId: form.appid,
      apiKey: form.apikey,
      apiSecret: form.apisecret,
      serverUrl: form.serverurl,
      sceneId: form.sceneid,
    }
    console.log("初始化SDK信息:", params)
    // 初始化SDK
    avatarPlatform2.setApiInfo(params)
    open2("初始化SDK成功")
  }
}

const SetGlobalParams = () => {
  if (avatarPlatform2 != null) {
    let params = Object.assign({}, setglobalparamsform)
    console.log("setglobalparamsform.stream.alpha", setglobalparamsform.stream.alpha)
    if (setglobalparamsform.enable == false) {
      delete params.background
      delete params.enable
    }
    console.log("setglobalparamsform", setglobalparamsform)
    if (setglobalparamsform.stream.alpha == true) {
      console.log("设置alpha=1")
      params.stream.alpha = 1
    } else {
      console.log("设置alpha=0")
      params.stream.alpha = 0
    }
    console.log("设置的全局变量为:", params)
    avatarPlatform2.setGlobalParams(params)
    open2("设置全局变量成功")
  } else {
    alert("请先实例化SDK")
  }
}

const start = () => {
  if (avatarPlatform2 != null) {
    avatarPlatform2
        .start({ wrapper: document.querySelector("#wrapper") })
        .catch((e) => {
          console.error(e.code, e.message, e.name, e.stack)
        })
  } else {
    alert("请先实例化SDK")
  }
}

const writeText = () => {
  if (avatarPlatform2 != null) {
    isReadingQuestion.value = true;
    const text = currentQuestion.value;
    if (text != "" && vc.value == "") {
      avatarPlatform2.writeText(text, {
        nlp: nlp.value, // 是否开启语义理解
        tts: {
          volume: 100,
        },
      });
    } else if (text != "" && vc.value != "") {
      avatarPlatform2.writeText(text, {
        nlp: nlp.value, // 是否开启语义理解
        tts: {
          vcn: vc.value, // 变声
          volume: 100,
          emotion: emotion.value,
        },
      });
    } else {
      alert("内容不许为空");
    }
  } else {
    isReadingQuestion.value = false;
    alert("请先实例化SDK");
  }
};

const writeCmd = () => {
  avatarPlatform2.writeCmd("action", action.value)
}

const interrupt = () => {
  if (avatarPlatform2 != null) {
    avatarPlatform2.interrupt()
  } else {
    alert("请先实例化SDK")
  }
}

const startRecord = () => {
  if (avatarPlatform2 != null) {
    avatarPlatform2.recorder.startRecord(
        0,
        () => {
          console.warn('STOPED RECORDER')
        },
        {
          nlp: true,
          avatar_dispatch: {
            interactive_mode: 0 // 交互模式(追加或打断)
          }
        }
    )
    // 关闭录音按钮显示
    recorderbutton.value = true
  } else {
    alert("请先实例化SDK")
  }
}

const stopRecord = () => {
  if (avatarPlatform2 != null) {
    avatarPlatform2.recorder.stopRecord()
    // 开启录音按钮显示
    recorderbutton.value = false
  } else {
    alert("请先实例化SDK")
  }
}

const stop = () => {
  if (avatarPlatform2 != null) {
    avatarPlatform2.stop()
  } else {
    alert("请先实例化SDK")
  }
}

const destroy = () => {
  if (avatarPlatform2 != null) {
    // 销毁SDK示例,内部包含stop协议,重启需重新示例化avatarPlatform实例
    avatarPlatform2.destroy()
    avatarPlatform2 = null
  } else {
    alert("请先实例化SDK")
  }
}

const open2 = (text) => {
  /*ElMessage({
    message: text,
    type: "success",
  })*/
}


// 生命周期
onMounted(() => {
  const div = document.getElementById('wrapper')
  const range = document.getElementById('opacityRange')

  if (div && range) {
    range.addEventListener('input', function () {
      div.style.opacity = this.value
    })
  }
  initSDK();
  createRecoder();
  setSDKEvenet();
  setPlayerEvenet();
  SetApiInfo2();
  SetGlobalParams();
  start();
  initializeInterview();

});

onUnmounted(() => {
  // 清理资源
  ttsService.stop();
  clearInterval(recordingTimer.value);
  if (audioRecorderRef.value) {
    audioRecorderRef.value.stopRealTimeTranscription();
  }
  // 确保关闭摄像头
  if (videoRecorderRef.value) {
    videoRecorderRef.value.stopCamera();
  }

});

// 组件卸载前清理资源
onBeforeUnmount(() => {
  // 关闭页面时调用stop协议,确保链接断开,释放资源
  if (avatarPlatform2) {
    avatarPlatform2.stop()
  }
});
</script>

<style scoped>
.voice-interview-page {
  min-height: 100vh;
  background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%); /* 浅蓝色渐变 */
  padding: 20px;
}

.interview-header {
  text-align: center;
  margin-bottom: 30px;
}

.interview-title {
  color: white;
  font-size: 2.5rem;
  margin-bottom: 20px;
  text-shadow: 0 2px 4px rgba(0,0,0,0.3);
}

.progress-bar {
  max-width: 400px;
  margin: 0 auto;
  background: rgba(255,255,255,0.1);
  padding: 15px;
  border-radius: 10px;
  backdrop-filter: blur(10px);
}

.progress-text {
  color: white;
  font-size: 1.1rem;
  display: block;
  margin-bottom: 10px;
}

.interview-main {
  max-width: 1400px;
  margin: 0 auto;
}

/* 视频录制区域样式 */
.video-section {
  margin-bottom: 20px;
}

.video-card {
  background: white;
  border-radius: 15px;
  padding: 25px;
  box-shadow: 0 8px 32px rgba(0,0,0,0.1);
  height: 100%;
}

.video-title {
  color: #303133;
  font-size: 1.4rem;
  margin-bottom: 15px;
  display: flex;
  align-items: center;
  gap: 10px;
  text-align: center;
  justify-content: center;
}

.video-tip {
  color: #666;
  margin-bottom: 15px;
  text-align: center;
  font-size: 0.9rem;
}

/* 数字人区域样式 */
.avatar-section {
  margin-bottom: 20px;
}

.avatar-card {
  background: white;
  border-radius: 15px;
  padding: 25px;
  box-shadow: 0 8px 32px rgba(0,0,0,0.1);
  height: 100%;
}

.avatar-title {
  color: #303133;
  font-size: 1.4rem;
  margin-bottom: 15px;
  display: flex;
  align-items: center;
  gap: 10px;
  text-align: center;
  justify-content: center;
}

.avatar-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  height: 600px;
}

#wrapper {
  width: 400px;
  height: 500px;
  background: #f5f7fa;
  border: 2px solid #dcdfe6;
  border-radius: 10px;
  margin-bottom: 20px;
  position: relative;
  overflow: hidden;
}

.avatar-controls {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 10px;
}

.avatar-controls span {
  color: #606266;
  font-size: 0.9rem;
}

.avatar-controls input[type="range"] {
  width: 150px;
}

.status-indicator {
  margin-bottom: 20px;
}

.status-item {
  display: flex;
  align-items: center;
  gap: 20px;
  background: white;
  padding: 20px;
  border-radius: 15px;
  box-shadow: 0 8px 32px rgba(0,0,0,0.1);
}

.status-icon {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 24px;
  color: white;
}

.status-item.reading .status-icon {
  background: #409EFF;
}

.status-item.recording .status-icon {
  background: #E6A23C;
}

.status-item.processing .status-icon {
  background: #909399;
}

.status-item.ready .status-icon {
  background: #67C23A;
}

.recording-pulse {
  animation: pulse 1.5s infinite;
}

@keyframes pulse {
  0% { transform: scale(1); }
  50% { transform: scale(1.1); }
  100% { transform: scale(1); }
}

.status-content h3 {
  margin: 0 0 5px 0;
  color: #303133;
  font-size: 1.3rem;
}

.status-content p {
  margin: 0;
  color: #606266;
  font-size: 1rem;
}

.question-display,
.transcription-display,
.evaluation-display {
  margin-bottom: 20px;
}

.question-card,
.transcription-card,
.evaluation-card {
  background: white;
  border-radius: 15px;
  padding: 25px;
  box-shadow: 0 8px 32px rgba(0,0,0,0.1);
}

.question-title,
.transcription-title,
.evaluation-title {
  color: #303133;
  font-size: 1.4rem;
  margin-bottom: 15px;
  display: flex;
  align-items: center;
  gap: 10px;
}

.question-content {
  background: #f5f7fa;
  padding: 20px;
  border-radius: 10px;
  margin-bottom: 20px;
  border-left: 4px solid #409EFF;
}

.question-content p {
  font-size: 1.2rem;
  line-height: 1.6;
  margin: 0;
  color: #303133;
}

.question-actions {
  text-align: center;
}

.transcription-content {
  min-height: 120px;
  margin-bottom: 20px;
}

.transcription-text {
  background: #f0f9ff;
  border: 2px solid #409EFF;
  border-radius: 10px;
  padding: 20px;
  font-size: 1.1rem;
  line-height: 1.6;
  color: #303133;
}

.transcription-placeholder {
  text-align: center;
  color: #909399;
  padding: 40px 20px;
}

.transcription-placeholder i {
  font-size: 48px;
  margin-bottom: 15px;
  display: block;
}

.transcription-actions {
  display: flex;
  gap: 15px;
  justify-content: center;
  flex-wrap: wrap;
}

.evaluation-content {
  display: flex;
  gap: 30px;
  align-items: flex-start;
}

.evaluation-score {
  flex-shrink: 0;
}

.score-text {
  font-size: 18px;
  font-weight: bold;
}

.evaluation-details {
  flex: 1;
}

.evaluation-section {
  margin-bottom: 20px;
}

.evaluation-section h4 {
  color: #409EFF;
  margin-bottom: 10px;
  font-size: 1.1rem;
}

.evaluation-section ul {
  margin: 0;
  padding-left: 20px;
}

.evaluation-section li {
  margin-bottom: 5px;
  color: #606266;
}

.completion-content {
  text-align: center;
  padding: 20px;
}

.completion-icon {
  font-size: 64px;
  color: #67C23A;
  margin-bottom: 20px;
}

.completion-content h3 {
  color: #303133;
  margin-bottom: 15px;
}

.completion-content p {
  color: #606266;
}

/* 响应式设计 */
@media (max-width: 1200px) {
  .interview-main {
    max-width: 100%;
  }
  
  .avatar-container {
    height: 500px;
  }
  
  #wrapper {
    width: 320px;
    height: 420px;
  }
}

@media (max-width: 768px) {
  .voice-interview-page {
    padding: 10px;
  }
  
  .interview-title {
    font-size: 2rem;
  }
  
  .status-item {
    flex-direction: column;
    text-align: center;
    gap: 15px;
  }
  
  .evaluation-content {
    flex-direction: column;
    align-items: center;
  }
  
  .transcription-actions {
    flex-direction: column;
  }
  
  .interview-main .el-col {
    margin-bottom: 20px;
  }
  
  .avatar-container {
    height: 350px;
  }
  
  #wrapper {
    width: 250px;
    height: 300px;
  }
}
</style>
posted on 2025-05-23 23:29  leapss  阅读(15)  评论(0)    收藏  举报