mirror of
https://github.com/cocktailpeanut/dalai
synced 2024-11-20 23:07:32 +01:00
dc8658ae07
Add threads support to front end ui, showing system cpu count by default
169 lines
5.6 KiB
JavaScript
169 lines
5.6 KiB
JavaScript
const path = require('path');
|
|
const term = require( 'terminal-kit' ).terminal;
|
|
const git = require('isomorphic-git');
|
|
const Downloader = require("nodejs-file-downloader");
|
|
const http = require('isomorphic-git/http/node');
|
|
const os = require('os');
|
|
const fs = require("fs");
|
|
const platform = os.platform()
|
|
class LLaMA {
|
|
constructor(root) {
|
|
this.root = root
|
|
this.home = path.resolve(this.root.home, "llama")
|
|
this.url = "https://github.com/candywrap/llama.cpp.git"
|
|
}
|
|
async make() {
|
|
console.log("make")
|
|
let success
|
|
if (platform === "win32") {
|
|
// CMake on Windows
|
|
const venv_path = path.join(this.root.home, "venv")
|
|
const cmake_path = path.join(venv_path, "Scripts", "cmake")
|
|
await this.root.exec("mkdir build", this.home)
|
|
await this.root.exec(`Remove-Item -path ${path.resolve(this.home, "build", "CMakeCache.txt")}`, this.home)
|
|
let PS_COUNTER = 0
|
|
await this.root.exec(`${cmake_path} ..`, path.resolve(this.home, "build"), (proc, data) => {
|
|
console.log("# data", data);
|
|
if (/^PS .*/.test(data)) {
|
|
PS_COUNTER++;
|
|
if (PS_COUNTER >= 2) {
|
|
console.log("KILL")
|
|
proc.kill()
|
|
}
|
|
}
|
|
})
|
|
PS_COUNTER = 0;
|
|
await this.root.exec(`${cmake_path} --build . --config Release`, path.resolve(this.home, "build"), (proc, data) => {
|
|
console.log("# data", data);
|
|
if (/^PS .*/.test(data)) {
|
|
PS_COUNTER++;
|
|
if (PS_COUNTER >= 2) {
|
|
console.log("KILL2")
|
|
proc.kill()
|
|
}
|
|
}
|
|
})
|
|
} else {
|
|
// Make on linux + mac
|
|
success = await this.root.exec(`make`, this.home)
|
|
if (!success) {
|
|
throw new Error("running 'make' failed")
|
|
return
|
|
}
|
|
}
|
|
}
|
|
async add (...models) {
|
|
if (models.length === 0) models = ["7B"]
|
|
models = models.map((m) => {
|
|
return m.toUpperCase()
|
|
})
|
|
for(let model of models) {
|
|
if (!["7B", "13B", "30B", "65B"].includes(model)) {
|
|
console.log(`##########################################################
|
|
#
|
|
# ERROR
|
|
# The arguments must be one or more of the following:
|
|
#
|
|
# 7B, 13B, 30B, 65B
|
|
#
|
|
##########################################################
|
|
|
|
[Example]
|
|
|
|
# install just 7B (default)
|
|
npx dalai install
|
|
|
|
# install 7B manually
|
|
npx dalai install 7B
|
|
|
|
# install 7B and 13B
|
|
npx dalai install 7B 13B
|
|
`)
|
|
throw new Error("The model name must be one of: 7B, 13B, 30B, and 65B")
|
|
return
|
|
}
|
|
}
|
|
|
|
const venv_path = path.join(this.root.home, "venv")
|
|
const python_path = platform == "win32" ? path.join(venv_path, "Scripts", "python.exe") : path.join(venv_path, 'bin', 'python')
|
|
/**************************************************************************************************************
|
|
*
|
|
* 5. Download models + convert + quantize
|
|
*
|
|
**************************************************************************************************************/
|
|
for(let model of models) {
|
|
await this.download(model)
|
|
const outputFile = path.resolve(this.home, 'models', model, 'ggml-model-f16.bin')
|
|
// if (fs.existsSync(outputFile)) {
|
|
// console.log(`Skip conversion, file already exists: ${outputFile}`)
|
|
// } else {
|
|
await this.root.exec(`${python_path} convert-pth-to-ggml.py models/${model}/ 1`, this.home)
|
|
// }
|
|
await this.quantize(model)
|
|
}
|
|
}
|
|
async quantize(model) {
|
|
let num = {
|
|
"7B": 1,
|
|
"13B": 2,
|
|
"30B": 4,
|
|
"65B": 8,
|
|
}
|
|
for(let i=0; i<num[model]; i++) {
|
|
const suffix = (i === 0 ? "" : `.${i}`)
|
|
const outputFile1 = path.resolve(this.home, `./models/${model}/ggml-model-f16.bin${suffix}`)
|
|
const outputFile2 = path.resolve(this.home, `./models/${model}/ggml-model-q4_0.bin${suffix}`)
|
|
if (fs.existsSync(outputFile1) && fs.existsSync(outputFile2)) {
|
|
console.log(`Skip quantization, files already exists: ${outputFile1} and ${outputFile2}}`)
|
|
continue
|
|
}
|
|
const bin_path = platform === "win32" ? path.resolve(this.home, "build", "Release") : this.home
|
|
await this.root.exec(`./quantize ${outputFile1} ${outputFile2} 2`, bin_path)
|
|
}
|
|
}
|
|
async download(model) {
|
|
console.log(`Download model ${model}`)
|
|
const venv_path = path.join(this.root.home, "venv")
|
|
const python_path = platform == "win32" ? path.join(venv_path, "Scripts", "python.exe") : path.join(venv_path, 'bin', 'python')
|
|
const num = {
|
|
"7B": 1,
|
|
"13B": 2,
|
|
"30B": 4,
|
|
"65B": 8,
|
|
}
|
|
const files = ["checklist.chk", "params.json"]
|
|
for(let i=0; i<num[model]; i++) {
|
|
files.push(`consolidated.0${i}.pth`)
|
|
}
|
|
const resolvedPath = path.resolve(this.home, "models", model)
|
|
await fs.promises.mkdir(resolvedPath, { recursive: true }).catch((e) => { })
|
|
|
|
for(let file of files) {
|
|
if (fs.existsSync(path.resolve(resolvedPath, file))) {
|
|
console.log(`Skip file download, it already exists: ${file}`)
|
|
continue;
|
|
}
|
|
|
|
const url = `https://agi.gpt4.org/llama/LLaMA/${model}/${file}`
|
|
await this.root.down(url, path.resolve(resolvedPath, file), {
|
|
"User-Agent": "Mozilla/5.0"
|
|
})
|
|
}
|
|
|
|
const files2 = ["tokenizer_checklist.chk", "tokenizer.model"]
|
|
for(let file of files2) {
|
|
// if (fs.existsSync(path.resolve(this.home, "models", file))) {
|
|
// console.log(`Skip file download, it already exists: ${file}`)
|
|
// continue;
|
|
// }
|
|
const url = `https://agi.gpt4.org/llama/LLaMA/${file}`
|
|
const dir = path.resolve(this.home, "models")
|
|
await this.root.down(url, path.resolve(dir, file), {
|
|
"User-Agent": "Mozilla/5.0"
|
|
})
|
|
}
|
|
|
|
}
|
|
}
|
|
module.exports = LLaMA
|