Skip to content

Add space demo template #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions spaces/space-demo-template/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}
40 changes: 40 additions & 0 deletions spaces/space-demo-template/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# env files (can opt-in for commiting if needed)
.env*

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
70 changes: 70 additions & 0 deletions spaces/space-demo-template/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Adapted from https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile
# For more information, see https://nextjs.org/docs/pages/building-your-application/deploying#docker-image

# Use a base image for building
FROM node:18-slim AS base

# Install git
RUN apt-get update && apt-get install -y git

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using apt-get install -y --no-install-recommends git to avoid installing unnecessary recommended packages, which can help reduce the image size.


# Clone the repository and navigate to the next-server folder
WORKDIR /app
RUN git clone https://github.com/huggingface/transformers.js-examples .

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cloning the entire repository might include unnecessary files. Consider using a shallow clone or copying only the necessary files to reduce the image size.


# Set the working directory to the next-server folder
WORKDIR /app/next-server

# Install dependencies only when needed
FROM base AS deps

# Install dependencies based on the preferred package manager
RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding --production flag to yarn and npm ci commands to install only production dependencies, which can help reduce the image size.

elif [ -f package-lock.json ]; then npm ci; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
else echo "Lockfile not found." && exit 1; \
fi

# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app/next-server
COPY --from=deps /app/next-server/node_modules ./node_modules
COPY . .

RUN \
if [ -f yarn.lock ]; then yarn run build; \
elif [ -f package-lock.json ]; then npm run build; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \
else echo "Lockfile not found." && exit 1; \
fi

# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app/next-server

ENV NODE_ENV=production

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /app/next-server/public ./public

# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown nextjs:nodejs .next

# Automatically leverage output traces to reduce image size
COPY --from=builder --chown=nextjs:nodejs /app/next-server/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/next-server/.next/static ./.next/static

USER nextjs

# Allow the running process to write model files to the cache folder.
RUN mkdir -p /app/next-server/node_modules/@huggingface/transformers/.cache
RUN chmod 777 -R /app/next-server/node_modules/@huggingface/transformers/.cache

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using chmod 777 can pose security risks by allowing all users to read, write, and execute. Consider setting more restrictive permissions.


EXPOSE 3000

ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
CMD ["node", "server.js"]
45 changes: 45 additions & 0 deletions spaces/space-demo-template/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
title: Topcoder Hugging Face Space Template with Docker + Next.js
emoji: 🗄️
colorFrom: blue
colorTo: purple
sdk: docker
pinned: false
app_port: 3000
---

# Topcoder Hugging Face Space Template with Docker + Next.js

This project, bootstrapped using [`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) in the Topcoder Huggig Face organization.

Original repo source: https://github.com/huggingface/transformers.js-examples/tree/main/next-server

## Instructions

1. Clone the repository:

```sh
git clone https://github.com/topcoder-platform/tc-huggingface-spaces.git
```

2. Change directory to the `spaces/space-demo-template` project:

```sh
cd tc-huggingface-spaces/spaces/space-demo-template
```

3. Install the dependencies:

```sh
npm install
```

4. Run the development server:

```sh
npm run dev
```

5. Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
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.
7. Enjoy developing at Topcoder with Hugging Face.
20 changes: 20 additions & 0 deletions spaces/space-demo-template/app/api/classify/route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// https://nextjs.org/docs/app/building-your-application/routing/route-handlers

import { pipeline } from "@huggingface/transformers";

// NOTE: We attach the classifier to the global object to avoid unnecessary reloads during development
const classifier = (globalThis.classifier ??= await pipeline(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using globalThis to store the classifier can lead to potential issues in environments where globalThis is shared across multiple requests or instances. Consider using a more isolated storage mechanism if this is a concern.

"text-classification",
"Xenova/distilbert-base-uncased-finetuned-sst-2-english",
));

export async function GET(request) {
const text = request.nextUrl.searchParams.get("text");

if (!text) {
return Response.json({ message: "No text provided" }, { status: 400 });

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using a more descriptive error message to help users understand what input is expected, such as 'Query parameter "text" is required'.

}

const result = await classifier(text);
return Response.json(result[0]);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure that result[0] is always defined before accessing it to prevent potential runtime errors. Consider adding a check to handle cases where result might be empty or undefined.

}
32 changes: 32 additions & 0 deletions spaces/space-demo-template/app/classifier.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"use client";

import { useEffect, useState } from "react";

export default function Classifier() {
const [text, setText] = useState("I love Topcoder!");
const [result, setResult] = useState(null);

useEffect(() => {
const params = new URLSearchParams();
params.append("text", text);
const url = "/api/classify?" + params.toString();

fetch(url)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding error handling for the fetch request to handle potential network errors or server issues. This can improve the user experience by providing feedback if something goes wrong.

.then((res) => res.json())
.then((o) => setResult(o));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable name 'o' is not descriptive. Consider renaming it to something more meaningful, like 'data' or 'response', to improve code readability.

}, [text]);

return (
<>
<input
value={text}
onChange={(e) => setText(e.target.value)}
className="border border-gray-300 rounded p-2 dark:bg-black dark:text-white w-full"
></input>

<pre className="border border-gray-300 rounded p-2 dark:bg-black dark:text-white w-full min-h-[120px]">
{result ? JSON.stringify(result, null, 2) : "Loading…"}
</pre>
</>
);
}
Binary file added spaces/space-demo-template/app/favicon.ico
Binary file not shown.
Binary file not shown.
Binary file added spaces/space-demo-template/app/fonts/GeistVF.woff
Binary file not shown.
21 changes: 21 additions & 0 deletions spaces/space-demo-template/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

:root {
--background: #ffffff;
--foreground: #171717;
}

@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
}

body {
color: var(--foreground);
background: var(--background);
font-family: Arial, Helvetica, sans-serif;
}
30 changes: 30 additions & 0 deletions spaces/space-demo-template/app/layout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import localFont from "next/font/local";
import "./globals.css";

const geistSans = localFont({
src: "./fonts/GeistVF.woff",
variable: "--font-geist-sans",
weight: "100 900",
});
const geistMono = localFont({
src: "./fonts/GeistMonoVF.woff",
variable: "--font-geist-mono",
weight: "100 900",
});

export const metadata = {
title: "Topcoder Hugging Face Space Template with Docker + Next.js",
description: "Generated by create next app",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The description in the metadata object is generic. Consider providing a more specific description that accurately reflects the purpose or functionality of this template.

};

export default function RootLayout({ children }) {
return (
<html lang="en">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
{children}
</body>
</html>
);
}
92 changes: 92 additions & 0 deletions spaces/space-demo-template/app/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import Image from "next/image";
import Classifier from "./classifier";

export default function Home() {
return (
<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)]">
<main className="flex flex-col gap-8 row-start-2 items-center sm:items-start">
<div className="flex items-center">
<Image
src="/topcoder-logo.svg"
alt="Topcoder logo"
width={201}
height={31}
priority
/>
<span className="text-4xl font-light mx-5">&#xd7;</span>
<Image
src="/hf-logo.svg"
alt="Hugging Face logo"
width={50}
height={50}
priority
/>
<span className="text-4xl font-light mx-5">&#xd7;</span>
<Image
className="dark:invert"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding a fallback for the className attribute to ensure consistent styling in environments where the dark mode class might not be applied.

src="/next.svg"
alt="Next.js logo"
width={180}
height={38}
priority
/>
</div>
<ol className="list-inside list-decimal text-sm text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
<li className="mb-2">
Get started by editing{" "}
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-semibold">
app/page.js
</code>
.
</li>
<li className="mb-2">
Update Transformers.js code in{" "}
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-semibold">
app/api/classify/route.js
</code>
.
</li>
<li>Save and see your changes instantly.</li>
</ol>

<div className="flex gap-4 items-center flex-col sm:flex-row">
<a
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"
href="https://github.com/topcoder-platform/tc-huggingface-spaces.git"
target="_blank"
rel="noopener noreferrer"
>
Source code
</a>

{/* <a

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commented-out code block for the 'Read our docs' link should be removed if it's not intended for future use, to keep the codebase clean.

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"
href="https://huggingface.co/docs/transformers.js/index"
target="_blank"
rel="noopener noreferrer"
>
Read our docs
</a> */}
</div>
<Classifier />
</main>
<footer className="row-start-3 flex gap-6 flex-wrap items-center justify-center">
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://www.topcoder.com/ai-hub/competitions?utm_campaign=huggingface&utm_source=huggingface&utm_medium=Topcoder"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="/globe.svg"
alt="Globe icon"
width={16}
height={16}
/>
Go to Topcoder AI Hub Competitions →
</a>
</footer>
</div>
);
}
7 changes: 7 additions & 0 deletions spaces/space-demo-template/jsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"compilerOptions": {
"paths": {
"@/*": ["./*"]
}
}
}
9 changes: 9 additions & 0 deletions spaces/space-demo-template/next.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
// https://nextjs.org/docs/app/api-reference/config/next-config-js/output
output: "standalone",
// https://nextjs.org/docs/app/api-reference/config/next-config-js/serverExternalPackages
serverExternalPackages: ["@huggingface/transformers"],
};

export default nextConfig;
Loading