Skip to content

Commit 1f8b93b

Browse files
authored
Merge pull request #9 from huggingface/next-examples
Create Next.js server-side example project
2 parents f4c89bb + 18339d1 commit 1f8b93b

23 files changed

+5945
-0
lines changed

next-server/.eslintrc.json

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "next/core-web-vitals"
3+
}

next-server/.gitignore

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.*
7+
.yarn/*
8+
!.yarn/patches
9+
!.yarn/plugins
10+
!.yarn/releases
11+
!.yarn/versions
12+
13+
# testing
14+
/coverage
15+
16+
# next.js
17+
/.next/
18+
/out/
19+
20+
# production
21+
/build
22+
23+
# misc
24+
.DS_Store
25+
*.pem
26+
27+
# debug
28+
npm-debug.log*
29+
yarn-debug.log*
30+
yarn-error.log*
31+
32+
# env files (can opt-in for commiting if needed)
33+
.env*
34+
35+
# vercel
36+
.vercel
37+
38+
# typescript
39+
*.tsbuildinfo
40+
next-env.d.ts

next-server/Dockerfile

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Adapted from https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile
2+
# For more information, see https://nextjs.org/docs/pages/building-your-application/deploying#docker-image
3+
4+
# Use a base image for building
5+
FROM node:18-slim AS base
6+
7+
# Install git
8+
RUN apt-get update && apt-get install -y git
9+
10+
# Clone the repository and navigate to the next-server folder
11+
WORKDIR /app
12+
RUN git clone https://github.com/huggingface/transformers.js-examples .
13+
14+
# Set the working directory to the next-server folder
15+
WORKDIR /app/next-server
16+
17+
# Install dependencies only when needed
18+
FROM base AS deps
19+
20+
# Install dependencies based on the preferred package manager
21+
RUN \
22+
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
23+
elif [ -f package-lock.json ]; then npm ci; \
24+
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
25+
else echo "Lockfile not found." && exit 1; \
26+
fi
27+
28+
# Rebuild the source code only when needed
29+
FROM base AS builder
30+
WORKDIR /app/next-server
31+
COPY --from=deps /app/next-server/node_modules ./node_modules
32+
COPY . .
33+
34+
RUN \
35+
if [ -f yarn.lock ]; then yarn run build; \
36+
elif [ -f package-lock.json ]; then npm run build; \
37+
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \
38+
else echo "Lockfile not found." && exit 1; \
39+
fi
40+
41+
# Production image, copy all the files and run next
42+
FROM base AS runner
43+
WORKDIR /app/next-server
44+
45+
ENV NODE_ENV=production
46+
47+
RUN addgroup --system --gid 1001 nodejs
48+
RUN adduser --system --uid 1001 nextjs
49+
50+
COPY --from=builder /app/next-server/public ./public
51+
52+
# Set the correct permission for prerender cache
53+
RUN mkdir .next
54+
RUN chown nextjs:nodejs .next
55+
56+
# Automatically leverage output traces to reduce image size
57+
COPY --from=builder --chown=nextjs:nodejs /app/next-server/.next/standalone ./
58+
COPY --from=builder --chown=nextjs:nodejs /app/next-server/.next/static ./.next/static
59+
60+
USER nextjs
61+
62+
# Allow the running process to write model files to the cache folder.
63+
RUN mkdir -p /app/next-server/node_modules/@huggingface/transformers/.cache
64+
RUN chmod 777 -R /app/next-server/node_modules/@huggingface/transformers/.cache
65+
66+
EXPOSE 3000
67+
68+
ENV PORT=3000
69+
ENV HOSTNAME="0.0.0.0"
70+
CMD ["node", "server.js"]

next-server/README.md

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
title: Next.js + Transformers.js Server Template
3+
emoji: 🗄️
4+
colorFrom: blue
5+
colorTo: purple
6+
sdk: docker
7+
pinned: false
8+
app_port: 3000
9+
---
10+
11+
# next-server
12+
13+
This project, bootstrapped using generated by [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app), demonstrates how to use `@huggingface/transformers` in [Next.js](https://nextjs.org).
14+
15+
## Instructions
16+
17+
1. Clone the repository:
18+
```sh
19+
git clone https://github.com/huggingface/transformers.js-examples.git
20+
```
21+
2. Change directory to the `next-server` project:
22+
```sh
23+
cd transformers.js-examples/next-server
24+
```
25+
3. Install the dependencies:
26+
```sh
27+
npm install
28+
```
29+
4. Run the development server:
30+
```sh
31+
npm run dev
32+
```
33+
5. Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
34+
35+
6. You can start editing the page by modifying `app/page.js` (Next.js) and `app/api/classify/route.js` (Transformers.js). The page auto-updates as you edit the file.
36+
37+
## Learn More
38+
39+
To learn more about Next.js, take a look at the following resources:
40+
41+
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
42+
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

next-server/app/api/classify/route.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// https://nextjs.org/docs/app/building-your-application/routing/route-handlers
2+
3+
import { pipeline } from "@huggingface/transformers";
4+
5+
// NOTE: We attach the classifier to the global object to avoid loading it multiple times
6+
const classifier = (globalThis.classifier ??= await pipeline(
7+
"text-classification",
8+
"Xenova/distilbert-base-uncased-finetuned-sst-2-english",
9+
));
10+
11+
export async function GET(request) {
12+
// https://nextjs.org/docs/app/building-your-axpplication/routing/route-handlers#url-query-parameters
13+
const searchParams = request.nextUrl.searchParams;
14+
const text = searchParams.get("text");
15+
16+
const result = await classifier(text);
17+
return Response.json(result[0]);
18+
}

next-server/app/classifier.js

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"use client";
2+
3+
import { useEffect, useState } from "react";
4+
5+
export default function Classifier() {
6+
const [text, setText] = useState("I love Transformers.js!");
7+
const [result, setResult] = useState(null);
8+
9+
useEffect(() => {
10+
const params = new URLSearchParams();
11+
params.append("text", text);
12+
const url = "/api/classify?" + params.toString();
13+
14+
fetch(url)
15+
.then((res) => res.json())
16+
.then((o) => setResult(o));
17+
}, [text]);
18+
19+
return (
20+
<>
21+
<input
22+
value={text}
23+
onChange={(e) => setText(e.target.value)}
24+
className="border border-gray-300 rounded p-2 dark:bg-black dark:text-white w-full"
25+
></input>
26+
27+
<pre className="border border-gray-300 rounded p-2 dark:bg-black dark:text-white w-full min-h-[120px]">
28+
{result ? JSON.stringify(result, null, 2) : "Loading…"}
29+
</pre>
30+
</>
31+
);
32+
}

next-server/app/favicon.ico

46.8 KB
Binary file not shown.
66.3 KB
Binary file not shown.

next-server/app/fonts/GeistVF.woff

64.7 KB
Binary file not shown.

next-server/app/globals.css

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
@tailwind base;
2+
@tailwind components;
3+
@tailwind utilities;
4+
5+
:root {
6+
--background: #ffffff;
7+
--foreground: #171717;
8+
}
9+
10+
@media (prefers-color-scheme: dark) {
11+
:root {
12+
--background: #0a0a0a;
13+
--foreground: #ededed;
14+
}
15+
}
16+
17+
body {
18+
color: var(--foreground);
19+
background: var(--background);
20+
font-family: Arial, Helvetica, sans-serif;
21+
}

next-server/app/layout.js

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import localFont from "next/font/local";
2+
import "./globals.css";
3+
4+
const geistSans = localFont({
5+
src: "./fonts/GeistVF.woff",
6+
variable: "--font-geist-sans",
7+
weight: "100 900",
8+
});
9+
const geistMono = localFont({
10+
src: "./fonts/GeistMonoVF.woff",
11+
variable: "--font-geist-mono",
12+
weight: "100 900",
13+
});
14+
15+
export const metadata = {
16+
title: "Create Next App",
17+
description: "Generated by create next app",
18+
};
19+
20+
export default function RootLayout({ children }) {
21+
return (
22+
<html lang="en">
23+
<body
24+
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
25+
>
26+
{children}
27+
</body>
28+
</html>
29+
);
30+
}

next-server/app/page.js

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import Image from "next/image";
2+
import Classifier from "./classifier";
3+
4+
export default function Home() {
5+
return (
6+
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-8 font-[family-name:var(--font-geist-sans)]">
7+
<main className="flex flex-col gap-8 row-start-2 items-center sm:items-start">
8+
<div className="flex items-center">
9+
<Image
10+
src="/hf-logo.svg"
11+
alt="Hugging Face logo"
12+
width={50}
13+
height={50}
14+
priority
15+
/>
16+
<span className="text-4xl font-light mx-5">&#xd7;</span>
17+
<Image
18+
className="dark:invert"
19+
src="/next.svg"
20+
alt="Next.js logo"
21+
width={180}
22+
height={38}
23+
priority
24+
/>
25+
</div>
26+
<ol className="list-inside list-decimal text-sm text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
27+
<li className="mb-2">
28+
Get started by editing{" "}
29+
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-semibold">
30+
app/page.js
31+
</code>
32+
.
33+
</li>
34+
<li className="mb-2">
35+
Update Transformers.js code in{" "}
36+
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-semibold">
37+
app/api/classify/route.js
38+
</code>
39+
.
40+
</li>
41+
<li>Save and see your changes instantly.</li>
42+
</ol>
43+
44+
<div className="flex gap-4 items-center flex-col sm:flex-row">
45+
<a
46+
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5"
47+
href="https://github.com/huggingface/transformers.js-examples/tree/main/next-server"
48+
target="_blank"
49+
rel="noopener noreferrer"
50+
>
51+
Source code
52+
</a>
53+
54+
<a
55+
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5"
56+
href="https://huggingface.co/docs/transformers.js/index"
57+
target="_blank"
58+
rel="noopener noreferrer"
59+
>
60+
Read our docs
61+
</a>
62+
</div>
63+
<Classifier />
64+
</main>
65+
<footer className="row-start-3 flex gap-6 flex-wrap items-center justify-center">
66+
<a
67+
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
68+
href="https://github.com/huggingface/transformers.js"
69+
target="_blank"
70+
rel="noopener noreferrer"
71+
>
72+
<Image
73+
aria-hidden
74+
src="/github.svg"
75+
alt="GitHub icon"
76+
width={16}
77+
height={16}
78+
/>
79+
Transformers.js
80+
</a>
81+
<a
82+
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
83+
href="https://github.com/huggingface/transformers.js-examples"
84+
target="_blank"
85+
rel="noopener noreferrer"
86+
>
87+
<Image
88+
aria-hidden
89+
src="/window.svg"
90+
alt="Window icon"
91+
width={16}
92+
height={16}
93+
/>
94+
Examples
95+
</a>
96+
<a
97+
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
98+
href="https://hf.co"
99+
target="_blank"
100+
rel="noopener noreferrer"
101+
>
102+
<Image
103+
aria-hidden
104+
src="/globe.svg"
105+
alt="Globe icon"
106+
width={16}
107+
height={16}
108+
/>
109+
Go to hf.co →
110+
</a>
111+
</footer>
112+
</div>
113+
);
114+
}

next-server/jsconfig.json

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"compilerOptions": {
3+
"paths": {
4+
"@/*": ["./*"]
5+
}
6+
}
7+
}

next-server/next.config.mjs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/** @type {import('next').NextConfig} */
2+
const nextConfig = {
3+
output: "standalone",
4+
// https://nextjs.org/docs/app/api-reference/next-config-js/serverExternalPackages
5+
serverExternalPackages: ["@huggingface/transformers"],
6+
};
7+
8+
export default nextConfig;

0 commit comments

Comments
 (0)