Text Classification
Transformers
Safetensors
Chinese
spam-detection
advertising-detection
ad-classification
chinese
modernbert
mmbert
multi-task
four-head
Instructions to use x6nux/laya-ad with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use x6nux/laya-ad with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-classification", model="x6nux/laya-ad")# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("x6nux/laya-ad", device_map="auto") - Notebooks
- Google Colab
- Kaggle
Download code/laya-server/frontend/src/App.tsx from x6nux/laya-ad: direct link, hf CLI and curl.
- Browser
- Download file 17 kB
-
https://huggingface.co/x6nux/laya-ad/resolve/main/code/laya-server/frontend/src/App.tsx
- Command line
-
hf download hf://x6nux/laya-ad/code/laya-server/frontend/src/App.tsx
-
curl -L -o App.tsx https://huggingface.co/x6nux/laya-ad/resolve/main/code/laya-server/frontend/src/App.tsx
17 kB
| import { useEffect, useState, useSyncExternalStore, type FormEvent, type ReactNode } from "react" | |
| import { Activity, BookOpen, ChartNoAxesColumn, Check, CircleHelp, Copy, KeyRound, Languages, LogOut, Menu, Plus, Send, X } from "lucide-react" | |
| import { Button } from "@/components/ui/button" | |
| import { Input } from "@/components/ui/input" | |
| import { apiErrorMessage, useI18n, type Locale, type MessageKey, type Translate } from "./i18n" | |
| import { Playground, sampleRequest, type Model } from "./Playground" | |
| import { api, ApiError, getSession, setSession, subscribeSession, type Session } from "./api" | |
| type ApiKey = { id: number; name: string; mask: string; created_at: string; revoked_at: string | null; last_used_at: string | null } | |
| type Usage = { totals: { requests: number; input_tokens: number; output_tokens: number }; daily: { day: string; requests: number; input_tokens: number; output_tokens: number }[]; sources: { source: string; key_id: number | null; requests: number; input_tokens: number; output_tokens: number }[] } | |
| type Page = "home" | "keys" | "usage" | "playground" | "docs" | |
| const navigation: { id: Page; label: MessageKey; icon: typeof Activity }[] = [ | |
| { id: "home", label: "home", icon: Activity }, | |
| { id: "playground", label: "playground", icon: Send }, | |
| { id: "usage", label: "usage", icon: ChartNoAxesColumn }, | |
| { id: "keys", label: "apiKeys", icon: KeyRound }, | |
| { id: "docs", label: "documentation", icon: BookOpen }, | |
| ] | |
| function displayError(error: unknown, t: Translate) { | |
| return apiErrorMessage(error instanceof ApiError ? error.code : undefined, t) | |
| } | |
| async function copyText(value: string): Promise<boolean> { | |
| if (navigator.clipboard?.writeText) { | |
| try { | |
| await navigator.clipboard.writeText(value) | |
| return true | |
| } catch { /* Fall back when clipboard access is denied. */ } | |
| } | |
| const field = document.createElement("textarea") | |
| field.value = value | |
| field.readOnly = true | |
| field.style.position = "fixed" | |
| field.style.opacity = "0" | |
| const focused = document.activeElement instanceof HTMLElement ? document.activeElement : null | |
| document.body.appendChild(field) | |
| field.select() | |
| try { | |
| return document.execCommand("copy") | |
| } catch { | |
| return false | |
| } finally { | |
| field.remove() | |
| focused?.focus() | |
| } | |
| } | |
| function loadAvailableModels(): Promise<{ models: Model[] }> { | |
| return api("/internal/models") | |
| } | |
| function useSession() { | |
| const session = useSyncExternalStore(subscribeSession, getSession) | |
| const [ready, setReady] = useState(false) | |
| useEffect(() => { | |
| const controller = new AbortController() | |
| api<Session>("/internal/auth/session", { signal: controller.signal }) | |
| .then(value => { if (!controller.signal.aborted) setSession(value) }) | |
| .catch(cause => { | |
| if (!controller.signal.aborted && cause instanceof ApiError && cause.status === 401) setSession(null) | |
| }) | |
| .finally(() => { if (!controller.signal.aborted) setReady(true) }) | |
| return () => controller.abort() | |
| }, []) | |
| return { session, setSession, ready } | |
| } | |
| function BrandLogo() { | |
| return <img className="brand-logo" src="/laya-server-logo-black.png" alt="" aria-hidden="true" /> | |
| } | |
| function LanguagePicker() { | |
| const { locale, setLocale, t } = useI18n() | |
| return <label className="locale-picker"><Languages size={16} aria-hidden="true" /><span className="sr-only">{t("language")}</span><select aria-label={t("language")} value={locale} onChange={event => setLocale(event.target.value as Locale)}><option value="zh-CN">简体中文</option><option value="en">English</option><option value="zh-TW">繁體中文</option></select></label> | |
| } | |
| function Login({ onLogin }: { onLogin: (session: Session) => void }) { | |
| const { t } = useI18n() | |
| const [username, setUsername] = useState("") | |
| const [password, setPassword] = useState("") | |
| const [error, setError] = useState<unknown>(null) | |
| const [busy, setBusy] = useState(false) | |
| async function submit(event: FormEvent) { | |
| event.preventDefault() | |
| setBusy(true) | |
| setError(null) | |
| try { | |
| await api("/internal/auth/login", { method: "POST", body: JSON.stringify({ username, password }) }) | |
| onLogin(await api<Session>("/internal/auth/session")) | |
| } catch (cause) { | |
| setError(cause) | |
| } finally { | |
| setBusy(false) | |
| } | |
| } | |
| return <div className="login-shell"><div className="login-panel"> | |
| <div className="login-panel-header"><div className="brand-mark"><BrandLogo /></div><LanguagePicker /></div> | |
| <h1>{t("loginTitle")}</h1><p>{t("loginDescription")}</p> | |
| <form onSubmit={submit}> | |
| <label htmlFor="username">{t("username")}</label> | |
| <Input id="username" autoComplete="username" value={username} onChange={event => setUsername(event.target.value)} required /> | |
| <label htmlFor="password">{t("password")}</label> | |
| <Input id="password" type="password" autoComplete="current-password" value={password} onChange={event => setPassword(event.target.value)} required /> | |
| {error ? <div className="form-error" role="alert">{displayError(error, t)}</div> : null} | |
| <Button type="submit" disabled={busy} className="full-button">{busy ? t("signingIn") : t("signIn")}</Button> | |
| </form> | |
| </div></div> | |
| } | |
| function App() { | |
| const { t } = useI18n() | |
| const { session, setSession, ready } = useSession() | |
| const [page, setPage] = useState<Page>("home") | |
| const [mobileNav, setMobileNav] = useState(false) | |
| if (!ready) return <div className="loading">{t("loading")}</div> | |
| if (!session) return <Login onLogin={setSession} /> | |
| async function logout() { | |
| try { | |
| await api("/internal/auth/logout", { method: "POST" }, session!.csrf_token) | |
| if (getSession() === session) setSession(null) | |
| } catch (cause) { | |
| if (cause instanceof ApiError && cause.status === 401) return | |
| alert(displayError(cause, t)) | |
| } | |
| } | |
| const title = t(navigation.find(item => item.id === page)?.label || "home") | |
| return <div className="shell"> | |
| <aside className={mobileNav ? "sidebar open" : "sidebar"}> | |
| <div className="brand"><div className="brand-mark"><BrandLogo /></div><span>LAYA SERVER</span><button className="mobile-close" aria-label={t("closeNavigation")} onClick={() => setMobileNav(false)}><X size={18} /></button></div> | |
| <nav>{navigation.map(item => <button key={item.id} className={page === item.id ? "nav-item active" : "nav-item"} onClick={() => { setPage(item.id); setMobileNav(false) }}><item.icon size={17} strokeWidth={1.8} /><span>{t(item.label)}</span></button>)}</nav> | |
| <div className="account"><div className="account-avatar">{session.username.slice(0, 1).toUpperCase()}</div><div className="account-name"><strong>{session.username}</strong><span>{t("administrator")}</span></div><button aria-label={t("signOut")} title={t("signOut")} onClick={logout}><LogOut size={17} /></button></div> | |
| </aside> | |
| <div className="main"> | |
| <header className="topbar"><button className="menu-button" aria-label={t("openNavigation")} onClick={() => setMobileNav(true)}><Menu size={20} /></button><span>{title}</span><div className="topbar-controls"><span className="topbar-note">LAYA SERVER</span><LanguagePicker /></div></header> | |
| <main className="content">{page === "home" ? <Home setPage={setPage} /> : page === "keys" ? <Keys csrf={session.csrf_token} /> : page === "usage" ? <UsagePage /> : page === "playground" ? <Playground run={body => api("/internal/playground", { method: "POST", body }, session.csrf_token)} loadModels={loadAvailableModels} /> : <Docs />}</main> | |
| </div> | |
| {mobileNav ? <button className="nav-backdrop" aria-label={t("closeNavigation")} onClick={() => setMobileNav(false)} /> : null} | |
| </div> | |
| } | |
| function PageTitle({ title, description, action }: { title: string; description: string; action?: ReactNode }) { | |
| return <div className="page-title"><div><h1>{title}</h1><p>{description}</p></div>{action}</div> | |
| } | |
| function Home({ setPage }: { setPage: (page: Page) => void }) { | |
| const { t } = useI18n() | |
| const [keyCount, setKeyCount] = useState<number | null>(null) | |
| useEffect(() => { api<ApiKey[]>("/internal/api-keys").then(keys => setKeyCount(keys.filter(key => !key.revoked_at).length)).catch(() => {}) }, []) | |
| return <> | |
| <PageTitle title={t("homeTitle")} description={t("homeDescription")} /> | |
| <div className="home-intro"><span className="intro-icon"><KeyRound size={22} /></span><h2>{keyCount ? t("activeKeyCount", { count: keyCount }) : t("createFirstKey")}</h2><p>{t(keyCount ? "homeWithKeys" : "homeWithoutKeys")}</p><Button onClick={() => setPage("keys")}>{t("manageKeys")}</Button></div> | |
| <div className="home-links"><button onClick={() => setPage("playground")}><Send size={19} /><strong>{t("tryPlayground")}</strong><span>{t("tryPlaygroundDescription")}</span></button><button onClick={() => setPage("docs")}><BookOpen size={19} /><strong>{t("viewDocs")}</strong><span>{t("viewDocsDescription")}</span></button></div> | |
| </> | |
| } | |
| function Keys({ csrf }: { csrf: string }) { | |
| const { t, locale } = useI18n() | |
| const [keys, setKeys] = useState<ApiKey[]>([]) | |
| const [name, setName] = useState("") | |
| const [rawKey, setRawKey] = useState("") | |
| const [showCreate, setShowCreate] = useState(false) | |
| const [error, setError] = useState<unknown>(null) | |
| const [copyStatus, setCopyStatus] = useState<"idle" | "copied" | "error">("idle") | |
| const [busy, setBusy] = useState(false) | |
| const reload = () => api<ApiKey[]>("/internal/api-keys").then(setKeys).catch(setError) | |
| useEffect(() => { void reload() }, []) | |
| useEffect(() => { | |
| if (copyStatus !== "copied") return | |
| const timer = window.setTimeout(() => setCopyStatus("idle"), 3000) | |
| return () => window.clearTimeout(timer) | |
| }, [copyStatus]) | |
| async function create(event: FormEvent) { | |
| event.preventDefault() | |
| setBusy(true) | |
| setError(null) | |
| try { | |
| const created = await api<{ key: string }>("/internal/api-keys", { method: "POST", body: JSON.stringify({ name }) }, csrf) | |
| setRawKey(created.key) | |
| setCopyStatus("idle") | |
| setName("") | |
| setShowCreate(false) | |
| await reload() | |
| } catch (cause) { | |
| setError(cause) | |
| } finally { | |
| setBusy(false) | |
| } | |
| } | |
| async function revoke(key: ApiKey) { | |
| if (!confirm(t("revokeConfirm", { name: key.name }))) return | |
| try { | |
| await api("/internal/api-keys/" + key.id + "/revoke", { method: "POST" }, csrf) | |
| await reload() | |
| } catch (cause) { | |
| setError(cause) | |
| } | |
| } | |
| async function copyKey() { | |
| setCopyStatus("idle") | |
| setCopyStatus(await copyText(rawKey) ? "copied" : "error") | |
| } | |
| return <> | |
| <PageTitle title={t("apiKeys")} description={t("keysDescription")} action={<Button onClick={() => setShowCreate(true)}><Plus size={16} /> {t("createKey")}</Button>} /> | |
| {error ? <div className="form-error" role="alert">{displayError(error, t)}</div> : null} | |
| {rawKey ? <div className="key-reveal"><div><strong>{t("saveKeyTitle")}</strong><p>{t("saveKeyDescription")}</p>{copyStatus === "error" ? <p className="form-error" role="alert">{t("copyManually")}</p> : null}</div><div className="key-value"><code>{rawKey}</code><Button variant="outline" size="sm" className={copyStatus === "copied" ? "copy-success" : undefined} onClick={() => void copyKey()}>{copyStatus === "copied" ? <Check size={14} /> : <Copy size={14} />} {t(copyStatus === "copied" ? "copied" : "copy")}</Button><span className="sr-only" role="status">{copyStatus === "copied" ? t("copied") : ""}</span></div><button aria-label={t("closeKeyNotice")} onClick={() => { setRawKey(""); setCopyStatus("idle") }}><X size={18} /></button></div> : null} | |
| <div className="section-head"><h2>{t("keyList")}</h2><span>{t("keyCount", { count: keys.length })}</span></div> | |
| {keys.length === 0 ? <div className="empty"><KeyRound size={23} /><h3>{t("noKey")}</h3><p>{t("noKeyDescription")}</p><Button variant="outline" onClick={() => setShowCreate(true)}>{t("createKey")}</Button></div> : | |
| <div className="table-wrap"><table><thead><tr><th>{t("name")}</th><th>{t("key")}</th><th>{t("createdAt")}</th><th>{t("lastUsed")}</th><th>{t("status")}</th><th></th></tr></thead><tbody>{keys.map(key => | |
| <tr key={key.id}><td className="strong">{key.name}</td><td><code>{key.mask}</code></td><td>{formatDate(key.created_at, locale)}</td><td>{key.last_used_at ? formatDate(key.last_used_at, locale) : "—"}</td><td><span className={key.revoked_at ? "status revoked" : "status"}>{t(key.revoked_at ? "revoked" : "active")}</span></td><td>{!key.revoked_at ? <button className="text-danger" onClick={() => revoke(key)}>{t("revoke")}</button> : null}</td></tr> | |
| )}</tbody></table></div>} | |
| {showCreate ? <div className="dialog-backdrop" role="presentation" onMouseDown={() => setShowCreate(false)}><div className="dialog" role="dialog" aria-modal="true" aria-labelledby="create-title" onMouseDown={event => event.stopPropagation()}><button className="dialog-close" aria-label={t("close")} onClick={() => setShowCreate(false)}><X size={18} /></button><h2 id="create-title">{t("createKeyTitle")}</h2><p>{t("createKeyDescription")}</p><form onSubmit={create}><label htmlFor="key-name">{t("name")}</label><Input id="key-name" maxLength={80} autoFocus value={name} onChange={event => setName(event.target.value)} placeholder={t("keyNameExample")} required /><div className="dialog-actions"><Button type="button" variant="outline" onClick={() => setShowCreate(false)}>{t("cancel")}</Button><Button type="submit" disabled={busy}>{busy ? t("creating") : t("createKey")}</Button></div></form></div></div> : null} | |
| </> | |
| } | |
| function UsagePage() { | |
| const { t, locale } = useI18n() | |
| const [usage, setUsage] = useState<Usage | null>(null) | |
| const [error, setError] = useState<unknown>(null) | |
| useEffect(() => { api<Usage>("/internal/usage").then(setUsage).catch(setError) }, []) | |
| const totals = usage?.totals | |
| const daily = usage?.daily || [] | |
| const maxTokens = Math.max(1, ...daily.map(day => day.input_tokens + day.output_tokens)) | |
| const maxRequests = Math.max(1, ...daily.map(day => day.requests)) | |
| const number = (value: number) => value.toLocaleString(locale) | |
| return <> | |
| <PageTitle title={t("usage")} description={t("usageDescription")} /> | |
| {error ? <div className="form-error" role="alert">{displayError(error, t)}</div> : null} | |
| <section className="chart-section"><div className="chart-head"><h2>{t("tokens")}</h2><strong>{number((totals?.input_tokens || 0) + (totals?.output_tokens || 0))}</strong></div><div className="bars">{daily.length ? daily.map(day => <div className="bar-column" key={day.day} title={t("tokenTooltip", { day: day.day, count: number(day.input_tokens + day.output_tokens) })}><div className="bar" style={{ height: Math.max(2, ((day.input_tokens + day.output_tokens) / maxTokens) * 100) + "%" }} /><span>{day.day.slice(5)}</span></div>) : <div className="chart-empty">{t("noUsage")}</div>}</div></section> | |
| <section className="chart-section"><div className="chart-head"><h2>{t("requests")}</h2><strong>{number(totals?.requests || 0)}</strong></div><div className="bars">{daily.length ? daily.map(day => <div className="bar-column" key={day.day} title={t("requestTooltip", { day: day.day, count: number(day.requests) })}><div className="bar" style={{ height: Math.max(2, (day.requests / maxRequests) * 100) + "%" }} /><span>{day.day.slice(5)}</span></div>) : <div className="chart-empty">{t("noRequests")}</div>}</div></section> | |
| <div className="section-head"><h2>{t("sources")}</h2><span>{t("inputOutputSummary", { input: number(totals?.input_tokens || 0), output: number(totals?.output_tokens || 0) })}</span></div> | |
| <div className="table-wrap"><table><thead><tr><th>{t("sources")}</th><th>{t("requests")}</th><th>{t("inputTokens")}</th><th>{t("outputTokens")}</th></tr></thead><tbody>{usage?.sources.map(source => <tr key={source.source + "-" + source.key_id}><td className="strong">{source.source === "playground" ? t("playgroundSource") : "API Key #" + source.key_id}</td><td>{number(source.requests)}</td><td>{number(source.input_tokens)}</td><td>{number(source.output_tokens)}</td></tr>)}</tbody></table></div> | |
| </> | |
| } | |
| function Docs() { | |
| const { t } = useI18n() | |
| return <> | |
| <PageTitle title={t("documentation")} description={t("docsDescription")} /> | |
| <div className="docs"><h2>POST /v1/systemone</h2><p>{t("docsIntro")}</p><pre>{JSON.stringify(sampleRequest, null, 2)}</pre><h2>{t("docsMaxLenTitle")}</h2><p>{t("docsMaxLenDescription")}</p><pre>{JSON.stringify({ ...sampleRequest, max_len: 8192 }, null, 2)}</pre><h2>{t("docsResponse")}</h2><p>{t("docsResponseDescription")}</p><p className="docs-note"><CircleHelp size={16} /> {t("docsNote")}</p></div> | |
| </> | |
| } | |
| function formatDate(value: string, locale: Locale) { | |
| return new Date(value).toLocaleString(locale, { hour12: false }) | |
| } | |
| export default App | |