parent
2b3ef31d8d
commit
1e28611c0a
@ -0,0 +1,166 @@ |
||||
import path from 'path'; |
||||
import fs from 'fs'; |
||||
import axios from "axios"; |
||||
import { EventEmitter } from 'events'; |
||||
import { LlamaModel, LlamaContext, LlamaChatSession, LlamaModelOptions } from "node-llama-cpp"; |
||||
|
||||
class LLamaBackend { |
||||
static instance: any |
||||
static model: any |
||||
static modelPath: string |
||||
|
||||
static async getInstance() { |
||||
if (this.instance === null || this.instance === undefined) { |
||||
const LlamaApi = Function('return import("node-llama-cpp")')(); |
||||
const { LlamaModel, LlamaContext, LlamaChatSession, LlamaModelOptions } = await LlamaApi; |
||||
|
||||
const getModelOptions = () => { |
||||
|
||||
const options = { |
||||
modelPath: this.modelPath? this.modelPath: null, |
||||
threads: 1, |
||||
temperature: 0.6, |
||||
topK: 40, |
||||
topP: 0.92, |
||||
logitsAll: false, |
||||
vocabOnly: false, |
||||
useMmap: false, |
||||
useMlock: false, |
||||
embedding: false, |
||||
}; |
||||
return options; |
||||
} |
||||
console.log('loading model with options', getModelOptions()) |
||||
const m = new LlamaModel(getModelOptions()); |
||||
|
||||
console.log("system infos\n", LlamaModel.systemInfo) |
||||
console.log("model infos\n", m.modelInfo) |
||||
const context = new LlamaContext({model: m}); |
||||
const session = new LlamaChatSession({context}); |
||||
this.instance = session |
||||
return this.instance |
||||
} |
||||
return this.instance |
||||
} |
||||
|
||||
} |
||||
|
||||
export class LLamaInferencer { |
||||
plugin: any |
||||
isReady: boolean = false |
||||
selectedModel: any |
||||
modelPath: string |
||||
event: EventEmitter |
||||
inferencer: any |
||||
|
||||
constructor(props, model) { |
||||
this.plugin = props |
||||
this.selectedModel = model |
||||
this.event = new EventEmitter() |
||||
} |
||||
|
||||
async init(envPath?: string) { |
||||
try { |
||||
await this._downloadModel(this.selectedModel) |
||||
|
||||
if (this.modelPath === undefined) { |
||||
console.log('Model not downloaded or not found') |
||||
return |
||||
} |
||||
|
||||
console.log('Model downloaded at', this.modelPath) |
||||
|
||||
LLamaBackend.model = this.selectedModel |
||||
LLamaBackend.modelPath = this.modelPath |
||||
this.inferencer = await LLamaBackend.getInstance() |
||||
this.inferencer.init() |
||||
this.isReady = this.inferencer.initialized |
||||
} catch (error) { |
||||
console.log('Error initializing the model', error) |
||||
} |
||||
} |
||||
|
||||
async _downloadModel(model): Promise<void> { |
||||
console.log('Downloading the model model', model) |
||||
console.log('Downloading model', model.downloadUrl)
|
||||
|
||||
const wdir = await this.plugin.call('fs' as any, 'getWorkingDir'); |
||||
console.log('working dir is', wdir) |
||||
const outputLocationDir = await this.plugin.call('fs' as any, 'selectFolder', wdir); |
||||
console.log('output location dir is', outputLocationDir) |
||||
|
||||
if (outputLocationDir === undefined) { |
||||
console.log('No output location selected'); |
||||
return; |
||||
} |
||||
|
||||
const outputLocationPath = path.join(outputLocationDir, model.modelName); |
||||
console.log('output location path is', outputLocationDir) |
||||
if (fs.existsSync(outputLocationPath)) {
|
||||
this.modelPath = outputLocationPath |
||||
console.log('Model already exists in the output location', outputLocationPath); |
||||
return; |
||||
} |
||||
|
||||
// Make a HEAD request to get the file size
|
||||
const { headers } = await axios.head(model.downloadUrl); |
||||
const totalSize = parseInt(headers['content-length'], 10); |
||||
|
||||
// Create a write stream to save the file
|
||||
const writer = fs.createWriteStream(outputLocationPath); |
||||
|
||||
// Start the file download
|
||||
const response = await axios({ |
||||
method: 'get', |
||||
url: model.downloadUrl, |
||||
responseType: 'stream' |
||||
}); |
||||
|
||||
let downloadedSize = 0; |
||||
|
||||
response.data.on('data', (chunk: Buffer) => { |
||||
downloadedSize += chunk.length; |
||||
const progress = (Number((downloadedSize / totalSize) * 100).toFixed(2)); |
||||
console.log(`Downloaded ${progress}%`); |
||||
this.event.emit('download', progress); |
||||
}); |
||||
|
||||
response.data.pipe(writer); |
||||
|
||||
this.event.emit('ready') |
||||
this.modelPath = outputLocationPath |
||||
console.log('LLama Download complete'); |
||||
|
||||
return new Promise((resolve, reject) => { |
||||
writer.on('finish', resolve); |
||||
writer.on('error', reject); |
||||
}); |
||||
} |
||||
|
||||
async code_completion(context: any, params): Promise<any> { |
||||
if (!this.isReady) { |
||||
console.log('model not ready yet') |
||||
return |
||||
} |
||||
|
||||
// as of now no prompt required
|
||||
this.event.emit('onInference') |
||||
const result = this.inferencer.promptWithMeta(context) |
||||
this.event.emit('onInferenceDone') |
||||
return result |
||||
} |
||||
|
||||
async code_insertion(msg_pfx: string, msg_sfx: string, params): Promise<any> { |
||||
if (!this.isReady) { |
||||
console.log('model not ready yet') |
||||
return |
||||
} |
||||
|
||||
this.event.emit('onInference') |
||||
// const prompt = getInsertionPrompt(InlineCompletionTransformer.model, msg_pfx, msg_sfx)
|
||||
// const instance = await InlineCompletionTransformer.getInstance()
|
||||
// const result = instance(prompt, insertionParams)
|
||||
// this.event.emit('onInferenceDone')
|
||||
// return result
|
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue