Skip to content

Commit 1f8b93b

Browse files
authored
Merge pull request huggingface#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

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

next-server/.gitignore

Lines changed: 40 additions & 0 deletions
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

Lines changed: 70 additions & 0 deletions
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

Lines changed: 42 additions & 0 deletions
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.
Lines changed: 18 additions & 0 deletions
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

Lines changed: 32 additions & 0 deletions
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

Lines changed: 21 additions & 0 deletions
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+
}

0 commit comments

Comments
 (0)