missing model install directly from hf

This commit is contained in:
Weixuan Fu
2024-01-27 17:14:12 +08:00
parent a624e51f9d
commit 60a254a7c6
4 changed files with 79 additions and 39 deletions
@@ -1,7 +1,7 @@
import { GridItem, VStack, Button, Text } from "@chakra-ui/react";
import { GridItem, VStack, Button, Text, Link } from "@chakra-ui/react";
import { IconExternalLink } from "@tabler/icons-react";
import { useEffect, useState } from "react";
import { modelExtensions } from "../utils";
export interface MissingModel {
class_type: string;
input_name: string;
@@ -11,28 +11,57 @@ export interface MissingModel {
interface Props {
model: MissingModel;
}
type missingModelPredict = { url: string; name: string; downloadUrl: string };
export default function MissingModelItem({ model }: Props) {
const [suggestedUrls, setSuggestedUrls] = useState<{ url: string, name: string }[]>([]);
const [suggestedUrls, setSuggestedUrls] = useState<missingModelPredict[]>([]);
const modelName = formatSearchQuery(model.received_value);
const getHuggingFaceData = async () => {
const hfData = await fetch(`https://huggingface.co/api/models?limit=3&search=${modelName}`);
const hfSearchResult = await hfData.json() as { id: string; modelId: string }[];
const hfUrls = hfSearchResult.map(({ modelId }) => ({ name: `${modelId.split('/')[1]} on HuggingFace`, url: `https://huggingface.co/${modelId}` }));
setSuggestedUrls(p => [...p, ...hfUrls]);
console.warn("fetching hf", modelName);
const hfData = await fetch(
`https://huggingface.co/api/models?limit=3&search=${modelName}&full=true`,
);
const hfSearchResult = (await hfData.json()) as {
id: string;
modelId: string;
siblings?: { rfilename: string }[];
}[];
const hfUrls: missingModelPredict[] = [];
console.log(hfSearchResult);
hfSearchResult.slice(0, 1).forEach(({ modelId, siblings }) => {
console.log(modelId, siblings);
siblings?.forEach((s) => {
const ext = s.rfilename.split(".").pop();
console.log(ext);
if (modelExtensions.includes(ext ?? "")) {
hfUrls.push({
name: s.rfilename,
downloadUrl: `https://huggingface.co/${modelId}/resolve/main/${s.rfilename}`,
url: `https://huggingface.co/${modelId}/tree/main`,
});
}
});
});
setSuggestedUrls(hfUrls);
};
const getCivitaiData = async () => {
const civitaiData = await fetch(`https://civitai.com/api/v1/models?limit=3&query=${modelName}`);
const civitaiSearchResult = await civitaiData.json() as { items: { id: string, name: string }[] };
const civitaiUrls = civitaiSearchResult.items?.map(({ name, id }) => ({ name: `${name} on civitAI`, url: `https://civitai.com/models/${id}` })) ?? [];
setSuggestedUrls(p => [...p, ...civitaiUrls]);
const civitaiData = await fetch(
`https://civitai.com/api/v1/models?limit=3&query=${modelName}`,
);
const civitaiSearchResult = (await civitaiData.json()) as {
items: { id: string; name: string }[];
};
const civitaiUrls =
civitaiSearchResult.items?.map(({ name, id }) => ({
name: `${name} on civitAI`,
url: `https://civitai.com/models/${id}`,
downloadUrl: `https://civitai.com/models/${id}`,
})) ?? [];
setSuggestedUrls((p) => [...p, ...civitaiUrls]);
};
useEffect(() => {
getHuggingFaceData();
getCivitaiData();
}, [model]);
console.log(suggestedUrls);
// getCivitaiData();
}, []);
return (
<GridItem p={3} shadow="md" borderWidth="1px">
@@ -43,18 +72,16 @@ export default function MissingModelItem({ model }: Props) {
<Text fontWeight="bold">Received Value:</Text>
<Text color="red.400">{model.received_value}</Text>
{suggestedUrls.map(({ url, name }) => (
<Button
colorScheme="blue"
mt={5}
iconSpacing={1}
leftIcon={<IconExternalLink size={20} />}
size={"sm"}
onClick={() => {
window.open(url, "_blank");
<Link
href={url}
isExternal
onClick={(e) => {
e.stopPropagation();
}}
>
{name}
</Button>
<IconExternalLink size={20} />
</Link>
))}
<Button
colorScheme="blue"
@@ -77,14 +104,16 @@ export default function MissingModelItem({ model }: Props) {
}
function formatSearchQuery(query: string): string {
return query
// Remove path, only applies if model is in a subfolder
.replace(/^.*(\\|\/|\:)/, '')
// Remove file extension
.replace(/\.[^/.]+$/, "")
// Replace underscore with space
.replaceAll("_", " ")
// Add space before capital letters
.replace(/([A-Z])/g, " $1")
.trim();
}
return (
query
// Remove path, only applies if model is in a subfolder
.replace(/^.*(\\|\/|\:)/, "")
// Remove file extension
.replace(/\.[^/.]+$/, "")
// Replace underscore with space
.replaceAll("_", " ")
// Add space before capital letters
.replace(/([A-Z])/g, " $1")
.trim()
);
}
@@ -61,7 +61,9 @@ export default function MissingModelsListDrawer({
</Flex>
</CardHeader>
<Grid templateColumns="1" gap={1} marginTop={2}>
{missingModels.map((model) => <MissingModelItem model={model} />)}
{missingModels.map((model) => (
<MissingModelItem key={model.received_value} model={model} />
))}
</Grid>
</Card>
</Box>
@@ -34,7 +34,6 @@ export default function InstallMissingModelsButton({}: Props) {
try {
await queuePrompt.apply(app, [...arguments]);
} finally {
console.log("queuePrompt app.node err", app.lastNodeErrors);
const nodeErrors = (app.lastNodeErrors ?? {}) as Record<
string,
NodeError
+11 -1
View File
@@ -5,7 +5,7 @@ import { app, ComfyApp } from "/scripts/app.js";
export function formatTimestamp(
unixTimestamp: number,
showSec: boolean = false
showSec: boolean = false,
) {
// Create a new Date object from the UNIX timestamp
const date = new Date(unixTimestamp);
@@ -40,3 +40,13 @@ export function KBtoGB(kilobytes: number, decimalPlaces: number = 1) {
return sizeInMB.toFixed(decimalPlaces) + " MB";
}
}
// fro folder_path.py
export const modelExtensions = [
"ckpt",
"pt",
"bin",
"pth",
"safetensors",
"onnx",
];