From c36d5f620b30bef644a770e8e4cb71ff60d654d8 Mon Sep 17 00:00:00 2001
From: wangzhibo <wangzhibo@shsening.com>
Date: 星期三, 30 七月 2025 22:21:18 +0800
Subject: [PATCH] Merge branch 'master' of http://222.71.114.84:7070/r/AutoMediaPublisher

---
 data/auto_media_publisher.sqlite3 |    0 
 /dev/null                         |   17 -----------------
 2 files changed, 0 insertions(+), 17 deletions(-)

diff --git a/auto_media_publisher/utils/face_swap/__init__.py b/auto_media_publisher/utils/face_swap/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/auto_media_publisher/utils/face_swap/__init__.py
+++ /dev/null
diff --git a/auto_media_publisher/utils/face_swap/face_analyser.py b/auto_media_publisher/utils/face_swap/face_analyser.py
deleted file mode 100644
index e927185..0000000
--- a/auto_media_publisher/utils/face_swap/face_analyser.py
+++ /dev/null
@@ -1,54 +0,0 @@
-
-import torch
-from typing import Optional, List
-import numpy
-from insightface.app import FaceAnalysis
-from insightface.app.common import Face
-
-from gfpgan.utils import GFPGANer
-from .typing import Frame # 浣犲凡鏈夊畾涔�
-
-SIMILAR_FACE_DISTANCE: float = 0.45     # < 0.4 鍚屼竴浜� 0.4 -0.6 澶ф鏄悓涓�浜� >0.6 涓嶆槸鍚屼竴涓�
-
-
-class FaceAnalyser:
-    def __init__(self):
-        self.device = self._select_device()
-        self._analyser = FaceAnalysis(name='buffalo_l', root='./', providers=['CUDAExecutionProvider' if self.device == 'cuda' else 'CPUExecutionProvider'])
-        self._analyser.prepare(ctx_id=0, det_size=(640, 640))
-
-    def _select_device(self):
-        return 'cpu'
-        if torch.cuda.is_available():
-            return 'cuda'
-        elif torch.backends.mps.is_available():
-            return 'mps'
-        else:
-            return 'cpu'
-        
-    def get_many_faces(self,frame: Frame) -> Optional[List[Face]]:
-        try:
-            return self._analyser.get(frame)
-        except Exception as e:
-            print(f"{e}")
-            return None
-
-    def get_one_face(self,frame: Frame, position: int = 0) -> Optional[Face]:
-        many_faces = self.get_many_faces(frame)
-        if many_faces:
-            try:
-                return many_faces[position]
-            except IndexError:
-                return many_faces[-1]
-        return None
-
-
-    def find_similar_face(self,frame: Frame, reference_face: Face) -> Optional[Face]:
-        many_faces = self.get_many_faces(frame)
-        if many_faces:
-            for face in many_faces:
-                if hasattr(face, 'normed_embedding') and hasattr(reference_face, 'normed_embedding'):
-                    distance = numpy.sum(numpy.square(face.normed_embedding - reference_face.normed_embedding))
-                    if distance < SIMILAR_FACE_DISTANCE:
-                        return face
-        return None
diff --git a/auto_media_publisher/utils/face_swap/face_enhancer.py b/auto_media_publisher/utils/face_swap/face_enhancer.py
deleted file mode 100644
index d4b6beb..0000000
--- a/auto_media_publisher/utils/face_swap/face_enhancer.py
+++ /dev/null
@@ -1,50 +0,0 @@
-
-import torch
-from typing import List
-from insightface.app.common import Face
-
-from gfpgan.utils import GFPGANer
-from .typing import Frame # 浣犲凡鏈夊畾涔�
-from auto_media_publisher.config.conf_base import FACE_ENHANCER_MODEL_PATH
-
-SIMILAR_FACE_DISTANCE: float = 0.45     # < 0.4 鍚屼竴浜� 0.4 -0.6 澶ф鏄悓涓�浜� >0.6 涓嶆槸鍚屼竴涓�
-
-
-class FaceEnhancer:
-    def __init__(self):
-        self.device = self._select_device()
-        self._enhancer = GFPGANer(model_path=FACE_ENHANCER_MODEL_PATH, upscale=1, device=self.device)
-
-    def _select_device(self):
-        return 'cpu'
-        if torch.cuda.is_available():
-            return 'cuda'
-        elif torch.backends.mps.is_available():
-            return 'mps'
-        else:
-            return 'cpu'
-        
-    def _enhance_face(self,target_face: Face, temp_frame: Frame) -> Frame:
-        start_x, start_y, end_x, end_y = map(int, target_face['bbox'])
-        padding_x = int((end_x - start_x) * 0.5)
-        padding_y = int((end_y - start_y) * 0.5)
-        start_x = max(0, start_x - padding_x)
-        start_y = max(0, start_y - padding_y)
-        end_x = max(0, end_x + padding_x)
-        end_y = max(0, end_y + padding_y)
-        temp_face = temp_frame[start_y:end_y, start_x:end_x]
-        if temp_face.size:
-            _, _, temp_face = self._enhancer.enhance(
-                temp_face,
-                paste_back=True
-            )
-            temp_frame[start_y:end_y, start_x:end_x] = temp_face
-        return temp_frame
-
-
-    def process_frame(self,temp_frame: Frame,many_faces:List) -> Frame:
-        #many_faces = self._get_many_faces(temp_frame)  check face_analyser.py
-        if many_faces:
-            for target_face in many_faces:
-                temp_frame = self._enhance_face(target_face, temp_frame)
-        return temp_frame
diff --git a/auto_media_publisher/utils/face_swap/face_nsfw_predictor.py b/auto_media_publisher/utils/face_swap/face_nsfw_predictor.py
deleted file mode 100644
index 8cc5f96..0000000
--- a/auto_media_publisher/utils/face_swap/face_nsfw_predictor.py
+++ /dev/null
@@ -1,28 +0,0 @@
-import threading
-import numpy as np
-from PIL import Image
-from keras import Model
-import opennsfw2
-
-from .typing import Frame  # 浣犲凡鏈夊畾涔�
-
-MAX_PROBABILITY = 0.85
-
-class NSFWPredictor:
-    def __init__(self):
-        self._predictor = opennsfw2.make_open_nsfw_model()
-
-    def predict_frame(self, frame: Frame) -> bool:
-        image = Image.fromarray(frame)
-        image = opennsfw2.preprocess_image(image, opennsfw2.Preprocessing.YAHOO)
-        views = np.expand_dims(image, axis=0)
-        _, probability = self._predictor.predict(views)[0]
-        return probability > MAX_PROBABILITY
-
-    def predict_image(self, image_path: str) -> bool:
-        probability = opennsfw2.predict_image(image_path)
-        return probability > MAX_PROBABILITY
-
-    def predict_video(self, video_path: str, frame_interval: int = 100) -> bool:
-        _, probabilities = opennsfw2.predict_video_frames(video_path, frame_interval=frame_interval)
-        return any(prob > MAX_PROBABILITY for prob in probabilities)
diff --git a/auto_media_publisher/utils/face_swap/face_swaper_cv2.py b/auto_media_publisher/utils/face_swap/face_swaper_cv2.py
deleted file mode 100644
index 1e2dc41..0000000
--- a/auto_media_publisher/utils/face_swap/face_swaper_cv2.py
+++ /dev/null
@@ -1,138 +0,0 @@
-import cv2
-import numpy as np
-import insightface
-from insightface.app import FaceAnalysis
-from insightface.app.common import Face
-import threading
-from gfpgan.utils import GFPGANer
-from typing import Any
-
-Frame = np.ndarray
-
-
-class FaceProcessor:
-    """
-    璋冪敤cv鐨勬ā鍧楀垎瑙p4锛岀粍瑁卪p4锛岃棰戣川閲忓樊 
-    """
-    def __init__(self, face_enhancer_model: str = 'GFPGANv1.4.pth', face_swapper_model: str = 'inswapper_128.onnx', device: str = 'cuda'):
-        self.FACE_ENHANCER = None
-        self.FACE_SWAPPER = None
-        self.THREAD_SEMAPHORE = threading.Semaphore()
-        self.THREAD_LOCK = threading.Lock()
-
-        # Set device
-        self.device = device  # 'cuda' for GPU, 'cpu' for CPU
-
-        # Load models
-        self.face_enhancer_model = face_enhancer_model
-        self.face_swapper_model = face_swapper_model
-
-        # Initialize face analysis app
-        self.app = FaceAnalysis(providers=['CUDAExecutionProvider' if device == 'cuda' else 'CPUExecutionProvider'])
-        self.app.prepare(ctx_id=0, det_size=(640, 640))
-
-    def get_face_enhancer(self) -> GFPGANer:
-        with self.THREAD_LOCK:
-            if self.FACE_ENHANCER is None:
-                self.FACE_ENHANCER = GFPGANer(
-                    model_path=self.face_enhancer_model, upscale=1, device=self.device)
-        return self.FACE_ENHANCER
-
-    def get_face_swapper(self) -> Any:
-        with self.THREAD_LOCK:
-            if self.FACE_SWAPPER is None:
-                self.FACE_SWAPPER = insightface.model_zoo.get_model(
-                    self.face_swapper_model, providers=['CUDAExecutionProvider' if self.device == 'cuda' else 'CPUExecutionProvider'])
-        return self.FACE_SWAPPER
-
-    def enhance_face(self, target_face: Face, temp_frame: Frame) -> Frame:
-        start_x, start_y, end_x, end_y = map(int, target_face['bbox'])
-        padding_x = int((end_x - start_x) * 0.5)
-        padding_y = int((end_y - start_y) * 0.5)
-        start_x = max(0, start_x - padding_x)
-        start_y = max(0, start_y - padding_y)
-        end_x = max(0, end_x + padding_x)
-        end_y = max(0, end_y + padding_y)
-        temp_face = temp_frame[start_y:end_y, start_x:end_x]
-        if temp_face.size:
-            with self.THREAD_SEMAPHORE:
-                _, _, temp_face = self.get_face_enhancer().enhance(
-                    temp_face,
-                    paste_back=True
-                )
-            temp_frame[start_y:end_y, start_x:end_x] = temp_face
-        return temp_frame
-
-    def swap_face(self, source_face: Face, target_face: Face, temp_frame: Frame) -> Frame:
-        return self.get_face_swapper().get(temp_frame, target_face, source_face, paste_back=True)
-
-    def process_video(self, src_mp4: str, image_path: str, dst_mp4: str) -> None:
-        # Read the target image (source face)
-        target_image = cv2.imread(image_path)
-        target_faces = self.app.get(target_image)
-        if len(target_faces) == 0:
-            print("No face detected in the target image.")
-            return
-        target_face = target_faces[0]
-
-        # Open the source video
-        cap = cv2.VideoCapture(src_mp4)
-        if not cap.isOpened():
-            print("Error opening video stream or file")
-            return
-
-        # Get video properties
-        fourcc = cv2.VideoWriter_fourcc(*'mp4v')
-        fps = cap.get(cv2.CAP_PROP_FPS)
-        frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
-        frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
-
-        # Create VideoWriter object to save the output video
-        out = cv2.VideoWriter(dst_mp4, fourcc, fps, (frame_width, frame_height))
-
-        # Get the total frame count
-        total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
-
-        # Process each frame of the video
-        frame_count = 0
-        while cap.isOpened():
-            ret, frame = cap.read()
-            if not ret:
-                break
-
-            # Detect faces in the current frame
-            faces = self.app.get(frame)
-            if len(faces) > 0:
-                # Swap face from the target image to the current frame
-                swapped_face_frame = self.swap_face(target_face, faces[0], frame)
-                self.enhance_face(faces[0], swapped_face_frame)
-                out.write(swapped_face_frame)
-            else:
-                # If no face detected, just write the original frame
-                out.write(frame)
-
-            # Increment frame count
-            frame_count += 1
-
-            # Calculate and print progress every 5%
-            progress = (frame_count / total_frames) * 100
-            if progress >= 5 * (frame_count // (total_frames // 20)):
-                print(f"Processing: {int(progress)}% completed")
-
-        cap.release()
-        out.release()
-        print(f"Video processing complete. Output saved to {dst_mp4}")
-
-
-# Usage example:
-
-# Initialize the FaceProcessor (use 'cuda' for GPU)
-face_processor = FaceProcessor(device='cpu')
-
-# Process the video by swapping faces from the target image
-# face_processor.process_video('g1.mp4', 'from-face/girl-1.png', './g1-demo_output.mp4')
-# face_processor.process_video('g1.mp4', 'from-face/girl-2.png', './g2-demo_output.mp4')
-face_processor.process_video('g3.mp4', 'lilizhen.jpg', './lilizhen_output.mp4')
-face_processor.process_video('g3.mp4', 'from-face/girl-1.png', './g1-demo_output.mp4')
-face_processor.process_video('g3.mp4', 'from-face/girl-2.png', './g2-demo_output.mp4')
-
diff --git a/auto_media_publisher/utils/face_swap/face_swaper_ffmpeg.py b/auto_media_publisher/utils/face_swap/face_swaper_ffmpeg.py
deleted file mode 100644
index 7b28497..0000000
--- a/auto_media_publisher/utils/face_swap/face_swaper_ffmpeg.py
+++ /dev/null
@@ -1,245 +0,0 @@
-import cv2
-import os
-import torch
-import queue
-import threading
-import subprocess
-import json
-import numpy as np
-import time
-from typing import Union
-import insightface
-from insightface.app.common import Face
-from .face_nsfw_predictor import NSFWPredictor
-from .face_enhancer import FaceEnhancer
-from .face_analyser import FaceAnalyser
-from auto_media_publisher.utils.logger import get_logger
-from auto_media_publisher.config.conf_base import FACE_SWAPPER_MODEL_PATH
-
-
-class FaceSwapWorker:
-    def __init__(self, enable_enhancer:bool = False,enable_nsfw_predictor:bool=False):
-        self.logger = get_logger("FaceSwapWorker", "admin")      
-        self.device = self._select_device()
-        self.face_swaper = insightface.model_zoo.get_model(FACE_SWAPPER_MODEL_PATH, providers=['CUDAExecutionProvider' if self.device == 'cuda' else 'CPUExecutionProvider'])
-        self.main_analyser = FaceAnalyser()
-        self.enable_enhancer = enable_enhancer
-        self.enable_nsfw_predictor = enable_nsfw_predictor
-        if self.enable_nsfw_predictor:
-            self.nsfw_predictor = NSFWPredictor()
-        self._init()
-        
-    def _init(self):
-        self.frame_queue = queue.Queue()
-        self.processed_queue = queue.Queue()
-        self.buffered_frames = {}
-        self.expected_index = 0
-        self.fps = 0
-        self.width = 0
-        self.height = 0
-        self.total_frames = 0
-        self.process_threads = []
-        self.num_processors = 4
-
-    def _select_device(self):
-        if torch.cuda.is_available():
-            return 'cuda'
-        elif torch.backends.mps.is_available():
-            return 'mps'
-        else:
-            return 'cpu'
-
-    def _decode_video(self):
-        # === Step 1: 鐢� ffprobe 鑾峰彇瑙嗛淇℃伅 ===
-        probe_cmd = [
-            "ffprobe",
-            "-v", "error",
-            "-select_streams", "v:0",
-            "-show_entries", "stream=width,height,r_frame_rate",
-            "-of", "json",
-            self.input_video_path
-        ]
-        probe_result = subprocess.run(probe_cmd, capture_output=True, text=True, check=True)
-        probe_data = json.loads(probe_result.stdout)
-        video_stream = probe_data['streams'][0]
-        self.width = int(video_stream['width'])
-        self.height = int(video_stream['height'])
-        self.fps = eval(video_stream['r_frame_rate'])  # e.g. "30/1"
-
-        print(f"Video info: {self.width}x{self.height} @ {self.fps}fps")
-
-        # === Step 2: 鐢� ffmpeg 瑙g爜杈撳嚭 rawvideo 鍒� stdout pipe ===
-        decode_cmd = [
-            "ffmpeg",
-            "-loglevel", "info",
-            "-i", self.input_video_path,
-            "-f", "rawvideo",
-            "-pix_fmt", "rgb24",
-            "pipe:1"
-        ]
-        process = subprocess.Popen(decode_cmd, stdout=subprocess.PIPE, bufsize=10**8)
-
-        frame_size = self.width * self.height * 3
-        idx = 0
-        while True:
-            in_bytes = process.stdout.read(frame_size)
-            if not in_bytes:
-                break
-            frame = np.frombuffer(in_bytes, dtype=np.uint8).reshape((self.height, self.width, 3))
-            self.frame_queue.put((idx, frame))  # 鏀逛负 tuple 褰㈠紡
-            idx += 1
-
-        self.total_frames = idx
-        print(f"_decode_video Total frames: {self.total_frames}")
-
-        process.stdout.close()
-        process.wait()
-
-        # 閫氱煡澶勭悊绾跨▼缁撴潫
-        for _ in range(self.num_processors):
-            self.frame_queue.put(None)
-
-    def _process_frame(self):
-        thread_face_analyser = FaceAnalyser()
-        if self.enable_enhancer:
-            thread_face_enhancer = FaceEnhancer()
-        while True:
-            item = self.frame_queue.get()
-            if item is None:
-                self.processed_queue.put(None)  # 鎶婄粨鏉熶俊鍙风户缁紶閫�
-                break
-
-            idx, frame = item
-
-            print(f"[Thread ID: {threading.get_ident()}] is processing frame : {idx} of video file 锛歿self.input_video_path}")
-
-            old_face  = thread_face_analyser.get_one_face(frame)
-            if old_face:
-                frame = self.face_swaper.get(frame,old_face,self.new_face)
-            else:
-                print("face not detected")
-
-            print(self.enable_enhancer)
-
-            if self.enable_enhancer:
-                many_faces= thread_face_analyser.get_many_faces(frame)
-                if many_faces:
-                    frame = thread_face_enhancer.process_frame(frame,many_faces)
-                
-            self.processed_queue.put((idx, frame))
-
-    def _encode_video(self):
-        while not (self.width and self.height and self.fps):
-            time.sleep(0.01)
-        encode_cmd = [
-            "ffmpeg",
-            "-loglevel", "info",
-            "-y",  # 瑕嗙洊杈撳嚭鏂囦欢
-            "-f", "rawvideo",
-            "-pixel_format", "rgb24",
-            "-video_size", f"{self.width}x{self.height}",
-            "-framerate", str(self.fps),
-            "-i", "pipe:0",  # 浠� stdin 璇诲彇鍘熷瑙嗛甯�
-            #"-i", self.input_video_path if self.new_audio_path is None else self.new_audio_path, # 鎻愪緵闊抽
-            "-c:v", "libx264",   # 浣犲彲浠ユ浛鎹㈡垚 h264_nvenc銆乭evc_nvenc銆乭264_amf銆乭264_qsv 绛夌‖浠剁紪鐮佸櫒,璐ㄩ噺鍙兘绋嶅井閫婅壊
-            "-crf", "18",
-            "-preset", "veryfast",
-            "-pix_fmt", "yuv420p",
-             #"-c:a", "copy",
-             #"-map", "0:v:0",
-             #"-map", "1:a:0",
-             #"-shortest",
-            self.output_video_path
-            ]
-
-        process = subprocess.Popen(encode_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,bufsize=10**8)
-        
-        end_signals_received = 0
-        finished = 0
-
-        while True:
-            item = self.processed_queue.get()
-            if item is None:
-                end_signals_received += 1
-                if end_signals_received == self.num_processors:
-                    break
-                else:
-                    continue
-            idx,frame = item
-            self.buffered_frames[idx] = frame
-
-            while self.expected_index in self.buffered_frames:
-                next_frame = self.buffered_frames.pop(self.expected_index)
-                print(f"_encode frame next_frame: {self.expected_index}")
-                try:
-                    process.stdin.write(next_frame.astype(np.uint8).tobytes())
-                except BrokenPipeError:
-                    print("BrokenPipeError: ffmpeg process closed stdin.")
-                    break
-                self.expected_index += 1
-                finished += 1
-                print(f"_encode frame finished: {finished}")
-
-        
-        print(f"Total frames encoded: {finished}")
-
-        process.stdin.close()
-        return_code = process.wait()
-        print("FFmpeg exited with code:", return_code)
-
-    def swap_face(self,new_face_image_path:str,input_video_path: str, output_video_path: str,num_processors=4):
-        """
-        鎵ц鎹㈣劯鎿嶄綔锛屽弬鏁板涓嬶細
-        1銆� 鏂扮殑鑴哥収鐗囷紝璺緞瑕佹纭紝杩樿鍖呭惈涓�寮犱汉鑴革紱
-        2銆� 鑰佺殑瑙嗛锛岃矾寰勮姝g‘
-        3銆� 鏂拌棰� 鏈�缁堣緭鍑虹殑瑙嗛璺緞
-        4銆� 骞跺彂澶勭悊杩涚▼鏁伴噺锛岄粯璁ゆ槸4锛屼緷鎹‖浠舵�ц兘璁剧疆
-        5銆� 鏂拌棰� 鐨勯煶棰戯紝濡傛灉涓嶄负绌猴紝灏变娇鐢紱 鍚﹀垯 浣跨敤鑰佽棰戠殑闊抽
-        """
-        self._init()
-        self.num_processors = num_processors
-
-        if not os.path.exists(new_face_image_path):
-            self.logger.error(f"face swap image_path: {new_face_image_path} does not exists.")
-            return
-        self.new_face = self.main_analyser.get_one_face(cv2.imread(new_face_image_path))
-        if not self.new_face :
-            self.logger.error(f"target image DO NOT has face : {new_face_image_path} does not exists.")
-            return
-        
-        if not os.path.exists(input_video_path):
-            self.logger.error(f"face swap video_path: {input_video_path} does not exists.")
-            return
-       
-        self.input_video_path = input_video_path
-        self.output_video_path = output_video_path
-        #self.new_audio_path =new_audio_path
-
-        if self.enable_nsfw_predictor and self.nsfw_predictor:
-            if self.nsfw_predictor.predict_video(input_video_path):
-                self.logger.error(f" 瑙嗛杩濊锛� {self.input_video_path}")
-                return
-
-        # 1. 鍚姩 encode 绾跨▼锛堥渶瑕佺瓑寰� width/height/fps 璁剧疆锛屼絾鍙互鏀惧湪鍓嶉潰锛�
-        encode_thread = threading.Thread(target=self._encode_video)
-        encode_thread.start()
-
-        # 2. 鍚姩 decode 绾跨▼锛堣礋璐d粠瑙嗛涓鍙栧抚锛�
-        decode_thread = threading.Thread(target=self._decode_video)
-        decode_thread.start()
-
-        # 3. 鍚姩澶勭悊绾跨▼
-        for i in range(self.num_processors):
-            t = threading.Thread(target=self._process_frame)
-            t.start()
-            self.process_threads.append(t)
-
-        # 4. 绛夊緟 decode 瀹屾垚
-        decode_thread.join()
-
-        # 5. 绛夊緟鎵�鏈夊鐞嗙嚎绋嬪畬鎴�
-        for t in self.process_threads:
-            t.join()
-
-        # 6. 绛夊緟 encode 瀹屾垚
-        encode_thread.join()
diff --git a/auto_media_publisher/utils/face_swap/face_swaper_ffmpeg_stream.py b/auto_media_publisher/utils/face_swap/face_swaper_ffmpeg_stream.py
deleted file mode 100644
index 5966fe3..0000000
--- a/auto_media_publisher/utils/face_swap/face_swaper_ffmpeg_stream.py
+++ /dev/null
@@ -1,243 +0,0 @@
-import os
-import cv2
-import subprocess
-import threading
-from threading import Thread, current_thread
-import queue
-import numpy as np
-import torch
-import json
-import insightface
-from insightface.app.common import Face
-from .face_nsfw_predictor import NSFWPredictor
-from .face_enhancer import FaceEnhancer
-from .face_analyser import FaceAnalyser
-from auto_media_publisher.utils.logger import get_logger
-from auto_media_publisher.config.conf_base import FACE_SWAPPER_MODEL_PATH
-
-
-class FFmpegVideoProcessor:
-    def __init__(self,enable_enhancer:bool=False,enable_nsfw_predictor:bool=False):
-        self.logger = get_logger("FaceSwapWorker", "admin")      
-        self.device = self._select_device()
-        print(f"using device {self.device}")
-        self.face_swaper = insightface.model_zoo.get_model(FACE_SWAPPER_MODEL_PATH, providers=['CUDAExecutionProvider' if self.device == 'cuda' else 'CPUExecutionProvider'])
-        self.main_analyser = FaceAnalyser()
-        self.enable_enhancer = enable_enhancer
-        self.enable_nsfw_predictor = enable_nsfw_predictor
-        if self.enable_nsfw_predictor:
-            self.nsfw_predictor = NSFWPredictor()
-        self._init()
-    
-    def _init(self):
-        self.width = 0
-        self.height = 0
-        self.fps = 0
-        self.frame_queue = queue.Queue(maxsize=2000)  # 瑙g爜绾跨▼鏀惧抚
-        self.processed_queue = queue.Queue(maxsize=2000)  # 澶勭悊绾跨▼鏀惧抚
-        self.buffered_frames = {}
-        self.expected_index = 0
-        
-        self.stop_event = threading.Event()
-
-    def _select_device(self):
-        return 'cpu'
-        if torch.cuda.is_available():
-            return 'cuda'
-        elif torch.backends.mps.is_available():
-            return 'mps'
-        else:
-            return 'cpu'
-    
-    def probe_video(self):
-        cmd = [
-            "ffprobe",
-            "-v", "error",
-            "-select_streams", "v:0",
-            "-show_entries", "stream=width,height,r_frame_rate",
-            "-of", "json",
-            self.input_video_path,
-        ]
-        proc = subprocess.run(cmd, capture_output=True, text=True, check=True)
-        info = json.loads(proc.stdout)
-        stream = info["streams"][0]
-        self.width = int(stream["width"])
-        self.height = int(stream["height"])
-        self.fps = eval(stream["r_frame_rate"])
-        print(f"Video info: {self.width}x{self.height} @ {self.fps}fps")
-    
-    def decode_worker(self):
-        decode_cmd = [
-            "ffmpeg",
-            "-loglevel", "error",
-            "-i", self.input_video_path,
-            "-f", "rawvideo",
-            "-pix_fmt", "rgb24",
-            "pipe:1",
-        ]
-        self.decode_proc = subprocess.Popen(decode_cmd, stdout=subprocess.PIPE, bufsize=10**8)
-        
-        frame_size = self.width * self.height * 3
-        idx = 0
-        while not self.stop_event.is_set():
-            raw_frame = self.decode_proc.stdout.read(frame_size)
-            if len(raw_frame) < frame_size:
-                break
-            frame = np.frombuffer(raw_frame, np.uint8).reshape((self.height, self.width, 3))
-            self.frame_queue.put((idx, frame))
-            idx += 1
-        
-        # 缁撴潫淇″彿
-        for _ in range(self.num_workers):
-            self.frame_queue.put(None)
-        self.decode_proc.stdout.close()
-        self.decode_proc.wait()
-    
-    def process_frame(self, frame: np.ndarray,thread_face_analyser,thread_face_enhancer) -> np.ndarray:
-        # 杩欓噷鏀句綘鐨勬崲鑴搞�佸彉閫熺瓑澶勭悊閫昏緫
-        # 渚嬪锛�
-        # frame = your_face_swap_function(frame)
-        # 鎴栬�呯畝鍗曠ず鑼冿細鍙嶈浆棰滆壊
-        #return 255 - frame
-        if self.enable_enhancer:
-            many_faces= thread_face_analyser.get_many_faces(frame)
-            if many_faces:
-                frame = self.face_swaper.get(frame,many_faces[0],self.new_face)
-                frame = thread_face_enhancer.process_frame(frame,many_faces)
-        else:
-            old_face  = thread_face_analyser.get_one_face(frame)
-            if old_face:
-                frame = self.face_swaper.get(frame,old_face,self.new_face)
-            else:
-                print("face not detected")
-
-        return frame
-    
-    def process_worker(self):
-        thread_face_analyser = FaceAnalyser()
-        if self.enable_enhancer:
-            thread_face_enhancer = FaceEnhancer()
-        else:
-            thread_face_enhancer = None
-        while True:
-            item = self.frame_queue.get()
-            if item is None:
-                self.processed_queue.put(None)
-                break
-            idx, frame = item
-            try:
-                processed = self.process_frame(frame,thread_face_analyser,thread_face_enhancer)
-                print(f"{current_thread().name} has proceesed frame :{idx}")
-            except:
-                print(f"{current_thread().name} has error frame :{idx}")
-                processed=frame
-            self.processed_queue.put((idx, processed))
-    
-    def encode_worker(self):
-        input_audio_path = self.input_video_path
-        if self.new_audio_path and os.path.exists(self.new_audio_path):
-            input_audio_path = self.new_audio_path
-        encode_cmd = [
-            "ffmpeg",
-            "-y",
-            "-loglevel", "error",
-            "-f", "rawvideo",
-            "-pixel_format", "rgb24",
-            "-video_size", f"{self.width}x{self.height}",
-            "-framerate", str(self.fps),
-            "-i", "pipe:0",
-            "-i", input_audio_path,
-            "-c:v", "libx264",
-            "-crf", "18",
-            "-preset", "veryfast",
-            "-c:a", "copy",
-            "-map", "0:v:0",
-            "-map", "1:a:0",
-            "-shortest",
-            self.output_video_path,
-        ]
-        self.encode_proc = subprocess.Popen(encode_cmd, stdin=subprocess.PIPE, bufsize=10**8)
-        
-        end_signals = 0
-        finished = 0
-        while True:
-            item = self.processed_queue.get()
-            if item is None:
-                end_signals += 1
-                if end_signals == self.num_workers:
-                    break
-                else:
-                    continue
-            
-            idx, frame = item
-            self.buffered_frames[idx] = frame
-            
-            while self.expected_index in self.buffered_frames:
-                f = self.buffered_frames.pop(self.expected_index)
-                try:
-                    self.encode_proc.stdin.write(f.astype(np.uint8).tobytes())
-                    print(f"{self.expected_index} has been writed into stdin")
-                except BrokenPipeError:
-                    print("FFmpeg encoding pipe broken.")
-                    self.stop_event.set()
-                    break
-                self.expected_index += 1
-                finished += 1
-        
-        self.encode_proc.stdin.close()
-        self.encode_proc.wait()
-        print(f"Encoding finished, total frames: {finished}")
-    
-    def run(self,new_face_image_path,input_video_path, output_video_path, num_workers=4,new_audio_path=None):
-        """
-        鎵ц鎹㈣劯鎿嶄綔锛屽弬鏁板涓嬶細
-        1銆� 鏂扮殑鑴哥収鐗囷紝璺緞瑕佹纭紝杩樿鍖呭惈涓�寮犱汉鑴革紱
-        2銆� 鑰佺殑瑙嗛锛岃矾寰勮姝g‘
-        3銆� 鏂拌棰� 鏈�缁堣緭鍑虹殑瑙嗛璺緞
-        4銆� 骞跺彂澶勭悊杩涚▼鏁伴噺锛岄粯璁ゆ槸4锛屼緷鎹‖浠舵�ц兘璁剧疆
-        5銆� 鏂拌棰� 鐨勯煶棰戯紝濡傛灉涓嶄负绌猴紝灏变娇鐢紱 鍚﹀垯 浣跨敤鑰佽棰戠殑闊抽
-        """
-        if not os.path.exists(new_face_image_path):
-            self.logger.error(f"face swap image_path: {new_face_image_path} does not exists.")
-            return
-        self.new_face = self.main_analyser.get_one_face(cv2.imread(new_face_image_path))
-
-        if not self.new_face :
-            self.logger.error(f"target image DO NOT has face : {new_face_image_path} does not exists.")
-            return
-        
-        if not os.path.exists(input_video_path):
-            self.logger.error(f"face swap video_path: {input_video_path} does not exists.")
-            return
-       
-        self._init()
-        self.input_video_path = input_video_path
-        self.output_video_path = output_video_path
-        self.num_workers = num_workers
-        self.new_audio_path =new_audio_path
-        
-        self.probe_video()
-        
-        threads = []
-        
-        # 瑙g爜绾跨▼
-        t_decode = threading.Thread(target=self.decode_worker)
-        threads.append(t_decode)
-        t_decode.start()
-        
-        # 澶氬鐞嗙嚎绋�
-        for i in range(self.num_workers):
-            t = threading.Thread(target=self.process_worker, name=f"process_worker_{i}")
-            threads.append(t)
-            t.start()
-        
-        # 缂栫爜绾跨▼
-        t_encode = threading.Thread(target=self.encode_worker)
-        threads.append(t_encode)
-        t_encode.start()
-        
-        for t in threads:
-            t.join()
-        
-        print("Processing complete.")
-
diff --git a/auto_media_publisher/utils/face_swap/typing.py b/auto_media_publisher/utils/face_swap/typing.py
deleted file mode 100644
index 30791ef..0000000
--- a/auto_media_publisher/utils/face_swap/typing.py
+++ /dev/null
@@ -1,17 +0,0 @@
-
-from typing import Any
-from insightface.app.common import Face
-import numpy
-
-Face = Face
-Frame = numpy.ndarray[Any, Any]
-'''
-from typing import Any
-import numpy
-import numpy.typing as npt  # Import numpy.typing for NDArray
-
-from insightface.app.common import Face
-
-Face = Face
-Frame = npt.NDArray[numpy.uint8]  # Specify the dtype, e.g., uint8 for image frames
-'''
\ No newline at end of file
diff --git a/data/auto_media_publisher.sqlite3 b/data/auto_media_publisher.sqlite3
index a846672..05e7791 100644
--- a/data/auto_media_publisher.sqlite3
+++ b/data/auto_media_publisher.sqlite3
Binary files differ

--
Gitblit v1.9.1