easyai-ai-gateway/apps/web/src/pages/HomePage.tsx

128 lines
5.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type { ReactNode } from 'react';
import { Activity, Boxes, Image, Layers, Route, ServerCog, ShieldCheck, Video, Workflow } from 'lucide-react';
import { Badge, Button, Card, CardContent } from '../components/ui';
import type { PageKey } from '../types';
const coverage = [
{ icon: <Activity size={18} />, label: '大模型对话', value: 'Chat / Responses', detail: '兼容 OpenAI 对话接口与 EasyAI 站内调用' },
{ icon: <Image size={18} />, label: '图像生成', value: 'Image Generation', detail: '支持尺寸、质量、计费权重和结果转存' },
{ icon: <Layers size={18} />, label: '图像编辑', value: 'Image Edit', detail: '参考图、mask 和主服务文件上传链路' },
{ icon: <Video size={18} />, label: '视频能力', value: 'Video Ready', detail: '保留任务队列、进度事件和后续 Client 扩展位' },
];
const advantages = [
{ icon: <Route size={18} />, title: '多客户端路由', body: '同一模型可配置多个平台客户端,前一个失败后按策略切换下一个。' },
{ icon: <Workflow size={18} />, title: '持久化任务', body: '任务、事件、队列和回调 outbox 入库,服务重启后可以恢复运行状态。' },
{ icon: <ShieldCheck size={18} />, title: '策略化限流', body: 'TPM、RPM、并发、用户组折扣和平台优先级统一纳入调度。' },
{ icon: <ServerCog size={18} />, title: 'Hybrid 接入', body: '既可独立闭环运行,也可以对接 server-main 的认证、上传和业务前端。' },
];
export function HomePage(props: { onNavigate: (page: PageKey) => void }) {
return (
<div className="landingPage">
<section className="releaseNotice">
<Badge variant="success">线</Badge>
<strong>OpenAI Gemini Phase 1 Client </strong>
<span></span>
</section>
<section className="landingHero">
<div className="landingCopy">
<Badge variant="secondary">EasyAI AI Gateway</Badge>
<h1> AI </h1>
<p> server-main </p>
<div className="landingActions">
<Button type="button" onClick={() => props.onNavigate('models')}></Button>
<Button type="button" variant="outline" onClick={() => props.onNavigate('docs')}> API </Button>
</div>
</div>
<GatewayPreview />
</section>
<section className="landingSection">
<div className="landingSectionHeader">
<p className="eyebrow">Model Coverage</p>
<h2></h2>
</div>
<div className="coverageGrid">
{coverage.map((item) => (
<FeatureCard {...item} key={item.label} />
))}
</div>
</section>
<section className="landingSection">
<div className="landingSectionHeader">
<p className="eyebrow">Gateway Advantage</p>
<h2></h2>
</div>
<div className="advantageGrid">
{advantages.map((item) => (
<AdvantageCard {...item} key={item.title} />
))}
</div>
</section>
</div>
);
}
function GatewayPreview() {
return (
<div className="gatewayPreview" aria-label="网关能力预览">
<div className="previewHeader">
<span>Gateway Runtime</span>
<Badge variant="success">hybrid</Badge>
</div>
<div className="previewGrid">
<PreviewItem label="Provider" value="OpenAI / Gemini" />
<PreviewItem label="Routes" value="Chat · Image · Edit · Video" />
<PreviewItem label="Limits" value="TPM · RPM · Concurrent" />
<PreviewItem label="Queue" value="Persistent Recovery" />
</div>
<div className="previewFlow">
<span>Request</span>
<span>Policy</span>
<span>Client Retry</span>
<span>Callback</span>
<span>Result</span>
</div>
</div>
);
}
function PreviewItem(props: { label: string; value: string }) {
return (
<div>
<span>{props.label}</span>
<strong>{props.value}</strong>
</div>
);
}
function FeatureCard(props: { detail: string; icon: ReactNode; label: string; value: string }) {
return (
<Card>
<CardContent className="landingFeatureCard">
<div className="iconBox">{props.icon}</div>
<div>
<span>{props.label}</span>
<strong>{props.value}</strong>
<p>{props.detail}</p>
</div>
</CardContent>
</Card>
);
}
function AdvantageCard(props: { body: string; icon: ReactNode; title: string }) {
return (
<Card>
<CardContent className="advantageCard">
<div className="iconBox">{props.icon}</div>
<strong>{props.title}</strong>
<p>{props.body}</p>
</CardContent>
</Card>
);
}