Spaces:
Running
Running
Upload 48 files
Browse files- FaceFusion Paths.txt +0 -0
- LICENSE.md +3 -0
- README.md +60 -12
- facefusion.ico +0 -0
- facefusion.ini +118 -0
- facefusion.py +10 -0
- install.py +10 -0
- mypy.ini +7 -0
- requirements.txt +21 -0
- run.py +8 -0
- tests/__init__.py +0 -0
- tests/helper.py +44 -0
- tests/test_audio.py +28 -0
- tests/test_cli_age_modifier.py +38 -0
- tests/test_cli_batch_runner.py +45 -0
- tests/test_cli_expression_restorer.py +38 -0
- tests/test_cli_face_debugger.py +39 -0
- tests/test_cli_face_editor.py +39 -0
- tests/test_cli_face_enhancer.py +39 -0
- tests/test_cli_face_swapper.py +39 -0
- tests/test_cli_frame_colorizer.py +40 -0
- tests/test_cli_frame_enhancer.py +39 -0
- tests/test_cli_job_manager.py +209 -0
- tests/test_cli_job_runner.py +147 -0
- tests/test_cli_lip_syncer.py +40 -0
- tests/test_common_helper.py +27 -0
- tests/test_config.py +85 -0
- tests/test_curl_builder.py +14 -0
- tests/test_date_helper.py +15 -0
- tests/test_download.py +18 -0
- tests/test_execution.py +24 -0
- tests/test_face_analyser.py +113 -0
- tests/test_ffmpeg.py +119 -0
- tests/test_ffmpeg_builder.py +83 -0
- tests/test_filesystem.py +135 -0
- tests/test_inference_manager.py +32 -0
- tests/test_job_helper.py +8 -0
- tests/test_job_list.py +24 -0
- tests/test_job_manager.py +376 -0
- tests/test_job_runner.py +227 -0
- tests/test_json.py +19 -0
- tests/test_memory.py +8 -0
- tests/test_normalizer.py +16 -0
- tests/test_process_manager.py +22 -0
- tests/test_program_helper.py +40 -0
- tests/test_temp_helper.py +34 -0
- tests/test_vision.py +179 -0
- tests/test_wording.py +7 -0
FaceFusion Paths.txt
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
LICENSE.md
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
OpenRAIL-AS license
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2025 Henry Ruhs
|
README.md
CHANGED
|
@@ -1,12 +1,60 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FaceFusion
|
| 2 |
+
==========
|
| 3 |
+
|
| 4 |
+
> Industry leading face manipulation platform.
|
| 5 |
+
|
| 6 |
+
[](https://github.com/facefusion/facefusion/actions?query=workflow:ci)
|
| 7 |
+
[](https://coveralls.io/r/facefusion/facefusion)
|
| 8 |
+

|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
Preview
|
| 12 |
+
-------
|
| 13 |
+
|
| 14 |
+

|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
Installation
|
| 18 |
+
------------
|
| 19 |
+
|
| 20 |
+
Be aware, the [installation](https://docs.facefusion.io/installation) needs technical skills and is not recommended for beginners. In case you are not comfortable using a terminal, our [Windows Installer](http://windows-installer.facefusion.io) and [macOS Installer](http://macos-installer.facefusion.io) get you started.
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
Usage
|
| 24 |
+
-----
|
| 25 |
+
|
| 26 |
+
Run the command:
|
| 27 |
+
|
| 28 |
+
```
|
| 29 |
+
python facefusion.py [commands] [options]
|
| 30 |
+
|
| 31 |
+
options:
|
| 32 |
+
-h, --help show this help message and exit
|
| 33 |
+
-v, --version show program's version number and exit
|
| 34 |
+
|
| 35 |
+
commands:
|
| 36 |
+
run run the program
|
| 37 |
+
headless-run run the program in headless mode
|
| 38 |
+
batch-run run the program in batch mode
|
| 39 |
+
force-download force automate downloads and exit
|
| 40 |
+
job-list list jobs by status
|
| 41 |
+
job-create create a drafted job
|
| 42 |
+
job-submit submit a drafted job to become a queued job
|
| 43 |
+
job-submit-all submit all drafted jobs to become a queued jobs
|
| 44 |
+
job-delete delete a drafted, queued, failed or completed job
|
| 45 |
+
job-delete-all delete all drafted, queued, failed and completed jobs
|
| 46 |
+
job-add-step add a step to a drafted job
|
| 47 |
+
job-remix-step remix a previous step from a drafted job
|
| 48 |
+
job-insert-step insert a step to a drafted job
|
| 49 |
+
job-remove-step remove a step from a drafted job
|
| 50 |
+
job-run run a queued job
|
| 51 |
+
job-run-all run all queued jobs
|
| 52 |
+
job-retry retry a failed job
|
| 53 |
+
job-retry-all retry all failed jobs
|
| 54 |
+
```
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
Documentation
|
| 58 |
+
-------------
|
| 59 |
+
|
| 60 |
+
Read the [documentation](https://docs.facefusion.io) for a deep dive.
|
facefusion.ico
ADDED
|
|
facefusion.ini
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[paths]
|
| 2 |
+
temp_path =
|
| 3 |
+
jobs_path =
|
| 4 |
+
source_paths =
|
| 5 |
+
target_path =
|
| 6 |
+
output_path =
|
| 7 |
+
|
| 8 |
+
[patterns]
|
| 9 |
+
source_pattern =
|
| 10 |
+
target_pattern =
|
| 11 |
+
output_pattern =
|
| 12 |
+
|
| 13 |
+
[face_detector]
|
| 14 |
+
face_detector_model =
|
| 15 |
+
face_detector_size =
|
| 16 |
+
face_detector_angles =
|
| 17 |
+
face_detector_score =
|
| 18 |
+
|
| 19 |
+
[face_landmarker]
|
| 20 |
+
face_landmarker_model =
|
| 21 |
+
face_landmarker_score =
|
| 22 |
+
|
| 23 |
+
[face_selector]
|
| 24 |
+
face_selector_mode =
|
| 25 |
+
face_selector_order =
|
| 26 |
+
face_selector_age_start =
|
| 27 |
+
face_selector_age_end =
|
| 28 |
+
face_selector_gender =
|
| 29 |
+
face_selector_race =
|
| 30 |
+
reference_face_position =
|
| 31 |
+
reference_face_distance =
|
| 32 |
+
reference_frame_number =
|
| 33 |
+
|
| 34 |
+
[face_masker]
|
| 35 |
+
face_occluder_model =
|
| 36 |
+
face_parser_model =
|
| 37 |
+
face_mask_types =
|
| 38 |
+
face_mask_blur =
|
| 39 |
+
face_mask_padding =
|
| 40 |
+
face_mask_regions =
|
| 41 |
+
|
| 42 |
+
[frame_extraction]
|
| 43 |
+
trim_frame_start =
|
| 44 |
+
trim_frame_end =
|
| 45 |
+
temp_frame_format =
|
| 46 |
+
keep_temp =
|
| 47 |
+
|
| 48 |
+
[output_creation]
|
| 49 |
+
output_image_quality =
|
| 50 |
+
output_image_resolution =
|
| 51 |
+
output_audio_encoder =
|
| 52 |
+
output_audio_quality =
|
| 53 |
+
output_audio_volume =
|
| 54 |
+
output_video_encoder =
|
| 55 |
+
output_video_preset =
|
| 56 |
+
output_video_quality =
|
| 57 |
+
output_video_resolution =
|
| 58 |
+
output_video_fps =
|
| 59 |
+
skip_audio =
|
| 60 |
+
|
| 61 |
+
[processors]
|
| 62 |
+
processors =
|
| 63 |
+
age_modifier_model =
|
| 64 |
+
age_modifier_direction =
|
| 65 |
+
deep_swapper_model =
|
| 66 |
+
deep_swapper_morph =
|
| 67 |
+
expression_restorer_model =
|
| 68 |
+
expression_restorer_factor =
|
| 69 |
+
face_debugger_items =
|
| 70 |
+
face_editor_model =
|
| 71 |
+
face_editor_eyebrow_direction =
|
| 72 |
+
face_editor_eye_gaze_horizontal =
|
| 73 |
+
face_editor_eye_gaze_vertical =
|
| 74 |
+
face_editor_eye_open_ratio =
|
| 75 |
+
face_editor_lip_open_ratio =
|
| 76 |
+
face_editor_mouth_grim =
|
| 77 |
+
face_editor_mouth_pout =
|
| 78 |
+
face_editor_mouth_purse =
|
| 79 |
+
face_editor_mouth_smile =
|
| 80 |
+
face_editor_mouth_position_horizontal =
|
| 81 |
+
face_editor_mouth_position_vertical =
|
| 82 |
+
face_editor_head_pitch =
|
| 83 |
+
face_editor_head_yaw =
|
| 84 |
+
face_editor_head_roll =
|
| 85 |
+
face_enhancer_model =
|
| 86 |
+
face_enhancer_blend =
|
| 87 |
+
face_enhancer_weight =
|
| 88 |
+
face_swapper_model =
|
| 89 |
+
face_swapper_pixel_boost =
|
| 90 |
+
frame_colorizer_model =
|
| 91 |
+
frame_colorizer_size =
|
| 92 |
+
frame_colorizer_blend =
|
| 93 |
+
frame_enhancer_model =
|
| 94 |
+
frame_enhancer_blend =
|
| 95 |
+
lip_syncer_model =
|
| 96 |
+
|
| 97 |
+
[uis]
|
| 98 |
+
open_browser =
|
| 99 |
+
ui_layouts =
|
| 100 |
+
ui_workflow =
|
| 101 |
+
|
| 102 |
+
[execution]
|
| 103 |
+
execution_device_id =
|
| 104 |
+
execution_providers =
|
| 105 |
+
execution_thread_count =
|
| 106 |
+
execution_queue_count =
|
| 107 |
+
|
| 108 |
+
[download]
|
| 109 |
+
download_providers =
|
| 110 |
+
download_scope =
|
| 111 |
+
|
| 112 |
+
[memory]
|
| 113 |
+
video_memory_strategy =
|
| 114 |
+
system_memory_limit =
|
| 115 |
+
|
| 116 |
+
[misc]
|
| 117 |
+
log_level =
|
| 118 |
+
halt_on_error =
|
facefusion.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
|
| 3 |
+
import os
|
| 4 |
+
|
| 5 |
+
os.environ['OMP_NUM_THREADS'] = '1'
|
| 6 |
+
|
| 7 |
+
from facefusion import core
|
| 8 |
+
|
| 9 |
+
if __name__ == '__main__':
|
| 10 |
+
core.cli()
|
install.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
|
| 3 |
+
import os
|
| 4 |
+
|
| 5 |
+
os.environ['SYSTEM_VERSION_COMPAT'] = '0'
|
| 6 |
+
|
| 7 |
+
from facefusion import installer
|
| 8 |
+
|
| 9 |
+
if __name__ == '__main__':
|
| 10 |
+
installer.cli()
|
mypy.ini
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[mypy]
|
| 2 |
+
check_untyped_defs = True
|
| 3 |
+
disallow_any_generics = True
|
| 4 |
+
disallow_untyped_calls = True
|
| 5 |
+
disallow_untyped_defs = True
|
| 6 |
+
ignore_missing_imports = True
|
| 7 |
+
strict_optional = False
|
requirements.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio
|
| 2 |
+
gradio-rangeslider
|
| 3 |
+
numpy
|
| 4 |
+
onnx
|
| 5 |
+
onnxruntime
|
| 6 |
+
opencv-python
|
| 7 |
+
psutil
|
| 8 |
+
tqdm
|
| 9 |
+
scipy
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
#gradio==5.20.0
|
| 14 |
+
#gradio-rangeslider==0.0.8
|
| 15 |
+
#numpy==2.2.3
|
| 16 |
+
#onnx==1.17.0
|
| 17 |
+
#onnxruntime==1.21.0
|
| 18 |
+
#opencv-python==4.11.0.86
|
| 19 |
+
#psutil==7.0.0
|
| 20 |
+
#tqdm==4.67.1
|
| 21 |
+
#scipy==1.15.2
|
run.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
import subprocess
|
| 3 |
+
|
| 4 |
+
python_executable = sys.executable # Jo bhi active Python hai usko detect karega
|
| 5 |
+
command = [python_executable, "facefusion.py", "run"]
|
| 6 |
+
|
| 7 |
+
print(f"🚀 Launching FaceFusion with {python_executable}...")
|
| 8 |
+
subprocess.run(command)
|
tests/__init__.py
ADDED
|
File without changes
|
tests/helper.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import tempfile
|
| 3 |
+
|
| 4 |
+
from facefusion.filesystem import create_directory, is_directory, is_file, remove_directory
|
| 5 |
+
from facefusion.types import JobStatus
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def is_test_job_file(file_path : str, job_status : JobStatus) -> bool:
|
| 9 |
+
return is_file(get_test_job_file(file_path, job_status))
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def get_test_job_file(file_path : str, job_status : JobStatus) -> str:
|
| 13 |
+
return os.path.join(get_test_jobs_directory(), job_status, file_path)
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def get_test_jobs_directory() -> str:
|
| 17 |
+
return os.path.join(tempfile.gettempdir(), 'facefusion-test-jobs')
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def get_test_example_file(file_path : str) -> str:
|
| 21 |
+
return os.path.join(get_test_examples_directory(), file_path)
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def get_test_examples_directory() -> str:
|
| 25 |
+
return os.path.join(tempfile.gettempdir(), 'facefusion-test-examples')
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def is_test_output_file(file_path : str) -> bool:
|
| 29 |
+
return is_file(get_test_output_file(file_path))
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def get_test_output_file(file_path : str) -> str:
|
| 33 |
+
return os.path.join(get_test_outputs_directory(), file_path)
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def get_test_outputs_directory() -> str:
|
| 37 |
+
return os.path.join(tempfile.gettempdir(), 'facefusion-test-outputs')
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def prepare_test_output_directory() -> bool:
|
| 41 |
+
test_outputs_directory = get_test_outputs_directory()
|
| 42 |
+
remove_directory(test_outputs_directory)
|
| 43 |
+
create_directory(test_outputs_directory)
|
| 44 |
+
return is_directory(test_outputs_directory)
|
tests/test_audio.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import subprocess
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
|
| 5 |
+
from facefusion.audio import get_audio_frame, read_static_audio
|
| 6 |
+
from facefusion.download import conditional_download
|
| 7 |
+
from .helper import get_test_example_file, get_test_examples_directory
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
| 11 |
+
def before_all() -> None:
|
| 12 |
+
conditional_download(get_test_examples_directory(),
|
| 13 |
+
[
|
| 14 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.mp3'
|
| 15 |
+
])
|
| 16 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.mp3'), get_test_example_file('source.wav') ])
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def test_get_audio_frame() -> None:
|
| 20 |
+
assert hasattr(get_audio_frame(get_test_example_file('source.mp3'), 25), '__array_interface__')
|
| 21 |
+
assert hasattr(get_audio_frame(get_test_example_file('source.wav'), 25), '__array_interface__')
|
| 22 |
+
assert get_audio_frame('invalid', 25) is None
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def test_read_static_audio() -> None:
|
| 26 |
+
assert len(read_static_audio(get_test_example_file('source.mp3'), 25)) == 280
|
| 27 |
+
assert len(read_static_audio(get_test_example_file('source.wav'), 25)) == 280
|
| 28 |
+
assert read_static_audio('invalid', 25) is None
|
tests/test_cli_age_modifier.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import subprocess
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
from facefusion.download import conditional_download
|
| 7 |
+
from facefusion.jobs.job_manager import clear_jobs, init_jobs
|
| 8 |
+
from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
| 12 |
+
def before_all() -> None:
|
| 13 |
+
conditional_download(get_test_examples_directory(),
|
| 14 |
+
[
|
| 15 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
|
| 16 |
+
])
|
| 17 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
@pytest.fixture(scope = 'function', autouse = True)
|
| 21 |
+
def before_each() -> None:
|
| 22 |
+
clear_jobs(get_test_jobs_directory())
|
| 23 |
+
init_jobs(get_test_jobs_directory())
|
| 24 |
+
prepare_test_output_directory()
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def test_modify_age_to_image() -> None:
|
| 28 |
+
commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'age_modifier', '--age-modifier-direction', '100', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-age-face-to-image.jpg') ]
|
| 29 |
+
|
| 30 |
+
assert subprocess.run(commands).returncode == 0
|
| 31 |
+
assert is_test_output_file('test-age-face-to-image.jpg') is True
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def test_modify_age_to_video() -> None:
|
| 35 |
+
commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'age_modifier', '--age-modifier-direction', '100', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test-age-face-to-video.mp4'), '--trim-frame-end', '1' ]
|
| 36 |
+
|
| 37 |
+
assert subprocess.run(commands).returncode == 0
|
| 38 |
+
assert is_test_output_file('test-age-face-to-video.mp4') is True
|
tests/test_cli_batch_runner.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import subprocess
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
from facefusion.download import conditional_download
|
| 7 |
+
from facefusion.jobs.job_manager import clear_jobs, init_jobs
|
| 8 |
+
from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
| 12 |
+
def before_all() -> None:
|
| 13 |
+
conditional_download(get_test_examples_directory(),
|
| 14 |
+
[
|
| 15 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
|
| 16 |
+
])
|
| 17 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p-batch-1.jpg') ])
|
| 18 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '2', get_test_example_file('target-240p-batch-2.jpg') ])
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
@pytest.fixture(scope = 'function', autouse = True)
|
| 22 |
+
def before_each() -> None:
|
| 23 |
+
clear_jobs(get_test_jobs_directory())
|
| 24 |
+
init_jobs(get_test_jobs_directory())
|
| 25 |
+
prepare_test_output_directory()
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def test_batch_run_targets() -> None:
|
| 29 |
+
commands = [ sys.executable, 'facefusion.py', 'batch-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p-batch-*.jpg'), '-o', get_test_output_file('test-batch-run-targets-{index}.jpg') ]
|
| 30 |
+
|
| 31 |
+
assert subprocess.run(commands).returncode == 0
|
| 32 |
+
assert is_test_output_file('test-batch-run-targets-0.jpg') is True
|
| 33 |
+
assert is_test_output_file('test-batch-run-targets-1.jpg') is True
|
| 34 |
+
assert is_test_output_file('test-batch-run-targets-2.jpg') is False
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def test_batch_run_sources_to_targets() -> None:
|
| 38 |
+
commands = [ sys.executable, 'facefusion.py', 'batch-run', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('target-240p-batch-*.jpg'), '-t', get_test_example_file('target-240p-batch-*.jpg'), '-o', get_test_output_file('test-batch-run-sources-to-targets-{index}.jpg') ]
|
| 39 |
+
|
| 40 |
+
assert subprocess.run(commands).returncode == 0
|
| 41 |
+
assert is_test_output_file('test-batch-run-sources-to-targets-0.jpg') is True
|
| 42 |
+
assert is_test_output_file('test-batch-run-sources-to-targets-1.jpg') is True
|
| 43 |
+
assert is_test_output_file('test-batch-run-sources-to-targets-2.jpg') is True
|
| 44 |
+
assert is_test_output_file('test-batch-run-sources-to-targets-3.jpg') is True
|
| 45 |
+
assert is_test_output_file('test-batch-run-sources-to-targets-4.jpg') is False
|
tests/test_cli_expression_restorer.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import subprocess
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
from facefusion.download import conditional_download
|
| 7 |
+
from facefusion.jobs.job_manager import clear_jobs, init_jobs
|
| 8 |
+
from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
| 12 |
+
def before_all() -> None:
|
| 13 |
+
conditional_download(get_test_examples_directory(),
|
| 14 |
+
[
|
| 15 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
|
| 16 |
+
])
|
| 17 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
@pytest.fixture(scope = 'function', autouse = True)
|
| 21 |
+
def before_each() -> None:
|
| 22 |
+
clear_jobs(get_test_jobs_directory())
|
| 23 |
+
init_jobs(get_test_jobs_directory())
|
| 24 |
+
prepare_test_output_directory()
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def test_restore_expression_to_image() -> None:
|
| 28 |
+
commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'expression_restorer', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-restore-expression-to-image.jpg') ]
|
| 29 |
+
|
| 30 |
+
assert subprocess.run(commands).returncode == 0
|
| 31 |
+
assert is_test_output_file('test-restore-expression-to-image.jpg') is True
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def test_restore_expression_to_video() -> None:
|
| 35 |
+
commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'expression_restorer', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test-restore-expression-to-video.mp4'), '--trim-frame-end', '1' ]
|
| 36 |
+
|
| 37 |
+
assert subprocess.run(commands).returncode == 0
|
| 38 |
+
assert is_test_output_file('test-restore-expression-to-video.mp4') is True
|
tests/test_cli_face_debugger.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import subprocess
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
from facefusion.download import conditional_download
|
| 7 |
+
from facefusion.jobs.job_manager import clear_jobs, init_jobs
|
| 8 |
+
from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
| 12 |
+
def before_all() -> None:
|
| 13 |
+
conditional_download(get_test_examples_directory(),
|
| 14 |
+
[
|
| 15 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
|
| 16 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
|
| 17 |
+
])
|
| 18 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
@pytest.fixture(scope = 'function', autouse = True)
|
| 22 |
+
def before_each() -> None:
|
| 23 |
+
clear_jobs(get_test_jobs_directory())
|
| 24 |
+
init_jobs(get_test_jobs_directory())
|
| 25 |
+
prepare_test_output_directory()
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def test_debug_face_to_image() -> None:
|
| 29 |
+
commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-debug-face-to-image.jpg') ]
|
| 30 |
+
|
| 31 |
+
assert subprocess.run(commands).returncode == 0
|
| 32 |
+
assert is_test_output_file('test-debug-face-to-image.jpg') is True
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def test_debug_face_to_video() -> None:
|
| 36 |
+
commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test-debug-face-to-video.mp4'), '--trim-frame-end', '1' ]
|
| 37 |
+
|
| 38 |
+
assert subprocess.run(commands).returncode == 0
|
| 39 |
+
assert is_test_output_file('test-debug-face-to-video.mp4') is True
|
tests/test_cli_face_editor.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import subprocess
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
from facefusion.download import conditional_download
|
| 7 |
+
from facefusion.jobs.job_manager import clear_jobs, init_jobs
|
| 8 |
+
from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
| 12 |
+
def before_all() -> None:
|
| 13 |
+
conditional_download(get_test_examples_directory(),
|
| 14 |
+
[
|
| 15 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
|
| 16 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
|
| 17 |
+
])
|
| 18 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
@pytest.fixture(scope = 'function', autouse = True)
|
| 22 |
+
def before_each() -> None:
|
| 23 |
+
clear_jobs(get_test_jobs_directory())
|
| 24 |
+
init_jobs(get_test_jobs_directory())
|
| 25 |
+
prepare_test_output_directory()
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def test_edit_face_to_image() -> None:
|
| 29 |
+
commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_editor', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-edit-face-to-image.jpg') ]
|
| 30 |
+
|
| 31 |
+
assert subprocess.run(commands).returncode == 0
|
| 32 |
+
assert is_test_output_file('test-edit-face-to-image.jpg') is True
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def test_edit_face_to_video() -> None:
|
| 36 |
+
commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_editor', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test-edit-face-to-video.mp4'), '--trim-frame-end', '1' ]
|
| 37 |
+
|
| 38 |
+
assert subprocess.run(commands).returncode == 0
|
| 39 |
+
assert is_test_output_file('test-edit-face-to-video.mp4') is True
|
tests/test_cli_face_enhancer.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import subprocess
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
from facefusion.download import conditional_download
|
| 7 |
+
from facefusion.jobs.job_manager import clear_jobs, init_jobs
|
| 8 |
+
from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
| 12 |
+
def before_all() -> None:
|
| 13 |
+
conditional_download(get_test_examples_directory(),
|
| 14 |
+
[
|
| 15 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
|
| 16 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
|
| 17 |
+
])
|
| 18 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
@pytest.fixture(scope = 'function', autouse = True)
|
| 22 |
+
def before_each() -> None:
|
| 23 |
+
clear_jobs(get_test_jobs_directory())
|
| 24 |
+
init_jobs(get_test_jobs_directory())
|
| 25 |
+
prepare_test_output_directory()
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def test_enhance_face_to_image() -> None:
|
| 29 |
+
commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_enhancer', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-enhance-face-to-image.jpg') ]
|
| 30 |
+
|
| 31 |
+
assert subprocess.run(commands).returncode == 0
|
| 32 |
+
assert is_test_output_file('test-enhance-face-to-image.jpg') is True
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def test_enhance_face_to_video() -> None:
|
| 36 |
+
commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_enhancer', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test-enhance-face-to-video.mp4'), '--trim-frame-end', '1' ]
|
| 37 |
+
|
| 38 |
+
assert subprocess.run(commands).returncode == 0
|
| 39 |
+
assert is_test_output_file('test-enhance-face-to-video.mp4') is True
|
tests/test_cli_face_swapper.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import subprocess
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
from facefusion.download import conditional_download
|
| 7 |
+
from facefusion.jobs.job_manager import clear_jobs, init_jobs
|
| 8 |
+
from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
| 12 |
+
def before_all() -> None:
|
| 13 |
+
conditional_download(get_test_examples_directory(),
|
| 14 |
+
[
|
| 15 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
|
| 16 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
|
| 17 |
+
])
|
| 18 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
@pytest.fixture(scope = 'function', autouse = True)
|
| 22 |
+
def before_each() -> None:
|
| 23 |
+
clear_jobs(get_test_jobs_directory())
|
| 24 |
+
init_jobs(get_test_jobs_directory())
|
| 25 |
+
prepare_test_output_directory()
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def test_swap_face_to_image() -> None:
|
| 29 |
+
commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_swapper', '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-swap-face-to-image.jpg') ]
|
| 30 |
+
|
| 31 |
+
assert subprocess.run(commands).returncode == 0
|
| 32 |
+
assert is_test_output_file('test-swap-face-to-image.jpg') is True
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def test_swap_face_to_video() -> None:
|
| 36 |
+
commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_swapper', '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test-swap-face-to-video.mp4'), '--trim-frame-end', '1' ]
|
| 37 |
+
|
| 38 |
+
assert subprocess.run(commands).returncode == 0
|
| 39 |
+
assert is_test_output_file('test-swap-face-to-video.mp4') is True
|
tests/test_cli_frame_colorizer.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import subprocess
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
from facefusion.download import conditional_download
|
| 7 |
+
from facefusion.jobs.job_manager import clear_jobs, init_jobs
|
| 8 |
+
from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
| 12 |
+
def before_all() -> None:
|
| 13 |
+
conditional_download(get_test_examples_directory(),
|
| 14 |
+
[
|
| 15 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
|
| 16 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
|
| 17 |
+
])
|
| 18 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', '-vf', 'hue=s=0', get_test_example_file('target-240p-0sat.jpg') ])
|
| 19 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vf', 'hue=s=0', get_test_example_file('target-240p-0sat.mp4') ])
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
@pytest.fixture(scope = 'function', autouse = True)
|
| 23 |
+
def before_each() -> None:
|
| 24 |
+
clear_jobs(get_test_jobs_directory())
|
| 25 |
+
init_jobs(get_test_jobs_directory())
|
| 26 |
+
prepare_test_output_directory()
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def test_colorize_frame_to_image() -> None:
|
| 30 |
+
commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'frame_colorizer', '-t', get_test_example_file('target-240p-0sat.jpg'), '-o', get_test_output_file('test_colorize-frame-to-image.jpg') ]
|
| 31 |
+
|
| 32 |
+
assert subprocess.run(commands).returncode == 0
|
| 33 |
+
assert is_test_output_file('test_colorize-frame-to-image.jpg') is True
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def test_colorize_frame_to_video() -> None:
|
| 37 |
+
commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'frame_colorizer', '-t', get_test_example_file('target-240p-0sat.mp4'), '-o', get_test_output_file('test-colorize-frame-to-video.mp4'), '--trim-frame-end', '1' ]
|
| 38 |
+
|
| 39 |
+
assert subprocess.run(commands).returncode == 0
|
| 40 |
+
assert is_test_output_file('test-colorize-frame-to-video.mp4') is True
|
tests/test_cli_frame_enhancer.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import subprocess
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
from facefusion.download import conditional_download
|
| 7 |
+
from facefusion.jobs.job_manager import clear_jobs, init_jobs
|
| 8 |
+
from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
| 12 |
+
def before_all() -> None:
|
| 13 |
+
conditional_download(get_test_examples_directory(),
|
| 14 |
+
[
|
| 15 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
|
| 16 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
|
| 17 |
+
])
|
| 18 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
@pytest.fixture(scope = 'function', autouse = True)
|
| 22 |
+
def before_each() -> None:
|
| 23 |
+
clear_jobs(get_test_jobs_directory())
|
| 24 |
+
init_jobs(get_test_jobs_directory())
|
| 25 |
+
prepare_test_output_directory()
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def test_enhance_frame_to_image() -> None:
|
| 29 |
+
commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'frame_enhancer', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-enhance-frame-to-image.jpg') ]
|
| 30 |
+
|
| 31 |
+
assert subprocess.run(commands).returncode == 0
|
| 32 |
+
assert is_test_output_file('test-enhance-frame-to-image.jpg') is True
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def test_enhance_frame_to_video() -> None:
|
| 36 |
+
commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'frame_enhancer', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test-enhance-frame-to-video.mp4'), '--trim-frame-end', '1' ]
|
| 37 |
+
|
| 38 |
+
assert subprocess.run(commands).returncode == 0
|
| 39 |
+
assert is_test_output_file('test-enhance-frame-to-video.mp4') is True
|
tests/test_cli_job_manager.py
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import subprocess
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
from facefusion.download import conditional_download
|
| 7 |
+
from facefusion.jobs.job_manager import clear_jobs, count_step_total, init_jobs
|
| 8 |
+
from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_job_file
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
| 12 |
+
def before_all() -> None:
|
| 13 |
+
conditional_download(get_test_examples_directory(),
|
| 14 |
+
[
|
| 15 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
|
| 16 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
|
| 17 |
+
])
|
| 18 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
@pytest.fixture(scope = 'function', autouse = True)
|
| 22 |
+
def before_each() -> None:
|
| 23 |
+
clear_jobs(get_test_jobs_directory())
|
| 24 |
+
init_jobs(get_test_jobs_directory())
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
@pytest.mark.skip()
|
| 28 |
+
def test_job_list() -> None:
|
| 29 |
+
pass
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def test_job_create() -> None:
|
| 33 |
+
commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-create', '--jobs-path', get_test_jobs_directory() ]
|
| 34 |
+
|
| 35 |
+
assert subprocess.run(commands).returncode == 0
|
| 36 |
+
assert is_test_job_file('test-job-create.json', 'drafted') is True
|
| 37 |
+
|
| 38 |
+
commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-create', '--jobs-path', get_test_jobs_directory() ]
|
| 39 |
+
|
| 40 |
+
assert subprocess.run(commands).returncode == 1
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def test_job_submit() -> None:
|
| 44 |
+
commands = [ sys.executable, 'facefusion.py', 'job-submit', 'test-job-submit', '--jobs-path', get_test_jobs_directory() ]
|
| 45 |
+
|
| 46 |
+
assert subprocess.run(commands).returncode == 1
|
| 47 |
+
|
| 48 |
+
commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-submit', '--jobs-path', get_test_jobs_directory() ]
|
| 49 |
+
subprocess.run(commands)
|
| 50 |
+
|
| 51 |
+
assert subprocess.run(commands).returncode == 1
|
| 52 |
+
|
| 53 |
+
commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-submit', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
|
| 54 |
+
subprocess.run(commands)
|
| 55 |
+
|
| 56 |
+
commands = [ sys.executable, 'facefusion.py', 'job-submit', 'test-job-submit', '--jobs-path', get_test_jobs_directory() ]
|
| 57 |
+
|
| 58 |
+
assert subprocess.run(commands).returncode == 0
|
| 59 |
+
assert is_test_job_file('test-job-submit.json', 'queued') is True
|
| 60 |
+
assert subprocess.run(commands).returncode == 1
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def test_submit_all() -> None:
|
| 64 |
+
commands = [ sys.executable, 'facefusion.py', 'job-submit-all', '--jobs-path', get_test_jobs_directory(), '--halt-on-error' ]
|
| 65 |
+
|
| 66 |
+
assert subprocess.run(commands).returncode == 1
|
| 67 |
+
|
| 68 |
+
commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-submit-all-1', '--jobs-path', get_test_jobs_directory() ]
|
| 69 |
+
subprocess.run(commands)
|
| 70 |
+
|
| 71 |
+
commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-submit-all-2', '--jobs-path', get_test_jobs_directory() ]
|
| 72 |
+
subprocess.run(commands)
|
| 73 |
+
|
| 74 |
+
assert subprocess.run(commands).returncode == 1
|
| 75 |
+
|
| 76 |
+
commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-submit-all-1', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
|
| 77 |
+
subprocess.run(commands)
|
| 78 |
+
|
| 79 |
+
commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-submit-all-2', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
|
| 80 |
+
subprocess.run(commands)
|
| 81 |
+
|
| 82 |
+
commands = [ sys.executable, 'facefusion.py', 'job-submit-all', '--jobs-path', get_test_jobs_directory(), '--halt-on-error' ]
|
| 83 |
+
|
| 84 |
+
assert subprocess.run(commands).returncode == 0
|
| 85 |
+
assert is_test_job_file('test-job-submit-all-1.json', 'queued') is True
|
| 86 |
+
assert is_test_job_file('test-job-submit-all-2.json', 'queued') is True
|
| 87 |
+
assert subprocess.run(commands).returncode == 1
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def test_job_delete() -> None:
|
| 91 |
+
commands = [ sys.executable, 'facefusion.py', 'job-delete', 'test-job-delete', '--jobs-path', get_test_jobs_directory() ]
|
| 92 |
+
|
| 93 |
+
assert subprocess.run(commands).returncode == 1
|
| 94 |
+
|
| 95 |
+
commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-delete', '--jobs-path', get_test_jobs_directory() ]
|
| 96 |
+
subprocess.run(commands)
|
| 97 |
+
|
| 98 |
+
commands = [ sys.executable, 'facefusion.py', 'job-delete', 'test-job-delete', '--jobs-path', get_test_jobs_directory() ]
|
| 99 |
+
|
| 100 |
+
assert subprocess.run(commands).returncode == 0
|
| 101 |
+
assert is_test_job_file('test-job-delete.json', 'drafted') is False
|
| 102 |
+
assert subprocess.run(commands).returncode == 1
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
def test_job_delete_all() -> None:
|
| 106 |
+
commands = [ sys.executable, 'facefusion.py', 'job-delete-all', '--jobs-path', get_test_jobs_directory(), '--halt-on-error' ]
|
| 107 |
+
|
| 108 |
+
assert subprocess.run(commands).returncode == 1
|
| 109 |
+
|
| 110 |
+
commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-delete-all-1', '--jobs-path', get_test_jobs_directory() ]
|
| 111 |
+
subprocess.run(commands)
|
| 112 |
+
|
| 113 |
+
commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-delete-all-2', '--jobs-path', get_test_jobs_directory() ]
|
| 114 |
+
subprocess.run(commands)
|
| 115 |
+
|
| 116 |
+
commands = [ sys.executable, 'facefusion.py', 'job-delete-all', '--jobs-path', get_test_jobs_directory(), '--halt-on-error' ]
|
| 117 |
+
|
| 118 |
+
assert subprocess.run(commands).returncode == 0
|
| 119 |
+
assert is_test_job_file('test-job-delete-all-1.json', 'drafted') is False
|
| 120 |
+
assert is_test_job_file('test-job-delete-all-2.json', 'drafted') is False
|
| 121 |
+
assert subprocess.run(commands).returncode == 1
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
def test_job_add_step() -> None:
|
| 125 |
+
commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-add-step', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
|
| 126 |
+
|
| 127 |
+
assert subprocess.run(commands).returncode == 1
|
| 128 |
+
assert count_step_total('test-job-add-step') == 0
|
| 129 |
+
|
| 130 |
+
commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-add-step', '--jobs-path', get_test_jobs_directory() ]
|
| 131 |
+
subprocess.run(commands)
|
| 132 |
+
|
| 133 |
+
commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-add-step', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
|
| 134 |
+
|
| 135 |
+
assert subprocess.run(commands).returncode == 0
|
| 136 |
+
assert count_step_total('test-job-add-step') == 1
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
def test_job_remix() -> None:
|
| 140 |
+
commands = [ sys.executable, 'facefusion.py', 'job-remix-step', 'test-job-remix-step', '0', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
|
| 141 |
+
|
| 142 |
+
assert subprocess.run(commands).returncode == 1
|
| 143 |
+
assert count_step_total('test-job-remix-step') == 0
|
| 144 |
+
|
| 145 |
+
commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-remix-step', '--jobs-path', get_test_jobs_directory() ]
|
| 146 |
+
subprocess.run(commands)
|
| 147 |
+
|
| 148 |
+
commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-remix-step', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
|
| 149 |
+
subprocess.run(commands)
|
| 150 |
+
|
| 151 |
+
commands = [ sys.executable, 'facefusion.py', 'job-remix-step', 'test-job-remix-step', '0', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
|
| 152 |
+
|
| 153 |
+
assert count_step_total('test-job-remix-step') == 1
|
| 154 |
+
assert subprocess.run(commands).returncode == 0
|
| 155 |
+
assert count_step_total('test-job-remix-step') == 2
|
| 156 |
+
|
| 157 |
+
commands = [ sys.executable, 'facefusion.py', 'job-remix-step', 'test-job-remix-step', '-1', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
|
| 158 |
+
|
| 159 |
+
assert subprocess.run(commands).returncode == 0
|
| 160 |
+
assert count_step_total('test-job-remix-step') == 3
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
def test_job_insert_step() -> None:
|
| 164 |
+
commands = [ sys.executable, 'facefusion.py', 'job-insert-step', 'test-job-insert-step', '0', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
|
| 165 |
+
|
| 166 |
+
assert subprocess.run(commands).returncode == 1
|
| 167 |
+
assert count_step_total('test-job-insert-step') == 0
|
| 168 |
+
|
| 169 |
+
commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-insert-step', '--jobs-path', get_test_jobs_directory() ]
|
| 170 |
+
subprocess.run(commands)
|
| 171 |
+
|
| 172 |
+
commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-insert-step', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
|
| 173 |
+
subprocess.run(commands)
|
| 174 |
+
|
| 175 |
+
commands = [ sys.executable, 'facefusion.py', 'job-insert-step', 'test-job-insert-step', '0', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
|
| 176 |
+
|
| 177 |
+
assert count_step_total('test-job-insert-step') == 1
|
| 178 |
+
assert subprocess.run(commands).returncode == 0
|
| 179 |
+
assert count_step_total('test-job-insert-step') == 2
|
| 180 |
+
|
| 181 |
+
commands = [ sys.executable, 'facefusion.py', 'job-insert-step', 'test-job-insert-step', '-1', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
|
| 182 |
+
|
| 183 |
+
assert subprocess.run(commands).returncode == 0
|
| 184 |
+
assert count_step_total('test-job-insert-step') == 3
|
| 185 |
+
|
| 186 |
+
|
| 187 |
+
def test_job_remove_step() -> None:
|
| 188 |
+
commands = [ sys.executable, 'facefusion.py', 'job-remove-step', 'test-job-remove-step', '0', '--jobs-path', get_test_jobs_directory() ]
|
| 189 |
+
|
| 190 |
+
assert subprocess.run(commands).returncode == 1
|
| 191 |
+
|
| 192 |
+
commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-remove-step', '--jobs-path', get_test_jobs_directory() ]
|
| 193 |
+
subprocess.run(commands)
|
| 194 |
+
|
| 195 |
+
commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-remove-step', '--jobs-path', get_test_jobs_directory(), '-s', get_test_example_file('source.jpg'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-remix-step.jpg') ]
|
| 196 |
+
subprocess.run(commands)
|
| 197 |
+
subprocess.run(commands)
|
| 198 |
+
|
| 199 |
+
commands = [ sys.executable, 'facefusion.py', 'job-remove-step', 'test-job-remove-step', '0', '--jobs-path', get_test_jobs_directory() ]
|
| 200 |
+
|
| 201 |
+
assert count_step_total('test-job-remove-step') == 2
|
| 202 |
+
assert subprocess.run(commands).returncode == 0
|
| 203 |
+
assert count_step_total('test-job-remove-step') == 1
|
| 204 |
+
|
| 205 |
+
commands = [ sys.executable, 'facefusion.py', 'job-remove-step', 'test-job-remove-step', '-1', '--jobs-path', get_test_jobs_directory() ]
|
| 206 |
+
|
| 207 |
+
assert subprocess.run(commands).returncode == 0
|
| 208 |
+
assert subprocess.run(commands).returncode == 1
|
| 209 |
+
assert count_step_total('test-job-remove-step') == 0
|
tests/test_cli_job_runner.py
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import subprocess
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
from facefusion.download import conditional_download
|
| 7 |
+
from facefusion.jobs.job_manager import clear_jobs, init_jobs, move_job_file, set_steps_status
|
| 8 |
+
from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
| 12 |
+
def before_all() -> None:
|
| 13 |
+
conditional_download(get_test_examples_directory(),
|
| 14 |
+
[
|
| 15 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
|
| 16 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
|
| 17 |
+
])
|
| 18 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
@pytest.fixture(scope = 'function', autouse = True)
|
| 22 |
+
def before_each() -> None:
|
| 23 |
+
clear_jobs(get_test_jobs_directory())
|
| 24 |
+
init_jobs(get_test_jobs_directory())
|
| 25 |
+
prepare_test_output_directory()
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def test_job_run() -> None:
|
| 29 |
+
commands = [ sys.executable, 'facefusion.py', 'job-run', 'test-job-run', '--jobs-path', get_test_jobs_directory() ]
|
| 30 |
+
|
| 31 |
+
assert subprocess.run(commands).returncode == 1
|
| 32 |
+
|
| 33 |
+
commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-run', '--jobs-path', get_test_jobs_directory() ]
|
| 34 |
+
subprocess.run(commands)
|
| 35 |
+
|
| 36 |
+
commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-run.jpg') ]
|
| 37 |
+
subprocess.run(commands)
|
| 38 |
+
|
| 39 |
+
commands = [ sys.executable, 'facefusion.py', 'job-run', 'test-job-run', '--jobs-path', get_test_jobs_directory() ]
|
| 40 |
+
|
| 41 |
+
assert subprocess.run(commands).returncode == 1
|
| 42 |
+
|
| 43 |
+
commands = [ sys.executable, 'facefusion.py', 'job-submit', 'test-job-run', '--jobs-path', get_test_jobs_directory() ]
|
| 44 |
+
subprocess.run(commands)
|
| 45 |
+
|
| 46 |
+
commands = [ sys.executable, 'facefusion.py', 'job-run', 'test-job-run', '--jobs-path', get_test_jobs_directory() ]
|
| 47 |
+
|
| 48 |
+
assert subprocess.run(commands).returncode == 0
|
| 49 |
+
assert subprocess.run(commands).returncode == 1
|
| 50 |
+
assert is_test_output_file('test-job-run.jpg') is True
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def test_job_run_all() -> None:
|
| 54 |
+
commands = [ sys.executable, 'facefusion.py', 'job-run-all', '--jobs-path', get_test_jobs_directory(), '--halt-on-error' ]
|
| 55 |
+
|
| 56 |
+
assert subprocess.run(commands).returncode == 1
|
| 57 |
+
|
| 58 |
+
commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-run-all-1', '--jobs-path', get_test_jobs_directory() ]
|
| 59 |
+
subprocess.run(commands)
|
| 60 |
+
|
| 61 |
+
commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-run-all-2', '--jobs-path', get_test_jobs_directory() ]
|
| 62 |
+
subprocess.run(commands)
|
| 63 |
+
|
| 64 |
+
commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-run-all-1', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-run-all-1.jpg') ]
|
| 65 |
+
subprocess.run(commands)
|
| 66 |
+
|
| 67 |
+
commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-run-all-2', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test-job-run-all-2.mp4'), '--trim-frame-end', '1' ]
|
| 68 |
+
subprocess.run(commands)
|
| 69 |
+
|
| 70 |
+
commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-run-all-2', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test-job-run-all-2.mp4'), '--trim-frame-start', '0', '--trim-frame-end', '1' ]
|
| 71 |
+
subprocess.run(commands)
|
| 72 |
+
|
| 73 |
+
commands = [ sys.executable, 'facefusion.py', 'job-run-all', '--jobs-path', get_test_jobs_directory(), '--halt-on-error' ]
|
| 74 |
+
|
| 75 |
+
assert subprocess.run(commands).returncode == 1
|
| 76 |
+
|
| 77 |
+
commands = [ sys.executable, 'facefusion.py', 'job-submit-all', '--jobs-path', get_test_jobs_directory(), '--halt-on-error' ]
|
| 78 |
+
subprocess.run(commands)
|
| 79 |
+
|
| 80 |
+
commands = [ sys.executable, 'facefusion.py', 'job-run-all', '--jobs-path', get_test_jobs_directory(), '--halt-on-error' ]
|
| 81 |
+
|
| 82 |
+
assert subprocess.run(commands).returncode == 0
|
| 83 |
+
assert subprocess.run(commands).returncode == 1
|
| 84 |
+
assert is_test_output_file('test-job-run-all-1.jpg') is True
|
| 85 |
+
assert is_test_output_file('test-job-run-all-2.mp4') is True
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
def test_job_retry() -> None:
|
| 89 |
+
commands = [ sys.executable, 'facefusion.py', 'job-retry', 'test-job-retry', '--jobs-path', get_test_jobs_directory() ]
|
| 90 |
+
|
| 91 |
+
assert subprocess.run(commands).returncode == 1
|
| 92 |
+
|
| 93 |
+
commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-retry', '--jobs-path', get_test_jobs_directory() ]
|
| 94 |
+
subprocess.run(commands)
|
| 95 |
+
|
| 96 |
+
commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-retry', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-retry.jpg') ]
|
| 97 |
+
subprocess.run(commands)
|
| 98 |
+
|
| 99 |
+
commands = [ sys.executable, 'facefusion.py', 'job-retry', 'test-job-retry', '--jobs-path', get_test_jobs_directory() ]
|
| 100 |
+
|
| 101 |
+
assert subprocess.run(commands).returncode == 1
|
| 102 |
+
|
| 103 |
+
set_steps_status('test-job-retry', 'failed')
|
| 104 |
+
move_job_file('test-job-retry', 'failed')
|
| 105 |
+
|
| 106 |
+
commands = [ sys.executable, 'facefusion.py', 'job-retry', 'test-job-retry', '--jobs-path', get_test_jobs_directory() ]
|
| 107 |
+
|
| 108 |
+
assert subprocess.run(commands).returncode == 0
|
| 109 |
+
assert subprocess.run(commands).returncode == 1
|
| 110 |
+
assert is_test_output_file('test-job-retry.jpg') is True
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
def test_job_retry_all() -> None:
|
| 114 |
+
commands = [ sys.executable, 'facefusion.py', 'job-retry-all', '--jobs-path', get_test_jobs_directory(), '--halt-on-error' ]
|
| 115 |
+
|
| 116 |
+
assert subprocess.run(commands).returncode == 1
|
| 117 |
+
|
| 118 |
+
commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-retry-all-1', '--jobs-path', get_test_jobs_directory() ]
|
| 119 |
+
subprocess.run(commands)
|
| 120 |
+
|
| 121 |
+
commands = [ sys.executable, 'facefusion.py', 'job-create', 'test-job-retry-all-2', '--jobs-path', get_test_jobs_directory() ]
|
| 122 |
+
subprocess.run(commands)
|
| 123 |
+
|
| 124 |
+
commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-retry-all-1', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test-job-retry-all-1.jpg') ]
|
| 125 |
+
subprocess.run(commands)
|
| 126 |
+
|
| 127 |
+
commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-retry-all-2', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test-job-retry-all-2.mp4'), '--trim-frame-end', '1' ]
|
| 128 |
+
subprocess.run(commands)
|
| 129 |
+
|
| 130 |
+
commands = [ sys.executable, 'facefusion.py', 'job-add-step', 'test-job-retry-all-2', '--jobs-path', get_test_jobs_directory(), '--processors', 'face_debugger', '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test-job-retry-all-2.mp4'), '--trim-frame-start', '0', '--trim-frame-end', '1' ]
|
| 131 |
+
subprocess.run(commands)
|
| 132 |
+
|
| 133 |
+
commands = [ sys.executable, 'facefusion.py', 'job-retry-all', '--jobs-path', get_test_jobs_directory(), '--halt-on-error' ]
|
| 134 |
+
|
| 135 |
+
assert subprocess.run(commands).returncode == 1
|
| 136 |
+
|
| 137 |
+
set_steps_status('test-job-retry-all-1', 'failed')
|
| 138 |
+
set_steps_status('test-job-retry-all-2', 'failed')
|
| 139 |
+
move_job_file('test-job-retry-all-1', 'failed')
|
| 140 |
+
move_job_file('test-job-retry-all-2', 'failed')
|
| 141 |
+
|
| 142 |
+
commands = [ sys.executable, 'facefusion.py', 'job-retry-all', '--jobs-path', get_test_jobs_directory(), '--halt-on-error' ]
|
| 143 |
+
|
| 144 |
+
assert subprocess.run(commands).returncode == 0
|
| 145 |
+
assert subprocess.run(commands).returncode == 1
|
| 146 |
+
assert is_test_output_file('test-job-retry-all-1.jpg') is True
|
| 147 |
+
assert is_test_output_file('test-job-retry-all-2.mp4') is True
|
tests/test_cli_lip_syncer.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import subprocess
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
from facefusion.download import conditional_download
|
| 7 |
+
from facefusion.jobs.job_manager import clear_jobs, init_jobs
|
| 8 |
+
from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
| 12 |
+
def before_all() -> None:
|
| 13 |
+
conditional_download(get_test_examples_directory(),
|
| 14 |
+
[
|
| 15 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
|
| 16 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.mp3',
|
| 17 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
|
| 18 |
+
])
|
| 19 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
@pytest.fixture(scope = 'function', autouse = True)
|
| 23 |
+
def before_each() -> None:
|
| 24 |
+
clear_jobs(get_test_jobs_directory())
|
| 25 |
+
init_jobs(get_test_jobs_directory())
|
| 26 |
+
prepare_test_output_directory()
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def test_sync_lip_to_image() -> None:
|
| 30 |
+
commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'lip_syncer', '-s', get_test_example_file('source.mp3'), '-t', get_test_example_file('target-240p.jpg'), '-o', get_test_output_file('test_sync_lip_to_image.jpg') ]
|
| 31 |
+
|
| 32 |
+
assert subprocess.run(commands).returncode == 0
|
| 33 |
+
assert is_test_output_file('test_sync_lip_to_image.jpg') is True
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def test_sync_lip_to_video() -> None:
|
| 37 |
+
commands = [ sys.executable, 'facefusion.py', 'headless-run', '--jobs-path', get_test_jobs_directory(), '--processors', 'lip_syncer', '-s', get_test_example_file('source.mp3'), '-t', get_test_example_file('target-240p.mp4'), '-o', get_test_output_file('test_sync_lip_to_video.mp4'), '--trim-frame-end', '1' ]
|
| 38 |
+
|
| 39 |
+
assert subprocess.run(commands).returncode == 0
|
| 40 |
+
assert is_test_output_file('test_sync_lip_to_video.mp4') is True
|
tests/test_common_helper.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from facefusion.common_helper import calc_float_step, calc_int_step, create_float_metavar, create_float_range, create_int_metavar, create_int_range
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
def test_create_int_metavar() -> None:
|
| 5 |
+
assert create_int_metavar([ 1, 2, 3, 4, 5 ]) == '[1..5:1]'
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def test_create_float_metavar() -> None:
|
| 9 |
+
assert create_float_metavar([ 0.1, 0.2, 0.3, 0.4, 0.5 ]) == '[0.1..0.5:0.1]'
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def test_create_int_range() -> None:
|
| 13 |
+
assert create_int_range(0, 2, 1) == [ 0, 1, 2 ]
|
| 14 |
+
assert create_float_range(0, 1, 1) == [ 0, 1 ]
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
def test_create_float_range() -> None:
|
| 18 |
+
assert create_float_range(0.0, 1.0, 0.5) == [ 0.0, 0.5, 1.0 ]
|
| 19 |
+
assert create_float_range(0.0, 1.0, 0.05) == [ 0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.0 ]
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def test_calc_int_step() -> None:
|
| 23 |
+
assert calc_int_step([ 0, 1 ]) == 1
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def test_calc_float_step() -> None:
|
| 27 |
+
assert calc_float_step([ 0.1, 0.2 ]) == 0.1
|
tests/test_config.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from configparser import ConfigParser
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
|
| 5 |
+
from facefusion import config
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
| 9 |
+
def before_all() -> None:
|
| 10 |
+
config.CONFIG_PARSER = ConfigParser()
|
| 11 |
+
config.CONFIG_PARSER.read_dict(
|
| 12 |
+
{
|
| 13 |
+
'str':
|
| 14 |
+
{
|
| 15 |
+
'valid': 'a',
|
| 16 |
+
'unset': ''
|
| 17 |
+
},
|
| 18 |
+
'int':
|
| 19 |
+
{
|
| 20 |
+
'valid': '1',
|
| 21 |
+
'unset': ''
|
| 22 |
+
},
|
| 23 |
+
'float':
|
| 24 |
+
{
|
| 25 |
+
'valid': '1.0',
|
| 26 |
+
'unset': ''
|
| 27 |
+
},
|
| 28 |
+
'bool':
|
| 29 |
+
{
|
| 30 |
+
'valid': 'True',
|
| 31 |
+
'unset': ''
|
| 32 |
+
},
|
| 33 |
+
'str_list':
|
| 34 |
+
{
|
| 35 |
+
'valid': 'a b c',
|
| 36 |
+
'unset': ''
|
| 37 |
+
},
|
| 38 |
+
'int_list':
|
| 39 |
+
{
|
| 40 |
+
'valid': '1 2 3',
|
| 41 |
+
'unset': ''
|
| 42 |
+
}
|
| 43 |
+
})
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def test_get_str_value() -> None:
|
| 47 |
+
assert config.get_str_value('str', 'valid') == 'a'
|
| 48 |
+
assert config.get_str_value('str', 'unset', 'b') == 'b'
|
| 49 |
+
assert config.get_str_value('str', 'unset') is None
|
| 50 |
+
assert config.get_str_value('str', 'invalid') is None
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def test_get_int_value() -> None:
|
| 54 |
+
assert config.get_int_value('int', 'valid') == 1
|
| 55 |
+
assert config.get_int_value('int', 'unset', '1') == 1
|
| 56 |
+
assert config.get_int_value('int', 'unset') is None
|
| 57 |
+
assert config.get_int_value('int', 'invalid') is None
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def test_get_float_value() -> None:
|
| 61 |
+
assert config.get_float_value('float', 'valid') == 1.0
|
| 62 |
+
assert config.get_float_value('float', 'unset', '1.0') == 1.0
|
| 63 |
+
assert config.get_float_value('float', 'unset') is None
|
| 64 |
+
assert config.get_float_value('float', 'invalid') is None
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
def test_get_bool_value() -> None:
|
| 68 |
+
assert config.get_bool_value('bool', 'valid') is True
|
| 69 |
+
assert config.get_bool_value('bool', 'unset', 'False') is False
|
| 70 |
+
assert config.get_bool_value('bool', 'unset') is None
|
| 71 |
+
assert config.get_bool_value('bool', 'invalid') is None
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
def test_get_str_list() -> None:
|
| 75 |
+
assert config.get_str_list('str_list', 'valid') == [ 'a', 'b', 'c' ]
|
| 76 |
+
assert config.get_str_list('str_list', 'unset', 'c b a') == [ 'c', 'b', 'a' ]
|
| 77 |
+
assert config.get_str_list('str_list', 'unset') is None
|
| 78 |
+
assert config.get_str_list('str_list', 'invalid') is None
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
def test_get_int_list() -> None:
|
| 82 |
+
assert config.get_int_list('int_list', 'valid') == [ 1, 2, 3 ]
|
| 83 |
+
assert config.get_int_list('int_list', 'unset', '3 2 1') == [ 3, 2, 1 ]
|
| 84 |
+
assert config.get_int_list('int_list', 'unset') is None
|
| 85 |
+
assert config.get_int_list('int_list', 'invalid') is None
|
tests/test_curl_builder.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from shutil import which
|
| 2 |
+
|
| 3 |
+
from facefusion import metadata
|
| 4 |
+
from facefusion.curl_builder import chain, head, run
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def test_run() -> None:
|
| 8 |
+
user_agent = metadata.get('name') + '/' + metadata.get('version')
|
| 9 |
+
|
| 10 |
+
assert run([]) == [ which('curl'), '--user-agent', user_agent, '--insecure', '--location', '--silent' ]
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def test_chain() -> None:
|
| 14 |
+
assert chain(head(metadata.get('url'))) == [ '-I', metadata.get('url') ]
|
tests/test_date_helper.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from datetime import datetime, timedelta
|
| 2 |
+
|
| 3 |
+
from facefusion.date_helper import describe_time_ago
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
def get_time_ago(days : int, hours : int, minutes : int) -> datetime:
|
| 7 |
+
previous_time = datetime.now() - timedelta(days = days, hours = hours, minutes = minutes)
|
| 8 |
+
return previous_time.astimezone()
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def test_describe_time_ago() -> None:
|
| 12 |
+
assert describe_time_ago(get_time_ago(0, 0, 0)) == 'just now'
|
| 13 |
+
assert describe_time_ago(get_time_ago(0, 0, 10)) == '10 minutes ago'
|
| 14 |
+
assert describe_time_ago(get_time_ago(0, 5, 10)) == '5 hours and 10 minutes ago'
|
| 15 |
+
assert describe_time_ago(get_time_ago(1, 5, 10)) == '1 days, 5 hours and 10 minutes ago'
|
tests/test_download.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from facefusion.download import get_static_download_size, ping_static_url, resolve_download_url_by_provider
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
def test_get_static_download_size() -> None:
|
| 5 |
+
assert get_static_download_size('https://github.com/facefusion/facefusion-assets/releases/download/models-3.0.0/fairface.onnx') == 85170772
|
| 6 |
+
assert get_static_download_size('https://huggingface.co/facefusion/models-3.0.0/resolve/main/fairface.onnx') == 85170772
|
| 7 |
+
assert get_static_download_size('invalid') == 0
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def test_static_ping_url() -> None:
|
| 11 |
+
assert ping_static_url('https://github.com') is True
|
| 12 |
+
assert ping_static_url('https://huggingface.co') is True
|
| 13 |
+
assert ping_static_url('invalid') is False
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def test_resolve_download_url_by_provider() -> None:
|
| 17 |
+
assert resolve_download_url_by_provider('github', 'models-3.0.0', 'fairface.onnx') == 'https://github.com/facefusion/facefusion-assets/releases/download/models-3.0.0/fairface.onnx'
|
| 18 |
+
assert resolve_download_url_by_provider('huggingface', 'models-3.0.0', 'fairface.onnx') == 'https://huggingface.co/facefusion/models-3.0.0/resolve/main/fairface.onnx'
|
tests/test_execution.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from facefusion.execution import create_inference_session_providers, get_available_execution_providers, has_execution_provider
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
def test_has_execution_provider() -> None:
|
| 5 |
+
assert has_execution_provider('cpu') is True
|
| 6 |
+
assert has_execution_provider('openvino') is False
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def test_get_available_execution_providers() -> None:
|
| 10 |
+
assert 'cpu' in get_available_execution_providers()
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def test_create_inference_session_providers() -> None:
|
| 14 |
+
inference_session_providers =\
|
| 15 |
+
[
|
| 16 |
+
('CUDAExecutionProvider',
|
| 17 |
+
{
|
| 18 |
+
'device_id': '1',
|
| 19 |
+
'cudnn_conv_algo_search': 'EXHAUSTIVE'
|
| 20 |
+
}),
|
| 21 |
+
'CPUExecutionProvider'
|
| 22 |
+
]
|
| 23 |
+
|
| 24 |
+
assert create_inference_session_providers('1', [ 'cpu', 'cuda' ]) == inference_session_providers
|
tests/test_face_analyser.py
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import subprocess
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
|
| 5 |
+
from facefusion import face_classifier, face_detector, face_landmarker, face_recognizer, state_manager
|
| 6 |
+
from facefusion.download import conditional_download
|
| 7 |
+
from facefusion.face_analyser import get_many_faces, get_one_face
|
| 8 |
+
from facefusion.types import Face
|
| 9 |
+
from facefusion.vision import read_static_image
|
| 10 |
+
from .helper import get_test_example_file, get_test_examples_directory
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
| 14 |
+
def before_all() -> None:
|
| 15 |
+
conditional_download(get_test_examples_directory(),
|
| 16 |
+
[
|
| 17 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg'
|
| 18 |
+
])
|
| 19 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.jpg'), '-vf', 'crop=iw*0.8:ih*0.8', get_test_example_file('source-80crop.jpg') ])
|
| 20 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.jpg'), '-vf', 'crop=iw*0.7:ih*0.7', get_test_example_file('source-70crop.jpg') ])
|
| 21 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.jpg'), '-vf', 'crop=iw*0.6:ih*0.6', get_test_example_file('source-60crop.jpg') ])
|
| 22 |
+
state_manager.init_item('execution_device_id', '0')
|
| 23 |
+
state_manager.init_item('execution_providers', [ 'cpu' ])
|
| 24 |
+
state_manager.init_item('download_providers', [ 'github' ])
|
| 25 |
+
state_manager.init_item('face_detector_angles', [ 0 ])
|
| 26 |
+
state_manager.init_item('face_detector_model', 'many')
|
| 27 |
+
state_manager.init_item('face_detector_score', 0.5)
|
| 28 |
+
state_manager.init_item('face_landmarker_model', 'many')
|
| 29 |
+
state_manager.init_item('face_landmarker_score', 0.5)
|
| 30 |
+
face_classifier.pre_check()
|
| 31 |
+
face_landmarker.pre_check()
|
| 32 |
+
face_recognizer.pre_check()
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
@pytest.fixture(autouse = True)
|
| 36 |
+
def before_each() -> None:
|
| 37 |
+
face_classifier.clear_inference_pool()
|
| 38 |
+
face_detector.clear_inference_pool()
|
| 39 |
+
face_landmarker.clear_inference_pool()
|
| 40 |
+
face_recognizer.clear_inference_pool()
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def test_get_one_face_with_retinaface() -> None:
|
| 44 |
+
state_manager.init_item('face_detector_model', 'retinaface')
|
| 45 |
+
state_manager.init_item('face_detector_size', '320x320')
|
| 46 |
+
face_detector.pre_check()
|
| 47 |
+
|
| 48 |
+
source_paths =\
|
| 49 |
+
[
|
| 50 |
+
get_test_example_file('source.jpg'),
|
| 51 |
+
get_test_example_file('source-80crop.jpg'),
|
| 52 |
+
get_test_example_file('source-70crop.jpg'),
|
| 53 |
+
get_test_example_file('source-60crop.jpg')
|
| 54 |
+
]
|
| 55 |
+
|
| 56 |
+
for source_path in source_paths:
|
| 57 |
+
source_frame = read_static_image(source_path)
|
| 58 |
+
many_faces = get_many_faces([ source_frame ])
|
| 59 |
+
face = get_one_face(many_faces)
|
| 60 |
+
|
| 61 |
+
assert isinstance(face, Face)
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def test_get_one_face_with_scrfd() -> None:
|
| 65 |
+
state_manager.init_item('face_detector_model', 'scrfd')
|
| 66 |
+
state_manager.init_item('face_detector_size', '640x640')
|
| 67 |
+
face_detector.pre_check()
|
| 68 |
+
|
| 69 |
+
source_paths =\
|
| 70 |
+
[
|
| 71 |
+
get_test_example_file('source.jpg'),
|
| 72 |
+
get_test_example_file('source-80crop.jpg'),
|
| 73 |
+
get_test_example_file('source-70crop.jpg'),
|
| 74 |
+
get_test_example_file('source-60crop.jpg')
|
| 75 |
+
]
|
| 76 |
+
|
| 77 |
+
for source_path in source_paths:
|
| 78 |
+
source_frame = read_static_image(source_path)
|
| 79 |
+
many_faces = get_many_faces([ source_frame ])
|
| 80 |
+
face = get_one_face(many_faces)
|
| 81 |
+
|
| 82 |
+
assert isinstance(face, Face)
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
def test_get_one_face_with_yoloface() -> None:
|
| 86 |
+
state_manager.init_item('face_detector_model', 'yoloface')
|
| 87 |
+
state_manager.init_item('face_detector_size', '640x640')
|
| 88 |
+
face_detector.pre_check()
|
| 89 |
+
|
| 90 |
+
source_paths =\
|
| 91 |
+
[
|
| 92 |
+
get_test_example_file('source.jpg'),
|
| 93 |
+
get_test_example_file('source-80crop.jpg'),
|
| 94 |
+
get_test_example_file('source-70crop.jpg'),
|
| 95 |
+
get_test_example_file('source-60crop.jpg')
|
| 96 |
+
]
|
| 97 |
+
|
| 98 |
+
for source_path in source_paths:
|
| 99 |
+
source_frame = read_static_image(source_path)
|
| 100 |
+
many_faces = get_many_faces([ source_frame ])
|
| 101 |
+
face = get_one_face(many_faces)
|
| 102 |
+
|
| 103 |
+
assert isinstance(face, Face)
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
def test_get_many_faces() -> None:
|
| 107 |
+
source_path = get_test_example_file('source.jpg')
|
| 108 |
+
source_frame = read_static_image(source_path)
|
| 109 |
+
many_faces = get_many_faces([ source_frame, source_frame, source_frame ])
|
| 110 |
+
|
| 111 |
+
assert isinstance(many_faces[0], Face)
|
| 112 |
+
assert isinstance(many_faces[1], Face)
|
| 113 |
+
assert isinstance(many_faces[2], Face)
|
tests/test_ffmpeg.py
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import subprocess
|
| 2 |
+
import tempfile
|
| 3 |
+
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
from facefusion import process_manager, state_manager
|
| 7 |
+
from facefusion.download import conditional_download
|
| 8 |
+
from facefusion.ffmpeg import concat_video, extract_frames, get_available_encoder_set, read_audio_buffer, replace_audio, restore_audio
|
| 9 |
+
from facefusion.filesystem import copy_file
|
| 10 |
+
from facefusion.temp_helper import clear_temp_directory, create_temp_directory, get_temp_file_path, resolve_temp_frame_paths
|
| 11 |
+
from .helper import get_test_example_file, get_test_examples_directory, get_test_output_file, prepare_test_output_directory
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
| 15 |
+
def before_all() -> None:
|
| 16 |
+
process_manager.start()
|
| 17 |
+
conditional_download(get_test_examples_directory(),
|
| 18 |
+
[
|
| 19 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
|
| 20 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.mp3',
|
| 21 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
|
| 22 |
+
])
|
| 23 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.mp3'), get_test_example_file('source.wav') ])
|
| 24 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vf', 'fps=25', get_test_example_file('target-240p-25fps.mp4') ])
|
| 25 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vf', 'fps=30', get_test_example_file('target-240p-30fps.mp4') ])
|
| 26 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vf', 'fps=60', get_test_example_file('target-240p-60fps.mp4') ])
|
| 27 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.mp3'), '-i', get_test_example_file('target-240p.mp4'), '-ar', '16000', get_test_example_file('target-240p-16khz.mp4') ])
|
| 28 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('source.mp3'), '-i', get_test_example_file('target-240p.mp4'), '-ar', '48000', get_test_example_file('target-240p-48khz.mp4') ])
|
| 29 |
+
state_manager.init_item('temp_path', tempfile.gettempdir())
|
| 30 |
+
state_manager.init_item('temp_frame_format', 'png')
|
| 31 |
+
state_manager.init_item('output_audio_encoder', 'aac')
|
| 32 |
+
state_manager.init_item('output_audio_quality', 80)
|
| 33 |
+
state_manager.init_item('output_audio_volume', 100)
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
@pytest.fixture(scope = 'function', autouse = True)
|
| 37 |
+
def before_each() -> None:
|
| 38 |
+
prepare_test_output_directory()
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
@pytest.mark.skip()
|
| 42 |
+
def test_get_available_encoder_set() -> None:
|
| 43 |
+
available_encoder_set = get_available_encoder_set()
|
| 44 |
+
|
| 45 |
+
assert 'aac' in available_encoder_set.get('audio')
|
| 46 |
+
assert 'libx264' in available_encoder_set.get('video')
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def test_extract_frames() -> None:
|
| 50 |
+
extract_set =\
|
| 51 |
+
[
|
| 52 |
+
(get_test_example_file('target-240p-25fps.mp4'), 0, 270, 324),
|
| 53 |
+
(get_test_example_file('target-240p-25fps.mp4'), 224, 270, 55),
|
| 54 |
+
(get_test_example_file('target-240p-25fps.mp4'), 124, 224, 120),
|
| 55 |
+
(get_test_example_file('target-240p-25fps.mp4'), 0, 100, 120),
|
| 56 |
+
(get_test_example_file('target-240p-30fps.mp4'), 0, 324, 324),
|
| 57 |
+
(get_test_example_file('target-240p-30fps.mp4'), 224, 324, 100),
|
| 58 |
+
(get_test_example_file('target-240p-30fps.mp4'), 124, 224, 100),
|
| 59 |
+
(get_test_example_file('target-240p-30fps.mp4'), 0, 100, 100),
|
| 60 |
+
(get_test_example_file('target-240p-60fps.mp4'), 0, 648, 324),
|
| 61 |
+
(get_test_example_file('target-240p-60fps.mp4'), 224, 648, 212),
|
| 62 |
+
(get_test_example_file('target-240p-60fps.mp4'), 124, 224, 50),
|
| 63 |
+
(get_test_example_file('target-240p-60fps.mp4'), 0, 100, 50)
|
| 64 |
+
]
|
| 65 |
+
|
| 66 |
+
for target_path, trim_frame_start, trim_frame_end, frame_total in extract_set:
|
| 67 |
+
create_temp_directory(target_path)
|
| 68 |
+
|
| 69 |
+
assert extract_frames(target_path, '452x240', 30.0, trim_frame_start, trim_frame_end) is True
|
| 70 |
+
assert len(resolve_temp_frame_paths(target_path)) == frame_total
|
| 71 |
+
|
| 72 |
+
clear_temp_directory(target_path)
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def test_concat_video() -> None:
|
| 76 |
+
output_path = get_test_output_file('test-concat-video.mp4')
|
| 77 |
+
temp_output_paths =\
|
| 78 |
+
[
|
| 79 |
+
get_test_example_file('target-240p.mp4'),
|
| 80 |
+
get_test_example_file('target-240p.mp4')
|
| 81 |
+
]
|
| 82 |
+
|
| 83 |
+
assert concat_video(output_path, temp_output_paths) is True
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
def test_read_audio_buffer() -> None:
|
| 87 |
+
assert isinstance(read_audio_buffer(get_test_example_file('source.mp3'), 1, 16, 1), bytes)
|
| 88 |
+
assert isinstance(read_audio_buffer(get_test_example_file('source.wav'), 1, 16, 1), bytes)
|
| 89 |
+
assert read_audio_buffer(get_test_example_file('invalid.mp3'), 1, 16, 1) is None
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
def test_restore_audio() -> None:
|
| 93 |
+
target_paths =\
|
| 94 |
+
[
|
| 95 |
+
get_test_example_file('target-240p-16khz.mp4'),
|
| 96 |
+
get_test_example_file('target-240p-48khz.mp4')
|
| 97 |
+
]
|
| 98 |
+
output_path = get_test_output_file('test-restore-audio.mp4')
|
| 99 |
+
|
| 100 |
+
for target_path in target_paths:
|
| 101 |
+
create_temp_directory(target_path)
|
| 102 |
+
copy_file(target_path, get_temp_file_path(target_path))
|
| 103 |
+
|
| 104 |
+
assert restore_audio(target_path, output_path, 0, 270) is True
|
| 105 |
+
|
| 106 |
+
clear_temp_directory(target_path)
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
def test_replace_audio() -> None:
|
| 110 |
+
target_path = get_test_example_file('target-240p.mp4')
|
| 111 |
+
output_path = get_test_output_file('test-replace-audio.mp4')
|
| 112 |
+
|
| 113 |
+
create_temp_directory(target_path)
|
| 114 |
+
copy_file(target_path, get_temp_file_path(target_path))
|
| 115 |
+
|
| 116 |
+
assert replace_audio(target_path, get_test_example_file('source.mp3'), output_path) is True
|
| 117 |
+
assert replace_audio(target_path, get_test_example_file('source.wav'), output_path) is True
|
| 118 |
+
|
| 119 |
+
clear_temp_directory(target_path)
|
tests/test_ffmpeg_builder.py
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from shutil import which
|
| 2 |
+
|
| 3 |
+
from facefusion import ffmpeg_builder
|
| 4 |
+
from facefusion.ffmpeg_builder import chain, run, select_frame_range, set_audio_quality, set_audio_sample_size, set_stream_mode, set_video_quality
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def test_run() -> None:
|
| 8 |
+
assert run([]) == [ which('ffmpeg'), '-loglevel', 'error' ]
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def test_chain() -> None:
|
| 12 |
+
assert chain(ffmpeg_builder.set_progress()) == [ '-progress' ]
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def test_set_stream_mode() -> None:
|
| 16 |
+
assert set_stream_mode('udp') == [ '-f', 'mpegts' ]
|
| 17 |
+
assert set_stream_mode('v4l2') == [ '-f', 'v4l2' ]
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def test_select_frame_range() -> None:
|
| 21 |
+
assert select_frame_range(0, None, 30) == [ '-vf', 'trim=start_frame=0,fps=30' ]
|
| 22 |
+
assert select_frame_range(None, 100, 30) == [ '-vf', 'trim=end_frame=100,fps=30' ]
|
| 23 |
+
assert select_frame_range(0, 100, 30) == [ '-vf', 'trim=start_frame=0:end_frame=100,fps=30' ]
|
| 24 |
+
assert select_frame_range(None, None, 30) == [ '-vf', 'fps=30' ]
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def test_set_audio_sample_size() -> None:
|
| 28 |
+
assert set_audio_sample_size(16) == [ '-f', 's16le' ]
|
| 29 |
+
assert set_audio_sample_size(32) == [ '-f', 's32le' ]
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def test_set_audio_quality() -> None:
|
| 33 |
+
assert set_audio_quality('aac', 0) == [ '-q:a', '0.1' ]
|
| 34 |
+
assert set_audio_quality('aac', 50) == [ '-q:a', '1.0' ]
|
| 35 |
+
assert set_audio_quality('aac', 100) == [ '-q:a', '2.0' ]
|
| 36 |
+
assert set_audio_quality('libmp3lame', 0) == [ '-q:a', '9' ]
|
| 37 |
+
assert set_audio_quality('libmp3lame', 50) == [ '-q:a', '4' ]
|
| 38 |
+
assert set_audio_quality('libmp3lame', 100) == [ '-q:a', '0' ]
|
| 39 |
+
assert set_audio_quality('libopus', 0) == [ '-b:a', '64k' ]
|
| 40 |
+
assert set_audio_quality('libopus', 50) == [ '-b:a', '192k' ]
|
| 41 |
+
assert set_audio_quality('libopus', 100) == [ '-b:a', '320k' ]
|
| 42 |
+
assert set_audio_quality('libvorbis', 0) == [ '-q:a', '-1.0' ]
|
| 43 |
+
assert set_audio_quality('libvorbis', 50) == [ '-q:a', '4.5' ]
|
| 44 |
+
assert set_audio_quality('libvorbis', 100) == [ '-q:a', '10.0' ]
|
| 45 |
+
assert set_audio_quality('flac', 0) == []
|
| 46 |
+
assert set_audio_quality('flac', 50) == []
|
| 47 |
+
assert set_audio_quality('flac', 100) == []
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def test_set_video_quality() -> None:
|
| 51 |
+
assert set_video_quality('libx264', 0) == [ '-crf', '51' ]
|
| 52 |
+
assert set_video_quality('libx264', 50) == [ '-crf', '26' ]
|
| 53 |
+
assert set_video_quality('libx264', 100) == [ '-crf', '0' ]
|
| 54 |
+
assert set_video_quality('libx265', 0) == [ '-crf', '51' ]
|
| 55 |
+
assert set_video_quality('libx265', 50) == [ '-crf', '26' ]
|
| 56 |
+
assert set_video_quality('libx265', 100) == [ '-crf', '0' ]
|
| 57 |
+
assert set_video_quality('libvpx-vp9', 0) == [ '-crf', '63' ]
|
| 58 |
+
assert set_video_quality('libvpx-vp9', 50) == [ '-crf', '32' ]
|
| 59 |
+
assert set_video_quality('libvpx-vp9', 100) == [ '-crf', '0' ]
|
| 60 |
+
assert set_video_quality('h264_nvenc', 0) == [ '-cq' , '51' ]
|
| 61 |
+
assert set_video_quality('h264_nvenc', 50) == [ '-cq' , '26' ]
|
| 62 |
+
assert set_video_quality('h264_nvenc', 100) == [ '-cq' , '0' ]
|
| 63 |
+
assert set_video_quality('hevc_nvenc', 0) == [ '-cq' , '51' ]
|
| 64 |
+
assert set_video_quality('hevc_nvenc', 50) == [ '-cq' , '26' ]
|
| 65 |
+
assert set_video_quality('hevc_nvenc', 100) == [ '-cq' , '0' ]
|
| 66 |
+
assert set_video_quality('h264_amf', 0) == [ '-qp_i', '51', '-qp_p', '51', '-qp_b', '51' ]
|
| 67 |
+
assert set_video_quality('h264_amf', 50) == [ '-qp_i', '26', '-qp_p', '26', '-qp_b', '26' ]
|
| 68 |
+
assert set_video_quality('h264_amf', 100) == [ '-qp_i', '0', '-qp_p', '0', '-qp_b', '0' ]
|
| 69 |
+
assert set_video_quality('hevc_amf', 0) == [ '-qp_i', '51', '-qp_p', '51', '-qp_b', '51' ]
|
| 70 |
+
assert set_video_quality('hevc_amf', 50) == [ '-qp_i', '26', '-qp_p', '26', '-qp_b', '26' ]
|
| 71 |
+
assert set_video_quality('hevc_amf', 100) == [ '-qp_i', '0', '-qp_p', '0', '-qp_b', '0' ]
|
| 72 |
+
assert set_video_quality('h264_qsv', 0) == [ '-qp', '51' ]
|
| 73 |
+
assert set_video_quality('h264_qsv', 50) == [ '-qp', '26' ]
|
| 74 |
+
assert set_video_quality('h264_qsv', 100) == [ '-qp', '0' ]
|
| 75 |
+
assert set_video_quality('hevc_qsv', 0) == [ '-qp', '51' ]
|
| 76 |
+
assert set_video_quality('hevc_qsv', 50) == [ '-qp', '26' ]
|
| 77 |
+
assert set_video_quality('hevc_qsv', 100) == [ '-qp', '0' ]
|
| 78 |
+
assert set_video_quality('h264_videotoolbox', 0) == [ '-b:v', '1024k' ]
|
| 79 |
+
assert set_video_quality('h264_videotoolbox', 50) == [ '-b:v', '25768k' ]
|
| 80 |
+
assert set_video_quality('h264_videotoolbox', 100) == [ '-b:v', '50512k' ]
|
| 81 |
+
assert set_video_quality('hevc_videotoolbox', 0) == [ '-b:v', '1024k' ]
|
| 82 |
+
assert set_video_quality('hevc_videotoolbox', 50) == [ '-b:v', '25768k' ]
|
| 83 |
+
assert set_video_quality('hevc_videotoolbox', 100) == [ '-b:v', '50512k' ]
|
tests/test_filesystem.py
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os.path
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
|
| 5 |
+
from facefusion.download import conditional_download
|
| 6 |
+
from facefusion.filesystem import create_directory, filter_audio_paths, filter_image_paths, get_file_extension, get_file_format, get_file_size, has_audio, has_image, has_video, in_directory, is_audio, is_directory, is_file, is_image, is_video, remove_directory, resolve_file_paths, same_file_extension
|
| 7 |
+
from .helper import get_test_example_file, get_test_examples_directory, get_test_outputs_directory
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
| 11 |
+
def before_all() -> None:
|
| 12 |
+
conditional_download(get_test_examples_directory(),
|
| 13 |
+
[
|
| 14 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
|
| 15 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.mp3',
|
| 16 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
|
| 17 |
+
])
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def test_get_file_size() -> None:
|
| 21 |
+
assert get_file_size(get_test_example_file('source.jpg')) == 549458
|
| 22 |
+
assert get_file_size('invalid') == 0
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def test_get_file_extension() -> None:
|
| 26 |
+
assert get_file_extension('source.jpg') == '.jpg'
|
| 27 |
+
assert get_file_extension('source.mp3') == '.mp3'
|
| 28 |
+
assert get_file_extension('invalid') is None
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def test_get_file_format() -> None:
|
| 32 |
+
assert get_file_format('source.jpg') == 'jpeg'
|
| 33 |
+
assert get_file_format('source.jpeg') == 'jpeg'
|
| 34 |
+
assert get_file_format('source.mp3') == 'mp3'
|
| 35 |
+
assert get_file_format('invalid') is None
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def test_same_file_extension() -> None:
|
| 39 |
+
assert same_file_extension('source.jpg', 'source.jpg') is True
|
| 40 |
+
assert same_file_extension('source.jpg', 'source.mp3') is False
|
| 41 |
+
assert same_file_extension('invalid', 'invalid') is False
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def test_is_file() -> None:
|
| 45 |
+
assert is_file(get_test_example_file('source.jpg')) is True
|
| 46 |
+
assert is_file(get_test_examples_directory()) is False
|
| 47 |
+
assert is_file('invalid') is False
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def test_is_audio() -> None:
|
| 51 |
+
assert is_audio(get_test_example_file('source.mp3')) is True
|
| 52 |
+
assert is_audio(get_test_example_file('source.jpg')) is False
|
| 53 |
+
assert is_audio('invalid') is False
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
def test_has_audio() -> None:
|
| 57 |
+
assert has_audio([ get_test_example_file('source.mp3') ]) is True
|
| 58 |
+
assert has_audio([ get_test_example_file('source.mp3'), get_test_example_file('source.jpg') ]) is True
|
| 59 |
+
assert has_audio([ get_test_example_file('source.jpg'), get_test_example_file('source.jpg') ]) is False
|
| 60 |
+
assert has_audio([ 'invalid' ]) is False
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def test_is_image() -> None:
|
| 64 |
+
assert is_image(get_test_example_file('source.jpg')) is True
|
| 65 |
+
assert is_image(get_test_example_file('target-240p.mp4')) is False
|
| 66 |
+
assert is_image('invalid') is False
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def test_has_image() -> None:
|
| 70 |
+
assert has_image([ get_test_example_file('source.jpg') ]) is True
|
| 71 |
+
assert has_image([ get_test_example_file('source.jpg'), get_test_example_file('source.mp3') ]) is True
|
| 72 |
+
assert has_image([ get_test_example_file('source.mp3'), get_test_example_file('source.mp3') ]) is False
|
| 73 |
+
assert has_image([ 'invalid' ]) is False
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def test_is_video() -> None:
|
| 77 |
+
assert is_video(get_test_example_file('target-240p.mp4')) is True
|
| 78 |
+
assert is_video(get_test_example_file('source.jpg')) is False
|
| 79 |
+
assert is_video('invalid') is False
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def test_has_video() -> None:
|
| 83 |
+
assert has_video([ get_test_example_file('target-240p.mp4') ]) is True
|
| 84 |
+
assert has_video([ get_test_example_file('target-240p.mp4'), get_test_example_file('source.mp3') ]) is True
|
| 85 |
+
assert has_video([ get_test_example_file('source.mp3'), get_test_example_file('source.mp3') ]) is False
|
| 86 |
+
assert has_video([ 'invalid' ]) is False
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
def test_filter_audio_paths() -> None:
|
| 90 |
+
assert filter_audio_paths([ get_test_example_file('source.jpg'), get_test_example_file('source.mp3') ]) == [ get_test_example_file('source.mp3') ]
|
| 91 |
+
assert filter_audio_paths([ get_test_example_file('source.jpg'), get_test_example_file('source.jpg') ]) == []
|
| 92 |
+
assert filter_audio_paths([ 'invalid' ]) == []
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
def test_filter_image_paths() -> None:
|
| 96 |
+
assert filter_image_paths([ get_test_example_file('source.jpg'), get_test_example_file('source.mp3') ]) == [ get_test_example_file('source.jpg') ]
|
| 97 |
+
assert filter_image_paths([ get_test_example_file('source.mp3'), get_test_example_file('source.mp3') ]) == []
|
| 98 |
+
assert filter_audio_paths([ 'invalid' ]) == []
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
def test_resolve_file_paths() -> None:
|
| 102 |
+
file_paths = resolve_file_paths(get_test_examples_directory())
|
| 103 |
+
|
| 104 |
+
for file_path in file_paths:
|
| 105 |
+
assert file_path == get_test_example_file(file_path)
|
| 106 |
+
|
| 107 |
+
assert resolve_file_paths('invalid') == []
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
def test_create_directory() -> None:
|
| 111 |
+
create_directory_path = os.path.join(get_test_outputs_directory(), 'create_directory')
|
| 112 |
+
|
| 113 |
+
assert create_directory(create_directory_path) is True
|
| 114 |
+
assert create_directory(get_test_example_file('source.jpg')) is False
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
def test_remove_directory() -> None:
|
| 118 |
+
remove_directory_path = os.path.join(get_test_outputs_directory(), 'remove_directory')
|
| 119 |
+
create_directory(remove_directory_path)
|
| 120 |
+
|
| 121 |
+
assert remove_directory(remove_directory_path) is True
|
| 122 |
+
assert remove_directory(get_test_example_file('source.jpg')) is False
|
| 123 |
+
assert remove_directory('invalid') is False
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
def test_is_directory() -> None:
|
| 127 |
+
assert is_directory(get_test_examples_directory()) is True
|
| 128 |
+
assert is_directory(get_test_example_file('source.jpg')) is False
|
| 129 |
+
assert is_directory('invalid') is False
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
def test_in_directory() -> None:
|
| 133 |
+
assert in_directory(get_test_example_file('source.jpg')) is True
|
| 134 |
+
assert in_directory('source.jpg') is False
|
| 135 |
+
assert in_directory('invalid') is False
|
tests/test_inference_manager.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from unittest.mock import patch
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
from onnxruntime import InferenceSession
|
| 5 |
+
|
| 6 |
+
from facefusion import content_analyser, state_manager
|
| 7 |
+
from facefusion.inference_manager import INFERENCE_POOL_SET, get_inference_pool
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
| 11 |
+
def before_all() -> None:
|
| 12 |
+
state_manager.init_item('execution_device_id', '0')
|
| 13 |
+
state_manager.init_item('execution_providers', [ 'cpu' ])
|
| 14 |
+
state_manager.init_item('download_providers', [ 'github' ])
|
| 15 |
+
content_analyser.pre_check()
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def test_get_inference_pool() -> None:
|
| 19 |
+
model_names = [ 'yolo_nsfw' ]
|
| 20 |
+
model_source_set = content_analyser.get_model_options().get('sources')
|
| 21 |
+
|
| 22 |
+
with patch('facefusion.inference_manager.detect_app_context', return_value = 'cli'):
|
| 23 |
+
get_inference_pool('facefusion.content_analyser', model_names, model_source_set)
|
| 24 |
+
|
| 25 |
+
assert isinstance(INFERENCE_POOL_SET.get('cli').get('facefusion.content_analyser.yolo_nsfw.0.cpu').get('content_analyser'), InferenceSession)
|
| 26 |
+
|
| 27 |
+
with patch('facefusion.inference_manager.detect_app_context', return_value = 'ui'):
|
| 28 |
+
get_inference_pool('facefusion.content_analyser', model_names, model_source_set)
|
| 29 |
+
|
| 30 |
+
assert isinstance(INFERENCE_POOL_SET.get('ui').get('facefusion.content_analyser.yolo_nsfw.0.cpu').get('content_analyser'), InferenceSession)
|
| 31 |
+
|
| 32 |
+
assert INFERENCE_POOL_SET.get('cli').get('facefusion.content_analyser.yolo_nsfw.0.cpu').get('content_analyser') == INFERENCE_POOL_SET.get('ui').get('facefusion.content_analyser.yolo_nsfw.0.cpu').get('content_analyser')
|
tests/test_job_helper.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
|
| 3 |
+
from facefusion.jobs.job_helper import get_step_output_path
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
def test_get_step_output_path() -> None:
|
| 7 |
+
assert get_step_output_path('test-job', 0, 'test.mp4') == 'test-test-job-0.mp4'
|
| 8 |
+
assert get_step_output_path('test-job', 0, 'test/test.mp4') == os.path.join('test', 'test-test-job-0.mp4')
|
tests/test_job_list.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from time import sleep
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
|
| 5 |
+
from facefusion.jobs.job_list import compose_job_list
|
| 6 |
+
from facefusion.jobs.job_manager import clear_jobs, create_job, init_jobs
|
| 7 |
+
from .helper import get_test_jobs_directory
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
@pytest.fixture(scope = 'function', autouse = True)
|
| 11 |
+
def before_each() -> None:
|
| 12 |
+
clear_jobs(get_test_jobs_directory())
|
| 13 |
+
init_jobs(get_test_jobs_directory())
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def test_compose_job_list() -> None:
|
| 17 |
+
create_job('job-test-compose-job-list-1')
|
| 18 |
+
sleep(0.5)
|
| 19 |
+
create_job('job-test-compose-job-list-2')
|
| 20 |
+
job_headers, job_contents = compose_job_list('drafted')
|
| 21 |
+
|
| 22 |
+
assert job_headers == [ 'job id', 'steps', 'date created', 'date updated', 'job status' ]
|
| 23 |
+
assert job_contents[0] == [ 'job-test-compose-job-list-1', 0, 'just now', None, 'drafted' ]
|
| 24 |
+
assert job_contents[1] == [ 'job-test-compose-job-list-2', 0, 'just now', None, 'drafted' ]
|
tests/test_job_manager.py
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from time import sleep
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
|
| 5 |
+
from facefusion.jobs.job_helper import get_step_output_path
|
| 6 |
+
from facefusion.jobs.job_manager import add_step, clear_jobs, count_step_total, create_job, delete_job, delete_jobs, find_job_ids, get_steps, init_jobs, insert_step, move_job_file, remix_step, remove_step, set_step_status, set_steps_status, submit_job, submit_jobs
|
| 7 |
+
from .helper import get_test_jobs_directory
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
@pytest.fixture(scope = 'function', autouse = True)
|
| 11 |
+
def before_each() -> None:
|
| 12 |
+
clear_jobs(get_test_jobs_directory())
|
| 13 |
+
init_jobs(get_test_jobs_directory())
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def test_create_job() -> None:
|
| 17 |
+
args_1 =\
|
| 18 |
+
{
|
| 19 |
+
'source_path': 'source-1.jpg',
|
| 20 |
+
'target_path': 'target-1.jpg',
|
| 21 |
+
'output_path': 'output-1.jpg'
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
assert create_job('job-test-create-job') is True
|
| 25 |
+
assert create_job('job-test-create-job') is False
|
| 26 |
+
|
| 27 |
+
add_step('job-test-submit-job', args_1)
|
| 28 |
+
submit_job('job-test-create-job')
|
| 29 |
+
|
| 30 |
+
assert create_job('job-test-create-job') is False
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def test_submit_job() -> None:
|
| 34 |
+
args_1 =\
|
| 35 |
+
{
|
| 36 |
+
'source_path': 'source-1.jpg',
|
| 37 |
+
'target_path': 'target-1.jpg',
|
| 38 |
+
'output_path': 'output-1.jpg'
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
assert submit_job('job-invalid') is False
|
| 42 |
+
|
| 43 |
+
create_job('job-test-submit-job')
|
| 44 |
+
|
| 45 |
+
assert submit_job('job-test-submit-job') is False
|
| 46 |
+
|
| 47 |
+
add_step('job-test-submit-job', args_1)
|
| 48 |
+
|
| 49 |
+
assert submit_job('job-test-submit-job') is True
|
| 50 |
+
assert submit_job('job-test-submit-job') is False
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def test_submit_jobs() -> None:
|
| 54 |
+
args_1 =\
|
| 55 |
+
{
|
| 56 |
+
'source_path': 'source-1.jpg',
|
| 57 |
+
'target_path': 'target-1.jpg',
|
| 58 |
+
'output_path': 'output-1.jpg'
|
| 59 |
+
}
|
| 60 |
+
args_2 =\
|
| 61 |
+
{
|
| 62 |
+
'source_path': 'source-2.jpg',
|
| 63 |
+
'target_path': 'target-2.jpg',
|
| 64 |
+
'output_path': 'output-2.jpg'
|
| 65 |
+
}
|
| 66 |
+
halt_on_error = True
|
| 67 |
+
|
| 68 |
+
assert submit_jobs(halt_on_error) is False
|
| 69 |
+
|
| 70 |
+
create_job('job-test-submit-jobs-1')
|
| 71 |
+
create_job('job-test-submit-jobs-2')
|
| 72 |
+
|
| 73 |
+
assert submit_jobs(halt_on_error) is False
|
| 74 |
+
|
| 75 |
+
add_step('job-test-submit-jobs-1', args_1)
|
| 76 |
+
add_step('job-test-submit-jobs-2', args_2)
|
| 77 |
+
|
| 78 |
+
assert submit_jobs(halt_on_error) is True
|
| 79 |
+
assert submit_jobs(halt_on_error) is False
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def test_delete_job() -> None:
|
| 83 |
+
assert delete_job('job-invalid') is False
|
| 84 |
+
|
| 85 |
+
create_job('job-test-delete-job')
|
| 86 |
+
|
| 87 |
+
assert delete_job('job-test-delete-job') is True
|
| 88 |
+
assert delete_job('job-test-delete-job') is False
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
def test_delete_jobs() -> None:
|
| 92 |
+
halt_on_error = True
|
| 93 |
+
|
| 94 |
+
assert delete_jobs(halt_on_error) is False
|
| 95 |
+
|
| 96 |
+
create_job('job-test-delete-jobs-1')
|
| 97 |
+
create_job('job-test-delete-jobs-2')
|
| 98 |
+
|
| 99 |
+
assert delete_jobs(halt_on_error) is True
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
@pytest.mark.skip()
|
| 103 |
+
def test_find_jobs() -> None:
|
| 104 |
+
pass
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
def test_find_job_ids() -> None:
|
| 108 |
+
create_job('job-test-find-job-ids-1')
|
| 109 |
+
sleep(0.5)
|
| 110 |
+
create_job('job-test-find-job-ids-2')
|
| 111 |
+
sleep(0.5)
|
| 112 |
+
create_job('job-test-find-job-ids-3')
|
| 113 |
+
|
| 114 |
+
assert find_job_ids('drafted') == [ 'job-test-find-job-ids-1', 'job-test-find-job-ids-2', 'job-test-find-job-ids-3' ]
|
| 115 |
+
assert find_job_ids('queued') == []
|
| 116 |
+
assert find_job_ids('completed') == []
|
| 117 |
+
assert find_job_ids('failed') == []
|
| 118 |
+
|
| 119 |
+
move_job_file('job-test-find-job-ids-1', 'queued')
|
| 120 |
+
move_job_file('job-test-find-job-ids-2', 'queued')
|
| 121 |
+
move_job_file('job-test-find-job-ids-3', 'queued')
|
| 122 |
+
|
| 123 |
+
assert find_job_ids('drafted') == []
|
| 124 |
+
assert find_job_ids('queued') == [ 'job-test-find-job-ids-1', 'job-test-find-job-ids-2', 'job-test-find-job-ids-3' ]
|
| 125 |
+
assert find_job_ids('completed') == []
|
| 126 |
+
assert find_job_ids('failed') == []
|
| 127 |
+
|
| 128 |
+
move_job_file('job-test-find-job-ids-1', 'completed')
|
| 129 |
+
|
| 130 |
+
assert find_job_ids('drafted') == []
|
| 131 |
+
assert find_job_ids('queued') == [ 'job-test-find-job-ids-2', 'job-test-find-job-ids-3' ]
|
| 132 |
+
assert find_job_ids('completed') == [ 'job-test-find-job-ids-1' ]
|
| 133 |
+
assert find_job_ids('failed') == []
|
| 134 |
+
|
| 135 |
+
move_job_file('job-test-find-job-ids-2', 'failed')
|
| 136 |
+
|
| 137 |
+
assert find_job_ids('drafted') == []
|
| 138 |
+
assert find_job_ids('queued') == [ 'job-test-find-job-ids-3' ]
|
| 139 |
+
assert find_job_ids('completed') == [ 'job-test-find-job-ids-1' ]
|
| 140 |
+
assert find_job_ids('failed') == [ 'job-test-find-job-ids-2' ]
|
| 141 |
+
|
| 142 |
+
move_job_file('job-test-find-job-ids-3', 'completed')
|
| 143 |
+
|
| 144 |
+
assert find_job_ids('drafted') == []
|
| 145 |
+
assert find_job_ids('queued') == []
|
| 146 |
+
assert find_job_ids('completed') == [ 'job-test-find-job-ids-1', 'job-test-find-job-ids-3' ]
|
| 147 |
+
assert find_job_ids('failed') == [ 'job-test-find-job-ids-2' ]
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
def test_add_step() -> None:
|
| 151 |
+
args_1 =\
|
| 152 |
+
{
|
| 153 |
+
'source_path': 'source-1.jpg',
|
| 154 |
+
'target_path': 'target-1.jpg',
|
| 155 |
+
'output_path': 'output-1.jpg'
|
| 156 |
+
}
|
| 157 |
+
args_2 =\
|
| 158 |
+
{
|
| 159 |
+
'source_path': 'source-2.jpg',
|
| 160 |
+
'target_path': 'target-2.jpg',
|
| 161 |
+
'output_path': 'output-2.jpg'
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
assert add_step('job-invalid', args_1) is False
|
| 165 |
+
|
| 166 |
+
create_job('job-test-add-step')
|
| 167 |
+
|
| 168 |
+
assert add_step('job-test-add-step', args_1) is True
|
| 169 |
+
assert add_step('job-test-add-step', args_2) is True
|
| 170 |
+
|
| 171 |
+
steps = get_steps('job-test-add-step')
|
| 172 |
+
|
| 173 |
+
assert steps[0].get('args') == args_1
|
| 174 |
+
assert steps[1].get('args') == args_2
|
| 175 |
+
assert count_step_total('job-test-add-step') == 2
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
def test_remix_step() -> None:
|
| 179 |
+
args_1 =\
|
| 180 |
+
{
|
| 181 |
+
'source_path': 'source-1.jpg',
|
| 182 |
+
'target_path': 'target-1.jpg',
|
| 183 |
+
'output_path': 'output-1.jpg'
|
| 184 |
+
}
|
| 185 |
+
args_2 =\
|
| 186 |
+
{
|
| 187 |
+
'source_path': 'source-2.jpg',
|
| 188 |
+
'target_path': 'target-2.jpg',
|
| 189 |
+
'output_path': 'output-2.jpg'
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
assert remix_step('job-invalid', 0, args_1) is False
|
| 193 |
+
|
| 194 |
+
create_job('job-test-remix-step')
|
| 195 |
+
add_step('job-test-remix-step', args_1)
|
| 196 |
+
add_step('job-test-remix-step', args_2)
|
| 197 |
+
|
| 198 |
+
assert remix_step('job-test-remix-step', 99, args_1) is False
|
| 199 |
+
assert remix_step('job-test-remix-step', 0, args_2) is True
|
| 200 |
+
assert remix_step('job-test-remix-step', -1, args_2) is True
|
| 201 |
+
|
| 202 |
+
steps = get_steps('job-test-remix-step')
|
| 203 |
+
|
| 204 |
+
assert steps[0].get('args') == args_1
|
| 205 |
+
assert steps[1].get('args') == args_2
|
| 206 |
+
assert steps[2].get('args').get('source_path') == args_2.get('source_path')
|
| 207 |
+
assert steps[2].get('args').get('target_path') == get_step_output_path('job-test-remix-step', 0, args_1.get('output_path'))
|
| 208 |
+
assert steps[2].get('args').get('output_path') == args_2.get('output_path')
|
| 209 |
+
assert steps[3].get('args').get('source_path') == args_2.get('source_path')
|
| 210 |
+
assert steps[3].get('args').get('target_path') == get_step_output_path('job-test-remix-step', 2, args_2.get('output_path'))
|
| 211 |
+
assert steps[3].get('args').get('output_path') == args_2.get('output_path')
|
| 212 |
+
assert count_step_total('job-test-remix-step') == 4
|
| 213 |
+
|
| 214 |
+
|
| 215 |
+
def test_insert_step() -> None:
|
| 216 |
+
args_1 =\
|
| 217 |
+
{
|
| 218 |
+
'source_path': 'source-1.jpg',
|
| 219 |
+
'target_path': 'target-1.jpg',
|
| 220 |
+
'output_path': 'output-1.jpg'
|
| 221 |
+
}
|
| 222 |
+
args_2 =\
|
| 223 |
+
{
|
| 224 |
+
'source_path': 'source-2.jpg',
|
| 225 |
+
'target_path': 'target-2.jpg',
|
| 226 |
+
'output_path': 'output-2.jpg'
|
| 227 |
+
}
|
| 228 |
+
args_3 =\
|
| 229 |
+
{
|
| 230 |
+
'source_path': 'source-3.jpg',
|
| 231 |
+
'target_path': 'target-3.jpg',
|
| 232 |
+
'output_path': 'output-3.jpg'
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
assert insert_step('job-invalid', 0, args_1) is False
|
| 236 |
+
|
| 237 |
+
create_job('job-test-insert-step')
|
| 238 |
+
add_step('job-test-insert-step', args_1)
|
| 239 |
+
add_step('job-test-insert-step', args_1)
|
| 240 |
+
|
| 241 |
+
assert insert_step('job-test-insert-step', 99, args_1) is False
|
| 242 |
+
assert insert_step('job-test-insert-step', 0, args_2) is True
|
| 243 |
+
assert insert_step('job-test-insert-step', -1, args_3) is True
|
| 244 |
+
|
| 245 |
+
steps = get_steps('job-test-insert-step')
|
| 246 |
+
|
| 247 |
+
assert steps[0].get('args') == args_2
|
| 248 |
+
assert steps[1].get('args') == args_1
|
| 249 |
+
assert steps[2].get('args') == args_3
|
| 250 |
+
assert steps[3].get('args') == args_1
|
| 251 |
+
assert count_step_total('job-test-insert-step') == 4
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
def test_remove_step() -> None:
|
| 255 |
+
args_1 =\
|
| 256 |
+
{
|
| 257 |
+
'source_path': 'source-1.jpg',
|
| 258 |
+
'target_path': 'target-1.jpg',
|
| 259 |
+
'output_path': 'output-1.jpg'
|
| 260 |
+
}
|
| 261 |
+
args_2 =\
|
| 262 |
+
{
|
| 263 |
+
'source_path': 'source-2.jpg',
|
| 264 |
+
'target_path': 'target-2.jpg',
|
| 265 |
+
'output_path': 'output-2.jpg'
|
| 266 |
+
}
|
| 267 |
+
args_3 =\
|
| 268 |
+
{
|
| 269 |
+
'source_path': 'source-3.jpg',
|
| 270 |
+
'target_path': 'target-3.jpg',
|
| 271 |
+
'output_path': 'output-3.jpg'
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
assert remove_step('job-invalid', 0) is False
|
| 275 |
+
|
| 276 |
+
create_job('job-test-remove-step')
|
| 277 |
+
add_step('job-test-remove-step', args_1)
|
| 278 |
+
add_step('job-test-remove-step', args_2)
|
| 279 |
+
add_step('job-test-remove-step', args_1)
|
| 280 |
+
add_step('job-test-remove-step', args_3)
|
| 281 |
+
|
| 282 |
+
assert remove_step('job-test-remove-step', 99) is False
|
| 283 |
+
assert remove_step('job-test-remove-step', 0) is True
|
| 284 |
+
assert remove_step('job-test-remove-step', -1) is True
|
| 285 |
+
|
| 286 |
+
steps = get_steps('job-test-remove-step')
|
| 287 |
+
|
| 288 |
+
assert steps[0].get('args') == args_2
|
| 289 |
+
assert steps[1].get('args') == args_1
|
| 290 |
+
assert count_step_total('job-test-remove-step') == 2
|
| 291 |
+
|
| 292 |
+
|
| 293 |
+
def test_get_steps() -> None:
|
| 294 |
+
args_1 =\
|
| 295 |
+
{
|
| 296 |
+
'source_path': 'source-1.jpg',
|
| 297 |
+
'target_path': 'target-1.jpg',
|
| 298 |
+
'output_path': 'output-1.jpg'
|
| 299 |
+
}
|
| 300 |
+
args_2 =\
|
| 301 |
+
{
|
| 302 |
+
'source_path': 'source-2.jpg',
|
| 303 |
+
'target_path': 'target-2.jpg',
|
| 304 |
+
'output_path': 'output-2.jpg'
|
| 305 |
+
}
|
| 306 |
+
|
| 307 |
+
assert get_steps('job-invalid') == []
|
| 308 |
+
|
| 309 |
+
create_job('job-test-get-steps')
|
| 310 |
+
add_step('job-test-get-steps', args_1)
|
| 311 |
+
add_step('job-test-get-steps', args_2)
|
| 312 |
+
steps = get_steps('job-test-get-steps')
|
| 313 |
+
|
| 314 |
+
assert steps[0].get('args') == args_1
|
| 315 |
+
assert steps[1].get('args') == args_2
|
| 316 |
+
assert count_step_total('job-test-get-steps') == 2
|
| 317 |
+
|
| 318 |
+
|
| 319 |
+
def test_set_step_status() -> None:
|
| 320 |
+
args_1 =\
|
| 321 |
+
{
|
| 322 |
+
'source_path': 'source-1.jpg',
|
| 323 |
+
'target_path': 'target-1.jpg',
|
| 324 |
+
'output_path': 'output-1.jpg'
|
| 325 |
+
}
|
| 326 |
+
args_2 =\
|
| 327 |
+
{
|
| 328 |
+
'source_path': 'source-2.jpg',
|
| 329 |
+
'target_path': 'target-2.jpg',
|
| 330 |
+
'output_path': 'output-2.jpg'
|
| 331 |
+
}
|
| 332 |
+
|
| 333 |
+
assert set_step_status('job-invalid', 0, 'completed') is False
|
| 334 |
+
|
| 335 |
+
create_job('job-test-set-step-status')
|
| 336 |
+
add_step('job-test-set-step-status', args_1)
|
| 337 |
+
add_step('job-test-set-step-status', args_2)
|
| 338 |
+
|
| 339 |
+
assert set_step_status('job-test-set-step-status', 99, 'completed') is False
|
| 340 |
+
assert set_step_status('job-test-set-step-status', 0, 'completed') is True
|
| 341 |
+
assert set_step_status('job-test-set-step-status', 1, 'failed') is True
|
| 342 |
+
|
| 343 |
+
steps = get_steps('job-test-set-step-status')
|
| 344 |
+
|
| 345 |
+
assert steps[0].get('status') == 'completed'
|
| 346 |
+
assert steps[1].get('status') == 'failed'
|
| 347 |
+
assert count_step_total('job-test-set-step-status') == 2
|
| 348 |
+
|
| 349 |
+
|
| 350 |
+
def test_set_steps_status() -> None:
|
| 351 |
+
args_1 =\
|
| 352 |
+
{
|
| 353 |
+
'source_path': 'source-1.jpg',
|
| 354 |
+
'target_path': 'target-1.jpg',
|
| 355 |
+
'output_path': 'output-1.jpg'
|
| 356 |
+
}
|
| 357 |
+
args_2 =\
|
| 358 |
+
{
|
| 359 |
+
'source_path': 'source-2.jpg',
|
| 360 |
+
'target_path': 'target-2.jpg',
|
| 361 |
+
'output_path': 'output-2.jpg'
|
| 362 |
+
}
|
| 363 |
+
|
| 364 |
+
assert set_steps_status('job-invalid', 'queued') is False
|
| 365 |
+
|
| 366 |
+
create_job('job-test-set-steps-status')
|
| 367 |
+
add_step('job-test-set-steps-status', args_1)
|
| 368 |
+
add_step('job-test-set-steps-status', args_2)
|
| 369 |
+
|
| 370 |
+
assert set_steps_status('job-test-set-steps-status', 'queued') is True
|
| 371 |
+
|
| 372 |
+
steps = get_steps('job-test-set-steps-status')
|
| 373 |
+
|
| 374 |
+
assert steps[0].get('status') == 'queued'
|
| 375 |
+
assert steps[1].get('status') == 'queued'
|
| 376 |
+
assert count_step_total('job-test-set-steps-status') == 2
|
tests/test_job_runner.py
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import subprocess
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
|
| 5 |
+
from facefusion.download import conditional_download
|
| 6 |
+
from facefusion.filesystem import copy_file
|
| 7 |
+
from facefusion.jobs.job_manager import add_step, clear_jobs, create_job, init_jobs, submit_job, submit_jobs
|
| 8 |
+
from facefusion.jobs.job_runner import collect_output_set, finalize_steps, run_job, run_jobs, run_steps
|
| 9 |
+
from facefusion.types import Args
|
| 10 |
+
from .helper import get_test_example_file, get_test_examples_directory, get_test_jobs_directory, get_test_output_file, is_test_output_file, prepare_test_output_directory
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
| 14 |
+
def before_all() -> None:
|
| 15 |
+
conditional_download(get_test_examples_directory(),
|
| 16 |
+
[
|
| 17 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
|
| 18 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
|
| 19 |
+
])
|
| 20 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
@pytest.fixture(scope = 'function', autouse = True)
|
| 24 |
+
def before_each() -> None:
|
| 25 |
+
clear_jobs(get_test_jobs_directory())
|
| 26 |
+
init_jobs(get_test_jobs_directory())
|
| 27 |
+
prepare_test_output_directory()
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def process_step(job_id : str, step_index : int, step_args : Args) -> bool:
|
| 31 |
+
return copy_file(step_args.get('target_path'), step_args.get('output_path'))
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def test_run_job() -> None:
|
| 35 |
+
args_1 =\
|
| 36 |
+
{
|
| 37 |
+
'source_path': get_test_example_file('source.jpg'),
|
| 38 |
+
'target_path': get_test_example_file('target-240p.mp4'),
|
| 39 |
+
'output_path': get_test_output_file('output-1.mp4')
|
| 40 |
+
}
|
| 41 |
+
args_2 =\
|
| 42 |
+
{
|
| 43 |
+
'source_path': get_test_example_file('source.jpg'),
|
| 44 |
+
'target_path': get_test_example_file('target-240p.mp4'),
|
| 45 |
+
'output_path': get_test_output_file('output-2.mp4')
|
| 46 |
+
}
|
| 47 |
+
args_3 =\
|
| 48 |
+
{
|
| 49 |
+
'source_path': get_test_example_file('source.jpg'),
|
| 50 |
+
'target_path': get_test_example_file('target-240p.jpg'),
|
| 51 |
+
'output_path': get_test_output_file('output-1.jpg')
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
assert run_job('job-invalid', process_step) is False
|
| 55 |
+
|
| 56 |
+
create_job('job-test-run-job')
|
| 57 |
+
add_step('job-test-run-job', args_1)
|
| 58 |
+
add_step('job-test-run-job', args_2)
|
| 59 |
+
add_step('job-test-run-job', args_2)
|
| 60 |
+
add_step('job-test-run-job', args_3)
|
| 61 |
+
|
| 62 |
+
assert run_job('job-test-run-job', process_step) is False
|
| 63 |
+
|
| 64 |
+
submit_job('job-test-run-job')
|
| 65 |
+
|
| 66 |
+
assert run_job('job-test-run-job', process_step) is True
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def test_run_jobs() -> None:
|
| 70 |
+
args_1 =\
|
| 71 |
+
{
|
| 72 |
+
'source_path': get_test_example_file('source.jpg'),
|
| 73 |
+
'target_path': get_test_example_file('target-240p.mp4'),
|
| 74 |
+
'output_path': get_test_output_file('output-1.mp4')
|
| 75 |
+
}
|
| 76 |
+
args_2 =\
|
| 77 |
+
{
|
| 78 |
+
'source_path': get_test_example_file('source.jpg'),
|
| 79 |
+
'target_path': get_test_example_file('target-240p.mp4'),
|
| 80 |
+
'output_path': get_test_output_file('output-2.mp4')
|
| 81 |
+
}
|
| 82 |
+
args_3 =\
|
| 83 |
+
{
|
| 84 |
+
'source_path': get_test_example_file('source.jpg'),
|
| 85 |
+
'target_path': get_test_example_file('target-240p.jpg'),
|
| 86 |
+
'output_path': get_test_output_file('output-1.jpg')
|
| 87 |
+
}
|
| 88 |
+
halt_on_error = True
|
| 89 |
+
|
| 90 |
+
assert run_jobs(process_step, halt_on_error) is False
|
| 91 |
+
|
| 92 |
+
create_job('job-test-run-jobs-1')
|
| 93 |
+
create_job('job-test-run-jobs-2')
|
| 94 |
+
add_step('job-test-run-jobs-1', args_1)
|
| 95 |
+
add_step('job-test-run-jobs-1', args_1)
|
| 96 |
+
add_step('job-test-run-jobs-2', args_2)
|
| 97 |
+
add_step('job-test-run-jobs-3', args_3)
|
| 98 |
+
|
| 99 |
+
assert run_jobs(process_step, halt_on_error) is False
|
| 100 |
+
|
| 101 |
+
submit_jobs(halt_on_error)
|
| 102 |
+
|
| 103 |
+
assert run_jobs(process_step, halt_on_error) is True
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
@pytest.mark.skip()
|
| 107 |
+
def test_retry_job() -> None:
|
| 108 |
+
pass
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
@pytest.mark.skip()
|
| 112 |
+
def test_retry_jobs() -> None:
|
| 113 |
+
pass
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
def test_run_steps() -> None:
|
| 117 |
+
args_1 =\
|
| 118 |
+
{
|
| 119 |
+
'source_path': get_test_example_file('source.jpg'),
|
| 120 |
+
'target_path': get_test_example_file('target-240p.mp4'),
|
| 121 |
+
'output_path': get_test_output_file('output-1.mp4')
|
| 122 |
+
}
|
| 123 |
+
args_2 =\
|
| 124 |
+
{
|
| 125 |
+
'source_path': get_test_example_file('source.jpg'),
|
| 126 |
+
'target_path': get_test_example_file('target-240p.mp4'),
|
| 127 |
+
'output_path': get_test_output_file('output-2.mp4')
|
| 128 |
+
}
|
| 129 |
+
args_3 =\
|
| 130 |
+
{
|
| 131 |
+
'source_path': get_test_example_file('source.jpg'),
|
| 132 |
+
'target_path': get_test_example_file('target-240p.jpg'),
|
| 133 |
+
'output_path': get_test_output_file('output-1.jpg')
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
assert run_steps('job-invalid', process_step) is False
|
| 137 |
+
|
| 138 |
+
create_job('job-test-run-steps')
|
| 139 |
+
add_step('job-test-run-steps', args_1)
|
| 140 |
+
add_step('job-test-run-steps', args_1)
|
| 141 |
+
add_step('job-test-run-steps', args_2)
|
| 142 |
+
add_step('job-test-run-steps', args_3)
|
| 143 |
+
|
| 144 |
+
assert run_steps('job-test-run-steps', process_step) is True
|
| 145 |
+
|
| 146 |
+
|
| 147 |
+
def test_finalize_steps() -> None:
|
| 148 |
+
args_1 =\
|
| 149 |
+
{
|
| 150 |
+
'source_path': get_test_example_file('source.jpg'),
|
| 151 |
+
'target_path': get_test_example_file('target-240p.mp4'),
|
| 152 |
+
'output_path': get_test_output_file('output-1.mp4')
|
| 153 |
+
}
|
| 154 |
+
args_2 =\
|
| 155 |
+
{
|
| 156 |
+
'source_path': get_test_example_file('source.jpg'),
|
| 157 |
+
'target_path': get_test_example_file('target-240p.mp4'),
|
| 158 |
+
'output_path': get_test_output_file('output-2.mp4')
|
| 159 |
+
}
|
| 160 |
+
args_3 =\
|
| 161 |
+
{
|
| 162 |
+
'source_path': get_test_example_file('source.jpg'),
|
| 163 |
+
'target_path': get_test_example_file('target-240p.jpg'),
|
| 164 |
+
'output_path': get_test_output_file('output-1.jpg')
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
create_job('job-test-finalize-steps')
|
| 168 |
+
add_step('job-test-finalize-steps', args_1)
|
| 169 |
+
add_step('job-test-finalize-steps', args_1)
|
| 170 |
+
add_step('job-test-finalize-steps', args_2)
|
| 171 |
+
add_step('job-test-finalize-steps', args_3)
|
| 172 |
+
|
| 173 |
+
copy_file(args_1.get('target_path'), get_test_output_file('output-1-job-test-finalize-steps-0.mp4'))
|
| 174 |
+
copy_file(args_1.get('target_path'), get_test_output_file('output-1-job-test-finalize-steps-1.mp4'))
|
| 175 |
+
copy_file(args_2.get('target_path'), get_test_output_file('output-2-job-test-finalize-steps-2.mp4'))
|
| 176 |
+
copy_file(args_3.get('target_path'), get_test_output_file('output-1-job-test-finalize-steps-3.jpg'))
|
| 177 |
+
|
| 178 |
+
assert finalize_steps('job-test-finalize-steps') is True
|
| 179 |
+
assert is_test_output_file('output-1.mp4') is True
|
| 180 |
+
assert is_test_output_file('output-2.mp4') is True
|
| 181 |
+
assert is_test_output_file('output-1.jpg') is True
|
| 182 |
+
|
| 183 |
+
|
| 184 |
+
def test_collect_output_set() -> None:
|
| 185 |
+
args_1 =\
|
| 186 |
+
{
|
| 187 |
+
'source_path': get_test_example_file('source.jpg'),
|
| 188 |
+
'target_path': get_test_example_file('target-240p.mp4'),
|
| 189 |
+
'output_path': get_test_output_file('output-1.mp4')
|
| 190 |
+
}
|
| 191 |
+
args_2 =\
|
| 192 |
+
{
|
| 193 |
+
'source_path': get_test_example_file('source.jpg'),
|
| 194 |
+
'target_path': get_test_example_file('target-240p.mp4'),
|
| 195 |
+
'output_path': get_test_output_file('output-2.mp4')
|
| 196 |
+
}
|
| 197 |
+
args_3 =\
|
| 198 |
+
{
|
| 199 |
+
'source_path': get_test_example_file('source.jpg'),
|
| 200 |
+
'target_path': get_test_example_file('target-240p.jpg'),
|
| 201 |
+
'output_path': get_test_output_file('output-1.jpg')
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
create_job('job-test-collect-output-set')
|
| 205 |
+
add_step('job-test-collect-output-set', args_1)
|
| 206 |
+
add_step('job-test-collect-output-set', args_1)
|
| 207 |
+
add_step('job-test-collect-output-set', args_2)
|
| 208 |
+
add_step('job-test-collect-output-set', args_3)
|
| 209 |
+
|
| 210 |
+
output_set =\
|
| 211 |
+
{
|
| 212 |
+
get_test_output_file('output-1.mp4'):
|
| 213 |
+
[
|
| 214 |
+
get_test_output_file('output-1-job-test-collect-output-set-0.mp4'),
|
| 215 |
+
get_test_output_file('output-1-job-test-collect-output-set-1.mp4')
|
| 216 |
+
],
|
| 217 |
+
get_test_output_file('output-2.mp4'):
|
| 218 |
+
[
|
| 219 |
+
get_test_output_file('output-2-job-test-collect-output-set-2.mp4')
|
| 220 |
+
],
|
| 221 |
+
get_test_output_file('output-1.jpg'):
|
| 222 |
+
[
|
| 223 |
+
get_test_output_file('output-1-job-test-collect-output-set-3.jpg')
|
| 224 |
+
]
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
assert collect_output_set('job-test-collect-output-set') == output_set
|
tests/test_json.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import tempfile
|
| 2 |
+
|
| 3 |
+
from facefusion.json import read_json, write_json
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
def test_read_json() -> None:
|
| 7 |
+
_, json_path = tempfile.mkstemp(suffix = '.json')
|
| 8 |
+
|
| 9 |
+
assert not read_json(json_path)
|
| 10 |
+
|
| 11 |
+
write_json(json_path, {})
|
| 12 |
+
|
| 13 |
+
assert read_json(json_path) == {}
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def test_write_json() -> None:
|
| 17 |
+
_, json_path = tempfile.mkstemp(suffix = '.json')
|
| 18 |
+
|
| 19 |
+
assert write_json(json_path, {})
|
tests/test_memory.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from facefusion.common_helper import is_linux, is_macos
|
| 2 |
+
from facefusion.memory import limit_system_memory
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
def test_limit_system_memory() -> None:
|
| 6 |
+
assert limit_system_memory(4) is True
|
| 7 |
+
if is_linux() or is_macos():
|
| 8 |
+
assert limit_system_memory(1024) is False
|
tests/test_normalizer.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from facefusion.normalizer import normalize_fps, normalize_padding
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
def test_normalize_padding() -> None:
|
| 5 |
+
assert normalize_padding([ 0, 0, 0, 0 ]) == (0, 0, 0, 0)
|
| 6 |
+
assert normalize_padding([ 1 ]) == (1, 1, 1, 1)
|
| 7 |
+
assert normalize_padding([ 1, 2 ]) == (1, 2, 1, 2)
|
| 8 |
+
assert normalize_padding([ 1, 2, 3 ]) == (1, 2, 3, 2)
|
| 9 |
+
assert normalize_padding(None) is None
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def test_normalize_fps() -> None:
|
| 13 |
+
assert normalize_fps(0.0) == 1.0
|
| 14 |
+
assert normalize_fps(25.0) == 25.0
|
| 15 |
+
assert normalize_fps(61.0) == 60.0
|
| 16 |
+
assert normalize_fps(None) is None
|
tests/test_process_manager.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from facefusion.process_manager import end, is_pending, is_processing, is_stopping, set_process_state, start, stop
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
def test_start() -> None:
|
| 5 |
+
set_process_state('pending')
|
| 6 |
+
start()
|
| 7 |
+
|
| 8 |
+
assert is_processing()
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def test_stop() -> None:
|
| 12 |
+
set_process_state('processing')
|
| 13 |
+
stop()
|
| 14 |
+
|
| 15 |
+
assert is_stopping()
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def test_end() -> None:
|
| 19 |
+
set_process_state('processing')
|
| 20 |
+
end()
|
| 21 |
+
|
| 22 |
+
assert is_pending()
|
tests/test_program_helper.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from argparse import ArgumentParser
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
|
| 5 |
+
from facefusion.program_helper import find_argument_group, validate_actions
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def test_find_argument_group() -> None:
|
| 9 |
+
program = ArgumentParser()
|
| 10 |
+
program.add_argument_group('test-1')
|
| 11 |
+
program.add_argument_group('test-2')
|
| 12 |
+
|
| 13 |
+
assert find_argument_group(program, 'test-1')
|
| 14 |
+
assert find_argument_group(program, 'test-2')
|
| 15 |
+
assert find_argument_group(program, 'invalid') is None
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
@pytest.mark.skip()
|
| 19 |
+
def test_validate_args() -> None:
|
| 20 |
+
pass
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def test_validate_actions() -> None:
|
| 24 |
+
program = ArgumentParser()
|
| 25 |
+
program.add_argument('--test-1', default = 'test_1', choices = [ 'test_1', 'test_2' ])
|
| 26 |
+
program.add_argument('--test-2', default = 'test_2', choices= [ 'test_1', 'test_2' ], nargs = '+')
|
| 27 |
+
|
| 28 |
+
assert validate_actions(program) is True
|
| 29 |
+
|
| 30 |
+
args =\
|
| 31 |
+
{
|
| 32 |
+
'test_1': 'test_2',
|
| 33 |
+
'test_2': [ 'test_1', 'test_3' ]
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
for action in program._actions:
|
| 37 |
+
if action.dest in args:
|
| 38 |
+
action.default = args[action.dest]
|
| 39 |
+
|
| 40 |
+
assert validate_actions(program) is False
|
tests/test_temp_helper.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os.path
|
| 2 |
+
import tempfile
|
| 3 |
+
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
from facefusion import state_manager
|
| 7 |
+
from facefusion.download import conditional_download
|
| 8 |
+
from facefusion.temp_helper import get_temp_directory_path, get_temp_file_path, get_temp_frames_pattern
|
| 9 |
+
from .helper import get_test_example_file, get_test_examples_directory
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
| 13 |
+
def before_all() -> None:
|
| 14 |
+
conditional_download(get_test_examples_directory(),
|
| 15 |
+
[
|
| 16 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4'
|
| 17 |
+
])
|
| 18 |
+
state_manager.init_item('temp_path', tempfile.gettempdir())
|
| 19 |
+
state_manager.init_item('temp_frame_format', 'png')
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def test_get_temp_file_path() -> None:
|
| 23 |
+
temp_directory = tempfile.gettempdir()
|
| 24 |
+
assert get_temp_file_path(get_test_example_file('target-240p.mp4')) == os.path.join(temp_directory, 'facefusion', 'target-240p', 'temp.mp4')
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def test_get_temp_directory_path() -> None:
|
| 28 |
+
temp_directory = tempfile.gettempdir()
|
| 29 |
+
assert get_temp_directory_path(get_test_example_file('target-240p.mp4')) == os.path.join(temp_directory, 'facefusion', 'target-240p')
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def test_get_temp_frames_pattern() -> None:
|
| 33 |
+
temp_directory = tempfile.gettempdir()
|
| 34 |
+
assert get_temp_frames_pattern(get_test_example_file('target-240p.mp4'), '%04d') == os.path.join(temp_directory, 'facefusion', 'target-240p', '%04d.png')
|
tests/test_vision.py
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import subprocess
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
|
| 5 |
+
from facefusion.download import conditional_download
|
| 6 |
+
from facefusion.vision import calc_histogram_difference, count_trim_frame_total, count_video_frame_total, create_image_resolutions, create_video_resolutions, detect_image_resolution, detect_video_duration, detect_video_fps, detect_video_resolution, match_frame_color, normalize_resolution, pack_resolution, predict_video_frame_total, read_image, read_video_frame, restrict_image_resolution, restrict_trim_frame, restrict_video_fps, restrict_video_resolution, unpack_resolution, write_image
|
| 7 |
+
from .helper import get_test_example_file, get_test_examples_directory, get_test_output_file, prepare_test_output_directory
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
@pytest.fixture(scope = 'module', autouse = True)
|
| 11 |
+
def before_all() -> None:
|
| 12 |
+
conditional_download(get_test_examples_directory(),
|
| 13 |
+
[
|
| 14 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/source.jpg',
|
| 15 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-240p.mp4',
|
| 16 |
+
'https://github.com/facefusion/facefusion-assets/releases/download/examples-3.0.0/target-1080p.mp4'
|
| 17 |
+
])
|
| 18 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('target-240p.jpg') ])
|
| 19 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', get_test_example_file('目标-240p.webp') ])
|
| 20 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-1080p.mp4'), '-vframes', '1', get_test_example_file('target-1080p.jpg') ])
|
| 21 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', '-vf', 'hue=s=0', get_test_example_file('target-240p-0sat.jpg') ])
|
| 22 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vframes', '1', '-vf', 'transpose=0', get_test_example_file('target-240p-90deg.jpg') ])
|
| 23 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-1080p.mp4'), '-vframes', '1', '-vf', 'transpose=0', get_test_example_file('target-1080p-90deg.jpg') ])
|
| 24 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vf', 'fps=25', get_test_example_file('target-240p-25fps.mp4') ])
|
| 25 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vf', 'fps=30', get_test_example_file('target-240p-30fps.mp4') ])
|
| 26 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vf', 'fps=60', get_test_example_file('target-240p-60fps.mp4') ])
|
| 27 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-240p.mp4'), '-vf', 'transpose=0', get_test_example_file('target-240p-90deg.mp4') ])
|
| 28 |
+
subprocess.run([ 'ffmpeg', '-i', get_test_example_file('target-1080p.mp4'), '-vf', 'transpose=0', get_test_example_file('target-1080p-90deg.mp4') ])
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
@pytest.fixture(scope = 'function', autouse = True)
|
| 32 |
+
def before_each() -> None:
|
| 33 |
+
prepare_test_output_directory()
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def test_read_image() -> None:
|
| 37 |
+
assert read_image(get_test_example_file('target-240p.jpg')).shape == (226, 426, 3)
|
| 38 |
+
assert read_image(get_test_example_file('目标-240p.webp')).shape == (226, 426, 3)
|
| 39 |
+
assert read_image('invalid') is None
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
def test_write_image() -> None:
|
| 43 |
+
vision_frame = read_image(get_test_example_file('target-240p.jpg'))
|
| 44 |
+
|
| 45 |
+
assert write_image(get_test_output_file('target-240p.jpg'), vision_frame) is True
|
| 46 |
+
assert write_image(get_test_output_file('目标-240p.webp'), vision_frame) is True
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def test_detect_image_resolution() -> None:
|
| 50 |
+
assert detect_image_resolution(get_test_example_file('target-240p.jpg')) == (426, 226)
|
| 51 |
+
assert detect_image_resolution(get_test_example_file('target-240p-90deg.jpg')) == (226, 426)
|
| 52 |
+
assert detect_image_resolution(get_test_example_file('target-1080p.jpg')) == (2048, 1080)
|
| 53 |
+
assert detect_image_resolution(get_test_example_file('target-1080p-90deg.jpg')) == (1080, 2048)
|
| 54 |
+
assert detect_image_resolution('invalid') is None
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def test_restrict_image_resolution() -> None:
|
| 58 |
+
assert restrict_image_resolution(get_test_example_file('target-1080p.jpg'), (426, 226)) == (426, 226)
|
| 59 |
+
assert restrict_image_resolution(get_test_example_file('target-1080p.jpg'), (2048, 1080)) == (2048, 1080)
|
| 60 |
+
assert restrict_image_resolution(get_test_example_file('target-1080p.jpg'), (4096, 2160)) == (2048, 1080)
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def test_create_image_resolutions() -> None:
|
| 64 |
+
assert create_image_resolutions((426, 226)) == [ '106x56', '212x112', '320x170', '426x226', '640x340', '852x452', '1064x564', '1278x678', '1492x792', '1704x904' ]
|
| 65 |
+
assert create_image_resolutions((226, 426)) == [ '56x106', '112x212', '170x320', '226x426', '340x640', '452x852', '564x1064', '678x1278', '792x1492', '904x1704' ]
|
| 66 |
+
assert create_image_resolutions((2048, 1080)) == [ '512x270', '1024x540', '1536x810', '2048x1080', '3072x1620', '4096x2160', '5120x2700', '6144x3240', '7168x3780', '8192x4320' ]
|
| 67 |
+
assert create_image_resolutions((1080, 2048)) == [ '270x512', '540x1024', '810x1536', '1080x2048', '1620x3072', '2160x4096', '2700x5120', '3240x6144', '3780x7168', '4320x8192' ]
|
| 68 |
+
assert create_image_resolutions(None) == []
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
def test_read_video_frame() -> None:
|
| 72 |
+
assert hasattr(read_video_frame(get_test_example_file('target-240p-25fps.mp4')), '__array_interface__')
|
| 73 |
+
assert read_video_frame('invalid') is None
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def test_count_video_frame_total() -> None:
|
| 77 |
+
assert count_video_frame_total(get_test_example_file('target-240p-25fps.mp4')) == 270
|
| 78 |
+
assert count_video_frame_total(get_test_example_file('target-240p-30fps.mp4')) == 324
|
| 79 |
+
assert count_video_frame_total(get_test_example_file('target-240p-60fps.mp4')) == 648
|
| 80 |
+
assert count_video_frame_total('invalid') == 0
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
def test_predict_video_frame_total() -> None:
|
| 84 |
+
assert predict_video_frame_total(get_test_example_file('target-240p-25fps.mp4'), 12.5, 0, 100) == 50
|
| 85 |
+
assert predict_video_frame_total(get_test_example_file('target-240p-25fps.mp4'), 25, 0, 100) == 100
|
| 86 |
+
assert predict_video_frame_total(get_test_example_file('target-240p-25fps.mp4'), 25, 0, 200) == 200
|
| 87 |
+
assert predict_video_frame_total('invalid', 25, 0, 100) == 0
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def test_detect_video_fps() -> None:
|
| 91 |
+
assert detect_video_fps(get_test_example_file('target-240p-25fps.mp4')) == 25.0
|
| 92 |
+
assert detect_video_fps(get_test_example_file('target-240p-30fps.mp4')) == 30.0
|
| 93 |
+
assert detect_video_fps(get_test_example_file('target-240p-60fps.mp4')) == 60.0
|
| 94 |
+
assert detect_video_fps('invalid') is None
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
def test_restrict_video_fps() -> None:
|
| 98 |
+
assert restrict_video_fps(get_test_example_file('target-1080p.mp4'), 20.0) == 20.0
|
| 99 |
+
assert restrict_video_fps(get_test_example_file('target-1080p.mp4'), 25.0) == 25.0
|
| 100 |
+
assert restrict_video_fps(get_test_example_file('target-1080p.mp4'), 60.0) == 25.0
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
def test_detect_video_duration() -> None:
|
| 104 |
+
assert detect_video_duration(get_test_example_file('target-240p.mp4')) == 10.8
|
| 105 |
+
assert detect_video_duration('invalid') == 0
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
def test_count_trim_frame_total() -> None:
|
| 109 |
+
assert count_trim_frame_total(get_test_example_file('target-240p.mp4'), 0, 200) == 200
|
| 110 |
+
assert count_trim_frame_total(get_test_example_file('target-240p.mp4'), 70, 270) == 200
|
| 111 |
+
assert count_trim_frame_total(get_test_example_file('target-240p.mp4'), -10, None) == 270
|
| 112 |
+
assert count_trim_frame_total(get_test_example_file('target-240p.mp4'), None, -10) == 0
|
| 113 |
+
assert count_trim_frame_total(get_test_example_file('target-240p.mp4'), 280, None) == 0
|
| 114 |
+
assert count_trim_frame_total(get_test_example_file('target-240p.mp4'), None, 280) == 270
|
| 115 |
+
assert count_trim_frame_total(get_test_example_file('target-240p.mp4'), None, None) == 270
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
def test_restrict_trim_frame() -> None:
|
| 119 |
+
assert restrict_trim_frame(get_test_example_file('target-240p.mp4'), 0, 200) == (0, 200)
|
| 120 |
+
assert restrict_trim_frame(get_test_example_file('target-240p.mp4'), 70, 270) == (70, 270)
|
| 121 |
+
assert restrict_trim_frame(get_test_example_file('target-240p.mp4'), -10, None) == (0, 270)
|
| 122 |
+
assert restrict_trim_frame(get_test_example_file('target-240p.mp4'), None, -10) == (0, 0)
|
| 123 |
+
assert restrict_trim_frame(get_test_example_file('target-240p.mp4'), 280, None) == (270, 270)
|
| 124 |
+
assert restrict_trim_frame(get_test_example_file('target-240p.mp4'), None, 280) == (0, 270)
|
| 125 |
+
assert restrict_trim_frame(get_test_example_file('target-240p.mp4'), None, None) == (0, 270)
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
def test_detect_video_resolution() -> None:
|
| 129 |
+
assert detect_video_resolution(get_test_example_file('target-240p.mp4')) == (426, 226)
|
| 130 |
+
assert detect_video_resolution(get_test_example_file('target-240p-90deg.mp4')) == (226, 426)
|
| 131 |
+
assert detect_video_resolution(get_test_example_file('target-1080p.mp4')) == (2048, 1080)
|
| 132 |
+
assert detect_video_resolution(get_test_example_file('target-1080p-90deg.mp4')) == (1080, 2048)
|
| 133 |
+
assert detect_video_resolution('invalid') is None
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
def test_restrict_video_resolution() -> None:
|
| 137 |
+
assert restrict_video_resolution(get_test_example_file('target-1080p.mp4'), (426, 226)) == (426, 226)
|
| 138 |
+
assert restrict_video_resolution(get_test_example_file('target-1080p.mp4'), (2048, 1080)) == (2048, 1080)
|
| 139 |
+
assert restrict_video_resolution(get_test_example_file('target-1080p.mp4'), (4096, 2160)) == (2048, 1080)
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
def test_create_video_resolutions() -> None:
|
| 143 |
+
assert create_video_resolutions((426, 226)) == [ '426x226', '452x240', '678x360', '904x480', '1018x540', '1358x720', '2036x1080', '2714x1440', '4072x2160', '8144x4320' ]
|
| 144 |
+
assert create_video_resolutions((226, 426)) == [ '226x426', '240x452', '360x678', '480x904', '540x1018', '720x1358', '1080x2036', '1440x2714', '2160x4072', '4320x8144' ]
|
| 145 |
+
assert create_video_resolutions((2048, 1080)) == [ '456x240', '682x360', '910x480', '1024x540', '1366x720', '2048x1080', '2730x1440', '4096x2160', '8192x4320' ]
|
| 146 |
+
assert create_video_resolutions((1080, 2048)) == [ '240x456', '360x682', '480x910', '540x1024', '720x1366', '1080x2048', '1440x2730', '2160x4096', '4320x8192' ]
|
| 147 |
+
assert create_video_resolutions(None) == []
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
def test_normalize_resolution() -> None:
|
| 151 |
+
assert normalize_resolution((2.5, 2.5)) == (2, 2)
|
| 152 |
+
assert normalize_resolution((3.0, 3.0)) == (4, 4)
|
| 153 |
+
assert normalize_resolution((6.5, 6.5)) == (6, 6)
|
| 154 |
+
|
| 155 |
+
|
| 156 |
+
def test_pack_resolution() -> None:
|
| 157 |
+
assert pack_resolution((1, 1)) == '0x0'
|
| 158 |
+
assert pack_resolution((2, 2)) == '2x2'
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
def test_unpack_resolution() -> None:
|
| 162 |
+
assert unpack_resolution('0x0') == (0, 0)
|
| 163 |
+
assert unpack_resolution('2x2') == (2, 2)
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
def test_calc_histogram_difference() -> None:
|
| 167 |
+
source_vision_frame = read_image(get_test_example_file('target-240p.jpg'))
|
| 168 |
+
target_vision_frame = read_image(get_test_example_file('target-240p-0sat.jpg'))
|
| 169 |
+
|
| 170 |
+
assert calc_histogram_difference(source_vision_frame, source_vision_frame) == 1.0
|
| 171 |
+
assert calc_histogram_difference(source_vision_frame, target_vision_frame) < 0.5
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
def test_match_frame_color() -> None:
|
| 175 |
+
source_vision_frame = read_image(get_test_example_file('target-240p.jpg'))
|
| 176 |
+
target_vision_frame = read_image(get_test_example_file('target-240p-0sat.jpg'))
|
| 177 |
+
output_vision_frame = match_frame_color(source_vision_frame, target_vision_frame)
|
| 178 |
+
|
| 179 |
+
assert calc_histogram_difference(source_vision_frame, output_vision_frame) > 0.5
|
tests/test_wording.py
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from facefusion import wording
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
def test_get() -> None:
|
| 5 |
+
assert wording.get('python_not_supported')
|
| 6 |
+
assert wording.get('help.source_paths')
|
| 7 |
+
assert wording.get('invalid') is None
|