<script setup lang="ts">
import { ref } from 'vue'
import request from '@/utils/request'
import AudioPlayer from '@/component/AudioPlayer.vue'

const voiceList = ref([])
const isLoading = ref(false)
const progress = ref(0)
let progressInterval: number | null = null

const getVoiceList = async() => {  
  try {
    const result = await request.get('/voiceList')
    voiceList.value = result.data.voiceList
  } catch (error) {
    alert('请求出错: ' + error)
  }  
}
getVoiceList()

const selectedVoice = ref('')
const gen_text = ref('')
const audioUrl = ref('')
const teacherMode = ref(false)

const generateAudio = async() => {
  if (!gen_text.value || !selectedVoice.value) {
    alert('请选择声音并输入文本')
    return
  }

  const formData = new FormData()
  formData.append("ref_audio_name", selectedVoice.value + '.mp3')
  formData.append("gen_text", gen_text.value)

  try {
    isLoading.value = true
    progress.value = 0
   
    // 设置3分钟(180000毫秒)内从0%增加到99%
    const targetDuration = 180000 // 3分钟(毫秒)
    const targetProgress = 99 // 目标进度
    const steps = 100 // 总步数
    const increment = targetProgress / steps // 每步增量
    const intervalTime = targetDuration / steps // 每步间隔时间

    progressInterval = setInterval(() => {
      if (progress.value < targetProgress) {
        progress.value = Math.min(progress.value + increment, targetProgress)
      }
    }, intervalTime) as unknown as number

    letresponse
    if (teacherMode.value == false) {
      response = await request.post('/generateAudio', formData, {
        responseType: 'blob',
      })
    } else {
      response = await request.post('/teacher', formData, {
        responseType: 'blob',
      })
    }

    // 清除定时器
    if (progressInterval) {
      clearInterval(progressInterval)
      progressInterval = null
    }
   
    // 直接跳到100%
    progress.value = 100
   
    const audioBlob = new Blob([response.data], { type: 'audio/wav' })
    audioUrl.value = URL.createObjectURL(audioBlob)

  } catch (error) {
    alert('生成失败: ' + (error.response?.data?.error || error.message))
    if (progressInterval) {
      clearInterval(progressInterval)
      progressInterval = null
    }
  } finally {
    isLoading.value = false
  }
}
</script>

<template>
  <div class="container mt-5">
    <div class="row">
      <!-- 左侧选择语音库 -->
      <div class="col-md-3">
        <div class="d-flex justify-content-between align-items-center mb-3">
          <label for="voiceSelect" class="form-label mb-0">选择声音</label>
          <select v-model="selectedVoice" id="voiceSelect" class="form-select w-50">
            <option value="" disabled>请选择</option>
            <option v-for="(voice, index) in voiceList" :key="index" :value="voice">
              {{ voice }}
            </option>
          </select>
        </div>
       
        <div class="d-flex justify-content-between align-items-center">
          <label for="teacherMode" class="form-label mb-0">教师模式</label>
          <div class="form-check form-switch">
            <input class="form-check-input" type="checkbox" id="teacherMode" v-model="teacherMode" style="width: 3em; height: 1.5em;">
          </div>
        </div>
      </div>

      <!-- 右侧文本框和生成按钮 -->
      <div class="col-md-9">
        <div class="mb-3">
          <h4>输入文本</h4>
          <textarea v-model="gen_text" class="form-control" rows="10" placeholder="请输入教学内容..."></textarea>
        </div>
        <div class="d-flex justify-content-end">
          <button @click="generateAudio" class="btn btn-primary" :disabled="isLoading">
            {{ isLoading ? '生成中...' : '生成语音' }}
          </button>
        </div>

        <!-- 加载进度条 -->
        <div v-if="isLoading || audioUrl" class="mt-3">
          <h4 v-if="isLoading">音频生成中... {{ Math.floor(progress) }}%</h4>
          <h4 v-else>生成的音频</h4>
          <div class="progress mb-3">
            <divclass="progress-bar progress-bar-striped"
                 :class="{'progress-bar-animated':isLoading}"
                 role="progressbar"
                 :style="{ width:progress+'%'}"
                 :aria-valuenow="progress"
                 aria-valuemin="0"
                 aria-valuemax="100">
              {{ Math.floor(progress) }}%
            </div>
          </div>
        </div>

        <!-- 显示生成的音频 -->
        <div v-if="audioUrl && !isLoading" class="mt-3">
          <AudioPlayer :src="audioUrl"></AudioPlayer>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
.form-switch .form-check-input {
  cursor: pointer;
  transition: all 0.3s ease;
}

.form-switch .form-check-input:checked {
  background-color: #0d6efd;
  border-color: #0d6efd;
}

.btn-primary:hover {
  background-color: #0b5ed7;
}
</style>
posted on 2025-04-19 02:17  leapss  阅读(27)  评论(0)    收藏  举报