已关闭
bug反馈:pdf 阅读器AI识别出错。 #9
cnzen创建于  9月20日关闭于  9月21日
cnzen
cnzen成员
9月20日 创建

本条由数友社区的帖子转入(单向镜像)。讨论请在本 issue 进行;
社区那边只作为入口与检索面,状态以本 issue 为准。
来源帖:https://community.shuyo.cn/post/bug反馈pdf-阅读器ai识别出错

版本 / 平台

  • 版本:1.91.10
  • 平台:windows 11

复现步骤

1、在ShuyoNote文件夹,点击一个pdf文件;
2、点击 【AI 识别】 按钮。

期望

准确识别当前页文字内容。

实际

弹窗提示“识别失败...”

likedislike
fjt
fjt成员
9月20日 评论:

先说结论:这次不是"识别得不准",是失败原因被吞掉了 —— 界面上那句话把你指向了错的方向

我按 1.91.10 的代码把这条路走了一遍(【AI 识别】→ AI 视觉识别):

  • 【AI 识别】不走本地 tesseract,而是把当前页渲染成图、交给已配置的视觉模型(src/lib/ai/ocrVision.ts)。
  • 这条路上有 5 种失败,但其中 4 种在界面上塌成同一句「AI 视觉识别失败:请确认已配置支持图像的模型…」——
    因为 ocrWithVision() 只回了一个 error: "error",把具体原因(HTTP 状态、超时、空图)丢掉了。
    于是不管你遇到的是哪一种,看到的都是"去改模型",而真因可能根本不在这儿。

几种真因的区分办法:

真因 怎么判断
没配支持图像的模型 设置 → AI:必须是多模态模型(llava / qwen-vl / gpt-4o 这类);纯文本模型必然失败
模型名或 base URL 写错 ⇒ 404 下个版本会在提示里带上状态码
API key 不对 ⇒ 401 同上
这一页渲染出来是空的(取图环节) 阅读器里这一页显示正常吗?取图失败与模型失败原来长得一模一样
服务不可达 / 超时 那台模型服务起着吗、地址填对了吗

已经改好(进下一个版本)

分支 fix/pdf-ai-vision-error-reason @ 65b96278(基于 main,未合 dev):

  • ocrWithVision() 现在把具体原因跟着结果一起回(新增 message 字段):404/401/超时/空图各说各的;
  • 阅读器里失败时照实说,并把原因打进控制台([ai] vision ocr failed { error, message });
  • renderPage 抛错那条不再只喊一句「AI 视觉识别失败」,而是带上异常本身。

判据(新增 src/lib/ai/ocrVision.test.ts,5 条,全部通过;全量 vitest 1335 passed / 0 failed):

  • 404 ⇒ 提示里带状态码(而不是"请确认模型支持图像");
  • 401 ⇒ 带 401;
  • 空图 ⇒ 明说问题在取图/渲染、不在模型(且根本不该发这个请求);
  • 模型返回空文本 ⇒ 提示"可能不支持图像输入,也可能这页确实没字";
  • 成功 ⇒ 不塞多余信息。

需要你补一条读数(这样就能钉死,而不是猜)

在这台机器上复现一次,把控制台里这一行贴回来:

[ai] vision ocr failed { error: ..., message: ... }

(1.91.10 里还没有这行日志,所以如果现在只有那句笼统的弹窗,请顺手说一下:设置 → AI 里填的是哪个模型、
那个服务是本机起的还是远程的、以及这一页在阅读器里显示是否正常。有了这三条我就能判断是配置还是取图。)

issue 先不关:等你的读数,以及下一个版本里上面那几条提示落地。

likedislike
cnzen
cnzen成员
9月20日 评论:

配置的大模型:deepseek-v4-flash-vision-exp

likedislike
fjt
fjt成员
9月20日 评论:

查到根因了:桌面端的跨域 AI 调用被权限系统整体拒掉(不是模型的问题,也不是取图)

顺着你给的模型名(deepseek-v4-flash-vision-exp)我不用猜了 —— 配置就在本机:

provider = openai
baseUrl  = https://api.deepseek.com
model    = deepseek-v4-flash-vision-exp

一、先证明"服务商那一侧是好的"(我直接复现了应用的请求形状)

我做的事 读数
GET https://api.deepseek.com/v1/models(同一把 key) HTTP 200,这个 key 认的模型:deepseek-flash、deepseek-v4-pro
POST /v1/chat/completions,1×1 小图 HTTP 200(响应里 "model":"deepseek-flash" —— 那个名字是别名回落,不是 404)
POST 同上,4 MB 截图(请求体 5.3 MB) HTTP 200,6.2 秒,还把截图里的文字读出来了("DSH Desktop / Visual Studio Code / 回收站…")

⇒ 端点、key、模型名、大图载荷全都没问题;超时(90s)也够。

二、真正的根因:http 插件被授权了,却没给任何作用域

应用在桌面端把跨域请求统一走 @tauri-apps/plugin-http(native,绕开 WebView CORS)——
而 src-tauri/capabilities/default.json 里只写了字符串 "http:default"。插件自带的权限文件
(tauri-plugin-http-2.6.0/permissions/default.toml)原文:

This enables all fetch operations but does not allow explicitly any origins to be fetched.
This needs to be manually configured before usage.

⇒ 作用域为空 = 一个源都不许发(失败关闭)。所以桌面端所有走 coreFetch 的跨域 AI 调用
(AI 识别 / 对话 / 摘要 / 嵌入)都被权限系统拒掉;而 Web 版走浏览器 fetch,不受这条限制 ——
这就是"只有桌面端 AI 不好使"的原因。它又恰好只会冒出一句笼统的「AI 视觉识别失败」,
所以看起来像"模型不支持图像"(我上一条说的那个坑)。

三、已经改好的(两条,都在分支 fix/pdf-ai-vision-error-reason)

  1. 根因:给 http:default 显式作用域 —— https://** + http://**。
    为什么是"全放行"而不是白名单:服务商地址是用户自己填的(官方 HTTPS 端点,或局域网/回环上的
    自建模型服务走 http),固定白名单会把"填自己的地址"这条承诺作废。
    附一条回归判据(Rust 测试):http 插件被授权就必须带 allow scope、且覆盖 https/http
    —— 这类漏配是失败关闭的,不会再靠人记着。
  2. 报错指向(上一条评论里那笔):失败时把具体原因带回界面与控制台,不再一律喊"请确认模型支持图像"。

四、诚实的边界 + 你现在能做的

  • 我这边能证明的是:配置形状正确(作用域存在且覆盖 https/http)+ 构建期 schema 校验 +
    上面那张"服务商侧全绿灯"的读数。"打包后的桌面端真的能发出去"要等版本出来真机复验 ——
    这台机器跑不了 Tauri UI,我不把"应该好了"写成"已经好了"。
  • 变通:这个端点是给 CORS 头的(我实测 access-control-allow-origin 会回显),所以
    Web 版(https://shuyo.cn/app/)里配同一个模型是能用的;桌面端请等下一个版本。
  • 版本出来后请你按原步骤再点一次【AI 识别】:成功会提示「AI 视觉识别完成」;
    若还失败,请把弹窗那句完整文案(或控制台 [ai] vision ocr failed {...})贴回来 ——
    现在它能直接告诉我们是哪一环。

issue 先不关,等真机复验。

likedislike
fjt
fjt成员
9月20日 评论:

开发版实测:修好了(附「修复前 vs 修复后」的同一条探针读数)

在开发版(cargo run 起应用、前端挂 dev server、开 WebView2 调试端口)里,用应用自己的 coreFetch
(= @tauri-apps/plugin-http 那条 native 路,也就是出问题的那条)打你配的端点 —— 同一段代码、同一个页面,
只换 capability:

修复前(只有字符串 "http:default"):

{ "url": "https://api.deepseek.com/v1/models",
  "error": "url not allowed on the configured scope: https://api.deepseek.com/v1/models" }

修复后(http:default 补上 https://** + http://**):

{ "url": "https://api.deepseek.com/v1/models",
  "httpStatus": 200,
  "head": "{\"object\":\"list\",\"data\":[{\"id\":\"deepseek-flash\",…},{\"id\":\"deepseek-v4-pro\",…}]}" }

⇒ 那句 url not allowed on the configured scope 就是你在 1.91.10 里看到「识别失败」的直接原因:
异常被 runVisionOcr 的 catch 吞掉,只剩一句笼统提示(另一半修复正是让它说实话)。

两条修复已在 dev 上:ccdf4c28(报错说真话)+ 9dfa5a5c(补作用域 + 回归判据)。
下一个版本随包出去,出来后再请你点一次【AI 识别】确认 —— 成功会提示「AI 视觉识别完成」。

复现方式留档(对"权限类"问题特别有用:浏览器里的 fetch 能通 ≠ native 那条路能通):

$env:WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS='--remote-debugging-port=9222'; cargo run   # 开发版
# 然后 CDP 连到 http://127.0.0.1:9222/json 的页面目标,在页面里求值:
#   (await import('/src/lib/coreHttp.ts')).coreFetch(url, { headers })
likedislike
fjt
fjt成员
9月21日 评论:

已发布的桌面端实测:这条能力作用域确实修好了(附发布版 1.91.18 的真机读数)

先对齐一处时间线:修复从 v1.91.11 起就在每一个正式版里 —— ccdf4c28(报错说真话)+ 9dfa5a5c(补作用域 + 回归判据)都在 v1.91.11…v1.91.18 的 tag 里(git tag --contains 可复核)。你报的是 1.91.10,在修复之前,所以那条「识别失败」是预期内的。

一、这次验的是打包后的桌面端,不是开发版

上一轮我只能证明开发版;这次直接拿已发布产物:把 ShuyoNote_1.91.18_x64-setup.exe 里的 shuyonote.exe 用 7-Zip 解出来(不安装),带 WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS=--remote-debugging-port=9222 跑起来,用 CDP 在页面里直接调 http 插件的 IPC:

invoke('plugin:http|fetch', { clientConfig: { method:'GET', url:'https://api.deepseek.com/v1/models', headers: [] } })
→ { "ok": true, "scopeAllowed": true, "status": 401, "statusText": "Unauthorized",
    "url": "https://api.deepseek.com/v1/models" }

401 是预期的(探针没带 key)—— 关键是它拿到了 HTTP 响应:请求真的发到了 api.deepseek.com。
作用域缺失时是另一副样子:本地当场拒绝、根本不出网:

url not allowed on the configured scope: https://api.deepseek.com/v1/models

顺带留个小坑档(与作用域无关,是我探针形状写错了):clientConfig.headers 必须是序列([] 或 [["k","v"]]),给对象 {} 会被 serde 报 invalid type: map, expected a sequence。

二、你这边怎么确认

  1. 升级到 1.91.18(或任何 ≥ 1.91.11 的版本);
  2. 打开那个 PDF → 点【AI 识别】;
  3. 期望提示 「AI 视觉识别完成」。

若仍失败,请贴这两样之一 —— 现在的提示会说真话(不再一律喊"请确认模型支持图像"):

  • 弹窗的完整文案(会带 HTTP 状态:401 / 404 / 超时 / 空图各说各的);
  • 或控制台里这一行:[ai] vision ocr failed { error, message }。

三、状态

按上一条评论的约定「等真机复验」—— 打包产物那一半我已经验完(上面那条读数),端到端那一下(用你的模型 + key 点一次)在你这边。既然根因(权限作用域)在发布版里已确认修好,本 issue 先关;若复验仍失败,请直接重开并带上第二节那两样读数,我按新读数继续查。

likedislike
fjtfjt成员
9月21日 关闭了 issue