Spaces:
Sleeping
Sleeping
feat: update frontend to proxy requests to Hugging Face Space API and configure environment variables
Browse files- README.md +8 -0
- frontend/.env.local.example +7 -0
- frontend/lib/api.ts +1 -3
- frontend/next.config.js +22 -1
README.md
CHANGED
|
@@ -17,3 +17,11 @@ This Space runs the FastAPI service from `src/api/main.py` and exposes:
|
|
| 17 |
- `GET /health`
|
| 18 |
- `POST /detect/image`
|
| 19 |
- `POST /detect/video`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
- `GET /health`
|
| 18 |
- `POST /detect/image`
|
| 19 |
- `POST /detect/video`
|
| 20 |
+
|
| 21 |
+
## Frontend -> Hugging Face Space API
|
| 22 |
+
|
| 23 |
+
The Next.js frontend now sends requests to `/api/*` and proxies them to your Hugging Face Space.
|
| 24 |
+
|
| 25 |
+
1. Copy `frontend/.env.local.example` to `frontend/.env.local`.
|
| 26 |
+
2. Set `NEXT_PUBLIC_HF_SPACE_ID` (default: `akagtag/deepdetection`).
|
| 27 |
+
3. Optional: set `NEXT_PUBLIC_API_URL` to override and point to a local backend.
|
frontend/.env.local.example
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Hugging Face Space used by Next.js /api proxy.
|
| 2 |
+
NEXT_PUBLIC_HF_SPACE_ID=akagtag/deepdetection
|
| 3 |
+
|
| 4 |
+
# Optional direct API override (takes precedence over NEXT_PUBLIC_HF_SPACE_ID).
|
| 5 |
+
# NEXT_PUBLIC_API_URL=http://localhost:8000
|
| 6 |
+
# Local Uvicorn example:
|
| 7 |
+
NEXT_PUBLIC_API_URL=http://127.0.0.1:7860
|
frontend/lib/api.ts
CHANGED
|
@@ -2,9 +2,7 @@
|
|
| 2 |
|
| 3 |
import type { DetectionResponse } from '@/types/detection'
|
| 4 |
|
| 5 |
-
const BASE_URL =
|
| 6 |
-
process.env.NEXT_PUBLIC_API_URL ??
|
| 7 |
-
'http://localhost:8000'
|
| 8 |
|
| 9 |
async function _post(endpoint: string, file: File): Promise<DetectionResponse> {
|
| 10 |
const form = new FormData()
|
|
|
|
| 2 |
|
| 3 |
import type { DetectionResponse } from '@/types/detection'
|
| 4 |
|
| 5 |
+
const BASE_URL = '/api'
|
|
|
|
|
|
|
| 6 |
|
| 7 |
async function _post(endpoint: string, file: File): Promise<DetectionResponse> {
|
| 8 |
const form = new FormData()
|
frontend/next.config.js
CHANGED
|
@@ -1,5 +1,26 @@
|
|
| 1 |
const path = require('path')
|
| 2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
/** @type {import('next').NextConfig} */
|
| 4 |
const nextConfig = {
|
| 5 |
reactStrictMode: true,
|
|
@@ -8,7 +29,7 @@ const nextConfig = {
|
|
| 8 |
return [
|
| 9 |
{
|
| 10 |
source: '/api/:path*',
|
| 11 |
-
destination: `${
|
| 12 |
},
|
| 13 |
]
|
| 14 |
},
|
|
|
|
| 1 |
const path = require('path')
|
| 2 |
|
| 3 |
+
function trimTrailingSlash(value) {
|
| 4 |
+
return value.replace(/\/+$/, '')
|
| 5 |
+
}
|
| 6 |
+
|
| 7 |
+
function resolveApiBaseUrl() {
|
| 8 |
+
const explicitApiUrl = process.env.NEXT_PUBLIC_API_URL?.trim()
|
| 9 |
+
if (explicitApiUrl) {
|
| 10 |
+
return trimTrailingSlash(explicitApiUrl)
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
const hfSpaceId = (process.env.NEXT_PUBLIC_HF_SPACE_ID ?? 'akagtag/deepdetection').trim()
|
| 14 |
+
const [owner, space] = hfSpaceId.split('/')
|
| 15 |
+
if (owner && space) {
|
| 16 |
+
return `https://${owner}-${space}.hf.space`
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
return 'http://localhost:8000'
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
const API_BASE_URL = resolveApiBaseUrl()
|
| 23 |
+
|
| 24 |
/** @type {import('next').NextConfig} */
|
| 25 |
const nextConfig = {
|
| 26 |
reactStrictMode: true,
|
|
|
|
| 29 |
return [
|
| 30 |
{
|
| 31 |
source: '/api/:path*',
|
| 32 |
+
destination: `${API_BASE_URL}/:path*`,
|
| 33 |
},
|
| 34 |
]
|
| 35 |
},
|