smart_beauty_task.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import logging
  2. import os
  3. import subprocess
  4. import time
  5. from typing import Any
  6. from app.service.task.base_task import BaseTask
  7. from app.service.task.task_param import TaskParam
  8. from app.service.task.task_result import TaskResult
  9. from app.util.res_util import get_resources_path
  10. logger = logging.getLogger(__name__)
  11. class SmartBeautyTask(BaseTask):
  12. def get_type(self) -> str:
  13. return "smart_beauty"
  14. def execute(self, param: TaskParam) -> TaskResult:
  15. try:
  16. images_obj = param.inputs.get("images")
  17. images_in: list[str] = images_obj if isinstance(images_obj, list) else []
  18. if not images_in:
  19. return TaskResult.failure("No images provided for processing")
  20. workspace = param.workspace
  21. resources = param.resources
  22. if not workspace or not os.path.isdir(workspace):
  23. return TaskResult.failure("Workspace path is not provided")
  24. logger.info("[smart_beauty] Starting: %d images, resources=%s", len(images_in), resources)
  25. t0 = time.time()
  26. images_out: list[str] = []
  27. for i, inp in enumerate(images_in):
  28. try:
  29. base_name = _get_base_name(inp)
  30. output_path = f"{param.step_id}/{base_name}_beauty.jpg"
  31. logger.info("[smart_beauty] Processing image %d/%d: %s -> %s",
  32. i + 1, len(images_in), inp, output_path)
  33. if self._execute_beauty(workspace, inp, output_path, resources):
  34. images_out.append(output_path)
  35. logger.info("[smart_beauty] Image %d/%d processed successfully", i + 1, len(images_in))
  36. else:
  37. logger.warning("[smart_beauty] Image %d/%d processing failed", i + 1, len(images_in))
  38. except Exception as e:
  39. logger.error("[smart_beauty] Error processing image %d/%d %s: %s",
  40. i + 1, len(images_in), inp, e)
  41. if not images_out:
  42. return TaskResult.failure("No images were successfully processed")
  43. logger.info("[smart_beauty] Completed: %d/%d images in %.2fs",
  44. len(images_out), len(images_in), time.time() - t0)
  45. return TaskResult.success({"images": images_out})
  46. except Exception as e:
  47. logger.error("[smart_beauty] Error: %s", e, exc_info=True)
  48. return TaskResult.failure(f"Smart beauty processing failed: {e}")
  49. @staticmethod
  50. def _execute_beauty(workspace: str, inp: str, output: str, config: str) -> bool:
  51. try:
  52. base_dir = os.path.join(get_resources_path(), "beautify")
  53. executor_path = os.path.join(base_dir, "beautify")
  54. lib_path = os.path.join(base_dir, "libs")
  55. licence_path = os.path.join(base_dir, "res", "license.lic")
  56. face_model = os.path.join(base_dir, "res", "Face_Video_Template_p_4.0.0.model")
  57. hair_model = os.path.join(base_dir, "res", "Segment_Hair_p_4.4.0.model")
  58. if not os.path.isfile(executor_path):
  59. logger.error("[smart_beauty] Beauty program not found: %s", executor_path)
  60. return False
  61. cmd = [
  62. executor_path,
  63. f"-i={inp}",
  64. f"-o={output}",
  65. f"-p={config}",
  66. f"-l={licence_path}",
  67. f"-face={face_model}",
  68. f"-hair={hair_model}",
  69. ]
  70. env = os.environ.copy()
  71. ld = env.get("LD_LIBRARY_PATH", "")
  72. env["LD_LIBRARY_PATH"] = f"{ld}:{lib_path}" if ld else lib_path
  73. logger.info("[smart_beauty] Executing: %s", " ".join(cmd))
  74. cmd_t0 = time.time()
  75. result = subprocess.run(
  76. cmd, cwd=workspace, env=env,
  77. capture_output=True, text=True, timeout=60,
  78. )
  79. cmd_elapsed = time.time() - cmd_t0
  80. if result.stdout:
  81. logger.info("[smart_beauty] stdout: %s", result.stdout.strip())
  82. if result.stderr:
  83. logger.warning("[smart_beauty] stderr: %s", result.stderr.strip())
  84. if result.returncode == 0:
  85. out_file = os.path.join(workspace, output)
  86. if os.path.isfile(out_file):
  87. file_size = os.path.getsize(out_file)
  88. logger.info("[smart_beauty] Output generated: %s (%.1f KB) in %.2fs",
  89. output, file_size / 1024, cmd_elapsed)
  90. return True
  91. logger.warning("[smart_beauty] Output file not generated: %s", output)
  92. return False
  93. else:
  94. logger.error("[smart_beauty] Process failed: exit_code=%d in %.2fs",
  95. result.returncode, cmd_elapsed)
  96. return False
  97. except subprocess.TimeoutExpired:
  98. logger.error("[smart_beauty] Process timeout (60s) for input: %s", inp)
  99. return False
  100. except Exception as e:
  101. logger.error("[smart_beauty] Error executing command: %s", e)
  102. return False
  103. def _get_base_name(path: str) -> str:
  104. name = os.path.basename(path)
  105. dot = name.rfind(".")
  106. return name[:dot] if dot > 0 else name