康鲁杰
2025-04-22 59f1f7a0bdc4c95b090c4602eb75f00e0c8046e6
Merge remote-tracking branch 'origin/master'
已修改3个文件
139 ■■■■■ 文件已修改
easegen-front/src/utils/HaveFace.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easegen-front/src/views/chooseTemplate/index.vue 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easegen-front/src/views/myCourse/index.vue 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easegen-front/src/utils/HaveFace.ts
@@ -1,5 +1,7 @@
// 引入face.js
import * as faceapi from 'face-api.js';
import { reject } from 'lodash-es';
import { resolve } from 'path';
// 创建初始化标记,防止重复初始化
let isModelsLoaded = false;
// 类型定义
easegen-front/src/views/chooseTemplate/index.vue
@@ -630,7 +630,7 @@
<script lang="ts" setup>
import { ref, reactive, onMounted } from 'vue'
import draggable from 'vuedraggable'
import { ElMessage, ElMessageBox } from 'element-plus'
import Vue3DraggableResizable from 'vue3-draggable-resizable'
import 'vue3-draggable-resizable/dist/Vue3DraggableResizable.css'
import { config } from '@/config/axios/config'
@@ -956,6 +956,7 @@
const showLeftList = ref(true)
const selectPPT = ref({
  id:"",
  pictureUrl: '',
  innerPicture: {
    //定义画中画对象,属性与数字人相同
@@ -1187,7 +1188,6 @@
        console.log('PPTArr.value', PPTArr.value)
        PPTArr.value[0].isActive = true
        selectPPT.value = PPTArr.value[0]
        console.log('selectPPT.value', selectPPT.value)
        showLeftList.value = true
        clearInterval(schedulePPTTimer.value)
        //轮询保存课程
@@ -1244,13 +1244,48 @@
  clearInterval(schedulePPTTimer.value)
}
const copyDocument = (item, index) => {
  let copyItem = cloneDeep(item)
  copyItem.id = generateUUID()
  copyItem.isActive = false
  PPTArr.value.splice(index + 1, 0, copyItem)
  ElMessageBox.confirm(
    '是否复制这页PPT?',
    '提示',
    {
      confirmButtonText: '是',
      cancelButtonText: '否',
      type: 'warning',
    }
  )
    .then(() => {
      let copyItem = cloneDeep(item)
      copyItem.id = generateUUID()
      copyItem.isActive = false
      PPTArr.value.splice(index + 1, 0, copyItem)
    })
    .catch(() => {
      ElMessage({
        type: 'info',
        message: '已取消复制',
      })
    })
}
const deleteDocument = (item) => {
  PPTArr.value = PPTArr.value.filter((child) => child.id !== item.id)
  ElMessageBox.confirm(
    '是否删除这页PPT?',
    '提示',
    {
      confirmButtonText: '是',
      cancelButtonText: '否',
      type: 'warning',
    }
  )
      .then(() => {
      PPTArr.value = PPTArr.value.filter((child) => child.id !== item.id)
      }).catch(() => {
      ElMessage({
        type: 'info',
        message: '已取消删除',
      })
  })
}
const deleteDigitalHuman = () => {
  selectPPT.value.showDigitalHuman = false
@@ -1380,12 +1415,25 @@
    accountId: userId.value
  }
  pptTemplateApi.coursesCreate(params).then((res) => {
    console.log(res)
    if (res) {
      courseInfo.value.id = res
    }
  })
}
//ppt人脸校验
const PPtIsHaveFace = async ()=>{
  //添加ppt中人脸校验
  //向原始ppt添加数据,用作后续ppt中是否包含人脸的数据校验原始数据
  const InitPpt = PPTArr.value.map( (item)=>{
      return item.innerPicture.src
  } )
  const { detectFacesInImages } = useFaceDetection()
  const IsHaveFace = await detectFacesInImages(InitPpt)
  return IsHaveFace
}
//获取保存时间
const saveTime = ref()
@@ -1433,7 +1481,6 @@
//传入 save 则代表保存,空字符传则是合成视频
const saveSubmit = async (type) => {
  if( type.length === 0 ){
    //此时为视频合成
    MakeLoading.value = true
@@ -1446,21 +1493,6 @@
  // 检查场景是否为空
  if (!PPTArr.value || PPTArr.value.length === 0) {
    message.warning('场景为空,请先上传PPT!')
    //关闭视频合成与保存按钮的loading动画
    MakeLoading.value = false
    SaveLoading.value = false
    return false
  }
  //添加ppt中人脸校验
  //向原始ppt添加数据,用作后续ppt中是否包含人脸的数据校验原始数据
  const InitPpt = PPTArr.value.map( (item)=>{
      return item.innerPicture.src
  } )
  const { detectFacesInImages } = useFaceDetection()
  const IsHaveFace = await detectFacesInImages(InitPpt)
  if( IsHaveFace ){
    message.warning('当前ppt中包含人脸元素, 为方便后续视频生成 ,请去除该元素')
    //关闭视频合成与保存按钮的loading动画
    MakeLoading.value = false
    SaveLoading.value = false
@@ -1520,7 +1552,6 @@
    matting: 1,
    marker: 1
  }
  let pageNum = 1
  if (PPTArr.value && PPTArr.value.length > 0) {
    console.log('开始处理PPTArr数据')
@@ -1536,7 +1567,6 @@
        const innerPictureCom = item.innerPicture
        console.log('innerPictureCom:', JSON.stringify(innerPictureCom))
        console.log(item.pptRemark)
        item.pptRemark = removeHtmlTags(item.pptRemark)
        // item.pptRemark = editorRef.value.getText()
        // item.pptRemark=item.pptRemark.replace(/<[^>]+>/g, '')
@@ -1613,8 +1643,6 @@
      }
    })
  }
  console.log('pageInfo:', JSON.stringify(pageInfo))
  console.log('thumbnail:', thumbnail)
  try {
    saveSubmitForm.pageInfo = JSON.stringify(pageInfo)
@@ -1627,8 +1655,18 @@
    SaveLoading.value = false
    console.error('保存表单数据时出错:', error)
  }
  if (type == 'save') {
    //反正怎么走都会走save这一步,那就只在这一步进行一次人脸校验,如果后续合成视频按钮不再走保存,请将这一步也一并进行更改
    //主要因为wangEditor过于敏感
    const isHaveFace = await PPtIsHaveFace()
    if( isHaveFace ){
      message.warning('当前ppt中包含人脸元素, 为方便后续视频生成 ,请去除该元素')
      //关闭视频合成与保存按钮的loading动画
      MakeLoading.value = false
      SaveLoading.value = false
      return false
    }
    try {
      const res = await pptTemplateApi.coursesSave(stringifySafely(saveSubmitForm))
      if (res) {
@@ -1647,6 +1685,7 @@
      SaveLoading.value = false
      return false
    }
  } else {
    // 合成视频前先保存
    try {
@@ -1658,12 +1697,10 @@
        SaveLoading.value = false
        return
      }
      // 校验场景数据
      let warningStrArr: any = []
      for (let i = 0; i < PPTArr.value.length; i++) {
        const item = PPTArr.value[i]
        console.log(item)
        // 校验背景宽高
        if (!item.width || !item.height) {
          message.warning('背景尺寸无效,请检查宽高设置,或者重新选择模板')
@@ -1690,7 +1727,6 @@
          }
        }
      }
      if (warningStrArr.length > 0) {
        warningDialog.value.open(warningStrArr.map((warning) => `<div>${warning}</div>`).join(''))
        //关闭视频合成与保存按钮的loading动画
@@ -1698,7 +1734,6 @@
        SaveLoading.value = false
        return
      }
      // 合成视频
      try {
        const res = await pptTemplateApi.megerMedia(saveSubmitForm)
@@ -1723,7 +1758,9 @@
      message.error('操作失败,请重试')
    }
  }
}
function stringifySafely(obj) {
  const seen = new WeakSet()
  return JSON.stringify(obj, (key, value) => {
@@ -1769,6 +1806,7 @@
    }
  }
}
//富文本编辑器  -start
// 编辑器实例,必须用 shallowRef
const editorRef = shallowRef()
easegen-front/src/views/myCourse/index.vue
@@ -293,7 +293,7 @@
            <el-col :span="12">
              <el-form-item label="片头视频">
                <div class="video-select-container">
                  <div class="video-grid">
                  <div class="video-grid" v-if="titlesList.length>0">
                    <div
                      v-for="item in titlesList"
                      :key="item.id"
@@ -314,13 +314,17 @@
                      </div>
                    </div>
                  </div>
                  <div v-else>
                    <el-icon color="#ff0000" :size="20" style="vertical-align: middle"><Warning /></el-icon>
                    暂无片头视频,请在【片头片尾】上传!
                  </div>
                </div>
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="片尾视频">
                <div class="video-select-container">
                  <div class="video-grid">
                  <div class="video-grid" v-if="trailerList.length>0">
                    <div
                      v-for="item in trailerList"
                      :key="item.id"
@@ -340,6 +344,10 @@
                        <el-icon v-if="formData1.value.trailer === item.url" class="selected-icon"><Check /></el-icon>
                      </div>
                    </div>
                  </div>
                  <div v-else>
                    <el-icon color="#ff0000" :size="20" style="vertical-align: middle"><Warning /></el-icon>
                    暂无片尾视频,请在【片头片尾】上传!
                  </div>
                </div>
              </el-form-item>
@@ -899,17 +907,20 @@
        'tenant-id': getTenantId()
      }
    })
    // 5. 调用保存字幕接口
    const params = {
      id: subtitleForm.videoId,
      subtitlesUrl: uploadResponse.data.data,
    if(uploadResponse.data.data){
      const params = {
        id: subtitleForm.videoId,
        subtitlesUrl: uploadResponse.data.data,
      }
      // 5. 调用保存字幕接口
      const res = await pptTemplateApi.saveSubtitles(params)
      if (res) {
        message.success('字幕保存成功')
        subtitleForm.originalContent = subtitleForm.content
        isSubtitleModified.value = false
      }
    }
    await pptTemplateApi.saveSubtitles(params)
    message.success('字幕保存成功')
    subtitleForm.originalContent = subtitleForm.content
    isSubtitleModified.value = false
  } catch (error) {
    console.error('保存字幕失败:', error)
    message.error(`保存字幕失败: ${error.message || '未知错误'}`)