Files

115 lines
4.4 KiB
TypeScript

import { useId, useState } from "react";
import { families } from "@/lib/fast-models";
export const client = "load";
const local = (path: string) => `${import.meta.env.BASE_URL.replace(/\/$/, "")}${path}`;
export default function FastModels() {
const [family, setFamily] = useState("All models");
const [query, setQuery] = useState("");
const id = useId();
const visible = families
.map((group) => ({
...group,
models: group.models.filter(
(model) =>
(family === "All models" || family === group.name) &&
`${group.name} ${group.summary} ${model.id}`.toLowerCase().includes(query.trim().toLowerCase()),
),
}))
.filter((group) => group.models.length);
const count = visible.reduce((total, group) => total + group.models.length, 0);
return (
<div className="models-page not-prose">
<section className="model-families" aria-label="Model families">
{families.map((group) => (
<article className="model-family" key={group.name}>
<a href={group.collection} className="model-family-visual" aria-label={`${group.name} collection`}>
<span aria-hidden="true">{group.mark}</span>
<img src={local("/icon.svg")} alt="" width="24" height="24" />
</a>
<div className="model-family-body">
<h2>{group.name}</h2>
<p>{group.summary}</p>
<p className="model-family-detail">{group.detail}</p>
<div className="model-family-links">
<a href={group.collection}>
View collection <span aria-hidden="true">↗</span>
</a>
<a href={local(group.guide)}>
{group.name === "FastMetal" ? "MLX setup" : "Recipes and setup"} <span aria-hidden="true">→</span>
</a>
</div>
</div>
</article>
))}
</section>
<section className="model-catalog" aria-labelledby="checkpoint-catalog">
<header className="model-catalog-heading">
<div>
<h2 id="checkpoint-catalog">Browse checkpoints</h2>
<p>Find the export your runtime needs.</p>
</div>
<a href="https://huggingface.co/collections/FastVideo/fastvideo-fasth3">
Earlier FastH3 releases <span aria-hidden="true">↗</span>
</a>
</header>
<div className="model-catalog-controls">
<div className="model-filters" role="group" aria-label="Filter by model family">
{["All models", ...families.map((group) => group.name)].map((name) => (
<button key={name} type="button" aria-pressed={family === name} onClick={() => setFamily(name)}>
{name}
</button>
))}
</div>
<div className="model-search">
<label htmlFor={id}>Search checkpoints</label>
<input
id={id}
type="search"
placeholder="Name, precision, or runtime…"
value={query}
onChange={(event) => setQuery(event.target.value)}
/>
</div>
</div>
<p className="model-result-count" role="status">
{count} {count === 1 ? "checkpoint" : "checkpoints"}
</p>
{visible.map((group) => (
<section className="model-checkpoints" key={group.name} aria-labelledby={`catalog-${group.name}`}>
<h3 id={`catalog-${group.name}`}>{group.name}</h3>
<ul>
{group.models.map((model) => (
<li key={model.id}>
<div>
<a href={model.url}>{model.id.replace(/^FastVideo-/, "").replace(/-Diffusers$/, "")}</a>
<code>FastVideo/{model.id}</code>
</div>
<a className="model-checkpoint-link" href={model.url} aria-label={`Open ${model.id} on Hugging Face`}>
Hugging Face <span aria-hidden="true">↗</span>
</a>
</li>
))}
</ul>
</section>
))}
{!count && (
<div className="model-empty">
<p>No checkpoints match these filters.</p>
<button
type="button"
onClick={() => {
setQuery("");
setFamily("All models");
}}
>
Clear filters
</button>
</div>
)}
</section>
</div>
);
}