mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-30 14:58:08 +00:00
Pages from /machines to /risk, the model pages, and the kits they are made of
(page-kit, ProductLanding, LayerPage, Stack, the models kit, band's Head) mark
authored copy where it is written and draw it in the reader's language. A server
page marks a literal phrase('…') or wraps it in <T>; a client page calls t. The
kits translate a string prop through useSay (components/marketing/say), so a
page passes phrase('…') and markup passes as written. An arrow that points
turns over right to left (data-i18n-mirror).
Rebased on main: the fold-based heroes (Fold, PageHero, MachinesHero, the
product and layer pages) keep main's structure and copy, with their label,
title and lede marked phrase. /platform is main's CloudLanding; the deleted
/platform/layers and the old referral components stay deleted.
Claude-Session: https://claude.ai/code/session_015XYKLjZtDTJEnMo4eK3AFH
417 lines
17 KiB
TypeScript
417 lines
17 KiB
TypeScript
/**
|
|
* /models — the one overview of Hanzo's three model families, then every model
|
|
* the gateway answers for and what it costs.
|
|
*
|
|
* Order: the promise and the scale; `Family` (what Zen, Enso and Kai each do,
|
|
* each card to its own page); `Versus` (how Enso and Zen are had); the featured
|
|
* Enso and Zen models; one flagship per other lab; the priced catalogue; a
|
|
* thread to try; the request itself. The counts and the priced catalogue are
|
|
* read when the page opens (components/api/count, components/models/Catalog);
|
|
* the featured cards are the models this build wrote pages for, by id, so one
|
|
* the gateway stops serving drops off rather than 404s.
|
|
*/
|
|
import { KEYS } from '@/components/home/nav-data'
|
|
import { Live } from '@/components/models/Live'
|
|
import { Fold } from '@/components/marketing/fold'
|
|
import { Answer, type Spoken } from '@/components/preview/answer'
|
|
import { phrase } from '@hanzo/i18n'
|
|
import { T } from '@hanzo/i18n/react'
|
|
import { ProviderMark } from '@hanzo/app/ProviderMark'
|
|
import { TryChat } from '@/components/models/TryChat'
|
|
import { Modality, Tile } from '@/components/models/kit'
|
|
import type { ModelData } from '@/lib/models'
|
|
import { context, getOrgAndSlug, formatContext, modelName, modelPagePath } from '@/lib/models'
|
|
import { fetchModels } from '@/lib/models/served'
|
|
import Catalog from '@/components/models/Catalog'
|
|
import { Box, Text, XStack } from '@/components/ui'
|
|
import { Action, Lede, More, Title } from '@hanzo/ui/marketing'
|
|
import { Grid, Cell } from '@hanzo/ui/grid'
|
|
import { Request } from '@/components/models/preview'
|
|
import { Band, Card } from '@/components/marketing/band'
|
|
import { Family } from '@/components/family/Family'
|
|
import { Versus } from '@/components/family/Versus'
|
|
import { Related } from '@/components/product/Related'
|
|
import { product } from '@/lib/product'
|
|
import { NEXT, NOW, USES } from '@/lib/zen'
|
|
import { KAI as RESULTS } from '@/lib/bench-data'
|
|
import { p50 } from '@/lib/kai'
|
|
import { Code } from '@/components/code'
|
|
import { examples } from '@/lib/models/examples'
|
|
import { Samples } from '@/components/models/Samples'
|
|
import { CREATIVE_MODELS } from '@/lib/creative'
|
|
|
|
export const revalidate = 3600
|
|
|
|
/** What the shared product blocks say about this page: the audited command, the
|
|
* route the catalog proves it by, and the docs page or null. */
|
|
const PRODUCT = product('models')
|
|
|
|
/** The ground a band lifts to when it is told from its neighbour by colour as
|
|
* well as by a rule. */
|
|
const LIFT = 'color-mix(in oklab, var(--secondary) 10%, transparent)'
|
|
|
|
/**
|
|
* A card deck that never leaves a hole in the last row. Two-up, always: three
|
|
* tracks pass through two as the measure narrows, and a count that divides by
|
|
* three then strands its ninth card half across the row. Two divides everything
|
|
* but an odd count, and an odd count's last card simply takes the whole row.
|
|
*/
|
|
const tail = (n: number) => (n % 2 === 0 ? undefined : '1 / -1')
|
|
|
|
/** Ours, trained by Hanzo and served here only. */
|
|
const ENSO = ['enso', 'enso-flash', 'enso-ultra']
|
|
|
|
/** Zoo Labs Foundation's, weights published: the generation that answers now
|
|
* first (lib/zen), then the one before it and the specialists. */
|
|
const ZEN = [...NOW.ids, 'zen5', 'zen5-pro', 'zen5-coder', 'zen5-flash', 'zen-vl', 'zen-embedding']
|
|
|
|
const KAI = ['kai']
|
|
|
|
/** Kai's results card reads the research runs (lib/kai): the first harness claim
|
|
* that holds, the measured p50 when there is one, and the record sentence. */
|
|
const RESULT = RESULTS.claims.find((c) => c.board === 'kai-harness')
|
|
const TIMED = p50(RESULTS)
|
|
|
|
const FEATURED = [...ENSO, ...ZEN, ...KAI]
|
|
|
|
/**
|
|
* A model's mark, in the page's ink: Hanzo's H for ours (Enso, Kai and the
|
|
* creative models), Zoo Labs Foundation's venn for Zen, a lab's own mark for
|
|
* every other model.
|
|
*/
|
|
function markOf(id: string, size?: number) {
|
|
if (/^zen/.test(id)) return <ProviderMark org="zoo" model={id} size={size} ink />
|
|
if ([...ENSO, ...KAI].includes(id)) return <ProviderMark org="hanzo" size={size} ink />
|
|
return <ProviderMark org={getOrgAndSlug(id).org} model={id} size={size} />
|
|
}
|
|
|
|
/** Where Zen's weights are published, and who makes them with us. */
|
|
const ZENLM = 'https://huggingface.co/zenlm'
|
|
const ZOO = 'https://zoo.ngo'
|
|
|
|
/** One flagship per lab, in the order we would point a visitor at. The model is
|
|
* resolved from the live catalogue, so a version bump follows on its own. */
|
|
const TOP_LABS = ['anthropic', 'openai', 'google', 'deepseek', 'x-ai', 'meta', 'mistral', 'cohere']
|
|
|
|
/** A lab's headline general-purpose model: no alias namespace, no point
|
|
* variant, no speed or size cut, no dated snapshot, no specialised modality. */
|
|
function isCanonical(id: string): boolean {
|
|
const slug = id.split('/').pop() ?? id
|
|
if (id.startsWith('~') || id.includes(':')) return false
|
|
if (/(?:^|[-])(?:fast|flash|mini|nano|tiny|small|lite|air|preview|exp|latest|thinking|code|base|instruct|image|video|audio|voice|tts|embed|embedding|rerank|ocr|guard|moderation)(?:$|[-])/i.test(slug))
|
|
return false
|
|
if (/-\d{6,}$/.test(slug)) return false
|
|
return true
|
|
}
|
|
|
|
function ModelCard({ model }: { model: ModelData }) {
|
|
const ctx = context(model)
|
|
return (
|
|
<Tile
|
|
size="lg"
|
|
href={modelPagePath(model.id)}
|
|
mark={markOf(model.id)}
|
|
name={modelName(model)}
|
|
id={model.id}
|
|
ctx={ctx ? formatContext(ctx) : undefined}
|
|
blurb={model.description}
|
|
>
|
|
{model.modalities && model.modalities.length > 0 && (
|
|
<XStack flexWrap="wrap" gap="$1">
|
|
{model.modalities.slice(0, 3).map((m) => (
|
|
<Modality key={m} name={m} />
|
|
))}
|
|
</XStack>
|
|
)}
|
|
</Tile>
|
|
)
|
|
}
|
|
|
|
/** The deep link a section ends on: the page or the docs that go further than the cards. */
|
|
function Onward({ href, children }: { href: string; children: string }) {
|
|
return (
|
|
<XStack mt="$6" justify="center">
|
|
<More href={href}><T>{children}</T> →</More>
|
|
</XStack>
|
|
)
|
|
}
|
|
|
|
/** A model as the first screen's preview says it: its name, its words, its mark and the facts the catalog states. */
|
|
function spoken(m: ModelData, name = modelName(m), says = m.description ?? ''): Spoken {
|
|
const ctx = context(m)
|
|
return { id: m.id, name, says, mark: markOf(m.id, 16), facts: [...(ctx ? [formatContext(ctx)] : []), ...(m.modalities ?? []).slice(0, 2)] }
|
|
}
|
|
|
|
export default async function ModelsPage() {
|
|
const data = await fetchModels()
|
|
const available = data.models
|
|
const byId = new Map(available.map((m) => [m.id, m]))
|
|
|
|
const enso = ENSO.flatMap((id) => byId.get(id) ?? [])
|
|
const zen = ZEN.flatMap((id) => byId.get(id) ?? [])
|
|
const kai = KAI.flatMap((id) => byId.get(id) ?? [])
|
|
const featured = new Set(FEATURED.flatMap((id) => byId.get(id) ?? []).map((m) => m.id))
|
|
const top = TOP_LABS.flatMap((lab) => {
|
|
const m = available.find(
|
|
(x) => getOrgAndSlug(x.id).org.replace(/^~/, '') === lab && !featured.has(x.id) && isCanonical(x.id),
|
|
)
|
|
return m ? [m] : []
|
|
})
|
|
|
|
const dEnso = tail(enso.length)
|
|
const dZen = tail(zen.length + 1)
|
|
const dKai = tail(kai.length + 2)
|
|
const dTop = tail(top.length)
|
|
|
|
// The sample calls an id this catalogue serves: the first featured one, in four languages.
|
|
const called = FEATURED.find((id) => byId.has(id))
|
|
const request = called ? examples({ id: called, endpoint: byId.get(called)?.endpoint }) : null
|
|
|
|
// The first screen's models, each answering in its own words: the router, the
|
|
// open weights (lib/zen's words, since the catalog gives Zen none) and the first
|
|
// flagship the page lists from another lab. Kai answers at /v1/decisions, not
|
|
// here, so its own page draws its decision.
|
|
const asked: Spoken[] = [
|
|
...enso.slice(0, 1).map((m) => spoken(m)),
|
|
...zen.slice(0, 1).map((m) => spoken(m, NOW.name, USES.map((u) => u.detail).join(' '))),
|
|
...top.slice(0, 1).map((m) => spoken(m)),
|
|
].filter((m) => m.says)
|
|
|
|
return (
|
|
<Box minH="100vh" $platform-web={{ color: 'var(--foreground)' }}>
|
|
<Fold
|
|
label={phrase('Models')}
|
|
title={phrase('Frontier AI families')}
|
|
lede={phrase('Proprietary and open weight models for text, decisions, video, image, and more — one account, one API key.')}
|
|
actions={
|
|
<>
|
|
<Action href={KEYS} fill>
|
|
<T>Get API key</T>
|
|
</Action>
|
|
<Action href="#catalog">
|
|
<T>Every model</T>
|
|
</Action>
|
|
</>
|
|
}
|
|
below={<Live />}
|
|
preview={<Answer models={asked} />}
|
|
/>
|
|
|
|
{/* The three families side by side, then how Enso and Zen are had (LLM.md "/models explains the three families"). */}
|
|
<Family />
|
|
<Versus />
|
|
|
|
<Box position="relative" width="100%" maxW={896} mx="auto" px="$4" $sm={{ px: '$5' }} $lg={{ px: '$6' }} $platform-web={{ textAlign: 'center' }}>
|
|
<Band pad="$11" measure={1152}>
|
|
<Title quiet mb={40}>
|
|
<T>Enso models</T>
|
|
</Title>
|
|
<Grid columns={{ min: 250, max: 2 }} gap={24}>
|
|
{enso.map((model, i) =>
|
|
i === enso.length - 1 ? (
|
|
<Cell key={model.id} col={dEnso}>
|
|
<ModelCard model={model} />
|
|
</Cell>
|
|
) : (
|
|
<ModelCard key={model.id} model={model} />
|
|
),
|
|
)}
|
|
</Grid>
|
|
<Onward href="/enso">{phrase('Enso: the router, its presets and its runs')}</Onward>
|
|
</Band>
|
|
|
|
<Band pad="$11" measure={1152}>
|
|
<Title quiet mb={8}>
|
|
<T>Zen models</T>
|
|
</Title>
|
|
<Lede mb={40} maxW={720}>
|
|
<T
|
|
values={{
|
|
zoo: (
|
|
<Text render={<a href={ZOO} />} color="inherit" $platform-web={{ textDecoration: 'underline', textUnderlineOffset: '3px' }}>
|
|
Zoo Labs Foundation
|
|
</Text>
|
|
),
|
|
hub: (
|
|
<Text render={<a href={ZENLM} />} color="inherit" $platform-web={{ textDecoration: 'underline', textUnderlineOffset: '3px' }}>
|
|
huggingface.co/zenlm
|
|
</Text>
|
|
),
|
|
}}
|
|
>
|
|
{'Open weights, made with {zoo}. Download every Zen model at {hub}, or call it here.'}
|
|
</T>
|
|
</Lede>
|
|
<Grid columns={{ min: 250, max: 2 }} gap={24}>
|
|
{zen.map((model) => (
|
|
<ModelCard key={model.id} model={model} />
|
|
))}
|
|
<Cell col={dZen}>
|
|
<Tile size="lg" mark={markOf(NEXT.id)} name={NEXT.name} id={NEXT.id} blurb={NEXT.blurb}>
|
|
<Request />
|
|
</Tile>
|
|
</Cell>
|
|
</Grid>
|
|
<Onward href="https://docs.hanzo.ai/docs/models/zen">{phrase('Run Zen: the docs')}</Onward>
|
|
</Band>
|
|
|
|
<Band pad="$11" measure={1152}>
|
|
<Title quiet mb={40}>
|
|
<T>Kai decision models</T>
|
|
</Title>
|
|
<Grid columns={{ min: 250, max: 2 }} gap={24}>
|
|
{kai.map((model) => (
|
|
<ModelCard key={model.id} model={model} />
|
|
))}
|
|
<Tile
|
|
size="lg"
|
|
href="/kai#benchmarks"
|
|
mark={markOf('kai')}
|
|
name={<T>Decision Benchmarks</T>}
|
|
id={RESULT ? `${RESULT.figure} ${RESULT.label.split(',')[0].toLowerCase()}` : undefined}
|
|
ctx={TIMED ? `${TIMED.ms} ms` : undefined}
|
|
blurb={RESULTS.headline.lede}
|
|
>
|
|
<XStack flexWrap="wrap" gap="$1">
|
|
<Modality name={<T>benchmarks</T>} />
|
|
</XStack>
|
|
</Tile>
|
|
<Cell col={dKai}>
|
|
<Tile
|
|
size="lg"
|
|
href="/kai#types"
|
|
mark={markOf('kai')}
|
|
name={<T>Autonomous Agent Steering</T>}
|
|
id="decision-ready"
|
|
blurb={<T>{"A choice, a score or a yes/no, each with its probabilities, for agent loops such as Hanzo Dev's."}</T>}
|
|
>
|
|
<XStack flexWrap="wrap" gap="$1">
|
|
<Modality name="choice" />
|
|
<Modality name="score" />
|
|
<Modality name="noul" />
|
|
</XStack>
|
|
</Tile>
|
|
</Cell>
|
|
</Grid>
|
|
<Onward href="/kai">{phrase('Kai: decisions and their benchmarks')}</Onward>
|
|
</Band>
|
|
|
|
<Band id="creative" pad="$11" measure={1152}>
|
|
<Title quiet mb={8}>
|
|
<T>Creative models</T>
|
|
</Title>
|
|
<Lede mb={40} maxW={720}>
|
|
<T>Video, images, 3D, sound effects, voice and music, each its own model, in research preview.</T>
|
|
</Lede>
|
|
<Grid columns={{ min: 280, max: 3 }} gap={24}>
|
|
{CREATIVE_MODELS.map((m) => {
|
|
const endpoint = {
|
|
koma: 'api.hanzo.ai/v1/video',
|
|
iro: 'api.hanzo.ai/v1/images',
|
|
mori: 'api.hanzo.ai/v1/3d',
|
|
oto: 'api.hanzo.ai/v1/foley',
|
|
koe: 'api.hanzo.ai/v1/audio/speech',
|
|
uta: 'api.hanzo.ai/v1/music',
|
|
}[m.slug] ?? `api.hanzo.ai/v1/${m.slug}`
|
|
return (
|
|
<Tile
|
|
key={m.id}
|
|
size="lg"
|
|
href={m.route}
|
|
mark={<ProviderMark org="hanzo" ink />}
|
|
name={m.name}
|
|
id={m.modelId}
|
|
ctx={<T>Research preview</T>}
|
|
blurb={<T>{m.lede}</T>}
|
|
>
|
|
<XStack flexWrap="wrap" gap="$1" items="center" justify="space-between" width="100%">
|
|
<Modality name={<T>{m.role}</T>} />
|
|
<Text
|
|
fontSize="$1"
|
|
color="var(--muted-foreground)"
|
|
fontFamily="$mono"
|
|
>
|
|
{endpoint}
|
|
</Text>
|
|
</XStack>
|
|
</Tile>
|
|
)
|
|
})}
|
|
</Grid>
|
|
<Onward href="/studio">{phrase('Make something in Studio')}</Onward>
|
|
</Band>
|
|
|
|
<Band pad="$11" measure={1152} ground={LIFT}>
|
|
<Title quiet mb={40}>
|
|
<T>Flagships from other labs</T>
|
|
</Title>
|
|
<Grid columns={{ min: 250, max: 2 }} gap={24}>
|
|
{top.map((model, i) =>
|
|
i === top.length - 1 ? (
|
|
<Cell key={model.id} col={dTop}>
|
|
<ModelCard model={model} />
|
|
</Cell>
|
|
) : (
|
|
<ModelCard key={model.id} model={model} />
|
|
),
|
|
)}
|
|
</Grid>
|
|
<Onward href="#catalog">{phrase('Every model, priced')}</Onward>
|
|
</Band>
|
|
|
|
<Band id="catalog" pad="$11" measure={1152}>
|
|
<Title quiet>
|
|
<T>Every model, and what it costs</T>
|
|
</Title>
|
|
<Lede mt="$3.5" mb={40} maxW={672}>
|
|
<T>Dollars per million tokens, in and out, from the live catalog.</T>
|
|
</Lede>
|
|
<Catalog />
|
|
<Onward href="https://docs.hanzo.ai/docs/models">{phrase('How models are called and billed')}</Onward>
|
|
</Band>
|
|
|
|
<Band pad="$11" measure={1152} ground={LIFT}>
|
|
<Title quiet>
|
|
<T>Try any model</T>
|
|
</Title>
|
|
<Lede mt="$3.5" mb={40} maxW={672}>
|
|
<T>Test any model directly on the gateway. Switch models by changing one string.</T>
|
|
</Lede>
|
|
<TryChat />
|
|
</Band>
|
|
|
|
{request ? (
|
|
<Band pad="$11" measure={896}>
|
|
<Card p="$6" $md={{ p: '$8' }}>
|
|
<Box mb="$6" $platform-web={{ textAlign: 'center' }}>
|
|
<Title quiet>
|
|
<T>Your first request</T>
|
|
</Title>
|
|
<Lede mt="$3.5" mx="auto" maxW={672}>
|
|
<T>The chat-completions shape you already send, at api.hanzo.ai/v1, in the language you write.</T>
|
|
</Lede>
|
|
</Box>
|
|
<Box $platform-web={{ textAlign: 'start' }}>
|
|
<Samples
|
|
samples={[
|
|
{ lang: 'cURL', code: request.curl, sample: <Code lang="bash" code={request.curl} /> },
|
|
{ lang: 'Python', code: request.py, sample: <Code lang="python" code={request.py} /> },
|
|
{ lang: 'TypeScript', code: request.ts, sample: <Code lang="typescript" code={request.ts} /> },
|
|
{ lang: 'Go', code: request.go, sample: <Code lang="go" code={request.go} /> },
|
|
]}
|
|
/>
|
|
</Box>
|
|
<XStack mt="$5" flexWrap="wrap" columnGap={24} rowGap={8} justify="center">
|
|
<More href={KEYS}><T>Get an API key</T> →</More>
|
|
<More href="https://docs.hanzo.ai/docs/quickstart"><T>The quickstart</T> →</More>
|
|
</XStack>
|
|
</Card>
|
|
</Band>
|
|
) : null}
|
|
|
|
{PRODUCT && <Related product={PRODUCT} />}
|
|
</Box>
|
|
</Box>
|
|
)
|
|
}
|