index.vue 102 KB
Newer Older
Administrator's avatar
Administrator committed
1
<script setup lang="ts">
2 3
import text2videoService from '@/api/service/text2videoService'
import utils from '@/utils/utils'
周成波's avatar
周成波 committed
4
import {
5 6
  ElMessage,
  genFileId,
7 8
  type UploadInstance,
  type UploadProps,
9
  type UploadRawFile
10 11 12
} from 'element-plus'
import { nextTick, onMounted, reactive, ref } from 'vue'
import { useManyValues } from './compositions/useManyValues'
Administrator's avatar
Administrator committed
13

14
const debug = ref(import.meta.env.MODE === 'production' ? false : true)
周成波's avatar
周成波 committed
15
// const debug = ref(false);
16 17 18 19
const loading = ref(false)
const dialogVisible = ref(false)
const dialogData = ref('')
const default_data = useManyValues()
Administrator's avatar
Administrator committed
20
const form = reactive({
周成波's avatar
周成波 committed
21
  screen: default_data.screen,
周成波's avatar
周成波 committed
22
  img_size: <Wm.ImgSize>{},
周成波's avatar
周成波 committed
23
  if_need_subtitle: default_data.if_need_subtitle,
24 25
  chatgpt_prompt: '',
  chatgpt_answer: '',
26
  chatgpt_answer_roles: <Wm.RolesItem[]>[],
27
  all_roles: '',
周成波's avatar
周成波 committed
28
  adapt_result_json: <Wm.ScriptsItem[]>[],
29 30 31 32 33 34 35 36 37 38 39 40
  task_id: '',
  final_video: ''
})
const sd_model = default_data.sd_paras.juggernautXL_v9Rdphoto2Lightning
const sd_prompt_prefix = sd_model.sd_prompt_prefix
const sd_negative_prompt_prefix = default_data.sd_negative_prompt_prefix

const wen_an_llm = default_data.llms.tyqw_online
const role_llm = default_data.llms.tyqw_online
const role_keywords_llm = default_data.llms.tyqw_online
const tuili_llm = default_data.llms.tyqw_online
const tuili_keyword_llm = default_data.llms.tyqw_online
周成波's avatar
周成波 committed
41
// const fanyi_llm = default_data.llms.tyqw_online;
周成波's avatar
周成波 committed
42

周成波's avatar
周成波 committed
43
const voice_rate = ref(0)
周成波's avatar
周成波 committed
44
const voice_volume = ref(0)
45 46
const voice = ref('zh-CN-YunjianNeural')
const bgm = ref('解忧曲')
47
const bgm_volume = ref(0.3)
48 49 50
const pwdCheckDialogVisible = ref(false)
const pwdCheckValue = ref('')
const sub_font_color = ref('#FFFF00')
周成波's avatar
周成波 committed
51
const sub_bg_color = ref()
周成波's avatar
周成波 committed
52
const sub_font_size = ref(35)
周成波's avatar
周成波 committed
53
const sub_position = ref(0.3)
周成波's avatar
周成波 committed
54

55
const marketingTemplateVisible = ref(false)
周成波's avatar
周成波 committed
56
const marketing_template = reactive({
57 58 59 60 61 62 63
  product_name: '',
  product_description: '',
  target_people: '',
  text_role: '',
  text_style: '',
  story_type: '',
  reference: '',
周成波's avatar
周成波 committed
64
  words_num: 0,
65 66 67 68 69
  prompt1: '',
  prompt2: '',
  result1: '',
  result2: ''
})
周成波's avatar
周成波 committed
70 71

const cover_backcover = reactive({
72 73 74 75 76
  if_need_cover_pic: 'false',
  cover_pic: 'src/assets/waiting.png',
  cover_pic_local: '',
  cover_pic_with_text: 'src/assets/waiting.png',
  cover_pic_with_text_local: '',
周成波's avatar
周成波 committed
77
  cover_pic_titles: <Wm.PicText[]>[],
78
  cover_pic_use_scene: '',
周成波's avatar
周成波 committed
79

80 81 82 83 84
  if_need_product_pic: 'false',
  product_pic: 'src/assets/waiting.png',
  product_pic_local: '',
  product_pic_with_text: 'src/assets/waiting.png',
  product_pic_with_text_local: '',
周成波's avatar
周成波 committed
85
  product_pic_titles: <Wm.PicText[]>[],
86 87
  product_pic_speech: ''
})
88

89 90 91 92 93 94
const inPaintVisible = ref(false)
const inPaintBaseImgData = ref('')
const inPaintMaskData = ref('')
const inPaintType = ref('')
const inPaintItem = ref()
const inPaintPrompt = ref('')
Administrator's avatar
Administrator committed
95

96
const update_and_modify_product = reactive({
97 98 99 100 101 102 103
  if_need: 'false',
  pic: 'src/assets/waiting.png',
  pic_local: '',
  pic_preview: 'src/assets/waiting.png',
  pic_preview_local: '',
  pic_mask: 'src/assets/waiting.png',
  pic_mask_local: '',
104
  inPaintVisible: false,
105 106 107
  inPaintBaseImgData: '',
  inPaintMaskData: '',
  inPaintPrompt: '',
108 109
  cutout_obj: <Wm.Coordinate[]>[],
  cutout_no_obj: <Wm.Coordinate[]>[],
110 111
  cutoutPart: '1'
})
112
const radio1 = ref('1')
周成波's avatar
周成波 committed
113

周成波's avatar
周成波 committed
114
onMounted(() => {
周成波's avatar
周成波 committed
115
  // 初始化task_id
116
  form.task_id = utils.genDateTimeStr()
周成波's avatar
周成波 committed
117
  console.log('页面加载,task_id=', form.task_id)
118
  // 初始化示例数据
119
  onChangeScreen(form.screen)
120 121
  // 初始化密码框
  if (debug.value == true) {
122
    pwdCheckDialogVisible.value = false
123
  } else {
124
    pwdCheckDialogVisible.value = true
125
  }
126
})
周成波's avatar
周成波 committed
127

128
const delay = (ms: any) => new Promise((res) => setTimeout(res, ms))
周成波's avatar
周成波 committed
129

周成波's avatar
周成波 committed
130 131
const onSubmitGpt = () => {
  text2videoService
132 133 134 135 136 137 138
    .submitLLM(
      utils.aesEncrypt(form.chatgpt_prompt),
      utils.aesEncrypt(wen_an_llm.api),
      [],
      form.task_id,
      'true'
    )
周成波's avatar
周成波 committed
139
    .then((result: string) => {
周成波's avatar
周成波 committed
140 141
      // console.log(form.chatgpt_prompt);
      // console.log(result);
142
      form.chatgpt_answer = result
周成波's avatar
周成波 committed
143 144 145
    })
    .catch((error: any) => {
      // console.error(error);
Administrator's avatar
Administrator committed
146
      ElMessage({
周成波's avatar
周成波 committed
147
        message: error,
148 149 150 151
        type: 'error'
      })
    })
}
周成波's avatar
周成波 committed
152

153 154 155
const onAdaptRoles = async () => {
  if (!form.chatgpt_answer || form.chatgpt_answer.length == 0) {
    ElMessage({
156 157 158 159
      message: '文案不能为空',
      type: 'error'
    })
    return
160
  }
周成波's avatar
周成波 committed
161 162
  if (!form.task_id) {
    // 初始化task_id
163
    form.task_id = utils.genDateTimeStr()
周成波's avatar
周成波 committed
164 165
    console.log('推理角色,生成task_id=', form.task_id)
  }
166
  // 推理角色
周成波's avatar
周成波 committed
167
  try {
168 169 170 171 172 173 174 175 176 177 178 179 180
    form.chatgpt_answer_roles = []
    const adapt_restrict = `请理解这个故事:“${form.chatgpt_answer}”,给出这个故事中的所有角色,多个角色以逗号分隔。\n要求:只返回角色名称即可,不要添加其他的内容。`
    let roles = await text2videoService.submitLLM(
      utils.aesEncrypt(adapt_restrict),
      utils.aesEncrypt(role_llm.api),
      [],
      form.task_id,
      'true'
    )
    form.all_roles = roles.replace(/。|(|)/g, '').replace(/、/g, ',')
    console.log(form.all_roles)
    const roles_arr = form.all_roles.split(/[,,]/)
    console.log(roles_arr)
周成波's avatar
周成波 committed
181
    // 推理属性
182
    const attribute_options = default_data.role_attribute_options.map((option) => option.value)
周成波's avatar
周成波 committed
183
    console.log('dddddddd', attribute_options)
周成波's avatar
周成波 committed
184 185 186
    for (const one_role of roles_arr) {
      // const adapt_attribute_restrict = `根据这个故事:“${form.chatgpt_answer}”,你认为这个角色:“${one_role}”是“${String(attribute_options)}”中的哪一种?请返回选择的结果。\n要求:只返回选择的结果即可,不要添加其他的内容。`;
      // const adapt_attribute_restrict = `你认为这个角色:“${one_role}”是“${String(attribute_options)}”中的哪一种?请返回选择的结果。\n要求:只返回选择的结果即可,不要添加其他的内容。`;
187 188 189 190 191 192 193 194 195 196 197 198
      const adapt_attribute_restrict = `故事全文:“${
        form.chatgpt_answer
      }”,请理解故事全文,然后判断:“${one_role}”是“${String(
        attribute_options
      )}”中的哪一种?请返回选择的结果。\n要求:只返回选择的结果即可,不要添加其他的内容。`
      let attribute = await text2videoService.submitLLM(
        utils.aesEncrypt(adapt_attribute_restrict),
        utils.aesEncrypt(role_llm.api),
        [],
        form.task_id,
        'true'
      )
周成波's avatar
周成波 committed
199
      console.log('dddddddd', attribute)
周成波's avatar
周成波 committed
200 201
      if (attribute_options.includes(attribute)) {
        form.chatgpt_answer_roles.push({
202 203 204 205 206
          角色: one_role.trim(),
          角色关键词: '',
          角色关键词英文: '',
          属性: attribute
        })
周成波's avatar
周成波 committed
207
      }
周成波's avatar
周成波 committed
208 209 210 211 212
    }
    console.log(form.chatgpt_answer_roles)
  } catch (error) {
    ElMessage({
      message: String(error),
213 214
      type: 'error'
    })
周成波's avatar
周成波 committed
215
  }
216
}
周成波's avatar
周成波 committed
217 218 219 220

const onAdaptRolesKeywords = async () => {
  if (!form.chatgpt_answer_roles || form.chatgpt_answer_roles.length == 0) {
    ElMessage({
221 222 223 224
      message: '总角色不能为空',
      type: 'error'
    })
    return
周成波's avatar
周成波 committed
225 226 227 228 229
  }
  for (const one_role of form.chatgpt_answer_roles) {
    if (!one_role.属性) {
      ElMessage({
        message: `请选择 ${one_role.角色} 的属性`,
230 231 232
        type: 'error'
      })
      return
周成波's avatar
周成波 committed
233 234
    }
  }
235
  loading.value = true
周成波's avatar
周成波 committed
236 237
  // 推理角色关键词
  try {
周成波's avatar
周成波 committed
238
    async function processRoles() {
周成波's avatar
周成波 committed
239
      for (const one_role of form.chatgpt_answer_roles) {
240 241 242 243
        await delay(100)
        let adapt_keyword_restrict = `请理解这个故事:“${form.chatgpt_answer}”,给出其中这个角色“${one_role.角色}”的关键词,以逗号分隔。包括但不限于:`
        let temp_restrict = ''
        if (one_role.属性.includes('人')) {
周成波's avatar
周成波 committed
244 245
          temp_restrict = `性别(可以发挥想象进行补充,但一定要有), 年龄(可以发挥想象进行补充,但一定要有),
           肤色(可以发挥想象进行补充,但一定要有), 衣服(可以发挥想象进行补充,但一定要有), 发型(可以发挥想象进行补充,但一定要有),
246
           发色(可以发挥想象进行补充,但一定要有), 脸色(可以发挥想象进行补充,但一定要有), 五官特点(可以发挥想象进行补充,但一定要有)`
周成波's avatar
周成波 committed
247
        } else {
248 249 250 251
          let temp_restrict_pre = ''
          if (one_role.属性.includes('动物')) {
            temp_restrict_pre = `哪一种动物(可以发挥想象进行补充,但一定要有),`
          }
252
          temp_restrict = `${temp_restrict_pre} 体型(可以发挥想象进行补充,但一定要有), 颜色(可以发挥想象进行补充,但一定要有),
周成波's avatar
周成波 committed
253
           四肢(可以发挥想象进行补充,但一定要有), 五官特点(可以发挥想象进行补充,但一定要有),
254
           身体(皮毛,羽毛,鳞片,肤色等,可以发挥想象进行补充,没有就不提供)`
周成波's avatar
周成波 committed
255
        }
256 257 258 259 260 261 262 263 264 265 266 267
        adapt_keyword_restrict = adapt_keyword_restrict + temp_restrict + '。回答限制在30个字左右。'
        let keywords = await text2videoService.submitLLM(
          utils.aesEncrypt(adapt_keyword_restrict),
          utils.aesEncrypt(role_keywords_llm.api),
          [],
          form.task_id,
          'true'
        )
        keywords = keywords.replace(/。/g, '').replace(/、/g, ',')
        one_role.角色关键词 = keywords

        await delay(100)
268 269
        // const adapt_attribute_restrict_en = `你现在扮演专业的英语翻译的角色。请将这段文字“${keywords}”翻译为英语。\n要求:只返回英语即可,不要返回其他内容。`;
        // let keywords_en = await text2videoService.submitLLM(adapt_attribute_restrict_en, role_keywords_llm.api);
270 271 272 273 274
        let keywords_en = await text2videoService.submitTranslateToEn(
          utils.aesEncrypt(keywords),
          form.task_id,
          'true'
        )
周成波's avatar
周成波 committed
275 276
        // console.log(keywords_en)
        // keywords_en = utils.filterChineseAndPunctuation(keywords_en.replace(/"/g, ''));
277 278
        keywords_en = keywords_en.replace(/"/g, '')
        one_role.角色关键词英文 = keywords_en
279
      }
周成波's avatar
周成波 committed
280 281
    }
    try {
282
      await processRoles()
283
      console.log(form.chatgpt_answer_roles)
周成波's avatar
周成波 committed
284 285 286
    } catch (error) {
      ElMessage({
        message: String(error),
287 288
        type: 'error'
      })
289 290 291 292
    }
  } catch (error) {
    ElMessage({
      message: String(error),
293 294
      type: 'error'
    })
295 296
  } finally {
    // 最终关闭loading(无论成功或失败)
297
    loading.value = false
298
  }
299
}
周成波's avatar
周成波 committed
300

Administrator's avatar
Administrator committed
301
const onAdapt = async (type: string) => {
周成波's avatar
周成波 committed
302
  if (!form.chatgpt_answer || form.chatgpt_answer.length == 0) {
周成波's avatar
周成波 committed
303
    ElMessage({
304 305 306 307
      message: '文案不能为空',
      type: 'error'
    })
    return
周成波's avatar
周成波 committed
308
  }
周成波's avatar
周成波 committed
309
  if (!form.task_id) {
周成波's avatar
周成波 committed
310
    // 初始化task_id
311
    form.task_id = utils.genDateTimeStr()
周成波's avatar
周成波 committed
312
    console.log('分镜,生成task_id=', form.task_id)
周成波's avatar
周成波 committed
313
  }
周成波's avatar
周成波 committed
314
  // 按标点拆分成分镜
315 316 317
  let sentences = utils.splitText(form.chatgpt_answer)
  if (type == 'more_scene' && sentences.length < 5) {
    sentences = utils.splitText(form.chatgpt_answer, type)
318
  }
周成波's avatar
周成波 committed
319
  // console.log(sentences.length)
周成波's avatar
周成波 committed
320
  // 分镜
321 322
  form.adapt_result_json = []
  let texts = []
周成波's avatar
周成波 committed
323 324
  for (let i = 0; i < sentences.length; i++) {
    form.adapt_result_json.push({
325 326 327 328 329 330 331 332 333 334 335 336 337 338
      编号: (i + 1).toString(),
      场景描述: sentences[i].trim(),
      场景关键词: '',
      场景关键词英文: '',
      角色: '',
      角色关键词: '',
      角色关键词英文: '',
      画面描述词: '',
      本镜配图: 'src/assets/waiting.png',
      local_image_path: '',
      info: '',
      roles: [],
      info2: ''
    })
339 340
    texts.push({
      idx: (i + 1).toString(),
341
      text: sentences[i].trim()
342
    })
343
  }
344
  // 匹配产品图到最合适的场景
345
  if (update_and_modify_product.pic_local && update_and_modify_product.pic_local != '') {
346 347 348
    let para = {
      task_id: form.task_id,
      image_path: update_and_modify_product.pic_local,
349 350
      texts: texts
    }
351
    try {
352
      const result = await text2videoService.submitImgTextMatch(para)
353
      // 找到最高的分数
354 355 356 357 358 359
      const highestScoreObject = result.reduce(
        (maxObj, currObj) => {
          return currObj.score > maxObj.score ? currObj : maxObj
        },
        { score: -Infinity }
      )
360 361 362
      // 将最高的分数匹配到场景中
      for (const item of form.adapt_result_json) {
        if (item.编号 == highestScoreObject.idx) {
363 364 365
          item.本镜配图 = update_and_modify_product.pic
          item.local_image_path = update_and_modify_product.pic_local
          item.info2 = '产品图与场景匹配度:' + highestScoreObject.score
366 367
        }
        // 顺便将返回结果的分数都匹配到场景中
368
        const matchInResult = result.find((r) => item.编号 == r.idx)
369
        if (matchInResult) {
370
          item.info2 = '产品图与场景匹配度:' + matchInResult.score
371 372 373 374 375
        }
      }
    } catch (error) {
      ElMessage({
        message: String(error),
376 377
        type: 'error'
      })
378
    }
周成波's avatar
周成波 committed
379
  }
380
  console.log(form.adapt_result_json)
周成波's avatar
周成波 committed
381 382 383 384 385
}

const onAdaptScene = async () => {
  if (!form.adapt_result_json || form.adapt_result_json.length == 0) {
    ElMessage({
386 387 388 389
      message: '分镜不能为空',
      type: 'error'
    })
    return
周成波's avatar
周成波 committed
390
  }
391
  loading.value = true
392 393
  async function processScenes() {
    for (const item of form.adapt_result_json) {
394
      if (item.local_image_path == '') {
395
        await onAdaptOneScene(item)
396
      }
397 398
    }
  }
周成波's avatar
周成波 committed
399
  try {
400
    await processScenes()
周成波's avatar
周成波 committed
401
    ElMessage({
402 403 404 405
      message: 'all scene ok',
      type: 'success'
    })
    console.log(form.adapt_result_json)
周成波's avatar
周成波 committed
406
  } catch (error) {
周成波's avatar
周成波 committed
407
    ElMessage({
周成波's avatar
周成波 committed
408
      message: String(error),
409 410
      type: 'error'
    })
周成波's avatar
周成波 committed
411
  } finally {
412
    loading.value = false // 最终关闭loading(无论成功或失败)
周成波's avatar
周成波 committed
413
  }
414
}
周成波's avatar
周成波 committed
415 416

const onAdaptOneScene = async (item: any) => {
周成波's avatar
周成波 committed
417 418
  if (!item.场景描述) {
    ElMessage({
周成波's avatar
周成波 committed
419
      message: `分镜 ${item.编号} 场景描述不能为空`,
420 421 422
      type: 'error'
    })
    return
周成波's avatar
周成波 committed
423
  }
周成波's avatar
周成波 committed
424
  // 推理场景
周成波's avatar
周成波 committed
425
  // 人物(可以发挥想象进行补充,但一定要有),  暂时去掉
周成波's avatar
周成波 committed
426
  try {
周成波's avatar
周成波 committed
427 428 429 430 431 432 433 434 435 436 437 438 439 440
    // const adapt_restrict = `故事:\n${form.chatgpt_answer}\n
    // 指令:
    // 请理解这个故事,给出这个场景“${item.场景描述}”的关键词(年代(可以发挥想象进行补充,但一定要有),空间(可以发挥想象进行补充,但一定要有),
    // 时间段(可以发挥想象进行补充,但一定要有),地理环境(可以发挥想象进行补充,但一定要有),天气(可以发挥想象进行补充,但一定要有),
    // 物品(可以发挥想象进行补充,但一定要有),镜头角度(可以发挥想象进行补充,但一定要有))。
    // 要求:
    // 关键词以逗号分隔。
    // 只要返回关键词,不需要其他的说明文字。`;

    // const adapt_restrict = `剧本:“${form.chatgpt_answer}” \n 作为资深作家,请阅读剧本,并严格按照以下表单:
    // [{"旁白":"${item.场景描述}",场景描述:""}]
    // 根据旁白,来构造场景描述,语言要简要和清晰。你填写的内容只包括根据剧本所构思的摄像机镜头内的场景描述,而不需要其他的内容。请将你完成的表单返回给我。`;

    const adapt_restrict = `剧本:“${form.chatgpt_answer}
周成波's avatar
周成波 committed
441
    指令:
442 443 444 445 446 447 448 449
    作为资深作家,请阅读这个剧本,给出这个场景:“${item.场景描述}”的描述,50个字左右。`
    const keywords = await text2videoService.submitLLM(
      utils.aesEncrypt(adapt_restrict),
      utils.aesEncrypt(tuili_llm.api),
      [],
      form.task_id,
      'true'
    )
周成波's avatar
周成波 committed
450 451
    // console.log(adapt_restrict)
    // console.log(keywords)
452
    item.场景关键词 = keywords
周成波's avatar
周成波 committed
453 454 455

    // const adapt_restrict_en = `你现在扮演专业的英语翻译的角色。请将这段文字“${item.场景描述}”翻译为英语。\n要求:只返回英语即可,不要返回其他内容。`;
    // const keywords_en = await text2videoService.submitLLM(adapt_restrict_en, tuili_llm.api);
456 457 458 459 460
    let keywords_en = await text2videoService.submitTranslateToEn(
      utils.aesEncrypt(keywords),
      form.task_id,
      'true'
    )
周成波's avatar
周成波 committed
461
    // console.log(keywords_en)
周成波's avatar
周成波 committed
462
    // item.场景关键词英文 = utils.filterChineseAndPunctuation(keywords_en.replace(/"/g, ''));
463
    item.场景关键词英文 = keywords_en.replace(/"/g, '')
周成波's avatar
周成波 committed
464 465 466
  } catch (error) {
    ElMessage({
      message: String(error),
467 468
      type: 'error'
    })
周成波's avatar
周成波 committed
469
  }
470
}
周成波's avatar
周成波 committed
471 472 473 474

const onAdaptSceneRoles = async () => {
  if (!form.adapt_result_json || form.adapt_result_json.length == 0) {
    ElMessage({
475 476 477 478
      message: '分镜不能为空',
      type: 'error'
    })
    return
周成波's avatar
周成波 committed
479
  }
周成波's avatar
周成波 committed
480 481
  if (!form.all_roles) {
    ElMessage({
周成波's avatar
周成波 committed
482
      message: `总角色不能为空`,
483 484 485
      type: 'error'
    })
    return
周成波's avatar
周成波 committed
486
  }
487
  loading.value = true
周成波's avatar
周成波 committed
488 489
  async function processScenes() {
    for (const item of form.adapt_result_json) {
Administrator's avatar
Administrator committed
490
      if (item.local_image_path == '') {
491
        await onAdaptOneSceneRoles(item)
Administrator's avatar
Administrator committed
492
      }
周成波's avatar
周成波 committed
493 494 495
    }
  }
  try {
496 497
    await processScenes()
    console.log(form.adapt_result_json)
周成波's avatar
周成波 committed
498 499 500
  } catch (error) {
    ElMessage({
      message: String(error),
501 502
      type: 'error'
    })
周成波's avatar
周成波 committed
503
  } finally {
504
    loading.value = false // 最终关闭loading(无论成功或失败)
周成波's avatar
周成波 committed
505
  }
506
}
周成波's avatar
周成波 committed
507 508 509 510 511

const onAdaptOneSceneRoles = async (item: any) => {
  if (!item.场景描述) {
    ElMessage({
      message: `分镜 ${item.编号} 场景描述不能为空`,
512 513 514
      type: 'error'
    })
    return
周成波's avatar
周成波 committed
515
  }
周成波's avatar
周成波 committed
516 517
  if (!form.all_roles) {
    ElMessage({
周成波's avatar
周成波 committed
518
      message: `总角色不能为空`,
519 520 521
      type: 'error'
    })
    return
周成波's avatar
周成波 committed
522
  }
周成波's avatar
周成波 committed
523 524
  // 推理角色
  try {
周成波's avatar
周成波 committed
525 526
    if (form.chatgpt_answer_roles.length === 0) {
      // 总角色为空
527 528
      item.角色 = ''
      item.角色关键词 = ''
529
    } else {
周成波's avatar
周成波 committed
530
      // 总角色不为空
周成波's avatar
周成波 committed
531
      // const adapt_role_restrict = `请理解这个故事:“${form.chatgpt_answer}”,针对其中的这个场景:“${item.场景描述}”,从所有角色:“${form.all_roles}”中选择本场景的角色,多个角色以逗号分隔。`;
532 533 534 535 536 537 538 539
      const adapt_role_restrict = `整个故事(“${form.chatgpt_answer}),\n\n本章节(${item.场景描述}),\n\n角色列表(${form.all_roles}),\n\n请返回给本章节出现的角色。注意:不要发挥想象,必须从角色列表中选出本章节出现过的角色,如果多个用逗号隔开。`
      const item_roles_answer = await text2videoService.submitLLM(
        utils.aesEncrypt(adapt_role_restrict),
        utils.aesEncrypt(tuili_keyword_llm.api),
        [],
        form.task_id,
        'true'
      )
周成波's avatar
周成波 committed
540
      console.log(`==============${item.编号}===============`)
周成波's avatar
周成波 committed
541
      console.log('form.all_roles = ', form.all_roles)
周成波's avatar
周成波 committed
542
      item.info = `推理返回:${item_roles_answer}`
543 544
      let item_roles_answer_list = item_roles_answer.trim().split(/[,,、]/)
      item_roles_answer_list = item_roles_answer_list.map((item) => item.trim())
周成波's avatar
周成波 committed
545
      // 过滤推理出来的角色,都要在总角色里
546 547 548 549
      item.roles = ['无角色']
      for (const y of form.chatgpt_answer_roles) {
        item.roles.push(y.角色)
      }
周成波's avatar
周成波 committed
550

551 552
      item.角色 = '无角色'
      let filter_result = ''
周成波's avatar
周成波 committed
553
      console.log('item_roles_answer_list = ', item_roles_answer_list)
周成波's avatar
周成波 committed
554 555 556
      for (const x of item_roles_answer_list) {
        for (const y of form.chatgpt_answer_roles) {
          if (x == y.角色) {
557
            filter_result += x + ','
周成波's avatar
周成波 committed
558
            console.log('filter_result = ', filter_result)
周成波's avatar
周成波 committed
559 560 561 562 563 564
            // 下拉列表添加项目
            // item.roles.push(x);
          }
        }
      }
      if (filter_result.endsWith(',')) {
565 566 567 568
        filter_result = filter_result.slice(0, -1) // 去掉结尾的逗号
      }
      if (filter_result) {
        item.角色 = filter_result
周成波's avatar
周成波 committed
569
      }
周成波's avatar
周成波 committed
570
      console.log('过滤后 item.角色 = ', item.角色)
571

572
      ////// 加一段逻辑,本镜角色有且只能有一个,且尽量不与之前相同。【begin】
573 574
      const temp_arr = item.角色.split(/[,,、]/)
      const temp_arr_length = temp_arr.length
575
      ////// 如果本镜的角色大于1个,则只保留没有出现过的角色,且保证只有一个
周成波's avatar
周成波 committed
576
      if (temp_arr_length > 1) {
577
        ////// 获取本镜之前的所有角色
578 579
        let role_history = ''
        form.adapt_result_json.forEach((scene) => {
周成波's avatar
周成波 committed
580
          if (Number(scene.编号) < Number(item.编号)) {
581
            role_history += scene.角色 + ','
周成波's avatar
周成波 committed
582 583
          }
        })
584
        role_history = role_history.replace(/,+$/, '')
周成波's avatar
周成波 committed
585
        console.log(`role_history = ${role_history}`)
586 587
        for (const temp of temp_arr) {
          if (role_history.includes(temp)) {
588 589
            item.角色 = ''
            continue
590
          } else {
591 592
            item.角色 = temp
            break
593 594
          }
        }
周成波's avatar
周成波 committed
595
        if (!item.角色) {
596 597 598
          const role_history_arr = role_history.split(',')
          const lastOne = role_history_arr[role_history_arr.length - 1]
          const remainingValues = role_history_arr.filter((i) => i !== lastOne)
周成波's avatar
周成波 committed
599
          if (remainingValues.length >= 1) {
600
            item.角色 = remainingValues[remainingValues.length - 1]
601
          } else {
602
            item.角色 = item_roles_answer.trim()
603
          }
周成波's avatar
周成波 committed
604
          console.log(`lalalalala item.角色 = ${item.角色}`)
605 606
        }
      }
周成波's avatar
周成波 committed
607
      console.log(`item.角色 = ${item.角色}`)
608 609 610
      ////// 加一段逻辑,本镜角色有且只能有一个,且尽量不与之前相同。【end】

      // 开始匹配角色关键词
611 612 613
      let role_kws = ''
      let role_kws_en = ''
      const item_roles_arr = item.角色.split(/[,,、]/)
614
      item_roles_arr.forEach((one_item_role: string) => {
615 616
        let temp_role_kws = ''
        let temp_role_kws_en = ''
617 618
        // 人工匹配角色关键词,先找想同的
        for (const i of form.chatgpt_answer_roles) {
619 620 621
          if (i['角色'].trim() == one_item_role.trim()) {
            temp_role_kws = `${i['角色关键词']}`
            temp_role_kws_en = `${i['角色关键词英文']}`
622
            // 找到就ok
623
            break
周成波's avatar
周成波 committed
624
          }
625 626
        }
        // 如果找不到相同的,则模糊匹配
周成波's avatar
周成波 committed
627
        if (!temp_role_kws) {
628
          for (const i of form.chatgpt_answer_roles) {
629 630 631 632 633 634
            if (
              i['角色'].includes(one_item_role.trim()) ||
              one_item_role.includes(i['角色'].trim())
            ) {
              temp_role_kws = `${i['角色关键词']}`
              temp_role_kws_en = `${i['角色关键词英文']}`
635
              // 匹配到一个就ok
636
              break
637 638 639
            }
          }
        }
640 641
        role_kws = `${role_kws}${temp_role_kws}`
        role_kws_en = `${role_kws_en}${temp_role_kws_en}`
周成波's avatar
周成波 committed
642
      })
643 644
      item.角色关键词 = role_kws
      item.角色关键词英文 = role_kws_en
645
    }
周成波's avatar
周成波 committed
646 647 648
  } catch (error) {
    ElMessage({
      message: String(error),
649 650
      type: 'error'
    })
周成波's avatar
周成波 committed
651
  }
652
}
周成波's avatar
周成波 committed
653

周成波's avatar
周成波 committed
654
const onItemRolesChange = (item: any) => {
655 656 657 658
  console.log(item.编号, item.角色)
  if (item.角色 == '无角色') {
    item.角色关键词 = ''
    item.角色关键词英文 = ''
周成波's avatar
周成波 committed
659 660 661
  } else {
    for (const y of form.chatgpt_answer_roles) {
      if (item.角色 == y.角色) {
662 663 664
        item.角色关键词 = y.角色关键词
        item.角色关键词英文 = y.角色关键词英文
        break
周成波's avatar
周成波 committed
665 666 667 668 669
      }
    }
  }
}

周成波's avatar
周成波 committed
670 671 672
const onDraw = async () => {
  if (!form.adapt_result_json || form.adapt_result_json.length == 0) {
    ElMessage({
673 674 675 676
      message: '分镜不能为空',
      type: 'error'
    })
    return
周成波's avatar
周成波 committed
677
  }
678
  let is_all_ok = true
周成波's avatar
周成波 committed
679
  for (const item of form.adapt_result_json) {
680
    if (!item.场景关键词 && !item.角色关键词 && item.local_image_path == '') {
周成波's avatar
周成波 committed
681
      ElMessage({
周成波's avatar
周成波 committed
682
        message: `分镜 ${item.编号} 关键词为空,请重新推理本镜`,
683 684 685 686
        type: 'error'
      })
      is_all_ok = false
      break
周成波's avatar
周成波 committed
687
    }
688
  }
周成波's avatar
周成波 committed
689 690
  if (is_all_ok) {
    for (const item of form.adapt_result_json) {
691 692 693
      if (item.local_image_path == '') {
        // onDrawOne(item);
        // 因3090显存不够,暂时改成串行画图
694
        await onDrawOne(item)
695
      }
周成波's avatar
周成波 committed
696
    }
周成波's avatar
周成波 committed
697
  }
698
}
周成波's avatar
周成波 committed
699

周成波's avatar
周成波 committed
700
const onDrawOne = async (item: any) => {
周成波's avatar
周成波 committed
701
  if (!item.场景关键词 && !item.角色关键词) {
周成波's avatar
周成波 committed
702
    ElMessage({
703 704 705 706
      message: '本镜关键词为空,请重新推理本镜',
      type: 'error'
    })
    return
周成波's avatar
周成波 committed
707
  }
周成波's avatar
周成波 committed
708
  if (!form.task_id) {
周成波's avatar
周成波 committed
709
    ElMessage({
710 711 712 713
      message: 'task_id不能为空,请刷新页面',
      type: 'error'
    })
    return
周成波's avatar
周成波 committed
714
  }
周成波's avatar
周成波 committed
715
  // 翻译+画图
周成波's avatar
周成波 committed
716
  try {
717
    item.本镜配图 = 'src/assets/loading.gif'
周成波's avatar
周成波 committed
718 719 720 721 722 723 724 725 726 727 728
    // let temp_prompt = ""
    // if (item.场景描述) {temp_prompt = temp_prompt + `场景描述为:${item.场景描述}\n`};
    // if (item.场景关键词) {temp_prompt = temp_prompt + `场景关键词为:${item.场景关键词}\n`};
    // if (item.角色) {temp_prompt = temp_prompt + `场景中的角色有:${item.角色}\n`};
    // if (item.角色关键词) {temp_prompt = temp_prompt + `角色关键词为:${item.角色关键词}\n`};
    // const sd_describe = await text2videoService.submitLLM(
    //   `${temp_prompt}
    //   指令:
    //   请理解以上内容,并返回一段英文的描述。`, fanyi_llm.api
    // );
    // item.画面描述词 = sd_describe;
729
    item.画面描述词 = item.场景关键词英文 + ',' + item.角色关键词英文
周成波's avatar
周成波 committed
730

731
    const sd_prompt = item.画面描述词 + ',' + sd_prompt_prefix
732 733
    // console.log(sd_prompt);
    // console.log(sd_negative_prompt_prefix);
734 735 736 737 738
    const sampler_index = sd_model.sampler_index
    const seed = sd_model.seed
    const steps = sd_model.steps
    const cfg_scale = sd_model.cfg_scale
    const model = sd_model.model
周成波's avatar
周成波 committed
739
    const sd_img = await text2videoService.submitSD(
740 741 742 743 744 745 746 747 748
      form.task_id,
      item.编号,
      utils.aesEncrypt(sd_prompt),
      utils.aesEncrypt(sd_negative_prompt_prefix),
      utils.aesEncrypt(form.img_size.width),
      utils.aesEncrypt(form.img_size.height),
      utils.aesEncrypt(sampler_index),
      utils.aesEncrypt(seed),
      utils.aesEncrypt(steps),
周成波's avatar
周成波 committed
749
      utils.aesEncrypt(cfg_scale),
750 751 752 753 754
      'true',
      utils.aesEncrypt(model)
    )
    item.本镜配图 = sd_img.domain_image_path + '?v=' + utils.genDateTimeStr()
    item.local_image_path = sd_img.local_image_path
周成波's avatar
周成波 committed
755 756 757
  } catch (error) {
    ElMessage({
      message: String(error),
758 759 760 761
      type: 'error'
    })
    item.本镜配图 = ''
    item.local_image_path = ''
周成波's avatar
周成波 committed
762
  }
763
}
周成波's avatar
周成波 committed
764

周成波's avatar
周成波 committed
765
const onGenVideo = async () => {
周成波's avatar
周成波 committed
766
  if (!form.adapt_result_json || form.adapt_result_json.length == 0) {
周成波's avatar
周成波 committed
767
    ElMessage({
768 769 770 771 772 773 774 775
      message: '分镜必要信息不能为空,请重新执行',
      type: 'error'
    })
    return
  }
  let is_all_ok = true
  form.adapt_result_json.map((item) => {
    if (item.编号 == '' || item.场景描述 == '' || item.local_image_path == '') {
周成波's avatar
周成波 committed
776 777
      ElMessage({
        message: `分镜 ${item.编号} 的必要信息为空,请重新执行`,
778 779 780
        type: 'error'
      })
      is_all_ok = false
周成波's avatar
周成波 committed
781
    }
782 783
  })
  if (!is_all_ok) return
周成波's avatar
周成波 committed
784
  try {
周成波's avatar
周成波 committed
785
    if (cover_backcover.if_need_cover_pic == 'true') {
786 787 788 789 790
      console.log('添加封面文字到图片')
      let res = await onMarketingTemplateAddTextToPic('cover')
      if (!res) {
        return
      }
周成波's avatar
周成波 committed
791
    }
周成波's avatar
周成波 committed
792
    if (cover_backcover.if_need_product_pic == 'true') {
793 794 795 796 797
      console.log('添加封底文字到图片')
      let res = await onMarketingTemplateAddTextToPic('product')
      if (!res) {
        return
      }
周成波's avatar
周成波 committed
798
    }
799

800 801
    console.log(form.adapt_result_json)
    let video_param_detail = []
周成波's avatar
周成波 committed
802
    // 封面
周成波's avatar
周成波 committed
803
    if (cover_backcover.if_need_cover_pic == 'true' && cover_backcover.cover_pic_with_text_local) {
周成波's avatar
周成波 committed
804
      video_param_detail.push({
805 806
        idx: '0',
        text: '',
周成波's avatar
周成波 committed
807
        img_path: cover_backcover.cover_pic_with_text_local,
808
        no_text_duration: '0.1'
周成波's avatar
周成波 committed
809
      })
810
    }
周成波's avatar
周成波 committed
811
    // 分镜
812
    form.adapt_result_json.map((item) => {
周成波's avatar
周成波 committed
813 814 815 816 817
      video_param_detail.push({
        idx: item.编号,
        text: item.场景描述,
        img_path: item.local_image_path
      })
818
    })
周成波's avatar
周成波 committed
819
    // 封底
820 821 822 823
    if (
      cover_backcover.if_need_product_pic == 'true' &&
      cover_backcover.product_pic_with_text_local
    ) {
周成波's avatar
周成波 committed
824
      // 如果text没有值,则时长默认5秒
周成波's avatar
周成波 committed
825 826
      video_param_detail.push({
        idx: String(form.adapt_result_json.length + 1),
周成波's avatar
周成波 committed
827 828
        text: cover_backcover.product_pic_speech,
        img_path: cover_backcover.product_pic_with_text_local,
829
        no_text_duration: '5'
周成波's avatar
周成波 committed
830
      })
831 832 833 834 835 836 837 838 839
    }
    let para_rate = `${voice_rate.value}%`
    let para_volume = `${voice_volume.value}%`
    if (voice_rate.value >= 0) {
      para_rate = `+${para_rate}`
    }
    if (voice_volume.value >= 0) {
      para_volume = `+${para_volume}`
    }
周成波's avatar
周成波 committed
840 841 842
    const video_param = {
      task_id: form.task_id,
      if_need_subtitle: form.if_need_subtitle,
843
      lang: 'zh',
周成波's avatar
周成波 committed
844 845 846 847 848 849 850 851 852
      task_info: video_param_detail,
      rate: para_rate,
      volume: para_volume,
      voice: voice.value,
      bgm: bgm.value,
      bgm_volume: bgm_volume.value,
      sub_font_size: String(sub_font_size.value),
      sub_font_color: sub_font_color.value,
      sub_position: String(1 - sub_position.value),
853
      sub_bg_color: ''
周成波's avatar
周成波 committed
854 855
    }
    if (sub_bg_color.value) {
856
      video_param.sub_bg_color = sub_bg_color.value
周成波's avatar
周成波 committed
857
    }
858

859 860 861 862 863
    const result = await text2videoService.submitGenVideo(video_param)
    console.log(result)
    form.final_video = ''
    form.final_video = result + '?v=' + utils.genDateTimeStr()
  } catch (error: any) {
周成波's avatar
周成波 committed
864 865 866
    // console.error(error);
    ElMessage({
      message: error,
867 868 869 870
      type: 'error'
    })
  }
}
周成波's avatar
周成波 committed
871

周成波's avatar
周成波 committed
872
const clean_data = () => {
873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899
  form.chatgpt_prompt = ''
  form.chatgpt_answer = ''
  form.chatgpt_answer_roles = <Wm.RolesItem[]>[]
  form.adapt_result_json = <Wm.ScriptsItem[]>[]
  form.task_id = ''
  form.final_video = ''

  cover_backcover.if_need_cover_pic = 'false'
  cover_backcover.cover_pic = 'src/assets/waiting.png'
  cover_backcover.cover_pic_local = ''
  cover_backcover.cover_pic_with_text = 'src/assets/waiting.png'
  cover_backcover.cover_pic_with_text_local = ''
  cover_backcover.cover_pic_titles = <Wm.PicText[]>[]
  cover_backcover.cover_pic_use_scene = ''

  cover_backcover.if_need_product_pic = 'false'
  cover_backcover.product_pic = 'src/assets/waiting.png'
  cover_backcover.product_pic_local = ''
  cover_backcover.product_pic_with_text = 'src/assets/waiting.png'
  cover_backcover.product_pic_with_text_local = ''
  cover_backcover.product_pic_titles = <Wm.PicText[]>[]
  cover_backcover.product_pic_speech = ''

  update_and_modify_product.pic = 'src/assets/waiting.png'
  update_and_modify_product.pic_local = ''
  update_and_modify_product.pic_preview = 'src/assets/waiting.png'
  update_and_modify_product.pic_preview_local = ''
周成波's avatar
周成波 committed
900
}
周成波's avatar
周成波 committed
901

902
const clean_roles = () => {
903
  form.chatgpt_answer_roles = <Wm.RolesItem[]>[]
904
}
周成波's avatar
周成波 committed
905
const clean_scenes = () => {
906
  form.adapt_result_json = <Wm.ScriptsItem[]>[]
周成波's avatar
周成波 committed
907
}
908

周成波's avatar
周成波 committed
909
const onChangeScreen = (val: string) => {
周成波's avatar
周成波 committed
910
  // 先清理数据
911
  clean_data()
周成波's avatar
周成波 committed
912 913
  if (!form.task_id) {
    // 初始化task_id
914
    form.task_id = utils.genDateTimeStr()
Administrator's avatar
Administrator committed
915
    console.log('更改屏幕设置,task_id=', form.task_id)
周成波's avatar
周成波 committed
916 917
  }

周成波's avatar
周成波 committed
918
  if (debug.value == true) {
919 920 921 922 923 924 925 926
    if (val == '横屏') {
      form.task_id = default_data.horizontal_data.task_id
      form.chatgpt_prompt = default_data.horizontal_data.chatgpt_prompt
      form.chatgpt_answer = default_data.horizontal_data.chatgpt_answer
      form.chatgpt_answer_roles = default_data.horizontal_data.chatgpt_answer_roles
      form.all_roles = default_data.horizontal_data.all_roles
      form.adapt_result_json = default_data.horizontal_data.adapt_result_json
      form.final_video = default_data.horizontal_data.final_video
周成波's avatar
周成波 committed
927
    } else {
928 929 930 931 932 933 934
      form.task_id = default_data.vertical_data.task_id
      form.chatgpt_prompt = default_data.vertical_data.chatgpt_prompt
      form.chatgpt_answer = default_data.vertical_data.chatgpt_answer
      form.chatgpt_answer_roles = default_data.vertical_data.chatgpt_answer_roles
      form.all_roles = default_data.vertical_data.all_roles
      form.adapt_result_json = default_data.vertical_data.adapt_result_json
      form.final_video = default_data.vertical_data.final_video
周成波's avatar
周成波 committed
935
    }
周成波's avatar
周成波 committed
936

937 938 939 940 941 942 943 944
    marketing_template.product_name = default_data.marketing_template.product_name
    marketing_template.product_description = default_data.marketing_template.product_description
    marketing_template.target_people = default_data.marketing_template.target_people
    marketing_template.text_role = default_data.marketing_template.text_role
    marketing_template.text_style = default_data.marketing_template.text_style
    marketing_template.story_type = default_data.marketing_template.story_type
    marketing_template.reference = default_data.marketing_template.reference
    marketing_template.words_num = default_data.marketing_template.words_num
周成波's avatar
周成波 committed
945

周成波's avatar
周成波 committed
946 947
    // cover_backcover.if_need_product_pic = 'true';
    // cover_backcover.if_need_cover_pic = 'true';
948 949 950
    cover_backcover.product_pic_titles = default_data.cover_backcover.product_pic_titles
    cover_backcover.product_pic_speech = default_data.cover_backcover.product_pic_speech
    cover_backcover.cover_pic_titles = default_data.cover_backcover.cover_pic_titles
周成波's avatar
周成波 committed
951

周成波's avatar
周成波 committed
952 953 954 955
    // cover_backcover.product_pic = default_data.cover_backcover.product_pic;
    // cover_backcover.product_pic_local = default_data.cover_backcover.product_pic_local;
    // cover_backcover.product_pic_with_text = default_data.cover_backcover.product_pic_with_text;
    // cover_backcover.product_pic_with_text_local = default_data.cover_backcover.product_pic_with_text_local;
956

周成波's avatar
周成波 committed
957 958 959 960
    // cover_backcover.cover_pic = default_data.cover_backcover.cover_pic;
    // cover_backcover.cover_pic_local = default_data.cover_backcover.cover_pic_local;
    // cover_backcover.cover_pic_with_text = default_data.cover_backcover.cover_pic_with_text;
    // cover_backcover.cover_pic_with_text_local = default_data.cover_backcover.cover_pic_with_text_local;
周成波's avatar
周成波 committed
961

962 963 964 965 966
    update_and_modify_product.if_need = 'true'
    update_and_modify_product.pic =
      'http://wm-tools-backend.frp.wmdigit.com:8888/assets/2024/05/13/f60b2b58-10d8-11ef-a812-559c156fce46_resized.png'
    update_and_modify_product.pic_local =
      'assets/2024/05/13/f60b2b58-10d8-11ef-a812-559c156fce46_resized.png'
周成波's avatar
周成波 committed
967
  }
周成波's avatar
周成波 committed
968

周成波's avatar
周成波 committed
969
  // 宽高
970 971
  if (val == '横屏') {
    form.img_size = default_data.horizontal_img_size
周成波's avatar
周成波 committed
972
  } else {
973
    form.img_size = default_data.vertical_img_size
周成波's avatar
周成波 committed
974
  }
周成波's avatar
周成波 committed
975
}
976

977
const showsdprompt = (item: any) => {
周成波's avatar
周成波 committed
978 979
  if (!item.画面描述词) {
    ElMessage({
980 981 982 983
      message: '还未绘图,请绘图后查看',
      type: 'error'
    })
    return
周成波's avatar
周成波 committed
984
  }
985
  // alert(item.画面描述词)
986 987
  dialogData.value = `${item.画面描述词},${sd_prompt_prefix}===== 反向提示词 =====${sd_negative_prompt_prefix}`
  dialogVisible.value = true // 打开对话框
988 989 990 991 992 993
}

const upload = ref<UploadInstance>()

const actionUrl = ref(
  import.meta.env.MODE === 'production'
周成波's avatar
周成波 committed
994 995
    ? '/file/upload_pic_and_modify'
    : import.meta.env.VITE_APP_BASE_API + '/file/upload_pic_and_modify'
996 997
)

周成波's avatar
周成波 committed
998 999 1000
// 在分镜自定义上传图片时发现个bug
// 第一次上传没问题,但重复进行上传,会更新到最后一行上去。
// 奇怪,没找到原因。暂时先通过迂回的方法来处理。
1001
// 终于找到原因了,是handleUploadExceed的问题,它在超出limit后,清空已上传,并将新文件上传,但用的都是upload实例
朱国瑞's avatar
朱国瑞 committed
1002
let uploadItemId = 0
1003
const onClickUpload = (val: any) => {
朱国瑞's avatar
朱国瑞 committed
1004
  uploadItemId = val.编号 - 1
1005
  console.log(uploadItemId)
朱国瑞's avatar
朱国瑞 committed
1006
}
1007
const handleUploadSuccess = (val: Wm.UploadResult) => {
周成波's avatar
周成波 committed
1008
  console.log(val)
周成波's avatar
周成波 committed
1009
  if (val.code == 0) {
1010 1011
    form.adapt_result_json[uploadItemId].本镜配图 = val.data[0].url + '?v=' + utils.genDateTimeStr()
    form.adapt_result_json[uploadItemId].local_image_path = val.data[0].path
1012 1013 1014 1015 1016 1017
    ElMessage({
      message: '上传成功',
      type: 'success'
    })
  } else {
    ElMessage({
1018
      message: '上传失败:' + val.message,
1019 1020 1021 1022
      type: 'error'
    })
  }
}
周成波's avatar
周成波 committed
1023
const handleUploadExceed: UploadProps['onExceed'] = (files) => {
1024
  // 清除已上传的文件
1025
  upload.value!.clearFiles()
1026
  // 获取超出限制的第一个文件
1027
  const file = files[0] as UploadRawFile
1028
  // 给文件分配一个新的唯一标识
1029
  file.uid = genFileId()
1030
  // 手动触发文件上传
1031
  upload.value!.handleStart(file)
1032
  // 提交上传
1033
  upload.value!.submit()
1034
}
1035

周成波's avatar
周成波 committed
1036 1037 1038
const handleUploadError = (error: Error) => {
  ElMessage({
    message: String(error.message),
1039 1040
    type: 'error'
  })
周成波's avatar
周成波 committed
1041 1042
}

周成波's avatar
周成波 committed
1043
const handleBeforeUpload = async (file: any) => {
1044
  const isLt1M = file.size / 1024 / 1024 <= 1
周成波's avatar
周成波 committed
1045 1046 1047 1048 1049
  if (!isLt1M) {
    ElMessage.error('上传图片大小不能超过 1MB!')
    return false
  }
  return new Promise((resolve, reject) => {
1050 1051 1052 1053 1054
    let is_size_ok = false
    const reader = new FileReader()
    reader.onload = (e: any) => {
      const dataURL = e.target.result
      const img = new Image()
周成波's avatar
周成波 committed
1055
      img.onload = () => {
1056 1057 1058 1059 1060 1061 1062
        console.log('文件宽度:', img.width)
        console.log('文件高度:', img.height)
        if (
          (form.screen == '竖屏' && img.height >= img.width) ||
          (form.screen == '横屏' && img.width >= img.height)
        ) {
          is_size_ok = true
周成波's avatar
周成波 committed
1063 1064
        }
        if (is_size_ok) {
1065
          resolve(true) // 尺寸符合要求
周成波's avatar
周成波 committed
1066
        } else {
1067
          reject('竖屏请上传竖屏图片,横屏请上传横屏图片!')
周成波's avatar
周成波 committed
1068
        }
1069 1070 1071 1072 1073 1074 1075 1076 1077
      }
      img.src = dataURL
    }
    reader.readAsDataURL(file)
  }).catch((error) => {
    console.log('Error:', error)
    ElMessage.error(error)
    return false
  })
周成波's avatar
周成波 committed
1078 1079
}

1080
const onClearOnePic = (item: any) => {
1081 1082 1083
  item.本镜配图 = ''
  item.local_image_path = ''
}
1084

1085 1086 1087 1088
const onPwdCheckDialog = () => {
  text2videoService
    .submitPwdCheck(pwdCheckValue.value)
    .then((result: string) => {
1089 1090
      if (result == 'success') {
        pwdCheckDialogVisible.value = false
1091 1092 1093
      } else {
        ElMessage({
          message: result,
1094 1095
          type: 'error'
        })
1096 1097 1098 1099 1100
      }
    })
    .catch((error: any) => {
      ElMessage({
        message: error,
1101 1102 1103
        type: 'error'
      })
    })
1104
}
周成波's avatar
周成波 committed
1105 1106 1107

const onDeleteOne = (item: any) => {
  try {
1108
    let delete_no = item.编号
周成波's avatar
周成波 committed
1109
    // 删除记录
1110
    form.adapt_result_json = form.adapt_result_json.filter((item) => item.编号 !== delete_no)
周成波's avatar
周成波 committed
1111 1112
    // 重新对记录进行编号
    form.adapt_result_json = form.adapt_result_json.map((item, index) => {
1113 1114
      return { ...item, 编号: (index + 1).toString() }
    })
周成波's avatar
周成波 committed
1115 1116 1117
  } catch (error) {
    ElMessage({
      message: String(error),
1118 1119
      type: 'error'
    })
周成波's avatar
周成波 committed
1120
  }
1121
}
周成波's avatar
周成波 committed
1122 1123 1124 1125 1126 1127 1128 1129

// ///////  模板相关  ////////////

// const activeTab = ref("first");
// const goToNextPage = () => {
//   activeTab.value = "second";
// };

1130 1131 1132 1133 1134
const upload_cover = ref<UploadInstance>()
const upload_product = ref<UploadInstance>()

const MarketingTemplateUploadProductPicSuccess = (val: Wm.UploadResult) => {
  // console.log(val)
周成波's avatar
周成波 committed
1135
  if (val.code == 0) {
1136 1137 1138 1139
    cover_backcover.product_pic = val.data[0].url + '?v=' + utils.genDateTimeStr()
    cover_backcover.product_pic_local = val.data[0].path
    cover_backcover.product_pic_with_text = 'src/assets/waiting.png'
    cover_backcover.product_pic_with_text_local = ''
周成波's avatar
周成波 committed
1140 1141 1142 1143
    ElMessage({
      message: '上传成功',
      type: 'success'
    })
Administrator's avatar
Administrator committed
1144
    // onMarketingTemplateAddTextToPic('product');
周成波's avatar
周成波 committed
1145 1146
  } else {
    ElMessage({
1147
      message: '上传失败:' + val.message,
周成波's avatar
周成波 committed
1148 1149 1150 1151
      type: 'error'
    })
  }
}
1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166
const handleMarketingTemplateUploadProductPicExceed: UploadProps['onExceed'] = (files) => {
  // 清除已上传的文件
  upload_product.value!.clearFiles()
  // 获取超出限制的第一个文件
  const file = files[0] as UploadRawFile
  // 给文件分配一个新的唯一标识
  file.uid = genFileId()
  // 手动触发文件上传
  upload_product.value!.handleStart(file)
  // 提交上传
  upload_product.value!.submit()
}

const MarketingTemplateUploadCoverPicSuccess = (val: Wm.UploadResult) => {
  if (val.code == 0) {
1167 1168 1169 1170
    cover_backcover.cover_pic = val.data[0].url + '?v=' + utils.genDateTimeStr()
    cover_backcover.cover_pic_local = val.data[0].path
    cover_backcover.cover_pic_with_text = 'src/assets/waiting.png'
    cover_backcover.cover_pic_with_text_local = ''
1171 1172 1173 1174
    ElMessage({
      message: '上传成功',
      type: 'success'
    })
Administrator's avatar
Administrator committed
1175
    // onMarketingTemplateAddTextToPic('cover');
1176 1177
  } else {
    ElMessage({
1178
      message: '上传失败:' + val.message,
1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194
      type: 'error'
    })
  }
}
const handleMarketingTemplateUploadCoverPicExceed: UploadProps['onExceed'] = (files) => {
  // 清除已上传的文件
  upload_cover.value!.clearFiles()
  // 获取超出限制的第一个文件
  const file = files[0] as UploadRawFile
  // 给文件分配一个新的唯一标识
  file.uid = genFileId()
  // 手动触发文件上传
  upload_cover.value!.handleStart(file)
  // 提交上传
  upload_cover.value!.submit()
}
周成波's avatar
周成波 committed
1195

1196 1197
const onClearMarketingTemplatePic = (type: string) => {
  if (type == 'product') {
1198 1199 1200 1201 1202
    cover_backcover.product_pic = 'src/assets/waiting.png'
    cover_backcover.product_pic_local = ''
    cover_backcover.product_pic_with_text = 'src/assets/waiting.png'
    cover_backcover.product_pic_with_text_local = ''
  }
1203
  if (type == 'cover') {
1204 1205 1206 1207 1208 1209 1210
    cover_backcover.cover_pic = 'src/assets/waiting.png'
    cover_backcover.cover_pic_local = ''
    cover_backcover.cover_pic_with_text = 'src/assets/waiting.png'
    cover_backcover.cover_pic_with_text_local = ''
    cover_backcover.cover_pic_use_scene = ''
  }
}
周成波's avatar
周成波 committed
1211 1212

const check_if_has_pic = (type: string) => {
1213 1214 1215 1216
  if (
    (type == 'product' && !cover_backcover.product_pic_local) ||
    (type == 'cover' && !cover_backcover.cover_pic_local)
  ) {
周成波's avatar
周成波 committed
1217 1218 1219 1220
    ElMessage({
      message: '请先设置图片',
      type: 'error'
    })
1221 1222 1223 1224
    return false
  }
  return true
}
周成波's avatar
周成波 committed
1225 1226

const onAddMarketingTemplatePicText = async (type: string, action: string, index: number) => {
1227 1228 1229 1230
  if (action == 'add') {
    if (!check_if_has_pic(type)) {
      return
    }
周成波's avatar
周成波 committed
1231 1232
    if (type == 'cover') {
      const newElement = {
1233 1234 1235
        text: '新的文本',
        color: '#000000',
        bg_color: '#FFFFFF',
周成波's avatar
周成波 committed
1236 1237
        font_size: 60,
        position: 0.37
1238 1239 1240
      }
      cover_backcover.cover_pic_titles.push(newElement)
    }
周成波's avatar
周成波 committed
1241 1242
    if (type == 'product') {
      const newElement = {
1243 1244 1245
        text: '关注  点赞  评论',
        color: '#DAFB01',
        bg_color: '#000000',
周成波's avatar
周成波 committed
1246 1247
        font_size: 60,
        position: 0.2
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261
      }
      cover_backcover.product_pic_titles.push(newElement)
    }
  }
  if (action == 'del') {
    if (type == 'cover') {
      cover_backcover.cover_pic_titles.splice(index, 1)
    }
    if (type == 'product') {
      cover_backcover.product_pic_titles.splice(index, 1)
    }
  }
  await onMarketingTemplateAddTextToPic(type)
}
周成波's avatar
周成波 committed
1262

1263
const onMarketingTemplateAddTextToPic = async (type: string) => {
1264 1265 1266 1267
  if (
    (type == 'product' && !cover_backcover.product_pic_local) ||
    (type == 'cover' && !cover_backcover.cover_pic_local)
  ) {
周成波's avatar
周成波 committed
1268
    ElMessage({
周成波's avatar
周成波 committed
1269
      message: '请先设置图片',
周成波's avatar
周成波 committed
1270 1271
      type: 'error'
    })
1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283
    return false
  }
  if (type == 'product' && cover_backcover.product_pic_titles.length == 0) {
    cover_backcover.product_pic_with_text = cover_backcover.product_pic
    cover_backcover.product_pic_with_text_local = cover_backcover.product_pic_local
    return true
  }
  if (type == 'cover' && cover_backcover.cover_pic_titles.length == 0) {
    cover_backcover.cover_pic_with_text = cover_backcover.cover_pic
    cover_backcover.cover_pic_with_text_local = cover_backcover.cover_pic_local
    return true
  }
周成波's avatar
周成波 committed
1284 1285
  let params = {
    image_path: '',
1286 1287
    image_texts: [
      {
周成波's avatar
周成波 committed
1288 1289 1290 1291 1292
        text: '',
        text_color: '',
        text_bg_color: '',
        font_size: '',
        position: '',
1293 1294 1295 1296
        lang: ''
      }
    ]
  }
1297
  if (type == 'product') {
1298
    const texts = cover_backcover.product_pic_titles.map((item) => {
1299 1300 1301 1302 1303 1304
      return {
        text: item.text,
        text_color: item.color ? item.color : '',
        text_bg_color: item.bg_color ? item.bg_color : '',
        font_size: String(item.font_size),
        position: String(1 - item.position),
1305 1306 1307
        lang: 'zh'
      }
    })
1308
    params = {
周成波's avatar
周成波 committed
1309
      image_path: cover_backcover.product_pic_local,
1310 1311 1312
      image_texts: texts
    }
  }
1313
  if (type == 'cover') {
1314
    const texts = cover_backcover.cover_pic_titles.map((item) => {
1315 1316 1317 1318 1319 1320
      return {
        text: item.text,
        text_color: item.color ? item.color : '',
        text_bg_color: item.bg_color ? item.bg_color : '',
        font_size: String(item.font_size),
        position: String(1 - item.position),
1321 1322 1323
        lang: 'zh'
      }
    })
1324
    params = {
周成波's avatar
周成波 committed
1325
      image_path: cover_backcover.cover_pic_local,
1326 1327 1328
      image_texts: texts
    }
  }
周成波's avatar
周成波 committed
1329 1330 1331 1332 1333 1334
  params.image_texts.forEach((item, index) => {
    if (!item.text_color || item.text_color.trim() === '') {
      ElMessage({
        message: '字体颜色不能为空',
        type: 'error'
      })
1335
      return false
周成波's avatar
周成波 committed
1336
    }
1337
  })
周成波's avatar
周成波 committed
1338

周成波's avatar
周成波 committed
1339
  try {
1340
    const result = await text2videoService.submitAddTextToImg(params)
1341 1342
    // console.log(result);
    if (type == 'product') {
1343 1344 1345
      cover_backcover.product_pic_with_text =
        result.domain_image_path + '?v=' + utils.genDateTimeStr()
      cover_backcover.product_pic_with_text_local = result.local_image_path
1346 1347
    }
    if (type == 'cover') {
1348 1349 1350
      cover_backcover.cover_pic_with_text =
        result.domain_image_path + '?v=' + utils.genDateTimeStr()
      cover_backcover.cover_pic_with_text_local = result.local_image_path
1351
    }
1352
    return true
周成波's avatar
周成波 committed
1353 1354 1355
  } catch (error) {
    ElMessage({
      message: String(error),
1356 1357
      type: 'error'
    })
1358
    if (type == 'product') {
1359 1360
      cover_backcover.product_pic_with_text = ''
      cover_backcover.product_pic_with_text_local = ''
1361 1362
    }
    if (type == 'cover') {
1363 1364
      cover_backcover.cover_pic_with_text = ''
      cover_backcover.cover_pic_with_text_local = ''
1365
    }
1366
    return false
周成波's avatar
周成波 committed
1367
  }
1368
}
周成波's avatar
周成波 committed
1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386

const onMarketingTemplateSubmitGpt = async () => {
  marketing_template.prompt1 = `
  商品名称:{${marketing_template.product_name}}
  商品卖点:[${marketing_template.product_description}]
  文案主角:{${marketing_template.text_role}}
  产品目标群体:{${marketing_template.target_people}}
  参考信息:[${marketing_template.reference}]
  你是营销专家,请写一个文案主角和商品的互动文案,要先理解商品卖点,学习参考信息,以${marketing_template.text_style}的风格,先整理出这篇营销文案的文案提纲。
  注意,要用精简的语言总结出文案的提纲,文案提纲是:{}
  在最后总结,把故事情节总结成一句夺人眼球的疑问句开头,设置悬念,需要你总结成15个字以内,开头语总结是:{}
  `
  marketing_template.prompt2 = `
  你是${marketing_template.story_type}作家,请根据原始内容和你分析的框架,写一个${marketing_template.words_num}字的${marketing_template.story_type}故事文案。
  特别注意,不能提到功效类用词,不要直接用目标群体的描述带入到框架中,用这个群体的特征描述来代。第一句用你总结的开头语,整体字数是${marketing_template.words_num}字。
  你给出的文案是:{}
  `
  try {
1387 1388 1389 1390 1391 1392 1393 1394 1395
    console.log('第一次提问')
    let result1 = await text2videoService.submitLLM(
      utils.aesEncrypt(marketing_template.prompt1),
      utils.aesEncrypt(wen_an_llm.api),
      [],
      form.task_id,
      'true'
    )
    marketing_template.result1 = result1
周成波's avatar
周成波 committed
1396 1397
    // console.log(marketing_template.prompt1);
    // console.log(marketing_template.result1);
周成波's avatar
周成波 committed
1398

1399
    console.log('第二次带历史提问')
周成波's avatar
周成波 committed
1400
    const history = [
1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411
      { role: utils.aesEncrypt('user'), content: utils.aesEncrypt(marketing_template.prompt1) },
      { role: utils.aesEncrypt('assistant'), content: utils.aesEncrypt(result1) }
    ]
    let result2 = await text2videoService.submitLLM(
      utils.aesEncrypt(marketing_template.prompt2),
      utils.aesEncrypt(wen_an_llm.api),
      history,
      form.task_id,
      'true'
    )
    marketing_template.result2 = result2
周成波's avatar
周成波 committed
1412 1413
    // console.log(JSON.stringify(history), marketing_template.prompt2);
    // console.log(marketing_template.result2);
1414

1415 1416 1417
    form.chatgpt_answer = result2
    marketingTemplateVisible.value = false
  } catch (error) {
周成波's avatar
周成波 committed
1418 1419
    ElMessage({
      message: String(error),
1420 1421
      type: 'error'
    })
周成波's avatar
周成波 committed
1422
  }
1423
}
周成波's avatar
周成波 committed
1424

周成波's avatar
周成波 committed
1425
const onTest = () => {
1426 1427 1428
  console.log(form.chatgpt_prompt)
  const encrypt_data = utils.aesEncrypt(form.chatgpt_prompt)
  console.log(encrypt_data)
周成波's avatar
周成波 committed
1429 1430 1431
  text2videoService
    .submitTest(encrypt_data)
    .then((result: string) => {
1432 1433
      console.log(result)
      form.chatgpt_answer = result
周成波's avatar
周成波 committed
1434 1435 1436 1437 1438
    })
    .catch((error: any) => {
      // console.error(error);
      ElMessage({
        message: error,
1439 1440 1441 1442
        type: 'error'
      })
    })
}
周成波's avatar
周成波 committed
1443 1444

const onSelectCoverChange = (value: any) => {
1445 1446 1447 1448 1449
  cover_backcover.cover_pic = form.adapt_result_json[parseInt(value) - 1].本镜配图
  cover_backcover.cover_pic_local = form.adapt_result_json[parseInt(value) - 1].local_image_path
  cover_backcover.cover_pic_with_text = 'src/assets/waiting.png'
  cover_backcover.cover_pic_with_text_local = ''
  onMarketingTemplateAddTextToPic('cover')
周成波's avatar
周成波 committed
1450
}
Administrator's avatar
Administrator committed
1451 1452 1453

// 局部重绘Dialog
const showInPaintDialog = (type: string, item: any) => {
1454 1455 1456 1457 1458 1459 1460 1461 1462
  let base_img_path = ''
  inPaintType.value = type
  inPaintItem.value = null
  inPaintPrompt.value = ''
  inPaintBaseImgData.value = ''
  inPaintMaskData.value = ''

  if (type == 'scene') {
    inPaintItem.value = item
Administrator's avatar
Administrator committed
1463
    // inPaintPrompt.value = inPaintItem.value.场景关键词+' '+inPaintItem.value.角色关键词;
1464 1465 1466 1467 1468
    inPaintPrompt.value = ''
    base_img_path = inPaintItem.value.本镜配图
  } else if (type == 'cover') {
    inPaintPrompt.value = ''
    base_img_path = cover_backcover.cover_pic
Administrator's avatar
Administrator committed
1469
  } else if (type == 'product') {
1470 1471 1472
    inPaintPrompt.value = ''
    base_img_path = cover_backcover.product_pic
  }
Administrator's avatar
Administrator committed
1473

1474
  if (!base_img_path || base_img_path.length == 0) {
Administrator's avatar
Administrator committed
1475
    ElMessage({
1476 1477 1478 1479
      message: '没有基础图片,请确认',
      type: 'error'
    })
    return
Administrator's avatar
Administrator committed
1480 1481
  }

1482
  inPaintVisible.value = true // 打开对话框
Administrator's avatar
Administrator committed
1483 1484 1485 1486

  // 等待元素加载完成
  nextTick(() => {
    // 局部重绘
1487 1488
    const base_canvas = document.getElementById('baseCanvas') as HTMLCanvasElement
    const mask_canvas = document.getElementById('maskCanvas') as HTMLCanvasElement
Administrator's avatar
Administrator committed
1489
    if (base_canvas && mask_canvas) {
1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507
      let base_ctx = base_canvas.getContext('2d') as CanvasRenderingContext2D
      base_ctx.clearRect(0, 0, base_canvas.width, base_canvas.height)
      var img = new Image()
      img.crossOrigin = 'Anonymous' // 如果图片需要用于跨域,则需要设置这个属性
      img.onload = function () {
        base_canvas.width = img.width
        base_canvas.height = img.height
        base_ctx.drawImage(img, 0, 0, base_canvas.width, base_canvas.height)
      }
      img.src = base_img_path

      let mask_ctx = mask_canvas.getContext('2d') as CanvasRenderingContext2D
      mask_ctx.clearRect(0, 0, mask_canvas.width, mask_canvas.height)

      mask_ctx.lineWidth = 40 // 设置线条粗细
      mask_ctx.strokeStyle = 'rgba(255, 255, 255, 1)' // 设置线条颜色
      mask_ctx.lineCap = 'round' // 线头尾为圆形
      mask_ctx.lineJoin = 'round' // 拐点为圆形,默认是尖角
Administrator's avatar
Administrator committed
1508
      // mask_ctx.globalCompositeOperation = 'destination-atop';  //避免线条重叠的时候透明度也重叠
Administrator's avatar
Administrator committed
1509
      // mask_ctx.globalCompositeOperation = 'copy';  //避免线条重叠的时候透明度也重叠
Administrator's avatar
Administrator committed
1510

1511
      let isDrawing = false
Administrator's avatar
Administrator committed
1512
      // 鼠标或触摸事件开始绘制
1513 1514
      mask_canvas.addEventListener('mousedown', startDrawing)
      mask_canvas.addEventListener('touchstart', startDrawing)
Administrator's avatar
Administrator committed
1515 1516

      // 鼠标或触摸事件绘制中
1517 1518
      mask_canvas.addEventListener('mousemove', draw)
      mask_canvas.addEventListener('touchmove', draw)
Administrator's avatar
Administrator committed
1519 1520

      // 鼠标或触摸事件结束绘制
1521 1522 1523
      mask_canvas.addEventListener('mouseup', stopDrawing)
      mask_canvas.addEventListener('touchend', stopDrawing)
      mask_canvas.addEventListener('mouseout', stopDrawing)
Administrator's avatar
Administrator committed
1524 1525

      // 清除按钮点击事件
1526 1527
      const clearButton = document.getElementById('clearButton') as HTMLButtonElement
      clearButton.addEventListener('click', clearCanvas)
Administrator's avatar
Administrator committed
1528 1529 1530

      // 开始绘制
      function startDrawing(e: any) {
1531 1532 1533 1534 1535
        isDrawing = true
        mask_ctx.beginPath()
        const { offsetX, offsetY } = getOffset(e)
        mask_ctx.moveTo(offsetX, offsetY)
        draw(e)
Administrator's avatar
Administrator committed
1536 1537 1538 1539
      }

      // 绘制中
      function draw(e: any) {
1540 1541 1542 1543
        if (!isDrawing) return
        const { offsetX, offsetY } = getOffset(e)
        mask_ctx.lineTo(offsetX, offsetY)
        mask_ctx.stroke()
Administrator's avatar
Administrator committed
1544 1545 1546 1547
      }

      // 结束绘制
      function stopDrawing() {
1548 1549 1550
        isDrawing = false
        inPaintBaseImgData.value = base_canvas.toDataURL('image/png')
        inPaintMaskData.value = mask_canvas.toDataURL('image/png')
Administrator's avatar
Administrator committed
1551 1552 1553 1554
      }

      // 清除画布
      function clearCanvas() {
1555
        mask_ctx.clearRect(0, 0, mask_canvas.width, mask_canvas.height)
Administrator's avatar
Administrator committed
1556 1557 1558 1559
      }

      // 获取鼠标或触摸事件的偏移量
      function getOffset(e: any) {
1560 1561 1562 1563 1564 1565 1566 1567 1568 1569
        const rect = mask_canvas.getBoundingClientRect()
        let offsetX, offsetY
        if (e.type.includes('touch')) {
          offsetX = e.touches[0].clientX - rect.left
          offsetY = e.touches[0].clientY - rect.top
        } else {
          offsetX = e.offsetX
          offsetY = e.offsetY
        }
        return { offsetX, offsetY }
Administrator's avatar
Administrator committed
1570 1571
      }
    } else {
1572
      console.error('Canvas element not found')
Administrator's avatar
Administrator committed
1573
    }
1574
  })
Administrator's avatar
Administrator committed
1575 1576 1577 1578 1579
}

const onSubmitInPaint = async () => {
  if (!form.task_id) {
    ElMessage({
1580 1581 1582 1583
      message: 'task_id不能为空,请刷新页面',
      type: 'error'
    })
    return
Administrator's avatar
Administrator committed
1584 1585 1586
  }
  if (!inPaintBaseImgData.value || !inPaintMaskData.value) {
    ElMessage({
1587 1588 1589 1590
      message: '请在图片上涂抹需要保留的部分!',
      type: 'error'
    })
    return
Administrator's avatar
Administrator committed
1591
  }
1592
  if (!inPaintPrompt.value || inPaintPrompt.value.length == 0) {
Administrator's avatar
Administrator committed
1593
    ElMessage({
1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618
      message: '请填写画面描述!',
      type: 'error'
    })
    return
  }
  const sampler_index = sd_model.sampler_index
  const seed = sd_model.seed
  const steps = sd_model.steps
  const cfg_scale = sd_model.cfg_scale
  const model = sd_model.model
  const base_img = inPaintBaseImgData.value
  const mask = inPaintMaskData.value

  let sd_prompt = ''
  let img_id = ''
  let item = null

  if (inPaintType.value == 'scene') {
    item = inPaintItem.value
    item.本镜配图 = 'src/assets/loading.gif'
    img_id = item.编号
  } else if (inPaintType.value == 'cover') {
    img_id = 'cover'
    cover_backcover.cover_pic = 'src/assets/waiting.png'
    cover_backcover.cover_pic_local = ''
Administrator's avatar
Administrator committed
1619
  } else if (inPaintType.value == 'product') {
1620 1621 1622 1623
    img_id = 'product'
    cover_backcover.product_pic = 'src/assets/waiting.png'
    cover_backcover.product_pic_local = ''
  }
Administrator's avatar
Administrator committed
1624 1625

  try {
1626 1627 1628 1629 1630 1631 1632
    let keywords_en = await text2videoService.submitTranslateToEn(
      utils.aesEncrypt(inPaintPrompt.value),
      form.task_id,
      'true'
    )
    sd_prompt = keywords_en.replace(/"/g, '') + ',' + sd_prompt_prefix
    let sd_img
Administrator's avatar
Administrator committed
1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644
    if (debug.value == true) {
      sd_img = await text2videoService.submitSDInPaint(
        form.task_id,
        img_id,
        sd_prompt,
        sd_negative_prompt_prefix,
        form.img_size.width,
        form.img_size.height,
        sampler_index,
        seed,
        steps,
        cfg_scale,
1645
        'false',
Administrator's avatar
Administrator committed
1646 1647 1648
        model,
        base_img,
        mask,
1649 1650
        'img_data'
      )
Administrator's avatar
Administrator committed
1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662
    } else {
      sd_img = await text2videoService.submitSDInPaint(
        form.task_id,
        img_id,
        utils.aesEncrypt(sd_prompt),
        utils.aesEncrypt(sd_negative_prompt_prefix),
        utils.aesEncrypt(form.img_size.width),
        utils.aesEncrypt(form.img_size.height),
        utils.aesEncrypt(sampler_index),
        utils.aesEncrypt(seed),
        utils.aesEncrypt(steps),
        utils.aesEncrypt(cfg_scale),
1663
        'true',
Administrator's avatar
Administrator committed
1664 1665 1666
        utils.aesEncrypt(model),
        utils.aesEncrypt(base_img),
        utils.aesEncrypt(mask),
1667 1668
        'img_data'
      )
Administrator's avatar
Administrator committed
1669
    }
1670 1671 1672
    if (inPaintType.value == 'scene') {
      item.本镜配图 = sd_img.domain_image_path + '?v=' + utils.genDateTimeStr()
      item.local_image_path = sd_img.local_image_path
Administrator's avatar
Administrator committed
1673
    } else if (inPaintType.value == 'cover') {
1674 1675
      cover_backcover.cover_pic = sd_img.domain_image_path + '?v=' + utils.genDateTimeStr()
      cover_backcover.cover_pic_local = sd_img.local_image_path
Administrator's avatar
Administrator committed
1676
    } else if (inPaintType.value == 'product') {
1677 1678 1679
      cover_backcover.product_pic = sd_img.domain_image_path + '?v=' + utils.genDateTimeStr()
      cover_backcover.product_pic_local = sd_img.local_image_path
    }
Administrator's avatar
Administrator committed
1680 1681 1682
  } catch (error) {
    ElMessage({
      message: String(error),
1683 1684
      type: 'error'
    })
Administrator's avatar
Administrator committed
1685
  } finally {
1686
    inPaintVisible.value = false // 关闭对话框
Administrator's avatar
Administrator committed
1687 1688
  }
}
1689

1690
//  上传自定义的产品图并重绘
1691
const upload_update_and_modify_product = ref<UploadInstance>()
1692 1693
const UploadAndModifyProductPicSuccess = (val: Wm.UploadResult) => {
  if (val.code == 0) {
1694 1695 1696 1697
    update_and_modify_product.pic = val.data[0].url + '?v=' + utils.genDateTimeStr()
    update_and_modify_product.pic_local = val.data[0].path
    update_and_modify_product.pic_preview = val.data[0].url + '?v=' + utils.genDateTimeStr()
    update_and_modify_product.pic_preview_local = val.data[0].path
1698 1699 1700
    ElMessage({
      message: '上传成功',
      type: 'success'
1701 1702 1703
    })
  } else {
    ElMessage({
1704
      message: '上传失败:' + val.message,
1705 1706 1707 1708
      type: 'error'
    })
  }
}
1709 1710 1711 1712 1713
const onAnalyzeUploadAndModifyProductPic = () => {
  // 解析内容
  const param = {
    task_id: form.task_id,
    image_path: update_and_modify_product.pic_local,
1714
    prompt: '找到图片中的所有文字,理解图片中的商品信息和背景信息'
1715 1716
  }
  text2videoService
1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731
    .submitImgToText(param)
    .then((result: string) => {
      if (form.chatgpt_prompt == '') {
        form.chatgpt_prompt = result + ' 根据以上信息,编写一段50字的小故事。'
      } else {
        form.chatgpt_prompt = result + ' 根据以上信息,' + form.chatgpt_prompt
      }
    })
    .catch((error: any) => {
      ElMessage({
        message: '解析失败:' + error,
        type: 'error'
      })
    })
}
1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744
const handleUploadAndModifyProductPicExceed: UploadProps['onExceed'] = (files) => {
  // 清除已上传的文件
  upload_update_and_modify_product.value!.clearFiles()
  // 获取超出限制的第一个文件
  const file = files[0] as UploadRawFile
  // 给文件分配一个新的唯一标识
  file.uid = genFileId()
  // 手动触发文件上传
  upload_update_and_modify_product.value!.handleStart(file)
  // 提交上传
  upload_update_and_modify_product.value!.submit()
}
const onClearUploadAndModifyProductPic = () => {
1745 1746 1747 1748 1749
  update_and_modify_product.pic = 'src/assets/waiting.png'
  update_and_modify_product.pic_local = ''
  update_and_modify_product.pic_preview = 'src/assets/waiting.png'
  update_and_modify_product.pic_preview_local = ''
}
1750
// 自定义产品图重绘Dialog
1751
let if_binded_events = false
1752
const showUploadAndModifyProductPicInPaintDialog = () => {
1753 1754 1755 1756 1757 1758 1759 1760
  update_and_modify_product.inPaintPrompt = ''
  update_and_modify_product.inPaintBaseImgData = ''
  update_and_modify_product.inPaintMaskData = ''
  update_and_modify_product.cutout_obj = <Wm.Coordinate[]>[]
  update_and_modify_product.cutout_no_obj = <Wm.Coordinate[]>[]

  let base_img_path = update_and_modify_product.pic
  if (!base_img_path || base_img_path.length == 0) {
1761
    ElMessage({
1762 1763 1764 1765
      message: '没有基础图片,请确认',
      type: 'error'
    })
    return
1766
  }
1767 1768
  let preview_img_path = update_and_modify_product.pic_preview
  update_and_modify_product.inPaintVisible = true // 打开对话框
1769 1770 1771
  // 等待元素加载完成
  nextTick(() => {
    // 自定义产品图局部重绘
1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789
    const base_canvas = document.getElementById(
      'update_and_modify_product_baseCanvas'
    ) as HTMLCanvasElement
    const preview_canvas = document.getElementById(
      'update_and_modify_product_previewCanvas'
    ) as HTMLCanvasElement
    const mask_canvas = document.getElementById(
      'update_and_modify_product_maskCanvas'
    ) as HTMLCanvasElement
    const clearButton = document.getElementById(
      'update_and_modify_product_clearButton'
    ) as HTMLButtonElement
    const no_obj_checkbox = document.getElementById(
      'update_and_modify_product_noObjCheckbox'
    ) as HTMLInputElement
    const mask_canvas2 = document.getElementById(
      'update_and_modify_product_maskCanvas2'
    ) as HTMLCanvasElement
1790
    // 初始化非产品层
1791 1792
    no_obj_checkbox.checked = false
    mask_canvas2.style.zIndex = '3'
1793

1794 1795
    if (base_canvas && preview_canvas && mask_canvas) {
      // 基础图
1796 1797 1798 1799 1800 1801 1802 1803 1804 1805
      let base_ctx = base_canvas.getContext('2d') as CanvasRenderingContext2D
      base_ctx.clearRect(0, 0, base_canvas.width, base_canvas.height)
      var base_img = new Image()
      base_img.crossOrigin = 'Anonymous' // 如果图片需要用于跨域,则需要设置这个属性
      base_img.onload = function () {
        base_canvas.width = base_img.width
        base_canvas.height = base_img.height
        base_ctx.drawImage(base_img, 0, 0, base_canvas.width, base_canvas.height)
      }
      base_img.src = base_img_path
1806 1807

      // 预览图
1808 1809
      let preview_ctx = preview_canvas.getContext('2d') as CanvasRenderingContext2D
      preview_ctx.clearRect(0, 0, preview_canvas.width, preview_canvas.height)
1810
      if (preview_img_path && preview_img_path.length != 0) {
1811 1812 1813 1814 1815 1816 1817 1818
        var preview_img = new Image()
        preview_img.crossOrigin = 'Anonymous' // 如果图片需要用于跨域,则需要设置这个属性
        preview_img.onload = function () {
          preview_canvas.width = preview_img.width
          preview_canvas.height = preview_img.height
          preview_ctx.drawImage(preview_img, 0, 0, preview_canvas.width, preview_canvas.height)
        }
        preview_img.src = preview_img_path
1819 1820 1821
      }

      // 产品层mask
1822 1823 1824 1825 1826 1827 1828
      let mask_ctx = mask_canvas.getContext('2d') as CanvasRenderingContext2D
      mask_ctx.clearRect(0, 0, mask_canvas.width, mask_canvas.height)
      mask_ctx.lineWidth = 40 // 设置线条粗细
      mask_ctx.strokeStyle = 'rgba(255, 255, 255, 1)' // 设置线条颜色
      mask_ctx.lineCap = 'round' // 线头尾为圆形
      mask_ctx.lineJoin = 'round' // 拐点为圆形,默认是尖角
      mask_ctx.globalCompositeOperation = 'copy'
1829

1830
      // 非产品层mask
1831 1832 1833 1834 1835 1836 1837
      let mask_ctx2 = mask_canvas2.getContext('2d') as CanvasRenderingContext2D
      mask_ctx2.clearRect(0, 0, mask_canvas2.width, mask_canvas2.height)
      mask_ctx2.lineWidth = 40 // 设置线条粗细
      mask_ctx2.strokeStyle = 'rgba(255, 0, 0, 1)' // 设置线条颜色
      mask_ctx2.lineCap = 'round' // 线头尾为圆形
      mask_ctx2.lineJoin = 'round' // 拐点为圆形,默认是尖角
      mask_ctx2.globalCompositeOperation = 'copy'
1838

1839
      if (!if_binded_events) {
1840
        // 点选产品事件
1841
        mask_canvas.addEventListener('mousedown', onClickObj)
1842
        // 重置按钮点击事件
1843
        clearButton.addEventListener('click', resetCanvas)
1844
        // 复选框事件
1845
        no_obj_checkbox.addEventListener('click', onClickNoObjCheckbox)
1846
        // 点选非产品事件
1847
        mask_canvas2.addEventListener('mousedown', onClickNoObj)
1848
        // 每次打开都会再绑定一次,这里防止多次绑定,否则数据会重复
1849
        if_binded_events = true
1850 1851
      }

1852 1853
      // 点选产品
      function onClickObj(e: any) {
1854 1855 1856 1857 1858 1859 1860 1861 1862
        mask_ctx.beginPath()
        const { offsetX, offsetY } = getOffset(e)
        mask_ctx.moveTo(offsetX, offsetY)
        mask_ctx.lineTo(offsetX, offsetY)
        mask_ctx.stroke()
        console.log('obj==>', offsetX, offsetY)
        // 先清空再push,保证里面只有一个点
        update_and_modify_product.cutout_obj = <Wm.Coordinate[]>[]
        update_and_modify_product.cutout_obj.push({ x: offsetX, y: offsetY })
1863
      }
1864 1865 1866

      // 点选产品
      function onClickNoObj(e: any) {
1867 1868 1869 1870 1871 1872 1873 1874 1875
        mask_ctx2.beginPath()
        const { offsetX, offsetY } = getOffset(e)
        mask_ctx2.moveTo(offsetX, offsetY)
        mask_ctx2.lineTo(offsetX, offsetY)
        mask_ctx2.stroke()
        console.log('no-obj==>', offsetX, offsetY)
        // 先清空再push,保证里面只有一个点
        update_and_modify_product.cutout_no_obj = <Wm.Coordinate[]>[]
        update_and_modify_product.cutout_no_obj.push({ x: offsetX, y: offsetY })
1876 1877 1878 1879
      }

      // 重置
      function resetCanvas() {
1880 1881 1882 1883
        update_and_modify_product.pic_preview = ''
        update_and_modify_product.pic_preview_local = ''
        update_and_modify_product.inPaintVisible = false // 关闭对话框
        showUploadAndModifyProductPicInPaintDialog() // 再打开对话框进行预览
1884 1885 1886 1887
      }

      // checkbox点击事件
      function onClickNoObjCheckbox() {
1888 1889
        if (no_obj_checkbox.checked) {
          mask_canvas2.style.zIndex = '5'
1890
        } else {
1891
          mask_canvas2.style.zIndex = '3'
1892
        }
1893 1894 1895
        const computedStyle = window.getComputedStyle(mask_canvas2)
        const currentZIndex = computedStyle.getPropertyValue('z-index')
        console.log('Current z-index:', currentZIndex)
1896
      }
1897

1898 1899
      // 获取鼠标的偏移量
      function getOffset(e: any) {
1900 1901 1902 1903 1904
        // console.log(e)
        let offsetX = e.offsetX
        let offsetY = e.offsetY
        // console.log({ offsetX, offsetY })
        return { offsetX, offsetY }
1905 1906 1907 1908
      }
    } else {
      ElMessage({
        message: 'Canvas element not found',
1909 1910 1911
        type: 'error'
      })
      console.error('Canvas element not found')
1912
    }
1913
  })
1914 1915 1916 1917 1918
}

const onSubmitUploadAndModifyProductPicCutOut = async () => {
  if (!form.task_id) {
    ElMessage({
1919 1920 1921 1922
      message: 'task_id不能为空,请刷新页面',
      type: 'error'
    })
    return
1923
  }
1924
  if (update_and_modify_product.cutout_obj.length == 0) {
1925
    ElMessage({
1926 1927 1928 1929
      message: '没有产品坐标,至少要点击产品!',
      type: 'error'
    })
    return
1930
  }
1931 1932
  let point_prompt: any[] = []
  let point_label: any[] = []
1933 1934 1935
  // 产品坐标
  // console.log(update_and_modify_product.cutout_obj)
  update_and_modify_product.cutout_obj.forEach((item, index) => {
1936 1937 1938
    point_prompt.push([item.x, item.y])
    point_label.push(1)
  })
1939 1940
  // 非产品坐标
  update_and_modify_product.cutout_no_obj.forEach((item, index) => {
1941 1942 1943
    point_prompt.push([item.x, item.y])
    point_label.push(0)
  })
1944 1945 1946 1947 1948 1949 1950
  // console.log(point_prompt, point_label)
  // console.log(JSON.stringify(point_prompt), JSON.stringify(point_label))
  // return;
  const param = {
    task_id: form.task_id,
    image_path: update_and_modify_product.pic_local,
    point_prompt: JSON.stringify(point_prompt),
1951
    point_label: JSON.stringify(point_label)
1952 1953 1954
  }
  // console.log(param)
  try {
1955 1956 1957 1958 1959 1960 1961
    const cutout_result = await text2videoService.submitCutOutImg(param)
    update_and_modify_product.pic_preview =
      cutout_result.domain_image_path_preview + '?v=' + utils.genDateTimeStr()
    update_and_modify_product.pic_preview_local = cutout_result.local_image_path_preview
    update_and_modify_product.pic_mask =
      cutout_result.domain_image_path_mask + '?v=' + utils.genDateTimeStr()
    update_and_modify_product.pic_mask_local = cutout_result.local_image_path_mask
1962 1963 1964
  } catch (error) {
    ElMessage({
      message: String(error),
1965 1966
      type: 'error'
    })
1967
  } finally {
1968 1969
    update_and_modify_product.inPaintVisible = false // 关闭对话框
    showUploadAndModifyProductPicInPaintDialog() // 再打开对话框进行预览
1970 1971 1972 1973 1974 1975
  }
}

const onSubmitUploadAndModifyProductPicInPaint = async () => {
  if (!form.task_id) {
    ElMessage({
1976 1977 1978 1979
      message: 'task_id不能为空,请刷新页面',
      type: 'error'
    })
    return
1980 1981 1982
  }
  if (!update_and_modify_product.pic_local || !update_and_modify_product.pic_mask_local) {
    ElMessage({
1983 1984 1985 1986
      message: '缺少基本图片和mask图片!',
      type: 'error'
    })
    return
1987
  }
1988 1989 1990 1991
  if (
    !update_and_modify_product.inPaintPrompt ||
    update_and_modify_product.inPaintPrompt.length == 0
  ) {
1992
    ElMessage({
1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007
      message: '请填写画面描述!',
      type: 'error'
    })
    return
  }
  const sampler_index = sd_model.sampler_index
  const seed = sd_model.seed
  const steps = sd_model.steps
  const cfg_scale = sd_model.cfg_scale
  const model = sd_model.model
  const base_img = update_and_modify_product.pic_local
  const mask = update_and_modify_product.pic_mask_local
  let img_id = 'update_and_modify_product'
  update_and_modify_product.pic = 'src/assets/waiting.png'
  update_and_modify_product.pic_local = ''
2008
  try {
2009 2010 2011 2012 2013 2014 2015
    let keywords_en = await text2videoService.submitTranslateToEn(
      utils.aesEncrypt(update_and_modify_product.inPaintPrompt),
      form.task_id,
      'true'
    )
    let sd_prompt = keywords_en.replace(/"/g, '') + ',' + sd_prompt_prefix
    let sd_img
Administrator's avatar
Administrator committed
2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027
    if (debug.value == true) {
      sd_img = await text2videoService.submitSDInPaint(
        form.task_id,
        img_id,
        sd_prompt,
        sd_negative_prompt_prefix,
        form.img_size.width,
        form.img_size.height,
        sampler_index,
        seed,
        steps,
        cfg_scale,
2028
        'false',
Administrator's avatar
Administrator committed
2029 2030 2031
        model,
        base_img,
        mask,
2032 2033
        'img_path'
      )
Administrator's avatar
Administrator committed
2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045
    } else {
      sd_img = await text2videoService.submitSDInPaint(
        form.task_id,
        img_id,
        utils.aesEncrypt(sd_prompt),
        utils.aesEncrypt(sd_negative_prompt_prefix),
        utils.aesEncrypt(form.img_size.width),
        utils.aesEncrypt(form.img_size.height),
        utils.aesEncrypt(sampler_index),
        utils.aesEncrypt(seed),
        utils.aesEncrypt(steps),
        utils.aesEncrypt(cfg_scale),
2046
        'true',
Administrator's avatar
Administrator committed
2047 2048 2049
        utils.aesEncrypt(model),
        utils.aesEncrypt(base_img),
        utils.aesEncrypt(mask),
2050 2051
        utils.aesEncrypt('img_path')
      )
Administrator's avatar
Administrator committed
2052
    }
2053 2054
    update_and_modify_product.pic = sd_img.domain_image_path + '?v=' + utils.genDateTimeStr()
    update_and_modify_product.pic_local = sd_img.local_image_path
2055 2056 2057
  } catch (error) {
    ElMessage({
      message: String(error),
2058 2059
      type: 'error'
    })
2060
  } finally {
2061
    update_and_modify_product.inPaintVisible = false // 关闭对话框
2062 2063
  }
}
Administrator's avatar
Administrator committed
2064 2065 2066 2067
</script>

<template>
  <main class="home-container">
周成波's avatar
周成波 committed
2068
    <!-- 标题 -->
Administrator's avatar
Administrator committed
2069
    <el-divider content-position="left">text2video</el-divider>
周成波's avatar
周成波 committed
2070
    <el-form :model="form" label-width="114px" v-loading="loading">
周成波's avatar
周成波 committed
2071 2072 2073
      <el-form-item>
        <div>
          <el-radio-group v-model="form.screen" @change="onChangeScreen">
周成波's avatar
周成波 committed
2074 2075
            <el-radio label="横屏" size="large" border />
            <el-radio label="竖屏" size="large" border />
周成波's avatar
周成波 committed
2076 2077 2078
          </el-radio-group>
        </div>
      </el-form-item>
周成波's avatar
周成波 committed
2079
      <el-form-item>
周成波's avatar
周成波 committed
2080
        <el-button type="success" @click="clean_data">清除所有数据</el-button>
周成波's avatar
周成波 committed
2081
        <!-- <el-button type="danger" @click="onTest">测试</el-button> -->
周成波's avatar
周成波 committed
2082
      </el-form-item>
2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096
      <!-- 产品图 -->
      <el-form-item label="产品图">
        <el-switch
          v-model="update_and_modify_product.if_need"
          active-value="true"
          inactive-value="false"
        />
      </el-form-item>
      <div v-if="JSON.parse(update_and_modify_product.if_need.toLowerCase())">
        <el-form-item>
          <div
            :style="{ width: String(parseInt(form.img_size.width) / 3) + 'px' }"
            class="dashed-div"
          >
Administrator's avatar
Administrator committed
2097 2098 2099 2100 2101 2102 2103 2104 2105 2106
            <!-- <el-image :src="update_and_modify_product.pic" /> -->
            <el-image
              :src="update_and_modify_product.pic"
              :zoom-rate="1.0"
              :max-scale="1.5"
              :min-scale="1.5"
              :preview-src-list="[update_and_modify_product.pic]"
              fit="cover"
              :hide-on-click-modal="true"
            />
2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128
          </div>
          <!-- <div
            :style="{ width: String(parseInt(form.img_size.width) / 3) + 'px' }"
            class="dashed-div"
            style="margin-left: 20px"
          >
            <el-image :src="update_and_modify_product.pic_preview" />
          </div> -->
        </el-form-item>
        <el-form-item>
          <el-upload
            ref="upload_update_and_modify_product"
            :show-file-list="false"
            :limit="1"
            accept=".png,.PNG,.jpg,.JPG,.jpeg,.JPEG,.gif,.GIF,.bmp,.BMP"
            :action="actionUrl"
            :on-success="UploadAndModifyProductPicSuccess"
            :on-exceed="handleUploadAndModifyProductPicExceed"
            :on-error="handleUploadError"
            :data="{ width: form.img_size.width, height: form.img_size.height }"
            :before-upload="handleBeforeUpload"
          >
2129
            <el-button type="primary" size="small">上传图片</el-button>
2130
          </el-upload>
Administrator's avatar
Administrator committed
2131 2132 2133 2134 2135 2136 2137
          <el-button
            type="primary"
            size="small"
            @click="showUploadAndModifyProductPicInPaintDialog"
            style="margin-left: 12px"
            >局部重绘</el-button
          >
2138 2139 2140 2141 2142 2143 2144
          <el-button
            type="primary"
            size="small"
            @click="onAnalyzeUploadAndModifyProductPic"
            style="margin-left: 12px"
            >解析图片</el-button
          >
2145 2146 2147 2148 2149 2150 2151 2152 2153
          <el-button
            plain
            size="small"
            @click="onClearUploadAndModifyProductPic"
            style="margin-left: 12px"
            >清除图片</el-button
          >
        </el-form-item>
      </div>
周成波's avatar
周成波 committed
2154
      <!-- Prompt到文案 -->
2155
      <el-form-item label="Prompt">
周成波's avatar
周成波 committed
2156
        <el-input v-model="form.chatgpt_prompt" :autosize="true" type="textarea" />
Administrator's avatar
Administrator committed
2157
      </el-form-item>
周成波's avatar
周成波 committed
2158
      <el-form-item>
2159
        <el-button type="primary" @click="onSubmitGpt">生成文案({{ wen_an_llm.name }}</el-button>
2160 2161 2162
        <el-button type="danger" @click="marketingTemplateVisible = true"
          >通过营销模板生成文案</el-button
        >
周成波's avatar
周成波 committed
2163
      </el-form-item>
周成波's avatar
周成波 committed
2164
      <el-form-item label="文案">
周成波's avatar
周成波 committed
2165 2166 2167 2168 2169 2170 2171 2172
        <template v-if="marketing_template.result2">
          <el-text class="mx-1" type="danger">第一次提问:</el-text>
          <el-text class="mx-1">{{ marketing_template.prompt1 }}</el-text>
          <el-text class="mx-1" type="danger">返回:</el-text>
          <el-text class="mx-1">{{ marketing_template.result1 }}</el-text>
          <el-text class="mx-1" type="danger">第二次提问:</el-text>
          <el-text class="mx-1">{{ marketing_template.prompt2 }}</el-text>
        </template>
朱国瑞's avatar
朱国瑞 committed
2173
        <el-input v-model="form.chatgpt_answer" :autosize="true" type="textarea" />
周成波's avatar
周成波 committed
2174
      </el-form-item>
2175 2176
      <!-- 角色 -->
      <el-form-item>
2177
        <el-button type="primary" @click="onAdaptRoles">推理角色({{ role_llm.name }})</el-button>
2178 2179 2180
        <el-button type="primary" @click="onAdaptRolesKeywords"
          >推理角色关键词({{ role_keywords_llm.name }})</el-button
        >
2181
        <el-button plain @click="clean_roles">清空总角色列表</el-button>
2182 2183
      </el-form-item>
      <el-form-item label="角色">
2184 2185 2186 2187 2188
        <el-table
          :data="form.chatgpt_answer_roles"
          border
          style="width: 100%; z-index: calc(var(--el-table-index) -1)"
        >
周成波's avatar
周成波 committed
2189
          <el-table-column prop="角色" label="角色" width="300">
2190
            <template v-slot="scope">
2191
              <el-input v-model="scope.row.角色" :autosize="true" type="textarea"></el-input>
2192 2193
            </template>
          </el-table-column>
周成波's avatar
周成波 committed
2194 2195
          <el-table-column prop="属性" label="属性" width="300">
            <template v-slot="scope">
2196
              <el-select v-model="scope.row.属性" filterable allow-create :reserve-keyword="false">
2197 2198 2199 2200 2201 2202
                <el-option
                  v-for="item in default_data.role_attribute_options"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value"
                />
周成波's avatar
周成波 committed
2203 2204 2205
              </el-select>
            </template>
          </el-table-column>
2206 2207
          <el-table-column prop="角色关键词" label="角色关键词">
            <template v-slot="scope">
2208
              <el-input v-model="scope.row.角色关键词" :autosize="true" type="textarea"></el-input>
2209 2210
            </template>
          </el-table-column>
周成波's avatar
周成波 committed
2211
          <el-table-column prop="角色关键词英文" label="角色关键词英文">
周成波's avatar
周成波 committed
2212
            <template v-slot="scope">
2213 2214 2215 2216 2217
              <el-input
                v-model="scope.row.角色关键词英文"
                :autosize="true"
                type="textarea"
              ></el-input>
周成波's avatar
周成波 committed
2218 2219
            </template>
          </el-table-column>
2220 2221
        </el-table>
      </el-form-item>
周成波's avatar
周成波 committed
2222
      <!-- 分镜 -->
Administrator's avatar
Administrator committed
2223
      <el-form-item>
Administrator's avatar
Administrator committed
2224
        <el-button type="primary" @click="onAdapt('default')">分镜:标准模式</el-button>
2225 2226
        <el-button type="success" @click="onAdapt('more_scene')">分镜:丰富场景模式</el-button>
        <el-button type="primary" @click="onAdaptScene">推理场景({{ tuili_llm.name }})</el-button>
2227 2228 2229
        <el-button type="primary" @click="onAdaptSceneRoles"
          >推理场景中的角色({{ tuili_keyword_llm.name }})</el-button
        >
周成波's avatar
周成波 committed
2230 2231
        <el-button type="primary" @click="onDraw">绘图</el-button>
        <el-button plain @click="clean_scenes">清空分镜列表</el-button>
周成波's avatar
周成波 committed
2232
      </el-form-item>
周成波's avatar
周成波 committed
2233
      <el-form-item label="分镜">
2234 2235 2236 2237 2238
        <el-table
          :data="form.adapt_result_json"
          border
          style="width: 100%; z-index: calc(var(--el-table-index) -1)"
        >
周成波's avatar
周成波 committed
2239
          <el-table-column prop="编号" label="编号" width="55" />
周成波's avatar
周成波 committed
2240 2241
          <el-table-column prop="场景描述" label="场景描述">
            <template v-slot="scope">
2242
              <el-input v-model="scope.row.场景描述" :autosize="true" type="textarea"></el-input>
2243
              <el-text class="mx-1" size="small">{{ scope.row.info2 }}</el-text>
周成波's avatar
周成波 committed
2244 2245
            </template>
          </el-table-column>
周成波's avatar
周成波 committed
2246
          <el-table-column prop="场景关键词" label="场景关键词">
周成波's avatar
周成波 committed
2247
            <template v-slot="scope">
周成波's avatar
周成波 committed
2248
              <el-text class="mx-1" size="small">{{ scope.row.场景关键词 }}</el-text>
2249 2250 2251 2252 2253 2254
              <hr style="border: none; border-top: 1px dashed #999; margin: 5px 0" />
              <el-input
                v-model="scope.row.场景关键词英文"
                :autosize="true"
                type="textarea"
              ></el-input>
周成波's avatar
周成波 committed
2255 2256
            </template>
          </el-table-column>
周成波's avatar
周成波 committed
2257
          <el-table-column prop="角色" label="角色">
周成波's avatar
周成波 committed
2258
            <template v-slot="scope">
周成波's avatar
周成波 committed
2259
              <el-text class="mx-1" size="small">{{ scope.row.info }}</el-text>
2260 2261 2262 2263 2264 2265
              <hr style="border: none; border-top: 1px dashed #999; margin: 5px 0" />
              <el-select
                v-model="scope.row.角色"
                placeholder=""
                @change="onItemRolesChange(scope.row)"
              >
2266
                <el-option v-for="item in scope.row.roles" :key="item" :label="item" :value="item">
周成波's avatar
周成波 committed
2267 2268 2269 2270
                  <span style="float: left">{{ item }}</span>
                </el-option>
              </el-select>
              <!-- <el-text class="mx-1" size="small">{{ scope.row.角色 }}<br />{{ scope.row.info }}</el-text> -->
周成波's avatar
周成波 committed
2271 2272 2273 2274
            </template>
          </el-table-column>
          <el-table-column prop="角色关键词" label="角色关键词">
            <template v-slot="scope">
周成波's avatar
周成波 committed
2275
              <el-text class="mx-1" size="small">{{ scope.row.角色关键词 }}</el-text>
2276 2277 2278 2279 2280 2281
              <hr style="border: none; border-top: 1px dashed #999; margin: 5px 0" />
              <el-input
                v-model="scope.row.角色关键词英文"
                :autosize="true"
                type="textarea"
              ></el-input>
周成波's avatar
周成波 committed
2282 2283
            </template>
          </el-table-column>
周成波's avatar
周成波 committed
2284
          <el-table-column prop="本镜配图" label="本镜配图" width="300">
周成波's avatar
周成波 committed
2285 2286
            <template v-slot="scope">
              <div>
2287 2288
                <el-image
                  :src="scope.row.本镜配图"
Administrator's avatar
Administrator committed
2289
                  :zoom-rate="1.0"
2290
                  :max-scale="1.5"
Administrator's avatar
Administrator committed
2291
                  :min-scale="1.5"
2292 2293 2294 2295
                  :preview-src-list="[scope.row.本镜配图]"
                  fit="cover"
                  :hide-on-click-modal="true"
                />
周成波's avatar
周成波 committed
2296 2297 2298
              </div>
            </template>
          </el-table-column>
周成波's avatar
周成波 committed
2299 2300 2301 2302 2303 2304
          <el-table-column width="120" label="操作" align="center">
            <!-- 
            <template v-slot:header>
              <el-button type="danger" size="default" @click="">批量绘制所有图片</el-button>
            </template> 
            -->
周成波's avatar
周成波 committed
2305
            <template v-slot="scope">
2306 2307 2308 2309 2310 2311
              <div style="margin: 5px 0">
                <el-button type="primary" size="small" @click="onAdaptOneScene(scope.row)"
                  >推理场景</el-button
                >
              </div>
              <div style="margin: 5px 0">
2312
                <el-button type="primary" size="small" @click="onAdaptOneSceneRoles(scope.row)"
2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335
                  >推理角色</el-button
                >
              </div>
              <div style="margin: 5px 0">
                <el-button type="primary" size="small" @click="onDrawOne(scope.row)"
                  >绘图</el-button
                >
              </div>
              <el-upload
                ref="upload"
                :show-file-list="false"
                :limit="1"
                accept=".png,.PNG,.jpg,.JPG,.jpeg,.JPEG,.gif,.GIF,.bmp,.BMP"
                :action="actionUrl"
                :on-success="handleUploadSuccess"
                :on-exceed="handleUploadExceed"
                :on-error="handleUploadError"
                :data="{ width: form.img_size.width, height: form.img_size.height }"
                :before-upload="handleBeforeUpload"
              >
                <el-button type="primary" size="small" @click="onClickUpload(scope.row)"
                  >上传图片</el-button
                >
2336
              </el-upload>
Administrator's avatar
Administrator committed
2337
              <!-- <div style="margin: 5px 0">
Administrator's avatar
Administrator committed
2338 2339 2340 2341 2342 2343
                <el-button
                  type="primary"
                  size="small"
                  @click="showInPaintDialog('scene', scope.row)"
                  >局部重绘</el-button
                >
Administrator's avatar
Administrator committed
2344
              </div> -->
周成波's avatar
周成波 committed
2345
              <!-- <div style="margin: 5px 0"><el-button plain size="small" @click="onClearOnePic(scope.row)">清除图片</el-button></div> -->
2346
              <div style="margin: 5px 0">
2347
                <el-button plain size="small" @click="showsdprompt(scope.row)">debug</el-button>
2348 2349
              </div>
              <el-dialog v-model="dialogVisible" width="80%">
2350 2351 2352
                <p>{{ dialogData }}</p>
                <template #footer>
                  <div class="dialog-footer">
2353
                    <el-button type="primary" @click="dialogVisible = false">ok</el-button>
2354 2355 2356
                  </div>
                </template>
              </el-dialog>
2357 2358 2359 2360 2361
              <div style="margin: 10px 0">
                <el-button type="danger" size="small" @click="onDeleteOne(scope.row)"
                  >删除本镜</el-button
                >
              </div>
周成波's avatar
周成波 committed
2362 2363 2364 2365
            </template>
          </el-table-column>
        </el-table>
      </el-form-item>
周成波's avatar
周成波 committed
2366
      <el-form-item label="封面图片">
2367 2368 2369 2370 2371
        <el-switch
          v-model="cover_backcover.if_need_cover_pic"
          active-value="true"
          inactive-value="false"
        />
2372
      </el-form-item>
周成波's avatar
周成波 committed
2373
      <div v-if="JSON.parse(cover_backcover.if_need_cover_pic.toLowerCase())">
周成波's avatar
周成波 committed
2374 2375
        <el-form-item>
          <!-- :style="{ width: String(parseInt(form.img_size.width) / 3)+'px', height: String(parseInt(form.img_size.height) / 3)+'px' }" -->
2376 2377 2378 2379
          <div
            :style="{ width: String(parseInt(form.img_size.width) / 3) + 'px' }"
            class="dashed-div"
          >
周成波's avatar
周成波 committed
2380
            <el-image :src="cover_backcover.cover_pic" />
周成波's avatar
周成波 committed
2381
          </div>
2382 2383 2384 2385 2386
          <div
            :style="{ width: String(parseInt(form.img_size.width) / 3) + 'px' }"
            class="dashed-div"
            style="margin-left: 20px"
          >
周成波's avatar
周成波 committed
2387
            <el-image :src="cover_backcover.cover_pic_with_text" />
周成波's avatar
周成波 committed
2388 2389 2390
          </div>
        </el-form-item>
        <el-form-item>
2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402
          <el-upload
            ref="upload_cover"
            :show-file-list="false"
            :limit="1"
            accept=".png,.PNG,.jpg,.JPG,.jpeg,.JPEG,.gif,.GIF,.bmp,.BMP"
            :action="actionUrl"
            :on-success="MarketingTemplateUploadCoverPicSuccess"
            :on-exceed="handleMarketingTemplateUploadCoverPicExceed"
            :on-error="handleUploadError"
            :data="{ width: form.img_size.width, height: form.img_size.height }"
            :before-upload="handleBeforeUpload"
          >
周成波's avatar
周成波 committed
2403 2404
            <el-button type="primary" size="small">上传图片</el-button>
          </el-upload>
2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418
          <span style="margin-left: 12px">或使用第</span>
          <el-select
            size="small"
            v-model="cover_backcover.cover_pic_use_scene"
            placeholder="选择"
            style="width: 60px"
            @change="onSelectCoverChange"
          >
            <el-option
              v-for="item in form.adapt_result_json"
              :key="item.编号"
              :label="item.编号"
              :value="item.编号"
            >
周成波's avatar
周成波 committed
2419 2420 2421 2422
              <span style="float: left">{{ item.编号 }}</span>
            </el-option>
          </el-select>
          <span>帧做封面</span>
2423
          <el-button
2424
            plain
2425 2426 2427 2428 2429
            size="small"
            @click="onClearMarketingTemplatePic('cover')"
            style="margin-left: 12px"
            >清除图片</el-button
          >
Administrator's avatar
Administrator committed
2430
          <!-- <el-button
Administrator's avatar
Administrator committed
2431 2432 2433 2434 2435
            type="primary"
            size="small"
            @click="showInPaintDialog('cover', '')"
            style="margin-left: 12px"
            >局部重绘</el-button
Administrator's avatar
Administrator committed
2436
          > -->
周成波's avatar
周成波 committed
2437 2438
        </el-form-item>
        <el-form-item>
2439 2440 2441 2442 2443 2444 2445
          <div style="width: 100%">
            <el-button
              type="primary"
              size="small"
              @click="onAddMarketingTemplatePicText('cover', 'add', 0)"
              >增加文字</el-button
            >
周成波's avatar
周成波 committed
2446
            <!-- <el-button type="success" size="small" @click="onMarketingTemplateAddTextToPic('cover')">预览</el-button> -->
周成波's avatar
周成波 committed
2447
          </div>
2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496
          <div
            v-for="(pic_title, index) in cover_backcover.cover_pic_titles"
            :key="index"
            class="dashed-div"
            style="width: 100%"
          >
            <el-input
              v-model="pic_title.text"
              :autosize="true"
              type="textarea"
              @change="onMarketingTemplateAddTextToPic('cover')"
            ></el-input>
            <span style="margin-left: 10px">字体颜色:</span>
            <el-color-picker
              v-model="pic_title.color"
              @change="onMarketingTemplateAddTextToPic('cover')"
            />
            <span style="margin-left: 30px">字体背景:</span>
            <el-color-picker
              v-model="pic_title.bg_color"
              @change="onMarketingTemplateAddTextToPic('cover')"
            />
            <span style="margin-left: 30px">字体大小:</span>
            <el-input-number
              v-model="pic_title.font_size"
              :min="1"
              :max="100"
              controls-position="right"
              @change="onMarketingTemplateAddTextToPic('cover')"
            />
            <span style="margin-left: 30px">在图片上的位置:</span>
            <el-slider
              v-model="pic_title.position"
              :step="0.01"
              :min="0"
              :max="1"
              show-input
              vertical
              height="100px"
              style="margin-top: 10px"
              @change="onMarketingTemplateAddTextToPic('cover')"
            />
            <el-button
              type="danger"
              size="small"
              @click="onAddMarketingTemplatePicText('cover', 'del', index)"
              style="margin-left: 80px"
              >删除文字</el-button
            >
周成波's avatar
周成波 committed
2497
          </div>
周成波's avatar
周成波 committed
2498 2499 2500
        </el-form-item>
      </div>
      <el-form-item label="封底图片">
2501 2502 2503 2504 2505
        <el-switch
          v-model="cover_backcover.if_need_product_pic"
          active-value="true"
          inactive-value="false"
        />
周成波's avatar
周成波 committed
2506
      </el-form-item>
周成波's avatar
周成波 committed
2507
      <div v-if="JSON.parse(cover_backcover.if_need_product_pic.toLowerCase())">
周成波's avatar
周成波 committed
2508 2509
        <el-form-item>
          <!-- :style="{ width: String(parseInt(form.img_size.width) / 3)+'px', height: String(parseInt(form.img_size.height) / 3)+'px' }" -->
2510 2511 2512 2513
          <div
            :style="{ width: String(parseInt(form.img_size.width) / 3) + 'px' }"
            class="dashed-div"
          >
周成波's avatar
周成波 committed
2514
            <el-image :src="cover_backcover.product_pic" />
周成波's avatar
周成波 committed
2515
          </div>
2516 2517 2518 2519 2520
          <div
            :style="{ width: String(parseInt(form.img_size.width) / 3) + 'px' }"
            class="dashed-div"
            style="margin-left: 20px"
          >
周成波's avatar
周成波 committed
2521
            <el-image :src="cover_backcover.product_pic_with_text" />
周成波's avatar
周成波 committed
2522 2523 2524
          </div>
        </el-form-item>
        <el-form-item>
2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536
          <el-upload
            ref="upload_product"
            :show-file-list="false"
            :limit="1"
            accept=".png,.PNG,.jpg,.JPG,.jpeg,.JPEG,.gif,.GIF,.bmp,.BMP"
            :action="actionUrl"
            :on-success="MarketingTemplateUploadProductPicSuccess"
            :on-exceed="handleMarketingTemplateUploadProductPicExceed"
            :on-error="handleUploadError"
            :data="{ width: form.img_size.width, height: form.img_size.height }"
            :before-upload="handleBeforeUpload"
          >
周成波's avatar
周成波 committed
2537 2538
            <el-button type="primary" size="small">上传图片</el-button>
          </el-upload>
2539
          <el-button
2540
            plain
2541 2542 2543 2544 2545
            size="small"
            @click="onClearMarketingTemplatePic('product')"
            style="margin-left: 12px"
            >清除图片</el-button
          >
Administrator's avatar
Administrator committed
2546
          <!-- <el-button
Administrator's avatar
Administrator committed
2547 2548 2549 2550 2551
            type="primary"
            size="small"
            @click="showInPaintDialog('product', '')"
            style="margin-left: 12px"
            >局部重绘</el-button
Administrator's avatar
Administrator committed
2552
          > -->
周成波's avatar
周成波 committed
2553 2554
        </el-form-item>
        <el-form-item>
2555 2556 2557 2558 2559 2560 2561
          <div style="width: 100%">
            <el-button
              type="primary"
              size="small"
              @click="onAddMarketingTemplatePicText('product', 'add', 0)"
              >增加文字</el-button
            >
周成波's avatar
周成波 committed
2562
            <!-- <el-button type="success" size="small" @click="onMarketingTemplateAddTextToPic('product')">预览</el-button> -->
周成波's avatar
周成波 committed
2563
          </div>
2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612
          <div
            v-for="(pic_title, index) in cover_backcover.product_pic_titles"
            :key="index"
            class="dashed-div"
            style="width: 100%"
          >
            <el-input
              v-model="pic_title.text"
              :autosize="true"
              type="textarea"
              @change="onMarketingTemplateAddTextToPic('product')"
            ></el-input>
            <span style="margin-left: 10px">字体颜色:</span>
            <el-color-picker
              v-model="pic_title.color"
              @change="onMarketingTemplateAddTextToPic('product')"
            />
            <span style="margin-left: 30px">字体背景:</span>
            <el-color-picker
              v-model="pic_title.bg_color"
              @change="onMarketingTemplateAddTextToPic('product')"
            />
            <span style="margin-left: 30px">字体大小:</span>
            <el-input-number
              v-model="pic_title.font_size"
              :min="1"
              :max="100"
              controls-position="right"
              @change="onMarketingTemplateAddTextToPic('product')"
            />
            <span style="margin-left: 30px">在图片上的位置:</span>
            <el-slider
              v-model="pic_title.position"
              :step="0.01"
              :min="0"
              :max="1"
              show-input
              vertical
              height="100px"
              style="margin-top: 10px"
              @change="onMarketingTemplateAddTextToPic('product')"
            />
            <el-button
              type="danger"
              size="small"
              @click="onAddMarketingTemplatePicText('product', 'del', index)"
              style="margin-left: 80px"
              >删除文字</el-button
            >
周成波's avatar
周成波 committed
2613
          </div>
周成波's avatar
周成波 committed
2614 2615
        </el-form-item>
        <el-form-item label="封底旁白">
2616 2617 2618 2619 2620
          <el-input
            v-model="cover_backcover.product_pic_speech"
            :autosize="true"
            type="textarea"
          ></el-input>
周成波's avatar
周成波 committed
2621 2622
        </el-form-item>
      </div>
周成波's avatar
周成波 committed
2623
      <!-- 生成视频 -->
周成波's avatar
周成波 committed
2624 2625
      <el-form-item label="视频设置">
        <span style="margin: 0 20px 0 0">TTS语速:</span>
2626 2627 2628 2629 2630 2631 2632 2633
        <el-slider
          v-model="voice_rate"
          show-input
          :min="-50"
          :max="50"
          :marks="default_data.marks"
          style="width: 900px"
        />
周成波's avatar
周成波 committed
2634 2635
      </el-form-item>
      <el-form-item>
周成波's avatar
周成波 committed
2636
        <span style="margin: 0 20px 0 0">TTS音量:</span>
2637 2638 2639 2640 2641 2642 2643 2644
        <el-slider
          v-model="voice_volume"
          show-input
          :min="-80"
          :max="80"
          :marks="default_data.marks"
          style="width: 900px"
        />
周成波's avatar
周成波 committed
2645 2646
      </el-form-item>
      <el-form-item>
周成波's avatar
周成波 committed
2647
        <span style="margin: 20px 20px 0 0">TTS语音:</span>
2648
        <el-select v-model="voice" placeholder="Select" style="width: 400px; margin-top: 20px">
2649 2650 2651 2652 2653 2654
          <el-option
            v-for="item in default_data.voices"
            :key="item.value"
            :label="item.value"
            :value="item.value"
          >
周成波's avatar
周成波 committed
2655
            <span style="float: left">{{ item.value }}</span>
2656 2657 2658
            <span style="float: right; color: var(--el-text-color-secondary); font-size: 13px">{{
              item.label
            }}</span>
周成波's avatar
周成波 committed
2659 2660
          </el-option>
        </el-select>
2661 2662 2663 2664 2665
        <audio
          :src="'src/assets/edge-tts-voices/' + voice + '.mp3'"
          controls
          style="height: 30px; margin: 20px 0 0 10px"
        ></audio>
周成波's avatar
周成波 committed
2666 2667
      </el-form-item>
      <el-form-item>
周成波's avatar
周成波 committed
2668
        <span style="margin: 0 20px 0 0">背景音乐:</span>
2669 2670 2671 2672 2673 2674 2675
        <el-select v-model="bgm" placeholder="无" style="width: 400px">
          <el-option
            v-for="item in default_data.bgm"
            :key="item.value"
            :label="item.value"
            :value="item.value"
          >
周成波's avatar
周成波 committed
2676
            <span style="float: left">{{ item.label }}</span>
2677 2678 2679
            <span style="float: right; color: var(--el-text-color-secondary); font-size: 13px">{{
              item.value
            }}</span>
周成波's avatar
周成波 committed
2680 2681
          </el-option>
        </el-select>
2682 2683 2684 2685 2686
        <audio
          :src="'src/assets/bgm/' + bgm + '.mp3'"
          controls
          style="height: 30px; margin-left: 10px"
        ></audio>
周成波's avatar
周成波 committed
2687
      </el-form-item>
2688
      <el-form-item>
周成波's avatar
周成波 committed
2689
        <span style="margin: 0 20px 0 0">背景音量:</span>
2690 2691 2692 2693 2694 2695 2696 2697 2698
        <el-slider
          v-model="bgm_volume"
          show-input
          :step="0.1"
          :min="0"
          :max="2"
          :marks="default_data.bgm_volume_marks"
          style="width: 600px"
        />
2699 2700
      </el-form-item>
      <el-form-item>
周成波's avatar
周成波 committed
2701
        <span style="margin: 20px 20px 20px 0">字幕合成:</span>
2702
        <el-switch v-model="form.if_need_subtitle" active-value="true" inactive-value="false" />
周成波's avatar
周成波 committed
2703
        <div v-if="JSON.parse(form.if_need_subtitle.toLowerCase())">
2704
          <span style="margin-left: 30px">字体颜色:</span>
周成波's avatar
周成波 committed
2705
          <el-color-picker v-model="sub_font_color" />
2706
          <span style="margin-left: 30px">字体背景:</span>
周成波's avatar
周成波 committed
2707
          <el-color-picker v-model="sub_bg_color" />
2708
          <span style="margin-left: 30px">字体大小:</span>
2709
          <el-input-number v-model="sub_font_size" :min="1" :max="50" controls-position="right" />
2710 2711 2712 2713 2714 2715 2716 2717 2718 2719
          <span style="margin-left: 30px">在屏幕上的位置:</span>
          <el-slider
            v-model="sub_position"
            :step="0.1"
            :min="0"
            :max="1"
            show-input
            vertical
            height="100px"
          />
周成波's avatar
周成波 committed
2720
        </div>
2721
      </el-form-item>
周成波's avatar
周成波 committed
2722
      <el-form-item>
周成波's avatar
周成波 committed
2723
        <el-button type="primary" @click="onGenVideo">生成视频</el-button>
周成波's avatar
周成波 committed
2724
      </el-form-item>
周成波's avatar
周成波 committed
2725 2726 2727
      <el-form-item>
        <video :src="form.final_video" controls></video>
      </el-form-item>
Administrator's avatar
Administrator committed
2728
    </el-form>
Administrator's avatar
Administrator committed
2729

2730
    <!-- 授权密码框 -->
2731 2732 2733 2734 2735 2736 2737 2738
    <el-dialog
      v-model="pwdCheckDialogVisible"
      title="请输入密码"
      width="20%"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      :show-close="false"
    >
2739 2740
      <el-form :model="form">
        <el-form-item label="密码">
2741 2742 2743 2744 2745 2746 2747
          <el-input
            v-model="pwdCheckValue"
            autocomplete="off"
            type="password"
            show-password
            @keyup.enter="onPwdCheckDialog()"
          />
2748 2749
        </el-form-item>
      </el-form>
周成波's avatar
周成波 committed
2750

2751 2752 2753 2754 2755 2756
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="onPwdCheckDialog()">ok</el-button>
        </div>
      </template>
    </el-dialog>
周成波's avatar
周成波 committed
2757 2758

    <!-- 营销模板 -->
2759 2760 2761 2762 2763 2764 2765 2766 2767 2768
    <el-dialog
      v-model="marketingTemplateVisible"
      title="营销模板"
      width="60%"
      height="500"
      :close-on-click-modal="false"
      :close-on-press-escape="true"
      :show-close="true"
      :lock-scroll="true"
    >
周成波's avatar
周成波 committed
2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779
      <!-- 
      <el-tabs v-model="activeTab">
        <el-tab-pane label="商品" name="first">User</el-tab-pane>
        <el-tab-pane label="Config" name="second">Config</el-tab-pane>
        <el-tab-pane label="Role" name="third">Role</el-tab-pane>
        <el-tab-pane label="Task" name="fourth">Task</el-tab-pane>
      </el-tabs>
      <el-button @click="goToNextPage">下一步</el-button>
      -->
      <el-form :model="marketing_template">
        <el-form-item label="商品名称">
2780 2781 2782 2783 2784
          <el-input
            v-model="marketing_template.product_name"
            :autosize="true"
            type="textarea"
          ></el-input>
周成波's avatar
周成波 committed
2785 2786
        </el-form-item>
        <el-form-item label="商品描述">
2787 2788 2789 2790 2791
          <el-input
            v-model="marketing_template.product_description"
            :autosize="true"
            type="textarea"
          ></el-input>
周成波's avatar
周成波 committed
2792 2793
        </el-form-item>
        <el-form-item label="目标群体">
2794 2795 2796 2797 2798
          <el-input
            v-model="marketing_template.target_people"
            :autosize="true"
            type="textarea"
          ></el-input>
周成波's avatar
周成波 committed
2799 2800
        </el-form-item>
        <el-form-item label="文案主角">
2801 2802 2803 2804 2805
          <el-input
            v-model="marketing_template.text_role"
            :autosize="true"
            type="textarea"
          ></el-input>
周成波's avatar
周成波 committed
2806 2807
        </el-form-item>
        <el-form-item label="文案风格">
2808 2809 2810 2811 2812
          <el-input
            v-model="marketing_template.text_style"
            :autosize="true"
            type="textarea"
          ></el-input>
周成波's avatar
周成波 committed
2813 2814
        </el-form-item>
        <el-form-item label="故事类型">
2815 2816 2817 2818 2819
          <el-input
            v-model="marketing_template.story_type"
            :autosize="true"
            type="textarea"
          ></el-input>
周成波's avatar
周成波 committed
2820 2821
        </el-form-item>
        <el-form-item label="参考信息">
2822 2823 2824 2825 2826
          <el-input
            v-model="marketing_template.reference"
            :autosize="true"
            type="textarea"
          ></el-input>
周成波's avatar
周成波 committed
2827 2828
        </el-form-item>
        <el-form-item label="文案字数">
2829 2830 2831 2832 2833 2834
          <el-input-number
            v-model="marketing_template.words_num"
            :min="100"
            :max="500"
            controls-position="right"
          />
周成波's avatar
周成波 committed
2835 2836 2837 2838 2839
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="marketingTemplateVisible = false">取消</el-button>
2840
          <el-button type="primary" @click="onMarketingTemplateSubmitGpt()">提交</el-button>
周成波's avatar
周成波 committed
2841 2842 2843
        </div>
      </template>
    </el-dialog>
Administrator's avatar
Administrator committed
2844 2845 2846 2847

    <!-- 局部重绘 -->
    <el-dialog
      v-model="inPaintVisible"
Administrator's avatar
Administrator committed
2848
      :width="parseInt(form.img_size.width) + 40"
Administrator's avatar
Administrator committed
2849 2850 2851 2852
      :close-on-click-modal="false"
      :close-on-press-escape="true"
      :lock-scroll="true"
    >
Administrator's avatar
Administrator committed
2853
      <div style="color: red">请在图片上涂抹需要保留的部分</div>
Administrator's avatar
Administrator committed
2854 2855 2856 2857 2858 2859 2860
      <div
        ref="inpaint"
        :style="
          'position: relative; width: ' +
          form.img_size.width +
          'px; height: ' +
          form.img_size.height +
Administrator's avatar
Administrator committed
2861
          'px; margin: 10px auto;'
Administrator's avatar
Administrator committed
2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888
        "
      >
        <canvas
          id="baseCanvas"
          :width="form.img_size.width"
          :height="form.img_size.height"
          style="position: absolute; left: 0; top: 0"
        ></canvas>
        <canvas
          id="maskCanvas"
          :width="form.img_size.width"
          :height="form.img_size.height"
          style="position: absolute; left: 0; top: 0; z-index: 1; background: none"
        ></canvas>
      </div>
      <button id="clearButton">清除涂抹</button>
      <div>
        <span>画面描述:</span>
        <el-input v-model="inPaintPrompt" :autosize="true" type="textarea"></el-input>
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="inPaintVisible = false">取消</el-button>
          <el-button type="primary" @click="onSubmitInPaint">提交</el-button>
        </div>
      </template>
    </el-dialog>
2889 2890 2891 2892 2893 2894 2895 2896 2897

    <!-- 自定义产品图局部重绘 -->
    <el-dialog
      v-model="update_and_modify_product.inPaintVisible"
      :width="parseInt(form.img_size.width) + 40"
      :close-on-click-modal="false"
      :close-on-press-escape="true"
      :lock-scroll="true"
    >
2898 2899 2900 2901 2902
      <div style="color: red">
        先在图片上点击产品部分 ==> 点击智能抠图,预览效果 ==> 如效果不理想,则勾选此项
        <input type="checkbox" id="update_and_modify_product_noObjCheckbox" />
        ,再点击非产品部分,抠图,直到满意。
      </div>
2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925
      <div
        ref="update_and_modify_product_inpaint"
        :style="
          'position: relative; width: ' +
          form.img_size.width +
          'px; height: ' +
          form.img_size.height +
          'px; margin: 10px auto;'
        "
      >
        <canvas
          id="update_and_modify_product_baseCanvas"
          :width="form.img_size.width"
          :height="form.img_size.height"
          style="position: absolute; left: 0; top: 0; z-index: 1; background: none"
        ></canvas>
        <canvas
          id="update_and_modify_product_previewCanvas"
          :width="form.img_size.width"
          :height="form.img_size.height"
          style="position: absolute; left: 0; top: 0; z-index: 2; background: none"
        ></canvas>
        <canvas
2926
          id="update_and_modify_product_maskCanvas2"
2927 2928 2929 2930
          :width="form.img_size.width"
          :height="form.img_size.height"
          style="position: absolute; left: 0; top: 0; z-index: 3; background: none"
        ></canvas>
2931 2932
        <canvas
          id="update_and_modify_product_maskCanvas"
2933 2934 2935
          :width="form.img_size.width"
          :height="form.img_size.height"
          style="position: absolute; left: 0; top: 0; z-index: 4; background: none"
2936
        ></canvas>
2937
      </div>
2938
      <button id="update_and_modify_product_clearButton">重置</button>
2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949
      <el-button @click="onSubmitUploadAndModifyProductPicCutOut">智能抠图</el-button>
      <div>
        <span>画面描述:</span>
        <el-input
          v-model="update_and_modify_product.inPaintPrompt"
          :autosize="true"
          type="textarea"
        ></el-input>
      </div>
      <template #footer>
        <div class="dialog-footer">
2950
          <el-button @click="update_and_modify_product.inPaintVisible = false">取消</el-button>
2951 2952 2953 2954 2955 2956
          <el-button type="primary" @click="onSubmitUploadAndModifyProductPicInPaint"
            >重绘</el-button
          >
        </div>
      </template>
    </el-dialog>
Administrator's avatar
Administrator committed
2957 2958
  </main>
</template>
Administrator's avatar
Administrator committed
2959

Administrator's avatar
Administrator committed
2960
<style lang="scss" scoped>
朱国瑞's avatar
朱国瑞 committed
2961 2962 2963 2964 2965 2966 2967 2968 2969
.home-container {
  width: 100%;
}
</style>

<style lang="scss">
.home-container {
  .el-table .el-table__cell {
    z-index: calc(var(--el-table-index) -1);
周成波's avatar
周成波 committed
2970
  }
朱国瑞's avatar
朱国瑞 committed
2971
}
周成波's avatar
周成波 committed
2972 2973 2974 2975 2976
.dashed-div {
  border: 1px dashed #999;
  margin: 5px 0;
  padding: 2px;
}
Administrator's avatar
Administrator committed
2977
</style>