* 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>
145 lines
5.3 KiB
TypeScript
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
|