Transformers.js 文件
構建 Next.js 應用
並獲得增強的文件體驗
開始使用
構建 Next.js 應用
在本教程中,我們將使用 Transformers.js 構建一個簡單的 Next.js 應用程式來進行情感分析!由於 Transformers.js 可以在瀏覽器或 Node.js 中執行,您可以選擇在客戶端或服務端進行推理(我們將向您展示兩種方式)。無論哪種方式,我們都將使用新的 App Router 正規化進行開發。最終產品將如下所示
實用連結
先決條件
客戶端推理
步驟1:初始化專案
首先使用 create-next-app
建立一個新的 Next.js 應用程式。
npx create-next-app@latest
安裝時,您會看到各種提示。對於此演示,我們將選擇下面以粗體顯示的內容。
√ What is your project named? ... next √ Would you like to use TypeScript? ... No / Yes √ Would you like to use ESLint? ... No / Yes √ Would you like to use Tailwind CSS? ... No / Yes √ Would you like to use `src/` directory? ... No / Yes √ Would you like to use App Router? (recommended) ... No / Yes √ Would you like to customize the default import alias? ... No / Yes
步驟2:安裝和配置 Transformers.js
您可以使用以下命令從 NPM 安裝 Transformers.js
npm i @huggingface/transformers
我們還需要更新 next.config.js
檔案,以便在為瀏覽器打包時忽略特定於節點的模組。
/** @type {import('next').NextConfig} */
const nextConfig = {
// (Optional) Export as a static site
// See https://nextjs.org/docs/pages/building-your-application/deploying/static-exports#configuration
output: 'export', // Feel free to modify/remove this option
// Override the default webpack configuration
webpack: (config) => {
// See https://webpack.js.org/configuration/resolve/#resolvealias
config.resolve.alias = {
...config.resolve.alias,
"sharp$": false,
"onnxruntime-node$": false,
}
return config;
},
}
module.exports = nextConfig
接下來,我們將建立一個新的 Web Worker 指令碼,我們將在此處放置所有與機器學習相關的程式碼。這是為了確保在模型載入和執行推理時主執行緒不會被阻塞。對於此應用程式,我們將使用 Xenova/distilbert-base-uncased-finetuned-sst-2-english
,這是一個在 斯坦福情感樹庫 資料集上進行微調的約 67M 引數的模型。將以下程式碼新增到 ./src/app/worker.js
import { pipeline, env } from "@huggingface/transformers";
// Skip local model check
env.allowLocalModels = false;
// Use the Singleton pattern to enable lazy construction of the pipeline.
class PipelineSingleton {
static task = 'text-classification';
static model = 'Xenova/distilbert-base-uncased-finetuned-sst-2-english';
static instance = null;
static async getInstance(progress_callback = null) {
if (this.instance === null) {
this.instance = pipeline(this.task, this.model, { progress_callback });
}
return this.instance;
}
}
// Listen for messages from the main thread
self.addEventListener('message', async (event) => {
// Retrieve the classification pipeline. When called for the first time,
// this will load the pipeline and save it for future use.
let classifier = await PipelineSingleton.getInstance(x => {
// We also add a progress callback to the pipeline so that we can
// track model loading.
self.postMessage(x);
});
// Actually perform the classification
let output = await classifier(event.data.text);
// Send the output back to the main thread
self.postMessage({
status: 'complete',
output: output,
});
});
步驟3:設計使用者介面
現在,我們將修改預設的 ./src/app/page.js
檔案,使其連線到我們的 worker 執行緒。由於我們只在瀏覽器內執行推理,我們可以使用 'use client'
指令 選擇加入客戶端元件。
'use client'
import { useState, useEffect, useRef, useCallback } from 'react'
export default function Home() {
/* TODO: Add state variables */
// Create a reference to the worker object.
const worker = useRef(null);
// We use the `useEffect` hook to set up the worker as soon as the `App` component is mounted.
useEffect(() => {
if (!worker.current) {
// Create the worker if it does not yet exist.
worker.current = new Worker(new URL('./worker.js', import.meta.url), {
type: 'module'
});
}
// Create a callback function for messages from the worker thread.
const onMessageReceived = (e) => { /* TODO: See below */};
// Attach the callback function as an event listener.
worker.current.addEventListener('message', onMessageReceived);
// Define a cleanup function for when the component is unmounted.
return () => worker.current.removeEventListener('message', onMessageReceived);
});
const classify = useCallback((text) => {
if (worker.current) {
worker.current.postMessage({ text });
}
}, []);
return ( /* TODO: See below */ )
}
在 Home
元件的開頭初始化以下狀態變數
// Keep track of the classification result and the model loading status.
const [result, setResult] = useState(null);
const [ready, setReady] = useState(null);
並填寫 onMessageReceived
函式,以便在 worker 執行緒傳送訊息時更新這些變數。
const onMessageReceived = (e) => {
switch (e.data.status) {
case 'initiate':
setReady(false);
break;
case 'ready':
setReady(true);
break;
case 'complete':
setResult(e.data.output[0])
break;
}
};
最後,我們可以在 Home
元件中新增一個簡單的使用者介面,包括一個輸入文字框和一個預格式化文字元素,以顯示分類結果。
<main className="flex min-h-screen flex-col items-center justify-center p-12">
<h1 className="text-5xl font-bold mb-2 text-center">Transformers.js</h1>
<h2 className="text-2xl mb-4 text-center">Next.js template</h2>
<input
className="w-full max-w-xs p-2 border border-gray-300 rounded mb-4"
type="text"
placeholder="Enter text here"
onInput={e => {
classify(e.target.value);
}}
/>
{ready !== null && (
<pre className="bg-gray-100 p-2 rounded">
{ (!ready || !result) ? 'Loading...' : JSON.stringify(result, null, 2) }
</pre>
)}
</main>
您現在可以使用以下命令執行您的應用程式。
npm run dev
訪問終端中顯示的 URL(例如 https://:3000/)即可看到您的應用程式執行起來!
(可選)步驟4:構建和部署
要構建您的應用程式,只需執行
npm run build
這將會打包您的應用程式,並將靜態檔案輸出到 out
資料夾。
對於此演示,我們將把我們的應用程式部署為一個靜態的 Hugging Face Space,但您也可以將其部署到任何您喜歡的地方!如果您還沒有,可以在這裡建立一個免費的 Hugging Face 賬戶。
- 訪問 https://huggingface.co/new-space 並填寫表單。請記住選擇“Static”作為空間型別。
- 點選頁面底部的“建立空間”按鈕。
- 轉到“Files”→“Add file”→“Upload files”。將
out
資料夾中的檔案拖到上傳框中,然後點選“Upload”。上傳完成後,向下滾動到按鈕並點選“Commit changes to main”。
就是這樣! 您的應用程式現在應該可以在 https://huggingface.co/spaces/<your-username>/<your-space-name>
上訪問了!
服務端推理
雖然有許多不同的方法可以執行服務端推理,但最簡單的方法(我們將在本教程中討論)是使用新的 Route Handlers 功能。
步驟1:初始化專案
首先使用 create-next-app
建立一個新的 Next.js 應用程式。
npx create-next-app@latest
安裝時,您會看到各種提示。對於此演示,我們將選擇下面以粗體顯示的內容。
√ What is your project named? ... next √ Would you like to use TypeScript? ... No / Yes √ Would you like to use ESLint? ... No / Yes √ Would you like to use Tailwind CSS? ... No / Yes √ Would you like to use `src/` directory? ... No / Yes √ Would you like to use App Router? (recommended) ... No / Yes √ Would you like to customize the default import alias? ... No / Yes
步驟2:安裝和配置 Transformers.js
您可以使用以下命令從 NPM 安裝 Transformers.js
npm i @huggingface/transformers
我們還需要更新 next.config.js
檔案,以防止 Webpack 打包某些包。
/** @type {import('next').NextConfig} */
const nextConfig = {
// (Optional) Export as a standalone site
// See https://nextjs.org/docs/pages/api-reference/next-config-js/output#automatically-copying-traced-files
output: 'standalone', // Feel free to modify/remove this option
// Indicate that these packages should not be bundled by webpack
experimental: {
serverComponentsExternalPackages: ['sharp', 'onnxruntime-node'],
},
};
module.exports = nextConfig
接下來,讓我們設定我們的 Route Handler。我們可以透過在新的 ./src/app/classify/
目錄中建立兩個檔案來做到這一點。
pipeline.js
- 用於處理我們 pipeline 的構建。import { pipeline } from "@huggingface/transformers"; // Use the Singleton pattern to enable lazy construction of the pipeline. // NOTE: We wrap the class in a function to prevent code duplication (see below). const P = () => class PipelineSingleton { static task = 'text-classification'; static model = 'Xenova/distilbert-base-uncased-finetuned-sst-2-english'; static instance = null; static async getInstance(progress_callback = null) { if (this.instance === null) { this.instance = pipeline(this.task, this.model, { progress_callback }); } return this.instance; } } let PipelineSingleton; if (process.env.NODE_ENV !== 'production') { // When running in development mode, attach the pipeline to the // global object so that it's preserved between hot reloads. // For more information, see https://vercel.com/guides/nextjs-prisma-postgres if (!global.PipelineSingleton) { global.PipelineSingleton = P(); } PipelineSingleton = global.PipelineSingleton; } else { PipelineSingleton = P(); } export default PipelineSingleton;
route.js
- 用於處理對/classify
路由的請求。import { NextResponse } from 'next/server' import PipelineSingleton from './pipeline.js'; export async function GET(request) { const text = request.nextUrl.searchParams.get('text'); if (!text) { return NextResponse.json({ error: 'Missing text parameter', }, { status: 400 }); } // Get the classification pipeline. When called for the first time, // this will load the pipeline and cache it for future use. const classifier = await PipelineSingleton.getInstance(); // Actually perform the classification const result = await classifier(text); return NextResponse.json(result); }
步驟3:設計使用者介面
現在我們將修改預設的 ./src/app/page.js
檔案,以向我們新建立的 Route Handler 發出請求。
'use client'
import { useState } from 'react'
export default function Home() {
// Keep track of the classification result and the model loading status.
const [result, setResult] = useState(null);
const [ready, setReady] = useState(null);
const classify = async (text) => {
if (!text) return;
if (ready === null) setReady(false);
// Make a request to the /classify route on the server.
const result = await fetch(`/classify?text=${encodeURIComponent(text)}`);
// If this is the first time we've made a request, set the ready flag.
if (!ready) setReady(true);
const json = await result.json();
setResult(json);
};
return (
<main className="flex min-h-screen flex-col items-center justify-center p-12">
<h1 className="text-5xl font-bold mb-2 text-center">Transformers.js</h1>
<h2 className="text-2xl mb-4 text-center">Next.js template (server-side)</h2>
<input
type="text"
className="w-full max-w-xs p-2 border border-gray-300 rounded mb-4"
placeholder="Enter text here"
onInput={e => {
classify(e.target.value);
}}
/>
{ready !== null && (
<pre className="bg-gray-100 p-2 rounded">
{
(!ready || !result) ? 'Loading...' : JSON.stringify(result, null, 2)}
</pre>
)}
</main>
)
}
您現在可以使用以下命令執行您的應用程式。
npm run dev
訪問終端中顯示的 URL(例如 https://:3000/)即可看到您的應用程式執行起來!
(可選)步驟4:構建和部署
對於此演示,我們將構建我們的應用程式並將其部署到 Hugging Face Spaces。如果您還沒有,可以在這裡建立一個免費的 Hugging Face 帳戶。
- 在您專案的根資料夾中建立一個新的
Dockerfile
。您可以使用我們的示例 Dockerfile 作為模板。 - 訪問 https://huggingface.co/new-space 並填寫表單。請記住選擇“Docker”作為空間型別(您可以選擇“Blank” Docker 模板)。
- 點選頁面底部的“建立空間”按鈕。
- 轉到“Files”→“Add file”→“Upload files”。將專案資料夾中的檔案(不包括
node_modules
和.next
,如果存在)拖到上傳框中,然後點選“Upload”。上傳完成後,向下滾動到按鈕並點選“Commit changes to main”。 - 將以下行新增到您的
README.md
檔案的頂部--- title: Next Server Example App emoji: 🔥 colorFrom: yellow colorTo: red sdk: docker pinned: false app_port: 3000 ---
就是這樣! 您的應用程式現在應該可以在 https://huggingface.co/spaces/<your-username>/<your-space-name>
上訪問了!