final?
Browse files- PROMPT.md +81 -0
- README.md +18 -1
- backend/Makefile +1 -1
- frontend/src/App.tsx +5 -3
- frontend/src/components/BackendHealthCheck.tsx +1 -1
- frontend/src/components/OAuthButton.tsx +1 -1
- frontend/src/{config/constants.ts → constants.ts} +0 -0
- frontend/src/utils/apiFetch.ts +1 -1
PROMPT.md
ADDED
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
This repository contains a full-stack application designed to be deployed in a Hugging Face Space.
|
2 |
+
|
3 |
+
## backend/
|
4 |
+
|
5 |
+
The backend/ folder contains the API server, implemented in Python using FastAPI. Project is built using uv.
|
6 |
+
Main commands in that folder are:
|
7 |
+
- `make dev` to run a local dev server
|
8 |
+
- `make style` to apply code formatting
|
9 |
+
- `make quality` to check code format
|
10 |
+
- `make test` to run tests
|
11 |
+
- `uv add ...` to add a new dependency
|
12 |
+
|
13 |
+
When working in the `backend/` folder, please keep these instructions in mind:
|
14 |
+
- API is defined in `backend/src/app.py` using FastAPI. For now it contains an health check endpoint and endpoints to deal with the counter.
|
15 |
+
- You can define as many new endpoints as you need. Follow the FastAPI best practices. All routes should be defined under `/api` prefix.
|
16 |
+
- OAuth is already baked in. If an endpoint requires the user to be authenticated, pass `oauth_info: RequiredOAuth` as argument. If authentication is optional, pass `oauth_info: OptionalOAuth`. If you don't need authentication, no need for that arg. `RequiredOAuth` is a dataclass of type `OAuthInfo` (see below). `OptionalOAuth` is of type `OAuthInfo | None`.
|
17 |
+
- schemas are defined in `backend/src/schemas.py`. We use [SQLModel](https://sqlmodel.tiangolo.com/) to define them which is a wrapper on top of Pydantic and SQLAlchemy. Any object defined in this module with `table=True` will result in a table in the database. Since all models are Pydantic object, you can use them seamlessly with FastAPI. See examples in `backend/src/app.py` on how to load an object from database and how to insert one.
|
18 |
+
- The FastAPI server and Database are configured in `backend/src/app_factory.py`. DO NOT UPDATE this file.
|
19 |
+
- If the `BACKUP_DATASET_ID` and `HF_TOKEN` env variables are defined, the database will be regularly exported as parquet files in a dataset on the Hub. This is useful to have persistent storage in a Space. Export is done once every 5 minutes in an optimized way (only new data is upload). All of the logic is defined in `backend/src/app_factory.py` and `backend/src/parquet.py`. DO NOT UPDATE these files.
|
20 |
+
- App config and constants are defined in `backend/src/constants.py`. You can add new config value if required. Do not update existing ones unless explicitly requested.
|
21 |
+
|
22 |
+
### OAuthInfo definition
|
23 |
+
|
24 |
+
Here is how `OAuthInfo` dataclass is defined in Python. Useful when a user is authenticated.
|
25 |
+
|
26 |
+
```py
|
27 |
+
@dataclass
|
28 |
+
class OAuthUserInfo:
|
29 |
+
sub: str
|
30 |
+
name: str
|
31 |
+
preferred_username: str
|
32 |
+
email_verified: Optional[bool]
|
33 |
+
email: Optional[str]
|
34 |
+
picture: str
|
35 |
+
profile: str
|
36 |
+
website: Optional[str]
|
37 |
+
is_pro: bool
|
38 |
+
can_pay: Optional[bool]
|
39 |
+
orgs: Optional[List[OAuthOrgInfo]]
|
40 |
+
|
41 |
+
|
42 |
+
@dataclass
|
43 |
+
class OAuthInfo:
|
44 |
+
access_token: str
|
45 |
+
access_token_expires_at: datetime.datetime
|
46 |
+
user_info: OAuthUserInfo
|
47 |
+
state: Optional[str]
|
48 |
+
scope: str
|
49 |
+
```
|
50 |
+
|
51 |
+
## frontend/
|
52 |
+
|
53 |
+
The frontend/ folder contains the UI implemented in TS with React and Tailwind. Project is built using vite.
|
54 |
+
Main commands in that folder are:
|
55 |
+
- `pnpm install` to install packages
|
56 |
+
- `pnpm dev` to run a local dev environment
|
57 |
+
- `pnpm style` to apply code formatting
|
58 |
+
- `pnpm quality` to check code format
|
59 |
+
- `pnpm add (-D) ...` to add a new package
|
60 |
+
|
61 |
+
When working in the `frontend/` folder, please keep these instructions in mind:
|
62 |
+
- UI is a single-page application. It doesn't use any router. You must keep this structure.
|
63 |
+
- Main app is located in `frontend/src/App.tsx`.
|
64 |
+
- Components are defined in `frontend/src/components`.
|
65 |
+
- To make request to the backend, use `apiFetch` from `frontend/src/utils/apiFetch.ts`. It is a wrapper around `fetch` with a predefined backend url and authenticated calls.
|
66 |
+
- Authentication has to be done using the `OAuthButton` defined in `frontend/src/components/OAuthButton.tsx`. DO NOT UPDATE this file.
|
67 |
+
- The `BackendHealthCheck` component in `frontend/src/components/BackendHealthCheck.tsx` is made for dev purpose only. DO NOT UPDATE this file except if requested specifically.
|
68 |
+
- The `Counter` component in `frontend/src/components/Counter.tsx` is a good example on how to define a component making calls to the backend. You can remove / update it if necessary.
|
69 |
+
- You can define as many new components as you want. Make each component self contained. Define new components in `frontend/src/components/`.
|
70 |
+
- App config and constants are defined in `frontend/src/constants.ts` (backend url, health check interval, etc.). You can add new config value if required.
|
71 |
+
- Assets (images, etc.) should be added to the `frontend/src/assets` folder. There is a `frontend/src/assets/huggingface.svg` in it (Hugging Face logo). DO NOT REMOVE it. You can reuse it if you want and/or add any assets you want.
|
72 |
+
- Config files (`frontend/vite.config.ts`, `frontend/tsconfig.json`, `frontend/tsconfig.node.json`, `frontend/eslint.config.js`, `frontend/src/vite-env.d.ts`) should not be updated expect if explicitly requested by user.
|
73 |
+
- DO NOT MODIFY `frontend/src/index.css` (which imports tailwind) and `frontend/src/main.tsx` (main imports).
|
74 |
+
|
75 |
+
|
76 |
+
## How to add a new feature?
|
77 |
+
|
78 |
+
- add new API routes in `backend/src/app.py`. If needed, add a new schema in `backend/src/schemas.py`. Use authentication if required.
|
79 |
+
- add a new component in `frontend/src/components` and update `frontend/src/App.tsx` to include it.
|
80 |
+
- let the user run `cd frontend && pnpm dev` and `cd backend && make dev` in 2 terminals to try it out
|
81 |
+
- once tested, commit the changes and push to remote branch
|
README.md
CHANGED
@@ -17,7 +17,24 @@ This repo is a template to run a FastAPI server hosting a React+Tailwind app in
|
|
17 |
|
18 |
Spaces are very well suited to vibe-code demos using Cursor, Lovable, Claude Code, etc. The hardest past is often to correctly configure the tooltip to make it work in the first place. This repo is intended to solve that.
|
19 |
|
20 |
-
##
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
|
22 |
The backend (Python + FastAPI) and the frontend (TS + React + Tailwind) are located respectively in the `backend/` and `frontend/` folder.
|
23 |
|
|
|
17 |
|
18 |
Spaces are very well suited to vibe-code demos using Cursor, Lovable, Claude Code, etc. The hardest past is often to correctly configure the tooltip to make it work in the first place. This repo is intended to solve that.
|
19 |
|
20 |
+
## Main features
|
21 |
+
|
22 |
+
- 🚀 Built for HF Spaces
|
23 |
+
- ✨ Vibe-coding ready (see [PROMPT.md](./PROMPT.md))
|
24 |
+
- 🤗 Support OAuth (Sign in with Hugging Face)
|
25 |
+
- ⚡ FastAPI for the API²
|
26 |
+
- 🎨 React + Tailwind for the UI
|
27 |
+
- 💾 local SQLLite database + regular backups as HF dataset
|
28 |
+
|
29 |
+
## Quick start
|
30 |
+
|
31 |
+
1. Duplicate the Space.
|
32 |
+
2. Set an `HF_TOKEN` as Space secret and `BACKUP_DATASET_ID` as Space variable. These will be used to make regular backups of the database.
|
33 |
+
3. At this stage, Space should be running correctly on the Hub with a demo.
|
34 |
+
4. For local development, follow the dev instructions below.
|
35 |
+
5. Once server is running locally, you can start to edit it. All instructions are located in `PROMPT.md`. Inject that file in the vibe coding tool of your choice and start building!
|
36 |
+
|
37 |
+
## Instructions
|
38 |
|
39 |
The backend (Python + FastAPI) and the frontend (TS + React + Tailwind) are located respectively in the `backend/` and `frontend/` folder.
|
40 |
|
backend/Makefile
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
.PHONY: quality style
|
2 |
|
3 |
dev:
|
4 |
HF_HUB_DISABLE_EXPERIMENTAL_WARNING=1 uv run uvicorn src.app:app --reload
|
|
|
1 |
+
.PHONY: quality style dev preview test
|
2 |
|
3 |
dev:
|
4 |
HF_HUB_DISABLE_EXPERIMENTAL_WARNING=1 uv run uvicorn src.app:app --reload
|
frontend/src/App.tsx
CHANGED
@@ -78,16 +78,18 @@ function App() {
|
|
78 |
|
79 |
<div className="bg-gray-800/30 backdrop-blur-sm rounded-xl p-6 border border-gray-700/30">
|
80 |
<div className="text-cyan-400 text-2xl mb-3">💾</div>
|
81 |
-
<h3 className="text-lg font-semibold mb-2">
|
|
|
|
|
82 |
<p className="text-gray-300 text-sm">
|
83 |
-
|
84 |
</p>
|
85 |
</div>
|
86 |
</div>
|
87 |
|
88 |
<div className="bg-gray-800/20 backdrop-blur-sm rounded-xl p-6 border border-gray-700/20 mb-8">
|
89 |
<h3 className="text-xl font-semibold mb-4 text-center">
|
90 |
-
Duplicate this Space
|
91 |
</h3>
|
92 |
</div>
|
93 |
</div>
|
|
|
78 |
|
79 |
<div className="bg-gray-800/30 backdrop-blur-sm rounded-xl p-6 border border-gray-700/30">
|
80 |
<div className="text-cyan-400 text-2xl mb-3">💾</div>
|
81 |
+
<h3 className="text-lg font-semibold mb-2">
|
82 |
+
SQLite + Parquet backups
|
83 |
+
</h3>
|
84 |
<p className="text-gray-300 text-sm">
|
85 |
+
Work with SQLite locally, but persist data in a HF dataset as parquet
|
86 |
</p>
|
87 |
</div>
|
88 |
</div>
|
89 |
|
90 |
<div className="bg-gray-800/20 backdrop-blur-sm rounded-xl p-6 border border-gray-700/20 mb-8">
|
91 |
<h3 className="text-xl font-semibold mb-4 text-center">
|
92 |
+
Duplicate this Space to start building!
|
93 |
</h3>
|
94 |
</div>
|
95 |
</div>
|
frontend/src/components/BackendHealthCheck.tsx
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import { useState, useEffect } from "react";
|
2 |
-
import { BACKEND_URL, APP_CONFIG } from "../
|
3 |
|
4 |
interface BackendHealthCheckProps {
|
5 |
checkInterval?: number;
|
|
|
1 |
import { useState, useEffect } from "react";
|
2 |
+
import { BACKEND_URL, APP_CONFIG } from "../constants";
|
3 |
|
4 |
interface BackendHealthCheckProps {
|
5 |
checkInterval?: number;
|
frontend/src/components/OAuthButton.tsx
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import React, { useState, useEffect } from "react";
|
2 |
-
import { BACKEND_URL } from "../
|
3 |
import { apiFetch } from "../utils/apiFetch";
|
4 |
|
5 |
interface UserInfo {
|
|
|
1 |
import React, { useState, useEffect } from "react";
|
2 |
+
import { BACKEND_URL } from "../constants";
|
3 |
import { apiFetch } from "../utils/apiFetch";
|
4 |
|
5 |
interface UserInfo {
|
frontend/src/{config/constants.ts → constants.ts}
RENAMED
File without changes
|
frontend/src/utils/apiFetch.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
import { BACKEND_URL } from "../
|
2 |
|
3 |
export async function apiFetch(
|
4 |
endpoint: string,
|
|
|
1 |
+
import { BACKEND_URL } from "../constants";
|
2 |
|
3 |
export async function apiFetch(
|
4 |
endpoint: string,
|