我用 UniApp + 腾讯云 IAI 做了一个"明星脸比对"小程序,零后台延迟

13 阅读6分钟

我用 UniApp + 腾讯云 IAI 做了一个"明星脸比对"小程序,零后台延迟

最近花了些时间做了一个微信小程序——明星脸比对。用户上传一张照片,AI 就能找出和你最像的明星。

这个项目有点意思,因为它采用了一个不太常见的架构:前端直调腾讯云 IAI,云函数只存密钥,API 签名在前端完成。没有后台中转,零额外延迟。

今天就来聊聊这个项目的开发过程和一些技术取舍。

为什么做这个项目

想法其实很简单:大家都好奇自己长得像哪个明星。市面上类似的小程序不少,但大多需要把图片传到自己的服务器,经过后台处理后再调用 AI 服务。这样不仅慢,还增加了服务器成本。

我就在想,能不能让前端直接调用腾讯云的人脸识别服务?这样既快又省钱。

技术栈选择

前端用了 UniApp + Vue.js,目标是微信小程序。选择 UniApp 是因为一套代码可以跑多端,虽然这次只做小程序,但以后扩展方便。

人脸识别用的是腾讯云 IAI(人脸搜索 3.0) 。这个服务支持在指定人员库中搜索相似人脸,返回 Top K 结果和相似度分数,正好符合需求。

后台用 Flask (Python) ,但注意,这个后台不是小程序运行必需的。它只用于批量管理人员库数据——添加明星、删除明星、初始化人员库等。小程序本身不经过这个后台。

核心架构:前端直调

这是整个项目最关键的设计决策。

传统做法是:用户上传图片 → 传到自己的服务器 → 服务器调用腾讯云 API → 返回结果。多了一跳,延迟增加,服务器还要承担转发成本。

我的做法是:用户上传图片 → 前端完成 TC3-HMAC-SHA256 签名 → 直接调用腾讯云 IAI SearchFaces 接口 → 返回结果。

云函数在这里只做一件事:安全地存储腾讯云密钥。前端通过云函数获取临时密钥,然后在前端完成 API 签名。这样既保证了密钥安全,又实现了零中转延迟。

图片处理流程

前端处理图片的流程需要仔细设计:

  1. 用户选择图片:支持拍照和相册选择,优先使用 uni.chooseMedia,兼容降级到 uni.chooseImage
  2. 图片压缩:这是关键一步。人脸图片不需要太高分辨率,压缩到 800px 以内可以大幅减少传输时间。先用 uni.compressImage 做质量压缩,如果图片过大再用 canvas 做尺寸压缩。
  3. 上传到云存储:压缩后的图片上传到 uniCloud 云存储,获取永久 URL。这个 URL 用于结果页展示和分享功能。
  4. 转 base64:读取压缩后的图片文件,转换为 base64 编码,用于调用人脸搜索接口。
  5. 调用云函数:通过 uniCloud 云函数进行人脸检测和搜索。云函数内部完成签名和 API 调用。

人员库管理

腾讯云 IAI 的人脸搜索需要在指定的人员库中进行。所以第一步是建立一个明星人员库。

后台提供了完整的 CRUD 接口:

  • 创建人员库
  • 批量添加明星(从 JSON 文件导入)
  • 搜索人脸
  • 删除明星/人员库

初始化脚本 add_stars.py 会读取 data/new_cloud/ 目录下的所有 JSON 文件,批量导入到腾讯云人员库。每个明星数据包含 person_id、name、gender、url(照片 URL)等信息。

还有一个爬虫脚本 scrape_category.py,可以从网站抓取明星数据,自动生成 JSON 文件。

积分系统设计

小程序做了一个简单的积分系统:

  • 每次比对消耗 5 积分
  • 分享给好友可获得 5 积分
  • 观看视频广告可获得 5 积分

这个设计有两个目的:一是控制 API 调用频率(腾讯云按次计费),二是通过分享实现自然增长。

积分查询和扣除通过后端 API 完成,前端只负责展示和触发。

结果展示

结果页的设计花了些心思:

  • 对比展示:左边是用户上传的照片,右边是最匹配的明星,中间用 VS 图标连接,视觉冲击力强。
  • 相似度进度条:把腾讯云返回的分数转换成百分比,用渐变色进度条展示,直观易懂。
  • 其他相似明星:除了最匹配的一个,还展示 Top 2-5 的其他候选,增加趣味性。
  • 分享优化:分享时带上用户照片作为封面,标题显示"我和 XX 相似度 XX%",吸引点击。

1.png

2.png

3.png

4.png

5.png

踩过的坑

开发过程中遇到几个值得注意的问题:

1. 图片压缩比例问题

一开始用 canvas 压缩图片时,没有保持原始宽高比,导致人脸变形,识别率大幅下降。后来改为先获取图片信息,计算缩放比例,再用 canvas 等比例绘制。

2. 云函数调用失败

前端直接调用腾讯云 API 时,签名算法容易出错。TC3-HMAC-SHA256 签名需要严格按照腾讯云文档的步骤来,包括 CanonicalRequest、StringToSign 等。建议先用官方 SDK 测试,确认签名逻辑正确后再移植到前端。

3. 人员库初始化

批量导入明星数据时,API 有频率限制。一开始没有加延迟,导致部分请求被限流。后来在每次请求后加了 0.3-0.5 秒的间隔,问题解决。

项目结构

mingxing_face/
├── admin/                              # 后台管理(仅用于初始化/管理人员库)
│   ├── app.py                          # Flask 管理服务
│   ├── config.py                       # 腾讯云 API 配置
│   ├── tencent_iai.py                  # 腾讯云 IAI SDK 封装
│   ├── add_stars.py                    # 一键初始化 IAI 人员库
│   ├── scrape_category.py              # 明星数据爬取脚本
│   └── data/                           # 明星数据与图片
│
├── star_face_uniapp/                   # UniApp 前端(微信小程序)
│   ├── pages/index/index.vue           # 首页:拍照/选图 → 人脸搜索
│   └── pages/result/result.vue         # 结果页:展示 Top5 相似明星
│   └── uniCloud/                       # 云函数(仅存储密钥)

总结

这个项目的核心价值在于架构简化。通过前端直调云服务,省去了中间服务器层,降低了延迟和成本。

当然,这种架构也有局限:

  • 前端签名逻辑暴露了部分实现细节(虽然密钥是安全的)
  • 不适合需要复杂业务逻辑的场景
  • 云函数的冷启动时间仍然会影响首次调用速度

但对于这种"上传-处理-返回"的简单场景,前端直调是一个值得考虑的方案。

项目代码已经开源,如果你也感兴趣,可以看看完整实现。欢迎提 issue 或 PR。

github.com/liandyao/ai…


技术栈:UniApp + Vue.js | 腾讯云 IAI | uniCloud | Flask | Python

适用场景:人脸识别、图片比对、AI 趣味应用