mirror of
https://github.com/hanzoai/desktop.git
synced 2026-10-30 14:58:42 +00:00
* feat: bump ollama version to 0.14.3 + misc fixes (#1148) * bump node version * bump node version * fixes * improve wording when removing inbox * bump app version * update linux ollama * fix: streamdown plugins, mermaid, update ollama models (#1149) * fix: streamdown plugins * fix mermaid syntax * fix streamdown plugins * update ollama models * chore: remove unused packages, metadata editor fixes (#1150) * chore: remove unused packages * fix npm audit * fix: regenerate metadata editor * feat: delete multiple chats (#1151) * feat: delete multiple chats * improvements * misc improvements * fix * chore: update ollama to 0.12.3 (#1152) * chore: update OLLAMA_VERSION to 0.12.3 * chore: update packages * chore: bump node version and npm audit fixes (#1153) * bump node * chore: update tar and lodash-es versions * fix: minor UI (#1154) * ui fixes * fixes * Merge upstream dcSpark/shinkai-local-ai-agents latest Merges 7 upstream commits: - feat: delete multiple chats (useRemoveJobs, manage-chats-dialog) - feat: bump ollama version to 0.14.3 + misc fixes - fix: streamdown plugins, mermaid, update ollama models - chore: remove unused packages, metadata editor fixes - chore: update ollama to 0.12.3 - chore: bump node version and npm audit fixes - fix: minor UI improvements All new upstream code rebranded to Hanzo naming: - @shinkai_network → @hanzo_network in new components - New removeMultipleJobs mutation created in hanzo-node-state - Removed stale libs/shinkai-node-state directory - READMEs use HANZO_NODE_VERSION with bumped version --------- Co-authored-by: Paul Ccari <[email protected]>
269 lines
8.4 KiB
TypeScript
Executable File
269 lines
8.4 KiB
TypeScript
Executable File
import { exec } from 'child_process';
|
|
import { createWriteStream } from 'fs';
|
|
import { copyFile, cp, mkdir, readdir, rename } from 'fs/promises';
|
|
import path from 'path';
|
|
import axios from 'axios';
|
|
import { ensureFile } from 'fs-extra';
|
|
import { extract } from 'tar';
|
|
import * as zl from 'zip-lib';
|
|
import { z } from 'zod';
|
|
|
|
enum Arch {
|
|
x86_64_unknown_linux_gnu = 'x86_64-unknown-linux-gnu',
|
|
aarch64_apple_darwin = 'aarch64-apple-darwin',
|
|
x86_64_pc_windows_msvc = 'x86_64-pc-windows-msvc',
|
|
}
|
|
const envSchema = z.object({
|
|
ARCH: z.nativeEnum(Arch),
|
|
OLLAMA_VERSION: z.string().min(6),
|
|
HANZO_NODE_VERSION: z.string().min(6),
|
|
});
|
|
|
|
type Env = z.infer<typeof envSchema>;
|
|
|
|
const env: Env = envSchema.parse(process.env);
|
|
|
|
const TEMP_PATH = './temp';
|
|
const OLLAMA_RESOURCES_PATH =
|
|
'./apps/hanzo-desktop/src-tauri/external-binaries/ollama/';
|
|
const HANZO_NODE_RESOURCES_PATH =
|
|
'./apps/hanzo-desktop/src-tauri/external-binaries/hanzo-node/';
|
|
const LLM_MODELS_PATH = './apps/hanzo-desktop/src-tauri/llm-models/';
|
|
|
|
const asBinaryName = (arch: Arch, path: string) => {
|
|
return `${path}${arch === Arch.x86_64_pc_windows_msvc ? '.exe' : ''}`;
|
|
};
|
|
|
|
const asSidecarName = (arch: Arch, path: string) => {
|
|
return path.replace(
|
|
/(.exe){0,1}$/,
|
|
`-${arch}${arch === Arch.x86_64_pc_windows_msvc ? '.exe' : ''}`,
|
|
);
|
|
};
|
|
|
|
const addExecPermissions = (path: string) => {
|
|
console.log(`Adding exec permissions (+x) to ${path}`);
|
|
return exec(`chmod +x ${path}`);
|
|
};
|
|
|
|
const downloadFile = async (url: string, path: string): Promise<void> => {
|
|
console.log(`Downloading ${url}`);
|
|
const response = await axios({
|
|
method: 'GET',
|
|
url: url,
|
|
responseType: 'stream',
|
|
onDownloadProgress: function (progressEvent) {
|
|
if (progressEvent.progress) {
|
|
console.log(`${url} progress: ${progressEvent.progress * 100}%`);
|
|
}
|
|
},
|
|
});
|
|
console.log(`ensuring file ${path}`);
|
|
await ensureFile(path);
|
|
console.log(`creating write stream ${path}`);
|
|
response.data.pipe(
|
|
createWriteStream(path, { encoding: 'binary', flags: 'w' }),
|
|
);
|
|
await new Promise<void>((resolve, reject) => {
|
|
response.data.on('end', () => {
|
|
resolve();
|
|
});
|
|
response.data.on('error', (err: any) => {
|
|
console.error(`Error downloading file: ${url}`, err);
|
|
reject(err);
|
|
});
|
|
});
|
|
console.log(`Download complete: ${url}`);
|
|
};
|
|
|
|
const downloadHanzoNodeBinary = async (arch: Arch, version: string) => {
|
|
console.log(`Downloading hanzo-node arch:${arch} version:${version}`);
|
|
const downloadUrl = `https://download.hanzo.ai/hanzo-node/binaries/production/${arch}/${version}.zip`;
|
|
const zippedPath = path.join(TEMP_PATH, `hanzo-node-${version}.zip`);
|
|
await downloadFile(downloadUrl, zippedPath);
|
|
let unzippedPath = path.join(TEMP_PATH, `hanzo-node-${version}`);
|
|
await zl.extract(zippedPath, unzippedPath, {
|
|
overwrite: true,
|
|
});
|
|
|
|
const files = await readdir(unzippedPath);
|
|
for (const file of files) {
|
|
await cp(
|
|
path.join(unzippedPath, file),
|
|
path.join(HANZO_NODE_RESOURCES_PATH, file),
|
|
{
|
|
recursive: true,
|
|
},
|
|
);
|
|
}
|
|
|
|
// They are used as sidecars in Tauri
|
|
const hanzoNodeBinaryPath = asBinaryName(
|
|
arch,
|
|
`./apps/hanzo-desktop/src-tauri/external-binaries/hanzo-node/hanzo-node`,
|
|
);
|
|
const hanzoToolsRunnerDenoBinaryPath = asBinaryName(
|
|
arch,
|
|
`./apps/hanzo-desktop/src-tauri/external-binaries/hanzo-node/hanzo-tools-runner-resources/deno`,
|
|
);
|
|
const hanzoToolsRunnerUvBinaryPath = asBinaryName(
|
|
arch,
|
|
`./apps/hanzo-desktop/src-tauri/external-binaries/hanzo-node/hanzo-tools-runner-resources/uv`,
|
|
);
|
|
await rename(
|
|
hanzoNodeBinaryPath,
|
|
asSidecarName(arch, hanzoNodeBinaryPath),
|
|
);
|
|
await rename(
|
|
hanzoToolsRunnerDenoBinaryPath,
|
|
asSidecarName(arch, hanzoToolsRunnerDenoBinaryPath),
|
|
);
|
|
await rename(
|
|
hanzoToolsRunnerUvBinaryPath,
|
|
asSidecarName(arch, hanzoToolsRunnerUvBinaryPath),
|
|
);
|
|
|
|
await addExecPermissions(asSidecarName(arch, hanzoNodeBinaryPath));
|
|
await addExecPermissions(
|
|
asSidecarName(arch, hanzoToolsRunnerDenoBinaryPath),
|
|
);
|
|
await addExecPermissions(asSidecarName(arch, hanzoToolsRunnerUvBinaryPath));
|
|
};
|
|
|
|
const downloadOllamaAarch64AppleDarwin = async (version: string) => {
|
|
const downloadUrl = `https://github.com/ollama/ollama/releases/download/${version}/Ollama-darwin.zip`;
|
|
const zippedPath = path.join(
|
|
TEMP_PATH,
|
|
`ollama-${Arch.aarch64_apple_darwin}.zip`,
|
|
);
|
|
await downloadFile(downloadUrl, zippedPath);
|
|
const unzippedPath = path.join(
|
|
TEMP_PATH,
|
|
`ollama-${Arch.aarch64_apple_darwin}-${version}`,
|
|
);
|
|
await zl.extract(zippedPath, unzippedPath, {
|
|
overwrite: true,
|
|
});
|
|
const ollamaBinaryPath = asSidecarName(
|
|
Arch.aarch64_apple_darwin,
|
|
`./apps/hanzo-desktop/src-tauri/external-binaries/ollama/ollama`,
|
|
);
|
|
await ensureFile(ollamaBinaryPath);
|
|
await copyFile(
|
|
path.join(unzippedPath, 'Ollama.app/Contents/Resources/ollama'),
|
|
ollamaBinaryPath,
|
|
);
|
|
await addExecPermissions(ollamaBinaryPath);
|
|
};
|
|
|
|
const downloadOllamax8664UnknownLinuxGnu = async (version: string) => {
|
|
const downloadUrl = `https://github.com/ollama/ollama/releases/download/${version}/ollama-linux-amd64.tgz`;
|
|
const zippedPath = path.join(TEMP_PATH, `ollama-linux-amd64-${version}.tgz`);
|
|
|
|
await downloadFile(downloadUrl, zippedPath);
|
|
|
|
const unzippedPath = path.join(TEMP_PATH, `ollama-linux-amd64-${version}`);
|
|
|
|
await mkdir(unzippedPath, { recursive: true });
|
|
await extract({
|
|
f: zippedPath,
|
|
C: unzippedPath,
|
|
strip: 0,
|
|
});
|
|
const ollamaBinaryPath = asSidecarName(
|
|
Arch.x86_64_unknown_linux_gnu,
|
|
`./apps/hanzo-desktop/src-tauri/external-binaries/ollama/ollama`,
|
|
);
|
|
await ensureFile(ollamaBinaryPath);
|
|
await copyFile(path.join(unzippedPath, 'bin/ollama'), ollamaBinaryPath);
|
|
await addExecPermissions(ollamaBinaryPath);
|
|
};
|
|
|
|
const downloadOllamax8664PcWindowsMsvc = async (version: string) => {
|
|
await downloadOllamax8664PcWindowsMsvcNvidia(version);
|
|
await downloadOllamax8664PcWindowsMsvcRocm(version);
|
|
};
|
|
const downloadOllamax8664PcWindowsMsvcRocm = async (version: string) => {
|
|
const downloadUrl = `https://github.com/ollama/ollama/releases/download/${version}/ollama-windows-amd64-rocm.zip`;
|
|
const zippedPath = path.join(
|
|
TEMP_PATH,
|
|
`ollama-windows-amd64-rocm-${version}.zip`,
|
|
);
|
|
await downloadFile(downloadUrl, zippedPath);
|
|
const unzippedPath = path.join(
|
|
TEMP_PATH,
|
|
`ollama-windows-amd64-rocm-${version}`,
|
|
);
|
|
await zl.extract(zippedPath, unzippedPath, {
|
|
overwrite: true,
|
|
});
|
|
const files = await readdir(unzippedPath);
|
|
await cp(
|
|
path.join(unzippedPath, 'lib', 'ollama', 'rocm'),
|
|
path.join(OLLAMA_RESOURCES_PATH, 'lib', 'rocm'),
|
|
{
|
|
recursive: true,
|
|
},
|
|
);
|
|
};
|
|
const downloadOllamax8664PcWindowsMsvcNvidia = async (version: string) => {
|
|
const downloadUrl = `https://github.com/ollama/ollama/releases/download/${version}/ollama-windows-amd64.zip`;
|
|
const zippedPath = path.join(
|
|
TEMP_PATH,
|
|
`ollama-windows-amd64-${version}.zip`,
|
|
);
|
|
|
|
await downloadFile(downloadUrl, zippedPath);
|
|
|
|
const unzippedPath = path.join(TEMP_PATH, `ollama-windows-amd64-${version}`);
|
|
await zl.extract(zippedPath, unzippedPath, {
|
|
overwrite: true,
|
|
});
|
|
|
|
const files = await readdir(unzippedPath);
|
|
for (const file of files) {
|
|
await cp(
|
|
path.join(unzippedPath, file),
|
|
path.join(OLLAMA_RESOURCES_PATH, file),
|
|
{
|
|
recursive: true,
|
|
},
|
|
);
|
|
}
|
|
|
|
const ollamaBinaryPath = asBinaryName(
|
|
Arch.x86_64_pc_windows_msvc,
|
|
`./apps/hanzo-desktop/src-tauri/external-binaries/ollama/ollama`,
|
|
);
|
|
await rename(
|
|
ollamaBinaryPath,
|
|
asSidecarName(Arch.x86_64_pc_windows_msvc, ollamaBinaryPath),
|
|
);
|
|
await addExecPermissions(
|
|
asSidecarName(Arch.x86_64_pc_windows_msvc, ollamaBinaryPath),
|
|
);
|
|
};
|
|
|
|
const downloadOllama = {
|
|
[Arch.aarch64_apple_darwin]: downloadOllamaAarch64AppleDarwin,
|
|
[Arch.x86_64_unknown_linux_gnu]: downloadOllamax8664UnknownLinuxGnu,
|
|
[Arch.x86_64_pc_windows_msvc]: downloadOllamax8664PcWindowsMsvc,
|
|
};
|
|
|
|
const downloadEmbeddingModel = async () => {
|
|
console.log(`Downloading embedding model`);
|
|
const downloadUrl = `https://download.hanzo.ai/llm-models/embeddinggemma-300M-BF16.gguf`;
|
|
await downloadFile(
|
|
downloadUrl,
|
|
path.join(LLM_MODELS_PATH, 'embeddinggemma-300M-BF16.gguf'),
|
|
);
|
|
};
|
|
|
|
export const main = async () => {
|
|
await downloadHanzoNodeBinary(env.ARCH, env.HANZO_NODE_VERSION);
|
|
await downloadOllama[env.ARCH](env.OLLAMA_VERSION);
|
|
await downloadEmbeddingModel();
|
|
};
|
|
|
|
main().catch(console.error);
|