enzostvs HF staff commited on
Commit
bab2147
1 Parent(s): 704ade6

share roast feature

Browse files
Dockerfile CHANGED
@@ -1,24 +1,32 @@
1
  # Dockerfile
 
2
  # Use an official Node.js runtime as the base image
3
  FROM node:18
4
 
 
 
5
  # Set the working directory in the container
6
  WORKDIR /usr/src/app
7
 
8
  # Copy package.json and package-lock.json to the container
9
- COPY package.json package-lock.json ./
10
 
11
  # Install dependencies
12
  RUN npm install
13
 
 
 
14
  # Copy the rest of the application files to the container
15
- COPY . .
 
16
 
17
  # Build the Next.js application for production
18
- RUN npm run build
19
 
20
  # Expose the application port (assuming your app runs on port 3000)
21
  EXPOSE 3000
22
 
 
 
23
  # Start the application
24
- CMD ["npm", "start"]
 
1
  # Dockerfile
2
+
3
  # Use an official Node.js runtime as the base image
4
  FROM node:18
5
 
6
+ USER 1000
7
+
8
  # Set the working directory in the container
9
  WORKDIR /usr/src/app
10
 
11
  # Copy package.json and package-lock.json to the container
12
+ COPY --chown=1000 package.json package-lock.json ./
13
 
14
  # Install dependencies
15
  RUN npm install
16
 
17
+ VOLUME /data
18
+
19
  # Copy the rest of the application files to the container
20
+ COPY --chown=1000 . .
21
+ RUN chmod +x entrypoint.sh
22
 
23
  # Build the Next.js application for production
24
+ # RUN npm run build
25
 
26
  # Expose the application port (assuming your app runs on port 3000)
27
  EXPOSE 3000
28
 
29
+ RUN npx prisma generate
30
+
31
  # Start the application
32
+ ENTRYPOINT ["/usr/src/app/entrypoint.sh"]
app/[roastId]/page.tsx ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { redirect } from "next/navigation";
2
+ import Image from "next/image";
3
+
4
+ import { getRoast } from "@/app/actions/roast";
5
+ import { Quote } from "@/components/quote";
6
+ import Logo from "@/assets/logo.svg";
7
+ import Link from "next/link";
8
+
9
+ async function get(id: string) {
10
+ const roast = await getRoast({ id });
11
+ return roast;
12
+ }
13
+
14
+ export default async function Roast({
15
+ params: { roastId },
16
+ }: {
17
+ params: { roastId: string };
18
+ }) {
19
+ const quote = await get(roastId);
20
+
21
+ if (!quote?.data) {
22
+ redirect("/");
23
+ }
24
+ return (
25
+ <div>
26
+ <header className="flex items-start max-lg:gap-1 lg:items-center justify-between max-lg:flex-col border-b border-zinc-200 pb-5">
27
+ <Image
28
+ src={Logo}
29
+ alt="logo hugging face"
30
+ width={100}
31
+ height={100}
32
+ className="object-contain w-36 lg:w-44"
33
+ />
34
+ <div>
35
+ <p className="text-sm text-zinc-500">
36
+ Roast your favorite Hugging Face user! 👹
37
+ </p>
38
+ </div>
39
+ </header>
40
+ <Quote data={quote.data?.text}>
41
+ <Link
42
+ href="/"
43
+ className="bg-black rounded-full inline-block px-4 py-2.5 text-sm font-medium text-white hover:bg-zinc-800 mt-5"
44
+ >
45
+ Roast another user! 🧨
46
+ </Link>
47
+ </Quote>
48
+ </div>
49
+ );
50
+ }
app/actions/roast.ts CHANGED
@@ -5,6 +5,7 @@ import { HfInference } from '@huggingface/inference'
5
 
6
  import { formatInformations, transformForInference } from "@/utils/roast";
7
  import { FormProps } from "@/components/form";
 
8
 
9
  const MODEL_ID = "meta-llama/Meta-Llama-3.1-70B-Instruct";
10
 
@@ -60,4 +61,23 @@ export async function roast({ username, language }: FormProps) {
60
  return {
61
  data: res.generated_text
62
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  }
 
5
 
6
  import { formatInformations, transformForInference } from "@/utils/roast";
7
  import { FormProps } from "@/components/form";
8
+ import prisma from "@/utils/prisma";
9
 
10
  const MODEL_ID = "meta-llama/Meta-Llama-3.1-70B-Instruct";
11
 
 
61
  return {
62
  data: res.generated_text
63
  }
64
+ }
65
+
66
+ export async function getRoast({ id } : { id: string }) {
67
+ const roast = await prisma.quote.findUnique({
68
+ where: {
69
+ id
70
+ }
71
+ })
72
+
73
+ if (!roast) {
74
+ return {
75
+ error: "Roast not found",
76
+ status: 404
77
+ }
78
+ }
79
+
80
+ return {
81
+ data: roast
82
+ }
83
  }
app/actions/share.ts ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use server";
2
+ import prisma from "@/utils/prisma";
3
+
4
+ export interface ShareProps {
5
+ hf_user: string;
6
+ text: string;
7
+ }
8
+
9
+ export async function share(form: ShareProps) {
10
+
11
+ const quote = await prisma.quote.create({
12
+ data: {
13
+ hf_user: form.hf_user,
14
+ text: form.text
15
+ }
16
+ })
17
+
18
+ return {
19
+ data: quote
20
+ }
21
+ }
app/api/roast/route.ts DELETED
@@ -1,16 +0,0 @@
1
- import { NextResponse } from "next/server";
2
-
3
- export async function POST(req: Request) {
4
- const body = await req.json();
5
- console.log(body);
6
-
7
- // fetch the user's username from the body
8
- const { username } = body;
9
-
10
- // fetch user from hugging face API
11
- const user = await fetch(`https://huggingface.co/api/users/${username}`);
12
-
13
- console.log(user);
14
-
15
- return NextResponse.json({ message: "Roasted!" });
16
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/layout.tsx CHANGED
@@ -16,7 +16,11 @@ export default function RootLayout({
16
  }>) {
17
  return (
18
  <html lang="en">
19
- <body className={inter.className}>{children}</body>
 
 
 
 
20
  </html>
21
  );
22
  }
 
16
  }>) {
17
  return (
18
  <html lang="en">
19
+ <body className={inter.className}>
20
+ <section className="min-h-screen h-full w-full flex items-center justify-center flex-col bg-zinc-100 gap-5 overflow-auto p-6">
21
+ {children}
22
+ </section>
23
+ </body>
24
  </html>
25
  );
26
  }
app/page.tsx CHANGED
@@ -4,7 +4,10 @@ import Image from "next/image";
4
  import classNames from "classnames";
5
 
6
  import { roast } from "@/app/actions/roast";
 
7
  import { Form, FormProps } from "@/components/form";
 
 
8
 
9
  import Logo from "@/assets/logo.svg";
10
 
@@ -12,6 +15,9 @@ export default function Home() {
12
  const [data, setData] = useState("");
13
  const [error, setError] = useState("");
14
  const [loading, setLoading] = useState(false);
 
 
 
15
 
16
  const handleRoast = async (form: FormProps) => {
17
  setError("");
@@ -26,14 +32,25 @@ export default function Home() {
26
  if (res.error) {
27
  setError(res.error);
28
  } else {
 
 
29
  setData(res?.data);
30
  }
31
 
32
  setLoading(false);
33
  };
34
 
 
 
 
 
 
 
 
 
 
35
  return (
36
- <section className="min-h-screen h-full w-full flex items-center justify-center flex-col bg-zinc-100 gap-5 overflow-auto p-6">
37
  <div className="max-w-2xl w-full border border-gray-200 bg-white rounded-3xl p-8 grid gap-8 shadow-xl shadow-black/5">
38
  <header className="flex items-start max-lg:gap-1 lg:items-center justify-between max-lg:flex-col border-b border-zinc-200 pb-5">
39
  <Image
@@ -58,29 +75,27 @@ export default function Home() {
58
  <Form loading={loading} onSubmit={handleRoast} />
59
  </div>
60
  {data && (
61
- <div className="max-w-2xl w-full border border-gray-200 bg-white rounded-3xl p-8 shadow-xl shadow-black/5 relative z-[1] overflow-hidden">
62
- <p className="text-[8rem] absolute bottom-0 translate-y-1/3 right-0 opacity-20 -z-[1]">
63
- 🧨
64
- </p>
65
- <p className="uppercase text-base tracking-wider font-semibold mb-2">
66
- Roasting
67
- </p>
68
- <div className="text-lg text-gray-500 leading-relaxed container mx-auto text-pretty whitespace-break-spaces">
69
- {data}
70
- </div>
71
- <button
72
- className={classNames(
73
- "bg-black rounded-full mt-4 px-4 py-2.5 text-sm font-medium text-white hover:bg-zinc-800 disabled:bg-zinc-300 disabled:text-zinc-500 disabled:cursor-not-allowed",
74
- {
75
- // "animate-pulse": loading,
76
  }
77
- )}
78
- disabled={true}
79
- >
80
- Share (coming soon)
81
- </button>
82
- </div>
83
  )}
84
- </section>
85
  );
86
  }
 
4
  import classNames from "classnames";
5
 
6
  import { roast } from "@/app/actions/roast";
7
+ import { share, ShareProps } from "@/app/actions/share";
8
  import { Form, FormProps } from "@/components/form";
9
+ import { CopyToClipboard } from "@/components/copy";
10
+ import { Quote } from "@/components/quote";
11
 
12
  import Logo from "@/assets/logo.svg";
13
 
 
15
  const [data, setData] = useState("");
16
  const [error, setError] = useState("");
17
  const [loading, setLoading] = useState(false);
18
+ const [loadingShare, setLoadingShare] = useState(false);
19
+ const [hfUser, setHfUser] = useState<string | undefined>(undefined);
20
+ const [quote, setQuote] = useState<string | undefined>(undefined);
21
 
22
  const handleRoast = async (form: FormProps) => {
23
  setError("");
 
32
  if (res.error) {
33
  setError(res.error);
34
  } else {
35
+ setQuote(undefined);
36
+ setHfUser(form.username);
37
  setData(res?.data);
38
  }
39
 
40
  setLoading(false);
41
  };
42
 
43
+ const handleShare = async (form: ShareProps) => {
44
+ setLoadingShare(true);
45
+ const res = await share({ hf_user: form.hf_user, text: form.text });
46
+ if (res?.data) {
47
+ setQuote(res.data.id);
48
+ }
49
+ setLoadingShare(false);
50
+ };
51
+
52
  return (
53
+ <>
54
  <div className="max-w-2xl w-full border border-gray-200 bg-white rounded-3xl p-8 grid gap-8 shadow-xl shadow-black/5">
55
  <header className="flex items-start max-lg:gap-1 lg:items-center justify-between max-lg:flex-col border-b border-zinc-200 pb-5">
56
  <Image
 
75
  <Form loading={loading} onSubmit={handleRoast} />
76
  </div>
77
  {data && (
78
+ <Quote data={data}>
79
+ {quote ? (
80
+ <CopyToClipboard id={quote} />
81
+ ) : (
82
+ <button
83
+ className={classNames(
84
+ "bg-black rounded-full mt-4 px-4 py-2.5 text-sm font-medium text-white hover:bg-zinc-800 disabled:bg-zinc-300 disabled:text-zinc-500 disabled:cursor-not-allowed",
85
+ {
86
+ "animate-pulse": loadingShare,
87
+ }
88
+ )}
89
+ disabled={loadingShare}
90
+ onClick={() =>
91
+ hfUser && handleShare({ hf_user: hfUser, text: data })
 
92
  }
93
+ >
94
+ {loadingShare ? "Creating a quote..." : "Share my roast!"}
95
+ </button>
96
+ )}
97
+ </Quote>
 
98
  )}
99
+ </>
100
  );
101
  }
components/copy.tsx ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import classNames from "classnames";
2
+ import { CopyIcon } from "lucide-react";
3
+ import { useMemo, useState } from "react";
4
+ import { useCopyToClipboard, useUpdateEffect } from "react-use";
5
+
6
+ export const CopyToClipboard = ({ id }: { id: string }) => {
7
+ const [state, copyToClipboard] = useCopyToClipboard();
8
+ const [copied, setCopied] = useState(false);
9
+
10
+ const url = useMemo(() => {
11
+ return `https://huggingface.co/spaces/enzostvs/hugger-roaster/${id}`;
12
+ }, [id]);
13
+
14
+ const handleCopy = () => {
15
+ setCopied(true);
16
+ copyToClipboard(url);
17
+ setTimeout(() => {
18
+ setCopied(false);
19
+ }, 2000);
20
+ };
21
+
22
+ return (
23
+ <div className="w-full mt-5">
24
+ <p className="text-xs text-zinc-500">
25
+ Share this link with your friends so they can see your roast and try it
26
+ out themselves!
27
+ </p>
28
+ <div
29
+ className="bg-white mt-2 max-w-max rounded-md mr-2 border border-gray-200 text-sm px-3 py-2.5 relative ring-transparent text-zinc-600 hover:ring-blue-500/20 ring-[3px] flex items-center justify-center group"
30
+ onClick={handleCopy}
31
+ >
32
+ <div
33
+ className={classNames(
34
+ "bg-black/80 text-xs text-white px-2 py-1 rounded-md absolute left-0 top-0 -translate-y-1/2 transition-all duration-200",
35
+ {
36
+ "opacity-0 !translate-y-0": !copied,
37
+ }
38
+ )}
39
+ >
40
+ Copied!
41
+ </div>
42
+ <CopyIcon className="w-4 h-4 text-zinc-400 mr-2 group-hover:text-blue-500" />
43
+ <p className="flex-1">{url}</p>
44
+ </div>
45
+ </div>
46
+ );
47
+ };
components/quote.tsx ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export const Quote = ({
2
+ data,
3
+ children,
4
+ }: {
5
+ data: string;
6
+ children?: React.ReactNode;
7
+ }) => {
8
+ return (
9
+ <div className="max-w-2xl w-full border border-gray-200 bg-white rounded-3xl p-8 shadow-xl shadow-black/5 relative z-[1] overflow-hidden">
10
+ <p className="text-[8rem] absolute bottom-0 translate-y-1/3 right-0 opacity-20 -z-[1]">
11
+ 🧨
12
+ </p>
13
+ <p className="uppercase text-base tracking-wider font-semibold mb-2">
14
+ Roasting
15
+ </p>
16
+ <div className="text-lg text-gray-500 leading-relaxed container mx-auto text-pretty whitespace-break-spaces">
17
+ {data}
18
+ </div>
19
+ {children}
20
+ </div>
21
+ );
22
+ };
entrypoint.sh ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ #!/bin/bash
2
+ npm run build && npx prisma generate && npx prisma migrate deploy && npx prisma db push && npm start
package-lock.json CHANGED
@@ -9,10 +9,12 @@
9
  "version": "0.1.0",
10
  "dependencies": {
11
  "@huggingface/inference": "^2.8.0",
 
12
  "@xenova/transformers": "^2.17.2",
13
  "classnames": "^2.5.1",
14
  "lucide-react": "^0.436.0",
15
  "next": "14.2.7",
 
16
  "react": "^18",
17
  "react-dom": "^18",
18
  "react-use": "^17.5.1"
@@ -460,6 +462,63 @@
460
  "node": ">=14"
461
  }
462
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
463
  "node_modules/@protobufjs/aspromise": {
464
  "version": "1.1.2",
465
  "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
@@ -2463,7 +2522,6 @@
2463
  "version": "2.3.3",
2464
  "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
2465
  "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
2466
- "dev": true,
2467
  "hasInstallScript": true,
2468
  "optional": true,
2469
  "os": [
@@ -4308,6 +4366,24 @@
4308
  "node": ">= 0.8.0"
4309
  }
4310
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4311
  "node_modules/prop-types": {
4312
  "version": "15.8.1",
4313
  "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
 
9
  "version": "0.1.0",
10
  "dependencies": {
11
  "@huggingface/inference": "^2.8.0",
12
+ "@prisma/client": "^5.19.0",
13
  "@xenova/transformers": "^2.17.2",
14
  "classnames": "^2.5.1",
15
  "lucide-react": "^0.436.0",
16
  "next": "14.2.7",
17
+ "prisma": "^5.19.0",
18
  "react": "^18",
19
  "react-dom": "^18",
20
  "react-use": "^17.5.1"
 
462
  "node": ">=14"
463
  }
464
  },
465
+ "node_modules/@prisma/client": {
466
+ "version": "5.19.0",
467
+ "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.19.0.tgz",
468
+ "integrity": "sha512-CzOpau+q1kEWQyoQMvlnXIHqPvwmWbh48xZ4n8KWbAql0p8PC0BIgSTYW5ncxXa4JSEff0tcoxSZB874wDstdg==",
469
+ "hasInstallScript": true,
470
+ "engines": {
471
+ "node": ">=16.13"
472
+ },
473
+ "peerDependencies": {
474
+ "prisma": "*"
475
+ },
476
+ "peerDependenciesMeta": {
477
+ "prisma": {
478
+ "optional": true
479
+ }
480
+ }
481
+ },
482
+ "node_modules/@prisma/debug": {
483
+ "version": "5.19.0",
484
+ "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.19.0.tgz",
485
+ "integrity": "sha512-+b/G0ubAZlrS+JSiDhXnYV5DF/aTJ3pinktkiV/L4TtLRLZO6SVGyFELgxBsicCTWJ2ZMu5vEV/jTtYCdjFTRA=="
486
+ },
487
+ "node_modules/@prisma/engines": {
488
+ "version": "5.19.0",
489
+ "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.19.0.tgz",
490
+ "integrity": "sha512-UtW+0m4HYoRSSR3LoDGKF3Ud4BSMWYlLEt4slTnuP1mI+vrV3zaDoiAPmejdAT76vCN5UqnWURbkXxf66nSylQ==",
491
+ "hasInstallScript": true,
492
+ "dependencies": {
493
+ "@prisma/debug": "5.19.0",
494
+ "@prisma/engines-version": "5.19.0-31.5fe21811a6ba0b952a3bc71400666511fe3b902f",
495
+ "@prisma/fetch-engine": "5.19.0",
496
+ "@prisma/get-platform": "5.19.0"
497
+ }
498
+ },
499
+ "node_modules/@prisma/engines-version": {
500
+ "version": "5.19.0-31.5fe21811a6ba0b952a3bc71400666511fe3b902f",
501
+ "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.19.0-31.5fe21811a6ba0b952a3bc71400666511fe3b902f.tgz",
502
+ "integrity": "sha512-GimI9aZIFy/yvvR11KfXRn3pliFn1QAkdebVlsXlnoh5uk0YhLblVmeYiHfsu+wDA7BeKqYT4sFfzg8mutzuWw=="
503
+ },
504
+ "node_modules/@prisma/fetch-engine": {
505
+ "version": "5.19.0",
506
+ "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.19.0.tgz",
507
+ "integrity": "sha512-oOiPNtmJX0cP/ebu7BBEouJvCw8T84/MFD/Hf2zlqjxkK4ojl38bB9i9J5LAxotL6WlYVThKdxc7HqoWnPOhqQ==",
508
+ "dependencies": {
509
+ "@prisma/debug": "5.19.0",
510
+ "@prisma/engines-version": "5.19.0-31.5fe21811a6ba0b952a3bc71400666511fe3b902f",
511
+ "@prisma/get-platform": "5.19.0"
512
+ }
513
+ },
514
+ "node_modules/@prisma/get-platform": {
515
+ "version": "5.19.0",
516
+ "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.19.0.tgz",
517
+ "integrity": "sha512-s9DWkZKnuP4Y8uy6yZfvqQ/9X3/+2KYf3IZUVZz5OstJdGBJrBlbmIuMl81917wp5TuK/1k2TpHNCEdpYLPKmg==",
518
+ "dependencies": {
519
+ "@prisma/debug": "5.19.0"
520
+ }
521
+ },
522
  "node_modules/@protobufjs/aspromise": {
523
  "version": "1.1.2",
524
  "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
 
2522
  "version": "2.3.3",
2523
  "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
2524
  "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
 
2525
  "hasInstallScript": true,
2526
  "optional": true,
2527
  "os": [
 
4366
  "node": ">= 0.8.0"
4367
  }
4368
  },
4369
+ "node_modules/prisma": {
4370
+ "version": "5.19.0",
4371
+ "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.19.0.tgz",
4372
+ "integrity": "sha512-Pu7lUKpVyTx8cVwM26dYh8NdvMOkMnJXzE8L6cikFuR4JwyMU5NKofQkWyxJKlTT4fNjmcnibTvklV8oVMrn+g==",
4373
+ "hasInstallScript": true,
4374
+ "dependencies": {
4375
+ "@prisma/engines": "5.19.0"
4376
+ },
4377
+ "bin": {
4378
+ "prisma": "build/index.js"
4379
+ },
4380
+ "engines": {
4381
+ "node": ">=16.13"
4382
+ },
4383
+ "optionalDependencies": {
4384
+ "fsevents": "2.3.3"
4385
+ }
4386
+ },
4387
  "node_modules/prop-types": {
4388
  "version": "15.8.1",
4389
  "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
package.json CHANGED
@@ -10,10 +10,12 @@
10
  },
11
  "dependencies": {
12
  "@huggingface/inference": "^2.8.0",
 
13
  "@xenova/transformers": "^2.17.2",
14
  "classnames": "^2.5.1",
15
  "lucide-react": "^0.436.0",
16
  "next": "14.2.7",
 
17
  "react": "^18",
18
  "react-dom": "^18",
19
  "react-use": "^17.5.1"
 
10
  },
11
  "dependencies": {
12
  "@huggingface/inference": "^2.8.0",
13
+ "@prisma/client": "^5.19.0",
14
  "@xenova/transformers": "^2.17.2",
15
  "classnames": "^2.5.1",
16
  "lucide-react": "^0.436.0",
17
  "next": "14.2.7",
18
+ "prisma": "^5.19.0",
19
  "react": "^18",
20
  "react-dom": "^18",
21
  "react-use": "^17.5.1"
prisma/dev.db ADDED
Binary file (20.5 kB). View file
 
prisma/schema.prisma ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ generator client {
2
+ provider = "prisma-client-js"
3
+ }
4
+
5
+ datasource db {
6
+ provider = "sqlite"
7
+ url = env("DATABASE_URL")
8
+ }
9
+
10
+ model Quote {
11
+ id String @id @default(cuid())
12
+ hf_user String
13
+ text String
14
+ }
utils/prisma.ts ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ import { PrismaClient } from '@prisma/client'
2
+
3
+ const prisma = new PrismaClient()
4
+ export default prisma
utils/roast copy.ts DELETED
@@ -1,55 +0,0 @@
1
- const formatSpacesInfos = (spaces: any) => {
2
- const texts: string[] = []
3
- spaces.map((space: any) => {
4
- let text = `${space.cardData?.title} has ${space.likes} likes and has been updated ${space.lastModified} ago.`
5
- if (space.cardData?.short_description) {
6
- text += `The space description is: ${space.cardData?.short_description}`
7
- }
8
- texts.push(text)
9
- })
10
-
11
- return texts.join("\n")
12
- }
13
-
14
- const formatModelsInfos = (models: any) => {
15
- const texts: string[] = []
16
- models.map((model: any) => {
17
- let text = `${model.id?.split("/")[1]} has ${model.likes} likes and ${model.downloads} downloads.`
18
- if (model.gating) {
19
- text += `You should ask for access to this model.`
20
- } else {
21
- text += `This model is public.`
22
- }
23
- text += `This model is about ${model.pipeline_tag}`
24
-
25
- texts.push(text)
26
- })
27
-
28
- return texts.join("\n")
29
- }
30
-
31
- const formatUserInfos = (user: any, countFollowing: number, countFollowers: number, spacesLikes: number, modelsLikes: number, spaces: any, models: any) => {
32
- return `
33
- The user ${user.fullname} has ${countFollowers} followers and is following ${countFollowing} users.
34
- He is part of ${user.orgs?.length ?? 0} organizations.
35
- He is owner of ${spaces?.length ?? 0} spaces and has ${models?.length ?? 0} models.
36
- He already liked ${user.likes?.length ?? 0} models/spaces/datasets. This user is ${user.isPro ? "pro" : "not pro"}.
37
- He has ${spacesLikes} likes on his spaces and ${modelsLikes} likes on his models.
38
- `
39
- }
40
-
41
- export const formatInformations = (
42
- user: any,
43
- countFollowing: number,
44
- countFollowers: number,
45
- spaces: any,
46
- models: any,
47
- spacesLikes: number,
48
- modelsLikes: number
49
- ) => {
50
- const userInfos = formatUserInfos(user, countFollowing, countFollowers, spacesLikes, modelsLikes, spaces, models)
51
- const spacesInfos = formatSpacesInfos(spaces.slice(0, 6))
52
- const modelsInfos = formatModelsInfos(models.slice(0, 6))
53
-
54
- return `${userInfos}\n\n${spacesInfos}\n\n${modelsInfos}`
55
- }