Seth commited on
Commit
25bda12
·
1 Parent(s): 7dfcef5
Dockerfile ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ---------- build frontend ----------
2
+ FROM node:20-bookworm AS frontend-build
3
+ WORKDIR /frontend
4
+ COPY frontend/package.json frontend/package-lock.json* ./
5
+ RUN npm install
6
+ COPY frontend/ .
7
+ RUN npm run build
8
+
9
+ # ---------- runtime ----------
10
+ FROM python:3.11-slim
11
+ WORKDIR /app
12
+
13
+ # Backend deps
14
+ COPY backend/requirements.txt /app/backend/requirements.txt
15
+ RUN pip install --no-cache-dir -r /app/backend/requirements.txt
16
+
17
+ # Copy backend code
18
+ COPY backend /app/backend
19
+
20
+ # Copy frontend build into /app/frontend/dist
21
+ COPY --from=frontend-build /frontend/dist /app/frontend/dist
22
+
23
+ # HF Spaces uses port 7860
24
+ EXPOSE 7860
25
+
26
+ CMD ["uvicorn", "backend.app.main:app", "--host", "0.0.0.0", "--port", "7860"]
README.md CHANGED
@@ -1,8 +1,8 @@
1
  ---
2
- title: DocClassify
3
- emoji: 😻
4
- colorFrom: pink
5
- colorTo: red
6
  sdk: docker
7
  pinned: false
8
  ---
 
1
  ---
2
+ title: PostGen
3
+ emoji: 🐨
4
+ colorFrom: yellow
5
+ colorTo: green
6
  sdk: docker
7
  pinned: false
8
  ---
backend/app/main.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from fastapi.responses import FileResponse
3
+ from fastapi.staticfiles import StaticFiles
4
+ from fastapi.middleware.cors import CORSMiddleware
5
+ from pathlib import Path
6
+
7
+ app = FastAPI()
8
+
9
+ app.add_middleware(
10
+ CORSMiddleware,
11
+ allow_origins=["*"],
12
+ allow_credentials=True,
13
+ allow_methods=["*"],
14
+ allow_headers=["*"],
15
+ )
16
+
17
+ # ---- API ----
18
+ @app.get("/api/health")
19
+ def health():
20
+ return {"status": "ok"}
21
+
22
+ @app.get("/api/hello")
23
+ def hello():
24
+ return {"message": "Hello from FastAPI"}
25
+
26
+ # ---- Frontend static serving ----
27
+ FRONTEND_DIST = Path(__file__).resolve().parents[2] / "frontend" / "dist"
28
+ INDEX_FILE = FRONTEND_DIST / "index.html"
29
+
30
+ if FRONTEND_DIST.exists():
31
+ app.mount("/", StaticFiles(directory=str(FRONTEND_DIST), html=True), name="static")
32
+
33
+ # SPA fallback: any non-/api route should return React index.html
34
+ @app.get("/{full_path:path}")
35
+ def spa_fallback(full_path: str):
36
+ if full_path.startswith("api/"):
37
+ return {"detail": "Not Found"}
38
+ return FileResponse(str(INDEX_FILE))
backend/requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ fastapi
2
+ uvicorn
frontend/index.html ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>HF React + FastAPI by Seth</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/main.jsx"></script>
11
+ </body>
12
+ </html>
frontend/package.json ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "hf-react",
3
+ "private": true,
4
+ "version": "0.0.1",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite --host 0.0.0.0 --port 5173",
8
+ "build": "vite build",
9
+ "preview": "vite preview --host 0.0.0.0 --port 5173"
10
+ },
11
+ "dependencies": {
12
+ "react": "^18.3.1",
13
+ "react-dom": "^18.3.1"
14
+ },
15
+ "devDependencies": {
16
+ "@vitejs/plugin-react": "^4.3.1",
17
+ "vite": "^5.4.2"
18
+ }
19
+ }
frontend/src/App.jsx ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useEffect, useState } from "react";
2
+
3
+ export default function App() {
4
+ const [apiMsg, setApiMsg] = useState("");
5
+
6
+ useEffect(() => {
7
+ fetch("/api/hello")
8
+ .then((r) => r.json())
9
+ .then((d) => setApiMsg(d.message))
10
+ .catch(() => setApiMsg("API not reachable yet"));
11
+ }, []);
12
+
13
+ return (
14
+ <div style={{ fontFamily: "system-ui", padding: 24, lineHeight: 1.5 }}>
15
+ <h1>React + FastAPI (Docker, HF Spaces)</h1>
16
+ <p>This is a plain starter page. Customize freely.By Seth</p>
17
+
18
+ <div style={{ marginTop: 16, padding: 12, border: "1px solid #ddd", borderRadius: 8 }}>
19
+ <strong>API says:</strong> {apiMsg}
20
+ </div>
21
+ </div>
22
+ );
23
+ }
frontend/src/main.jsx ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import React from "react";
2
+ import ReactDOM from "react-dom/client";
3
+ import App from "./App.jsx";
4
+
5
+ ReactDOM.createRoot(document.getElementById("root")).render(
6
+ <React.StrictMode>
7
+ <App />
8
+ </React.StrictMode>
9
+ );
frontend/vite.config.js ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { defineConfig } from "vite";
2
+ import react from "@vitejs/plugin-react";
3
+
4
+ // IMPORTANT: proxy API calls to backend when running both inside one container
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ server: {
8
+ proxy: {
9
+ "/api": "http://127.0.0.1:8000"
10
+ }
11
+ }
12
+ });