【SadTalker】源码部署&搭建HTTP服务

环境搭建

git clone https://github.com/OpenTalker/SadTalker.git
cd SadTalker
conda create -n sadtalker python=3.8
conda activate sadtalker
# GPU版本
pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 torchaudio==0.12.1 --extra-index-url https://download.pytorch.org/whl/cu113
# CPU版本(https://pytorch.org/get-started/previous-versions/)
# pip install torch==1.12.1+cpu torchvision==0.13.1+cpu torchaudio==0.12.1 --extra-index-url https://download.pytorch.org/whl/cpu
conda install ffmpeg
# 如果报错,加上--use-pep517
pip install -r requirements.txt --use-pep517 -i https://pypi.douban.com/simple
### Coqui TTS is optional for gradio demo. 
### pip install TTS

安装其它缺少的依赖

pip install chardet

下载模型

bash scripts/download_models.sh
  • 预训练模型会下载到checkpoints目录下
  • GFP-GAN人脸复原模型会下载到gfpgan/weights目录下

WebUI demo

sh webui.sh

# webui.sh运行出错,也可以分解成如下命令运行
python3 -m venv venv
source ./venv/Scripts/activate
pip install Cython
python3 launcher.py

命令行测试

# 使用默认参数运行
python inference.py --driven_audio examples/driven_audio/chinese_poem1.wav \
                    --source_image examples/source_image/full4.jpeg \
                    --enhancer gfpgan 

# 最佳实践                 
python inference.py --driven_audio examples/driven_audio/chinese_poem1.wav \
                    --source_image examples/source_image/art_6.png \
                    --result_dir ./results \
                    --still \
                    --expression_scale 1 \
                    --preprocess full \
                    --enhancer gfpgan 

如果使用CPU运行,则加上--cpu参数

部署过程问题解决

AttributeError: module ‘numpy’ has no attribute ‘float’.

解决方案: 修改numpy版本,安装numpy 1.24之前的版本

pip uninstall numpy
pip install numpy==1.23.5

搭建http服务

修改inference2.py

复制inference.pyinference2.py,在def main(args):函数最后一行增加

return os.path.abspath(save_dir+'.mp4')

编写sadtalker_http.py

提供HTTP接口,就能方便被其它系统调用了,编写一个python脚本

from argparse import ArgumentParser

import torch
import uvicorn
from fastapi import FastAPI, APIRouter
# http请求和响应参数需要继承BaseModel
from pydantic import BaseModel

import inference2

context_path = "/sadtalker"
# 指定API前缀
router = APIRouter(prefix=context_path)


class MakeVideoRequest(BaseModel):
    source_image: str="full_body_1.png"
    driven_audio: str="./examples/driven_audio/bus_chinese.wav"
    # 相对./results的子目录,最终会在这个目录下生成.mp4视频文件
    result_dir: str=""
    still: bool=True
    expression_scale: float=1.
    preprocess: str="full"
    enhancer: str="gfpgan"
    cpu: bool=False
    verbose: bool=False


class MakeVideoResponse(BaseModel):
    video_path: str

    def __init__(self, video_path) -> None:
        super().__init__(video_path=video_path)
        self.video_path = video_path


# 绑定路由和视图函数
@router.post("/video/make", response_model=MakeVideoResponse)
async def makeVideo(request:MakeVideoRequest):
    parser = ArgumentParser()
    parser.add_argument("--driven_audio", default=request.driven_audio, help="path to driven audio")
    parser.add_argument("--source_image", default="./examples/source_image/"+request.source_image, help="path to source image")
    parser.add_argument("--ref_eyeblink", default=None, help="path to reference video providing eye blinking")
    parser.add_argument("--ref_pose", default=None, help="path to reference video providing pose")
    parser.add_argument("--checkpoint_dir", default='./checkpoints', help="path to output")
    parser.add_argument("--result_dir", default="./results"+request.result_dir, help="path to output")
    parser.add_argument("--pose_style", type=int, default=0,  help="input pose style from [0, 46)")
    parser.add_argument("--batch_size", type=int, default=2,  help="the batch size of facerender")
    parser.add_argument("--size", type=int, default=256,  help="the image size of the facerender")
    parser.add_argument("--expression_scale", type=float, default=request.expression_scale,  help="the batch size of facerender")
    parser.add_argument('--input_yaw', nargs='+', type=int, default=None, help="the input yaw degree of the user ")
    parser.add_argument('--input_pitch', nargs='+', type=int, default=None, help="the input pitch degree of the user")
    parser.add_argument('--input_roll', nargs='+', type=int, default=None, help="the input roll degree of the user")
    parser.add_argument('--enhancer',  type=str, default=request.enhancer, help="Face enhancer, [gfpgan, RestoreFormer]")
    parser.add_argument('--background_enhancer',  type=str, default=None, help="background enhancer, [realesrgan]")
    parser.add_argument("--cpu", dest="cpu", default=request.cpu, action="store_true")
    parser.add_argument("--face3dvis", action="store_true", help="generate 3d face and 3d landmarks")
    parser.add_argument("--still", action="store_true", help="can crop back to the original videos for the full body aniamtion")
    parser.add_argument("--preprocess", default=request.preprocess, choices=['crop', 'extcrop', 'resize', 'full', 'extfull'], help="how to preprocess the images" )
    parser.add_argument("--verbose",action="store_true",default=request.verbose, help="saving the intermedia output or not" )
    parser.add_argument("--old_version",action="store_true", help="use the pth other than safetensor version" )

    # net structure and parameters
    parser.add_argument('--net_recon', type=str, default='resnet50', choices=['resnet18', 'resnet34', 'resnet50'], help='useless')
    parser.add_argument('--init_path', type=str, default=None, help='Useless')
    parser.add_argument('--use_last_fc',default=False, help='zero initialize the last fc')
    parser.add_argument('--bfm_folder', type=str, default='./checkpoints/BFM_Fitting/')
    parser.add_argument('--bfm_model', type=str, default='BFM_model_front.mat', help='bfm model')

    # default renderer parameters
    parser.add_argument('--focal', type=float, default=1015.)
    parser.add_argument('--center', type=float, default=112.)
    parser.add_argument('--camera_d', type=float, default=10.)
    parser.add_argument('--z_near', type=float, default=5.)
    parser.add_argument('--z_far', type=float, default=15.)

    args = parser.parse_args()

    if torch.cuda.is_available() and not args.cpu:
        args.device = "cuda"
    else:
        args.device = "cpu"

    print("参数: ", args)
    video_path = inference2.main(args)
    respnose = MakeVideoResponse(video_path)
    return respnose


@router.post("/demo")
async def demo():
    print("hello world")
    return "hello world"


def main():
    # 类似于 app = Flask(__name__)
    # 设置接口文档地址
    app = FastAPI(openapi_url=context_path+"/openapi.json",
                  docs_url=context_path+"/docs",
                  redoc_url=context_path+"/redoc")
    app.include_router(router)

    # 启动服务,因为我们这个文件叫做 main.py
    # 所以需要启动 main.py 里面的 app
    # 第一个参数 "main:app" 就表示这个含义
    # 然后是 host 和 port 表示监听的 ip 和端口
    uvicorn.run(app, host="0.0.0.0", port=8100)


# 在 Windows 中必须加上 if __name__ == "__main__"
# 否则会抛出 RuntimeError: This event loop is already running
if __name__ == "__main__":
    main()

编写启动脚本start.sh

nohup python sadtalker_http.py &

运行截图

在这里插入图片描述

参考资料

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

太空眼睛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值