Louis d85d02693b
feat: Nitro-Tensorrt-LLM Extension (#2280)
* feat: tensorrt-llm-extension

* fix: loading

* feat: add download tensorrt llm runner

Signed-off-by: James <james@jan.ai>

* feat: update to rollupjs instead of webpack for monitoring extension

Signed-off-by: James <james@jan.ai>

* feat: move update nvidia info to monitor extension

Signed-off-by: James <james@jan.ai>

* allow download tensorrt

Signed-off-by: James <james@jan.ai>

* update

Signed-off-by: James <james@jan.ai>

* allow download tensor rt based on gpu setting

Signed-off-by: James <james@jan.ai>

* update downloaded models

Signed-off-by: James <james@jan.ai>

* feat: add extension compatibility

* dynamic tensor rt engines

Signed-off-by: James <james@jan.ai>

* update models

Signed-off-by: James <james@jan.ai>

* chore: remove ts-ignore

* feat: getting installation state from extension

Signed-off-by: James <james@jan.ai>

* chore: adding type for decompress

Signed-off-by: James <james@jan.ai>

* feat: update according Louis's comment

Signed-off-by: James <james@jan.ai>

* feat: add progress for installing extension

Signed-off-by: James <james@jan.ai>

* chore: remove args from extension installation

* fix: model download does not work properly

* fix: do not allow user to stop tensorrtllm inference

* fix: extension installed style

* fix: download tensorrt does not update state

Signed-off-by: James <james@jan.ai>

* chore: replace int4 by fl16

* feat: modal for installing extension

Signed-off-by: James <james@jan.ai>

* fix: start download immediately after press install

Signed-off-by: James <james@jan.ai>

* fix: error switching between engines

* feat: rename inference provider to ai engine and refactor to core

* fix: missing ulid

* fix: core bundler

* feat: add cancel extension installing

Signed-off-by: James <james@jan.ai>

* remove mocking for mac

Signed-off-by: James <james@jan.ai>

* fix: show models only when extension is ready

* add tensorrt badge for model

Signed-off-by: James <james@jan.ai>

* fix: copy

* fix: add compatible check (#2342)

* fix: add compatible check

Signed-off-by: James <james@jan.ai>

* fix: copy

* fix: font

* fix: copy

* fix: broken monitoring extension

* chore: bump engine

* fix: copy

* fix: model copy

* fix: copy

* fix: model json

---------

Signed-off-by: James <james@jan.ai>
Co-authored-by: James <james@jan.ai>
Co-authored-by: Louis <louis@jan.ai>

* fix: vulkan support

* fix: installation button padding

* fix: empty script

* fix: remove hard code string

---------

Signed-off-by: James <james@jan.ai>
Co-authored-by: James <james@jan.ai>
Co-authored-by: NamH <NamNh0122@gmail.com>
2024-03-14 14:07:22 +07:00

145 lines
5.3 KiB
TypeScript

/* eslint-disable @typescript-eslint/no-explicit-any */
import React, { useState, useEffect, useRef } from 'react'
import { Button, ScrollArea } from '@janhq/uikit'
import Loader from '@/containers/Loader'
import { formatExtensionsName } from '@/utils/converter'
import TensorRtExtensionItem from './TensorRtExtensionItem'
import { extensionManager } from '@/extension'
import Extension from '@/extension/Extension'
const ExtensionCatalog = () => {
const [activeExtensions, setActiveExtensions] = useState<Extension[]>([])
const [showLoading, setShowLoading] = useState(false)
const fileInputRef = useRef<HTMLInputElement | null>(null)
/**
* Fetches the active extensions and their preferences from the `extensions` and `preferences` modules.
* If the `experimentComponent` extension point is available, it executes the extension point and
* appends the returned components to the `experimentRef` element.
* If the `ExtensionPreferences` extension point is available, it executes the extension point and
* fetches the preferences for each extension using the `preferences.get` function.
*/
useEffect(() => {
const getActiveExtensions = async () => {
const exts = await extensionManager.getActive()
if (Array.isArray(exts)) setActiveExtensions(exts)
}
getActiveExtensions()
}, [])
/**
* Installs a extension by calling the `extensions.install` function with the extension file path.
* If the installation is successful, the application is relaunched using the `coreAPI.relaunch` function.
* @param e - The event object.
*/
const install = async (e: any) => {
e.preventDefault()
const extensionFile = e.target.files?.[0].path
// Send the filename of the to be installed extension
// to the main process for installation
const installed = await extensionManager.install([extensionFile])
if (installed) window.core?.api?.relaunch()
}
/**
* Uninstalls a extension by calling the `extensions.uninstall` function with the extension name.
* If the uninstallation is successful, the application is relaunched using the `coreAPI.relaunch` function.
* @param name - The name of the extension to uninstall.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const uninstall = async (name: string) => {
// Send the filename of the to be uninstalled extension
// to the main process for removal
const res = await extensionManager.uninstall([name])
if (res) window.core?.api?.relaunch()
}
/**
* Handles the change event of the extension file input element by setting the file name state.
* Its to be used to display the extension file name of the selected file.
* @param event - The change event object.
*/
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0]
if (file) {
setShowLoading(true)
install(event)
}
}
return (
<>
<ScrollArea className="h-full w-full px-4">
<div className="block w-full">
{activeExtensions.map((item, i) => {
// TODO: this is bad code, rewrite it
if (item.name === '@janhq/tensorrt-llm-extension') {
return <TensorRtExtensionItem key={i} item={item} />
}
return (
<div
key={i}
className="flex w-full items-start justify-between border-b border-border py-4 first:pt-4 last:border-none"
>
<div className="w-4/5 flex-shrink-0 space-y-1.5">
<div className="flex items-center gap-x-2">
<h6 className="text-sm font-semibold capitalize">
{formatExtensionsName(
item.name ?? item.description ?? ''
)}
</h6>
<p className="whitespace-pre-wrap text-sm font-semibold leading-relaxed ">
v{item.version}
</p>
</div>
<p className="whitespace-pre-wrap leading-relaxed ">
{item.description}
</p>
</div>
</div>
)
})}
{/* Manual Installation */}
<div className="flex w-full items-start justify-between border-b border-border py-4 first:pt-0 last:border-none">
<div className="w-4/5 flex-shrink-0 space-y-1.5">
<div className="flex gap-x-2">
<h6 className="text-sm font-semibold capitalize">
Manual Installation
</h6>
</div>
<p className="whitespace-pre-wrap leading-relaxed ">
Select a extension file to install (.tgz)
</p>
</div>
<div>
<input
type="file"
style={{ display: 'none' }}
ref={fileInputRef}
onChange={handleFileChange}
/>
<Button
themes="secondaryBlue"
size="sm"
onClick={() => fileInputRef.current?.click()}
>
Select
</Button>
</div>
</div>
</div>
</ScrollArea>
{showLoading && <Loader description="Installing..." />}
</>
)
}
export default ExtensionCatalog