From 795e689b9d6f7e3c2997e2ce2ae9dde591edaf6d Mon Sep 17 00:00:00 2001 From: ROHAN PANDEY <95585299+rohan-pandeyy@users.noreply.github.com> Date: Wed, 27 May 2026 22:41:20 +0530 Subject: [PATCH 1/2] feat: update hardware detection utility to support apple silicon --- backend/app/utils/hardware_detect.py | 51 ++++++++++ docs/backend/backend_python/openapi.json | 113 ----------------------- 2 files changed, 51 insertions(+), 113 deletions(-) diff --git a/backend/app/utils/hardware_detect.py b/backend/app/utils/hardware_detect.py index dbbd8a9a0..1a6a257a4 100644 --- a/backend/app/utils/hardware_detect.py +++ b/backend/app/utils/hardware_detect.py @@ -1,5 +1,6 @@ import shutil import subprocess +import platform import onnxruntime as ort import psutil @@ -35,11 +36,60 @@ def detect_physical_gpu() -> list[str]: return gpu_names +def detect_apple_silicon() -> str | None: + if platform.system() != "Darwin": + return None + if platform.machine() != "arm64": + return None + + sysctl = shutil.which("sysctl") + if sysctl: + try: + result = subprocess.run( + [sysctl, "-n", "machdep.cpu.brand_string"], + capture_output=True, + text=True, + check=True, + timeout=5, + ) + chip_name = result.stdout.strip() + if chip_name: + return chip_name + except (OSError, subprocess.SubprocessError): + pass + + proc = platform.processor() + if proc: + return proc + + return "Apple Silicon" + + +def detect_apple_silicon_tier() -> str | None: + chip = detect_apple_silicon() + if chip is None: + return None + + chip_lower = chip.lower() + + # Base M1 and M2 chips (without Pro/Max/Ultra modifiers) are "small" + if any(base in chip_lower for base in ["m1", "m2"]): + if not any(mod in chip_lower for mod in ["pro", "max", "ultra"]): + return "small" + + # Default to medium for all other Apple Silicon (Pro/Max/Ultra, M3+, and future chips) + return "medium" + + def detect_hardware_tier() -> str: """ Detect system hardware to recommend the best YOLO/FaceNet model tier. Returns: 'nano', 'small', or 'medium' """ + apple_tier = detect_apple_silicon_tier() + if apple_tier is not None: + return apple_tier + # Check RAM in GB ram_gb = psutil.virtual_memory().total / (1024**3) @@ -66,6 +116,7 @@ def get_hardware_info() -> dict: "ram_gb": round(psutil.virtual_memory().total / (1024**3), 2), "gpu_detected": bool(gpu_names), "gpu_names": gpu_names, + "apple_silicon": detect_apple_silicon(), "available_providers": ort.get_available_providers(), "recommended_tier": detect_hardware_tier(), } diff --git a/docs/backend/backend_python/openapi.json b/docs/backend/backend_python/openapi.json index fc71e037a..795b415be 100644 --- a/docs/backend/backend_python/openapi.json +++ b/docs/backend/backend_python/openapi.json @@ -2073,119 +2073,6 @@ ], "title": "DeleteFoldersResponse" }, - "app__schemas__folders__ErrorResponse": { - "properties": { - "success": { - "type": "boolean", - "title": "Success", - "default": false - }, - "message": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Message" - }, - "error": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Error" - } - }, - "type": "object", - "title": "ErrorResponse" - }, - "app__schemas__face_clusters__ErrorResponse": { - "properties": { - "success": { - "type": "boolean", - "title": "Success", - "default": false - }, - "message": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Message" - }, - "error": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Error" - } - }, - "type": "object", - "title": "ErrorResponse" - }, - "app__schemas__images__ErrorResponse": { - "properties": { - "success": { - "type": "boolean", - "title": "Success", - "default": false - }, - "message": { - "type": "string", - "title": "Message" - }, - "error": { - "type": "string", - "title": "Error" - } - }, - "type": "object", - "required": [ - "message", - "error" - ], - "title": "ErrorResponse" - }, - "app__schemas__user_preferences__ErrorResponse": { - "properties": { - "success": { - "type": "boolean", - "title": "Success" - }, - "error": { - "type": "string", - "title": "Error" - }, - "message": { - "type": "string", - "title": "Message" - } - }, - "type": "object", - "required": [ - "success", - "error", - "message" - ], - "title": "ErrorResponse", - "description": "Error response model" - }, "FaceSearchRequest": { "properties": { "path": { From b22f81a6fcb4f0d743426714232b86d0e8aa23da Mon Sep 17 00:00:00 2001 From: ROHAN PANDEY <95585299+rohan-pandeyy@users.noreply.github.com> Date: Thu, 28 May 2026 14:10:18 +0530 Subject: [PATCH 2/2] include apple_silicon in frontend HardwareInfo interface --- .../src/components/OnboardingSteps/AIModelSetupStep.tsx | 8 +++++--- frontend/src/types/models.ts | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/OnboardingSteps/AIModelSetupStep.tsx b/frontend/src/components/OnboardingSteps/AIModelSetupStep.tsx index 7fa264264..f41fc33d0 100644 --- a/frontend/src/components/OnboardingSteps/AIModelSetupStep.tsx +++ b/frontend/src/components/OnboardingSteps/AIModelSetupStep.tsx @@ -262,9 +262,11 @@ export const AIModelSetupStep: React.FC = ({ - {hardwareSpecs.gpu_names?.length - ? hardwareSpecs.gpu_names.join(', ') - : 'No dedicated GPU'} + {hardwareSpecs.apple_silicon + ? hardwareSpecs.apple_silicon + : hardwareSpecs.gpu_names?.length + ? hardwareSpecs.gpu_names.join(', ') + : 'No dedicated GPU'} )} diff --git a/frontend/src/types/models.ts b/frontend/src/types/models.ts index c8da5b4a2..5c8997bac 100644 --- a/frontend/src/types/models.ts +++ b/frontend/src/types/models.ts @@ -24,6 +24,7 @@ export interface HardwareInfo { ram_gb: number; gpu_detected: boolean; gpu_names: string[]; + apple_silicon: string | null; available_providers: string[]; recommended_tier: ModelTier; }