先说结论:这次不是"识别得不准",是失败原因被吞掉了 —— 界面上那句话把你指向了错的方向
我按 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 先不关:等你的读数,以及下一个版本里上面那几条提示落地。


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


查到根因了:桌面端的跨域 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)
- 根因:给
http:default显式作用域 ——https://**+http://**。
为什么是"全放行"而不是白名单:服务商地址是用户自己填的(官方 HTTPS 端点,或局域网/回环上的
自建模型服务走 http),固定白名单会把"填自己的地址"这条承诺作废。
附一条回归判据(Rust 测试):http 插件被授权就必须带 allow scope、且覆盖 https/http
—— 这类漏配是失败关闭的,不会再靠人记着。 - 报错指向(上一条评论里那笔):失败时把具体原因带回界面与控制台,不再一律喊"请确认模型支持图像"。
四、诚实的边界 + 你现在能做的
- 我这边能证明的是:配置形状正确(作用域存在且覆盖 https/http)+ 构建期 schema 校验 +
上面那张"服务商侧全绿灯"的读数。"打包后的桌面端真的能发出去"要等版本出来真机复验 ——
这台机器跑不了 Tauri UI,我不把"应该好了"写成"已经好了"。 - 变通:这个端点是给 CORS 头的(我实测
access-control-allow-origin会回显),所以
Web 版(https://shuyo.cn/app/)里配同一个模型是能用的;桌面端请等下一个版本。 - 版本出来后请你按原步骤再点一次【AI 识别】:成功会提示「AI 视觉识别完成」;
若还失败,请把弹窗那句完整文案(或控制台[ai] vision ocr failed {...})贴回来 ——
现在它能直接告诉我们是哪一环。
issue 先不关,等真机复验。


开发版实测:修好了(附「修复前 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 })


已发布的桌面端实测:这条能力作用域确实修好了(附发布版 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.91.18(或任何 ≥ 1.91.11 的版本);
- 打开那个 PDF → 点【AI 识别】;
- 期望提示 「AI 视觉识别完成」。
若仍失败,请贴这两样之一 —— 现在的提示会说真话(不再一律喊"请确认模型支持图像"):
- 弹窗的完整文案(会带 HTTP 状态:401 / 404 / 超时 / 空图各说各的);
- 或控制台里这一行:
[ai] vision ocr failed { error, message }。
三、状态
按上一条评论的约定「等真机复验」—— 打包产物那一半我已经验完(上面那条读数),端到端那一下(用你的模型 + key 点一次)在你这边。既然根因(权限作用域)在发布版里已确认修好,本 issue 先关;若复验仍失败,请直接重开并带上第二节那两样读数,我按新读数继续查。


版本 / 平台
复现步骤
1、在ShuyoNote文件夹,点击一个pdf文件;
2、点击 【AI 识别】 按钮。
期望
准确识别当前页文字内容。
实际
弹窗提示“识别失败...”