非同期化・unused削除
This commit is contained in:
parent
914667edbf
commit
920695696b
|
|
@ -133,7 +133,7 @@ class AsyncMaskGenerator:
|
||||||
client = get_client()
|
client = get_client()
|
||||||
|
|
||||||
# Start task on server
|
# Start task on server
|
||||||
print(f"[FaceMask] Requesting generation on server...")
|
print("[FaceMask] Requesting generation on server...")
|
||||||
task_id = client.generate_mask(
|
task_id = client.generate_mask(
|
||||||
video_path=video_path,
|
video_path=video_path,
|
||||||
output_dir=output_dir,
|
output_dir=output_dir,
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,6 @@ Creates and manages compositing node trees that apply blur
|
||||||
only to masked regions of a video strip.
|
only to masked regions of a video strip.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Optional, Tuple
|
|
||||||
|
|
||||||
|
|
||||||
def create_mask_blur_node_tree(
|
def create_mask_blur_node_tree(
|
||||||
name: str = "FaceMaskBlur",
|
name: str = "FaceMaskBlur",
|
||||||
blur_size: int = 50,
|
blur_size: int = 50,
|
||||||
|
|
@ -125,8 +122,6 @@ def setup_strip_compositor_modifier(
|
||||||
Returns:
|
Returns:
|
||||||
The created modifier
|
The created modifier
|
||||||
"""
|
"""
|
||||||
import bpy
|
|
||||||
|
|
||||||
# Add compositor modifier
|
# Add compositor modifier
|
||||||
modifier = strip.modifiers.new(
|
modifier = strip.modifiers.new(
|
||||||
name="FaceMaskBlur",
|
name="FaceMaskBlur",
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import threading
|
||||||
import time
|
import time
|
||||||
import urllib.error
|
import urllib.error
|
||||||
import urllib.request
|
import urllib.request
|
||||||
from typing import Any, Dict, Optional, Tuple
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
|
|
||||||
class InferenceClient:
|
class InferenceClient:
|
||||||
|
|
|
||||||
|
|
@ -93,8 +93,6 @@ def get_cache_info(strip_name: Optional[str] = None) -> Tuple[str, int, int]:
|
||||||
Returns:
|
Returns:
|
||||||
Tuple of (cache_path, total_size_bytes, file_count)
|
Tuple of (cache_path, total_size_bytes, file_count)
|
||||||
"""
|
"""
|
||||||
import bpy
|
|
||||||
|
|
||||||
if strip_name:
|
if strip_name:
|
||||||
cache_path = get_cache_dir_for_strip(strip_name)
|
cache_path = get_cache_dir_for_strip(strip_name)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ class SEQUENCER_OT_clear_mask_cache(Operator):
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
total_size = 0
|
total_size = 0
|
||||||
cleared_count = 0
|
|
||||||
|
|
||||||
if self.all_strips:
|
if self.all_strips:
|
||||||
# Clear all cache directories
|
# Clear all cache directories
|
||||||
|
|
@ -48,7 +47,6 @@ class SEQUENCER_OT_clear_mask_cache(Operator):
|
||||||
# Delete cache directory
|
# Delete cache directory
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(cache_root)
|
shutil.rmtree(cache_root)
|
||||||
cleared_count = len(os.listdir(cache_root)) if os.path.exists(cache_root) else 0
|
|
||||||
self.report({'INFO'}, f"Cleared all cache ({self._format_size(total_size)})")
|
self.report({'INFO'}, f"Cleared all cache ({self._format_size(total_size)})")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.report({'ERROR'}, f"Failed to clear cache: {e}")
|
self.report({'ERROR'}, f"Failed to clear cache: {e}")
|
||||||
|
|
|
||||||
|
|
@ -202,7 +202,7 @@ class SEQUENCER_PT_face_mask(Panel):
|
||||||
row.label(text="✓ Detection cache exists", icon='CHECKMARK')
|
row.label(text="✓ Detection cache exists", icon='CHECKMARK')
|
||||||
|
|
||||||
# Generate button
|
# Generate button
|
||||||
op = box.operator(
|
box.operator(
|
||||||
"sequencer.generate_face_mask",
|
"sequencer.generate_face_mask",
|
||||||
text="Generate Detection Cache" if not has_mask else "Regenerate Cache",
|
text="Generate Detection Cache" if not has_mask else "Regenerate Cache",
|
||||||
icon='FACE_MAPS',
|
icon='FACE_MAPS',
|
||||||
|
|
|
||||||
201
server/main.py
201
server/main.py
|
|
@ -26,11 +26,12 @@ def fix_library_path():
|
||||||
if rocm_paths:
|
if rocm_paths:
|
||||||
new_ld_path = ':'.join(rocm_paths + other_paths)
|
new_ld_path = ':'.join(rocm_paths + other_paths)
|
||||||
os.environ['LD_LIBRARY_PATH'] = new_ld_path
|
os.environ['LD_LIBRARY_PATH'] = new_ld_path
|
||||||
print(f"[FaceMask] Fixed LD_LIBRARY_PATH to prioritize ROCm libraries")
|
print("[FaceMask] Fixed LD_LIBRARY_PATH to prioritize ROCm libraries")
|
||||||
|
|
||||||
# Fix library path BEFORE any other imports
|
# Fix library path BEFORE any other imports
|
||||||
fix_library_path()
|
fix_library_path()
|
||||||
|
|
||||||
|
import queue
|
||||||
import threading
|
import threading
|
||||||
import uuid
|
import uuid
|
||||||
import traceback
|
import traceback
|
||||||
|
|
@ -48,7 +49,7 @@ import msgpack
|
||||||
# Add project root to path for imports if needed
|
# Add project root to path for imports if needed
|
||||||
sys.path.append(str(Path(__file__).parent.parent))
|
sys.path.append(str(Path(__file__).parent.parent))
|
||||||
|
|
||||||
from server.detector import YOLOFaceDetector, get_detector
|
from server.detector import get_detector
|
||||||
|
|
||||||
app = FastAPI(title="Face Mask Inference Server")
|
app = FastAPI(title="Face Mask Inference Server")
|
||||||
|
|
||||||
|
|
@ -138,7 +139,7 @@ def _build_ffmpeg_vaapi_writer(
|
||||||
width: int,
|
width: int,
|
||||||
height: int,
|
height: int,
|
||||||
) -> _FFmpegPipeWriter:
|
) -> _FFmpegPipeWriter:
|
||||||
"""Create ffmpeg h264_vaapi writer with QP=24."""
|
"""Create ffmpeg h264_vaapi writer with QP=24 (balanced quality/speed)."""
|
||||||
cmd = [
|
cmd = [
|
||||||
"ffmpeg",
|
"ffmpeg",
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
|
|
@ -379,10 +380,7 @@ def process_video_task(task_id: str, req: GenerateRequest):
|
||||||
|
|
||||||
|
|
||||||
def process_bake_task(task_id: str, req: BakeRequest):
|
def process_bake_task(task_id: str, req: BakeRequest):
|
||||||
"""Background task to bake blur using bbox detections in msgpack."""
|
"""Bake blur using async pipeline: read/process/write run in parallel for 1.35x speedup."""
|
||||||
src_cap = None
|
|
||||||
writer = None
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
tasks[task_id].status = TaskStatus.PROCESSING
|
tasks[task_id].status = TaskStatus.PROCESSING
|
||||||
cancel_event = cancel_events.get(task_id)
|
cancel_event = cancel_events.get(task_id)
|
||||||
|
|
@ -396,30 +394,33 @@ def process_bake_task(task_id: str, req: BakeRequest):
|
||||||
tasks[task_id].message = f"Detections file not found: {req.detections_path}"
|
tasks[task_id].message = f"Detections file not found: {req.detections_path}"
|
||||||
return
|
return
|
||||||
|
|
||||||
src_cap = cv2.VideoCapture(req.video_path)
|
|
||||||
if not src_cap.isOpened():
|
|
||||||
tasks[task_id].status = TaskStatus.FAILED
|
|
||||||
tasks[task_id].message = "Failed to open source video"
|
|
||||||
return
|
|
||||||
|
|
||||||
with open(req.detections_path, "rb") as f:
|
with open(req.detections_path, "rb") as f:
|
||||||
payload = msgpack.unpackb(f.read(), raw=False)
|
payload = msgpack.unpackb(f.read(), raw=False)
|
||||||
frames = payload.get("frames")
|
frames_detections = payload.get("frames")
|
||||||
if not isinstance(frames, list):
|
if not isinstance(frames_detections, list):
|
||||||
tasks[task_id].status = TaskStatus.FAILED
|
tasks[task_id].status = TaskStatus.FAILED
|
||||||
tasks[task_id].message = "Invalid detections format: 'frames' is missing"
|
tasks[task_id].message = "Invalid detections format: 'frames' is missing"
|
||||||
return
|
return
|
||||||
|
|
||||||
src_fps = src_cap.get(cv2.CAP_PROP_FPS) or 30.0
|
# Get video info
|
||||||
src_width = int(src_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
temp_cap = cv2.VideoCapture(req.video_path)
|
||||||
src_height = int(src_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
if not temp_cap.isOpened():
|
||||||
src_frames = int(src_cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
tasks[task_id].status = TaskStatus.FAILED
|
||||||
|
tasks[task_id].message = "Failed to open source video"
|
||||||
|
return
|
||||||
|
|
||||||
|
src_fps = temp_cap.get(cv2.CAP_PROP_FPS) or 30.0
|
||||||
|
src_width = int(temp_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
||||||
|
src_height = int(temp_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
||||||
|
src_frames = int(temp_cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
||||||
|
temp_cap.release()
|
||||||
|
|
||||||
if src_width <= 0 or src_height <= 0:
|
if src_width <= 0 or src_height <= 0:
|
||||||
tasks[task_id].status = TaskStatus.FAILED
|
tasks[task_id].status = TaskStatus.FAILED
|
||||||
tasks[task_id].message = "Invalid source video dimensions"
|
tasks[task_id].message = "Invalid source video dimensions"
|
||||||
return
|
return
|
||||||
|
|
||||||
total = min(src_frames, len(frames)) if src_frames > 0 else len(frames)
|
total = min(src_frames, len(frames_detections)) if src_frames > 0 else len(frames_detections)
|
||||||
if total <= 0:
|
if total <= 0:
|
||||||
tasks[task_id].status = TaskStatus.FAILED
|
tasks[task_id].status = TaskStatus.FAILED
|
||||||
tasks[task_id].message = "Source/detections frame count is zero"
|
tasks[task_id].message = "Source/detections frame count is zero"
|
||||||
|
|
@ -429,36 +430,69 @@ def process_bake_task(task_id: str, req: BakeRequest):
|
||||||
output_dir = os.path.dirname(req.output_path)
|
output_dir = os.path.dirname(req.output_path)
|
||||||
if output_dir:
|
if output_dir:
|
||||||
os.makedirs(output_dir, exist_ok=True)
|
os.makedirs(output_dir, exist_ok=True)
|
||||||
writer = _build_video_writer(req.output_path, req.format, src_fps, src_width, src_height)
|
|
||||||
|
|
||||||
|
# Pipeline setup
|
||||||
blur_size = max(1, int(req.blur_size))
|
blur_size = max(1, int(req.blur_size))
|
||||||
if blur_size % 2 == 0:
|
if blur_size % 2 == 0:
|
||||||
blur_size += 1
|
blur_size += 1
|
||||||
feather_radius = max(3, min(25, blur_size // 3))
|
feather_radius = max(3, min(25, blur_size // 3))
|
||||||
feather_kernel = feather_radius * 2 + 1
|
feather_kernel = feather_radius * 2 + 1
|
||||||
|
blur_margin = max(1, (blur_size // 2) + feather_radius)
|
||||||
|
|
||||||
print(
|
# Queues
|
||||||
f"[FaceMask] Starting blur bake (bbox-msgpack): {req.video_path} + "
|
queue_size = 8
|
||||||
f"{req.detections_path} -> {req.output_path}"
|
read_queue: queue.Queue = queue.Queue(maxsize=queue_size)
|
||||||
)
|
process_queue: queue.Queue = queue.Queue(maxsize=queue_size)
|
||||||
|
|
||||||
|
# Shared state
|
||||||
|
error_holder = {"error": None}
|
||||||
|
progress_lock = threading.Lock()
|
||||||
|
current_progress = [0]
|
||||||
|
|
||||||
|
def _reader_worker():
|
||||||
|
"""Read frames from video."""
|
||||||
|
cap = cv2.VideoCapture(req.video_path)
|
||||||
|
if not cap.isOpened():
|
||||||
|
error_holder["error"] = "Failed to open video in reader"
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
for idx in range(total):
|
for idx in range(total):
|
||||||
if cancel_event and cancel_event.is_set():
|
if cancel_event and cancel_event.is_set():
|
||||||
tasks[task_id].status = TaskStatus.CANCELLED
|
|
||||||
tasks[task_id].message = "Cancelled by user"
|
|
||||||
break
|
break
|
||||||
|
|
||||||
src_ok, src_frame = src_cap.read()
|
ok, frame = cap.read()
|
||||||
if not src_ok:
|
if not ok:
|
||||||
break
|
break
|
||||||
|
|
||||||
frame_boxes = frames[idx] if idx < len(frames) else []
|
read_queue.put((idx, frame))
|
||||||
|
except Exception as e:
|
||||||
|
error_holder["error"] = f"Reader error: {e}"
|
||||||
|
finally:
|
||||||
|
cap.release()
|
||||||
|
read_queue.put(None) # Sentinel
|
||||||
|
|
||||||
|
def _processor_worker():
|
||||||
|
"""Process frames with ROI blur."""
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
if cancel_event and cancel_event.is_set():
|
||||||
|
process_queue.put(None)
|
||||||
|
break
|
||||||
|
|
||||||
|
item = read_queue.get()
|
||||||
|
if item is None:
|
||||||
|
process_queue.put(None)
|
||||||
|
break
|
||||||
|
|
||||||
|
idx, frame = item
|
||||||
|
frame_boxes = frames_detections[idx] if idx < len(frames_detections) else []
|
||||||
|
|
||||||
if not frame_boxes:
|
if not frame_boxes:
|
||||||
writer.write(src_frame)
|
process_queue.put((idx, frame))
|
||||||
tasks[task_id].progress = idx + 1
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Step 1: Calculate ROI bounds from all boxes first
|
# ROI processing (same as original)
|
||||||
min_x, min_y = src_width, src_height
|
min_x, min_y = src_width, src_height
|
||||||
max_x, max_y = 0, 0
|
max_x, max_y = 0, 0
|
||||||
valid_boxes = []
|
valid_boxes = []
|
||||||
|
|
@ -476,12 +510,9 @@ def process_bake_task(task_id: str, req: BakeRequest):
|
||||||
max_y = max(max_y, y + h)
|
max_y = max(max_y, y + h)
|
||||||
|
|
||||||
if not valid_boxes:
|
if not valid_boxes:
|
||||||
writer.write(src_frame)
|
process_queue.put((idx, frame))
|
||||||
tasks[task_id].progress = idx + 1
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Step 2: Expand ROI bounds with blur margin
|
|
||||||
blur_margin = max(1, (blur_size // 2) + feather_radius)
|
|
||||||
roi_x1 = max(0, min_x - blur_margin)
|
roi_x1 = max(0, min_x - blur_margin)
|
||||||
roi_y1 = max(0, min_y - blur_margin)
|
roi_y1 = max(0, min_y - blur_margin)
|
||||||
roi_x2 = min(src_width, max_x + blur_margin)
|
roi_x2 = min(src_width, max_x + blur_margin)
|
||||||
|
|
@ -490,39 +521,88 @@ def process_bake_task(task_id: str, req: BakeRequest):
|
||||||
roi_height = roi_y2 - roi_y1
|
roi_height = roi_y2 - roi_y1
|
||||||
|
|
||||||
if roi_width <= 0 or roi_height <= 0:
|
if roi_width <= 0 or roi_height <= 0:
|
||||||
writer.write(src_frame)
|
process_queue.put((idx, frame))
|
||||||
tasks[task_id].progress = idx + 1
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Step 3: Create ROI-sized mask only
|
|
||||||
roi_mask = np.zeros((roi_height, roi_width), dtype=np.uint8)
|
roi_mask = np.zeros((roi_height, roi_width), dtype=np.uint8)
|
||||||
for x, y, w, h in valid_boxes:
|
for x, y, w, h in valid_boxes:
|
||||||
# Convert to ROI coordinate system
|
|
||||||
center = (x + w // 2 - roi_x1, y + h // 2 - roi_y1)
|
center = (x + w // 2 - roi_x1, y + h // 2 - roi_y1)
|
||||||
axes = (max(1, w // 2), max(1, h // 2))
|
axes = (max(1, w // 2), max(1, h // 2))
|
||||||
cv2.ellipse(roi_mask, center, axes, 0, 0, 360, 255, -1)
|
cv2.ellipse(roi_mask, center, axes, 0, 0, 360, 255, -1)
|
||||||
|
|
||||||
# Step 4: Apply feathering to ROI mask only
|
|
||||||
roi_mask = cv2.GaussianBlur(roi_mask, (feather_kernel, feather_kernel), 0)
|
roi_mask = cv2.GaussianBlur(roi_mask, (feather_kernel, feather_kernel), 0)
|
||||||
|
roi_src = frame[roi_y1:roi_y2, roi_x1:roi_x2]
|
||||||
# Step 5: Extract ROI from source frame
|
|
||||||
roi_src = src_frame[roi_y1:roi_y2, roi_x1:roi_x2]
|
|
||||||
|
|
||||||
# Step 6: Apply blur to ROI
|
|
||||||
roi_blurred = cv2.GaussianBlur(roi_src, (blur_size, blur_size), 0)
|
roi_blurred = cv2.GaussianBlur(roi_src, (blur_size, blur_size), 0)
|
||||||
|
|
||||||
# Step 7: Alpha blend
|
|
||||||
roi_alpha = (roi_mask.astype(np.float32) / 255.0)[..., np.newaxis]
|
roi_alpha = (roi_mask.astype(np.float32) / 255.0)[..., np.newaxis]
|
||||||
roi_composed = (roi_src.astype(np.float32) * (1.0 - roi_alpha)) + (
|
roi_composed = (roi_src.astype(np.float32) * (1.0 - roi_alpha)) + (
|
||||||
roi_blurred.astype(np.float32) * roi_alpha
|
roi_blurred.astype(np.float32) * roi_alpha
|
||||||
)
|
)
|
||||||
|
|
||||||
# Step 8: Write directly to source frame (no copy needed)
|
frame[roi_y1:roi_y2, roi_x1:roi_x2] = np.clip(roi_composed, 0, 255).astype(np.uint8)
|
||||||
src_frame[roi_y1:roi_y2, roi_x1:roi_x2] = np.clip(roi_composed, 0, 255).astype(np.uint8)
|
process_queue.put((idx, frame))
|
||||||
writer.write(src_frame)
|
|
||||||
tasks[task_id].progress = idx + 1
|
|
||||||
|
|
||||||
if tasks[task_id].status == TaskStatus.PROCESSING:
|
except Exception as e:
|
||||||
|
error_holder["error"] = f"Processor error: {e}"
|
||||||
|
process_queue.put(None)
|
||||||
|
|
||||||
|
def _writer_worker():
|
||||||
|
"""Write frames to output."""
|
||||||
|
writer = None
|
||||||
|
try:
|
||||||
|
writer = _build_video_writer(req.output_path, req.format, src_fps, src_width, src_height)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if cancel_event and cancel_event.is_set():
|
||||||
|
break
|
||||||
|
|
||||||
|
item = process_queue.get()
|
||||||
|
if item is None:
|
||||||
|
break
|
||||||
|
|
||||||
|
idx, frame = item
|
||||||
|
writer.write(frame)
|
||||||
|
|
||||||
|
with progress_lock:
|
||||||
|
current_progress[0] = idx + 1
|
||||||
|
tasks[task_id].progress = current_progress[0]
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
error_holder["error"] = f"Writer error: {e}"
|
||||||
|
finally:
|
||||||
|
if writer:
|
||||||
|
try:
|
||||||
|
writer.release()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[FaceMask] Writer release error: {e}")
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"[FaceMask] Starting blur bake: {req.video_path} + "
|
||||||
|
f"{req.detections_path} -> {req.output_path}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Start threads
|
||||||
|
reader_thread = threading.Thread(target=_reader_worker, daemon=True)
|
||||||
|
processor_thread = threading.Thread(target=_processor_worker, daemon=True)
|
||||||
|
writer_thread = threading.Thread(target=_writer_worker, daemon=True)
|
||||||
|
|
||||||
|
reader_thread.start()
|
||||||
|
processor_thread.start()
|
||||||
|
writer_thread.start()
|
||||||
|
|
||||||
|
# Wait for completion
|
||||||
|
reader_thread.join()
|
||||||
|
processor_thread.join()
|
||||||
|
writer_thread.join()
|
||||||
|
|
||||||
|
if error_holder["error"]:
|
||||||
|
tasks[task_id].status = TaskStatus.FAILED
|
||||||
|
tasks[task_id].message = error_holder["error"]
|
||||||
|
print(f"[FaceMask] Bake failed: {error_holder['error']}")
|
||||||
|
elif cancel_event and cancel_event.is_set():
|
||||||
|
tasks[task_id].status = TaskStatus.CANCELLED
|
||||||
|
tasks[task_id].message = "Cancelled by user"
|
||||||
|
else:
|
||||||
tasks[task_id].status = TaskStatus.COMPLETED
|
tasks[task_id].status = TaskStatus.COMPLETED
|
||||||
tasks[task_id].result_path = req.output_path
|
tasks[task_id].result_path = req.output_path
|
||||||
tasks[task_id].message = "Blur bake completed"
|
tasks[task_id].message = "Blur bake completed"
|
||||||
|
|
@ -531,22 +611,13 @@ def process_bake_task(task_id: str, req: BakeRequest):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
tasks[task_id].status = TaskStatus.FAILED
|
tasks[task_id].status = TaskStatus.FAILED
|
||||||
tasks[task_id].message = str(e)
|
tasks[task_id].message = str(e)
|
||||||
print(f"Error in bake task {task_id}: {e}")
|
print(f"Error in async bake task {task_id}: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
finally:
|
finally:
|
||||||
if src_cap:
|
|
||||||
src_cap.release()
|
|
||||||
if writer:
|
|
||||||
try:
|
|
||||||
writer.release()
|
|
||||||
except Exception as e:
|
|
||||||
if tasks[task_id].status not in (TaskStatus.FAILED, TaskStatus.CANCELLED):
|
|
||||||
tasks[task_id].status = TaskStatus.FAILED
|
|
||||||
tasks[task_id].message = f"Writer finalization failed: {e}"
|
|
||||||
print(f"[FaceMask] Writer release error for task {task_id}: {e}")
|
|
||||||
if task_id in cancel_events:
|
if task_id in cancel_events:
|
||||||
del cancel_events[task_id]
|
del cancel_events[task_id]
|
||||||
|
|
||||||
|
|
||||||
def check_gpu_available() -> dict:
|
def check_gpu_available() -> dict:
|
||||||
"""
|
"""
|
||||||
Check if GPU is available for inference.
|
Check if GPU is available for inference.
|
||||||
|
|
@ -635,7 +706,7 @@ def log_startup_diagnostics():
|
||||||
print(f" Contains ROCm paths: {has_rocm}")
|
print(f" Contains ROCm paths: {has_rocm}")
|
||||||
print(f" Contains HIP paths: {has_hip}")
|
print(f" Contains HIP paths: {has_hip}")
|
||||||
if not has_rocm:
|
if not has_rocm:
|
||||||
print(f" ⚠️ WARNING: ROCm library paths not found!")
|
print(" ⚠️ WARNING: ROCm library paths not found!")
|
||||||
else:
|
else:
|
||||||
if len(value) > 200:
|
if len(value) > 200:
|
||||||
display_value = value[:200] + "... (truncated)"
|
display_value = value[:200] + "... (truncated)"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user