mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-07-08 16:43:59 +08:00
### What this PR does Before this PR: - `supportsPdfInput()` hardcodes a provider ID whitelist, causing aggregator providers (cherryin, new-api type) to always fall back to text extraction even when the underlying model supports native PDF. - 5 places where PDF processing fails silently — files get dropped from messages with no user notification. After this PR: - Message preparation always produces the richest representation (FilePart) for all PDFs regardless of provider. - A new `pdfCompatibilityPlugin` middleware handles compatibility by converting PDF FileParts to TextParts for providers that don't support native PDF input, using `pdf-parse` 2.x to extract text directly from FilePart data in the renderer process. - All 5 failure paths now show user-facing toast notifications (warnings/errors). - `pdf-parse` upgraded to 2.x (browser-compatible, TypeScript, extracts text from buffer/base64 directly). - New shared utility `extractPdfText()` for PDF text extraction from any data format. Fixes #13603, fixes #13638 ### Why we need it and why it was done in this way The following tradeoffs were made: - The plugin uses `provider.type` (API protocol) instead of `getAiSdkProviderId()` to determine PDF support, because aggregator providers (cherryin, new-api, gateway) resolve to non-standard AI SDK IDs but speak standard protocols that support PDF. - `pdf-parse` 2.x is used directly in the renderer process to extract text from base64 PDF data, eliminating the need for IPC calls or providerOptions workarounds. - The plugin runs for every request but short-circuits immediately for supported providers (Set lookup). The following alternatives were considered: - Extending the whitelist to cover more providers — rejected because it's a whack-a-mole approach. - Using `getAiSdkProviderId()` — rejected because it returns unreliable IDs for aggregator providers. - Pre-extracting text in fileProcessor and passing via providerOptions — rejected as it misuses providerOptions and adds unnecessary IO for native providers. - Adding IPC methods for buffer-based text extraction — rejected as pdf-parse 2.x runs directly in renderer. Links to places where the discussion took place: - #13603 (provider whitelist issue) - #13638 (silent failure paths) ### Breaking changes None. This is a transparent improvement — providers that previously supported native PDF still get FileParts, and providers that didn't now get TextParts instead of silently dropped files. ### Special notes for your reviewer - `pdf-parse` upgraded from 1.1.1 to 2.4.5. The existing patch (`patches/pdf-parse-npm-1.1.1-04a6109b2a.patch`) is for the indirect dependency (via `office-text-extractor`) and remains untouched. - `@langchain/community` has a peer dep on `pdf-parse@1.1.1` but only `VoyageEmbeddings` is imported from it — `PDFLoader` is not used, so the peer warning is harmless. - **NOTE**: The `pdf-parse` peer dependency warning for `@langchain/community` is safe **only** when `PDFLoader` is not being used. If `PDFLoader` is ever imported in the future, this incompatibility must be addressed. - `qwen-long`/`qwen-doc` models use `handleLargeFileUpload` → `fileid://` reference → `SystemModelMessage`. They never reach the plugin as FilePart, so they are unaffected. - Non-PDF documents (Word, Excel) still return `null` from `convertFileBlockToFilePart` and use the text fallback path unchanged. - `isPdfFilePart` is a proper TypeScript type guard. No `as` type assertions in the plugin code. ### Checklist - [x] PR: The PR description is expressive enough and will help future contributors - [x] Code: [Write code that humans can understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans) and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle) - [x] Refactor: You have [left the code cleaner than you found it (Boy Scout Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html) - [x] Upgrade: Impact of this change on upgrade flows was considered and addressed if required - [ ] Documentation: A [user-guide update](https://docs.cherry-ai.com) was considered and is present (link) or not required. Check this only when the PR introduces or changes a user-facing feature or behavior. - [x] Self-review: I have reviewed my own code (e.g., via [`/gh-pr-review`](/.claude/skills/gh-pr-review/SKILL.md), `gh pr diff`, or GitHub UI) before requesting review from others ### Release note ```release-note Improved PDF file processing: aggregator providers (cherryin, new-api, etc.) now correctly handle native PDF input instead of always falling back to text extraction. Added user-facing notifications when PDF processing fails instead of silently dropping files. ``` --------- Signed-off-by: icarus <eurfelux@gmail.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>