From a7ec66a663cb2bc849f731f43b6b18f5675fb82e Mon Sep 17 00:00:00 2001 From: Dan Date: Sun, 30 Jul 2023 22:11:01 +0200 Subject: [PATCH] added documentation and also openapi export. Removed the cuda container, since they still dont work properly --- .gitignore | 1 - Dockerfile | 9 +- README.md | 9 ++ run_api.py => api.py | 12 +- cuda.Dockerfile | 26 ---- docker-compose.cuda.yml | 24 ---- docker-compose.yml | 8 +- openapi.json | 282 ++++++++++++++++++++++++++++++++++++++++ roop/predictor.py | 4 +- 9 files changed, 308 insertions(+), 67 deletions(-) rename run_api.py => api.py (90%) delete mode 100644 cuda.Dockerfile delete mode 100644 docker-compose.cuda.yml create mode 100644 openapi.json diff --git a/.gitignore b/.gitignore index dda3d88af..e25e7ce3b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ .idea models temp -workdir __pycache__ diff --git a/Dockerfile b/Dockerfile index 9d2badc97..d0a72a54f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,14 @@ FROM python:3.10 ENV EXECUTION_PROVIDER=CPU +ENV TEMP_FRAME_FORMAT=png +ENV TEMP_FRAME_QUALITY=0 +ENV OUTPUT_VIDEO_QUALITY=0 RUN apt-get update && apt-get install -y ffmpeg RUN pip install --upgrade pip -#RUN git clone https://github.com/s0md3v/roop.git /roop \ -RUN git clone https://github.com/danikhani/roop /roop +#RUN git clone https://github.com/s0md3v/roop.git /roop +RUN git clone https://github.com/danikhani/roop.git /roop RUN pip install -r roop/requirements-docker.txt -CMD ["python", "/roop/run_api.py"] \ No newline at end of file +CMD ["python", "/roop/api.py"] \ No newline at end of file diff --git a/README.md b/README.md index 5f268df2f..01120f108 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,16 @@ options: ``` Using the `-s/--source`, `-t/--target` and `-o/--output` argument will run the program in headless mode. +## Docker +FastAPI allows the communication with the Docker container. The OpenAPI export of endpoints are under [Openapi.json](openapi.json). + +### Start and Stop the container (CPU version) +Clone the repository. Build an Image and start the container by writing +```docker-compose -f docker-compose.yml up -d```. +The container can get stopped by +```docker-compose -f docker-compose.yml down```. +The models will be saved in a docker volume. First start of the roop container might take longer, since the models will be downloaded for the first time. ## Credits - [henryruhs](https://github.com/henryruhs): for being an irreplaceable contributor to the project diff --git a/run_api.py b/api.py similarity index 90% rename from run_api.py rename to api.py index e559dd026..2368ec27f 100644 --- a/run_api.py +++ b/api.py @@ -24,10 +24,7 @@ class RoopModel(BaseModel): reference_face_position: Optional[int] = 0 reference_frame_number: Optional[int] = 0 similar_face_distance: Optional[float] = 0.85 - temp_frame_format: Optional[Literal['png','jpg']] = 'png' - temp_frame_quality: Optional[int] = 0 output_video_encoder: Optional[Literal['libx264', 'libx265', 'libvpx-vp9', 'h264_nvenc', 'hevc_nvenc']] = 'libx264' - output_video_quality: Optional[int] = 0 max_memory: Optional[int] = 0 execution_threads: Optional[int] = suggest_execution_threads() @app.get('/get_execution_providers') @@ -58,6 +55,10 @@ async def image_file( execution_provider_list = ['cpu'] print(execution_provider_list) + roop.globals.temp_frame_format = os.getenv('TEMP_FRAME_FORMAT') + roop.globals.temp_frame_quality = os.getenv('TEMP_FRAME_QUALITY') + roop.globals.output_video_quality = os.getenv('OUTPUT_VIDEO_QUALITY') + # setting paths src_saving_path_complete = os.path.join(saving_path, src_file.filename) target_saving_path_complete = os.path.join(saving_path, target_file.filename) @@ -82,10 +83,7 @@ async def image_file( roop.globals.reference_face_position = roop_parameters.reference_face_position roop.globals.reference_frame_number = roop_parameters.reference_frame_number roop.globals.similar_face_distance = roop_parameters.similar_face_distance - roop.globals.temp_frame_format = roop_parameters.temp_frame_format - roop.globals.temp_frame_quality = roop_parameters.temp_frame_quality roop.globals.output_video_encoder = roop_parameters.output_video_encoder - roop.globals.output_video_quality = roop_parameters.output_video_quality roop.globals.max_memory = roop_parameters.max_memory roop.globals.execution_providers = decode_execution_providers(execution_provider_list) roop.globals.execution_threads = roop_parameters.execution_threads @@ -100,6 +98,6 @@ async def image_file( if __name__ == "__main__": if os.getenv('EXECUTION_PROVIDER') is None: print('Env variable for execution provider is not set. Setting default to CPU.') - os.environ['EXECUTION_PROVIDER'] = 'CUDA' + os.environ['EXECUTION_PROVIDER'] = 'CPU' print(os.getenv('EXECUTION_PROVIDER')) uvicorn.run(app, host="0.0.0.0", port=8000) diff --git a/cuda.Dockerfile b/cuda.Dockerfile deleted file mode 100644 index e0b9e3fed..000000000 --- a/cuda.Dockerfile +++ /dev/null @@ -1,26 +0,0 @@ -FROM nvidia/cuda:11.8.0-cudnn8-runtime-ubuntu22.04 - -#RUN rm -rf /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.1 /usr/lib/x86_64-linux-gnu/libcuda.so.1 -ENV EXECUTION_PROVIDER=CUDA -ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get install -y \ - ffmpeg \ - git \ - nvidia-cudnn \ - python3 \ - python3-pip \ - python3-tk \ - python-is-python3 - -RUN git clone https://github.com/danikhani/roop /roop -RUN pip install -r roop/requirements-docker.txt - -# fix modulus in wsl2.0 for windows: -# https://forums.developer.nvidia.com/t/wsl-modulus-docker-run-error-libnvidia-ml-so-1-file-exists-unknown/256058/5 -RUN rm -rf \ - /usr/lib/x86_64-linux-gnu/libcuda.so* \ - /usr/lib/x86_64-linux-gnu/libnvcuvid.so* \ - /usr/lib/x86_64-linux-gnu/libnvidia-*.so* \ - /usr/local/cuda/compat/lib/*.515.65.01 - -CMD ["python", "/roop/run_api.py"] \ No newline at end of file diff --git a/docker-compose.cuda.yml b/docker-compose.cuda.yml deleted file mode 100644 index 908fb742c..000000000 --- a/docker-compose.cuda.yml +++ /dev/null @@ -1,24 +0,0 @@ -version: '3.9' - -services: - roopapi: - build: - context: . - dockerfile: cuda.Dockerfile - restart: unless-stopped - volumes: - - roop-data:/roop - - open-nsfw:/root/.opennsfw2 - ports: - - 8000:8000 - deploy: - resources: - reservations: - devices: - - driver: nvidia - count: 1 - capabilities: [ gpu ] - -volumes: - roop-data: - open-nsfw: \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 2db8973cc..3b3b27861 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,17 +1,15 @@ version: '3.8' services: - roopapi: + roop-api: build: context: . dockerfile: Dockerfile - restart: unless-stopped + restart: always volumes: - roop-data:/roop - - open-nsfw:/root/.opennsfw2 ports: - 8000:8000 volumes: - roop-data: - open-nsfw: \ No newline at end of file + roop-data: \ No newline at end of file diff --git a/openapi.json b/openapi.json new file mode 100644 index 000000000..18c948b24 --- /dev/null +++ b/openapi.json @@ -0,0 +1,282 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "FastAPI", + "version": "0.1.0" + }, + "paths": { + "/get_execution_providers": { + "get": { + "summary": "Get Execution Provider", + "operationId": "get_execution_provider_get_execution_providers_get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + } + } + } + }, + "/start_roop": { + "post": { + "summary": "Image File", + "operationId": "image_file_start_roop_post", + "parameters": [ + { + "required": false, + "schema": { + "type": "boolean", + "title": "Keep Fps", + "default": false + }, + "name": "keep_fps", + "in": "query" + }, + { + "required": false, + "schema": { + "type": "boolean", + "title": "Keep Frames", + "default": false + }, + "name": "keep_frames", + "in": "query" + }, + { + "required": false, + "schema": { + "type": "boolean", + "title": "Skip Audio", + "default": false + }, + "name": "skip_audio", + "in": "query" + }, + { + "required": false, + "schema": { + "type": "boolean", + "title": "Many Faces", + "default": false + }, + "name": "many_faces", + "in": "query" + }, + { + "required": false, + "schema": { + "type": "integer", + "title": "Reference Face Position", + "default": 0 + }, + "name": "reference_face_position", + "in": "query" + }, + { + "required": false, + "schema": { + "type": "integer", + "title": "Reference Frame Number", + "default": 0 + }, + "name": "reference_frame_number", + "in": "query" + }, + { + "required": false, + "schema": { + "type": "number", + "title": "Similar Face Distance", + "default": 0.85 + }, + "name": "similar_face_distance", + "in": "query" + }, + { + "required": false, + "schema": { + "type": "string", + "enum": [ + "png", + "jpg" + ], + "title": "Temp Frame Format", + "default": "png" + }, + "name": "temp_frame_format", + "in": "query" + }, + { + "required": false, + "schema": { + "type": "integer", + "title": "Temp Frame Quality", + "default": 0 + }, + "name": "temp_frame_quality", + "in": "query" + }, + { + "required": false, + "schema": { + "type": "string", + "enum": [ + "libx264", + "libx265", + "libvpx-vp9", + "h264_nvenc", + "hevc_nvenc" + ], + "title": "Output Video Encoder", + "default": "libx264" + }, + "name": "output_video_encoder", + "in": "query" + }, + { + "required": false, + "schema": { + "type": "integer", + "title": "Output Video Quality", + "default": 0 + }, + "name": "output_video_quality", + "in": "query" + }, + { + "required": false, + "schema": { + "type": "integer", + "title": "Max Memory", + "default": 0 + }, + "name": "max_memory", + "in": "query" + }, + { + "required": false, + "schema": { + "type": "integer", + "title": "Execution Threads", + "default": 8 + }, + "name": "execution_threads", + "in": "query" + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/Body_image_file_start_roop_post" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Body_image_file_start_roop_post": { + "properties": { + "src_file": { + "type": "string", + "format": "binary", + "title": "Src File" + }, + "target_file": { + "type": "string", + "format": "binary", + "title": "Target File" + }, + "frame_processor": { + "items": {}, + "type": "array", + "title": "Frame Processor", + "default": [ + "face_swapper" + ] + } + }, + "type": "object", + "required": [ + "src_file", + "target_file" + ], + "title": "Body_image_file_start_roop_post" + }, + "HTTPValidationError": { + "properties": { + "detail": { + "items": { + "$ref": "#/components/schemas/ValidationError" + }, + "type": "array", + "title": "Detail" + } + }, + "type": "object", + "title": "HTTPValidationError" + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer" + } + ] + }, + "type": "array", + "title": "Location" + }, + "msg": { + "type": "string", + "title": "Message" + }, + "type": { + "type": "string", + "title": "Error Type" + } + }, + "type": "object", + "required": [ + "loc", + "msg", + "type" + ], + "title": "ValidationError" + } + } + } +} \ No newline at end of file diff --git a/roop/predictor.py b/roop/predictor.py index b59fee93e..c25f976e6 100644 --- a/roop/predictor.py +++ b/roop/predictor.py @@ -5,6 +5,7 @@ from keras import Model from roop.typing import Frame +from roop.utilities import resolve_relative_path PREDICTOR = None THREAD_LOCK = threading.Lock() @@ -16,7 +17,8 @@ def get_predictor() -> Model: with THREAD_LOCK: if PREDICTOR is None: - PREDICTOR = opennsfw2.make_open_nsfw_model() + rel_path = resolve_relative_path('../models/opennsfw2') + PREDICTOR = opennsfw2.make_open_nsfw_model(weights_path = rel_path) return PREDICTOR