Parcourir la source

调整yolo检测

yangg il y a 2 semaines
Parent
commit
96396c2f11

+ 248 - 42
pages/identity-verify/identity-verify.vue

@@ -101,6 +101,14 @@
           class="user-camera-video"
           :controls="false">
         </video>
+        <!-- 隐藏的离屏canvas用于录制期间的帧转图片(不影响UI) -->
+        <canvas v-if="useMiniProgramCameraComponent"
+                id="hiddenCaptureCanvas"
+                canvas-id="hiddenCaptureCanvas"
+                type="2d"
+                style="position:absolute;left:-9999px;top:-9999px;width:1px;height:1px;opacity:0;pointer-events:none;"
+                :width="frameCanvasWidth"
+                :height="frameCanvasHeight"></canvas>
       </div>
       
       <!-- 字幕/文本覆盖区域 -->
@@ -209,6 +217,9 @@
 </template>
 
 <script>
+// 使用非响应式引用存放小程序 canvas node,避免被Vue代理后访问width/height触发get拦截
+let hiddenCanvasNodeRef = null;
+let hiddenCanvasCtxRef = null;
 import { apiBaseUrl, personDetectionWsUrl } from '@/common/config.js';
 export default {
   name: 'IdentityVerify',
@@ -218,6 +229,16 @@ export default {
         followUpAudioUrl: '', // 追问音频URL
         audioContext: null, // 音频上下文
         followUpQuestions: [], // 追问问题列表
+        // 帧抓取相关
+        frameListener: null,
+        isFrameCapturing: false,
+        lastFrameCaptureAt: 0,
+        frameCaptureIntervalMs: 5000,
+        frameCanvasWidth: 320,
+        frameCanvasHeight: 240,
+        hiddenCanvasNode: null, // 仅用于调试展示,不在渲染中直接使用
+        hiddenCanvasCtx: null,  // 仅用于调试展示,不在渲染中直接使用
+        hiddenCanvasReady: false,
         isWaitingForAnswer: false, // 添加新的状态来控制是否在等待用户回答
         currentFollowUpIndex: -1, // 当前追问问题索引
         showSubtitleText: false, // 是否显示字幕
@@ -376,6 +397,10 @@ export default {
         
       }
     },
+  onReady() {
+    // 页面初次渲染完成后再初始化隐藏canvas,保证节点已生成
+    this.initHiddenCanvasNode(true);
+  },
   mounted() {
     this.fetchQuestions();
     //this.fetchFollowUpQuestions();
@@ -417,6 +442,8 @@ export default {
         });
       }
     });
+    // 兜底:mounted 后也尝试一次
+    this.initHiddenCanvasNode(false);
   },
   beforeDestroy() {
     // 移除截屏监听
@@ -424,6 +451,208 @@ export default {
     this.cleanupPersonDetectionWebSocket();
   },
       methods: {
+      // 初始化隐藏canvas,支持重试
+      initHiddenCanvasNode(fromReady = false, retries = 3) {
+        if (!this.useMiniProgramCameraComponent) return;
+        try {
+          const query = uni.createSelectorQuery().in(this);
+          query.select('#hiddenCaptureCanvas')
+            .fields({ node: true, size: true })
+            .exec((res) => {
+              const canvasNode = res && res[0] && res[0].node;
+              if (canvasNode && canvasNode.getContext) {
+                hiddenCanvasNodeRef = canvasNode;
+                hiddenCanvasCtxRef = canvasNode.getContext('2d');
+                // 可选:保留到data用于调试,但不要在渲染周期直接读写其属性
+                this.hiddenCanvasNode = canvasNode;
+                this.hiddenCanvasCtx = hiddenCanvasCtxRef;
+                this.hiddenCanvasReady = true;
+                console.info('隐藏canvas初始化成功(fromReady:', fromReady, ')');
+              } else {
+                console.warn('隐藏canvas未获取到node或不支持2D上下文(fromReady:', fromReady, ')');
+                if (retries > 0) {
+                  setTimeout(() => this.initHiddenCanvasNode(fromReady, retries - 1), 300);
+                }
+              }
+            });
+        } catch (e) {
+          console.warn('初始化隐藏canvas失败:', e);
+          if (retries > 0) {
+            setTimeout(() => this.initHiddenCanvasNode(fromReady, retries - 1), 300);
+          }
+        }
+      },
+      // 安全拍照再发送(非录制期)
+      safeTakePhotoAndSend() {
+        if (this.isFrameCapturing) return;
+        if (!this.personDetectionSocket || this.personDetectionSocket.readyState !== 1) return;
+        this.isFrameCapturing = true;
+        try {
+          this.cameraContext.takePhoto({
+            quality: 'low',
+            success: (res) => {
+              const tempFilePath = res && res.tempImagePath;
+              if (!tempFilePath) {
+                this.isFrameCapturing = false;
+                return;
+              }
+              uni.getFileSystemManager().readFile({
+                filePath: tempFilePath,
+                encoding: 'base64',
+                success: (r) => {
+                  try {
+                    const base64Image = r.data;
+                    if (!this.personDetectionSocket || this.personDetectionSocket.readyState !== 1) {
+                      return;
+                    }
+                    this.personDetectionSocket.send({
+                      data: JSON.stringify({
+                        type: 'person_detection',
+                        image_data: base64Image
+                      })
+                    });
+                  } finally {
+                    this.isFrameCapturing = false;
+                  }
+                },
+                fail: () => {
+                  this.isFrameCapturing = false;
+                }
+              });
+            },
+            fail: () => {
+              this.isFrameCapturing = false;
+            }
+          });
+        } catch (e) {
+          this.isFrameCapturing = false;
+        }
+      },
+
+      // 录制期间抓帧并经隐藏canvas导出为图片再发送(持续监听 + 节流)
+      startFrameStreamCapture() {
+        if (!this.useMiniProgramCameraComponent) { console.warn('帧抓取:非小程序相机,跳过'); return; }
+        if (!this.cameraContext || !this.cameraContext.onCameraFrame) { console.warn('帧抓取:cameraContext或onCameraFrame不可用'); return; }
+        if (this.frameListener && this.frameListener.stop) { /* 已启动 */ return; }
+        try {
+          const listener = this.cameraContext.onCameraFrame((frame) => {
+            const now = Date.now();
+            if (now - this.lastFrameCaptureAt < (this.frameCaptureIntervalMs || 5000)) return;
+            if (this.isFrameCapturing) return;
+            if (!this.hiddenCanvasReady || !hiddenCanvasCtxRef || !hiddenCanvasNodeRef) {
+              console.warn('帧抓取:隐藏canvas未就绪');
+              // 触发一次重试初始化,避免偶发未就绪
+              this.initHiddenCanvasNode(false, 2);
+              return;
+            }
+            if (!this.personDetectionSocket || this.personDetectionSocket.readyState !== 1) { console.warn('帧抓取:WebSocket未就绪'); return; }
+
+            this.isFrameCapturing = true;
+            this.lastFrameCaptureAt = now;
+            try {
+              const raw = frame && frame.data;
+              const frameW = (frame && frame.width) || this.frameCanvasWidth;
+              const frameH = (frame && frame.height) || this.frameCanvasHeight;
+              const canvas = hiddenCanvasNodeRef;
+              if (!canvas) { throw new Error('hiddenCanvasNode is undefined'); }
+              // 仅设置,不读取,避免未定义读取触发异常
+              canvas.width = frameW;
+              canvas.height = frameH;
+              const ctx = hiddenCanvasCtxRef;
+              if (!raw) { throw new Error('frame.data is undefined'); }
+              const rgba = raw instanceof Uint8ClampedArray ? raw : new Uint8ClampedArray(raw);
+              const imageData = ctx.createImageData(frameW, frameH);
+              imageData.data.set(rgba);
+              ctx.putImageData(imageData, 0, 0);
+
+              const exportSuccess = (tempFilePath) => {
+                uni.getFileSystemManager().readFile({
+                  filePath: tempFilePath,
+                  encoding: 'base64',
+                  success: (r) => {
+                    if (this.personDetectionSocket && this.personDetectionSocket.readyState === 1) {
+                      this.personDetectionSocket.send({
+                        data: JSON.stringify({ type: 'person_detection', image_data: r.data })
+                      });
+                      console.info('帧抓取:已发送图片');
+                    }
+                    this.isFrameCapturing = false;
+                  },
+                  fail: () => {
+                    console.warn('帧抓取:读取临时图片失败');
+                    this.isFrameCapturing = false;
+                  }
+                });
+              };
+
+              const doExport = () => {
+                // 优先使用 node.toTempFilePath,不可用时回退到 uni.canvasToTempFilePath(传入canvas与上下文)
+                if (canvas && typeof canvas.toTempFilePath === 'function') {
+                  canvas.toTempFilePath({
+                    fileType: 'jpg',
+                    quality: 0.5,
+                    success: (res) => exportSuccess(res.tempFilePath),
+                    fail: (err) => {
+                      console.warn('帧抓取:node.toTempFilePath 失败,回退到uni.canvasToTempFilePath', err);
+                      uni.canvasToTempFilePath({
+                        canvas: hiddenCanvasNodeRef,
+                        x: 0,
+                        y: 0,
+                        width: frameW,
+                        height: frameH,
+                        destWidth: frameW,
+                        destHeight: frameH,
+                        fileType: 'jpg',
+                        quality: 0.5,
+                        success: (res2) => exportSuccess(res2.tempFilePath),
+                        fail: (err2) => { console.warn('帧抓取:uni.canvasToTempFilePath 也失败', err2); this.isFrameCapturing = false; }
+                      }, this);
+                    }
+                  });
+                } else {
+                  uni.canvasToTempFilePath({
+                    canvas: hiddenCanvasNodeRef,
+                    x: 0,
+                    y: 0,
+                    width: frameW,
+                    height: frameH,
+                    destWidth: frameW,
+                    destHeight: frameH,
+                    fileType: 'jpg',
+                    quality: 0.5,
+                    success: (res3) => exportSuccess(res3.tempFilePath),
+                    fail: (err3) => { console.warn('帧抓取:uni.canvasToTempFilePath 失败', err3); this.isFrameCapturing = false; }
+                  }, this);
+                }
+              };
+
+              // 确保绘制已提交到画布,再导出
+              if (typeof canvas.requestAnimationFrame === 'function') {
+                canvas.requestAnimationFrame(() => doExport());
+              } else {
+                setTimeout(() => doExport(), 16);
+              }
+            } catch (err) {
+              console.warn('帧抓取:绘制或导出异常', err);
+              this.isFrameCapturing = false;
+            }
+          });
+          // 小程序需调用 start 启动监听
+          if (listener && listener.start) { listener.start(); console.info('帧抓取:监听已启动'); }
+          this.frameListener = listener;
+        } catch (e) {
+          console.warn('启动帧抓取监听失败,回退到拍照方案:', e);
+        }
+      },
+
+      stopFrameStreamCapture() {
+        try {
+          if (this.frameListener && this.frameListener.stop) {
+            this.frameListener.stop();
+          }
+        } catch (e) {}
+        this.frameListener = null;
+      },
       // ===== 追问次数控制:工具方法 =====
       getFollowUpLimit(jobPositionQuestionId) {
         if (!jobPositionQuestionId) return this.defaultFollowUpLimit;
@@ -1641,6 +1870,15 @@ export default {
     startRecordingAnswer() {
       console.log('开始录制用户回答');
       this.isRecording = true;
+      // 录制开始:重置帧抓取节流时间
+      this.lastFrameCaptureAt = 0;
+      // 录制开始:若人脸检测socket已就绪,立即启动帧抓取监听
+      try {
+        if (this.personDetectionSocket && this.personDetectionSocket.readyState === 1) {
+          if (!this.hiddenCanvasReady) { this.initHiddenCanvasNode(false, 3); }
+          this.startFrameStreamCapture();
+        }
+      } catch (e) {}
       
       // 记录录制开始时间
       this.recordingStartTime = Date.now();
@@ -2170,6 +2408,8 @@ export default {
       
       // 隐藏录制指示器
       this.isRecording = false;
+      // 停止帧监听(如有)
+      this.stopFrameStreamCapture();
       
       // 根据平台选择不同的停止录制方法
       const systemInfo = uni.getSystemInfoSync();
@@ -4766,6 +5006,7 @@ export default {
         clearInterval(this.personDetectionInterval);
       }
 
+      // 录制时走帧抓取,否则走拍照
       this.personDetectionInterval = setInterval(() => {
         try {
           if (!this.personDetectionSocket || !this.cameraContext) {
@@ -4773,51 +5014,16 @@ export default {
             return;
           }
 
-          this.cameraContext.takePhoto({
-            quality: 'low',
-            success: (res) => {
-              try {
-                const tempFilePath = res.tempImagePath;
-                if (!tempFilePath) {
-                  console.warn('人脸检测:未获取到有效的图片路径');
-                 
-                }
-                uni.getFileSystemManager().readFile({
-                  filePath: tempFilePath,
-                  encoding: 'base64',
-                  success: (res) => {
-                    try {
-                      const base64Image = res.data;
-                      if (!this.personDetectionSocket || this.personDetectionSocket.readyState !== 1) {
-                        console.warn('人脸检测:WebSocket连接已断开或未就绪');
-                        return;
-                      }
-                      this.personDetectionSocket.send({
-                        data: JSON.stringify({
-                          type: 'person_detection',
-                          image_data: base64Image
-                        })
-                      });
-                    } catch (wsError) {
-                      console.error('人脸检测:发送WebSocket数据时出错:', wsError);
-                    }
-                  },
-                  fail: (error) => {
-                    console.error('人脸检测:读取图片文件失败:', error);
-                  }
-                });
-              } catch (fileError) {
-                console.error('人脸检测:处理图片文件时出错:', fileError);
-              }
-            },
-            fail: (error) => {
-              console.error('人脸检测:拍照失败:', error);
-            }
-          });
+          if (this.isRecording && this.useMiniProgramCameraComponent) {
+            this.startFrameStreamCapture();
+          } else {
+            this.stopFrameStreamCapture();
+            this.safeTakePhotoAndSend();
+          }
         } catch (mainError) {
           console.error('人脸检测:主流程执行出错:', mainError);
         }
-      }, 5000);
+      }, this.frameCaptureIntervalMs || 5000);
     },
 
     cleanupPersonDetectionWebSocket() {

+ 281 - 63
unpackage/dist/dev/mp-weixin/pages/identity-verify/identity-verify.js

@@ -1,6 +1,8 @@
 "use strict";
 const common_vendor = require("../../common/vendor.js");
 const common_config = require("../../common/config.js");
+let hiddenCanvasNodeRef = null;
+let hiddenCanvasCtxRef = null;
 const _sfc_main = {
   name: "IdentityVerify",
   data() {
@@ -13,6 +15,18 @@ const _sfc_main = {
       // 音频上下文
       followUpQuestions: [],
       // 追问问题列表
+      // 帧抓取相关
+      frameListener: null,
+      isFrameCapturing: false,
+      lastFrameCaptureAt: 0,
+      frameCaptureIntervalMs: 5e3,
+      frameCanvasWidth: 320,
+      frameCanvasHeight: 240,
+      hiddenCanvasNode: null,
+      // 仅用于调试展示,不在渲染中直接使用
+      hiddenCanvasCtx: null,
+      // 仅用于调试展示,不在渲染中直接使用
+      hiddenCanvasReady: false,
       isWaitingForAnswer: false,
       // 添加新的状态来控制是否在等待用户回答
       currentFollowUpIndex: -1,
@@ -257,6 +271,9 @@ const _sfc_main = {
       this.initPersonDetectionWebSocket();
     }
   },
+  onReady() {
+    this.initHiddenCanvasNode(true);
+  },
   mounted() {
     this.fetchQuestions();
     this.checkAudioPermission();
@@ -294,12 +311,231 @@ const _sfc_main = {
         });
       }
     });
+    this.initHiddenCanvasNode(false);
   },
   beforeDestroy() {
     common_vendor.index.offUserCaptureScreen();
     this.cleanupPersonDetectionWebSocket();
   },
   methods: {
+    // 初始化隐藏canvas,支持重试
+    initHiddenCanvasNode(fromReady = false, retries = 3) {
+      if (!this.useMiniProgramCameraComponent)
+        return;
+      try {
+        const query = common_vendor.index.createSelectorQuery().in(this);
+        query.select("#hiddenCaptureCanvas").fields({ node: true, size: true }).exec((res) => {
+          const canvasNode = res && res[0] && res[0].node;
+          if (canvasNode && canvasNode.getContext) {
+            hiddenCanvasNodeRef = canvasNode;
+            hiddenCanvasCtxRef = canvasNode.getContext("2d");
+            this.hiddenCanvasNode = canvasNode;
+            this.hiddenCanvasCtx = hiddenCanvasCtxRef;
+            this.hiddenCanvasReady = true;
+            console.info("隐藏canvas初始化成功(fromReady:", fromReady, ")");
+          } else {
+            console.warn("隐藏canvas未获取到node或不支持2D上下文(fromReady:", fromReady, ")");
+            if (retries > 0) {
+              setTimeout(() => this.initHiddenCanvasNode(fromReady, retries - 1), 300);
+            }
+          }
+        });
+      } catch (e) {
+        console.warn("初始化隐藏canvas失败:", e);
+        if (retries > 0) {
+          setTimeout(() => this.initHiddenCanvasNode(fromReady, retries - 1), 300);
+        }
+      }
+    },
+    // 安全拍照再发送(非录制期)
+    safeTakePhotoAndSend() {
+      if (this.isFrameCapturing)
+        return;
+      if (!this.personDetectionSocket || this.personDetectionSocket.readyState !== 1)
+        return;
+      this.isFrameCapturing = true;
+      try {
+        this.cameraContext.takePhoto({
+          quality: "low",
+          success: (res) => {
+            const tempFilePath = res && res.tempImagePath;
+            if (!tempFilePath) {
+              this.isFrameCapturing = false;
+              return;
+            }
+            common_vendor.index.getFileSystemManager().readFile({
+              filePath: tempFilePath,
+              encoding: "base64",
+              success: (r) => {
+                try {
+                  const base64Image = r.data;
+                  if (!this.personDetectionSocket || this.personDetectionSocket.readyState !== 1) {
+                    return;
+                  }
+                  this.personDetectionSocket.send({
+                    data: JSON.stringify({
+                      type: "person_detection",
+                      image_data: base64Image
+                    })
+                  });
+                } finally {
+                  this.isFrameCapturing = false;
+                }
+              },
+              fail: () => {
+                this.isFrameCapturing = false;
+              }
+            });
+          },
+          fail: () => {
+            this.isFrameCapturing = false;
+          }
+        });
+      } catch (e) {
+        this.isFrameCapturing = false;
+      }
+    },
+    // 录制期间抓帧并经隐藏canvas导出为图片再发送(持续监听 + 节流)
+    startFrameStreamCapture() {
+      if (!this.useMiniProgramCameraComponent) {
+        console.warn("帧抓取:非小程序相机,跳过");
+        return;
+      }
+      if (!this.cameraContext || !this.cameraContext.onCameraFrame) {
+        console.warn("帧抓取:cameraContext或onCameraFrame不可用");
+        return;
+      }
+      if (this.frameListener && this.frameListener.stop) {
+        return;
+      }
+      try {
+        const listener = this.cameraContext.onCameraFrame((frame) => {
+          const now = Date.now();
+          if (now - this.lastFrameCaptureAt < (this.frameCaptureIntervalMs || 5e3))
+            return;
+          if (this.isFrameCapturing)
+            return;
+          if (!this.hiddenCanvasReady || !hiddenCanvasCtxRef || !hiddenCanvasNodeRef) {
+            console.warn("帧抓取:隐藏canvas未就绪");
+            this.initHiddenCanvasNode(false, 2);
+            return;
+          }
+          if (!this.personDetectionSocket || this.personDetectionSocket.readyState !== 1) {
+            console.warn("帧抓取:WebSocket未就绪");
+            return;
+          }
+          this.isFrameCapturing = true;
+          this.lastFrameCaptureAt = now;
+          try {
+            const raw = frame && frame.data;
+            const frameW = frame && frame.width || this.frameCanvasWidth;
+            const frameH = frame && frame.height || this.frameCanvasHeight;
+            const canvas = hiddenCanvasNodeRef;
+            if (!canvas) {
+              throw new Error("hiddenCanvasNode is undefined");
+            }
+            canvas.width = frameW;
+            canvas.height = frameH;
+            const ctx = hiddenCanvasCtxRef;
+            if (!raw) {
+              throw new Error("frame.data is undefined");
+            }
+            const rgba = raw instanceof Uint8ClampedArray ? raw : new Uint8ClampedArray(raw);
+            const imageData = ctx.createImageData(frameW, frameH);
+            imageData.data.set(rgba);
+            ctx.putImageData(imageData, 0, 0);
+            const exportSuccess = (tempFilePath) => {
+              common_vendor.index.getFileSystemManager().readFile({
+                filePath: tempFilePath,
+                encoding: "base64",
+                success: (r) => {
+                  if (this.personDetectionSocket && this.personDetectionSocket.readyState === 1) {
+                    this.personDetectionSocket.send({
+                      data: JSON.stringify({ type: "person_detection", image_data: r.data })
+                    });
+                    console.info("帧抓取:已发送图片");
+                  }
+                  this.isFrameCapturing = false;
+                },
+                fail: () => {
+                  console.warn("帧抓取:读取临时图片失败");
+                  this.isFrameCapturing = false;
+                }
+              });
+            };
+            const doExport = () => {
+              if (canvas && typeof canvas.toTempFilePath === "function") {
+                canvas.toTempFilePath({
+                  fileType: "jpg",
+                  quality: 0.5,
+                  success: (res) => exportSuccess(res.tempFilePath),
+                  fail: (err) => {
+                    console.warn("帧抓取:node.toTempFilePath 失败,回退到uni.canvasToTempFilePath", err);
+                    common_vendor.index.canvasToTempFilePath({
+                      canvas: hiddenCanvasNodeRef,
+                      x: 0,
+                      y: 0,
+                      width: frameW,
+                      height: frameH,
+                      destWidth: frameW,
+                      destHeight: frameH,
+                      fileType: "jpg",
+                      quality: 0.5,
+                      success: (res2) => exportSuccess(res2.tempFilePath),
+                      fail: (err2) => {
+                        console.warn("帧抓取:uni.canvasToTempFilePath 也失败", err2);
+                        this.isFrameCapturing = false;
+                      }
+                    }, this);
+                  }
+                });
+              } else {
+                common_vendor.index.canvasToTempFilePath({
+                  canvas: hiddenCanvasNodeRef,
+                  x: 0,
+                  y: 0,
+                  width: frameW,
+                  height: frameH,
+                  destWidth: frameW,
+                  destHeight: frameH,
+                  fileType: "jpg",
+                  quality: 0.5,
+                  success: (res3) => exportSuccess(res3.tempFilePath),
+                  fail: (err3) => {
+                    console.warn("帧抓取:uni.canvasToTempFilePath 失败", err3);
+                    this.isFrameCapturing = false;
+                  }
+                }, this);
+              }
+            };
+            if (typeof canvas.requestAnimationFrame === "function") {
+              canvas.requestAnimationFrame(() => doExport());
+            } else {
+              setTimeout(() => doExport(), 16);
+            }
+          } catch (err) {
+            console.warn("帧抓取:绘制或导出异常", err);
+            this.isFrameCapturing = false;
+          }
+        });
+        if (listener && listener.start) {
+          listener.start();
+          console.info("帧抓取:监听已启动");
+        }
+        this.frameListener = listener;
+      } catch (e) {
+        console.warn("启动帧抓取监听失败,回退到拍照方案:", e);
+      }
+    },
+    stopFrameStreamCapture() {
+      try {
+        if (this.frameListener && this.frameListener.stop) {
+          this.frameListener.stop();
+        }
+      } catch (e) {
+      }
+      this.frameListener = null;
+    },
     // ===== 追问次数控制:工具方法 =====
     getFollowUpLimit(jobPositionQuestionId) {
       if (!jobPositionQuestionId)
@@ -1150,6 +1386,16 @@ const _sfc_main = {
     startRecordingAnswer() {
       console.log("开始录制用户回答");
       this.isRecording = true;
+      this.lastFrameCaptureAt = 0;
+      try {
+        if (this.personDetectionSocket && this.personDetectionSocket.readyState === 1) {
+          if (!this.hiddenCanvasReady) {
+            this.initHiddenCanvasNode(false, 3);
+          }
+          this.startFrameStreamCapture();
+        }
+      } catch (e) {
+      }
       this.recordingStartTime = Date.now();
       this.recordingTimerCount = 0;
       this.maxRecordingTime = this.getCurrentQuestionRecommendedDuration();
@@ -1513,6 +1759,7 @@ const _sfc_main = {
       this.finalRecordingDuration = this.recordingTimerCount;
       this.showStopRecordingButton = false;
       this.isRecording = false;
+      this.stopFrameStreamCapture();
       const systemInfo = common_vendor.index.getSystemInfoSync();
       const isMiniProgram = systemInfo.uniPlatform && systemInfo.uniPlatform.startsWith("mp-");
       if (isMiniProgram) {
@@ -3381,50 +3628,16 @@ const _sfc_main = {
             console.warn("人脸检测:相机上下文或WebSocket连接未就绪");
             return;
           }
-          this.cameraContext.takePhoto({
-            quality: "low",
-            success: (res) => {
-              try {
-                const tempFilePath = res.tempImagePath;
-                if (!tempFilePath) {
-                  console.warn("人脸检测:未获取到有效的图片路径");
-                }
-                common_vendor.index.getFileSystemManager().readFile({
-                  filePath: tempFilePath,
-                  encoding: "base64",
-                  success: (res2) => {
-                    try {
-                      const base64Image = res2.data;
-                      if (!this.personDetectionSocket || this.personDetectionSocket.readyState !== 1) {
-                        console.warn("人脸检测:WebSocket连接已断开或未就绪");
-                        return;
-                      }
-                      this.personDetectionSocket.send({
-                        data: JSON.stringify({
-                          type: "person_detection",
-                          image_data: base64Image
-                        })
-                      });
-                    } catch (wsError) {
-                      console.error("人脸检测:发送WebSocket数据时出错:", wsError);
-                    }
-                  },
-                  fail: (error) => {
-                    console.error("人脸检测:读取图片文件失败:", error);
-                  }
-                });
-              } catch (fileError) {
-                console.error("人脸检测:处理图片文件时出错:", fileError);
-              }
-            },
-            fail: (error) => {
-              console.error("人脸检测:拍照失败:", error);
-            }
-          });
+          if (this.isRecording && this.useMiniProgramCameraComponent) {
+            this.startFrameStreamCapture();
+          } else {
+            this.stopFrameStreamCapture();
+            this.safeTakePhotoAndSend();
+          }
         } catch (mainError) {
           console.error("人脸检测:主流程执行出错:", mainError);
         }
-      }, 5e3);
+      }, this.frameCaptureIntervalMs || 5e3);
     },
     cleanupPersonDetectionWebSocket() {
       if (this.personDetectionInterval) {
@@ -3803,20 +4016,25 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
   }, $data.useMiniProgramCameraComponent ? {
     s: common_vendor.o((...args) => $options.handleCameraError && $options.handleCameraError(...args))
   } : {}, {
-    t: $data.showPageWarning ? 1 : "",
-    v: $data.loading
+    t: $data.useMiniProgramCameraComponent
+  }, $data.useMiniProgramCameraComponent ? {
+    v: $data.frameCanvasWidth,
+    w: $data.frameCanvasHeight
+  } : {}, {
+    x: $data.showPageWarning ? 1 : "",
+    y: $data.loading
   }, $data.loading ? {} : {}, {
-    w: $data.showDebugInfo
+    z: $data.showDebugInfo
   }, $data.showDebugInfo ? common_vendor.e({
-    x: $data.assistantResponse
+    A: $data.assistantResponse
   }, $data.assistantResponse ? {
-    y: common_vendor.t($data.assistantResponse)
+    B: common_vendor.t($data.assistantResponse)
   } : {}, {
-    z: $data.audioTranscript
+    C: $data.audioTranscript
   }, $data.audioTranscript ? {
-    A: common_vendor.t($data.audioTranscript)
+    D: common_vendor.t($data.audioTranscript)
   } : {}, {
-    B: common_vendor.f($data.processedResponses, (item, index, i0) => {
+    E: common_vendor.f($data.processedResponses, (item, index, i0) => {
       return common_vendor.e({
         a: item.role
       }, item.role ? {
@@ -3830,32 +4048,32 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
       });
     })
   }) : {}, {
-    C: $data.showStopRecordingButton
+    F: $data.showStopRecordingButton
   }, $data.showStopRecordingButton ? {
-    D: common_vendor.o((...args) => $options.stopRecordingAnswer && $options.stopRecordingAnswer(...args))
+    G: common_vendor.o((...args) => $options.stopRecordingAnswer && $options.stopRecordingAnswer(...args))
   } : {}, {
-    E: $data.isRecording
+    H: $data.isRecording
   }, $data.isRecording ? {
-    F: common_vendor.t($data.recordingTimeDisplay),
-    G: `conic-gradient(${$data.progressColor} ${$options.progressPercent}%, ${$data.progressBgColor} 0%)`
+    I: common_vendor.t($data.recordingTimeDisplay),
+    J: `conic-gradient(${$data.progressColor} ${$options.progressPercent}%, ${$data.progressBgColor} 0%)`
   } : {}, {
-    H: $data.showStartRecordingButton
+    K: $data.showStartRecordingButton
   }, $data.showStartRecordingButton ? {
-    I: common_vendor.o((...args) => $options.handleStartRecordingClick && $options.handleStartRecordingClick(...args))
+    L: common_vendor.o((...args) => $options.handleStartRecordingClick && $options.handleStartRecordingClick(...args))
   } : {}, {
-    J: $data.showRetryButton
+    M: $data.showRetryButton
   }, $data.showRetryButton ? {
-    K: common_vendor.o((...args) => $options.retryVideoUpload && $options.retryVideoUpload(...args))
+    N: common_vendor.o((...args) => $options.retryVideoUpload && $options.retryVideoUpload(...args))
   } : {}, {
-    L: $data.showCountdown
+    O: $data.showCountdown
   }, $data.showCountdown ? {
-    M: common_vendor.t($data.countdownValue)
+    P: common_vendor.t($data.countdownValue)
   } : {}, {
-    N: $data.showRerecordButton
+    Q: $data.showRerecordButton
   }, $data.showRerecordButton ? {
-    O: common_vendor.o((...args) => $options.handleRerecordButtonClick && $options.handleRerecordButtonClick(...args))
+    R: common_vendor.o((...args) => $options.handleRerecordButtonClick && $options.handleRerecordButtonClick(...args))
   } : {}, {
-    P: $data.showPageWarning ? 1 : ""
+    S: $data.showPageWarning ? 1 : ""
   });
 }
 const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-464e78c6"]]);

Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
unpackage/dist/dev/mp-weixin/pages/identity-verify/identity-verify.wxml


+ 1 - 1
unpackage/dist/dev/mp-weixin/project.private.config.json

@@ -10,7 +10,7 @@
         {
           "name": "pages/index/index",
           "pathName": "pages/index/index",
-          "query": "scene=1",
+          "query": "scene=15",
           "launchMode": "default",
           "scene": 1047
         },

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff