Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
Esteves Enzo
commited on
Commit
·
5916048
0
Parent(s):
init
Browse files- .env +1 -0
- .gitattributes +35 -0
- .gitignore +35 -0
- Dockerfile +25 -0
- README 2.md +36 -0
- README.md +11 -0
- app/layout.tsx +35 -0
- app/page.tsx +10 -0
- assets/globals.css +16 -0
- assets/hf-logo.svg +8 -0
- components/editor/header.tsx +18 -0
- components/editor/index.tsx +37 -0
- components/editor/main/endpoint.tsx +48 -0
- components/editor/main/index.tsx +68 -0
- components/editor/main/request.tsx +37 -0
- components/editor/main/response.tsx +11 -0
- components/editor/sidebar.tsx +92 -0
- components/method/index.tsx +23 -0
- next.config.js +4 -0
- package-lock.json +0 -0
- package.json +33 -0
- postcss.config.js +6 -0
- public/background_noisy.webp +0 -0
- tailwind.config.ts +17 -0
- tsconfig.json +27 -0
- utils/axios.ts +7 -0
- utils/datas/api_collections.ts +76 -0
- utils/index.ts +5 -0
- utils/type.ts +10 -0
.env
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
NEXT_PUBLIC_APP_APIURL=https://huggingface.co
|
.gitattributes
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
*.7z filter=lfs diff=lfs merge=lfs -text
|
2 |
+
*.arrow filter=lfs diff=lfs merge=lfs -text
|
3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
4 |
+
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
5 |
+
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
6 |
+
*.ftz filter=lfs diff=lfs merge=lfs -text
|
7 |
+
*.gz filter=lfs diff=lfs merge=lfs -text
|
8 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
9 |
+
*.joblib filter=lfs diff=lfs merge=lfs -text
|
10 |
+
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
11 |
+
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
12 |
+
*.model filter=lfs diff=lfs merge=lfs -text
|
13 |
+
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
14 |
+
*.npy filter=lfs diff=lfs merge=lfs -text
|
15 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
16 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
17 |
+
*.ot filter=lfs diff=lfs merge=lfs -text
|
18 |
+
*.parquet filter=lfs diff=lfs merge=lfs -text
|
19 |
+
*.pb filter=lfs diff=lfs merge=lfs -text
|
20 |
+
*.pickle filter=lfs diff=lfs merge=lfs -text
|
21 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
22 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
23 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
24 |
+
*.rar filter=lfs diff=lfs merge=lfs -text
|
25 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
26 |
+
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
27 |
+
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
28 |
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
29 |
+
*.tflite filter=lfs diff=lfs merge=lfs -text
|
30 |
+
*.tgz filter=lfs diff=lfs merge=lfs -text
|
31 |
+
*.wasm filter=lfs diff=lfs merge=lfs -text
|
32 |
+
*.xz filter=lfs diff=lfs merge=lfs -text
|
33 |
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
+
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
+
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
2 |
+
|
3 |
+
# dependencies
|
4 |
+
/node_modules
|
5 |
+
/.pnp
|
6 |
+
.pnp.js
|
7 |
+
|
8 |
+
# testing
|
9 |
+
/coverage
|
10 |
+
|
11 |
+
# next.js
|
12 |
+
/.next/
|
13 |
+
/out/
|
14 |
+
|
15 |
+
# production
|
16 |
+
/build
|
17 |
+
|
18 |
+
# misc
|
19 |
+
.DS_Store
|
20 |
+
*.pem
|
21 |
+
|
22 |
+
# debug
|
23 |
+
npm-debug.log*
|
24 |
+
yarn-debug.log*
|
25 |
+
yarn-error.log*
|
26 |
+
|
27 |
+
# local env files
|
28 |
+
.env*.local
|
29 |
+
|
30 |
+
# vercel
|
31 |
+
.vercel
|
32 |
+
|
33 |
+
# typescript
|
34 |
+
*.tsbuildinfo
|
35 |
+
next-env.d.ts
|
Dockerfile
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Dockerfile
|
2 |
+
|
3 |
+
# Use an official Node.js runtime as the base image
|
4 |
+
FROM node:18
|
5 |
+
|
6 |
+
# Set the working directory in the container
|
7 |
+
WORKDIR /usr/src/app
|
8 |
+
|
9 |
+
# Copy package.json and package-lock.json to the container
|
10 |
+
COPY package.json package-lock.json ./
|
11 |
+
|
12 |
+
# Install dependencies
|
13 |
+
RUN npm install
|
14 |
+
|
15 |
+
# Copy the rest of the application files to the container
|
16 |
+
COPY . .
|
17 |
+
|
18 |
+
# Build the Next.js application for production
|
19 |
+
RUN npm run build
|
20 |
+
|
21 |
+
# Expose the application port (assuming your app runs on port 3000)
|
22 |
+
EXPOSE 3000
|
23 |
+
|
24 |
+
# Start the application
|
25 |
+
CMD ["npm", "start"]
|
README 2.md
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
|
2 |
+
|
3 |
+
## Getting Started
|
4 |
+
|
5 |
+
First, run the development server:
|
6 |
+
|
7 |
+
```bash
|
8 |
+
npm run dev
|
9 |
+
# or
|
10 |
+
yarn dev
|
11 |
+
# or
|
12 |
+
pnpm dev
|
13 |
+
# or
|
14 |
+
bun dev
|
15 |
+
```
|
16 |
+
|
17 |
+
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
18 |
+
|
19 |
+
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
20 |
+
|
21 |
+
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
|
22 |
+
|
23 |
+
## Learn More
|
24 |
+
|
25 |
+
To learn more about Next.js, take a look at the following resources:
|
26 |
+
|
27 |
+
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
28 |
+
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
29 |
+
|
30 |
+
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
|
31 |
+
|
32 |
+
## Deploy on Vercel
|
33 |
+
|
34 |
+
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
35 |
+
|
36 |
+
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
|
README.md
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
title: Hugging Face Client REST API
|
3 |
+
emoji: ⚡
|
4 |
+
colorFrom: blue
|
5 |
+
colorTo: indigo
|
6 |
+
sdk: docker
|
7 |
+
pinned: true
|
8 |
+
license: mit
|
9 |
+
---
|
10 |
+
|
11 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
app/layout.tsx
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import type { Metadata } from "next";
|
2 |
+
import { Fira_Code, Inter } from "next/font/google";
|
3 |
+
import "@/assets/globals.css";
|
4 |
+
|
5 |
+
const inter = Inter({
|
6 |
+
subsets: ["latin"],
|
7 |
+
display: "swap",
|
8 |
+
variable: "--font-inter",
|
9 |
+
});
|
10 |
+
|
11 |
+
const fira_code = Fira_Code({
|
12 |
+
subsets: ["latin"],
|
13 |
+
display: "swap",
|
14 |
+
variable: "--font-fira-code",
|
15 |
+
});
|
16 |
+
|
17 |
+
export const metadata: Metadata = {
|
18 |
+
title: "Create Next App",
|
19 |
+
description: "Generated by create next app",
|
20 |
+
};
|
21 |
+
|
22 |
+
export default function RootLayout({
|
23 |
+
children,
|
24 |
+
}: {
|
25 |
+
children: React.ReactNode;
|
26 |
+
}) {
|
27 |
+
return (
|
28 |
+
<html lang="en" className={`${inter.variable} ${fira_code.variable}`}>
|
29 |
+
<body>
|
30 |
+
<div id="background__noisy" />
|
31 |
+
{children}
|
32 |
+
</body>
|
33 |
+
</html>
|
34 |
+
);
|
35 |
+
}
|
app/page.tsx
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Editor } from "@/components/editor";
|
2 |
+
import Image from "next/image";
|
3 |
+
|
4 |
+
export default function Home() {
|
5 |
+
return (
|
6 |
+
<section className="h-full">
|
7 |
+
<Editor />
|
8 |
+
</section>
|
9 |
+
);
|
10 |
+
}
|
assets/globals.css
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
@tailwind base;
|
2 |
+
@tailwind components;
|
3 |
+
@tailwind utilities;
|
4 |
+
|
5 |
+
html, body {
|
6 |
+
@apply bg-gray-200 min-h-screen relative tracking-wide overflow-x-hidden;
|
7 |
+
z-index: 1;
|
8 |
+
}
|
9 |
+
|
10 |
+
#background__noisy {
|
11 |
+
@apply bg-blend-normal pointer-events-none opacity-80;
|
12 |
+
background-size: 25ww auto;
|
13 |
+
background-image: url('/background_noisy.webp');
|
14 |
+
z-index: -1;
|
15 |
+
@apply fixed w-screen h-screen top-0 left-0;
|
16 |
+
}
|
assets/hf-logo.svg
ADDED
|
components/editor/header.tsx
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import HFLogo from "assets/hf-logo.svg";
|
2 |
+
import Image from "next/image";
|
3 |
+
|
4 |
+
export const EditorHeader = () => {
|
5 |
+
return (
|
6 |
+
<header className="px-6 py-2.5 border border-slate-950 bg-slate-950 flex justify-between items-center">
|
7 |
+
<Image src={HFLogo} alt="Hugging Face Logo" width={34} height={34} />
|
8 |
+
<p className="text-gray-300 font-code text-sm font-semibold">
|
9 |
+
Hugging Face API
|
10 |
+
</p>
|
11 |
+
<div className="flex items-center justify-end gap-3">
|
12 |
+
<div className="bg-teal-600 w-3 h-3 rounded-full" />
|
13 |
+
<div className="bg-indigo-600 w-3 h-3 rounded-full" />
|
14 |
+
<div className="bg-purple-500 w-3 h-3 rounded-full" />
|
15 |
+
</div>
|
16 |
+
</header>
|
17 |
+
);
|
18 |
+
};
|
components/editor/index.tsx
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"use client";
|
2 |
+
import { useState } from "react";
|
3 |
+
|
4 |
+
import { EditorHeader } from "./header";
|
5 |
+
import { EditorSidebar } from "./sidebar";
|
6 |
+
import { EditorMain } from "./main";
|
7 |
+
import { ApiRoute } from "@/utils/type";
|
8 |
+
import { API_COLLECTIONS } from "@/utils/datas/api_collections";
|
9 |
+
|
10 |
+
export const Editor = () => {
|
11 |
+
const [collections, setCollections] = useState<string[]>(["search"]);
|
12 |
+
const [endpoint, setEndpoint] = useState<ApiRoute | null>(
|
13 |
+
API_COLLECTIONS[0].endpoints[0]
|
14 |
+
);
|
15 |
+
|
16 |
+
return (
|
17 |
+
<div className="bg-slate-950 w-full overflow-hidden shadow-xl h-[100vh]">
|
18 |
+
<EditorHeader />
|
19 |
+
<main className="flex h-full">
|
20 |
+
<EditorSidebar
|
21 |
+
collections={collections}
|
22 |
+
endpoint={endpoint}
|
23 |
+
onCollections={setCollections}
|
24 |
+
onEndpoint={setEndpoint}
|
25 |
+
/>
|
26 |
+
{endpoint && (
|
27 |
+
<EditorMain
|
28 |
+
collections={collections}
|
29 |
+
endpoint={endpoint}
|
30 |
+
onCollections={setCollections}
|
31 |
+
onEndpoint={setEndpoint}
|
32 |
+
/>
|
33 |
+
)}
|
34 |
+
</main>
|
35 |
+
</div>
|
36 |
+
);
|
37 |
+
};
|
components/editor/main/endpoint.tsx
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { useMemo } from "react";
|
2 |
+
import classNames from "classnames";
|
3 |
+
|
4 |
+
import { Method } from "@/components/method";
|
5 |
+
import { splitStringBracket } from "@/utils";
|
6 |
+
import { ApiRoute } from "@/utils/type";
|
7 |
+
|
8 |
+
export const Endpoint = ({
|
9 |
+
endpoint,
|
10 |
+
children,
|
11 |
+
}: {
|
12 |
+
endpoint: ApiRoute;
|
13 |
+
children: React.ReactElement;
|
14 |
+
}) => {
|
15 |
+
const path_formatted = useMemo(
|
16 |
+
() => splitStringBracket(endpoint.path),
|
17 |
+
[endpoint.path]
|
18 |
+
);
|
19 |
+
|
20 |
+
return (
|
21 |
+
<div className="bg-slate-900 w-full">
|
22 |
+
<div className="bg-slate-950/50 p-3 rounded-lg flex items-center justify-between">
|
23 |
+
<div className="text-white text-sm flex items-center justify-start gap-2 w-full">
|
24 |
+
<Method method={endpoint.method} />
|
25 |
+
<div className="flex items-center justify-start gap-1">
|
26 |
+
{path_formatted.map((p, i) => {
|
27 |
+
const isCustomizable = p.includes("{") && p.includes("}");
|
28 |
+
return (
|
29 |
+
<p
|
30 |
+
key={i}
|
31 |
+
className={classNames("", {
|
32 |
+
"bg-indigo-600 !text-white px-1.5 rounded-md outline-none bg-opacity-80":
|
33 |
+
isCustomizable,
|
34 |
+
"text-slate-300": !isCustomizable,
|
35 |
+
})}
|
36 |
+
contentEditable={isCustomizable}
|
37 |
+
>
|
38 |
+
{p}
|
39 |
+
</p>
|
40 |
+
);
|
41 |
+
})}
|
42 |
+
</div>
|
43 |
+
</div>
|
44 |
+
{children}
|
45 |
+
</div>
|
46 |
+
</div>
|
47 |
+
);
|
48 |
+
};
|
components/editor/main/index.tsx
ADDED
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { useState } from "react";
|
2 |
+
|
3 |
+
import { ApiRoute } from "@/utils/type";
|
4 |
+
import axios from "@/utils/axios";
|
5 |
+
|
6 |
+
import { Endpoint } from "./endpoint";
|
7 |
+
import { Request } from "./request";
|
8 |
+
import { Response } from "./response";
|
9 |
+
|
10 |
+
export const EditorMain = ({
|
11 |
+
collections,
|
12 |
+
endpoint,
|
13 |
+
onCollections,
|
14 |
+
onEndpoint,
|
15 |
+
}: {
|
16 |
+
collections: string[];
|
17 |
+
endpoint: ApiRoute;
|
18 |
+
onCollections: (collections: string[]) => void;
|
19 |
+
onEndpoint: (endpoint: ApiRoute) => void;
|
20 |
+
}) => {
|
21 |
+
const [formattedEndpoint, setFormattedEndpoint] = useState<string | null>(
|
22 |
+
null
|
23 |
+
);
|
24 |
+
|
25 |
+
const [response, setResponse] = useState<any | null>(null);
|
26 |
+
|
27 |
+
const handleRequest = async () => {
|
28 |
+
const url = new URL(endpoint.path, process.env.NEXT_PUBLIC_APP_APIURL);
|
29 |
+
if (endpoint?.parameters) {
|
30 |
+
const parameters = Object.entries(endpoint.parameters).filter(
|
31 |
+
([key, value]) => value !== "" && value !== null
|
32 |
+
);
|
33 |
+
parameters.forEach(([key, value]) => {
|
34 |
+
url.searchParams.append(key, value as string);
|
35 |
+
});
|
36 |
+
}
|
37 |
+
console.log("url ", url);
|
38 |
+
|
39 |
+
axios
|
40 |
+
.get(url.pathname, {
|
41 |
+
params: url.searchParams,
|
42 |
+
})
|
43 |
+
.then((res: any) => {
|
44 |
+
console.log("res ", res);
|
45 |
+
if (res.ok) {
|
46 |
+
setResponse(res.data);
|
47 |
+
}
|
48 |
+
});
|
49 |
+
};
|
50 |
+
|
51 |
+
return (
|
52 |
+
<div className="flex-1 bg-slate-900/50 h-[calc(100%-56px)]">
|
53 |
+
<div className="h-full grid grid-cols-2">
|
54 |
+
<Request endpoint={endpoint}>
|
55 |
+
<Endpoint endpoint={endpoint}>
|
56 |
+
<button
|
57 |
+
className="bg-indigo-500 hover:bg-indigo-500/80 text-white px-3 py-1 rounded-lg text-sm"
|
58 |
+
onClick={handleRequest}
|
59 |
+
>
|
60 |
+
Send
|
61 |
+
</button>
|
62 |
+
</Endpoint>
|
63 |
+
</Request>
|
64 |
+
<Response res={response} />
|
65 |
+
</div>
|
66 |
+
</div>
|
67 |
+
);
|
68 |
+
};
|
components/editor/main/request.tsx
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ApiRoute } from "@/utils/type";
|
2 |
+
|
3 |
+
export const Request = ({
|
4 |
+
endpoint,
|
5 |
+
children,
|
6 |
+
}: {
|
7 |
+
endpoint: ApiRoute;
|
8 |
+
children: React.ReactElement;
|
9 |
+
}) => {
|
10 |
+
return (
|
11 |
+
<div className="h-full bg-slate-900 p-4">
|
12 |
+
{children}
|
13 |
+
{endpoint?.parameters && (
|
14 |
+
<div className="mt-6 grid grid-cols-1 gap-4">
|
15 |
+
<p className="text-slate-400 uppercase text-xs font-semibold">
|
16 |
+
Optional parameters
|
17 |
+
</p>
|
18 |
+
{endpoint?.parameters &&
|
19 |
+
Object.entries(endpoint.parameters).map(([key, value]) => (
|
20 |
+
<div
|
21 |
+
key={key}
|
22 |
+
className="flex items-center justify-between gap-2"
|
23 |
+
>
|
24 |
+
<p className="text-slate-300 text-sm">{key}</p>
|
25 |
+
<input
|
26 |
+
value={value as string}
|
27 |
+
type="text"
|
28 |
+
className="bg-slate-950/50 w-full rounded-md px-2 py-1 text-slate-100 outline-none placeholder:text-slate-600"
|
29 |
+
placeholder="value"
|
30 |
+
/>
|
31 |
+
</div>
|
32 |
+
))}
|
33 |
+
</div>
|
34 |
+
)}
|
35 |
+
</div>
|
36 |
+
);
|
37 |
+
};
|
components/editor/main/response.tsx
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import Highlight from "react-highlight";
|
2 |
+
import "node_modules/highlight.js/styles/atom-one-dark.css";
|
3 |
+
export const Response = ({ res }: { res: any }) => {
|
4 |
+
return (
|
5 |
+
<div className="overflow-auto h-full">
|
6 |
+
<Highlight className="json text-sm !bg-slate-950/10 !h-full !p-3">
|
7 |
+
{JSON.stringify(res ?? {}, null, 2)}
|
8 |
+
</Highlight>
|
9 |
+
</div>
|
10 |
+
);
|
11 |
+
};
|
components/editor/sidebar.tsx
ADDED
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"use client";
|
2 |
+
import { TbChevronDown } from "react-icons/tb";
|
3 |
+
import classNames from "classnames";
|
4 |
+
|
5 |
+
import { API_COLLECTIONS } from "@/utils/datas/api_collections";
|
6 |
+
import { Method } from "@/components/method";
|
7 |
+
import { ApiRoute } from "@/utils/type";
|
8 |
+
|
9 |
+
export const EditorSidebar = ({
|
10 |
+
collections,
|
11 |
+
endpoint,
|
12 |
+
onCollections,
|
13 |
+
onEndpoint,
|
14 |
+
}: {
|
15 |
+
collections: string[];
|
16 |
+
endpoint: ApiRoute | null;
|
17 |
+
onCollections: (collections: string[]) => void;
|
18 |
+
onEndpoint: (endpoint: ApiRoute) => void;
|
19 |
+
}) => {
|
20 |
+
const handleSetActiveCollection = (key: string) => {
|
21 |
+
if (collections.includes(key)) {
|
22 |
+
onCollections(collections.filter((col) => col !== key));
|
23 |
+
} else {
|
24 |
+
onCollections([...collections, key]);
|
25 |
+
}
|
26 |
+
};
|
27 |
+
|
28 |
+
// useUpdateEffect(() => {
|
29 |
+
// if (collections) {
|
30 |
+
// const first_endpoint = API_COLLECTIONS.find(
|
31 |
+
// (col) => col.key === collections
|
32 |
+
// )?.endpoints[0];
|
33 |
+
// if (first_endpoint) onEndpoint(first_endpoint);
|
34 |
+
// }
|
35 |
+
// }, [collections]);
|
36 |
+
|
37 |
+
return (
|
38 |
+
<ul className="min-w-[300px] max-w-sm w-full bg-slate-900 border-r border-slate-700/40 h-full overflow-auto">
|
39 |
+
{API_COLLECTIONS.map((collection, c) => (
|
40 |
+
<li key={collection.key} className="block w-full">
|
41 |
+
<div
|
42 |
+
className={classNames(
|
43 |
+
"p-4 border-b border-slate-700/70 text-slate-400 cursor-pointer hover:bg-slate-700/30 flex items-center justify-between transition-all duration-200 select-none active:bg-indigo-600 active:text-slate-100",
|
44 |
+
{
|
45 |
+
"bg-indigo-600 !text-slate-100 hover:!bg-indigo-600 !border-indigo-500":
|
46 |
+
collections.includes(collection.key),
|
47 |
+
}
|
48 |
+
)}
|
49 |
+
onClick={() => handleSetActiveCollection(collection.key)}
|
50 |
+
>
|
51 |
+
<p className="font-semibold uppercase text-xs flex items-center justify-between">
|
52 |
+
{collection.key} API
|
53 |
+
</p>
|
54 |
+
<TbChevronDown
|
55 |
+
className={classNames(
|
56 |
+
"text-slate-400 transition-all duration-200",
|
57 |
+
{
|
58 |
+
"transform rotate-180 !text-slate-100": collections.includes(
|
59 |
+
collection.key
|
60 |
+
),
|
61 |
+
}
|
62 |
+
)}
|
63 |
+
/>
|
64 |
+
</div>
|
65 |
+
{collections.includes(collection.key) && (
|
66 |
+
<div className="bg-slate-700/20 w-full p-3 border-b border-slate-700/70">
|
67 |
+
<ul className="w-full">
|
68 |
+
{collection.endpoints.map((end, e) => (
|
69 |
+
<li
|
70 |
+
key={e}
|
71 |
+
className={classNames(
|
72 |
+
"text-slate-400 font-semibold text-xs flex items-center justify-start gap-2 rounded-md p-2.5 hover:bg-slate-600 hover:bg-opacity-10 cursor-pointer border-t border-b border-transparent select-none",
|
73 |
+
{
|
74 |
+
"bg-slate-600 bg-opacity-20 hover:!bg-opacity-20 !text-slate-200 border-b !border-b-slate-700/70 border-t !border-t-slate-800":
|
75 |
+
endpoint?.path === end.path &&
|
76 |
+
endpoint?.method === end.method,
|
77 |
+
}
|
78 |
+
)}
|
79 |
+
onClick={() => onEndpoint(end)}
|
80 |
+
>
|
81 |
+
<Method method={end.method} />
|
82 |
+
<p className="truncate">{end.path}</p>
|
83 |
+
</li>
|
84 |
+
))}
|
85 |
+
</ul>
|
86 |
+
</div>
|
87 |
+
)}
|
88 |
+
</li>
|
89 |
+
))}
|
90 |
+
</ul>
|
91 |
+
);
|
92 |
+
};
|
components/method/index.tsx
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import classNames from "classnames";
|
2 |
+
|
3 |
+
export const Method = ({
|
4 |
+
method,
|
5 |
+
className,
|
6 |
+
}: {
|
7 |
+
method: string;
|
8 |
+
className?: string;
|
9 |
+
}) => (
|
10 |
+
<div
|
11 |
+
className={classNames(
|
12 |
+
`px-1 text-[10px] rounded text-slate-100 font-semibold inline-block ${className}`,
|
13 |
+
{
|
14 |
+
"bg-blue-500": method === "GET",
|
15 |
+
"bg-green-600": method === "POST",
|
16 |
+
"bg-yellow-600": method === "PUT" || method === "PATCH",
|
17 |
+
"bg-red-600": method === "DELETE",
|
18 |
+
}
|
19 |
+
)}
|
20 |
+
>
|
21 |
+
{method}
|
22 |
+
</div>
|
23 |
+
);
|
next.config.js
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/** @type {import('next').NextConfig} */
|
2 |
+
const nextConfig = {}
|
3 |
+
|
4 |
+
module.exports = nextConfig
|
package-lock.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
package.json
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "client-api",
|
3 |
+
"version": "0.1.0",
|
4 |
+
"private": true,
|
5 |
+
"scripts": {
|
6 |
+
"dev": "next dev",
|
7 |
+
"build": "next build",
|
8 |
+
"start": "next start",
|
9 |
+
"lint": "next lint"
|
10 |
+
},
|
11 |
+
"dependencies": {
|
12 |
+
"classnames": "^2.3.2",
|
13 |
+
"next": "13.5.6",
|
14 |
+
"react": "^18",
|
15 |
+
"react-dom": "^18",
|
16 |
+
"react-highlight": "^0.15.0",
|
17 |
+
"react-icons": "^4.11.0",
|
18 |
+
"react-use": "^17.4.0",
|
19 |
+
"redaxios": "^0.5.1"
|
20 |
+
},
|
21 |
+
"devDependencies": {
|
22 |
+
"@types/node": "^20",
|
23 |
+
"@types/react": "^18",
|
24 |
+
"@types/react-dom": "^18",
|
25 |
+
"@types/react-highlight": "^0.12.7",
|
26 |
+
"autoprefixer": "^10",
|
27 |
+
"eslint": "^8",
|
28 |
+
"eslint-config-next": "13.5.6",
|
29 |
+
"postcss": "^8",
|
30 |
+
"tailwindcss": "^3",
|
31 |
+
"typescript": "^5"
|
32 |
+
}
|
33 |
+
}
|
postcss.config.js
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
module.exports = {
|
2 |
+
plugins: {
|
3 |
+
tailwindcss: {},
|
4 |
+
autoprefixer: {},
|
5 |
+
},
|
6 |
+
}
|
public/background_noisy.webp
ADDED
![]() |
tailwind.config.ts
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import type { Config } from 'tailwindcss'
|
2 |
+
|
3 |
+
const config: Config = {
|
4 |
+
content: [
|
5 |
+
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
|
6 |
+
'./components/**/*.{js,ts,jsx,tsx,mdx}',
|
7 |
+
'./app/**/*.{js,ts,jsx,tsx,mdx}',
|
8 |
+
],
|
9 |
+
theme: {
|
10 |
+
fontFamily: {
|
11 |
+
sans: ['var(--font-inter)', 'sans-serif'],
|
12 |
+
code: ['var(--font-fira-code)', 'monospace'],
|
13 |
+
}
|
14 |
+
},
|
15 |
+
plugins: [],
|
16 |
+
}
|
17 |
+
export default config
|
tsconfig.json
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"compilerOptions": {
|
3 |
+
"target": "es5",
|
4 |
+
"lib": ["dom", "dom.iterable", "esnext"],
|
5 |
+
"allowJs": true,
|
6 |
+
"skipLibCheck": true,
|
7 |
+
"strict": true,
|
8 |
+
"noEmit": true,
|
9 |
+
"esModuleInterop": true,
|
10 |
+
"module": "esnext",
|
11 |
+
"moduleResolution": "bundler",
|
12 |
+
"resolveJsonModule": true,
|
13 |
+
"isolatedModules": true,
|
14 |
+
"jsx": "preserve",
|
15 |
+
"incremental": true,
|
16 |
+
"plugins": [
|
17 |
+
{
|
18 |
+
"name": "next"
|
19 |
+
}
|
20 |
+
],
|
21 |
+
"paths": {
|
22 |
+
"@/*": ["./*"]
|
23 |
+
}
|
24 |
+
},
|
25 |
+
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
26 |
+
"exclude": ["node_modules"]
|
27 |
+
}
|
utils/axios.ts
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import redaxios from 'redaxios';
|
2 |
+
|
3 |
+
const axios = redaxios.create({
|
4 |
+
baseURL: process.env.NEXT_PUBLIC_APP_APIURL
|
5 |
+
});
|
6 |
+
|
7 |
+
export default axios
|
utils/datas/api_collections.ts
ADDED
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ApiCollection } from "@/utils/type";
|
2 |
+
|
3 |
+
export const API_COLLECTIONS: Array<ApiCollection> = [{
|
4 |
+
key: 'search',
|
5 |
+
endpoints: [{
|
6 |
+
method: 'GET',
|
7 |
+
path: '/api/models',
|
8 |
+
parameters: {
|
9 |
+
search: "",
|
10 |
+
author: "",
|
11 |
+
filter: "",
|
12 |
+
sort: "",
|
13 |
+
direction: "",
|
14 |
+
limit: 10,
|
15 |
+
full: true,
|
16 |
+
config: true
|
17 |
+
}
|
18 |
+
}, {
|
19 |
+
method: 'GET',
|
20 |
+
path: '/api/models/{repo_id}'
|
21 |
+
}, {
|
22 |
+
method: 'GET',
|
23 |
+
path: '/api/models-tags-by-type'
|
24 |
+
}, {
|
25 |
+
method: 'GET',
|
26 |
+
path: '/api/datasets'
|
27 |
+
}, {
|
28 |
+
method: 'GET',
|
29 |
+
path: '/api/datasets/{repo_id}'
|
30 |
+
}],
|
31 |
+
}, {
|
32 |
+
key: 'repo',
|
33 |
+
endpoints: [{
|
34 |
+
method: 'POST',
|
35 |
+
path: '/api/repos/create',
|
36 |
+
}, {
|
37 |
+
method: 'DELETE',
|
38 |
+
path: '/api/repos/delete'
|
39 |
+
}, {
|
40 |
+
method: 'PUT',
|
41 |
+
path: '/api/repos/{repo_type}/{repo_id}/settings'
|
42 |
+
}, {
|
43 |
+
method: 'POST',
|
44 |
+
path: '/api/repos/move'
|
45 |
+
}],
|
46 |
+
}, {
|
47 |
+
key: 'user',
|
48 |
+
endpoints: [{
|
49 |
+
method: 'GET',
|
50 |
+
path: '/api/whoami-v2',
|
51 |
+
}],
|
52 |
+
}, {
|
53 |
+
key: 'collection',
|
54 |
+
endpoints: [{
|
55 |
+
method: 'POST',
|
56 |
+
path: '/api/collections',
|
57 |
+
}, {
|
58 |
+
method: 'GET',
|
59 |
+
path: '/api/collections/{namespace}/{slug}-{id}'
|
60 |
+
}, {
|
61 |
+
method: 'PATCH',
|
62 |
+
path: '/api/collections/{namespace}/{slug}-{id}'
|
63 |
+
}, {
|
64 |
+
method: 'DELETE',
|
65 |
+
path: '/api/collections/{namespace}/{slug}-{id}'
|
66 |
+
}, {
|
67 |
+
method: 'POST',
|
68 |
+
path: '/api/collections/{namespace}/{slug}-{id}/item'
|
69 |
+
}, {
|
70 |
+
method: 'PATCH',
|
71 |
+
path: '/api/collections/{namespace}/{slug}-{id}/items/{item_id}'
|
72 |
+
}, {
|
73 |
+
method: 'DELETE',
|
74 |
+
path: '/api/collections/{namespace}/{slug}-{id}/items/{item_id}'
|
75 |
+
}],
|
76 |
+
}]
|
utils/index.ts
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export const splitStringBracket = (str: string): string[] => {
|
2 |
+
// Split string by bracket but keep the bracket
|
3 |
+
const result = str.split(/(\{.*?\})/g)
|
4 |
+
return result.filter((item) => item !== '')
|
5 |
+
}
|
utils/type.ts
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export interface ApiCollection {
|
2 |
+
key: string
|
3 |
+
endpoints: Array<ApiRoute>
|
4 |
+
}
|
5 |
+
|
6 |
+
export interface ApiRoute {
|
7 |
+
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'
|
8 |
+
path: string,
|
9 |
+
parameters?: any
|
10 |
+
}
|