Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ jobs:
- name: Generate docs
run: npm run generate-docs
- name: Download latest llama.cpp release
run: node ./dist/cli/cli.js download --release latest --skipBuild --updateBinariesReleaseMetadata
env:
CI: true
run: node ./dist/cli/cli.js download --release latest --skipBuild --updateBinariesReleaseMetadataAndSaveGitBundle
- name: Upload build artifact
uses: actions/upload-artifact@v3
with:
Expand All @@ -41,6 +43,11 @@ jobs:
with:
name: "llama.cpp"
path: "llama/llama.cpp"
- name: Upload gitRelease.bundle artifact
uses: actions/upload-artifact@v3
with:
name: "gitReleaseBundle"
path: "llama/gitRelease.bundle"

build-binaries:
name: Build binaries - ${{ matrix.config.name }}
Expand Down Expand Up @@ -243,6 +250,9 @@ jobs:
rm -f ./llama/binariesGithubRelease.json
mv artifacts/binariesGithubRelease/binariesGithubRelease.json ./llama/binariesGithubRelease.json

rm -f ./llama/gitRelease.bundle
mv artifacts/gitReleaseBundle/gitRelease.bundle ./llama/gitRelease.bundle

echo "Built binaries:"
ls llamaBins
- name: Add "postinstall" script to package.json
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ node_modules

/llama/compile_commands.json
/llama/llama.cpp
/llama/gitRelease.bundle
/llama/.temp
/llama/build
/llama/Release
Expand Down
49 changes: 9 additions & 40 deletions src/cli/commands/DownloadCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ import {CommandModule} from "yargs";
import {Octokit} from "octokit";
import fs from "fs-extra";
import chalk from "chalk";
import cliProgress from "cli-progress";
import simpleGit from "simple-git";
import {
defaultLlamaCppCudaSupport, defaultLlamaCppGitHubRepo, defaultLlamaCppMetalSupport, defaultLlamaCppRelease, llamaCppDirectory
defaultLlamaCppCudaSupport, defaultLlamaCppGitHubRepo, defaultLlamaCppMetalSupport, defaultLlamaCppRelease, isCI, llamaCppDirectory
} from "../../config.js";
import {compileLlamaCpp} from "../../utils/compileLLamaCpp.js";
import withOra from "../../utils/withOra.js";
import {clearTempFolder} from "../../utils/clearTempFolder.js";
import {setBinariesGithubRelease} from "../../utils/binariesGithubRelease.js";
import {downloadCmakeIfNeeded} from "../../utils/cmake.js";
import withStatusLogs from "../../utils/withStatusLogs.js";
import {saveCurrentRepoAsReleaseBundle} from "../../utils/gitReleaseBundles.js";
import {cloneLlamaCppRepo} from "../../utils/cloneLlamaCppRepo.js";

type DownloadCommandArgs = {
repo: string,
Expand All @@ -23,7 +23,7 @@ type DownloadCommandArgs = {
metal: boolean,
cuda: boolean,
skipBuild?: boolean,
updateBinariesReleaseMetadata?: boolean
updateBinariesReleaseMetadataAndSaveGitBundle?: boolean
};

export const DownloadCommand: CommandModule<object, DownloadCommandArgs> = {
Expand Down Expand Up @@ -68,7 +68,7 @@ export const DownloadCommand: CommandModule<object, DownloadCommandArgs> = {
default: false,
description: "Skip building llama.cpp after downloading it"
})
.option("updateBinariesReleaseMetadata", {
.option("updateBinariesReleaseMetadataAndSaveGitBundle", {
type: "boolean",
hidden: true, // this for the CI to use
default: false,
Expand All @@ -79,7 +79,7 @@ export const DownloadCommand: CommandModule<object, DownloadCommandArgs> = {
};

export async function DownloadLlamaCppCommand({
repo, release, arch, nodeTarget, metal, cuda, skipBuild, updateBinariesReleaseMetadata
repo, release, arch, nodeTarget, metal, cuda, skipBuild, updateBinariesReleaseMetadataAndSaveGitBundle
}: DownloadCommandArgs) {
const octokit = new Octokit();
const [githubOwner, githubRepo] = repo.split("/");
Expand Down Expand Up @@ -143,7 +143,7 @@ export async function DownloadLlamaCppCommand({
});

console.log(chalk.blue("Cloning llama.cpp"));
await cloneTag(githubOwner, githubRepo, githubRelease!.data.tag_name, llamaCppDirectory);
await cloneLlamaCppRepo(githubOwner, githubRepo, githubRelease!.data.tag_name);

if (!skipBuild) {
await downloadCmakeIfNeeded(true);
Expand All @@ -163,8 +163,9 @@ export async function DownloadLlamaCppCommand({
});
}

if (updateBinariesReleaseMetadata) {
if (isCI && updateBinariesReleaseMetadataAndSaveGitBundle) {
await setBinariesGithubRelease(githubRelease!.data.tag_name);
await saveCurrentRepoAsReleaseBundle();
}

console.log();
Expand All @@ -174,35 +175,3 @@ export async function DownloadLlamaCppCommand({
console.log();
console.log(chalk.green("Done"));
}


async function cloneTag(githubOwner: string, githubRepo: string, tag: string, directory: string) {
const progressBar = new cliProgress.Bar({
clearOnComplete: false,
hideCursor: true,
autopadding: true,
format: `${chalk.bold("Clone {repo}")} ${chalk.yellow("{percentage}%")} ${chalk.cyan("{bar}")} ${chalk.grey("{eta_formatted}")}`
}, cliProgress.Presets.shades_classic);

progressBar.start(100, 0, {
speed: "",
repo: `${githubOwner}/${githubRepo}`
});

try {
await simpleGit({
progress({progress, total, processed}) {
const totalProgress = (processed / 100) + (progress / total);

progressBar.update(Math.floor(totalProgress * 10000) / 100);
}
}).clone(`https://github.com/${githubOwner}/${githubRepo}.git`, directory, {
"--depth": 1,
"--branch": tag,
"--quiet": null
});
} finally {
progressBar.update(100);
progressBar.stop();
}
}
4 changes: 4 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,15 @@ export const llamaCppGrammarsDirectory = path.join(llamaDirectory, "llama.cpp",
export const tempDownloadDirectory = path.join(os.tmpdir(), "node-llama-cpp", uuid.v4());
export const usedBinFlagJsonPath = path.join(llamaDirectory, "usedBin.json");
export const binariesGithubReleasePath = path.join(llamaDirectory, "binariesGithubRelease.json");
export const currentReleaseGitBundlePath = path.join(llamaDirectory, "gitRelease.bundle");
export const xpackDirectory = path.join(llamaDirectory, "xpack");
export const localXpacksStoreDirectory = path.join(xpackDirectory, "store");
export const localXpacksCacheDirectory = path.join(xpackDirectory, "cache");
export const xpmVersion = "^0.16.3";

export const isCI = env.get("CI")
.default("false")
.asBool();
export const defaultLlamaCppGitHubRepo = env.get("NODE_LLAMA_CPP_REPO")
.default("ggerganov/llama.cpp")
.asString();
Expand Down
71 changes: 71 additions & 0 deletions src/utils/cloneLlamaCppRepo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import simpleGit, {SimpleGit} from "simple-git";
import cliProgress from "cli-progress";
import chalk from "chalk";
import fs from "fs-extra";
import {llamaCppDirectory} from "../config.js";
import {getGitBundlePathForRelease} from "./gitReleaseBundles.js";


export async function cloneLlamaCppRepo(githubOwner: string, githubRepo: string, tag: string) {
const gitBundleForTag = await getGitBundlePathForRelease(githubOwner, githubRepo, tag);
const remoteGitUrl = `https://github.com/${githubOwner}/${githubRepo}.git`;

async function withGitCloneProgress<T>(cloneName: string, callback: (gitWithCloneProgress: SimpleGit) => Promise<T>): Promise<T> {
const progressBar = new cliProgress.Bar({
clearOnComplete: false,
hideCursor: true,
autopadding: true,
format: `${chalk.bold("Clone {repo}")} ${chalk.yellow("{percentage}%")} ${chalk.cyan("{bar}")} ${chalk.grey("{eta_formatted}")}`
}, cliProgress.Presets.shades_classic);

progressBar.start(100, 0, {
speed: "",
repo: `${githubOwner}/${githubRepo} (${cloneName})`
});

const gitWithCloneProgress = simpleGit({
progress({progress, total, processed}) {
const totalProgress = (processed / 100) + (progress / total);

progressBar.update(Math.floor(totalProgress * 10000) / 100);
}
});

try {
const res = await callback(gitWithCloneProgress);

progressBar.update(100);

return res;
} finally {
progressBar.stop();
}
}

if (gitBundleForTag != null) {
try {
await withGitCloneProgress("local bundle", async (gitWithCloneProgress) => {
await gitWithCloneProgress.clone(gitBundleForTag, llamaCppDirectory, {
"--quiet": null
});

await simpleGit(llamaCppDirectory)
.removeRemote("origin");
await simpleGit(llamaCppDirectory)
.addRemote("origin", remoteGitUrl);
});
return;
} catch (err) {
await fs.remove(llamaCppDirectory);
console.error("Failed to clone git bundle, cloning from GitHub instead", err);
}
}

await withGitCloneProgress("GitHub", async (gitWithCloneProgress) => {
await gitWithCloneProgress.clone(remoteGitUrl, llamaCppDirectory, {
"--depth": 1,
"--branch": tag,
"--quiet": null
});
});
}
34 changes: 34 additions & 0 deletions src/utils/gitReleaseBundles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import fs from "fs-extra";
import simpleGit from "simple-git";
import {currentReleaseGitBundlePath, defaultLlamaCppGitHubRepo, llamaCppDirectory} from "../config.js";
import {getBinariesGithubRelease} from "./binariesGithubRelease.js";


export async function saveCurrentRepoAsReleaseBundle() {
if (!(await fs.pathExists(llamaCppDirectory)))
throw new Error("llama.cpp directory does not exist");

if (await fs.pathExists(currentReleaseGitBundlePath))
await fs.remove(currentReleaseGitBundlePath);

await simpleGit(llamaCppDirectory).raw(["bundle", "create", currentReleaseGitBundlePath, "HEAD"]);
}

export async function getGitBundlePathForRelease(githubOwner: string, githubRepo: string, release: string) {
const [defaultGithubOwner, defaultGithubRepo] = defaultLlamaCppGitHubRepo.split("/");
if (githubOwner !== defaultGithubOwner || githubRepo !== defaultGithubRepo)
return null;

const currentBundleRelease = await getBinariesGithubRelease();

if (currentBundleRelease === "latest")
return null;

if (currentBundleRelease !== release)
return null;

if (!(await fs.pathExists(currentReleaseGitBundlePath)))
return null;

return currentReleaseGitBundlePath;
}