83 lines
2.6 KiB
TypeScript
83 lines
2.6 KiB
TypeScript
import { useRef, useState } from "react";
|
|
import { Button, Surface, EmptyState, Tag } from "../components/primitives";
|
|
|
|
export function VisionMode(): React.ReactNode {
|
|
const [preview, setPreview] = useState<string | null>(null);
|
|
const [analyzing, setAnalyzing] = useState(false);
|
|
const [tags, setTags] = useState<string[]>([]);
|
|
const fileRef = useRef<HTMLInputElement>(null);
|
|
|
|
const onFile = (file: File | undefined) => {
|
|
if (!file) return;
|
|
setPreview(URL.createObjectURL(file));
|
|
setTags([]);
|
|
};
|
|
|
|
const analyze = () => {
|
|
if (!preview) return;
|
|
setAnalyzing(true);
|
|
// 占位分析:真实实现会调用视觉模型,此处演示加载态并给出结果。
|
|
window.setTimeout(() => {
|
|
setAnalyzing(false);
|
|
setTags(["图像", "占位分析", "视觉模型待接入"]);
|
|
}, 900);
|
|
};
|
|
|
|
return (
|
|
<div className="mx-auto max-w-3xl space-y-5 p-4">
|
|
<div>
|
|
<h2 className="text-lg font-semibold">视觉</h2>
|
|
<p className="text-sm text-[var(--mu-text-lo)]">图像分析</p>
|
|
</div>
|
|
|
|
<input
|
|
ref={fileRef}
|
|
type="file"
|
|
accept="image/*"
|
|
className="hidden"
|
|
onChange={(e) => onFile(e.target.files?.[0])}
|
|
/>
|
|
|
|
<button
|
|
onClick={() => fileRef.current?.click()}
|
|
className="flex min-h-[16rem] w-full flex-col items-center justify-center gap-3 rounded-[var(--mu-radius-lg)] border border-dashed border-[var(--mu-glass-border)] bg-[var(--mu-surface-2)]/40 p-4"
|
|
>
|
|
{preview ? (
|
|
<img src={preview} alt="预览" className="max-h-64 rounded-[var(--mu-radius)] object-contain" />
|
|
) : (
|
|
<EmptyState icon="👁" title="点击上传图片" hint="支持拖拽/点选,占位实现,视觉模型待接入" />
|
|
)}
|
|
</button>
|
|
|
|
<div className="flex items-center gap-2">
|
|
<Button variant="primary" onClick={analyze} disabled={!preview || analyzing}>
|
|
{analyzing ? "分析中…" : "开始分析"}
|
|
</Button>
|
|
{preview ? (
|
|
<Button
|
|
variant="ghost"
|
|
onClick={() => {
|
|
if (preview) URL.revokeObjectURL(preview);
|
|
setPreview(null);
|
|
setTags([]);
|
|
}}
|
|
>
|
|
清除
|
|
</Button>
|
|
) : null}
|
|
</div>
|
|
|
|
{tags.length > 0 ? (
|
|
<Surface className="flex flex-wrap items-center gap-2">
|
|
<span className="text-xs text-[var(--mu-text-lo)]">识别结果</span>
|
|
{tags.map((t) => (
|
|
<Tag key={t} tone="accent">
|
|
{t}
|
|
</Tag>
|
|
))}
|
|
</Surface>
|
|
) : null}
|
|
</div>
|
|
);
|
|
}
|