cocktailpeanut / dalai

The simplest way to run LLaMA on your local machine
https://cocktailpeanut.github.io/dalai
13.11k stars 1.43k forks source link

Windows Alpaca 7B not responding #421

Open Hebleh opened 1 year ago

Hebleh commented 1 year ago

Apologies but this is like my first time doing "coding", I have 0 experience in coding so bare with me and ELI5, but I have been having issues getting the LLM to respond and have tried a lot of different things, I feel like I am missing a file here or there but I do not have the know how to figure out what and where. I get this from the CMD after running npx dalai serve and inputting "hello" on the server. Any help will be appreciated thanks!

`The system cannot find the path specified.

C:\Users\Gerri>npx dalai serve mkdir C:\Users\Gerri\dalai Server running on http://localhost:3000/

query: { method: 'installed', models: [] } modelsPath C:\Users\Gerri\dalai\alpaca\models { modelFolders: [ '7B' ] } exists 7B modelsPath C:\Users\Gerri\dalai\llama\models { modelFolders: [] } query: { seed: '1', threads: '4', n_predict: 200, top_k: 40, top_p: 0.9, temp: 0.8, repeat_last_n: 64, repeat_penalty: '1.1', debug: false, models: [ 'alpaca.7B' ], model: 'alpaca.7B', prompt: 'hello\n', id: 'TS-1682461988744-56715' } { Core: 'alpaca', Model: '7B' } exec: C:\Users\Gerri\dalai\alpaca\build\Release\main --seed 1 --threads 4 --n_predict 200 --model models/7B/ggml-model-q4_0.bin --top_k 40 --top_p 0.9 --temp 0.8 --repeat_last_n 64 --repeat_penalty 1.1 -p "hello\n" in C:\Users\Gerri\dalai\alpaca`

fzn0x commented 1 year ago

In debug mode:

Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.Install the latest PowerShell for new features and improvements! https://aka.ms/PSWindows:WindowsSystem32WindowsPowerShellv1.0powershell.exePS C:UsersUserdalaillama> > [> [System.Console]::OutputEncoding=[System.Console]::InputEncoding=[System.Text.Encoding]::UTF8; C:UsersUserdalaillamauildReleasemain --seed -1 --threads 4 --n_predict 200 --model models/7B/ggml-model-q4_0.bin --top_k 40 --top_p 0.9 --temp 0.8 --repeat_last_n 64 --repeat_penalty 1.3 -p "Hello, AI. "
C:UsersUserdalaillamauildReleasemain : The term 'C:UsersUserdalaillamauildReleasemain' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:96
+ ... Encoding]::UTF8; C:UsersUserdalaillamauildReleasemain --seed  ...
+                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:UsersUserd...ldReleasemain:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

PS C:UsersUserdalaillama> exit

This is recent issue from Windows caused by it's path. Seems like no fix yet.

Hebleh commented 1 year ago

Damn, I thought at least it would have been due to my incompetence which would have been solved by coming here for help. I do have a Steam Deck though, but I saw that both python and node.js is not supported on that specific linux OS? Or am I mistaken

TahaW863 commented 1 year ago

This is a working file for index.js file that can be located by following the node_module for dalai

const os = require('os');
const pty = require('node-pty');
//const pty = require('@cdktf/node-pty-prebuilt-multiarch');
const git = require('isomorphic-git');
const http = require('isomorphic-git/http/node');
const Http = require("http")
const path = require('path');
const fs = require("fs");
const tar = require('tar');
const { createServer } = require("http");
const { Server } = require("socket.io");
const { io } = require("socket.io-client");
const term = require( 'terminal-kit' ).terminal;
const Downloader = require("nodejs-file-downloader");
const semver = require('semver');
//const _7z = require('7zip-min');
const axios = require('axios')
const platform = os.platform()
const shell = platform === 'win32' ? 'powershell.exe' : 'bash';
const L = require("./llama")
const A = require("./alpaca")
const TorrentDownloader = require("./torrent")
const exists = s => new Promise(r=>fs.access(s, fs.constants.F_OK, e => r(!e)))
const escapeNewLine = (platform, arg) => platform === 'win32' ? arg.replaceAll(/\n/g, "\\n").replaceAll(/\r/g, "\\r") : arg
const escapeDoubleQuotes = (platform, arg) => platform === 'win32' ? arg.replaceAll(/"/g, '`"') : arg.replaceAll(/"/g, '\\"')
const stripAnsi = (str) => {
  const pattern = [
    '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
    '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))'
  ].join('|');

  const regex = new RegExp(pattern, 'g')
  return str.replace(regex, '');
}
const winEscape = (str) => {
  return str
  .replaceAll(/\\n/g, "\n")
  .replaceAll(/\\r/g, "\r")
  .replaceAll(/\\t/g, "\t")
  .replaceAll(/\\b/g, "\b")
  .replaceAll(/\\f/g, "\f")
  .replaceAll(/\\/g, "")
}

class Dalai {
  constructor(home) {
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //
    // 1. manually set llama.cpp home
    // 2. otherwise store llama.cpp at ~/llama.cpp
    //
    //  # NOTE
    //  Could have used process.cwd() (The current execution directory) to download llama.cpp
    //  but this makes it cumbersome as you try to build multiple apps, because by default Dalai client will
    //  look for the current execution directory for llama.cpp.
    //  It's simpler to set the ~/llama.cpp as the default directory and use that path as the single source
    //  of truth and let multiple apps all connect to that path
    //  Otherwise if you want to customize the path you can just pass in the "home" attribute to manually set it.
    //
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    this.home = home ? path.resolve(home) : path.resolve(os.homedir(), "dalai")
    try {
      console.log("mkdir", this.home)
      fs.mkdirSync(this.home, { recursive: true })
    } catch (e) {
      console.log("E", e)
    }
    this.torrent = new TorrentDownloader()
    this.config = {
      name: 'xterm-color',
      cols: 1000,
      rows: 30,
    }
    this.cores = {
      llama: new L(this),
      alpaca: new A(this),
    }
  }
  htmlencode (str) {
    let encodedStr = '';
    for (let i = 0; i < str.length; i++) {
      let charCode = str.charCodeAt(i);
      if (charCode < 128) {
        // ASCII characters
        switch (str[i]) {
          case '<': encodedStr += '&lt;'; break;
          case '>': encodedStr += '&gt;'; break;
          case '&': encodedStr += '&amp;'; break;
          case '"': encodedStr += '&quot;'; break;
          case '\'': encodedStr += '&#39;'; break;
          case '\n': encodedStr += '<br>'; break;
          case '\r': break; // ignore
          case '\t': encodedStr += '&nbsp;&nbsp;&nbsp;&nbsp;'; break;
          case '\b': encodedStr += '&nbsp;'; break;
          case '\f': encodedStr += '&nbsp;'; break;
          default: encodedStr += String.fromCharCode(charCode); break;
        }
      } else {
        // Non-ASCII characters
        encodedStr += "&#" + charCode + ";";
      }
    }
    return encodedStr;
  }
  down(url, dest, headers) {
    return new Promise((resolve, reject) => {
      const task = path.basename(dest)
      this.startProgress(task)
      axios({
        url,
        method: 'GET',
        responseType: 'stream',
        maxContentLength: Infinity,
        headers,
        onDownloadProgress: progressEvent => {
          const progress = (progressEvent.loaded / progressEvent.total) * 100;
          this.progress(task, progress)
        }

      }).then(response => {
        const writer = fs.createWriteStream(dest);
        response.data.pipe(writer);
        writer.on('finish', () => {
          this.progressBar.update(1);
          term("\n")
          resolve()
        });
      }).catch(error => {
        reject(error)
      });
    })
  }
  async python () {
    // install self-contained python => only for windows for now
    // 1. download
    // 2. unzip

    const filename = "cpython-3.10.9+20230116-x86_64-pc-windows-msvc-shared-install_only.tar.gz"
    const task = "downloading self contained python"
    const downloader = new Downloader({
      url: `https://github.com/indygreg/python-build-standalone/releases/download/20230116/${filename}`,
      directory: this.home,
      onProgress: (percentage, chunk, remainingSize) => {
        this.progress(task, percentage)
      },
    });
    try {
      await this.startProgress(task)
      await downloader.download();
    } catch (error) {
      console.log(error);
    }
    this.progressBar.update(1);
    console.log("extracting python")
    await tar.x({
      file: path.resolve(this.home, filename),
      C: this.home,
      strict: true
    })
    console.log("cleaning up temp files")
    await fs.promises.rm(path.resolve(this.home, filename))
  }
//  async mingw() {
//    const mingw = "https://github.com/niXman/mingw-builds-binaries/releases/download/12.2.0-rt_v10-rev2/x86_64-12.2.0-release-win32-seh-msvcrt-rt_v10-rev2.7z"
//    const downloader = new Downloader({
//      url: mingw,
//      directory: this.home,
//      onProgress: (percentage, chunk, remainingSize) => {
//        this.progress("download mingw", percentage)
//      },
//    });
//    try {
//      await this.startProgress("download mingw")
//      await downloader.download();
//    } catch (error) {
//      console.log(error);
//    }
//    this.progressBar.update(1);
//    await new Promise((resolve, reject) => {
//      _7z.unpack(path.resolve(this.home, "x86_64-12.2.0-release-win32-seh-msvcrt-rt_v10-rev2.7z"), this.home, (err) => {
//        if (err) { 
//          reject(err)
//        } else {
//          resolve()
//        }
//      })
//    })
//    console.log("cleaning up temp files")
//    await fs.promises.rm(path.resolve(this.home, "x86_64-12.2.0-release-win32-seh-msvcrt-rt_v10-rev2.7z"))
//  }
  async query(req, cb) {

    console.log(`> query:`, req)
    if (req.method === "installed") {
      let models = await this.installed()
      for(let model of models) {
        cb(model)
      }
      cb('\n\n<end>')
      return
    }

    if (req.prompt && req.prompt.startsWith("/")) {
      try {
        const mod = require(`./cmds/${req.prompt.slice(1)}`)
        if (mod) {
          mod(this)
          return
        }
      } catch (e) {
        console.log("require log", e)
      }
    }

    if (!req.prompt) {
      return
    }
    console.log(req.models)
    let [Core, Model] = req.models[0].split(".")
    Model = Model.toUpperCase()

    console.log( { Core, Model } )

    let o = {
      seed: req.seed || -1,
      threads: req.threads || 8,
      n_predict: req.n_predict || 128,
      model: `models/${Model || "7B"}/ggml-model-q4_0.bin`,
    }

    let e = await exists(path.resolve(this.home, Core, "models", Model))
    if (!e) {
      cb(`File does not exist: ${Model}. Try "dalai ${Core} get ${Model}" first.`)
      return
    }

    if (req.top_k) o.top_k = req.top_k
    if (req.top_p) o.top_p = req.top_p
    if (req.temp) o.temp = req.temp
    if (req.batch_size) o.batch_size = req.batch_size
    if (req.repeat_last_n) o.repeat_last_n = req.repeat_last_n
    if (req.repeat_penalty) o.repeat_penalty = req.repeat_penalty
    if (typeof req.interactive !== "undefined") o.interactive = req.interactive

    let chunks = []
    for(let key in o) {
      chunks.push(`--${key} ${escapeDoubleQuotes(platform, o[key].toString())}`)
    }
    const escaped = escapeNewLine(platform, req.prompt)
    const prompt = `"${escapeDoubleQuotes(platform, escaped)}"`

    chunks.push(`-p ${prompt}`)

    const main_bin_path = platform === "win32" ? path.resolve(this.home, Core, "build", "Release", "main") : path.resolve(this.home, Core, "main")
    this.sessionBuffer = "";
    this.bufferStarted = false;
    if (req.full) {
      await this.exec(`${main_bin_path} ${chunks.join(" ")}`, this.cores[Core].home, cb)
    } else {
      const startpattern = /.*sampling parameters:.*/g
      const endpattern = /.*mem per token.*/g
      let started = req.debug
      let ended = false
      let writeEnd = !req.skip_end
      await this.exec(`${main_bin_path} ${chunks.join(" ")}`, this.cores[Core].home, (proc, msg) => {
        if (endpattern.test(msg)) ended = true
        if (started && !ended) {
          this.buffer(req, msg, cb)
        } else if (ended && writeEnd) {
          cb('\n\n<end>')
          writeEnd = false
        }
        if (startpattern.test(msg)) started = true
      })
    }
  }
  buffer(req, msg, cb) {
    if (!this.queue) this.queue = []
    if (platform === "win32") {
      for(let i=0;i<msg.length; i++) {
        if (msg[i] === "\\") {
          this.queueActive = true
          // start pushing to buffer
          this.queue.push(msg[i]);
        } else {
          // otherwise flush
          this.queue.push(msg[i])
          let queueContent = this.queue.join("")

          if (!this.bufferStarted && ["\n", "\b", "\f", "\r", "\t"].includes(queueContent)) {
            // if the buffer hasn't started and incoming tokens are whitespaces, ignore
          } else {
            if (req.html) {
              cb(this.htmlencode(winEscape(queueContent)))
            } else {
              cb(winEscape(queueContent))
            }
            this.bufferStarted = true
          }
          this.queue = []
          this.queueActive = false
        }
      }
    } else {
      if (req.html) {
        cb(this.htmlencode(msg))
      } else {
        cb(msg)
      } 
    }
  }
  async uninstall(core, ...models) {
    if (models.length > 0) {
      // delete the model folder
      const modelsPath = path.resolve(this.home, core, "models")
      for(let model of models) {
        const modelPath = path.resolve(modelsPath, model)
        console.log("rm", modelPath)
        await fs.promises.rm(modelPath, { recursive: true, force: true }).catch((e) => {
          console.log("rm", modelPath, e)
        })
      }
    }
  }
  async install(core, ...models) {

    let engine = this.cores[core]

    const venv_path = path.join(this.home, "venv")
    let ve = await exists(venv_path)
    if (!ve) {
      await this.setup()
    }

    // temporary

    let models_path = path.resolve(engine.home, "models")
    let temp_path = path.resolve(this.home, "tmp")
    let temp_models_path = path.resolve(temp_path, "models")
    await fs.promises.mkdir(temp_path, { recursive: true }).catch((e) => { console.log("1", e) })
    // 1. move the models folder to ../tmp
    await fs.promises.rename(models_path, temp_models_path).catch((e) => { console.log("2", e) })
    // 2. wipe out the folder
    await fs.promises.rm(engine.home, { recursive: true }).catch((e) => { console.log("3", e) })
    // 3. install engine
    await this.add(core)
    // 4. move back the files inside /tmp
    await fs.promises.rename(temp_models_path, models_path).catch((e) => { console.log("4", e) })

    // next add the models
    let res = await this.cores[core].add(...models)
    return res
  }
  async installed() {
    // get cores
    const modelNames = []
    for(let core of ["alpaca", "llama"]) {
      const modelsPath = path.resolve(this.home, core, "models")
      console.log("modelsPath", modelsPath)
      let modelFolders = []
      try {
        modelFolders = (await fs.promises.readdir(modelsPath, { withFileTypes: true }))
          .filter(dirent => dirent.isDirectory())
          .map(dirent => dirent.name)
      } catch (e) {
      }

      console.log({ modelFolders })
      for(let modelFolder of modelFolders) {
        let e = await exists(path.resolve(modelsPath, modelFolder, 'ggml-model-q4_0.bin'))
        if (e) {
          modelNames.push(`${core}.${modelFolder}`)
          console.log("exists", modelFolder)
        }
      }
    }
    return modelNames
  }
  async add (core) {
    /**************************************************************************************************************
    *
    * 2. Download Core
    *
    **************************************************************************************************************/
    let engine = this.cores[core]
    let e = await exists(path.resolve(engine.home));
    console.log("mkdir", path.resolve(engine.home))
    await fs.promises.mkdir(path.resolve(engine.home), { recursive: true }).catch((e) => {
      console.log("ERROR" ,e)
    })

    try {
      console.log("try fetching", engine.home, engine.url)
      await git.pull({ fs, http, dir: engine.home, url: engine.url })
    } catch (e) {
      console.log("[E] Pull", e)
      try {
        console.log("try cloning", engine.home, engine.url)
        await git.clone({ fs, http, dir: engine.home, url: engine.url })
      } catch (e2) {
        console.log("[E] Clone", e2)
      }
    }
    console.log("next", core, engine.make);
    /**************************************************************************************************************
    *
    * 4. Compile & Build
    *   - make: linux + mac
    *   - cmake: windows
    *
    **************************************************************************************************************/
    await engine.make()
  }
  async setup() {

    let success;

    /**************************************************************************************************************
    *
    * 1. Validate
    *
    **************************************************************************************************************/
    // Check if current version is greater than or equal to 18
    const node_version = process.version;
    if (!semver.gte(node_version, '18.0.0')) {
      throw new Error("outdated Node version, please install Node 18 or newer")
    }

    /**************************************************************************************************************
    *
    * 3. Download Global Dependencies
    *   - Python (windows only)
    *   - build-essential (linux only)
    *   - virtualenv
    *   - torch, numpy, etc.
    *
    **************************************************************************************************************/

    // 3.1. Python: Windows doesn't ship with python, so install a dedicated self-contained python
    if (platform === "win32") {
      await this.python() 
    }
    const root_python_paths = (platform === "win32" ? ["python3", "python", path.resolve(this.home, "python", "python.exe")] : ["python3", "python"])
    const root_pip_paths = (platform === "win32" ? ["pip3", "pip", path.resolve(this.home, "python", "python -m pip")] : ["pip3", "pip"])

    // 3.2. Build tools
    if (platform === "linux") {
      // ubuntu debian
      success = await this.exec("apt-get install build-essential python3-venv -y")
      if (!success) {
        // fefdora
        success = await this.exec("dnf install make automake gcc gcc-c++ kernel-devel python3-virtualenv -y")
      }
    } else {
      // for win32 / darwin
      for(let root_pip_path of root_pip_paths) {
        success = await this.exec(`${root_pip_path} install --user virtualenv`)
        if (success) {
          break;
        }
        success = await this.exec(`${root_pip_path} install virtualenv`)
        if (success) {
          break;
        }
      }
      if (!success) {
        throw new Error("cannot install virtualenv")
      }

    }

    // 3.3. virtualenv
    const venv_path = path.join(this.home, "venv")
    for(let root_python_path of root_python_paths) {
      console.log("trying with", root_python_path)
      let code = await this.exec(`${root_python_path} -m venv ${venv_path}`)
      console.log({ code })
    }
    /*
    if (!success) {
      throw new Error("cannot execute python3 or python")
      return
    }
    */

    // 3.4. Python libraries
    const pip_path = platform === "win32" ? path.join(venv_path, "Scripts", "pip.exe") : path.join(venv_path, "bin", "pip")
    const python_path = platform == "win32" ? path.join(venv_path, "Scripts", "python.exe") : path.join(venv_path, 'bin', 'python')
    // cmake (only on windows. the rest platforms use make)
    if (platform === "win32") {
      success = await this.exec(`${pip_path} install cmake`)
      if (!success) {
        throw new Error("cmake installation failed")
        return
      }
    }
    success = await this.exec(`${pip_path} install --upgrade pip setuptools wheel`)
    if (!success) {
      success = await this.exec(`${pip_path} install --user --upgrade pip setuptools wheel`)
      if (!success) {
        throw new Error("pip setuptools wheel upgrade failed")
        return  
      }
    }
    success = await this.exec(`${pip_path} install torch torchvision torchaudio sentencepiece numpy`)
    //success = await this.exec(`${pip_path} install torch torchvision torchaudio sentencepiece numpy wget`)
    if (!success) {
      success = await this.exec(`${pip_path} install --user torch torchvision torchaudio sentencepiece numpy`)
      if (!success) {
        throw new Error("dependency installation failed")
        return  
      }
    }

  }
  serve(port, options) {
    const httpServer = createServer();
    const io = new Server(httpServer)
    io.on("connection", (socket) => {
      socket.on('request', async (req) => {
        await this.query(req, (str) => {
          io.emit("result", { response: str, request: req })
        })
      });
    });
    httpServer.listen(port)
  }
  http(httpServer) {
    const io = new Server(httpServer)
    io.on("connection", (socket) => {
      socket.on('request', async (req) => {
        req.models = Array.from(new Set(req.models))
        await this.query(req, (str) => {
          io.emit("result", { response: str, request: req })
        })
      });
    });
  }
  async request(req, cb) {
    if (req.url) {
      await this.connect(req, cb)
    } else {
      await this.query(req, cb)
    }
  }
  connect(req, cb) {
    const socket = io(req.url)
    socket.emit('request', req)
    socket.on('response', cb)
    socket.on('error', function(e) {
      throw e
    });
  }
  exec(cmd, cwd, cb) {
    return new Promise((resolve, reject) => {
      try {
        const config = Object.assign({}, this.config)
        if (cwd) {
          config.cwd = path.resolve(cwd)
        }
        console.log(`exec: ${cmd} in ${config.cwd}`)
        this.ptyProcess = pty.spawn(shell, [], config)
        this.ptyProcess.onData((data) => {
          if (cb) {
            cb(this.ptyProcess, stripAnsi(data))
          } else {
            process.stdout.write(data);
          }
        });
        this.ptyProcess.onExit((res) => {
          if (res.exitCode === 0) {
            // successful
            resolve(true)
          } else {
            // something went wrong
            resolve(false)
          }
        });

        if (platform === "win32") {
          this.ptyProcess.write(`[System.Console]::OutputEncoding=[System.Console]::InputEncoding=[System.Text.Encoding]::UTF8; ${cmd}\r`)
        } else {
          this.ptyProcess.write(`${cmd}\r`)
        }
        this.ptyProcess.write("exit\r")
      } catch (e) {
        console.log("caught error", e)
        this.ptyProcess.kill()
        // ptyProcess.write("exit\r")
      }
    })
  }
  progress(task, percent) {
    this.progressBar.update(percent/100);
    //if (percent >= 100) {
    //  setTimeout(() => {
    //    term("\n")
    //  }, 200)
    //}
  }
  startProgress(title) {
    this.progressBar = term.progressBar({
      width: 120,
      title,
      eta: true ,
      percent: true
    });
  }
}
module.exports = Dalai
Hebleh commented 1 year ago

This is a working file for index.js file that can be located by following the node_module for dalai

const os = require('os');
const pty = require('node-pty');
//const pty = require('@cdktf/node-pty-prebuilt-multiarch');
const git = require('isomorphic-git');
const http = require('isomorphic-git/http/node');
const Http = require("http")
const path = require('path');
const fs = require("fs");
const tar = require('tar');
const { createServer } = require("http");
const { Server } = require("socket.io");
const { io } = require("socket.io-client");
const term = require( 'terminal-kit' ).terminal;
const Downloader = require("nodejs-file-downloader");
const semver = require('semver');
//const _7z = require('7zip-min');
const axios = require('axios')
const platform = os.platform()
const shell = platform === 'win32' ? 'powershell.exe' : 'bash';
const L = require("./llama")
const A = require("./alpaca")
const TorrentDownloader = require("./torrent")
const exists = s => new Promise(r=>fs.access(s, fs.constants.F_OK, e => r(!e)))
const escapeNewLine = (platform, arg) => platform === 'win32' ? arg.replaceAll(/\n/g, "\\n").replaceAll(/\r/g, "\\r") : arg
const escapeDoubleQuotes = (platform, arg) => platform === 'win32' ? arg.replaceAll(/"/g, '`"') : arg.replaceAll(/"/g, '\\"')
const stripAnsi = (str) => {
  const pattern = [
    '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
    '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))'
  ].join('|');

  const regex = new RegExp(pattern, 'g')
  return str.replace(regex, '');
}
const winEscape = (str) => {
  return str
  .replaceAll(/\\n/g, "\n")
  .replaceAll(/\\r/g, "\r")
  .replaceAll(/\\t/g, "\t")
  .replaceAll(/\\b/g, "\b")
  .replaceAll(/\\f/g, "\f")
  .replaceAll(/\\/g, "")
}

class Dalai {
  constructor(home) {
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //
    // 1. manually set llama.cpp home
    // 2. otherwise store llama.cpp at ~/llama.cpp
    //
    //  # NOTE
    //  Could have used process.cwd() (The current execution directory) to download llama.cpp
    //  but this makes it cumbersome as you try to build multiple apps, because by default Dalai client will
    //  look for the current execution directory for llama.cpp.
    //  It's simpler to set the ~/llama.cpp as the default directory and use that path as the single source
    //  of truth and let multiple apps all connect to that path
    //  Otherwise if you want to customize the path you can just pass in the "home" attribute to manually set it.
    //
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    this.home = home ? path.resolve(home) : path.resolve(os.homedir(), "dalai")
    try {
      console.log("mkdir", this.home)
      fs.mkdirSync(this.home, { recursive: true })
    } catch (e) {
      console.log("E", e)
    }
    this.torrent = new TorrentDownloader()
    this.config = {
      name: 'xterm-color',
      cols: 1000,
      rows: 30,
    }
    this.cores = {
      llama: new L(this),
      alpaca: new A(this),
    }
  }
  htmlencode (str) {
    let encodedStr = '';
    for (let i = 0; i < str.length; i++) {
      let charCode = str.charCodeAt(i);
      if (charCode < 128) {
        // ASCII characters
        switch (str[i]) {
          case '<': encodedStr += '&lt;'; break;
          case '>': encodedStr += '&gt;'; break;
          case '&': encodedStr += '&amp;'; break;
          case '"': encodedStr += '&quot;'; break;
          case '\'': encodedStr += '&#39;'; break;
          case '\n': encodedStr += '<br>'; break;
          case '\r': break; // ignore
          case '\t': encodedStr += '&nbsp;&nbsp;&nbsp;&nbsp;'; break;
          case '\b': encodedStr += '&nbsp;'; break;
          case '\f': encodedStr += '&nbsp;'; break;
          default: encodedStr += String.fromCharCode(charCode); break;
        }
      } else {
        // Non-ASCII characters
        encodedStr += "&#" + charCode + ";";
      }
    }
    return encodedStr;
  }
  down(url, dest, headers) {
    return new Promise((resolve, reject) => {
      const task = path.basename(dest)
      this.startProgress(task)
      axios({
        url,
        method: 'GET',
        responseType: 'stream',
        maxContentLength: Infinity,
        headers,
        onDownloadProgress: progressEvent => {
          const progress = (progressEvent.loaded / progressEvent.total) * 100;
          this.progress(task, progress)
        }

      }).then(response => {
        const writer = fs.createWriteStream(dest);
        response.data.pipe(writer);
        writer.on('finish', () => {
          this.progressBar.update(1);
          term("\n")
          resolve()
        });
      }).catch(error => {
        reject(error)
      });
    })
  }
  async python () {
    // install self-contained python => only for windows for now
    // 1. download
    // 2. unzip

    const filename = "cpython-3.10.9+20230116-x86_64-pc-windows-msvc-shared-install_only.tar.gz"
    const task = "downloading self contained python"
    const downloader = new Downloader({
      url: `https://github.com/indygreg/python-build-standalone/releases/download/20230116/${filename}`,
      directory: this.home,
      onProgress: (percentage, chunk, remainingSize) => {
        this.progress(task, percentage)
      },
    });
    try {
      await this.startProgress(task)
      await downloader.download();
    } catch (error) {
      console.log(error);
    }
    this.progressBar.update(1);
    console.log("extracting python")
    await tar.x({
      file: path.resolve(this.home, filename),
      C: this.home,
      strict: true
    })
    console.log("cleaning up temp files")
    await fs.promises.rm(path.resolve(this.home, filename))
  }
//  async mingw() {
//    const mingw = "https://github.com/niXman/mingw-builds-binaries/releases/download/12.2.0-rt_v10-rev2/x86_64-12.2.0-release-win32-seh-msvcrt-rt_v10-rev2.7z"
//    const downloader = new Downloader({
//      url: mingw,
//      directory: this.home,
//      onProgress: (percentage, chunk, remainingSize) => {
//        this.progress("download mingw", percentage)
//      },
//    });
//    try {
//      await this.startProgress("download mingw")
//      await downloader.download();
//    } catch (error) {
//      console.log(error);
//    }
//    this.progressBar.update(1);
//    await new Promise((resolve, reject) => {
//      _7z.unpack(path.resolve(this.home, "x86_64-12.2.0-release-win32-seh-msvcrt-rt_v10-rev2.7z"), this.home, (err) => {
//        if (err) { 
//          reject(err)
//        } else {
//          resolve()
//        }
//      })
//    })
//    console.log("cleaning up temp files")
//    await fs.promises.rm(path.resolve(this.home, "x86_64-12.2.0-release-win32-seh-msvcrt-rt_v10-rev2.7z"))
//  }
  async query(req, cb) {

    console.log(`> query:`, req)
    if (req.method === "installed") {
      let models = await this.installed()
      for(let model of models) {
        cb(model)
      }
      cb('\n\n<end>')
      return
    }

    if (req.prompt && req.prompt.startsWith("/")) {
      try {
        const mod = require(`./cmds/${req.prompt.slice(1)}`)
        if (mod) {
          mod(this)
          return
        }
      } catch (e) {
        console.log("require log", e)
      }
    }

    if (!req.prompt) {
      return
    }
    console.log(req.models)
    let [Core, Model] = req.models[0].split(".")
    Model = Model.toUpperCase()

    console.log( { Core, Model } )

    let o = {
      seed: req.seed || -1,
      threads: req.threads || 8,
      n_predict: req.n_predict || 128,
      model: `models/${Model || "7B"}/ggml-model-q4_0.bin`,
    }

    let e = await exists(path.resolve(this.home, Core, "models", Model))
    if (!e) {
      cb(`File does not exist: ${Model}. Try "dalai ${Core} get ${Model}" first.`)
      return
    }

    if (req.top_k) o.top_k = req.top_k
    if (req.top_p) o.top_p = req.top_p
    if (req.temp) o.temp = req.temp
    if (req.batch_size) o.batch_size = req.batch_size
    if (req.repeat_last_n) o.repeat_last_n = req.repeat_last_n
    if (req.repeat_penalty) o.repeat_penalty = req.repeat_penalty
    if (typeof req.interactive !== "undefined") o.interactive = req.interactive

    let chunks = []
    for(let key in o) {
      chunks.push(`--${key} ${escapeDoubleQuotes(platform, o[key].toString())}`)
    }
    const escaped = escapeNewLine(platform, req.prompt)
    const prompt = `"${escapeDoubleQuotes(platform, escaped)}"`

    chunks.push(`-p ${prompt}`)

    const main_bin_path = platform === "win32" ? path.resolve(this.home, Core, "build", "Release", "main") : path.resolve(this.home, Core, "main")
    this.sessionBuffer = "";
    this.bufferStarted = false;
    if (req.full) {
      await this.exec(`${main_bin_path} ${chunks.join(" ")}`, this.cores[Core].home, cb)
    } else {
      const startpattern = /.*sampling parameters:.*/g
      const endpattern = /.*mem per token.*/g
      let started = req.debug
      let ended = false
      let writeEnd = !req.skip_end
      await this.exec(`${main_bin_path} ${chunks.join(" ")}`, this.cores[Core].home, (proc, msg) => {
        if (endpattern.test(msg)) ended = true
        if (started && !ended) {
          this.buffer(req, msg, cb)
        } else if (ended && writeEnd) {
          cb('\n\n<end>')
          writeEnd = false
        }
        if (startpattern.test(msg)) started = true
      })
    }
  }
  buffer(req, msg, cb) {
    if (!this.queue) this.queue = []
    if (platform === "win32") {
      for(let i=0;i<msg.length; i++) {
        if (msg[i] === "\\") {
          this.queueActive = true
          // start pushing to buffer
          this.queue.push(msg[i]);
        } else {
          // otherwise flush
          this.queue.push(msg[i])
          let queueContent = this.queue.join("")

          if (!this.bufferStarted && ["\n", "\b", "\f", "\r", "\t"].includes(queueContent)) {
            // if the buffer hasn't started and incoming tokens are whitespaces, ignore
          } else {
            if (req.html) {
              cb(this.htmlencode(winEscape(queueContent)))
            } else {
              cb(winEscape(queueContent))
            }
            this.bufferStarted = true
          }
          this.queue = []
          this.queueActive = false
        }
      }
    } else {
      if (req.html) {
        cb(this.htmlencode(msg))
      } else {
        cb(msg)
      } 
    }
  }
  async uninstall(core, ...models) {
    if (models.length > 0) {
      // delete the model folder
      const modelsPath = path.resolve(this.home, core, "models")
      for(let model of models) {
        const modelPath = path.resolve(modelsPath, model)
        console.log("rm", modelPath)
        await fs.promises.rm(modelPath, { recursive: true, force: true }).catch((e) => {
          console.log("rm", modelPath, e)
        })
      }
    }
  }
  async install(core, ...models) {

    let engine = this.cores[core]

    const venv_path = path.join(this.home, "venv")
    let ve = await exists(venv_path)
    if (!ve) {
      await this.setup()
    }

    // temporary

    let models_path = path.resolve(engine.home, "models")
    let temp_path = path.resolve(this.home, "tmp")
    let temp_models_path = path.resolve(temp_path, "models")
    await fs.promises.mkdir(temp_path, { recursive: true }).catch((e) => { console.log("1", e) })
    // 1. move the models folder to ../tmp
    await fs.promises.rename(models_path, temp_models_path).catch((e) => { console.log("2", e) })
    // 2. wipe out the folder
    await fs.promises.rm(engine.home, { recursive: true }).catch((e) => { console.log("3", e) })
    // 3. install engine
    await this.add(core)
    // 4. move back the files inside /tmp
    await fs.promises.rename(temp_models_path, models_path).catch((e) => { console.log("4", e) })

    // next add the models
    let res = await this.cores[core].add(...models)
    return res
  }
  async installed() {
    // get cores
    const modelNames = []
    for(let core of ["alpaca", "llama"]) {
      const modelsPath = path.resolve(this.home, core, "models")
      console.log("modelsPath", modelsPath)
      let modelFolders = []
      try {
        modelFolders = (await fs.promises.readdir(modelsPath, { withFileTypes: true }))
          .filter(dirent => dirent.isDirectory())
          .map(dirent => dirent.name)
      } catch (e) {
      }

      console.log({ modelFolders })
      for(let modelFolder of modelFolders) {
        let e = await exists(path.resolve(modelsPath, modelFolder, 'ggml-model-q4_0.bin'))
        if (e) {
          modelNames.push(`${core}.${modelFolder}`)
          console.log("exists", modelFolder)
        }
      }
    }
    return modelNames
  }
  async add (core) {
    /**************************************************************************************************************
    *
    * 2. Download Core
    *
    **************************************************************************************************************/
    let engine = this.cores[core]
    let e = await exists(path.resolve(engine.home));
    console.log("mkdir", path.resolve(engine.home))
    await fs.promises.mkdir(path.resolve(engine.home), { recursive: true }).catch((e) => {
      console.log("ERROR" ,e)
    })

    try {
      console.log("try fetching", engine.home, engine.url)
      await git.pull({ fs, http, dir: engine.home, url: engine.url })
    } catch (e) {
      console.log("[E] Pull", e)
      try {
        console.log("try cloning", engine.home, engine.url)
        await git.clone({ fs, http, dir: engine.home, url: engine.url })
      } catch (e2) {
        console.log("[E] Clone", e2)
      }
    }
    console.log("next", core, engine.make);
    /**************************************************************************************************************
    *
    * 4. Compile & Build
    *   - make: linux + mac
    *   - cmake: windows
    *
    **************************************************************************************************************/
    await engine.make()
  }
  async setup() {

    let success;

    /**************************************************************************************************************
    *
    * 1. Validate
    *
    **************************************************************************************************************/
    // Check if current version is greater than or equal to 18
    const node_version = process.version;
    if (!semver.gte(node_version, '18.0.0')) {
      throw new Error("outdated Node version, please install Node 18 or newer")
    }

    /**************************************************************************************************************
    *
    * 3. Download Global Dependencies
    *   - Python (windows only)
    *   - build-essential (linux only)
    *   - virtualenv
    *   - torch, numpy, etc.
    *
    **************************************************************************************************************/

    // 3.1. Python: Windows doesn't ship with python, so install a dedicated self-contained python
    if (platform === "win32") {
      await this.python() 
    }
    const root_python_paths = (platform === "win32" ? ["python3", "python", path.resolve(this.home, "python", "python.exe")] : ["python3", "python"])
    const root_pip_paths = (platform === "win32" ? ["pip3", "pip", path.resolve(this.home, "python", "python -m pip")] : ["pip3", "pip"])

    // 3.2. Build tools
    if (platform === "linux") {
      // ubuntu debian
      success = await this.exec("apt-get install build-essential python3-venv -y")
      if (!success) {
        // fefdora
        success = await this.exec("dnf install make automake gcc gcc-c++ kernel-devel python3-virtualenv -y")
      }
    } else {
      // for win32 / darwin
      for(let root_pip_path of root_pip_paths) {
        success = await this.exec(`${root_pip_path} install --user virtualenv`)
        if (success) {
          break;
        }
        success = await this.exec(`${root_pip_path} install virtualenv`)
        if (success) {
          break;
        }
      }
      if (!success) {
        throw new Error("cannot install virtualenv")
      }

    }

    // 3.3. virtualenv
    const venv_path = path.join(this.home, "venv")
    for(let root_python_path of root_python_paths) {
      console.log("trying with", root_python_path)
      let code = await this.exec(`${root_python_path} -m venv ${venv_path}`)
      console.log({ code })
    }
    /*
    if (!success) {
      throw new Error("cannot execute python3 or python")
      return
    }
    */

    // 3.4. Python libraries
    const pip_path = platform === "win32" ? path.join(venv_path, "Scripts", "pip.exe") : path.join(venv_path, "bin", "pip")
    const python_path = platform == "win32" ? path.join(venv_path, "Scripts", "python.exe") : path.join(venv_path, 'bin', 'python')
    // cmake (only on windows. the rest platforms use make)
    if (platform === "win32") {
      success = await this.exec(`${pip_path} install cmake`)
      if (!success) {
        throw new Error("cmake installation failed")
        return
      }
    }
    success = await this.exec(`${pip_path} install --upgrade pip setuptools wheel`)
    if (!success) {
      success = await this.exec(`${pip_path} install --user --upgrade pip setuptools wheel`)
      if (!success) {
        throw new Error("pip setuptools wheel upgrade failed")
        return  
      }
    }
    success = await this.exec(`${pip_path} install torch torchvision torchaudio sentencepiece numpy`)
    //success = await this.exec(`${pip_path} install torch torchvision torchaudio sentencepiece numpy wget`)
    if (!success) {
      success = await this.exec(`${pip_path} install --user torch torchvision torchaudio sentencepiece numpy`)
      if (!success) {
        throw new Error("dependency installation failed")
        return  
      }
    }

  }
  serve(port, options) {
    const httpServer = createServer();
    const io = new Server(httpServer)
    io.on("connection", (socket) => {
      socket.on('request', async (req) => {
        await this.query(req, (str) => {
          io.emit("result", { response: str, request: req })
        })
      });
    });
    httpServer.listen(port)
  }
  http(httpServer) {
    const io = new Server(httpServer)
    io.on("connection", (socket) => {
      socket.on('request', async (req) => {
        req.models = Array.from(new Set(req.models))
        await this.query(req, (str) => {
          io.emit("result", { response: str, request: req })
        })
      });
    });
  }
  async request(req, cb) {
    if (req.url) {
      await this.connect(req, cb)
    } else {
      await this.query(req, cb)
    }
  }
  connect(req, cb) {
    const socket = io(req.url)
    socket.emit('request', req)
    socket.on('response', cb)
    socket.on('error', function(e) {
      throw e
    });
  }
  exec(cmd, cwd, cb) {
    return new Promise((resolve, reject) => {
      try {
        const config = Object.assign({}, this.config)
        if (cwd) {
          config.cwd = path.resolve(cwd)
        }
        console.log(`exec: ${cmd} in ${config.cwd}`)
        this.ptyProcess = pty.spawn(shell, [], config)
        this.ptyProcess.onData((data) => {
          if (cb) {
            cb(this.ptyProcess, stripAnsi(data))
          } else {
            process.stdout.write(data);
          }
        });
        this.ptyProcess.onExit((res) => {
          if (res.exitCode === 0) {
            // successful
            resolve(true)
          } else {
            // something went wrong
            resolve(false)
          }
        });

        if (platform === "win32") {
          this.ptyProcess.write(`[System.Console]::OutputEncoding=[System.Console]::InputEncoding=[System.Text.Encoding]::UTF8; ${cmd}\r`)
        } else {
          this.ptyProcess.write(`${cmd}\r`)
        }
        this.ptyProcess.write("exit\r")
      } catch (e) {
        console.log("caught error", e)
        this.ptyProcess.kill()
        // ptyProcess.write("exit\r")
      }
    })
  }
  progress(task, percent) {
    this.progressBar.update(percent/100);
    //if (percent >= 100) {
    //  setTimeout(() => {
    //    term("\n")
    //  }, 200)
    //}
  }
  startProgress(title) {
    this.progressBar = term.progressBar({
      width: 120,
      title,
      eta: true ,
      percent: true
    });
  }
}
module.exports = Dalai

I tried, still not working for me, windows 11. debug code I have pasted below

Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

Try the new cross-platform PowerShell https://aka.ms/pscore6:WINDOWSSystem32WindowsPowerShellv1.0powershell.exePS C:UsersGerridalaialpaca> > [System.Console]::OutputEncoding=[System.Console]::InputEncoding=[System.Text.Encoding]::UTF8; C:UsersGerridalaialpacauildReleasemain --seed 1 --threads 4 --n_predict 200 --model models/7B/ggml-model-q4_0.bin --top_k 40 --top_p 0.9 --temp 0.8 --repeat_last_n 64 --repeat_penalty 1.1 -p "Below is an instruction that describes a task, paired with an input that provides further context. Write a response that appropriately completes the request.

### Instruction:
>PROMPT

### Response:
"[System.Console]::OutputEncoding=[System.Console]::InputEncoding=[System.Text.Encoding]::UTF8; C:UsersGerridalaialpacauildReleasemain --seed 1 --threads 4 --n_predict 200 --model models/7B/ggml-model-q4_0.bin --top_k 40 --top_p 0.9 --temp 0.8 --repeat_last_n 64 --repeat_penalty 1.1 -p "Below is an instruction that describes a task, paired with an input that provides further context. Write a response that appropriately completes the request.

### Instruction:
>PROMPT

### Response:
"
C:UsersGerridalaialpacauildReleasemain : The term 'C:UsersGerridalaialpacauildReleasemain' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:96X
+ ... coding]::UTF8; C:UsersGerridalaialpacauildReleasemain --seed  ...X
+                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~X
    + CategoryInfo          : ObjectNotFound: (C:UsersGerri...ldReleasemain:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundExceptionX
 X
PS C:UsersGerridalaialpaca> exitX

Btw I have been trying to get it to work on Arch linux on my SD. keep getting error messages saying I need root to install node.js but I already have root