* feat: model hub revamp UI * chore: model description - consistent markdown css * chore: add model versions dropdown * chore: integrate APIs - model sources * chore: update model display name * chore: lint fix * chore: page transition animation * feat: model search dropdown - deeplink * chore: bump cortex version * chore: add remote model sources * chore: model download state * chore: fix model metadata label * chore: polish model detail page markdown * test: fix test cases * chore: initialize default Hub model sources * chore: fix model stats * chore: clean up click outside and inside hooks * feat: change hub banner * chore: lint fix * chore: fix css long model id
243 lines
5.3 KiB
TypeScript
243 lines
5.3 KiB
TypeScript
import PQueue from 'p-queue'
|
|
import ky from 'ky'
|
|
import { extractModelLoadParams, Model, ModelSource } from '@janhq/core'
|
|
import { extractInferenceParams } from '@janhq/core'
|
|
/**
|
|
* cortex.cpp Model APIs interface
|
|
*/
|
|
interface ICortexAPI {
|
|
getModel(model: string): Promise<Model>
|
|
getModels(): Promise<Model[]>
|
|
pullModel(model: string, id?: string, name?: string): Promise<void>
|
|
importModel(
|
|
path: string,
|
|
modelPath: string,
|
|
name?: string,
|
|
option?: string
|
|
): Promise<void>
|
|
deleteModel(model: string): Promise<void>
|
|
updateModel(model: object): Promise<void>
|
|
cancelModelPull(model: string): Promise<void>
|
|
configs(body: { [key: string]: any }): Promise<void>
|
|
getSources(): Promise<ModelSource[]>
|
|
addSource(source: string): Promise<void>
|
|
deleteSource(source: string): Promise<void>
|
|
}
|
|
|
|
type Data = {
|
|
data: any[]
|
|
}
|
|
|
|
export class CortexAPI implements ICortexAPI {
|
|
queue = new PQueue({ concurrency: 1 })
|
|
|
|
constructor() {
|
|
this.queue.add(() => this.healthz())
|
|
}
|
|
|
|
/**
|
|
* Fetches a model detail from cortex.cpp
|
|
* @param model
|
|
* @returns
|
|
*/
|
|
getModel(model: string): Promise<any> {
|
|
return this.queue.add(() =>
|
|
ky
|
|
.get(`${API_URL}/v1/models/${model}`)
|
|
.json()
|
|
.then((e) => this.transformModel(e))
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Fetches models list from cortex.cpp
|
|
* @param model
|
|
* @returns
|
|
*/
|
|
getModels(): Promise<Model[]> {
|
|
return this.queue
|
|
.add(() => ky.get(`${API_URL}/v1/models?limit=-1`).json<Data>())
|
|
.then((e) =>
|
|
typeof e === 'object' ? e.data.map((e) => this.transformModel(e)) : []
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Pulls a model from HuggingFace via cortex.cpp
|
|
* @param model
|
|
* @returns
|
|
*/
|
|
pullModel(model: string, id?: string, name?: string): Promise<void> {
|
|
return this.queue.add(() =>
|
|
ky
|
|
.post(`${API_URL}/v1/models/pull`, { json: { model, id, name } })
|
|
.json()
|
|
.catch(async (e) => {
|
|
throw (await e.response?.json()) ?? e
|
|
})
|
|
.then()
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Imports a model from a local path via cortex.cpp
|
|
* @param model
|
|
* @returns
|
|
*/
|
|
importModel(
|
|
model: string,
|
|
modelPath: string,
|
|
name?: string,
|
|
option?: string
|
|
): Promise<void> {
|
|
return this.queue.add(() =>
|
|
ky
|
|
.post(`${API_URL}/v1/models/import`, {
|
|
json: { model, modelPath, name, option },
|
|
})
|
|
.json()
|
|
.catch((e) => console.debug(e)) // Ignore error
|
|
.then()
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Deletes a model from cortex.cpp
|
|
* @param model
|
|
* @returns
|
|
*/
|
|
deleteModel(model: string): Promise<void> {
|
|
return this.queue.add(() =>
|
|
ky.delete(`${API_URL}/v1/models/${model}`).json().then()
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Update a model in cortex.cpp
|
|
* @param model
|
|
* @returns
|
|
*/
|
|
updateModel(model: Partial<Model>): Promise<void> {
|
|
return this.queue.add(() =>
|
|
ky
|
|
.patch(`${API_URL}/v1/models/${model.id}`, { json: { ...model } })
|
|
.json()
|
|
.then()
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Cancel model pull in cortex.cpp
|
|
* @param model
|
|
* @returns
|
|
*/
|
|
cancelModelPull(model: string): Promise<void> {
|
|
return this.queue.add(() =>
|
|
ky
|
|
.delete(`${API_URL}/v1/models/pull`, { json: { taskId: model } })
|
|
.json()
|
|
.then()
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Check model status
|
|
* @param model
|
|
*/
|
|
async getModelStatus(model: string): Promise<boolean> {
|
|
return this.queue
|
|
.add(() => ky.get(`${API_URL}/v1/models/status/${model}`))
|
|
.then((e) => true)
|
|
.catch(() => false)
|
|
}
|
|
|
|
// BEGIN - Model Sources
|
|
/**
|
|
* Get model sources
|
|
* @param model
|
|
*/
|
|
async getSources(): Promise<ModelSource[]> {
|
|
return this.queue
|
|
.add(() => ky.get(`${API_URL}/v1/models/sources`).json<Data>())
|
|
.then((e) => (typeof e === 'object' ? (e.data as ModelSource[]) : []))
|
|
.catch(() => [])
|
|
}
|
|
|
|
/**
|
|
* Add a model source
|
|
* @param model
|
|
*/
|
|
async addSource(source: string): Promise<any> {
|
|
return this.queue.add(() =>
|
|
ky.post(`${API_URL}/v1/models/sources`, {
|
|
json: {
|
|
source,
|
|
},
|
|
})
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Delete a model source
|
|
* @param model
|
|
*/
|
|
async deleteSource(source: string): Promise<any> {
|
|
return this.queue.add(() =>
|
|
ky.delete(`${API_URL}/v1/models/sources`, {
|
|
json: {
|
|
source,
|
|
},
|
|
})
|
|
)
|
|
}
|
|
// END - Model Sources
|
|
|
|
/**
|
|
* Do health check on cortex.cpp
|
|
* @returns
|
|
*/
|
|
healthz(): Promise<void> {
|
|
return ky
|
|
.get(`${API_URL}/healthz`, {
|
|
retry: {
|
|
limit: 20,
|
|
delay: () => 500,
|
|
methods: ['get'],
|
|
},
|
|
})
|
|
.then(() => {})
|
|
}
|
|
|
|
/**
|
|
* Configure model pull options
|
|
* @param body
|
|
*/
|
|
configs(body: { [key: string]: any }): Promise<void> {
|
|
return this.queue.add(() =>
|
|
ky.patch(`${API_URL}/v1/configs`, { json: body }).then(() => {})
|
|
)
|
|
}
|
|
|
|
/**
|
|
* TRansform model to the expected format (e.g. parameters, settings, metadata)
|
|
* @param model
|
|
* @returns
|
|
*/
|
|
private transformModel(model: any) {
|
|
model.parameters = {
|
|
...extractInferenceParams(model),
|
|
...model.parameters,
|
|
...model.inference_params,
|
|
}
|
|
model.settings = {
|
|
...extractModelLoadParams(model),
|
|
...model.settings,
|
|
}
|
|
model.metadata = model.metadata ?? {
|
|
tags: [],
|
|
size: model.size ?? model.metadata?.size ?? 0,
|
|
}
|
|
return model as Model
|
|
}
|
|
}
|