Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions backend/app/utils/hardware_detect.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import shutil
import subprocess
import platform

import onnxruntime as ort
import psutil
Comment on lines 1 to 6
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Add from __future__ import annotations for Python 3.9 compatibility.

The file uses PEP 604 union syntax (str | None) in type hints but is missing the required future import for Python 3.9 compatibility. Based on learnings, this repo targets Python 3.9 minimum and requires from __future__ import annotations when using X | Y syntax.

🔧 Proposed fix
+from __future__ import annotations
+
 import shutil
 import subprocess
 import platform
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import shutil
import subprocess
import platform
import onnxruntime as ort
import psutil
from __future__ import annotations
import shutil
import subprocess
import platform
import onnxruntime as ort
import psutil
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/app/utils/hardware_detect.py` around lines 1 - 6, This module uses
PEP 604 union syntax (e.g., annotations like "str | None") but lacks the
compatibility import; add "from __future__ import annotations" as the very first
line of backend/app/utils/hardware_detect.py (before any other imports such as
shutil, subprocess, platform, onnxruntime or psutil) so functions and type hints
in this file (e.g., any that use "|" unions) work on Python 3.9.

Expand Down Expand Up @@ -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"
Comment on lines +68 to +81
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Default tier for unknown Apple Silicon contradicts requirements.

Line 81 defaults unknown Apple Silicon chips to "medium", but issue #1292 explicitly requires unknown Apple Silicon to default to "small". This could lead to over-recommending model sizes for future or unrecognized chips.

📝 Proposed fix to match requirements
-    # Default to medium for all other Apple Silicon (Pro/Max/Ultra, M3+, and future chips)
-    return "medium"
+    # M3+, Pro/Max/Ultra variants are medium
+    # M3, M4, and newer chips (with or without modifiers) should be medium
+    if any(chip in chip_lower for chip in ["m3", "m4", "m5", "m6", "m7", "m8", "m9"]):
+        return "medium"
+    if any(mod in chip_lower for mod in ["pro", "max", "ultra"]):
+        return "medium"
+    
+    # Default to small for unknown Apple Silicon chips
+    return "small"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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_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"
# M3+, Pro/Max/Ultra variants are medium
# M3, M4, and newer chips (with or without modifiers) should be medium
if any(chip in chip_lower for chip in ["m3", "m4", "m5", "m6", "m7", "m8", "m9"]):
return "medium"
if any(mod in chip_lower for mod in ["pro", "max", "ultra"]):
return "medium"
# Default to small for unknown Apple Silicon chips
return "small"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/app/utils/hardware_detect.py` around lines 68 - 81, The function
detect_apple_silicon_tier currently returns "medium" by default for any Apple
Silicon not matched as base M1/M2 small, which contradicts issue `#1292`; update
detect_apple_silicon_tier (using the chip variable from detect_apple_silicon())
so that the final/default return is "small" instead of "medium" while keeping
existing logic that explicitly classifies Pro/Max/Ultra as non-small.



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)

Expand All @@ -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(),
}
8 changes: 5 additions & 3 deletions frontend/src/components/OnboardingSteps/AIModelSetupStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -262,9 +262,11 @@ export const AIModelSetupStep: React.FC<AIModelSetupStepProps> = ({
</span>
<span className="bg-muted/60 text-muted-foreground inline-flex items-center gap-1 rounded-full border px-3 py-1 text-xs font-medium">
<Cpu className="h-3 w-3" />
{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'}
</span>
</div>
)}
Expand Down
1 change: 1 addition & 0 deletions frontend/src/types/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Loading