当前位置: 首页 > news >正文

慧视项目的图片上传与前后端联通实现

实现代码

后端

核心思想

  1. 流式推理驱动的低延迟体验
    接口使用流式响应(SSE)逐步推送模型生成的文本片段,避免等待完整结果,提高交互性。系统在首个字符到达时记录首字延迟,用于衡量实时性。
  2. 任务链路一体化
    一次请求同时完成图像上传、模型调用、流式响应和性能指标记录,形成闭环链路:输入 → 推理 → 输出 → 指标回写。
  3. 可量化的性能监控
    每次请求都会记录首字延迟与总延迟,写入数据库,实现真实线上性能可追踪,可用于 SLA 与优化分析。
  4. 轻量化本地持久化
    使用 SQLite 作为本地日志存储,降低部署成本,便于快速验证和调试,也能平滑迁移到更重型数据库。

代码逻辑

  1. 应用初始化
    • 创建 FastAPI 实例。
    • 启动时调用 init_db() 初始化数据库表。
    • 设置 dashscope.api_key。
  2. 接口 /v1/vision/analyze
    • 生成 request_id 并记录起始时间。
    • 读取上传图片,校验非空,转为 Base64。
  3. 流式生成 event_generator
    • 调用 DashScope 多模态模型,开启 stream=True。
    • 循环读取流式返回:
    • 取出当前累计文本。
    • 计算新增内容并 yield 给客户端。
    • 第一次有新增内容时记录首字时间。
  4. 统计与落库
    • 流结束后计算:
    • 首字延迟 first_latency
    • 总延迟 total_latency
    • 写入 VisionLog 表(请求 ID、图片信息、AI 结果、延迟指标)。
  5. 响应
    • 返回 StreamingResponse,媒体类型为 text/event-stream。

前端

拍照上传

在环境配置的 envList.js 中新增后端地址配置

先用快速分析测试前后端联通
流程是“创建相机控制器 → 拍照 → 成功就拿到图片路径并上传分析,失败就提示用户”。

核心思想是将“拍照识别”做成一个前端到后端的异步流水线:先用小程序相机拍照,再把照片上传给 AI 服务处理,最后把识别结果反馈给用户。整体流程是事件驱动的,用户点一次按钮,就触发一次完整的采集、上传、识别、展示。

代码逻辑

  • quickAnalysis()负责发起拍照。它先创建相机上下文wx.createCameraContext(),然后调用takePhoto()
  • 拍照成功后,微信会返回临时图片路径tempImagePath,代码把这个路径交给uploadAndAnalyze(filePath)
  • uploadAndAnalyze()先显示“正在识别…”的加载提示,告诉用户当前在处理。
  • 然后通过wx.uploadFile()把图片上传到后端接口/v1/vision/analyze
  • formData里带了mode: this.data.activeMode,这表示当前识别模式会一起传给后端,后端可以据此决定按“会视”还是“出行”逻辑来分析。
  • 后端返回结果后,前端用JSON.parse(res.data)解析响应,取出result.description
  • 最后用wx.showModal()把识别结果展示给用户。
  • 无论成功还是失败,complete都会执行wx.hideLoading(),保证加载态被清理掉。

消息发送功能

核心思想是把用户输入的文字当作“对话请求”,校验后发给后端聊天接口,并在发送成功后清空输入框,形成一个最小闭环的消息发送流程。

代码逻辑

  1. 先读取输入框内容inputValue,并用trim()去掉首尾空白。
  2. 如果内容为空,直接返回,避免发出无效请求。
  3. 通过wx.request()${API_URL}/api/chat发送一个 POST 请求。
  4. 请求体里带了两个字段:query是用户输入内容,mode是当前页面模式activeMode

前后端联通测试

本机测试

后端:
uvicorn.run(app, host="0.0.0.0", port=8000)

前端:
API_URL = "http://127.0.0.1:8000"

局域网测试

电脑连接手机 Wifi,关闭防火墙。

将前端的 API_URL 中的 127.0.0.1 改成上一步中的地址。

内网穿透

使用平台贝锐蒲公英

源码

后端:

@app.post("/v1/vision/analyze") async def analyze_scene(file: UploadFile = File(...)): request_id = str(uuid.uuid4()) start_time = time.time() content = await file.read() if not content: raise HTTPException(status_code=400, detail="图片上传失败") base64_image = base64.b64encode(content).decode("utf-8") async def event_generator(): full_content = "" first_token_time = None responses = dashscope.MultiModalConversation.call( model="qwen-vl-plus", messages=[{"role": "user", "content": [ {"image": f"data:image/jpeg;base64,{base64_image}"}, {"text": "你是一位视障人士向导。请简洁描述正前方2米内的障碍物及方位。"} ]}], stream=True ) for response in responses: if response.status_code == 200: current_full_text = response.output.choices[0].message.content[0]["text"] new_content = current_full_text[len(full_content):] full_content = current_full_text if not first_token_time and new_content: first_token_time = time.time() if new_content: yield new_content else: yield f"Error: {response.message}" end_time = time.time() first_latency = (first_token_time - start_time) * 1000 if first_token_time else 0 total_latency = (end_time - start_time) * 1000 db = SessionLocal() try: log_entry = VisionLog( request_id=request_id, image_path=file.filename, ai_result=full_content, first_token_latency=first_latency, total_latency=total_latency ) db.add(log_entry) db.commit() print(f"日志已存库: ReqID={request_id}, 首字延迟={first_latency:.2f}ms") except Exception as e: print(f"数据库写入失败: {e}") finally: db.close() return StreamingResponse(event_generator(), media_type="text/event-stream")

前端:
index.js

// 流程是“创建相机控制器 → 拍照 → 成功就拿到图片路径并上传分析,失败就提示用户”。 quickAnalysis() { const ctx = wx.createCameraContext(); ctx.takePhoto({ quality: 'normal', success: (res) => { const tempFilePath = res.tempImagePath; this.uploadAndAnalyze(tempFilePath); // 调用上传函数 }, fail: () => { wx.showToast({ title: '拍照失败', icon: 'none' }); } }); }, // 发送图片到后端进行 AI 分析 uploadAndAnalyze(filePath) { wx.showLoading({ title: '正在识别...' }); wx.uploadFile({ url: `${API_URL}/v1/vision/analyze`, // 后端接口路径 filePath: filePath, name: 'file', // 后端接收文件的字段名 formData: { 'mode': this.data.activeMode // 传入当前模式:出行或会视 }, success: (res) => { const result = JSON.parse(res.data); console.log('分析结果:', result.description); wx.showModal({ title: '识别结果', content: result.description, showCancel: false }); }, fail: (err) => { console.error('联调失败:', err); wx.showToast({ title: '网络请求失败', icon: 'none' }); }, complete: () => { wx.hideLoading(); } }); }, // 发送消息 sendMessage() { const value = this.data.inputValue.trim(); if (!value) return; wx.request({ url: `${API_URL}/api/chat`, // 后端接口路径 method: 'POST', data: { query: value, mode: this.data.activeMode }, success: (res) => { // 处理对话结果 this.setData({ inputValue: '' }); } }); },

vision.js:

// 拍照功能 takePhoto() { const ctx = wx.createCameraContext(); ctx.takePhoto({ quality: 'high', success: (res) => { console.log('照片路径:', res.tempImagePath); // 联调关键:将照片上传至后端 wx.uploadFile({ url: `${API_URL}/api/vision-identify`, // 后端接口路径 filePath: res.tempImagePath, name: 'image', success: (uploadRes) => { wx.showToast({ title: '识别中...', icon: 'loading' }); // 处理识别逻辑 } }); }, fail: (err) => { console.error(err); wx.showToast({ title: '拍照失败', icon: 'none' }); } }); }
http://www.jsqmd.com/news/647605/

相关文章:

  • WindowResizer技术解密:打破Windows窗口限制的数字助手
  • 验收检测报告怎么写才靠谱
  • 爱依克KF-05C可视电子签名板重磅来袭
  • 【多模态大模型监控告警体系构建指南】:20年SRE专家亲授5大核心模块、7类典型失效场景与实时拦截SOP
  • 区块链隐私保护技术
  • 16.修正 LangGraph Agent 的路由层,让 Router 真正只负责选工具
  • 跨境电商商品采集skill来了,可部署openclaw,不用Python也能搞定爬虫
  • 为什么Redis的KEYS命令在生产环境是禁止使用的?
  • 运维工程师最后的护城河正在崩塌?:多模态大模型自动解析监控截图、语音工单、异常堆栈的3层可信推理机制
  • 网络运维Windows Server管理
  • 计算机毕业设计:Python全国降水数据采集与预警平台 Flask框架 数据分析 可视化 大数据 AI 大模型 爬虫 数据大屏(建议收藏)✅
  • 便携式综合气象观测仪
  • NLP学习笔记03:文本分类——从 TF-IDF 到 BERT
  • 嵌入式学习day3:数组与结构体
  • 【独家首发】央企信创云实战:基于Qwen-VL与InternVL的多模态运维Agent(已通过等保2.0三级认证)
  • CodeQ 项目数据库设计
  • 数学建模研究者可通过爱毕业(aibiye)快速实现论文复现与自动化排版
  • amcl_pose vs tf的位姿输出频率
  • SpringBoot入门核心要点
  • 零知识证明系统:zk-SNARK协议的工作原理与构造
  • 基于MPC模型预测控制的风电与储能调频策略:实时调整风电出力,仿真对比展现优越性
  • 【GitHub项目推荐--Plane:开源版 JIRA,让项目管理回归“有序”】⭐⭐⭐
  • 负载因子才0.5,unordered_map就有30%的桶在碰撞——读libstdc++源码看懂Google为什么要造absl::flat_hash_map
  • Web 品质可读性
  • Spring Data 2027 高级查询技巧:构建高效的数据访问层
  • 构建垂直领域专家级AI Agent的方法论
  • Windows系统iPhone USB网络共享驱动终极安装与优化指南
  • SMRT借助AI与数据分析技术预测轨道故障并提升维护效率
  • 从阻容复位到专用芯片:以MAX706为例,解析MCU看门狗复位电路的设计升级
  • C语言完美演绎8-3