Commit 5409f5a0 authored by Administrator's avatar Administrator

基本完成

parent 2c8d4c77
......@@ -6,4 +6,3 @@ outputs
tests
**/checkpoints
/app/ai_gen_image/images
\ No newline at end of file
FROM harbor.5jstore.com:8020/ai/wm_generate_ai:v0.2
FROM harbor.5jstore.com:8020/ai/wm_video_cut:v0.2
LABEL maintainer="zhouchengbo@wmdigit.com"
ARG DEBIAN_FRONTEND=noninteractive
......
FROM harbor.5jstore.com:8020/ai/wm_generate_ai:v0.1
FROM harbor.5jstore.com:8020/ai/wm_video_cut:v0.1
LABEL maintainer="zhouchengbo@wmdigit.com"
ARG DEBIAN_FRONTEND=noninteractive
......
# AI Generate
# 视频自动翻译剪辑
# 生成基础镜像,将所有依赖都放到基础镜像中
<!-- v0 -->
docker rmi harbor.5jstore.com:8020/ai/wm_generate_ai:v0
docker build -f Dockerfile_v0 -t harbor.5jstore.com:8020/ai/wm_generate_ai:v0 .
docker rmi harbor.5jstore.com:8020/ai/wm_video_cut:v0
docker build -f Dockerfile_v0 -t harbor.5jstore.com:8020/ai/wm_video_cut:v0 .
<!-- 0.1 根据v0手工生成,主要安装完整版的 cuda -->
docker rmi harbor.5jstore.com:8020/ai/wm_generate_ai:v0.1
docker run --gpus all --runtime=nvidia -it harbor.5jstore.com:8020/ai/wm_generate_ai:v0 /bin/bash
docker rmi harbor.5jstore.com:8020/ai/wm_video_cut:v0.1
docker run --gpus all --runtime=nvidia -it harbor.5jstore.com:8020/ai/wm_video_cut:v0 /bin/bash
wget https://developer.download.nvidia.com/compute/cuda/11.3.0/local_installers/cuda_11.3.0_465.19.01_linux.run
sh cuda_11.3.0_465.19.01_linux.run
1、不选驱动
......@@ -21,16 +20,16 @@ export CUDA_HOME=/usr/local/cuda-11.3
删除下载文件
rm cuda_11.3.0_465.19.01_linux.run
提交新镜像
docker commit c9c2a347491d harbor.5jstore.com:8020/ai/wm_generate_ai:v0.1
docker commit c9c2a347491d harbor.5jstore.com:8020/ai/wm_video_cut:v0.1
<!-- end -->
<!-- 0.2 在0.1基础上安装项目依赖 -->
docker rmi harbor.5jstore.com:8020/ai/wm_generate_ai:v0.2
docker build -f Dockerfile_v0.2 -t harbor.5jstore.com:8020/ai/wm_generate_ai:v0.2 .
docker rmi harbor.5jstore.com:8020/ai/wm_video_cut:v0.2
docker build -f Dockerfile_v0.2 -t harbor.5jstore.com:8020/ai/wm_video_cut:v0.2 .
# 生成主镜像
docker rmi harbor.5jstore.com:8020/ai/wm_generate_ai:v2
docker build -f Dockerfile -t harbor.5jstore.com:8020/ai/wm_generate_ai:v2 .
docker rmi harbor.5jstore.com:8020/ai/wm_video_cut:v2
docker build -f Dockerfile -t harbor.5jstore.com:8020/ai/wm_video_cut:v2 .
docker-compose up -d
......@@ -42,9 +41,9 @@ docker-compose up -d
<!-- 调试docker镜像,去掉Dockerfile里最后一句启动命令 -->
docker run -it harbor.5jstore.com:8020/ai/wm_generate_ai:v0 /bin/bash
docker run -it harbor.5jstore.com:8020/ai/wm_generate_ai:v1 /bin/bash
docker run -it harbor.5jstore.com:8020/ai/wm_generate_ai:v2 /bin/bash
docker run -it harbor.5jstore.com:8020/ai/wm_video_cut:v0 /bin/bash
docker run -it harbor.5jstore.com:8020/ai/wm_video_cut:v1 /bin/bash
docker run -it harbor.5jstore.com:8020/ai/wm_video_cut:v2 /bin/bash
docker run --gpus all --runtime=nvidia -v ./inputs/:/app/inputs/ -v ./outputs/:/app/outputs/ -it harbor.5jstore.com:8020/common/ai_generate_video:proc_v4 /bin/bash
......@@ -52,4 +51,6 @@ ffmpeg -hwaccels
<!-- 调试命令 -->
python start.py
gunicorn start:app -c ./gunicorn.conf.py
\ No newline at end of file
gunicorn start:app -c ./gunicorn.conf.py
flask --app start run --debug
\ No newline at end of file
......@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
import requests
from werkzeug.utils import secure_filename
from urllib import parse
import oss2
import datetime, os
......@@ -134,3 +135,23 @@ def get_wm_option(wm_key):
return ""
else:
return wm_option.option_value
def upload_file(file):
upload_dir = f'./inputs/{datetime.datetime.now().strftime("%Y%m%d%H%M%S")}'
if not os.path.exists(upload_dir):
os.makedirs(upload_dir)
def allowed_file(filename):
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif', 'mp4'}
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
filepath = os.path.join(upload_dir, filename)
file.save(filepath)
return filepath
else:
return ''
......@@ -412,10 +412,12 @@ def text_to_audio_by_edge_tts(text, local_voice_file, lang, retry=1):
def get_mp3_duration(file_path):
from mutagen.mp3 import MP3
audio = MP3(file_path)
duration_in_seconds = audio.info.length
return duration_in_seconds
try:
audio = MP3(file_path)
duration_in_seconds = audio.info.length
return duration_in_seconds
except:
return 0
def delete_files(current_dir, prefix):
......
......@@ -50,6 +50,7 @@ class WhisperModel(AbstractWhisperModel):
"tiny", "base", "small", "medium", "large", "large-v2"
] = "small",
device: Union[Literal["cpu", "cuda"], None] = None,
env = "dev",
):
self.device = device
......
......@@ -132,4 +132,5 @@ class Cutter:
# utils.delete_files(os.path.dirname(fns['media']), f"._{os.path.splitext(os.path.basename(fns['media']))[0]}")
# utils.delete_files(os.path.dirname(fns['media']), f".DS_Store")
# utils.delete_files(os.path.dirname(fns['media']), f"._.DS_Store")
utils.delete_files(os.path.dirname(fns['media']), f".")
\ No newline at end of file
utils.delete_files(os.path.dirname(fns['media']), f".")
return output_fn
\ No newline at end of file
......@@ -54,16 +54,15 @@ class Transcribe:
logging.info(f"Transcribed {input} to {output}")
self._save_md(name + ".md", output, input, bool(self.args.wmdigit))
logging.info(f'Saved texts to {name + ".md"} to mark sentences')
except:
if retry == 10:
raise RuntimeError(f"Failed to Transcribing {input}")
except Exception as e:
if retry == 3:
raise RuntimeError(f"Failed to Transcribing {e}")
else:
time.sleep(1)
logging.info(f"Retry {retry} to Transcribing {input}")
retry += 1
self.run(retry)
def _detect_voice_activity(self, audio) -> List[SPEECH_ARRAY_INDEX]:
"""Detect segments that have voice activities"""
if self.args.vad == "0":
......
import argparse
import logging
import os
from app.video_cut.autocut import utils
from app.video_cut.autocut.type import WhisperMode, WhisperModel
def main_args(logger):
logger.info('load augument')
parser = argparse.ArgumentParser()
parser.add_argument("--inputs", type=str, help="Inputs filenames/folders")
parser.add_argument(
"--lang",
type=str,
default="zh",
choices=[
"zh",
"en",
"Afrikaans",
"Arabic",
"Armenian",
"Azerbaijani",
"Belarusian",
"Bosnian",
"Bulgarian",
"Catalan",
"Croatian",
"Czech",
"Danish",
"Dutch",
"Estonian",
"Finnish",
"French",
"Galician",
"German",
"Greek",
"Hebrew",
"Hindi",
"Hungarian",
"Icelandic",
"Indonesian",
"Italian",
"Japanese",
"Kannada",
"Kazakh",
"Korean",
"Latvian",
"Lithuanian",
"Macedonian",
"Malay",
"Marathi",
"Maori",
"Nepali",
"Norwegian",
"Persian",
"Polish",
"Portuguese",
"Romanian",
"Russian",
"Serbian",
"Slovak",
"Slovenian",
"Spanish",
"Swahili",
"Swedish",
"Tagalog",
"Tamil",
"Thai",
"Turkish",
"Ukrainian",
"Urdu",
"Vietnamese",
"Welsh",
],
help="The output language of transcription",
)
parser.add_argument(
"--prompt", type=str, default="", help="initial prompt feed into whisper"
)
parser.add_argument(
"--whisper-mode",
type=str,
default=WhisperMode.WHISPER.value,
choices=WhisperMode.get_values(),
help="Whisper inference mode: whisper: run whisper locally; openai: use openai api.",
)
parser.add_argument(
"--openai-rpm",
type=int,
default=3,
choices=[3, 50],
help="Openai Whisper API REQUESTS PER MINUTE(FREE USERS: 3RPM; PAID USERS: 50RPM). "
"More info: https://platform.openai.com/docs/guides/rate-limits/overview",
)
parser.add_argument(
"--whisper-model",
type=str,
default=WhisperModel.SMALL.value,
choices=WhisperModel.get_values(),
help="The whisper model used to transcribe.",
)
parser.add_argument(
"--bitrate",
type=str,
default="10m",
help="The bitrate to export the cutted video, such as 10m, 1m, or 500k",
)
parser.add_argument(
"--vad", help="If or not use VAD", choices=["1", "0", "auto"], default="0"
)
parser.add_argument(
"--force",
help="Force write even if files exist",
action=argparse.BooleanOptionalAction,
)
parser.add_argument(
"--encoding", type=str, default="utf-8", help="Document encoding format"
)
parser.add_argument(
"--device",
type=str,
default=None,
choices=["cpu", "cuda"],
help="Force to CPU or GPU for transcribing. In default automatically use GPU if available.",
)
parser.add_argument(
"--wmdigit",
help="Convert video to different language",
action=argparse.BooleanOptionalAction,
)
args = parser.parse_args(args=[])
args.wmdigit = True
args.force = True
args.vad = "0"
return args
\ No newline at end of file
from flask import abort, request, jsonify
import datetime, os, time
from app.video_cut.autocut import wmdigit_cut, wmdigit_transcribe, utils
def error(msg):
abort(jsonify({"error": msg}))
# 校验请求参数
def validate_request():
if not request.json or 'instances' not in request.json:
error("参数错误: 缺少instances参数")
instance = request.json['instances']
if len(instance) <= 0 or 'video' not in instance[0] or 'lang' not in instance[0]:
error('参数错误: instances缺少:video,lang')
video = instance[0]['video']
lang = instance[0]['lang']
if len(video) <= 0:
error('参数错误: video 参数不可为空')
if len(lang) <= 0:
error('参数错误: lang 参数不可为空')
# if not video.startswith('http'):
# error('video 必须是网络路径')
return video, lang
# 主线
def video_cut_pipeline(logger, args):
# print(args)
time_record = []
media_file, lang = validate_request()
all_start_time = time.time()
# 1、视频生成srt和md
start_time = time.time()
srt_fn = utils.change_ext(media_file, "srt")
md_fn = utils.change_ext(media_file, "md")
# 如果目标语言不是中文,则提示whisper翻译全部字幕
if lang != "zh":
prompt = f"Subtitles must be fully translated into {lang}"
else:
prompt = ""
logger.info(f"Transcribe {media_file} lang={lang} promt={prompt}")
args.inputs = [media_file]
args.lang = lang
wmdigit_transcribe.Transcribe(args).run()
time_record.append(f"视频生成srt和md。耗时: {time.time() - start_time:.4f} 秒")
# 2、从字幕生成cut视频
start_time = time.time()
args.inputs = [media_file, md_fn, srt_fn]
final_video_fn = wmdigit_cut.Cutter(args).run()
time_record.append(f"从字幕生成cut视频。耗时: {time.time() - start_time:.4f} 秒")
time_record.append(f"所有步骤处理完毕。耗时: {time.time() - all_start_time:.4f} 秒")
for i in time_record:
print(i)
return final_video_fn, srt_fn
version: '3'
services:
pytorch:
image: "harbor.5jstore.com:8020/ai/wm_generate_ai:v1"
image: "harbor.5jstore.com:8020/ai/wm_video_cut:v1"
restart: always
runtime: nvidia
environment:
......
version: '3'
services:
pytorch:
image: "harbor.5jstore.com:8020/ai/wm_generate_ai:v2"
image: "harbor.5jstore.com:8020/ai/wm_video_cut:v2"
restart: always
runtime: nvidia
environment:
......
......@@ -2,8 +2,4 @@ workers = 1 # 定义同时开启的处理请求的进程数量,根据网站
worker_class = "gevent" # 采用gevent库,支持异步处理请求,提高吞吐量
timeout = 600
bind = "0.0.0.0:5000"
accesslog = '-'
errorlog = '-'
loglevel = 'debug'
\ No newline at end of file
bind = "0.0.0.0:8080"
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from flask import Flask, abort, request, jsonify
from flask import Flask, abort, request, jsonify, send_file
import datetime, os, sys, time
import logging
from app.utils import util
from app.models.wm_option import db
from app.video_cut.load_args import main_args
from app.video_cut.main import video_cut_pipeline
logging.basicConfig(level = logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
......@@ -24,12 +26,37 @@ input_root = os.path.join(root, 'inputs')
output_root = os.path.join(root, 'outputs')
# 预加载模型
args = main_args(logger)
# 对外接口
@app.route('/ai_generate_video', methods=['GET'])
def ai_generate_video():
return jsonify({"result": "akakkakaka"})
@app.route('/wm_video_cut', methods=['POST'])
def wm_video_cut():
final_video_url, srt_url = video_cut_pipeline(logger, args)
return jsonify({"result": {"final_video_url": final_video_url, "srt_url": srt_url}})
@app.route('/upload_file', methods=['POST'])
def upload_file():
# check if the post request has the file part
if 'file' not in request.files:
return 'No file part', 403
file = request.files['file']
if file.filename == '':
return 'No selected file', 403
file_url = util.upload_file(file)
if not file_url:
return '上传文件失败', 500
else:
return jsonify({"result": {"file_url": file_url}})
@app.route('/download/<path:file_path>')
def download_file(file_path):
if not file_path.startswith('input'):
return '文件不存在', 404
# 发送文件给浏览器进行下载
return send_file(file_path, as_attachment=True)
if __name__ == "__main__":
# 将host设置为0.0.0.0,则外网用户也可以访问到这个服务
app.run(debug=True, host="0.0.0.0", use_reloader=False)
app.run()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment