Transcendental-Programmer
commited on
Commit
·
0f25023
1
Parent(s):
a8da4e0
fix: localhost error
Browse files- Dockerfile +3 -1
- README.md +41 -11
- app.py +46 -14
- faceforge_api/main.py +8 -2
- faceforge_ui/app.py +25 -3
- main.py +39 -11
Dockerfile
CHANGED
@@ -21,6 +21,8 @@ EXPOSE 7860
|
|
21 |
# Set environment variables
|
22 |
ENV PYTHONPATH="/app"
|
23 |
ENV PYTHONUNBUFFERED=1
|
|
|
|
|
24 |
|
25 |
# Start app (with the patch applied)
|
26 |
-
CMD ["python", "
|
|
|
21 |
# Set environment variables
|
22 |
ENV PYTHONPATH="/app"
|
23 |
ENV PYTHONUNBUFFERED=1
|
24 |
+
ENV API_URL="/api"
|
25 |
+
ENV MOCK_API="false"
|
26 |
|
27 |
# Start app (with the patch applied)
|
28 |
+
CMD ["python", "app.py"]
|
README.md
CHANGED
@@ -5,7 +5,7 @@ colorFrom: indigo
|
|
5 |
colorTo: pink
|
6 |
sdk: gradio
|
7 |
sdk_version: "4.44.1"
|
8 |
-
app_file:
|
9 |
pinned: false
|
10 |
---
|
11 |
|
@@ -19,7 +19,7 @@ FaceForge is ready to run as a Gradio app on [Hugging Face Spaces](https://huggi
|
|
19 |
1. **Push your code to a public GitHub repository.**
|
20 |
2. **Create a new Space** at https://huggingface.co/spaces (choose the Gradio SDK or Docker SDK).
|
21 |
3. **Add your `requirements.txt` and the provided `Dockerfile` to your repo.**
|
22 |
-
4. **Set the entrypoint to `
|
23 |
5. **Deploy!** Your app will be live at `https://<your-username>.hf.space`.
|
24 |
|
25 |
### Example Dockerfile (already included):
|
@@ -45,10 +45,21 @@ pip install -r requirements.txt
|
|
45 |
python main.py
|
46 |
```
|
47 |
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
|
53 |
## Features
|
54 |
- Latent space exploration and manipulation
|
@@ -78,11 +89,30 @@ TypeError: argument of type 'bool' is not iterable
|
|
78 |
|
79 |
The application includes a patch that should fix the issue automatically. This patch addresses a known issue with schema processing in older Gradio versions.
|
80 |
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
|
86 |
## Notes
|
87 |
-
- The backend and frontend are fully integrated for Spaces.
|
88 |
- For custom model integration, edit the core and backend modules as needed.
|
|
|
5 |
colorTo: pink
|
6 |
sdk: gradio
|
7 |
sdk_version: "4.44.1"
|
8 |
+
app_file: app.py
|
9 |
pinned: false
|
10 |
---
|
11 |
|
|
|
19 |
1. **Push your code to a public GitHub repository.**
|
20 |
2. **Create a new Space** at https://huggingface.co/spaces (choose the Gradio SDK or Docker SDK).
|
21 |
3. **Add your `requirements.txt` and the provided `Dockerfile` to your repo.**
|
22 |
+
4. **Set the entrypoint to `app.py`** (which integrates both the API and UI components).
|
23 |
5. **Deploy!** Your app will be live at `https://<your-username>.hf.space`.
|
24 |
|
25 |
### Example Dockerfile (already included):
|
|
|
45 |
python main.py
|
46 |
```
|
47 |
|
48 |
+
This will start the integrated application with both the API and UI components available:
|
49 |
+
- UI accessible at http://localhost:7860/
|
50 |
+
- API accessible at http://localhost:7860/api/
|
51 |
+
|
52 |
+
## Architecture
|
53 |
+
|
54 |
+
FaceForge uses a modular architecture:
|
55 |
+
|
56 |
+
1. **Core Components** (`faceforge_core/`): Core algorithms and utilities
|
57 |
+
2. **API Layer** (`faceforge_api/`): FastAPI endpoints for model interaction
|
58 |
+
3. **UI Layer** (`faceforge_ui/`): Gradio interface for user interaction
|
59 |
+
|
60 |
+
The main application integrates these components into a single FastAPI application where:
|
61 |
+
- The API is mounted at `/api/`
|
62 |
+
- The Gradio UI is mounted at the root path `/`
|
63 |
|
64 |
## Features
|
65 |
- Latent space exploration and manipulation
|
|
|
89 |
|
90 |
The application includes a patch that should fix the issue automatically. This patch addresses a known issue with schema processing in older Gradio versions.
|
91 |
|
92 |
+
### Common Issues:
|
93 |
+
|
94 |
+
#### API Connection Errors
|
95 |
+
|
96 |
+
If you see errors like:
|
97 |
+
```
|
98 |
+
Request failed: HTTPConnectionPool(host='localhost', port=8000): Max retries exceeded with url: /generate
|
99 |
+
```
|
100 |
+
|
101 |
+
This means the UI can't connect to the API. In the integrated version, the API is available at `/api/generate` rather than a separate server.
|
102 |
+
|
103 |
+
To fix this:
|
104 |
+
1. Ensure you're using the integrated version by running `python main.py`
|
105 |
+
2. If you need to run the API separately, set the API_URL environment variable:
|
106 |
+
```bash
|
107 |
+
API_URL=http://localhost:8000 python faceforge_ui/app.py
|
108 |
+
```
|
109 |
+
|
110 |
+
#### Environment Variables
|
111 |
+
|
112 |
+
- `MOCK_API`: Set to "true" to use mock API responses (for testing without API)
|
113 |
+
- `API_URL`: Override the API endpoint URL
|
114 |
+
- `PORT`: Set the port for the server (default: 7860)
|
115 |
|
116 |
## Notes
|
117 |
+
- The backend and frontend are fully integrated for Spaces deployment.
|
118 |
- For custom model integration, edit the core and backend modules as needed.
|
app.py
CHANGED
@@ -17,8 +17,8 @@ logging.basicConfig(
|
|
17 |
|
18 |
logger = logging.getLogger("faceforge")
|
19 |
|
20 |
-
def
|
21 |
-
"""
|
22 |
try:
|
23 |
# Apply the patch for Gradio
|
24 |
logger.info("Applying Gradio patch...")
|
@@ -32,21 +32,53 @@ def main():
|
|
32 |
logger.warning(f"Error applying Gradio patch: {e}")
|
33 |
logger.debug(traceback.format_exc())
|
34 |
|
35 |
-
#
|
36 |
-
logger.info("
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
from faceforge_ui.app import create_demo
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
demo = create_demo()
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
except Exception as e:
|
46 |
-
logger.critical(f"
|
47 |
logger.debug(traceback.format_exc())
|
48 |
-
|
|
|
|
|
|
|
|
|
49 |
|
50 |
-
# This module is imported by Hugging Face Spaces
|
51 |
if __name__ == "__main__":
|
52 |
-
|
|
|
|
|
|
|
|
|
|
17 |
|
18 |
logger = logging.getLogger("faceforge")
|
19 |
|
20 |
+
def create_app():
|
21 |
+
"""Creates and configures the integrated FastAPI application with both API and UI components."""
|
22 |
try:
|
23 |
# Apply the patch for Gradio
|
24 |
logger.info("Applying Gradio patch...")
|
|
|
32 |
logger.warning(f"Error applying Gradio patch: {e}")
|
33 |
logger.debug(traceback.format_exc())
|
34 |
|
35 |
+
# Set up FastAPI application with both API and UI
|
36 |
+
logger.info("Setting up FastAPI application with API and UI for Hugging Face Spaces")
|
37 |
+
from fastapi import FastAPI
|
38 |
+
from fastapi.middleware.cors import CORSMiddleware
|
39 |
+
import gradio as gr
|
40 |
+
|
41 |
+
# Import the API and UI components
|
42 |
+
from faceforge_api.main import app as api_app
|
43 |
from faceforge_ui.app import create_demo
|
44 |
+
|
45 |
+
# Create a new FastAPI application that will serve as the main app
|
46 |
+
app = FastAPI(title="FaceForge")
|
47 |
+
|
48 |
+
# Add CORS middleware
|
49 |
+
app.add_middleware(
|
50 |
+
CORSMiddleware,
|
51 |
+
allow_origins=["*"],
|
52 |
+
allow_credentials=True,
|
53 |
+
allow_methods=["*"],
|
54 |
+
allow_headers=["*"],
|
55 |
+
)
|
56 |
+
|
57 |
+
# Mount the API under /api
|
58 |
+
logger.info("Mounting API at /api")
|
59 |
+
app.mount("/api", api_app)
|
60 |
+
|
61 |
+
# Create Gradio UI
|
62 |
+
logger.info("Creating Gradio UI")
|
63 |
demo = create_demo()
|
64 |
+
|
65 |
+
# Mount Gradio UI
|
66 |
+
logger.info("Mounting Gradio UI")
|
67 |
+
gr_app = gr.mount_gradio_app(app, demo, path="/")
|
68 |
+
|
69 |
+
return app
|
70 |
except Exception as e:
|
71 |
+
logger.critical(f"Failed to create app: {e}")
|
72 |
logger.debug(traceback.format_exc())
|
73 |
+
raise
|
74 |
+
|
75 |
+
# Create the app for Hugging Face Spaces
|
76 |
+
# This is the entry point that Hugging Face Spaces will use
|
77 |
+
app = create_app()
|
78 |
|
|
|
79 |
if __name__ == "__main__":
|
80 |
+
# If this file is run directly, start the server
|
81 |
+
import uvicorn
|
82 |
+
port = int(os.environ.get("PORT", 7860))
|
83 |
+
logger.info(f"Starting integrated server on port {port}")
|
84 |
+
uvicorn.run(app, host="0.0.0.0", port=port)
|
faceforge_api/main.py
CHANGED
@@ -49,7 +49,13 @@ class AttributeDirectionRequest(BaseModel):
|
|
49 |
|
50 |
# --- FastAPI app ---
|
51 |
|
52 |
-
app = FastAPI(
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
|
54 |
# Add CORS middleware to allow requests from any origin
|
55 |
app.add_middleware(
|
@@ -78,7 +84,7 @@ async def error_handling_middleware(request: Request, call_next):
|
|
78 |
|
79 |
@app.get("/")
|
80 |
def read_root():
|
81 |
-
logger.debug("
|
82 |
return {"message": "FaceForge API is running"}
|
83 |
|
84 |
@app.post("/generate")
|
|
|
49 |
|
50 |
# --- FastAPI app ---
|
51 |
|
52 |
+
app = FastAPI(
|
53 |
+
title="FaceForge API",
|
54 |
+
description="API for latent space exploration and manipulation",
|
55 |
+
version="1.0.0",
|
56 |
+
# Important: set root_path to empty to ensure routes work correctly when mounted under /api
|
57 |
+
root_path=""
|
58 |
+
)
|
59 |
|
60 |
# Add CORS middleware to allow requests from any origin
|
61 |
app.add_middleware(
|
|
|
84 |
|
85 |
@app.get("/")
|
86 |
def read_root():
|
87 |
+
logger.debug("API root endpoint called")
|
88 |
return {"message": "FaceForge API is running"}
|
89 |
|
90 |
@app.post("/generate")
|
faceforge_ui/app.py
CHANGED
@@ -23,7 +23,9 @@ logging.getLogger("gradio").setLevel(logging.DEBUG)
|
|
23 |
logging.getLogger("gradio_client").setLevel(logging.DEBUG)
|
24 |
|
25 |
# API configuration
|
26 |
-
|
|
|
|
|
27 |
logger.info(f"Using API URL: {API_URL}")
|
28 |
|
29 |
def generate_image(prompts, mode, player_x, player_y):
|
@@ -48,7 +50,24 @@ def generate_image(prompts, mode, player_x, player_y):
|
|
48 |
|
49 |
# Make API call
|
50 |
try:
|
51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
logger.debug(f"API response status: {resp.status_code}")
|
53 |
|
54 |
if resp.ok:
|
@@ -89,7 +108,10 @@ def generate_image(prompts, mode, player_x, player_y):
|
|
89 |
|
90 |
except requests.exceptions.RequestException as e:
|
91 |
logger.error(f"Request failed: {e}")
|
92 |
-
|
|
|
|
|
|
|
93 |
|
94 |
except Exception as e:
|
95 |
logger.error(f"Unexpected error: {e}")
|
|
|
23 |
logging.getLogger("gradio_client").setLevel(logging.DEBUG)
|
24 |
|
25 |
# API configuration
|
26 |
+
# In HF Spaces, we need to use a relative path since both UI and API run on the same server
|
27 |
+
# For local development with separate servers, the env var can be set to http://localhost:8000
|
28 |
+
API_URL = os.environ.get("API_URL", "/api")
|
29 |
logger.info(f"Using API URL: {API_URL}")
|
30 |
|
31 |
def generate_image(prompts, mode, player_x, player_y):
|
|
|
50 |
|
51 |
# Make API call
|
52 |
try:
|
53 |
+
# For debugging/testing, create a mock image if API is not available
|
54 |
+
if API_URL == "/api" and os.environ.get("MOCK_API", "false").lower() == "true":
|
55 |
+
logger.debug("Using mock API response")
|
56 |
+
# Create a test image
|
57 |
+
img = Image.new("RGB", (256, 256), (int(player_x*128)+128, 100, int(player_y*128)+128))
|
58 |
+
return img, "Image generated using mock API"
|
59 |
+
|
60 |
+
# Determine the base URL for the API
|
61 |
+
if API_URL.startswith("/"):
|
62 |
+
# Relative URL, construct the full URL based on the request context
|
63 |
+
# For Gradio apps, we'll just use a relative path
|
64 |
+
base_url = API_URL
|
65 |
+
else:
|
66 |
+
# Absolute URL, use as is
|
67 |
+
base_url = API_URL
|
68 |
+
|
69 |
+
logger.debug(f"Making request to: {base_url}/generate")
|
70 |
+
resp = requests.post(f"{base_url}/generate", json=req, timeout=30)
|
71 |
logger.debug(f"API response status: {resp.status_code}")
|
72 |
|
73 |
if resp.ok:
|
|
|
108 |
|
109 |
except requests.exceptions.RequestException as e:
|
110 |
logger.error(f"Request failed: {e}")
|
111 |
+
# Fall back to a test image
|
112 |
+
logger.debug("Falling back to test image")
|
113 |
+
img = Image.new("RGB", (256, 256), (int(player_x*128)+128, 100, int(player_y*128)+128))
|
114 |
+
return img, f"API connection failed (using test image): {str(e)}"
|
115 |
|
116 |
except Exception as e:
|
117 |
logger.error(f"Unexpected error: {e}")
|
main.py
CHANGED
@@ -32,17 +32,45 @@ def main():
|
|
32 |
logger.warning(f"Error applying Gradio patch: {e}")
|
33 |
logger.debug(traceback.format_exc())
|
34 |
|
35 |
-
#
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
|
47 |
except ImportError as e:
|
48 |
logger.critical(f"Import error: {e}. Please check your dependencies.")
|
|
|
32 |
logger.warning(f"Error applying Gradio patch: {e}")
|
33 |
logger.debug(traceback.format_exc())
|
34 |
|
35 |
+
# Set up FastAPI application with both API and UI
|
36 |
+
logger.info("Setting up FastAPI application with API and UI")
|
37 |
+
from fastapi import FastAPI
|
38 |
+
from fastapi.middleware.cors import CORSMiddleware
|
39 |
+
import gradio as gr
|
40 |
+
|
41 |
+
# Import the API and UI components
|
42 |
+
from faceforge_api.main import app as api_app
|
43 |
+
from faceforge_ui.app import create_demo
|
44 |
+
|
45 |
+
# Create a new FastAPI application that will serve as the main app
|
46 |
+
app = FastAPI(title="FaceForge")
|
47 |
+
|
48 |
+
# Add CORS middleware
|
49 |
+
app.add_middleware(
|
50 |
+
CORSMiddleware,
|
51 |
+
allow_origins=["*"],
|
52 |
+
allow_credentials=True,
|
53 |
+
allow_methods=["*"],
|
54 |
+
allow_headers=["*"],
|
55 |
+
)
|
56 |
+
|
57 |
+
# Mount the API under /api
|
58 |
+
logger.info("Mounting API at /api")
|
59 |
+
app.mount("/api", api_app)
|
60 |
+
|
61 |
+
# Create Gradio UI
|
62 |
+
logger.info("Creating Gradio UI")
|
63 |
+
demo = create_demo()
|
64 |
+
|
65 |
+
# Mount Gradio UI
|
66 |
+
logger.info("Mounting Gradio UI")
|
67 |
+
gr_app = gr.mount_gradio_app(app, demo, path="/")
|
68 |
+
|
69 |
+
# Configure server
|
70 |
+
import uvicorn
|
71 |
+
port = int(os.environ.get("PORT", 7860))
|
72 |
+
logger.info(f"Starting integrated server on port {port}")
|
73 |
+
uvicorn.run(app, host="0.0.0.0", port=port)
|
74 |
|
75 |
except ImportError as e:
|
76 |
logger.critical(f"Import error: {e}. Please check your dependencies.")
|