《60天AI学习计划启动 | Day 31:前端 + 多模态 AI(图片 / 文件 / 截图》
Day 31:前端 + 多模态 AI(图片 / 文件 / 截图)
学习目标
- 理解 前端如何把图片/文件接入 AI(不只文本)
- 掌握 基础多模态场景:图片描述、表格截图识别、PDF/Excel 解析入口
- 会设计 通用的「上传 → 预览 → 调用 AI → 展示结果」前端流程
核心知识点
-
多模态入口形态
- 上传文件:图片(JPG/PNG)、PDF、Excel、纯文本
- 截图/粘贴:
onPaste+DataTransfer处理图片/富文本 - 拖拽:
dragover/drop区域快速投喂文件 - 统一抽象:
{ id, type: 'image'|'pdf'|'excel'|'text', file|url|content, meta }
-
与后端交互模式
- 模式 A:先上传 → 返回
fileId/url→ 携带question + files[]调 AI - 模式 B:前端直接读小文件内容(txt/csv),拼进 prompt 作为 context
- Payload 示例:
{ "question": "帮我总结这张表格的关键信息", "files": [ { "id": "file_xxx", "type": "image", "url": "https://..." } ] }
- 模式 A:先上传 → 返回
-
UI / UX 要点
- 上传区:空态 / 上传中 / 成功 / 失败
- 文件列表:名称、类型、大小、删除、缩略图/图标预览
- 与聊天结合:消息中展示「附带了 N 个文件」+ 可点击预览;AI 回答中可以引用「文件1」
实战作业 + 代码示例
- 作业 1:多模态输入组件 props
export type MultiModalFileType = 'image' | 'pdf' | 'excel' | 'text' | 'other'
export interface MultiModalFile {
id: string
type: MultiModalFileType
file: File
previewUrl?: string
meta?: Record<string, any>
}
export interface MultiModalInputProps {
acceptTypes?: string[]
maxSize?: number
multiple?: boolean
maxCount?: number
disabled?: boolean
onFilesChange: (files: MultiModalFile[]) => void
onError?: (msg: string) => void
}
- 作业 2:图片 + 问题调用流程(简化版)
function ImageQA() {
const [file, setFile] = useState<File | null>(null)
const [preview, setPreview] = useState<string | null>(null)
const [question, setQuestion] = useState('')
const [answer, setAnswer] = useState('')
const [loading, setLoading] = useState(false)
const onFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const f = e.target.files?.[0]
if (!f) return
if (!f.type.startsWith('image/') || f.size > 5 * 1024 * 1024) {
alert('只支持 5MB 以内图片')
return
}
setFile(f)
setPreview(URL.createObjectURL(f))
}
const onSend = async () => {
if (!file || !question.trim()) return
setLoading(true); setAnswer('')
try {
const form = new FormData()
form.append('file', file)
const upRes = await fetch('/api/upload', { method: 'POST', body: form })
const { fileId } = await upRes.json()
const chatRes = await fetch('/api/image-qa', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ question: question.trim(), files: [{ id: fileId, type: 'image' }] })
})
const data = await chatRes.json()
setAnswer(data.answer)
} finally {
setLoading(false)
}
}
return (
<div>
<input type="file" accept="image/*" onChange={onFileChange} />
{preview && <img src={preview} style={{ maxWidth: 200 }} />}
<textarea value={question} onChange={e => setQuestion(e.target.value)} />
<button disabled={loading || !file || !question.trim()} onClick={onSend}>
{loading ? '分析中…' : '发送'}
</button>
{answer && <div>AI:{answer}</div>}
</div>
)
}
- 作业 3:5 个多模态场景(demo)
- 报表截图 → AI 解释趋势
- UI 截图 → AI 找间距/对齐问题
- 表格截图 → AI 抽取为 JSON
- 报错弹窗截图 → AI 分析原因
- 线框草图 → AI 生成初版 HTML/CSS 结构建议

浙公网安备 33010602011771号