Files
omniai-web/src/features/home/ModelGenerationShowcase.tsx
T

284 lines
12 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 { useEffect, useRef, useState } from "react";
import "../../styles/pages/model-generation-showcase.css";
type ShowMode = "agent" | "image" | "video";
const MODE_TABS = [
{ key: "agent" as const, icon: "🤖", title: "Agent 模式", desc: "文本生成,对话式交互,智能推理" },
{ key: "image" as const, icon: "🖼️", title: "图片模式", desc: "图像生成,风格迁移,场景合成" },
{ key: "video" as const, icon: "🎬", title: "视频模式", desc: "视频生成,动态场景,数字人演绎" },
];
const AGENT_OUTPUTS = [
{ tag: "Agent", title: "营销文案", preview: "「未来已来,腕间即达」—— 全新智能手表,让每一秒都充满可能。健康监测、智能提醒、时尚设计,三合一体验。从晨跑配速到会议提醒,它比你更懂你的节奏。" },
{ tag: "Agent", title: "产品描述", preview: "搭载最新AI芯片,支持实时心率/血氧/睡眠监测,50米防水,AMOLED视网膜屏,续航长达14天。钛合金表壳 + 硅胶快拆表带,商务运动自由切换。" },
{ tag: "Agent", title: "剧本大纲", preview: "第一幕:品牌故事引入 → 第二幕:产品亮点展示 → 第三幕:用户见证与CTA引导。" },
];
const IMAGE_OUTPUTS = [
{ tag: "Image", title: "写实风格", icon: "📷", styleClass: "realistic" },
{ tag: "Image", title: "插画风格", icon: "🎨", styleClass: "illustration" },
{ tag: "Image", title: "电商风格", icon: "🛍️", styleClass: "ecommerce" },
];
const VIDEO_OUTPUTS = [
{ tag: "Video", title: "数字人播报", duration: "0:15" },
{ tag: "Video", title: "场景动画", duration: "0:30" },
{ tag: "Video", title: "产品展示", duration: "0:20" },
];
function ModelGenerationShowcase() {
const [mode, setMode] = useState<ShowMode>("agent");
const [selectedImageOpt, setSelectedImageOpt] = useState(0);
const [, setAnimated] = useState(false);
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const el = containerRef.current;
if (!el) return;
const observer = new IntersectionObserver(
([entry]) => {
if (entry?.isIntersecting) {
setAnimated(true);
observer.disconnect();
}
},
{ threshold: 0.2 },
);
observer.observe(el);
return () => observer.disconnect();
}, []);
const workflowSteps = [
{ label: "选择模式", active: mode === "agent" },
{ label: "输入描述", active: mode === "image" },
{ label: "AI生成", active: mode === "video" },
{ label: "输出内容", active: false },
];
return (
<div className="omni-model-gen-showcase" ref={containerRef}>
{/* Left Panel */}
<div className="mgs-left-panel">
<div className="mgs-brand-section">
<h1><br /></h1>
<p className="mgs-subtitle">AI模型生成文本</p>
</div>
<div className="mgs-mode-tabs">
{MODE_TABS.map((tab) => (
<div
key={tab.key}
className={`mgs-mode-tab${mode === tab.key ? " is-active" : ""}`}
onClick={() => setMode(tab.key)}
role="button"
tabIndex={0}
onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") setMode(tab.key); }}
>
<div className="mgs-mode-icon">{tab.icon}</div>
<div className="mgs-mode-info">
<h3>{tab.title}</h3>
<p>{tab.desc}</p>
</div>
</div>
))}
</div>
<div className="mgs-workflow">
<div className="mgs-workflow-title"></div>
<div className="mgs-workflow-steps">
{workflowSteps.map((step, i) => (
<span key={step.label}>
{i > 0 && <span className="mgs-wf-arrow"></span>}
<span className={`mgs-wf-step${step.active ? " is-active" : ""}`}>{step.label}</span>
</span>
))}
</div>
</div>
</div>
{/* Center Area */}
<div className="mgs-center-area">
<div className="mgs-input-card">
{/* Agent Mode */}
{mode === "agent" && (
<div className="mgs-mode-content is-active">
<div className="mgs-card-header">
<div className="mgs-card-mode-badge"><span className="mgs-dot" /> Agent </div>
<div className="mgs-card-status">线 · GPT-4o</div>
</div>
<div className="mgs-prompt-area">
<textarea
className="mgs-prompt-input"
placeholder="描述你的需求...&#10;例如:帮我生成一段智能手表的营销文案,突出健康监测功能"
readOnly
/>
</div>
<div className="mgs-options">
{["营销文案", "产品描述", "剧本大纲", "数据分析"].map((opt, i) => (
<span key={opt} className={`mgs-opt${i === 0 ? " is-selected" : ""}`}>{opt}</span>
))}
</div>
<div className="mgs-agent-output-area">
<div className="mgs-agent-result">
<div className="mgs-agent-result-label">AI </div>
<div className="mgs-agent-result-text">
</div>
</div>
</div>
<div className="mgs-chat-input-row">
<input className="mgs-chat-input" placeholder="继续对话或修改需求..." readOnly />
<button className="mgs-chat-send" type="button" tabIndex={-1}> </button>
</div>
</div>
)}
{/* Image Mode */}
{mode === "image" && (
<div className="mgs-mode-content is-active">
<div className="mgs-card-header">
<div className="mgs-card-mode-badge"><span className="mgs-dot" /> </div>
<div className="mgs-card-status">SDXL · Flux</div>
</div>
<div className="mgs-prompt-area">
<textarea
className="mgs-prompt-input"
placeholder="描述你想生成的图片...&#10;例如:未来科技感城市,赛博朋克风格,霓虹灯光"
readOnly
/>
</div>
<div className="mgs-options">
{["写实风", "插画风", "电商风", "3D渲染"].map((opt, i) => (
<span
key={opt}
className={`mgs-opt${selectedImageOpt === i ? " is-selected" : ""}`}
onClick={() => setSelectedImageOpt(i)}
>
{opt}
</span>
))}
</div>
<div className="mgs-img-grid">
<div className="mgs-img-cell">🎨</div>
<div className="mgs-img-cell">🖼</div>
<div className="mgs-img-cell"></div>
<div className="mgs-img-cell">🌈</div>
</div>
</div>
)}
{/* Video Mode */}
{mode === "video" && (
<div className="mgs-mode-content is-active">
<div className="mgs-card-header">
<div className="mgs-card-mode-badge"><span className="mgs-dot" /> </div>
<div className="mgs-card-status">Sora · Kling</div>
</div>
<div className="mgs-video-config">
<div className="mgs-config-row">
<span className="mgs-config-label"></span>
<span className="mgs-config-value">1080p</span>
</div>
<div className="mgs-config-row">
<span className="mgs-config-label"></span>
<span className="mgs-config-value">15s</span>
</div>
<div className="mgs-config-row">
<span className="mgs-config-label"></span>
<span className="mgs-config-value">30fps</span>
</div>
<div className="mgs-config-row">
<span className="mgs-config-label"></span>
<span className="mgs-config-value"></span>
</div>
</div>
<div className="mgs-video-preview">
<div className="mgs-play-btn">
<svg viewBox="0 0 24 24"><polygon points="6,3 20,12 6,21" /></svg>
</div>
</div>
<div className="mgs-video-timeline">
<div className="mgs-video-timeline-fill" />
</div>
</div>
)}
</div>
</div>
{/* Right Panel */}
<div className="mgs-right-panel">
{/* Agent Outputs */}
{mode === "agent" && (
<div className="mgs-output-section">
<div className="mgs-section-label">
<span className="mgs-section-dot is-green" />
Agent
</div>
<div className="mgs-output-cards">
{AGENT_OUTPUTS.map((item) => (
<div key={item.title} className="mgs-out-card">
<div className="mgs-out-card-top">
<span className="mgs-out-tag">{item.tag}</span>
<span className="mgs-out-title">{item.title}</span>
</div>
<div className="mgs-out-preview">{item.preview}</div>
</div>
))}
</div>
</div>
)}
{/* Image Outputs */}
{mode === "image" && (
<div className="mgs-output-section">
<div className="mgs-section-label">
<span className="mgs-section-dot is-blue" />
</div>
<div className="mgs-output-cards">
{IMAGE_OUTPUTS.map((item) => (
<div key={item.title} className="mgs-out-card">
<div className="mgs-out-card-top">
<span className="mgs-out-tag is-img">{item.tag}</span>
<span className="mgs-out-title">{item.title}</span>
</div>
<div className={`mgs-out-img-placeholder is-${item.styleClass}`}>{item.icon}</div>
</div>
))}
</div>
</div>
)}
{/* Video Outputs */}
{mode === "video" && (
<div className="mgs-output-section">
<div className="mgs-section-label">
<span className="mgs-section-dot is-purple" />
</div>
<div className="mgs-output-cards">
{VIDEO_OUTPUTS.map((item) => (
<div key={item.title} className="mgs-out-card">
<div className="mgs-out-card-top">
<span className="mgs-out-tag is-video">{item.tag}</span>
<span className="mgs-out-title">{item.title}</span>
</div>
<div className="mgs-out-video-placeholder">
<div className="mgs-mini-play">
<svg viewBox="0 0 24 24"><polygon points="6,3 20,12 6,21" /></svg>
</div>
<span className="mgs-video-duration">{item.duration}</span>
</div>
</div>
))}
</div>
</div>
)}
</div>
</div>
);
}
export default ModelGenerationShowcase;