评论

调用mediaCheckAsync并处理异步检测结果推送

调用mediaCheckAsync并处理异步检测结果推送的整体思路与具体代码实现

仅给出我的处理方式。如果你有更好的处理方式,欢迎在评论区讨论。

本人使用云开发,图片上传到云存储。

整体思路

具体场景(便于讨论):用户发布评论comment,图片上传到字段image_upload

  • 准备:在数据库里创建一个traceId集合;
  • 首先,用户上传图片,触发图片审核,并将traceId作为云存储路径;
  • 异步检测结果推送到来时,如果'suggest' != 'pass'
    • traceId和固定前缀拼出一个云存储的fileID
    • 在集合traceId,利用fileID作为一个字段创建一个对象
    • 利用fileID在相关集合(如comment)的相关字段(如image_upload)里找:如果找到则直接删除云存储中的fileID,找不到则不处理;
  • 用户点击提交,首先先创建相关对象(如一个comment对象,其中包括字段image_upload),创建成功后查询集合traceId的所有对象(违规图片集合),将现有图片列表和违规图片集合进行比较,删除违规图片,并对相关字段(如:image_upload移除违规图片的fileID)进行更新。

具体步骤和代码

1、创建云函数:checkContent(右键 cloudfunctions新建 Node.js 云函数 进行创建),上传并部署:云端安装依赖

//index.js
const cloud = require('wx-server-sdk');

cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV })

exports.main = async (event, context) => {
  const { value, scene } = event;
  const { OPENID } = cloud.getWXContext()
  try {
    let imageR = false;
    
    //检查 图片内容是否违规
    if (value) {
      imageR = await cloud.openapi.security.mediaCheckAsync({
        openid: OPENID,
        scene: scene,
        version: 2,
        media_type: 2,
        media_url: value
      })
    }
    return {
      imageR,   //图片检查返回值
    };
  } catch (err) {
    return err
  }
}

2、在某个page中的js文件中:

wx.chooseMedia({
      count: 9,
      sizeType: ['original', 'compressed'],
      mediaType: ['image'],
      sourceType: ['album', 'camera'],
      camera: 'back',
      success: res => {
        checkAndUploadManyImages(res.tempFiles, this)
      },
      fail: err => {
        console.log(err)
      },
})

其中,checkAndUploadManyImages 函数(放在Page({})之外)实现:

/**
 * 触发图片审核
 * @param {待审核图片列表} tempFiles 
 * @param {page = this} page 
 */
function checkAndUploadManyImages(tempFiles, page) {
  wx.showLoading({
    title: '上传中',
    mask: true
  })

  for (var i = 0; i < tempFiles.length; i++) {
    const { tempFilePath } = tempFiles[i]
    /**
     * 1、触发审核,获取traceId
     */
    wx.cloud.callFunction({
      name: 'checkContent',
      data: {
        value: wx.cloud.CDN({
          type: 'filePath',
          filePath: tempFilePath
        }),
        scene: 3 //场景枚举值(1 资料;2 评论;3 论坛;4 社交日志)
      },
      success: json => {
        console.log(json)
        const { traceId } = json.result.imageR
        /**
         * 2、将traceId作为图片的云存储路径
         */
        wx.cloud.uploadFile({
          cloudPath: traceId, // 上传至云端的路径
          filePath: tempFilePath, // 小程序临时文件路径
          success: res => {
            const { fileID } = res
            
            //data里:fileID: []。用于存放图片云存储路径。
            page.data.fileID.push(fileID)
            page.setData({
              fileID: page.data.fileID,
            })
            wx.hideLoading()
            wx.showToast({
              title: '上传成功 正在审核',
              icon: 'none'
            })
          },
          fail: err => {
            console.error('uploadFile err', err)
            wx.hideLoading()
            wx.showToast({
              icon: 'error',
              title: '上传失败',
            })
          }
        })
      },
      fail: err => {
        console.log('checkContent err', err)
      }
    })
  }
}

至此,只是触发了图片审核。接下来配置mediaCheckAsync的异步检测结果推送。

1、创建云函数 getMediaCheckResult,上传并部署:云端安装依赖

//index.js
const cloud = require('wx-server-sdk')

cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV })

const db = cloud.database();
const traceId = db.collection('traceId') //在此之前,请数据库创建traceId集合

const head = 'cloud://xxx-xxx/' //这里请观察图片云存储路径(可使用consloe.log进行输出查看),将共同的前缀替换这里的字符串

function deleteImage(fileId) {
  cloud.deleteFile({
    fileList: [fileId],
    success: res => {
      return res
    },
    fail: err => {
      return err
    }
  })
}

// 云函数入口函数
exports.main = async (event, context) => {
  const { result, trace_id, CreateTime } = event
  const { suggest } = result

  const fileId = head + trace_id;

  if (suggest != 'pass') {
    traceId.add({
      data: {
        fileId,
        CreateTime
      }
    }).then(() => {
       //下面根据需要替换成自己的集合
       db.collection('comment').where({
        image_upload: fileId
      }).get()
      .then(() => { deleteImage(fileId); })
      .catch((err) => { return err })
    })
  } else {
    return {
      suggest
    }
  }
}

2、点击“云开发”-“设置”-“其他设置”-“添加消息推送”-进行配置(下图)-“确定”

3、回到pagejs文件:

//用户点击“提交”触发的事件
sendContent: function() {
	  ...
          comment.add({
            data: {
              ...
              image_upload: that.data.fileID,
            },
          }).then((res) => {
            /**
            * 二、图片审核:处理异步检测结果推送
            */

            /**
             * 1、拿到全部的traceId集合(违规图片集合)
             */
            const { _id } = res
            traceId.orderBy('CreateTime', 'desc').get()
              .then((res) => {
                /**
                 * 2、删除上传图片列表中违规图片
                 */
                deleteInvalidImages(that.data.fileID, res.data).then((res) => {
                  /**
                   * 3、更新图片列表
                   */
                  comment.doc(_id).update({
                    data: {
                      image_upload: res
                    }
                  }).then(() => {
                    wx.hideLoading()
                  })
                })
              })
          })
}

其中,deleteInvalidImages函数实现:

/**
 * 删除已上传图片列表中的违规图片,并移除traceId对象
 * @param {已上传图片列表} fileIds 
 * @param {违规图片集合} cloudFileIds 
 */
async function deleteInvalidImages(fileIds, cloudFileIds) {
  return new Promise(async function (resolve, reject) {
    try {
      const promises = [];
      let fileIdsWithoutCommon = [];
      promises.push(new Promise((resolve, reject) => {
        // 找到数组 fileIds 和数组 cloudFileIds 共有的元素
        const common = fileIds.filter((elementA) =>
          cloudFileIds.some((elementB) => elementA === elementB.fileId)
        );

        // 删除数组 fileIds 中的共有元素
        fileIdsWithoutCommon = fileIds.filter((elementA) =>
          !cloudFileIds.some((elementB) => elementA === elementB.fileId)
        );
        /**
         * 删除云存储中的违规图片
         */
        wx.cloud.deleteFile({
          fileList: common,
          success: res => {
            console.log(res)
            resolve();
          },
          fail: err => {
            console.log(err)
            reject(err);
          }
        })

        /**
         * 移除traceId对象
         */
        traceId.where({
          fileId: _.in(common)
        }).remove({
          success: res => {
            console.log(res)
            resolve();
          },
          fail: err => {
            console.log(err)
            reject(err);
          }
        })
      }));

      await Promise.all(promises);
      resolve(fileIdsWithoutCommon);
    } catch (error) {
      reject(error);
    }
  })
}
最后一次编辑于  2023-02-26  
点赞 1
收藏
评论

2 个评论

  • Mr.Zhao
    Mr.Zhao
    2023-02-26

    云函数里面用wx.cloud.delete不报错吗

    2023-02-26
    赞同 1
    回复 3
    • noritake
      noritake
      2023-02-26
      感想指正!
      2023-02-26
      回复
    • Mr.Zhao
      Mr.Zhao
      2023-02-26回复noritake
      删除文件是可以传数组的,集合remove可以用_in批量删,循环一个一个处理效率很差
      2023-02-26
      1
      回复
    • noritake
      noritake
      2023-02-26回复Mr.Zhao
      感谢指点!已更新代码!
      2023-02-26
      回复
  • qw
    qw
    01-31

    一次可以检测多张图片吗

    01-31
    赞同
    回复
登录 后发表内容