From 29c24a15208f2148d0417e2195a41cd1db1a7820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=EC=B0=AC?= Date: Sat, 11 Apr 2026 09:11:07 +0900 Subject: [PATCH] =?UTF-8?q?fix(desktop):=20Mac=20sidecar=20=EB=B6=80?= =?UTF-8?q?=ED=8C=85=20+=20=EB=8B=A8=EC=B6=95=ED=82=A4=20=EB=85=B9?= =?UTF-8?q?=ED=99=94=20=EB=AA=A8=EB=8B=AC=20=E2=8C=98=20=ED=91=9C=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 문제 1: STT release 안 됨 → 진짜 원인은 sidecar import 실패 - 시스템 python3 (Python 3.13)에 numpy/faster-whisper 등 sidecar deps 없음 - 매번 spawn 직후 ModuleNotFoundError로 즉사 → /health 30s 타임아웃 - 사용자에게는 '핫키 release 안 됨'으로 보이지만, 실제로는 핫키는 정상, STT 응답이 없어 결과 팝업이 안 뜬 것 수정: - apps/desktop/sidecar/.venv/ 신규 (gitignored) - Python 3.13.13 venv - 최소 deps: faster-whisper 1.2.1, fastapi 0.135, uvicorn 0.44, python-multipart, numpy 2.4 - torch/pyannote는 lazy import이므로 화자 구분 쓸 때 추가 설치 - main/utils/paths.ts: getSidecarCommand가 venv python 우선 사용 - existsSync(.venv/bin/python3) → 그걸로 spawn - 없으면 시스템 python3 폴백 (기존 동작) - Windows는 .venv/Scripts/python.exe 문제 2: HotkeyRecordModal 칩에 'WIN' 그대로 표기 - getKeyName()이 KEY_DISPLAY_MAP (Windows 전용 매핑) 사용 - 91/92 → 'Win' 하드코딩 - format-hotkey.ts의 keyCodeToName/getPlatform export - HotkeyRecordModal.getKeyName이 keyCodeToName(platform) 호출 → macOS는 ⌘/⇧/⌃/⌥ - 'Shift + Win + 1 — 저장을 눌러주세요' 안내 텍스트도 macOS는 구분자 없이 결합 --- apps/desktop/src/main/utils/paths.ts | 17 ++++++++++++++--- .../renderer/components/HotkeyRecordModal.tsx | 14 +++++++++++--- .../desktop/src/renderer/utils/format-hotkey.ts | 6 +++--- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/apps/desktop/src/main/utils/paths.ts b/apps/desktop/src/main/utils/paths.ts index 35e7b32..fb8e61b 100644 --- a/apps/desktop/src/main/utils/paths.ts +++ b/apps/desktop/src/main/utils/paths.ts @@ -54,7 +54,7 @@ export function getRecPath(): string { /** * STT sidecar 실행 경로. - * - dev: python/python3 + sidecar/main.py + * - dev: sidecar/.venv/bin/python (있으면) + sidecar/main.py, 없으면 시스템 python3 * - production: sidecar/sidecar(.exe) (PyInstaller 빌드) */ export function getSidecarCommand(): { command: string; args: string[] } { @@ -71,8 +71,19 @@ export function getSidecarCommand(): { command: string; args: string[] } { return { command: pythonCmd, args: [pyPath] } } - // dev: Python 직접 실행 - const sidecarPath = path.join(app.getAppPath(), 'sidecar', 'main.py') + // dev: venv 우선 → 없으면 시스템 python + const sidecarDir = path.join(app.getAppPath(), 'sidecar') + const sidecarPath = path.join(sidecarDir, 'main.py') + + const venvPython = + process.platform === 'win32' + ? path.join(sidecarDir, '.venv', 'Scripts', 'python.exe') + : path.join(sidecarDir, '.venv', 'bin', 'python3') + + if (existsSync(venvPython)) { + return { command: venvPython, args: [sidecarPath] } + } + const pythonCmd = process.platform === 'win32' ? 'python' : 'python3' return { command: pythonCmd, args: [sidecarPath] } } diff --git a/apps/desktop/src/renderer/components/HotkeyRecordModal.tsx b/apps/desktop/src/renderer/components/HotkeyRecordModal.tsx index 8a577a4..a939c5c 100644 --- a/apps/desktop/src/renderer/components/HotkeyRecordModal.tsx +++ b/apps/desktop/src/renderer/components/HotkeyRecordModal.tsx @@ -18,7 +18,7 @@ import { import { d3roPalette } from '@d3ro/ui/theme' import { useI18n } from '@d3ro/i18n' import type { HotkeyBinding } from '@d3ro/core/types' -import { formatHotkeyLabel } from '../utils/format-hotkey' +import { formatHotkeyLabel, getPlatform, keyCodeToName } from '../utils/format-hotkey' // ── 키 이름 매핑 (Windows) ────────────────────────────── const KEY_DISPLAY_MAP: Record = { @@ -55,7 +55,10 @@ const RESERVED_COMBOS = [ const MODIFIER_KEYCODES = new Set([16, 17, 18, 91, 92, 160, 161, 162, 163, 164, 165]) function getKeyName(keyCode: number, key: string): string { - if (KEY_DISPLAY_MAP[keyCode]) return KEY_DISPLAY_MAP[keyCode] + // 플랫폼별 라벨 (macOS는 ⌘/⇧/⌃/⌥). format-hotkey.ts의 단일 매핑을 사용. + const platform = getPlatform() + const mapped = keyCodeToName(keyCode, platform) + if (mapped && !mapped.startsWith('Key')) return mapped if (key.length === 1) return key.toUpperCase() return key } @@ -291,7 +294,12 @@ export function HotkeyRecordModal({ {/* 상태 표시 */} {isReady && !error && ( - {t('hotkey.ready', { keys: captured?.map(k => k.name).join(' + ') ?? '' })} + {t('hotkey.ready', { + keys: + captured + ?.map((k) => k.name) + .join(getPlatform() === 'darwin' ? '' : ' + ') ?? '' + })} )} diff --git a/apps/desktop/src/renderer/utils/format-hotkey.ts b/apps/desktop/src/renderer/utils/format-hotkey.ts index a59a853..0210ebc 100644 --- a/apps/desktop/src/renderer/utils/format-hotkey.ts +++ b/apps/desktop/src/renderer/utils/format-hotkey.ts @@ -7,9 +7,9 @@ import type { HotkeyBinding } from '@d3ro/core/types' -type Platform = 'darwin' | 'win32' | 'linux' +export type Platform = 'darwin' | 'win32' | 'linux' -function getPlatform(): Platform { +export function getPlatform(): Platform { const p = (window as { electronAPI?: { platform?: string } }).electronAPI?.platform if (p === 'darwin' || p === 'win32' || p === 'linux') return p // 폴백: SSR/테스트 환경에서는 navigator.platform로 추정. @@ -18,7 +18,7 @@ function getPlatform(): Platform { } // keyCode → 키명. Windows VK_* 기준 + 일부 macOS 분기. -function keyCodeToName(keyCode: number, platform: Platform): string { +export function keyCodeToName(keyCode: number, platform: Platform = getPlatform()): string { // Modifier 표기 — 플랫폼별 if (platform === 'darwin') { if (keyCode === 16 || keyCode === 160 || keyCode === 161) return '⇧'