Files
CamTalk/docs/fix-text-input-camera-issue.md
cfy666 ed95ce56a8 fix: 关闭摄像头后文本输入不再发送图像数据
修复了用户关闭摄像头后,使用文本输入时 AI 仍会分析黑色画面的问题。

变更:
- sendTextMessage: 只在摄像头开启时捕获画面
- 待发消息队列: 根据摄像头状态决定是否携带画面

效果:
- 摄像头关闭时纯文本对话,不提及画面
- 节省 token 消耗和网络带宽

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 22:21:03 +08:00

3.9 KiB
Raw Blame History

修复文本输入时仍调用摄像头的问题

问题描述

当用户关闭视频对话改用文本输入聊天时AI 仍然会说"画面是黑色的",然后才回答问题。这是因为即使摄像头关闭,前端仍然发送了图像数据(黑屏)给后端。

问题根源

前端问题

frontend/src/hooks/useVisionSession.ts 中:

  1. sendTextMessage 函数(第 441 行):无论摄像头是否开启,都会调用 captureFrame() 捕获画面
  2. 待发消息队列处理(第 140 行):连接成功后 flush 待发消息时,也会无条件捕获画面
// 问题代码
const frame = captureFrame();  // 即使摄像头关闭也会捕获(返回黑屏)
send({
  type: "query",
  image: frame ? dataUrlToBase64(frame) : "",  // 发送黑屏数据
  text: text.trim(),
});

后端行为

backend/internal/eino/nodes_history.go 中:

  • 第 68-86 行:只要收到图像数据(len(imageData) > 0),就会构建多模态消息发送给 LLM
  • LLM 会分析这个黑色画面,导致回复中提到"画面是黑色的"

解决方案

修改内容

修改了两处代码,都在 frontend/src/hooks/useVisionSession.ts

1. sendTextMessage 函数(第 421-462 行)

// 修改前
const frame = captureFrame();

// 修改后
// 只在摄像头开启时才捕获画面,避免发送黑屏给 AI
const frame = isCameraOn ? captureFrame() : null;

并在依赖数组中添加了 isCameraOn

[captureFrame, send, connect, accessToken, isCameraOn]

2. 待发消息队列处理(第 124-156 行)

// 修改前
const frame = captureFrame();

// 修改后
// 只在摄像头开启时才捕获画面,避免发送黑屏给 AI
const frame = isCameraOn ? captureFrame() : null;

效果

修改后:

  • 摄像头开启时,文本输入仍然会携带当前画面(多模态对话)
  • 摄像头关闭时,文本输入只发送文字(纯文本对话)
  • AI 不会再说"画面是黑色的"
  • 节省 token 消耗(不发送无用的图像数据)

测试场景

  1. 开启视频对话 → 关闭摄像头 → 文本输入聊天

    • 预期AI 只回答文本问题,不提及画面
  2. 直接文本输入(未开启摄像头)

    • 预期:纯文本对话,不发送图像数据
  3. 开启摄像头 → 文本输入

    • 预期AI 可以看到画面并结合文本回答
  4. 未连接时文本输入 → 自动连接

    • 预期:待发消息在连接成功后发送,根据当时的摄像头状态决定是否携带画面

替代方案(未采用)

方案二:后端过滤空图像

在后端 nodes_history.go 中增加图像有效性检测:

// 检测图像是否有效(非全黑/全白)
func isValidImage(data []byte) bool {
    // 检测文件大小(黑屏图像通常很小)
    if len(data) < 1024 { // 小于 1KB
        return false
    }
    // 可以进一步检测像素方差等
    return true
}

// 在 NewHistoryLambda 中
if len(imageData) > 0 && isValidImage(imageData) {
    // 构建多模态消息
} else {
    // 纯文本消息
}

未采用原因

  • 前端方案更直接,从源头解决问题
  • 避免后端做额外的图像检测(性能开销)
  • 节省网络传输(不发送无用的图像数据)

相关文件

  • frontend/src/hooks/useVisionSession.ts - 核心会话逻辑
  • backend/internal/eino/nodes_history.go - 后端历史消息组装
  • docs/02-接口文档.md - WebSocket 协议定义

提交信息

fix: 关闭摄像头后文本输入不再发送图像数据

修复了用户关闭摄像头后,使用文本输入时 AI 仍会分析黑色画面的问题。

变更:
- sendTextMessage: 只在摄像头开启时捕获画面
- 待发消息队列: 根据摄像头状态决定是否携带画面

效果:
- 摄像头关闭时纯文本对话,不提及画面
- 节省 token 消耗和网络带宽