From 4419c5094263308b73759743151352bc3e253c7c Mon Sep 17 00:00:00 2001 From: catlog22 Date: Sun, 28 Dec 2025 17:49:40 +0800 Subject: [PATCH] feat: enhance internationalization support and improve GPU mode selector with Python environment checks --- ccw/src/templates/dashboard-js/i18n.js | 24 +++++- .../dashboard-js/views/codexlens-manager.js | 16 +++- ccw/src/tools/codex-lens.ts | 84 +++++++++++++++++-- 3 files changed, 110 insertions(+), 14 deletions(-) diff --git a/ccw/src/templates/dashboard-js/i18n.js b/ccw/src/templates/dashboard-js/i18n.js index 517532b4..e77ae22c 100644 --- a/ccw/src/templates/dashboard-js/i18n.js +++ b/ccw/src/templates/dashboard-js/i18n.js @@ -1734,7 +1734,9 @@ const i18n = { 'discovery.title': 'Issue Discovery', 'discovery.description': 'Discover potential issues from multiple perspectives', 'discovery.noSessions': 'No discovery sessions', + 'discovery.noDiscoveries': 'No discoveries yet', 'discovery.runHint': 'Run /issue:discover to start discovering issues', + 'discovery.runCommand': 'Run /issue:discover to start discovering issues', 'discovery.sessions': 'Sessions', 'discovery.findings': 'Findings', 'discovery.phase': 'Phase', @@ -1769,10 +1771,18 @@ const i18n = { 'discovery.confidence': 'Confidence', 'discovery.suggestedIssue': 'Suggested Issue', 'discovery.externalRef': 'External Reference', - 'discovery.noFindings': 'No findings in this session', + 'discovery.noFindings': 'No findings match your filters', 'discovery.filterPerspective': 'Filter by Perspective', 'discovery.filterPriority': 'Filter by Priority', 'discovery.filterAll': 'All', + 'discovery.allPerspectives': 'All Perspectives', + 'discovery.allPriorities': 'All Priorities', + 'discovery.selectFinding': 'Select a finding to preview', + 'discovery.location': 'Location', + 'discovery.code': 'Code', + 'discovery.impact': 'Impact', + 'discovery.recommendation': 'Recommendation', + 'discovery.exportAsIssues': 'Export as Issues', 'discovery.deleteSession': 'Delete Session', 'discovery.confirmDelete': 'Are you sure you want to delete this discovery session?', 'discovery.deleted': 'Discovery session deleted', @@ -3649,7 +3659,9 @@ const i18n = { 'discovery.title': '议题发现', 'discovery.description': '从多个视角发现潜在问题', 'discovery.noSessions': '暂无发现会话', + 'discovery.noDiscoveries': '暂无发现', 'discovery.runHint': '运行 /issue:discover 开始发现问题', + 'discovery.runCommand': '运行 /issue:discover 开始发现问题', 'discovery.sessions': '会话', 'discovery.findings': '发现', 'discovery.phase': '阶段', @@ -3684,10 +3696,18 @@ const i18n = { 'discovery.confidence': '置信度', 'discovery.suggestedIssue': '建议议题', 'discovery.externalRef': '外部参考', - 'discovery.noFindings': '此会话暂无发现', + 'discovery.noFindings': '没有匹配的发现', 'discovery.filterPerspective': '按视角筛选', 'discovery.filterPriority': '按优先级筛选', 'discovery.filterAll': '全部', + 'discovery.allPerspectives': '所有视角', + 'discovery.allPriorities': '所有优先级', + 'discovery.selectFinding': '选择一个发现以预览', + 'discovery.location': '位置', + 'discovery.code': '代码', + 'discovery.impact': '影响', + 'discovery.recommendation': '建议', + 'discovery.exportAsIssues': '导出为议题', 'discovery.deleteSession': '删除会话', 'discovery.confirmDelete': '确定要删除此发现会话吗?', 'discovery.deleted': '发现会话已删除', diff --git a/ccw/src/templates/dashboard-js/views/codexlens-manager.js b/ccw/src/templates/dashboard-js/views/codexlens-manager.js index c63c70f1..c62f0198 100644 --- a/ccw/src/templates/dashboard-js/views/codexlens-manager.js +++ b/ccw/src/templates/dashboard-js/views/codexlens-manager.js @@ -446,6 +446,12 @@ async function loadSemanticDepsStatus() { * Build GPU mode selector HTML */ function buildGpuModeSelector(gpuInfo) { + // Check if DirectML is unavailable due to Python environment + var directmlUnavailableReason = null; + if (!gpuInfo.available.includes('directml') && gpuInfo.pythonEnv && gpuInfo.pythonEnv.error) { + directmlUnavailableReason = gpuInfo.pythonEnv.error; + } + var modes = [ { id: 'cpu', @@ -457,10 +463,13 @@ function buildGpuModeSelector(gpuInfo) { { id: 'directml', label: 'DirectML', - desc: t('codexlens.directmlModeDesc') || 'Windows GPU (NVIDIA/AMD/Intel)', + desc: directmlUnavailableReason + ? directmlUnavailableReason + : (t('codexlens.directmlModeDesc') || 'Windows GPU (NVIDIA/AMD/Intel)'), icon: 'cpu', available: gpuInfo.available.includes('directml'), - recommended: gpuInfo.mode === 'directml' + recommended: gpuInfo.mode === 'directml', + warning: directmlUnavailableReason }, { id: 'cuda', @@ -487,6 +496,7 @@ function buildGpuModeSelector(gpuInfo) { var isDisabled = !mode.available; var isRecommended = mode.recommended; var isDefault = mode.id === gpuInfo.mode; + var hasWarning = mode.warning; html += ''; }); diff --git a/ccw/src/tools/codex-lens.ts b/ccw/src/tools/codex-lens.ts index 50ee6f68..19302542 100644 --- a/ccw/src/tools/codex-lens.ts +++ b/ccw/src/tools/codex-lens.ts @@ -379,11 +379,63 @@ async function ensureLiteLLMEmbedderReady(): Promise { */ type GpuMode = 'cpu' | 'cuda' | 'directml'; +/** + * Python environment info for compatibility checks + */ +interface PythonEnvInfo { + version: string; // e.g., "3.11.5" + majorMinor: string; // e.g., "3.11" + architecture: number; // 32 or 64 + compatible: boolean; // true if 64-bit and Python 3.8-3.12 + error?: string; +} + +/** + * Check Python environment in venv for DirectML compatibility + * DirectML requires: 64-bit Python, version 3.8-3.12 + */ +async function checkPythonEnvForDirectML(): Promise { + const pythonPath = + process.platform === 'win32' + ? join(CODEXLENS_VENV, 'Scripts', 'python.exe') + : join(CODEXLENS_VENV, 'bin', 'python'); + + if (!existsSync(pythonPath)) { + return { version: '', majorMinor: '', architecture: 0, compatible: false, error: 'Python not found in venv' }; + } + + try { + // Get Python version and architecture in one call + const checkScript = `import sys, struct; print(f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}|{struct.calcsize('P') * 8}")`; + const result = execSync(`"${pythonPath}" -c "${checkScript}"`, { encoding: 'utf-8', timeout: 10000 }).trim(); + const [version, archStr] = result.split('|'); + const architecture = parseInt(archStr, 10); + const [major, minor] = version.split('.').map(Number); + const majorMinor = `${major}.${minor}`; + + // DirectML wheels available for Python 3.8-3.12, 64-bit only + const versionCompatible = major === 3 && minor >= 8 && minor <= 12; + const archCompatible = architecture === 64; + const compatible = versionCompatible && archCompatible; + + let error: string | undefined; + if (!archCompatible) { + error = `Python is ${architecture}-bit. onnxruntime-directml requires 64-bit Python. Please reinstall Python as 64-bit.`; + } else if (!versionCompatible) { + error = `Python ${majorMinor} is not supported. onnxruntime-directml requires Python 3.8-3.12.`; + } + + return { version, majorMinor, architecture, compatible, error }; + } catch (e) { + return { version: '', majorMinor: '', architecture: 0, compatible: false, error: `Failed to check Python: ${(e as Error).message}` }; + } +} + /** * Detect available GPU acceleration * @returns Detected GPU mode and info */ -async function detectGpuSupport(): Promise<{ mode: GpuMode; available: GpuMode[]; info: string }> { +async function detectGpuSupport(): Promise<{ mode: GpuMode; available: GpuMode[]; info: string; pythonEnv?: PythonEnvInfo }> { const available: GpuMode[] = ['cpu']; let detectedInfo = 'CPU only'; @@ -402,19 +454,20 @@ async function detectGpuSupport(): Promise<{ mode: GpuMode; available: GpuMode[] // NVIDIA not available } - // On Windows, DirectML is always available if DirectX 12 is supported + // On Windows, DirectML requires 64-bit Python 3.8-3.12 + let pythonEnv: PythonEnvInfo | undefined; if (process.platform === 'win32') { - try { - // Check for DirectX 12 support via dxdiag or registry - // DirectML works on most modern Windows 10/11 systems + pythonEnv = await checkPythonEnvForDirectML(); + if (pythonEnv.compatible) { available.push('directml'); if (available.includes('cuda')) { detectedInfo = 'NVIDIA GPU detected (CUDA & DirectML available)'; } else { detectedInfo = 'DirectML available (Windows GPU acceleration)'; } - } catch { - // DirectML check failed + } else if (pythonEnv.error) { + // DirectML not available due to Python environment + console.log(`[CodexLens] DirectML unavailable: ${pythonEnv.error}`); } } @@ -426,7 +479,7 @@ async function detectGpuSupport(): Promise<{ mode: GpuMode; available: GpuMode[] recommendedMode = 'cuda'; } - return { mode: recommendedMode, available, info: detectedInfo }; + return { mode: recommendedMode, available, info: detectedInfo, pythonEnv }; } /** @@ -441,6 +494,19 @@ async function installSemantic(gpuMode: GpuMode = 'cpu'): Promise