update
Signed-off-by: James <james@jan.ai>
This commit is contained in:
parent
d982dce090
commit
773bbaf4cc
@ -116,22 +116,10 @@ function storeModel(params: any) {
|
|||||||
model.nsfw,
|
model.nsfw,
|
||||||
modelTags,
|
modelTags,
|
||||||
model.greeting,
|
model.greeting,
|
||||||
model.type,
|
model.type
|
||||||
function (err: any) {
|
|
||||||
if (err) {
|
|
||||||
// Handle the insertion error here
|
|
||||||
console.error(err.message);
|
|
||||||
res(undefined);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// @ts-ignoreF
|
|
||||||
const id = this.lastID;
|
|
||||||
res(id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
stmt.finalize();
|
||||||
|
|
||||||
// insert modelVersion to MODEL_VERSION_TABLE_INSERTION
|
|
||||||
const stmt2 = db.prepare(MODEL_VERSION_TABLE_INSERTION);
|
const stmt2 = db.prepare(MODEL_VERSION_TABLE_INSERTION);
|
||||||
stmt2.run(
|
stmt2.run(
|
||||||
modelVersion.id,
|
modelVersion.id,
|
||||||
@ -143,25 +131,14 @@ function storeModel(params: any) {
|
|||||||
modelVersion.usecase,
|
modelVersion.usecase,
|
||||||
modelVersion.downloadLink,
|
modelVersion.downloadLink,
|
||||||
model.id,
|
model.id,
|
||||||
modelVersion.startDownloadAt,
|
modelVersion.startDownloadAt
|
||||||
function (err: any) {
|
|
||||||
if (err) {
|
|
||||||
// Handle the insertion error here
|
|
||||||
console.error(err.message);
|
|
||||||
res(undefined);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// @ts-ignoreF
|
|
||||||
const id = this.lastID;
|
|
||||||
res(id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
stmt.finalize();
|
|
||||||
stmt2.finalize();
|
stmt2.finalize();
|
||||||
});
|
});
|
||||||
|
|
||||||
db.close();
|
db.close();
|
||||||
|
res(undefined);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +148,7 @@ function storeModel(params: any) {
|
|||||||
* @param model Product
|
* @param model Product
|
||||||
*/
|
*/
|
||||||
function updateFinishedDownloadAt(modelVersionId: string) {
|
function updateFinishedDownloadAt(modelVersionId: string) {
|
||||||
return new Promise((res) => {
|
return new Promise((res, rej) => {
|
||||||
const db = new sqlite3.Database(getDbPath());
|
const db = new sqlite3.Database(getDbPath());
|
||||||
const time = Date.now();
|
const time = Date.now();
|
||||||
console.debug(
|
console.debug(
|
||||||
@ -181,7 +158,7 @@ function updateFinishedDownloadAt(modelVersionId: string) {
|
|||||||
db.run(stmt, [time, modelVersionId], (err: any) => {
|
db.run(stmt, [time, modelVersionId], (err: any) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
res(undefined);
|
rej(err);
|
||||||
} else {
|
} else {
|
||||||
console.log("Updated 1 row");
|
console.log("Updated 1 row");
|
||||||
res("Updated");
|
res("Updated");
|
||||||
@ -299,7 +276,7 @@ function deleteDownloadModel(modelId: string) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchModelVersion(db: any, versionId: string) {
|
function fetchModelVersion(db: any, versionId: string) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
db.get(
|
db.get(
|
||||||
"SELECT * FROM model_versions WHERE id = ?",
|
"SELECT * FROM model_versions WHERE id = ?",
|
||||||
@ -308,32 +285,7 @@ async function fetchModelVersion(db: any, versionId: string) {
|
|||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
} else {
|
} else {
|
||||||
if (row) {
|
resolve(row);
|
||||||
const product = {
|
|
||||||
id: row.id,
|
|
||||||
slug: row.slug,
|
|
||||||
name: row.name,
|
|
||||||
description: row.description,
|
|
||||||
avatarUrl: row.avatar_url,
|
|
||||||
longDescription: row.long_description,
|
|
||||||
technicalDescription: row.technical_description,
|
|
||||||
author: row.author,
|
|
||||||
version: row.version,
|
|
||||||
modelUrl: row.model_url,
|
|
||||||
nsfw: row.nsfw,
|
|
||||||
greeting: row.greeting,
|
|
||||||
type: row.type,
|
|
||||||
inputs: row.inputs,
|
|
||||||
outputs: row.outputs,
|
|
||||||
createdAt: new Date(row.created_at),
|
|
||||||
updatedAt: new Date(row.updated_at),
|
|
||||||
fileName: row.file_name,
|
|
||||||
downloadUrl: row.download_url,
|
|
||||||
};
|
|
||||||
resolve(product);
|
|
||||||
} else {
|
|
||||||
resolve(undefined);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "data-plugin",
|
"name": "data-plugin",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"description": "Jan Database Plugin efficiently stores conversation and model data using SQLite, providing accessible data management",
|
"description": "Jan Database Plugin efficiently stores conversation and model data using SQLite, providing accessible data management",
|
||||||
"icon": "https://raw.githubusercontent.com/tailwindlabs/heroicons/88e98b0c2b458553fbadccddc2d2f878edc0387b/src/20/solid/circle-stack.svg",
|
"icon": "https://raw.githubusercontent.com/tailwindlabs/heroicons/88e98b0c2b458553fbadccddc2d2f878edc0387b/src/20/solid/circle-stack.svg",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
const MODULE_PATH = "model-management-plugin/dist/module.js";
|
const MODULE_PATH = "model-management-plugin/dist/module.js";
|
||||||
|
|
||||||
const getDownloadedModels = async () =>
|
const getDownloadedModels = () =>
|
||||||
new Promise(async (resolve) => {
|
new Promise(async (resolve) => {
|
||||||
if (window.electronAPI) {
|
if (window.electronAPI) {
|
||||||
window.electronAPI
|
window.electronAPI
|
||||||
@ -9,7 +9,7 @@ const getDownloadedModels = async () =>
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const getAvailableModels = async () =>
|
const getAvailableModels = () =>
|
||||||
new Promise(async (resolve) => {
|
new Promise(async (resolve) => {
|
||||||
if (window.electronAPI) {
|
if (window.electronAPI) {
|
||||||
window.electronAPI
|
window.electronAPI
|
||||||
@ -18,7 +18,7 @@ const getAvailableModels = async () =>
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const downloadModel = async (product) =>
|
const downloadModel = (product) =>
|
||||||
new Promise(async (resolve) => {
|
new Promise(async (resolve) => {
|
||||||
if (window && window.electronAPI) {
|
if (window && window.electronAPI) {
|
||||||
window.electronAPI
|
window.electronAPI
|
||||||
@ -29,7 +29,7 @@ const downloadModel = async (product) =>
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const deleteModel = async (path) =>
|
const deleteModel = (path) =>
|
||||||
new Promise(async (resolve) => {
|
new Promise(async (resolve) => {
|
||||||
if (window.electronAPI) {
|
if (window.electronAPI) {
|
||||||
console.debug(`Delete model model management plugin: ${path}`);
|
console.debug(`Delete model model management plugin: ${path}`);
|
||||||
@ -38,7 +38,7 @@ const deleteModel = async (path) =>
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const searchModels = async (params) =>
|
const searchModels = (params) =>
|
||||||
new Promise(async (resolve) => {
|
new Promise(async (resolve) => {
|
||||||
if (window.electronAPI) {
|
if (window.electronAPI) {
|
||||||
window.electronAPI
|
window.electronAPI
|
||||||
@ -47,7 +47,7 @@ const searchModels = async (params) =>
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const getConfiguredModels = async () =>
|
const getConfiguredModels = () =>
|
||||||
new Promise(async (resolve) => {
|
new Promise(async (resolve) => {
|
||||||
if (window.electronAPI) {
|
if (window.electronAPI) {
|
||||||
window.electronAPI
|
window.electronAPI
|
||||||
|
|||||||
@ -6,10 +6,10 @@ import ExploreModelFilter from "../ExploreModelFilter";
|
|||||||
const ExploreModelContainer: React.FC = () => (
|
const ExploreModelContainer: React.FC = () => (
|
||||||
<div className="flex flex-col flex-1 px-16 pt-14 overflow-hidden">
|
<div className="flex flex-col flex-1 px-16 pt-14 overflow-hidden">
|
||||||
<HeaderTitle title="Explore Models" />
|
<HeaderTitle title="Explore Models" />
|
||||||
<SearchBar
|
{/* <SearchBar
|
||||||
type={SearchType.Model}
|
type={SearchType.Model}
|
||||||
placeholder="Owner name like TheBloke, bhlim etc.."
|
placeholder="Owner name like TheBloke, bhlim etc.."
|
||||||
/>
|
/> */}
|
||||||
<div className="flex flex-1 gap-x-10 mt-9 overflow-hidden">
|
<div className="flex flex-1 gap-x-10 mt-9 overflow-hidden">
|
||||||
<ExploreModelFilter />
|
<ExploreModelFilter />
|
||||||
<ExploreModelList />
|
<ExploreModelList />
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import SearchBar from "../SearchBar";
|
import SearchBar from "../SearchBar";
|
||||||
import SimpleCheckbox from "../SimpleCheckbox";
|
import SimpleCheckbox from "../SimpleCheckbox";
|
||||||
import SimpleTag, { TagType } from "../SimpleTag";
|
import SimpleTag from "../SimpleTag";
|
||||||
|
import { TagType } from "../SimpleTag/TagType";
|
||||||
|
|
||||||
const tags = [
|
const tags = [
|
||||||
"Roleplay",
|
"Roleplay",
|
||||||
|
|||||||
@ -4,10 +4,11 @@
|
|||||||
|
|
||||||
import ExploreModelItemHeader from "../ExploreModelItemHeader";
|
import ExploreModelItemHeader from "../ExploreModelItemHeader";
|
||||||
import ModelVersionList from "../ModelVersionList";
|
import ModelVersionList from "../ModelVersionList";
|
||||||
import { Fragment, forwardRef, useState } from "react";
|
import { Fragment, forwardRef, useEffect, useState } from "react";
|
||||||
import SimpleTag, { TagType } from "../SimpleTag";
|
import SimpleTag from "../SimpleTag";
|
||||||
import { displayDate } from "@/_utils/datetime";
|
import { displayDate } from "@/_utils/datetime";
|
||||||
import { Product } from "@/_models/Product";
|
import { Product } from "@/_models/Product";
|
||||||
|
import useGetMostSuitableModelVersion from "@/_hooks/useGetMostSuitableModelVersion";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
model: Product;
|
model: Product;
|
||||||
@ -16,15 +17,26 @@ type Props = {
|
|||||||
const ExploreModelItem = forwardRef<HTMLDivElement, Props>(({ model }, ref) => {
|
const ExploreModelItem = forwardRef<HTMLDivElement, Props>(({ model }, ref) => {
|
||||||
const [show, setShow] = useState(false);
|
const [show, setShow] = useState(false);
|
||||||
|
|
||||||
|
const { availableVersions } = model;
|
||||||
|
const { suitableModel, getMostSuitableModelVersion } =
|
||||||
|
useGetMostSuitableModelVersion();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getMostSuitableModelVersion(availableVersions);
|
||||||
|
}, [availableVersions]);
|
||||||
|
|
||||||
|
if (!suitableModel) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className="flex flex-col border border-gray-200 rounded-md mb-4"
|
className="flex flex-col border border-gray-200 rounded-md mb-4"
|
||||||
>
|
>
|
||||||
<ExploreModelItemHeader
|
<ExploreModelItemHeader
|
||||||
name={model.name}
|
suitableModel={suitableModel}
|
||||||
status={TagType.Recommended}
|
exploreModel={model}
|
||||||
versions={model.availableVersions}
|
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-col px-[26px] py-[22px]">
|
<div className="flex flex-col px-[26px] py-[22px]">
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
@ -42,11 +54,11 @@ const ExploreModelItem = forwardRef<HTMLDivElement, Props>(({ model }, ref) => {
|
|||||||
Hardware Compatibility
|
Hardware Compatibility
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<SimpleTag
|
{/* <SimpleTag
|
||||||
clickable={false}
|
clickable={false}
|
||||||
title={TagType.Compatible}
|
title={TagType.Compatible}
|
||||||
type={TagType.Compatible}
|
type={TagType.Compatible}
|
||||||
/>
|
/> */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -63,11 +75,11 @@ const ExploreModelItem = forwardRef<HTMLDivElement, Props>(({ model }, ref) => {
|
|||||||
<div className="text-sm font-medium text-gray-500">
|
<div className="text-sm font-medium text-gray-500">
|
||||||
Expected Performance
|
Expected Performance
|
||||||
</div>
|
</div>
|
||||||
<SimpleTag
|
{/* <SimpleTag
|
||||||
title={TagType.Medium}
|
title={TagType.Medium}
|
||||||
type={TagType.Medium}
|
type={TagType.Medium}
|
||||||
clickable={false}
|
clickable={false}
|
||||||
/>
|
/> */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -77,8 +89,14 @@ const ExploreModelItem = forwardRef<HTMLDivElement, Props>(({ model }, ref) => {
|
|||||||
{model.longDescription}
|
{model.longDescription}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col mt-5">
|
||||||
<span className="text-sm font-medium text-gray-500">Tags</span>
|
<span className="text-sm font-medium text-gray-500">Tags</span>
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{model.tags.map((tag) => (
|
||||||
|
// @ts-ignore
|
||||||
|
<SimpleTag key={tag} title={tag} type={tag} clickable={false} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{model.availableVersions?.length > 0 && (
|
{model.availableVersions?.length > 0 && (
|
||||||
@ -87,6 +105,7 @@ const ExploreModelItem = forwardRef<HTMLDivElement, Props>(({ model }, ref) => {
|
|||||||
<ModelVersionList
|
<ModelVersionList
|
||||||
model={model}
|
model={model}
|
||||||
versions={model.availableVersions}
|
versions={model.availableVersions}
|
||||||
|
recommendedVersion={suitableModel?.id ?? ""}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
|
|||||||
@ -1,34 +1,74 @@
|
|||||||
import SimpleTag, { TagType } from "../SimpleTag";
|
import SimpleTag from "../SimpleTag";
|
||||||
import PrimaryButton from "../PrimaryButton";
|
import PrimaryButton from "../PrimaryButton";
|
||||||
import { formatDownloadPercentage, toGigabytes } from "@/_utils/converter";
|
import { formatDownloadPercentage, toGigabytes } from "@/_utils/converter";
|
||||||
import { DownloadState } from "@/_models/DownloadState";
|
|
||||||
import SecondaryButton from "../SecondaryButton";
|
import SecondaryButton from "../SecondaryButton";
|
||||||
|
import { Product } from "@/_models/Product";
|
||||||
|
import { useCallback, useEffect, useMemo } from "react";
|
||||||
import { ModelVersion } from "@/_models/ModelVersion";
|
import { ModelVersion } from "@/_models/ModelVersion";
|
||||||
|
import useGetPerformanceTag from "@/_hooks/useGetPerformanceTag";
|
||||||
|
import useDownloadModel from "@/_hooks/useDownloadModel";
|
||||||
|
import { useGetDownloadedModels } from "@/_hooks/useGetDownloadedModels";
|
||||||
|
import { modelDownloadStateAtom } from "@/_helpers/atoms/DownloadState.atom";
|
||||||
|
import { atom, useAtomValue, useSetAtom } from "jotai";
|
||||||
|
import {
|
||||||
|
MainViewState,
|
||||||
|
setMainViewStateAtom,
|
||||||
|
} from "@/_helpers/atoms/MainView.atom";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
name: string;
|
suitableModel: ModelVersion;
|
||||||
status: TagType;
|
exploreModel: Product;
|
||||||
versions: ModelVersion[];
|
|
||||||
size?: number;
|
|
||||||
downloadState?: DownloadState;
|
|
||||||
onDownloadClick?: () => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const ExploreModelItemHeader: React.FC<Props> = ({
|
const ExploreModelItemHeader: React.FC<Props> = ({
|
||||||
name,
|
suitableModel,
|
||||||
status,
|
exploreModel,
|
||||||
size,
|
|
||||||
versions,
|
|
||||||
downloadState,
|
|
||||||
onDownloadClick,
|
|
||||||
}) => {
|
}) => {
|
||||||
|
const { downloadModel } = useDownloadModel();
|
||||||
|
const { downloadedModels } = useGetDownloadedModels();
|
||||||
|
const { performanceTag, title, getPerformanceForModel } =
|
||||||
|
useGetPerformanceTag();
|
||||||
|
const downloadAtom = useMemo(
|
||||||
|
() => atom((get) => get(modelDownloadStateAtom)[suitableModel.id]),
|
||||||
|
[suitableModel.id]
|
||||||
|
);
|
||||||
|
const downloadState = useAtomValue(downloadAtom);
|
||||||
|
const setMainViewState = useSetAtom(setMainViewStateAtom);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getPerformanceForModel(suitableModel);
|
||||||
|
}, [suitableModel]);
|
||||||
|
|
||||||
|
const onDownloadClick = useCallback(() => {
|
||||||
|
downloadModel(exploreModel, suitableModel);
|
||||||
|
}, [exploreModel, suitableModel]);
|
||||||
|
|
||||||
|
const isDownloaded =
|
||||||
|
downloadedModels.find((model) => model.id === suitableModel.id) != null;
|
||||||
|
|
||||||
let downloadButton = (
|
let downloadButton = (
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
title={size ? `Download (${toGigabytes(size)})` : "Download"}
|
title={
|
||||||
onClick={() => onDownloadClick?.()}
|
suitableModel.size
|
||||||
|
? `Download (${toGigabytes(suitableModel.size)})`
|
||||||
|
: "Download"
|
||||||
|
}
|
||||||
|
onClick={() => onDownloadClick()}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (isDownloaded) {
|
||||||
|
downloadButton = (
|
||||||
|
<PrimaryButton
|
||||||
|
title="View Downloaded Model"
|
||||||
|
onClick={() => {
|
||||||
|
setMainViewState(MainViewState.MyModel);
|
||||||
|
}}
|
||||||
|
className="bg-green-500 hover:bg-green-400"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (downloadState != null) {
|
if (downloadState != null) {
|
||||||
// downloading
|
// downloading
|
||||||
downloadButton = (
|
downloadButton = (
|
||||||
@ -39,15 +79,15 @@ const ExploreModelItemHeader: React.FC<Props> = ({
|
|||||||
)})`}
|
)})`}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else if (versions.length === 0) {
|
|
||||||
downloadButton = <SecondaryButton disabled title="No files available" />;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-between p-4 border-b border-gray-200">
|
<div className="flex items-center justify-between p-4 border-b border-gray-200">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span>{name}</span>
|
<span>{exploreModel.name}</span>
|
||||||
<SimpleTag title={status} type={status} clickable={false} />
|
{performanceTag && (
|
||||||
|
<SimpleTag title={title} type={performanceTag} clickable={false} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{downloadButton}
|
{downloadButton}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -6,14 +6,26 @@ import useDownloadModel from "@/_hooks/useDownloadModel";
|
|||||||
import { modelDownloadStateAtom } from "@/_helpers/atoms/DownloadState.atom";
|
import { modelDownloadStateAtom } from "@/_helpers/atoms/DownloadState.atom";
|
||||||
import { atom, useAtomValue } from "jotai";
|
import { atom, useAtomValue } from "jotai";
|
||||||
import { ModelVersion } from "@/_models/ModelVersion";
|
import { ModelVersion } from "@/_models/ModelVersion";
|
||||||
|
import { useGetDownloadedModels } from "@/_hooks/useGetDownloadedModels";
|
||||||
|
import SimpleTag from "../SimpleTag";
|
||||||
|
import { ModelPerformance } from "../SimpleTag/TagType";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
model: Product;
|
model: Product;
|
||||||
modelVersion: ModelVersion;
|
modelVersion: ModelVersion;
|
||||||
|
isRecommended: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ModelVersionItem: React.FC<Props> = ({ model, modelVersion }) => {
|
const ModelVersionItem: React.FC<Props> = ({
|
||||||
|
model,
|
||||||
|
modelVersion,
|
||||||
|
isRecommended,
|
||||||
|
}) => {
|
||||||
const { downloadModel } = useDownloadModel();
|
const { downloadModel } = useDownloadModel();
|
||||||
|
const { downloadedModels } = useGetDownloadedModels();
|
||||||
|
const isDownloaded =
|
||||||
|
downloadedModels.find((model) => model.id === modelVersion.id) != null;
|
||||||
|
|
||||||
const downloadAtom = useMemo(
|
const downloadAtom = useMemo(
|
||||||
() => atom((get) => get(modelDownloadStateAtom)[modelVersion.id ?? ""]),
|
() => atom((get) => get(modelDownloadStateAtom)[modelVersion.id ?? ""]),
|
||||||
[modelVersion.id ?? ""]
|
[modelVersion.id ?? ""]
|
||||||
@ -37,6 +49,8 @@ const ModelVersionItem: React.FC<Props> = ({ model, modelVersion }) => {
|
|||||||
downloadButton = (
|
downloadButton = (
|
||||||
<div>{formatDownloadPercentage(downloadState.percent)}</div>
|
<div>{formatDownloadPercentage(downloadState.percent)}</div>
|
||||||
);
|
);
|
||||||
|
} else if (isDownloaded) {
|
||||||
|
downloadButton = <div>Downloaded</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -46,6 +60,13 @@ const ModelVersionItem: React.FC<Props> = ({ model, modelVersion }) => {
|
|||||||
<span className="font-sm text-gray-900">{modelVersion.name}</span>
|
<span className="font-sm text-gray-900">{modelVersion.name}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
|
{isRecommended && (
|
||||||
|
<SimpleTag
|
||||||
|
title={"Recommended"}
|
||||||
|
type={ModelPerformance.PerformancePositive}
|
||||||
|
clickable={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<div className="px-2.5 py-0.5 bg-gray-200 text-xs font-medium rounded">
|
<div className="px-2.5 py-0.5 bg-gray-200 text-xs font-medium rounded">
|
||||||
{toGigabytes(modelVersion.size)}
|
{toGigabytes(modelVersion.size)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -6,17 +6,31 @@ import { ModelVersion } from "@/_models/ModelVersion";
|
|||||||
type Props = {
|
type Props = {
|
||||||
model: Product;
|
model: Product;
|
||||||
versions: ModelVersion[];
|
versions: ModelVersion[];
|
||||||
|
recommendedVersion: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ModelVersionList: React.FC<Props> = ({ model, versions }) => (
|
const ModelVersionList: React.FC<Props> = ({
|
||||||
|
model,
|
||||||
|
versions,
|
||||||
|
recommendedVersion,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
<div className="px-4 py-5 border-t border-gray-200">
|
<div className="px-4 py-5 border-t border-gray-200">
|
||||||
<div className="text-sm font-medium text-gray-500">Available Versions</div>
|
<div className="text-sm font-medium text-gray-500">
|
||||||
|
Available Versions
|
||||||
|
</div>
|
||||||
<div className="border border-gray-200 rounded-lg overflow-hidden">
|
<div className="border border-gray-200 rounded-lg overflow-hidden">
|
||||||
{versions.map((item) => (
|
{versions.map((item) => (
|
||||||
<ModelVersionItem key={item.id} model={model} modelVersion={item} />
|
<ModelVersionItem
|
||||||
|
key={item.id}
|
||||||
|
model={model}
|
||||||
|
modelVersion={item}
|
||||||
|
isRecommended={item.id === recommendedVersion}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default ModelVersionList;
|
export default ModelVersionList;
|
||||||
|
|||||||
16
web/app/_components/SimpleTag/TagStyleMapper.ts
Normal file
16
web/app/_components/SimpleTag/TagStyleMapper.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { TagType } from "./TagType";
|
||||||
|
|
||||||
|
export const tagStyleMapper: Record<TagType, string> = {
|
||||||
|
GGUF: "bg-yellow-100 text-yellow-800",
|
||||||
|
PerformancePositive:
|
||||||
|
"text-green-700 ring-1 ring-inset ring-green-600/20 bg-green-50",
|
||||||
|
PerformanceNeutral:
|
||||||
|
"bg-yellow-50 text-yellow-800 ring-1 ring-inset ring-yellow-600/20",
|
||||||
|
PerformanceNegative:
|
||||||
|
"bg-red-50 ext-red-700 ring-1 ring-inset ring-red-600/10",
|
||||||
|
HardwareCompatible: "bg-red-50 ext-red-700 ring-1 ring-inset ring-red-600/10",
|
||||||
|
HardwareIncompatible:
|
||||||
|
"bg-red-50 ext-red-700 ring-1 ring-inset ring-red-600/10",
|
||||||
|
FreeStyle: "bg-gray-100 text-gray-800",
|
||||||
|
ExpectPerformanceMedium: "bg-yellow-100 text-yellow-800",
|
||||||
|
};
|
||||||
32
web/app/_components/SimpleTag/TagType.ts
Normal file
32
web/app/_components/SimpleTag/TagType.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
export enum ModelPerformance {
|
||||||
|
PerformancePositive = "PerformancePositive",
|
||||||
|
|
||||||
|
PerformanceNeutral = "PerformanceNeutral",
|
||||||
|
|
||||||
|
PerformanceNegative = "PerformanceNegative",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum HardwareCompatibility {
|
||||||
|
HardwareCompatible = "HardwareCompatible",
|
||||||
|
|
||||||
|
HardwareIncompatible = "HardwareIncompatible",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ExpectedPerformance {
|
||||||
|
ExpectPerformanceMedium = "ExpectPerformanceMedium",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ModelFormat {
|
||||||
|
GGUF = "GGUF",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum FreestyleTag {
|
||||||
|
FreeStyle = "FreeStyle",
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TagType =
|
||||||
|
| ModelPerformance
|
||||||
|
| HardwareCompatibility
|
||||||
|
| ExpectedPerformance
|
||||||
|
| ModelFormat
|
||||||
|
| FreestyleTag;
|
||||||
@ -1,57 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { TagType } from "./TagType";
|
||||||
export enum TagType {
|
import { tagStyleMapper } from "./TagStyleMapper";
|
||||||
Roleplay = "Roleplay",
|
|
||||||
Llama = "Llama",
|
|
||||||
Story = "Story",
|
|
||||||
Casual = "Casual",
|
|
||||||
Professional = "Professional",
|
|
||||||
CodeLlama = "CodeLlama",
|
|
||||||
Coding = "Coding",
|
|
||||||
|
|
||||||
// Positive
|
|
||||||
Recommended = "Recommended",
|
|
||||||
Compatible = "Compatible",
|
|
||||||
|
|
||||||
// Neutral
|
|
||||||
SlowOnDevice = "This model will be slow on your device",
|
|
||||||
|
|
||||||
// Negative
|
|
||||||
InsufficientRam = "Insufficient RAM",
|
|
||||||
Incompatible = "Incompatible with your device",
|
|
||||||
TooLarge = "This model is too large for your device",
|
|
||||||
|
|
||||||
// Performance
|
|
||||||
Medium = "Medium",
|
|
||||||
BalancedQuality = "Balanced Quality",
|
|
||||||
}
|
|
||||||
|
|
||||||
const tagStyleMapper: Record<TagType, string> = {
|
|
||||||
[TagType.Roleplay]: "bg-red-100 text-red-800",
|
|
||||||
[TagType.Llama]: "bg-green-100 text-green-800",
|
|
||||||
[TagType.Story]: "bg-blue-100 text-blue-800",
|
|
||||||
[TagType.Casual]: "bg-yellow-100 text-yellow-800",
|
|
||||||
[TagType.Professional]: "text-indigo-800 bg-indigo-100",
|
|
||||||
[TagType.CodeLlama]: "bg-pink-100 text-pink-800",
|
|
||||||
[TagType.Coding]: "text-purple-800 bg-purple-100",
|
|
||||||
|
|
||||||
[TagType.Recommended]:
|
|
||||||
"text-green-700 ring-1 ring-inset ring-green-600/20 bg-green-50",
|
|
||||||
[TagType.Compatible]:
|
|
||||||
"bg-red-50 ext-red-700 ring-1 ring-inset ring-red-600/10",
|
|
||||||
|
|
||||||
[TagType.SlowOnDevice]:
|
|
||||||
"bg-yellow-50 text-yellow-800 ring-1 ring-inset ring-yellow-600/20",
|
|
||||||
|
|
||||||
[TagType.Incompatible]:
|
|
||||||
"bg-red-50 ext-red-700 ring-1 ring-inset ring-red-600/10",
|
|
||||||
[TagType.InsufficientRam]:
|
|
||||||
"bg-red-50 ext-red-700 ring-1 ring-inset ring-red-600/10",
|
|
||||||
[TagType.TooLarge]: "bg-red-50 ext-red-700 ring-1 ring-inset ring-red-600/10",
|
|
||||||
|
|
||||||
[TagType.Medium]: "bg-yellow-100 text-yellow-800",
|
|
||||||
[TagType.BalancedQuality]: "bg-yellow-100 text-yellow-800",
|
|
||||||
};
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
title: string;
|
title: string;
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { searchModels } from "./useGetDownloadedModels";
|
|
||||||
import { SearchModelParamHf } from "@/_models/hf/SearchModelParam.hf";
|
import { SearchModelParamHf } from "@/_models/hf/SearchModelParam.hf";
|
||||||
import { Product } from "@/_models/Product";
|
import { Product } from "@/_models/Product";
|
||||||
import { useSetAtom } from "jotai";
|
import { useSetAtom } from "jotai";
|
||||||
@ -22,14 +21,14 @@ export default function useGetHuggingFaceModel() {
|
|||||||
search: { owner },
|
search: { owner },
|
||||||
limit: 5,
|
limit: 5,
|
||||||
};
|
};
|
||||||
const result = await searchModels(searchParams);
|
// const result = await searchModels(searchParams);
|
||||||
console.debug("result", JSON.stringify(result));
|
// console.debug("result", JSON.stringify(result));
|
||||||
if (owner !== currentOwner) {
|
// if (owner !== currentOwner) {
|
||||||
setModelList(result.data);
|
// setModelList(result.data);
|
||||||
setCurrentOwner(owner);
|
// setCurrentOwner(owner);
|
||||||
} else {
|
// } else {
|
||||||
setModelList([...modelList, ...result.data]);
|
// setModelList([...modelList, ...result.data]);
|
||||||
}
|
// }
|
||||||
setLoadMoreInProgress(false);
|
setLoadMoreInProgress(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
29
web/app/_hooks/useGetMostSuitableModelVersion.ts
Normal file
29
web/app/_hooks/useGetMostSuitableModelVersion.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { executeSerial } from "@/_services/pluginService";
|
||||||
|
import { SystemMonitoringService } from "../../shared/coreService";
|
||||||
|
import { ModelVersion } from "@/_models/ModelVersion";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export default function useGetMostSuitableModelVersion() {
|
||||||
|
const [suitableModel, setSuitableModel] = useState<ModelVersion | undefined>();
|
||||||
|
|
||||||
|
const getMostSuitableModelVersion = async (modelVersions: ModelVersion[]) => {
|
||||||
|
const resourceInfo = await executeSerial(
|
||||||
|
SystemMonitoringService.GET_RESOURCES_INFORMATION
|
||||||
|
);
|
||||||
|
const totalRam = resourceInfo.mem.total;
|
||||||
|
|
||||||
|
// find the model version with the highest required RAM that is still below the user's RAM by 80%
|
||||||
|
const modelVersion = modelVersions.reduce((prev, current) => {
|
||||||
|
if (current.maxRamRequired > prev.maxRamRequired) {
|
||||||
|
if (current.maxRamRequired < totalRam * 0.8) {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
});
|
||||||
|
|
||||||
|
setSuitableModel(modelVersion);
|
||||||
|
};
|
||||||
|
|
||||||
|
return { suitableModel, getMostSuitableModelVersion };
|
||||||
|
}
|
||||||
53
web/app/_hooks/useGetPerformanceTag.ts
Normal file
53
web/app/_hooks/useGetPerformanceTag.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { executeSerial } from "../../../electron/core/plugin-manager/execution/extension-manager";
|
||||||
|
import { SystemMonitoringService } from "../../shared/coreService";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { ModelVersion } from "@/_models/ModelVersion";
|
||||||
|
import { ModelPerformance, TagType } from "@/_components/SimpleTag/TagType";
|
||||||
|
|
||||||
|
// Recommendation:
|
||||||
|
// `Recommended (green)`: "Max RAM required" is 80% of users max RAM.
|
||||||
|
// `Slow on your device (yellow)`: Max RAM required is 80-100% of users max RAM
|
||||||
|
// `Not enough RAM (red)`: User RAM is below "Max RAM required"
|
||||||
|
|
||||||
|
export default function useGetPerformanceTag() {
|
||||||
|
const [performanceTag, setPerformanceTag] = useState<TagType | undefined>();
|
||||||
|
|
||||||
|
const getPerformanceForModel = async (modelVersion: ModelVersion) => {
|
||||||
|
const resourceInfo = await executeSerial(
|
||||||
|
SystemMonitoringService.GET_RESOURCES_INFORMATION
|
||||||
|
);
|
||||||
|
const totalRam = resourceInfo.mem.total;
|
||||||
|
const requiredRam = modelVersion.maxRamRequired;
|
||||||
|
setPerformanceTag(calculateRamPerformance(requiredRam, totalRam));
|
||||||
|
};
|
||||||
|
|
||||||
|
let title = "";
|
||||||
|
switch (performanceTag) {
|
||||||
|
case ModelPerformance.PerformancePositive:
|
||||||
|
title = "Recommended";
|
||||||
|
break;
|
||||||
|
case ModelPerformance.PerformanceNeutral:
|
||||||
|
title = "Slow on your device";
|
||||||
|
break;
|
||||||
|
case ModelPerformance.PerformanceNegative:
|
||||||
|
title = "Not enough RAM";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { performanceTag, title, getPerformanceForModel };
|
||||||
|
}
|
||||||
|
|
||||||
|
const calculateRamPerformance = (
|
||||||
|
requiredRamAmt: number,
|
||||||
|
totalRamAmt: number
|
||||||
|
) => {
|
||||||
|
const percentage = requiredRamAmt / totalRamAmt;
|
||||||
|
|
||||||
|
if (percentage < 0.8) {
|
||||||
|
return ModelPerformance.PerformancePositive;
|
||||||
|
} else if (percentage >= 0.8 && percentage < 1) {
|
||||||
|
return ModelPerformance.PerformanceNeutral;
|
||||||
|
} else {
|
||||||
|
return ModelPerformance.PerformanceNegative;
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -57,9 +57,9 @@ export type AssistantModel = {
|
|||||||
|
|
||||||
updatedAt?: number;
|
updatedAt?: number;
|
||||||
|
|
||||||
status: string; // TODO: add this in the database // Downloaded, Active
|
status: string;
|
||||||
|
|
||||||
releaseDate: number; // TODO: add this in the database
|
releaseDate: number;
|
||||||
|
|
||||||
tags: string[];
|
tags: string[];
|
||||||
};
|
};
|
||||||
|
|||||||
@ -24,8 +24,8 @@ export interface Product {
|
|||||||
outputs?: ProductOutput;
|
outputs?: ProductOutput;
|
||||||
createdAt: number;
|
createdAt: number;
|
||||||
updatedAt?: number;
|
updatedAt?: number;
|
||||||
status: string; // TODO: add this in the database // Downloaded, Active
|
status: string;
|
||||||
releaseDate: number; // TODO: add this in the database
|
releaseDate: number;
|
||||||
tags: string[];
|
tags: string[];
|
||||||
availableVersions: ModelVersion[];
|
availableVersions: ModelVersion[];
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user