本文介绍一个通过上传图片学习英语单词的交互系统。用户选择一张图片后,系统调用大模型分析内容,提取核心英文单词,并生成描述、例句和对话示例,最后通过语音合成播放该单词的发音,实现“看图学词”的完整流程。
前端通过文件输入框获取用户上传的图片,并将其转换为 Base64 格式的数据 URL,以便在后续请求中使用。图片预览通过 imgPreview 状态实时展示。
系统调用月之恋(Moonshot)的视觉大模型 API 进行图像分析。请求配置如下:
js
浅色版本
const endpoint = 'https://api.moonshot.cn/v1/chat/completions';
const headers = {
'Authorization': `Bearer ${import.meta.env.VITE_KIMI_API_KEY}`,
'Content-Type': 'application/json'
};
const response = await fetch(endpoint, {
method: 'POST',
headers,
body: JSON.stringify({
model: "moonshot-v1-8k-vision-preview",
messages: [
{
role: 'user',
content: [
{
type: 'image_url',
image_url: { url: data }
},
{
type: 'text',
text: userPrompt
}
]
}
]
})
});
提示词
const userPrompt = `
请仔细分析图片内容,并完成以下任务:
1. 找出最能代表该图片的一个核心英文单词。
- 要求:必须是 CEFR A1~A2 水平的简单词汇(如 child, dog, ball, eat, run),避免复杂词或抽象词。
- 如果图片有多个元素,请选择最突出、最中心的那个事物对应的单词。
2. 基于图片和所选单词,生成以下 JSON 格式的数据:
{
"image_description": "用一句话简要描述图片内容,客观准确。",
"representative_word": "选出的那个英文单词(小写)",
"example_sentence": "一个包含该单词的简单英文句子,主语优先用 'The' 或 'A',语法正确,A1水平。",
"explanation": "以 'Look at...' 开头,用简单英文解释图片与单词的关系。每句话单独一行(用 \\n 分隔),描述画面细节。最后一行提出一个与日常生活相关的简单问句。",
"example_replys": [
"用户可以用这个单词或句子回答的自然回复(英文)",
"另一个可能的回答,鼓励互动"
]
}
📌 注意事项:
- 所有字段必须基于图片实际内容,不要猜测或虚构。
- explanation 中每句话要短(不超过10词为佳),适合英语初学者阅读。
- example_replys 必须是日常口语化表达,能真实用于对话。
- 输出仅返回 JSON 对象,不要额外说明。
现在请开始分析图片:
`;
userPrompt 是一段结构化提示词,要求模型返回 JSON 格式的分析结果,包含图片描述、代表单词、例句、解释和回复示例。AI 返回结果后,前端解析 res.choices[0].message.content,并将各字段存入 React 状态:
const res = await response.json();
const example = JSON.parse(res.choices[0].message.content);
setWord(example.representative_word);
setSentence(example.example_sentence);
setExplanation(example.explanation);
setReplys(example.example_replys);
界面展示方面,核心单词和播放按钮居中显示。通过 detailExpand 状态控制详情展开:
<button onClick={() => setDetailExpand(!detailExpand)}>Talk about it</button>
{
!detailExpand ?
<div className='fold'></div> :
(
<div className="expand">
<img src={imgPreview} alt="" />
<div className="explaination">
<p>{explanation}</p>
</div>
<div className="reply">
<p>{replys[0]}</p>
{replys[1] && <p>{replys[1]}</p>}
</div>
</div>
)
}
语音播放功能通过调用字节跳动的 TTS 服务实现。为避免跨域问题,Vite 配置了代理:
server: {
proxy: {
'/tts': {
target: 'https://openspeech.bytedance.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^/tts/, ''),
},
},
}
前端请求 /tts 接口生成音频,收到 Base64 数据后,需转换为 Blob URL 才能播放:
function createBlobUrl(base64AudioData) {
const byteCharacters = atob(base64AudioData);
const byteArrays = [];
for (let i = 0; i < byteCharacters.length; i++) {
byteArrays.push(byteCharacters.charCodeAt(i));
}
const blob = new Blob([new Uint8Array(byteArrays)], { type: 'audio/mp3' });
return URL.createObjectURL(blob);
}
播放时创建 Audio 实例并调用 play():
const playAudio = async (audio) => {
const au = new Audio(audio);
au.play();
};
<div className="playAudio" onClick={() => playAudio(audio)}>
播放音频
</div>