React智能前端:从零开始写的图片分析页面实战

一、项目用到的大模型------月之暗面简介

月之暗面(Moonshot AI),它所提供的moonshot-v1-8k-vision-preview模型,支持图像与文本的联合分析,我们可以通过API将图片和文本同时输入AI模型,获取智能分析结果。

该模型的特点如下:

  • 多模态输入:支持同时处理图片和文本
  • 高精度视觉理解:可识别图片中的物体、场景、文字等信息
  • 自然语言输出:以中文或英文返回分析结果

本项目通过调用月之暗面的API,构建一个具备图片上传、预览和AI分析功能的前端页面,演示如何将AI能力无缝集成到Web应用中。


二、开始前的准备

由于代码需要调用月之暗面大模型的接口,为此,我们需要先做好以下准备:

  1. 打开月之暗面官网

  2. 点击右上角用户中心进行登录

3.在左侧找到API Key 管理,随后新建API Key,创建后记得复制你的密钥。

  1. 在项目根目录下创建.env.local文件,随后按下面格式输入你的密钥: VITE_API_KEY= 你的密钥

注意事项

  • VITE_前缀是Vite框架的约定,确保环境变量在客户端可访问。
  • 生产环境建议通过后端中转API密钥,避免直接暴露。

三、服务代理配置

为解决跨域问题,我们使用Vite的代理功能,在vite.config.js进行以下配置:

vite.config.js 复制代码
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  server: {
    proxy: {
      '/api': {
        target: 'https://api.moonshot.cn',
        changeOrigin: true,
        rewrite: path => path.replace(/^\/api/, '/v1')
      }
    }
  }
})

作用

  • 将本地请求/api/chat/completions映射到https://api.moonshot.cn/v1/chat/completions, 避免浏览器的同源策略限制。

四、完整代码和效果展示

1. 效果展示

为了使屏幕前的你对接下来实现的功能有更明确的认识,我将先进行页面效果展示:

效果说明:在该页面中,用户可以通过上传一张本地的照图片,在点击提交后,ai便会生成一段描述该图片的文字。

2. 完整代码

App.jsx 复制代码
import { useState } from 'react'
import './App.css'

function App() {
  const [content, setContent] = useState('')
  const [imgBase64Data, setImgBase64Data] = useState('')
  const [isValid, setIsValid] = useState(false)
  const updateBase64Data = (e) => {
    const file = e.target.files[0]
    if (!file) return;
    const reader = new FileReader()
    reader.readAsDataURL(file) 
    reader.onload = () => {
      setImgBase64Data(reader.result)
      setIsValid(true)
    }
  }
  const update = async() => {
    if(!imgBase64Data) return;
    const endpoint = 'https://api.moonshot.cn/v1/chat/completions';
    const headers ={
      'Content-Type':'application/json',
      'Authorization':`Bearer ${import.meta.env.VITE_API_KEY}`
    }
    setContent('正在加载中...')
    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":imgBase64Data
                }
              },
              {
                type:'text',
                text:'请用中文描述图片'
              }
            ]
          }
        ],
      })
    })
    const data = await response.json()
    setContent(data.choices[0].message.content)
  }
  return (
    <div className="container">
       <div className="output">
        <div className="preview">
          {
            imgBase64Data && <img src={imgBase64Data} alt="" />
          }
        </div>
      </div>
      <div>
        <label htmlFor='fileInput'>文件:</label>
        <input
          type="file"
          id='fileInput'
          className='input'
          accept='.jpg,.png,.gif,.jpeg'
          onChange={updateBase64Data}
        />
        <button onClick={update} disabled={!isValid}>提交</button>
      </div>
      {content}
    </div>
  )
}
export default App

五、代码分析

5.1 导入模块和组件定义

jsx 复制代码
import { useState } from 'react'
import './App.css'

useState

  • React内置的Hook函数,用于管理响应式状态数据
  • 作用
    • 创建可变状态变量(content, imgBase64Data, isValid
    • 当状态更新时,自动触发组件重渲染

5.2 状态变量初始化

jsx 复制代码
  const [content, setContent] = useState('')
  const [imgBase64Data, setImgBase64Data] = useState('')
  const [isValid, setIsValid] = useState(false)

5.2.1 状态变量说明

变量名 类型 作用
content string 存储AI分析结果
imgBase64Data string 存储图片的Base64编码
isValid boolean 控制表单验证状态

5.2.2 技术点

  • 响应式更新:状态更新会触发组件重渲染
  • 初始值设定:空字符串表示未选择文件或未生成结果
  • 状态组合:三个状态共同管理应用的交互流程

5.3 图片处理函数 updateBase64Data

jsx 复制代码
  const updateBase64Data = (e) => {
    const file = e.target.files[0]
    console.log(file)
    if (!file) return;
    
    const reader = new FileReader()
    reader.readAsDataURL(file)
    
    reader.onload = () => {
      setImgBase64Data(reader.result)
      setIsValid(true)
    }
  }

5.3.1 文件操作流程

  1. 获取文件对象

    • e.target.files[0] 获取用户选择的第一个文件
    • File API 提供对本地文件的读取能力
  2. Base64编码转换

    • FileReader 异步读取文件内容
    • readAsDataURL() 将文件转为data:image/png;base64,iVBORw0KG...格式
  3. 状态更新

    • 通过onload回调处理异步结果
    • 更新imgBase64Data和表单验证状态

5.3.2 技术点详解

  • HTML5 File API
    • 允许JavaScript访问本地文件系统
    • 支持文件类型检测(file.type)、大小读取等
  • Base64编码
    • Data URLs格式:data:<mediatype>;<encoding>,<data>
    • 优点:直接嵌入图片数据,避免额外请求
    • 缺点:体积比原始文件大33%

5.4 AI分析函数 update

jsx 复制代码
  const update = async () => {
    if (!imgBase64Data) return;
    
    const endpoint = 'https://api.moonshot.cn/v1/chat/completions';
    const headers = {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${import.meta.env.VITE_API_KEY}`
    }
    
    setContent('正在加载中...')
    
    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": imgBase64Data } },
              { type: 'text', text: '请用中文描述图片' }
            ]
          }
        ],
      })
    })
    
    const data = await response.json()
    setContent(data.choices[0].message.content)
  }

5.4.1 API请求流程

  1. 请求准备

    • 构造API地址和请求头
    • 设置Bearer Token认证(通过环境变量注入)
  2. 请求体构建

    • 使用moonshot-v1-8k-vision-preview模型
    • 构建多模态输入内容(图片+文本指令)
  3. 异步处理

    • 使用async/await同步化异步操作
    • 通过fetch发起HTTP POST请求
  4. 结果处理

    • 解析JSON响应
    • 更新分析结果状态

5.4.2 技术点

  • HTTP请求头
    • Content-Type 声明请求体格式
    • Authorization Bearer Token认证
  • 多模态输入
    • 支持同时处理图像和文本
    • 消息结构符合OpenAI兼容格式
  • 错误处理缺失
    • 当前代码缺少try/catch异常捕获
    • 需补充错误提示逻辑(参考知识库中的错误示例)

5.5 UI渲染部分

jsx 复制代码
  return (
    <div className="container">
      <div className="output">
        <div className="preview">
          {
            imgBase64Data && <img src={imgBase64Data} alt="" />
          }
        </div>
      </div>
      <div>
        <label htmlFor='fileInput'>文件:</label>
        <input
          type="file"
          id='fileInput'
          className='input'
          accept='.jpg,.png,.gif,.jpeg'
          onChange={updateBase64Data}
        />
        <button onClick={update} disabled={!isValid}>提交</button>
      </div>

      {content}
    </div>
  )

5.5.1 组件结构分析

  • 容器布局

    • 使用container类控制整体布局
    • 包含预览区、操作区和结果展示区
  • 条件渲染

    • imgBase64Data && <img ... /> 实现图片存在时才渲染
    • 避免未选择文件时渲染空img标签
  • 表单交互

    • accept 属性限制可选文件类型
    • disabled={!isValid} 动态控制按钮可用状态

5.5.2 技术点

  • JSX语法
    • 使用&&操作符实现条件渲染
    • 表单元素通过onChange绑定处理函数
  • 无障碍设计
    • htmlForid 关联提升可访问性
    • 输入框添加accept属性限制文件类型


六、代码执行流程图

scss 复制代码
用户选择图片
   ↓
FileReader读取为Base64
   ↓
更新imgBase64Data和isValid状态
   ↓
点击提交按钮(disabled状态解除)
   ↓
构造API请求体
   ↓
发送POST请求到Moonshot API
   ↓
接收JSON响应
   ↓
解析并更新content状态
   ↓
页面重新渲染显示分析结果

七、总结

通过本文的实践,我们完成了以下目标:

  1. 集成月之暗面API:将AI视觉分析能力嵌入前端页面
  2. 实现核心功能
    • 图片上传与Base64编码转换
    • 动态预览与表单验证
    • 异步请求与结果展示
  3. 掌握关键技术点
    • React状态管理(useState
    • 文件操作与Base64编码
    • 原生JavaScript异步编程
    • Vite环境变量与代理配置
相关推荐
zwjapple1 小时前
docker-compose一键部署全栈项目。springboot后端,react前端
前端·spring boot·docker
像风一样自由20203 小时前
HTML与JavaScript:构建动态交互式Web页面的基石
前端·javascript·html
伍哥的传说3 小时前
React 各颜色转换方法、颜色值换算工具HEX、RGB/RGBA、HSL/HSLA、HSV、CMYK
深度学习·神经网络·react.js
aiprtem4 小时前
基于Flutter的web登录设计
前端·flutter
浪裡遊4 小时前
React Hooks全面解析:从基础到高级的实用指南
开发语言·前端·javascript·react.js·node.js·ecmascript·php
why技术4 小时前
Stack Overflow,轰然倒下!
前端·人工智能·后端
GISer_Jing4 小时前
0704-0706上海,又聚上了
前端·新浪微博
止观止4 小时前
深入探索 pnpm:高效磁盘利用与灵活的包管理解决方案
前端·pnpm·前端工程化·包管理器
whale fall4 小时前
npm install安装的node_modules是什么
前端·npm·node.js
墨风如雪5 小时前
苹果设备上的“大模型炼丹炉”:mlx-lm-lora,让你的 Mac 变身 AI 工作站!
aigc