diff --git a/resources/scripts/install-ovms.js b/resources/scripts/install-ovms.js index 57710e43f6..e4a5cf0444 100644 --- a/resources/scripts/install-ovms.js +++ b/resources/scripts/install-ovms.js @@ -5,105 +5,171 @@ const { execSync } = require('child_process') const { downloadWithPowerShell } = require('./download') // Base URL for downloading OVMS binaries -const OVMS_PKG_NAME = 'ovms250911.zip' -const OVMS_RELEASE_BASE_URL = [`https://gitcode.com/gcw_ggDjjkY3/kjfile/releases/download/download/${OVMS_PKG_NAME}`] +const OVMS_RELEASE_BASE_URL = + 'https://storage.openvinotoolkit.org/repositories/openvino_model_server/packages/2025.3.0/ovms_windows_python_on.zip' +const OVMS_EX_URL = 'https://gitcode.com/gcw_ggDjjkY3/kjfile/releases/download/download/ovms_25.3_ex.zip' /** - * Downloads and extracts the OVMS binary for the specified platform + * error code: + * 101: Unsupported CPU (not Intel Ultra) + * 102: Unsupported platform (not Windows) + * 103: Download failed + * 104: Installation failed + * 105: Failed to create ovdnd.exe + * 106: Failed to create run.bat + * 110: Cleanup of old installation failed */ -async function downloadOvmsBinary() { - // Create output directory structure - OVMS goes into its own subdirectory + +/** + * Clean old OVMS installation if it exists + */ +function cleanOldOvmsInstallation() { + console.log('Cleaning the existing OVMS installation...') const csDir = path.join(os.homedir(), '.cherrystudio') - - // Ensure directories exist - fs.mkdirSync(csDir, { recursive: true }) - const csOvmsDir = path.join(csDir, 'ovms') - // Delete existing OVMS directory if it exists if (fs.existsSync(csOvmsDir)) { - fs.rmSync(csOvmsDir, { recursive: true }) - } - - const tempdir = os.tmpdir() - const tempFilename = path.join(tempdir, 'ovms.zip') - - // Try each URL until one succeeds - let downloadSuccess = false - let lastError = null - - for (let i = 0; i < OVMS_RELEASE_BASE_URL.length; i++) { - const downloadUrl = OVMS_RELEASE_BASE_URL[i] - console.log(`Attempting download from URL ${i + 1}/${OVMS_RELEASE_BASE_URL.length}: ${downloadUrl}`) - try { - console.log(`Downloading OVMS from ${downloadUrl} to ${tempFilename}...`) - - // Try PowerShell download first, fallback to Node.js download if it fails - await downloadWithPowerShell(downloadUrl, tempFilename) - - // If we get here, download was successful - downloadSuccess = true - console.log(`Successfully downloaded from: ${downloadUrl}`) - break + fs.rmSync(csOvmsDir, { recursive: true }) } catch (error) { - console.warn(`Download failed from ${downloadUrl}: ${error.message}`) - lastError = error - - // Clean up failed download file if it exists - if (fs.existsSync(tempFilename)) { - try { - fs.unlinkSync(tempFilename) - } catch (cleanupError) { - console.warn(`Failed to clean up temporary file: ${cleanupError.message}`) - } - } - - // Continue to next URL if this one failed - if (i < OVMS_RELEASE_BASE_URL.length - 1) { - console.log(`Trying next URL...`) - } + console.warn(`Failed to clean up old OVMS installation: ${error.message}`) + return 110 } } - // Check if any download succeeded - if (!downloadSuccess) { - console.error(`All download URLs failed. Last error: ${lastError?.message || 'Unknown error'}`) + return 0 +} + +/** + * Install OVMS Base package + */ +async function installOvmsBase() { + // Download the base package + const tempdir = os.tmpdir() + const tempFilename = path.join(tempdir, 'ovms.zip') + + try { + console.log(`Downloading OVMS Base Package from ${OVMS_RELEASE_BASE_URL} to ${tempFilename}...`) + + // Try PowerShell download first, fallback to Node.js download if it fails + await downloadWithPowerShell(OVMS_RELEASE_BASE_URL, tempFilename) + console.log(`Successfully downloaded from: ${OVMS_RELEASE_BASE_URL}`) + } catch (error) { + console.error(`Download OVMS Base failed: ${error.message}`) + fs.unlinkSync(tempFilename) return 103 } - try { - console.log(`Extracting to ${csDir}...`) + // unzip the base package to the target directory + const csDir = path.join(os.homedir(), '.cherrystudio') + const csOvmsDir = path.join(csDir, 'ovms') + fs.mkdirSync(csOvmsDir, { recursive: true }) + try { // Use tar.exe to extract the ZIP file - console.log(`Extracting OVMS to ${csDir}...`) - execSync(`tar -xf ${tempFilename} -C ${csDir}`, { stdio: 'inherit' }) - console.log(`OVMS extracted to ${csDir}`) + console.log(`Extracting OVMS Base to ${csOvmsDir}...`) + execSync(`tar -xf ${tempFilename} -C ${csOvmsDir}`, { stdio: 'inherit' }) + console.log(`OVMS extracted to ${csOvmsDir}`) // Clean up temporary file fs.unlinkSync(tempFilename) console.log(`Installation directory: ${csDir}`) } catch (error) { console.error(`Error installing OVMS: ${error.message}`) - if (fs.existsSync(tempFilename)) { - fs.unlinkSync(tempFilename) - } - - // Check if ovmsDir is empty and remove it if so - try { - const ovmsDir = path.join(csDir, 'ovms') - const files = fs.readdirSync(ovmsDir) - if (files.length === 0) { - fs.rmSync(ovmsDir, { recursive: true }) - console.log(`Removed empty directory: ${ovmsDir}`) - } - } catch (cleanupError) { - console.warn(`Warning: Failed to clean up directory: ${cleanupError.message}`) - return 105 - } - + fs.unlinkSync(tempFilename) return 104 } + const csOvmsBinDir = path.join(csOvmsDir, 'ovms') + // copy ovms.exe to ovdnd.exe + try { + fs.copyFileSync(path.join(csOvmsBinDir, 'ovms.exe'), path.join(csOvmsBinDir, 'ovdnd.exe')) + console.log('Copied ovms.exe to ovdnd.exe') + } catch (error) { + console.error(`Error copying ovms.exe to ovdnd.exe: ${error.message}`) + return 105 + } + + // copy {csOvmsBinDir}/setupvars.bat to {csOvmsBinDir}/run.bat, and append the following lines to run.bat: + // del %USERPROFILE%\.cherrystudio\ovms_log.log + // ovms.exe --config_path models/config.json --rest_port 8000 --log_level DEBUG --log_path %USERPROFILE%\.cherrystudio\ovms_log.log + const runBatPath = path.join(csOvmsBinDir, 'run.bat') + try { + fs.copyFileSync(path.join(csOvmsBinDir, 'setupvars.bat'), runBatPath) + fs.appendFileSync(runBatPath, '\r\n') + fs.appendFileSync(runBatPath, 'del %USERPROFILE%\\.cherrystudio\\ovms_log.log\r\n') + fs.appendFileSync( + runBatPath, + 'ovms.exe --config_path models/config.json --rest_port 8000 --log_level DEBUG --log_path %USERPROFILE%\\.cherrystudio\\ovms_log.log\r\n' + ) + console.log(`Created run.bat at: ${runBatPath}`) + } catch (error) { + console.error(`Error creating run.bat: ${error.message}`) + return 106 + } + + // create {csOvmsBinDir}/models/config.json with content '{"model_config_list": []}' + const configJsonPath = path.join(csOvmsBinDir, 'models', 'config.json') + fs.mkdirSync(path.dirname(configJsonPath), { recursive: true }) + fs.writeFileSync(configJsonPath, '{"mediapipe_config_list":[],"model_config_list":[]}') + console.log(`Created config file: ${configJsonPath}`) + + return 0 +} + +/** + * Install OVMS Extra package + */ +async function installOvmsExtra() { + // Download the extra package + const tempdir = os.tmpdir() + const tempFilename = path.join(tempdir, 'ovms_ex.zip') + + try { + console.log(`Downloading OVMS Extra Package from ${OVMS_EX_URL} to ${tempFilename}...`) + + // Try PowerShell download first, fallback to Node.js download if it fails + await downloadWithPowerShell(OVMS_EX_URL, tempFilename) + console.log(`Successfully downloaded from: ${OVMS_EX_URL}`) + } catch (error) { + console.error(`Download OVMS Extra failed: ${error.message}`) + fs.unlinkSync(tempFilename) + return 103 + } + + // unzip the extra package to the target directory + const csDir = path.join(os.homedir(), '.cherrystudio') + const csOvmsDir = path.join(csDir, 'ovms') + + try { + // Use tar.exe to extract the ZIP file + console.log(`Extracting OVMS Extra to ${csOvmsDir}...`) + execSync(`tar -xf ${tempFilename} -C ${csOvmsDir}`, { stdio: 'inherit' }) + console.log(`OVMS extracted to ${csOvmsDir}`) + + // Clean up temporary file + fs.unlinkSync(tempFilename) + console.log(`Installation directory: ${csDir}`) + } catch (error) { + console.error(`Error installing OVMS Extra: ${error.message}`) + fs.unlinkSync(tempFilename) + return 104 + } + + // apply ovms patch, copy all files in {csOvmsDir}/patch/ovms to {csOvmsDir}/ovms with overwrite mode + const patchDir = path.join(csOvmsDir, 'patch', 'ovms') + const csOvmsBinDir = path.join(csOvmsDir, 'ovms') + try { + const files = fs.readdirSync(patchDir) + files.forEach((file) => { + const srcPath = path.join(patchDir, file) + const destPath = path.join(csOvmsBinDir, file) + fs.copyFileSync(srcPath, destPath) + console.log(`Applied patch file: ${file}`) + }) + } catch (error) { + console.error(`Error applying OVMS patch: ${error.message}`) + } + return 0 } @@ -158,7 +224,27 @@ async function installOvms() { return 102 } - return await downloadOvmsBinary() + // Clean old installation if it exists + const cleanupCode = cleanOldOvmsInstallation() + if (cleanupCode !== 0) { + console.error(`OVMS cleanup failed with code: ${cleanupCode}`) + return cleanupCode + } + + const installBaseCode = await installOvmsBase() + if (installBaseCode !== 0) { + console.error(`OVMS Base installation failed with code: ${installBaseCode}`) + cleanOldOvmsInstallation() + return installBaseCode + } + + const installExtraCode = await installOvmsExtra() + if (installExtraCode !== 0) { + console.error(`OVMS Extra installation failed with code: ${installExtraCode}`) + return installExtraCode + } + + return 0 } // Run the installation diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index 7d2f745333..56ec466988 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -1881,8 +1881,10 @@ "install_code_101": "Only supports Intel(R) Core(TM) Ultra CPU", "install_code_102": "Only supports Windows", "install_code_103": "Download OVMS runtime failed", - "install_code_104": "Uncompress OVMS runtime failed", - "install_code_105": "Clean OVMS runtime failed", + "install_code_104": "Failed to install OVMS runtime", + "install_code_105": "Failed to create ovdnd.exe", + "install_code_106": "Failed to create run.bat", + "install_code_110": "Failed to clean old OVMS runtime", "run": "Run OVMS failed:", "stop": "Stop OVMS failed:" }, diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index 1c1dde25f7..97df635d4a 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -1856,7 +1856,7 @@ "description": "

1. 下载 OV 模型.

2. 在 'Manager' 中添加模型.

仅支持 Windows!

OVMS 安装路径: '%USERPROFILE%\\.cherrystudio\\ovms' .

请参考 Intel OVMS 指南

", "download": { "button": "下载", - "error": "选择失败", + "error": "下载失败", "model_id": { "label": "模型 ID", "model_id_pattern": "模型 ID 必须以 OpenVINO/ 开头", @@ -1881,8 +1881,10 @@ "install_code_101": "仅支持 Intel(R) Core(TM) Ultra CPU", "install_code_102": "仅支持 Windows", "install_code_103": "下载 OVMS runtime 失败", - "install_code_104": "解压 OVMS runtime 失败", - "install_code_105": "清理 OVMS runtime 失败", + "install_code_104": "安装 OVMS runtime 失败", + "install_code_105": "创建 ovdnd.exe 失败", + "install_code_106": "创建 run.bat 失败", + "install_code_110": "清理旧 OVMS runtime 失败", "run": "运行 OVMS 失败:", "stop": "停止 OVMS 失败:" }, diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index eacb7a47a0..3f41863961 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -1856,7 +1856,7 @@ "description": "

1. 下載 OV 模型。

2. 在 'Manager' 中新增模型。

僅支援 Windows!

OVMS 安裝路徑: '%USERPROFILE%\\.cherrystudio\\ovms' 。

請參考 Intel OVMS 指南

", "download": { "button": "下載", - "error": "選擇失敗", + "error": "下載失敗", "model_id": { "label": "模型 ID", "model_id_pattern": "模型 ID 必須以 OpenVINO/ 開頭", @@ -1881,8 +1881,10 @@ "install_code_101": "僅支援 Intel(R) Core(TM) Ultra CPU", "install_code_102": "僅支援 Windows", "install_code_103": "下載 OVMS runtime 失敗", - "install_code_104": "解壓 OVMS runtime 失敗", - "install_code_105": "清理 OVMS runtime 失敗", + "install_code_104": "安裝 OVMS runtime 失敗", + "install_code_105": "創建 ovdnd.exe 失敗", + "install_code_106": "創建 run.bat 失敗", + "install_code_110": "清理舊 OVMS runtime 失敗", "run": "執行 OVMS 失敗:", "stop": "停止 OVMS 失敗:" }, diff --git a/src/renderer/src/pages/settings/ProviderSettings/OVMSSettings.tsx b/src/renderer/src/pages/settings/ProviderSettings/OVMSSettings.tsx index 827e4097e0..057408375e 100644 --- a/src/renderer/src/pages/settings/ProviderSettings/OVMSSettings.tsx +++ b/src/renderer/src/pages/settings/ProviderSettings/OVMSSettings.tsx @@ -36,7 +36,9 @@ const OVMSSettings: FC = () => { '102': t('ovms.failed.install_code_102'), '103': t('ovms.failed.install_code_103'), '104': t('ovms.failed.install_code_104'), - '105': t('ovms.failed.install_code_105') + '105': t('ovms.failed.install_code_105'), + '106': t('ovms.failed.install_code_106'), + '110': t('ovms.failed.install_code_110') } const match = error.message.match(/code (\d+)/) const code = match ? match[1] : 'unknown' @@ -135,7 +137,7 @@ const OVMSSettings: FC = () => { type="primary" onClick={runOvms} loading={isRunningOvms} - disabled={isRunningOvms} + disabled={isRunningOvms || isInstallingOvms} size="small"> {isRunningOvms ? t('ovms.action.starting') : t('ovms.action.run')}