UNPKG

electron-ollama

Version:

Bundle Ollama with your Electron.js app for seamless user experience

240 lines 9.52 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.ElectronOllama = exports.ElectronOllamaServer = void 0; const path = __importStar(require("path")); const fs = __importStar(require("fs/promises")); const os = __importStar(require("os")); const github_fetch_1 = require("./github-fetch"); const unzip_1 = require("./unzip"); const untgz_1 = require("./untgz"); const server_1 = require("./server"); Object.defineProperty(exports, "ElectronOllamaServer", { enumerable: true, get: function () { return server_1.ElectronOllamaServer; } }); const stream_1 = require("stream"); class ElectronOllama { constructor(config) { this.config = { directory: 'electron-ollama', ...config, }; } /** * Get the current platform configuration */ currentPlatformConfig() { const platform = os.platform(); const arch = os.arch(); let osType; let architecture; // Map platform switch (platform) { case 'win32': osType = 'windows'; break; case 'darwin': osType = 'darwin'; break; case 'linux': osType = 'linux'; break; default: throw new Error(`Unsupported platform: ${platform}`); } // Map architecture switch (arch) { case 'arm64': architecture = 'arm64'; break; case 'x64': architecture = 'amd64'; break; default: throw new Error(`Unsupported architecture: ${arch}`); } return { os: osType, arch: architecture, }; } /** * Get the name of the asset for the given platform configuration (e.g. "ollama-windows-amd64.zip" or "ollama-darwin.tgz") */ getAssetName(platformConfig) { const { os, arch: architecture } = platformConfig; switch (os) { case 'windows': return `ollama-windows-${architecture}.zip`; case 'darwin': return 'ollama-darwin.tgz'; case 'linux': return `ollama-linux-${architecture}.tgz`; } } /** * Get metadata for a specific version ('latest' by default) and platform */ async getMetadata(version = 'latest', platformConfig = this.currentPlatformConfig()) { const { os, arch: architecture } = platformConfig; const releaseUrlPath = version === 'latest' ? `latest` : `tags/${version}`; const gitHubResponse = await (0, github_fetch_1.githubFetch)(`https://api.github.com/repos/ollama/ollama/releases/${releaseUrlPath}`); const releaseData = await gitHubResponse.json(); const assetName = this.getAssetName(platformConfig); const asset = releaseData.assets.find((asset) => asset.name === assetName); if (!asset) { throw new Error(`${os}-${architecture} is not supported by Ollama ${releaseData.tag_name}`); } return { digest: asset.digest, size: asset.size, fileName: asset.name, contentType: asset.content_type, version: releaseData.tag_name, downloads: asset.download_count, downloadUrl: asset.browser_download_url, releaseUrl: releaseData.html_url, body: releaseData.body, }; } /** * Download Ollama for the specified version ('latest' by default) and platform */ async download(version = 'latest', platformConfig = this.currentPlatformConfig()) { const metadata = await this.getMetadata(version, platformConfig); const versionDir = this.getBinPath(metadata.version, platformConfig); // 1. Create directory if it doesn't exist console.log('Creating directory if it doesn\'t exist'); await fs.mkdir(versionDir, { recursive: true }); // 2. Download the file console.log(`Downloading file to ${versionDir}`); const response = await fetch(metadata.downloadUrl); // 3. Extract the archive console.log(`Extracting archive ${metadata.fileName} in ${versionDir}`); if (metadata.contentType === 'application/zip') { const buffer = await response.arrayBuffer(); await fs.writeFile(path.join(versionDir, metadata.fileName), Buffer.from(buffer)); await (0, unzip_1.unzipFile)(path.join(versionDir, metadata.fileName), versionDir, true); } else if (['application/x-gtar', 'application/x-tar', 'application/x-gzip', 'application/tar', 'application/gzip', 'application/x-tgz'].includes(metadata.contentType)) { const stream = stream_1.Readable.from(response.body); await (0, untgz_1.untgzStream)(stream, versionDir); } else { throw new Error(`The Ollama asset type ${metadata.contentType} is not supported`); } console.log(`Extracted archive ${metadata.fileName} to ${versionDir}`); // 4. Verify checksum } /** * Check if a version is downloaded for the given platform configuration */ async isDownloaded(version, platformConfig = this.currentPlatformConfig()) { const binPath = this.getBinPath(version, platformConfig); return fs.access(binPath).then(() => true).catch(() => false); } /** * List all downloaded versions for the given platform configuration */ async downloadedVersions(platformConfig = this.currentPlatformConfig()) { let versions = []; try { versions = await fs.readdir(path.join(this.config.basePath, this.config.directory)); } catch { return []; // directory does not exist - nothing to list } const downloaded = await Promise.all(versions.map((version) => this.isDownloaded(version, platformConfig))); return versions.filter((_version, index) => downloaded[index]); } /** * Get the path to the directory for the given version and platform configuration */ getBinPath(version, platformConfig = this.currentPlatformConfig()) { return path.join(this.config.basePath, this.config.directory, version, platformConfig.os, platformConfig.arch); } /** * Get the name of the executable for the given platform configuration */ getExecutableName(platformConfig) { switch (platformConfig.os) { case 'windows': return 'ollama.exe'; case 'darwin': return 'ollama'; case 'linux': return 'bin/ollama'; } } /** * Start serving Ollama with the specified version */ async serve(version) { const platformConfig = this.currentPlatformConfig(); const binPath = this.getBinPath(version, platformConfig); // Ensure the binary exists if (!await this.isDownloaded(version, platformConfig)) { await this.download(version, platformConfig); } const server = new server_1.ElectronOllamaServer({ binPath, log: this.config.serveLog || (() => { }), }); server.start(this.getExecutableName(platformConfig)); // Wait for the server to start for (let i = 0; i < 50; i++) { await new Promise(resolve => setTimeout(resolve, 100)); if (await this.isRunning()) { return server; } } throw new Error('Ollama server failed to start in 5 seconds'); } /** * Check if Ollama is running */ async isRunning() { try { const response = await fetch('http://localhost:11434'); const text = await response.text(); return text.includes('Ollama is running'); } catch { return false; } } } exports.ElectronOllama = ElectronOllama; // Export default instance exports.default = ElectronOllama; //# sourceMappingURL=index.js.map