所有耀眼的成績,都需要苦熬,熬得過,出眾;熬不過,出局
大家好,我是柒八九。一個專注于前端開發技術/Rust
及AI
應用知識分享的Coder
此篇文章所涉及到的技術有
Rust
wasm-bindgen/js-sys/web-sys
Web Worker
WebAssembly
Webpack/Vite
配置WebAssembly
OffscreenCanvas
- 腳手架生成項目(
npx f_cli_f create xxx
)tailwindcss
等MuPDF.js/mammoth.js
因為,行文字數所限,有些概念可能會一帶而過亦或者提供對應的學習資料。請大家酌情觀看。
前言
在前一篇文章寫一個類ChatGPT應用,前后端數據交互有哪幾種我們介紹了,如果要進行一個類ChatGPT
應用的開發,可能會用到的前后端數據交互的方式。同時呢,我們也介紹了最近公司所做的項目,做一款基于文檔類問答的AI功能。
而談到文檔相關的應用,從操作文檔角度來看,無非就是文件上傳
,文件解析
和文件展示
。而我們之前在文件上傳 = 拖拽 + 多文件 + 文件夾介紹過更優雅的上傳方式。而文件展示
如果大家想了解的話,我們可以單獨寫一篇文章。
而我們今天來聊聊關于文件解析
的相關操作。
業務背景
大家肯定用過很多云盤類的應用。在我們對本地文件進行上傳后,在展示的時候一般分為兩種模式
- 列表模式
- 大圖模式
如果大家觀察過云盤針對大圖模式
的文件資源的展示,就會發現每個文件的頭圖都是用一個<img/>
接收了一個從后端返回的固定圖片資源。
而現在,我們針對大圖模式
有幾點改進
- 要求該圖片能顯示文件資料的
概要內容
(這塊可以借助AI
對文本進行Summary
處理,這個我們后面會單獨寫一篇文章),而不是單單的把文件的首頁信息(pdf/word/pptx
)轉換成圖片(像阿里云盤一樣) - 要求前端在上傳過程中,就需要顯示文件的
概要信息
,而不是走接口從服務器獲取,也就是這是一個純前端的事情 - 還需要在圖片的標識文件的類型,例如展示
pdf/word/ppt
等的圖標
為什么做呢,有沒有發現我們通過上述的改造和處理,我們直接在大圖模式
下,通過文件頭圖信息就能大致知曉文件的內容(概要信息),其次如果展示的資源信息過多,每次從后端獲取對應的圖片資源也是一件極其耗費帶寬的事情。
前端糅合其他語言
講到這里,大家可能會疑惑,你上面說了那么多,那么這和Rust
有啥關系?
關系大著呢,從上面的需求點出發,我們可以看出,其實針對文檔解析
的處理,都是在前端環境中操作的。同時,針對大體積的文件資源,對其解析處理是一件極其耗時的事情。有時針對特殊文件,可能前端還暫時無法處理。
既然,我們想要在前端執行這些耗時
且不易處理的任務,我們就需要請幫手,而在其他語言中有成熟的方案來處理我們遇到的這些問題。(由于種種原因,其他端的小伙伴無瑕處理這種情況)
那么,我們就可以選擇一種方式,在前端環境中通過某種方式來糅合其他語言的操作來執行對應的任務。那思來想去,WebAssembly
是再合適不過的方式了。如果不了解它,可以看我們之前的文章 - 瀏覽器第四種語言-WebAssembly。
當然,其他語言(
C/TypeScript
)都可以通過編譯工具轉化成WebAssembly
,此片文章中也會涉及,只不過我們是直接使用別人構建好的WebAssembly
,而現行階段,Rust
是對WebAssembly
最友好的語言。并且,我們也會用Rust
手搓一個WebAssembly
。這也是為什么這篇文章的主標題叫Rust賦能前端
而不是WebAssembly賦能前端
(我們在本文的第三部分,Word 解析
中詳細介紹了用Rust
寫WebAssembly
,如果不想看mupdf
的可以直接跳到第三節)
好了,天不早了,干點正事哇。
我們能所學到的知識點
- 服務配置&項目配置
- PDF 解析
- Word 解析
1. 服務配置&項目配置
由于,WebAssembly
是一個新興技術,在一些常規的打包工具(vite/webpack
)中使用,我們需要額外處理。
使用WebAssembly
從來源大致可以兩類
npm包/公司私包
(針對如何發私包可以參考之前的如何在gitlab上發布npm包)- 直接在項目目錄中使用已經構建好的
wasm
這兩種情況我們接下來都會涉及。其實他們的處理方式都是一樣的。下面我們就來講講Webpack/Vite
是如何配置它們的。
Webpack
針對Webpack
中使用WebAssembly
,我們之前在Rust 編譯為 WebAssembly 在前端項目中使用就介紹過。
其實,最關鍵的點就是需要wasm-pack-plugin
其次,我們還想讓WebAssembly
模塊能夠和其他ESM
一樣,通過import
進行方法的導入處理,針對Webapck5
我們還可以通過配置experiments
的asyncWebAssembly為true
來啟動該項功能。
最后,為了兼容性,我們處理TextEncoder/TextDecoder
。
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin");module.exports = {entry: './index.js',output: {path: path.resolve(__dirname, 'dist'),filename: 'index.js',},plugins: [new HtmlWebpackPlugin({template: 'index.html'}),new WasmPackPlugin({crateDirectory: path.resolve(__dirname, ".")}),// 讓這個示例在不包含`TextEncoder`或`TextDecoder`的Edge瀏覽器中正常工作。new webpack.ProvidePlugin({TextDecoder: ['text-encoding', 'TextDecoder'],TextEncoder: ['text-encoding', 'TextEncoder']})],mode: 'development',experiments: {asyncWebAssembly: true}
};
Vite
從Vite
官網看,它只兼容了引入預編譯的.wasm
,但是對 WebAssembly
的 ES 模塊集成提案
尚未支持。而恰巧,我們今天所涉及到的.wasm
都是ESM
格式的。
按照官網的提示,我們可以借助vite-plugin-wasm的幫助。
配置也很簡單,按照下面的處理即可。
import wasm from "vite-plugin-wasm";
import topLevelAwait from "vite-plugin-top-level-await";export default defineConfig({plugins: [wasm(),topLevelAwait()],worker: {plugins: [wasm(),topLevelAwait()]}
});
項目配置
由于,我們公司的打包工具是Vite
,還記得我們之前介紹過的腳手架工具嗎。
大家可以在自己電腦中執行,npx f_cli_f create file_to_img
來構建一個以Vite
為打包工具的前端項目。
然后,我們就可以將上面邏輯寫到對應的文件中。
執行到這里,我們的前期的配置工作就算完成了。
如果使用過我們的f_cli_f
的人,會知道。我們在項目中內置了很多東西,可以算是開箱即用。
所以,我們保留之前的結構的基礎上,在pages
中新建一個FileToImg
的目錄結構,并且將其放置于main
路由下。
最后的頁面結構如下
- 左側的待處理文件類型我們提供了針對
pdf/word/text
的常規文件的解析 - 附件上傳就是使用最原始的
<input type="file"/>
- 搜索區塊的話,是針對
PDF
的內容檢索 - 右側的格式輸出,可以切換文件的輸