gen_digit_human_video.vue 10.3 KB
<script setup lang="ts">
import text2videoService from "@/api/service/text2videoService";
import utils from "@/utils/utils";
import {
  ElMessage, genFileId,
  type UploadInstance,
  type UploadProps,
  type UploadRawFile
} from "element-plus";
import { nextTick, onMounted, reactive, ref } from "vue";

const debug = ref(import.meta.env.MODE === 'production' ? false : true);
// const debug = ref(false);
const loading = ref(false);
const title = ref("生成数字人视频");
const form = reactive({
  task_id: "",
  lang: "<|zh|>",
  text: "国庆假期期间A股休市,而港股继续狂飙,成交量创历史新高,吸引了全球投资者目光。A股节日休市期间,恒生指数累计上涨9.3%,恒生科技指数涨幅超13%,“牛市旗手”券商股的普遍涨幅更是达到50%~100%甚至更高。与此同时,外资也继续看多中国资产。贝莱德、高盛等国际金融机构纷纷上调中国股市评级至“超配”。火上热搜!节后A股开盘即涨停?持续狂飙,还没上车的怎么办?国新办举行发布会介绍系统落实一揽子增量政策等情况,又将传递哪些信号?10月8日8:00开始,第一财经《直击节后首日交易》特别节目,与您一起见证历史,探讨投资策略,敬请关注!",
  sample_audio_path: "",
  sample_video_path: "",
  show_image_or_video_path: "",
  bgm: "",
  final_video: "",
});

onMounted(() => {
  // 初始化task_id
  form.task_id = utils.genDateTimeStr();
  console.log('页面加载,task_id=', form.task_id)
  document.title = title.value;
  if (!debug) {
    form.text = "";
    form.sample_audio_path = "";
    form.sample_video_path = "";
    form.show_image_or_video_path = "";
    form.bgm = "";
  }
});

// =========== 上传通用 Begin ===========
const actionUrl = ref(
  import.meta.env.MODE === 'production'
    ? '/file'
    : import.meta.env.VITE_APP_BASE_API + '/file'
)
const handleUploadError = (error: Error) => {
  ElMessage({
    message: String(error.message),
    type: "error",
  });
}
const handleBeforeUpload = async (file: any) => {
  const isLt1M = file.size / 1024 / 1024 <= 10;
  if (!isLt1M) {
    ElMessage.error('文件大小不能超过 10MB')
    return false
  }
}
// =========== 上传通用 END ===========

// =========== 上传音频 Begin ===========
const upload_sample_audio = ref<UploadInstance>();
const UploadSampleAudioSuccess = (val: Wm.UploadResult) => {
  if (val.code == 0) {
    form.sample_audio_path = val.data[0].path;
    ElMessage({
      message: '上传成功',
      type: 'success'
    })
  } else {
    ElMessage({
      message: '上传失败:'+val.message,
      type: 'error'
    })
  }
}
const handleUploadSampleAudioExceed: UploadProps['onExceed'] = (files) => {
  // 清除已上传的文件
  upload_sample_audio.value!.clearFiles()
  // 获取超出限制的第一个文件
  const file = files[0] as UploadRawFile
  // 给文件分配一个新的唯一标识
  file.uid = genFileId()
  // 手动触发文件上传
  upload_sample_audio.value!.handleStart(file)
  // 提交上传
  upload_sample_audio.value!.submit()
}
const handleUploadSampleAudioRemove: UploadProps['onRemove'] = (file, uploadFiles) => {
  // 清除已上传的文件
  upload_sample_audio.value!.clearFiles()
  form.sample_audio_path = '';
}
// =========== 上传音频 END ===========

// =========== 上传采样视频 Begin ===========
const upload_sample_video = ref<UploadInstance>();
const UploadSampleVideoSuccess = (val: Wm.UploadResult) => {
  if (val.code == 0) {
    form.sample_video_path = val.data[0].path;
    ElMessage({
      message: '上传成功',
      type: 'success'
    })
  } else {
    ElMessage({
      message: '上传失败:'+val.message,
      type: 'error'
    })
  }
}
const handleUploadSampleVideoExceed: UploadProps['onExceed'] = (files) => {
  // 清除已上传的文件
  upload_sample_video.value!.clearFiles()
  // 获取超出限制的第一个文件
  const file = files[0] as UploadRawFile
  // 给文件分配一个新的唯一标识
  file.uid = genFileId()
  // 手动触发文件上传
  upload_sample_video.value!.handleStart(file)
  // 提交上传
  upload_sample_video.value!.submit()
}
const handleUploadSampleVideoRemove: UploadProps['onRemove'] = (file, uploadFiles) => {
  // 清除已上传的文件
  upload_sample_video.value!.clearFiles()
  form.sample_video_path = '';
}
// =========== 上传采样视频 END ===========

// =========== 上传拼接视频或图片 Begin ===========
const upload_show_image_or_video = ref<UploadInstance>();
const UploadShowImageOrVideoSuccess = (val: Wm.UploadResult) => {
  if (val.code == 0) {
    form.show_image_or_video_path = val.data[0].path;
    ElMessage({
      message: '上传成功',
      type: 'success'
    })
  } else {
    ElMessage({
      message: '上传失败:'+val.message,
      type: 'error'
    })
  }
}
const handleUploadShowImageOrVideoExceed: UploadProps['onExceed'] = (files) => {
  // 清除已上传的文件
  upload_show_image_or_video.value!.clearFiles()
  // 获取超出限制的第一个文件
  const file = files[0] as UploadRawFile
  // 给文件分配一个新的唯一标识
  file.uid = genFileId()
  // 手动触发文件上传
  upload_show_image_or_video.value!.handleStart(file)
  // 提交上传
  upload_show_image_or_video.value!.submit()
}
const handleUploadShowImageOrVideoRemove: UploadProps['onRemove'] = (file, uploadFiles) => {
  // 清除已上传的文件
  upload_show_image_or_video.value!.clearFiles()
  form.show_image_or_video_path = '';
}
// =========== 上传拼接视频或图片 END ===========

// 生成视频
const onGenVideo = async () => {
  if (!form.text || form.text.length == 0
    || !form.sample_audio_path || form.sample_audio_path.length == 0
    || !form.sample_video_path || form.sample_video_path.length == 0
  ) {
    ElMessage({
      message: "文案、采样声音、出镜人物 均不能为空",
      type: "error",
    });
    return;
  }
  try {
    const video_param = {
      task_id: form.task_id,
      lang: form.lang,
      text: form.text,
      sample_audio_path: form.sample_audio_path,
      sample_video_path: form.sample_video_path,
      show_image_or_video_path: form.show_image_or_video_path,
      bgm: "",
    }
    const result = await text2videoService.submitGenDigitHumanVideo(video_param);
    console.log(result);
    form.final_video = "";
    form.final_video = result + "?v=" + utils.genDateTimeStr();
  } catch(error: any) {
    // console.error(error);
    ElMessage({
      message: error,
      type: "error",
    });
  };
};
</script>

<!-- ============================================================================================================ -->
<!-- ============================================================================================================ -->
<!-- ============================================================================================================ -->

<template>
  <main class="home-container">
    <!-- 标题 -->
    <el-divider content-position="left">{{ title }}</el-divider>
    <el-form :model="form" label-width="114px" v-loading="loading">
      <!-- 文案 -->
      <el-form-item label="文案">
        <el-input
          v-model="form.text"
          :autosize="{ minRows: 2, maxRows: 4 }"
          type="textarea"
          placeholder="Please input"
        />
      </el-form-item>
      <!-- 采样声音 -->
      <el-form-item label="采样声音">
        <el-upload
          ref="upload_sample_audio"
          :show-file-list="true"
          :limit="1"
          accept=".wav,.WAV"
          :action="actionUrl"
          :on-success="UploadSampleAudioSuccess"
          :on-exceed="handleUploadSampleAudioExceed"
          :on-error="handleUploadError"
          :before-upload="handleBeforeUpload"
          :on-remove="handleUploadSampleAudioRemove"
        >
          <el-button type="primary" size="small">上传</el-button>
          <template #tip>
            <div class="el-upload__tip" style="color: #ff0000">
              wav 格式, 时长不大于 30秒, 文件小于 10M。
            </div>
          </template>
        </el-upload>
      </el-form-item>
      <!-- 出镜人物 -->
      <el-form-item label="出镜人物">
        <el-upload
          ref="upload_sample_video"
          :show-file-list="true"
          :limit="1"
          accept=".mp4,.MP4"
          :action="actionUrl"
          :on-success="UploadSampleVideoSuccess"
          :on-exceed="handleUploadSampleVideoExceed"
          :on-error="handleUploadError"
          :before-upload="handleBeforeUpload"
          :on-remove="handleUploadSampleVideoRemove"
        >
          <el-button type="primary" size="small">上传</el-button>
          <template #tip>
            <div class="el-upload__tip" style="color: #ff0000">
              mp4 格式, 时长 5秒左右即可, 文件小于 10M。
            </div>
          </template>
        </el-upload>
      </el-form-item>
      <!-- 拼接视频或图片 -->
      <el-form-item label="拼接视频或图片">
        <el-upload
          ref="upload_show_image_or_video"
          :show-file-list="true"
          :limit="1"
          accept=".mp4,.MP4,.png,.PNG,.jpg,.JPG,.jpeg,.JPEG"
          :action="actionUrl"
          :on-success="UploadShowImageOrVideoSuccess"
          :on-exceed="handleUploadShowImageOrVideoExceed"
          :on-error="handleUploadError"
          :before-upload="handleBeforeUpload"
          :on-remove="handleUploadShowImageOrVideoRemove"
        >
          <el-button type="primary" size="small">上传</el-button>
          <template #tip>
            <div class="el-upload__tip" style="color: #ff0000">
              可以上传视频(mp4)或图片(jpg, png),
              作为最终视频的上半部分,也可以不上传,不传则只生成数字人视频。
            </div>
          </template>
        </el-upload>
      </el-form-item>

      <!-- 结果 -->
      <el-form-item>
        <el-button type="primary" @click="onGenVideo">生成视频</el-button>
      </el-form-item>
      <el-form-item>
        <video :src="form.final_video" controls></video>
      </el-form-item>
    </el-form>
  </main>
</template>

<style lang="scss" scoped>
.home-container {
  width: 100%;
}
</style>

<style lang="scss">
.home-container {
  .el-table .el-table__cell {
    z-index: calc(var(--el-table-index) -1);
  }
}
.dashed-div {
  border: 1px dashed #999;
  margin: 5px 0;
  padding: 2px;
}
</style>