Transcendental-Programmer commited on
Commit
a8da4e0
·
1 Parent(s): 659182f

fix: upgraded gradio version

Browse files
Files changed (8) hide show
  1. Dockerfile +13 -7
  2. README.md +26 -5
  3. app.py +41 -18
  4. faceforge_api/main.py +21 -12
  5. faceforge_ui/app.py +93 -35
  6. main.py +53 -16
  7. patch_gradio_utils.py +66 -0
  8. requirements.txt +1 -1
Dockerfile CHANGED
@@ -1,20 +1,26 @@
1
  FROM python:3.10-slim
2
 
3
- # Install system dependencies
4
  RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
5
 
6
- # Set workdir
7
  WORKDIR /app
8
 
9
- # Copy requirements and install
10
  COPY requirements.txt ./
 
 
11
  RUN pip install --no-cache-dir -r requirements.txt
12
 
13
- # Copy all code
14
  COPY . .
15
 
16
- # Expose Gradio port
17
  EXPOSE 7860
18
 
19
- # Run Gradio app
20
- CMD ["python", "faceforge_ui/app.py"]
 
 
 
 
 
1
  FROM python:3.10-slim
2
 
3
+ # Install dependencies
4
  RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
5
 
6
+ # Set working directory
7
  WORKDIR /app
8
 
9
+ # Copy requirements
10
  COPY requirements.txt ./
11
+
12
+ # Install dependencies
13
  RUN pip install --no-cache-dir -r requirements.txt
14
 
15
+ # Copy application code
16
  COPY . .
17
 
18
+ # Expose port
19
  EXPOSE 7860
20
 
21
+ # Set environment variables
22
+ ENV PYTHONPATH="/app"
23
+ ENV PYTHONUNBUFFERED=1
24
+
25
+ # Start app (with the patch applied)
26
+ CMD ["python", "main.py"]
README.md CHANGED
@@ -4,8 +4,8 @@ emoji: 🧑‍🎨
4
  colorFrom: indigo
5
  colorTo: pink
6
  sdk: gradio
7
- sdk_version: "4.27.0"
8
- app_file: faceforge_ui/app.py
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 `faceforge_ui/app.py`** (the Gradio app).
23
  5. **Deploy!** Your app will be live at `https://<your-username>.hf.space`.
24
 
25
  ### Example Dockerfile (already included):
@@ -31,7 +31,9 @@ COPY requirements.txt ./
31
  RUN pip install --no-cache-dir -r requirements.txt
32
  COPY . .
33
  EXPOSE 7860
34
- CMD ["python", "faceforge_ui/app.py"]
 
 
35
  ```
36
 
37
  ## Local Development (Optional)
@@ -40,7 +42,12 @@ You can still run FaceForge locally:
40
 
41
  ```bash
42
  pip install -r requirements.txt
43
- python faceforge_ui/app.py
 
 
 
 
 
44
  ```
45
 
46
  ## Features
@@ -62,6 +69,20 @@ Run all tests with:
62
  pytest tests/
63
  ```
64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  ## Notes
66
  - The backend and frontend are fully integrated for Spaces.
67
  - For custom model integration, edit the core and backend modules as needed.
 
4
  colorFrom: indigo
5
  colorTo: pink
6
  sdk: gradio
7
+ sdk_version: "4.44.1"
8
+ app_file: main.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 `main.py`** (which handles 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):
 
31
  RUN pip install --no-cache-dir -r requirements.txt
32
  COPY . .
33
  EXPOSE 7860
34
+ ENV PYTHONPATH="/app"
35
+ ENV PYTHONUNBUFFERED=1
36
+ CMD ["python", "main.py"]
37
  ```
38
 
39
  ## Local Development (Optional)
 
42
 
43
  ```bash
44
  pip install -r requirements.txt
45
+ python main.py
46
+ ```
47
+
48
+ To run in API-only mode:
49
+ ```bash
50
+ FACEFORGE_MODE=api python main.py
51
  ```
52
 
53
  ## Features
 
69
  pytest tests/
70
  ```
71
 
72
+ ## Debugging
73
+
74
+ If you encounter Gradio schema-related errors like:
75
+ ```
76
+ TypeError: argument of type 'bool' is not iterable
77
+ ```
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
+ Recommended steps to diagnose UI issues:
82
+ 1. Check the logs for detailed error information
83
+ 2. Ensure you're using Gradio version 4.44.1 or newer (`pip install --upgrade gradio==4.44.1`)
84
+ 3. Try running in API-only mode to isolate the issue
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.
app.py CHANGED
@@ -1,6 +1,12 @@
 
 
 
 
 
1
  import os
2
- import sys
3
  import logging
 
 
4
 
5
  # Configure logging
6
  logging.basicConfig(
@@ -8,22 +14,39 @@ logging.basicConfig(
8
  format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
9
  handlers=[logging.StreamHandler(sys.stdout)]
10
  )
11
- logger = logging.getLogger("faceforge_app")
12
 
13
- # Add the project root to the Python path
14
- sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
- try:
17
- logger.info("Starting FaceForge app")
18
- # Import the demo from the UI module
19
- from faceforge_ui.app import demo
20
-
21
- # Launch the app
22
- if __name__ == "__main__":
23
- logger.info("Launching Gradio interface")
24
- demo.launch(server_name="0.0.0.0")
25
- except Exception as e:
26
- logger.critical(f"Failed to start app: {e}")
27
- import traceback
28
- logger.debug(traceback.format_exc())
29
- raise
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Main entry point for Hugging Face Spaces deployment
4
+ """
5
+
6
  import os
 
7
  import logging
8
+ import sys
9
+ import traceback
10
 
11
  # Configure logging
12
  logging.basicConfig(
 
14
  format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
15
  handlers=[logging.StreamHandler(sys.stdout)]
16
  )
 
17
 
18
+ logger = logging.getLogger("faceforge")
19
+
20
+ def main():
21
+ """Main function to start the FaceForge application."""
22
+ try:
23
+ # Apply the patch for Gradio
24
+ logger.info("Applying Gradio patch...")
25
+ try:
26
+ from patch_gradio_utils import apply_patch
27
+ if apply_patch():
28
+ logger.info("Gradio patch applied successfully.")
29
+ else:
30
+ logger.warning("Failed to apply Gradio patch. The app may encounter errors.")
31
+ except Exception as e:
32
+ logger.warning(f"Error applying Gradio patch: {e}")
33
+ logger.debug(traceback.format_exc())
34
+
35
+ # Import and run the UI app by default for HF Spaces
36
+ logger.info("Starting in UI mode for Hugging Face Spaces")
37
+ from faceforge_ui.app import create_demo
38
+ demo = create_demo()
39
+ demo.launch(server_name="0.0.0.0", share=False)
40
+
41
+ except ImportError as e:
42
+ logger.critical(f"Import error: {e}. Please check your dependencies.")
43
+ logger.debug(traceback.format_exc())
44
+ sys.exit(1)
45
+ except Exception as e:
46
+ logger.critical(f"Unexpected error: {e}")
47
+ logger.debug(traceback.format_exc())
48
+ sys.exit(1)
49
 
50
+ # This module is imported by Hugging Face Spaces
51
+ if __name__ == "__main__":
52
+ main()
 
 
 
 
 
 
 
 
 
 
 
faceforge_api/main.py CHANGED
@@ -1,8 +1,8 @@
1
  from fastapi import FastAPI, HTTPException, Request
2
  from fastapi.responses import JSONResponse
3
  from fastapi.middleware.cors import CORSMiddleware
4
- from pydantic import BaseModel
5
- from typing import List, Optional
6
  import numpy as np
7
  import base64
8
  import logging
@@ -10,6 +10,7 @@ import sys
10
  import traceback
11
  import io
12
  from PIL import Image
 
13
 
14
  from faceforge_core.latent_explorer import LatentSpaceExplorer
15
  from faceforge_core.attribute_directions import LatentDirectionFinder
@@ -27,14 +28,14 @@ logger = logging.getLogger("faceforge_api")
27
 
28
  class PointIn(BaseModel):
29
  text: str
30
- encoding: Optional[List[float]] = None
31
- xy_pos: Optional[List[float]] = None
32
 
33
  class GenerateRequest(BaseModel):
34
  prompts: List[str]
35
- positions: Optional[List[List[float]]] = None
36
  mode: str = "distance"
37
- player_pos: Optional[List[float]] = None
38
 
39
  class ManipulateRequest(BaseModel):
40
  encoding: List[float]
@@ -43,7 +44,7 @@ class ManipulateRequest(BaseModel):
43
 
44
  class AttributeDirectionRequest(BaseModel):
45
  latents: List[List[float]]
46
- labels: Optional[List[int]] = None
47
  n_components: Optional[int] = 10
48
 
49
  # --- FastAPI app ---
@@ -81,9 +82,12 @@ def read_root():
81
  return {"message": "FaceForge API is running"}
82
 
83
  @app.post("/generate")
84
- def generate_image(req: GenerateRequest):
85
  try:
86
- logger.debug(f"Generate image request: {req}")
 
 
 
87
 
88
  # Clear existing points
89
  explorer.points = []
@@ -123,8 +127,13 @@ def generate_image(req: GenerateRequest):
123
  pil_img.save(buffer, format="PNG")
124
  img_b64 = base64.b64encode(buffer.getvalue()).decode("utf-8")
125
 
 
 
 
 
 
126
  logger.debug("Image generated successfully")
127
- return {"status": "success", "image": img_b64}
128
 
129
  except Exception as e:
130
  logger.error(f"Error in generate_image: {str(e)}")
@@ -134,7 +143,7 @@ def generate_image(req: GenerateRequest):
134
  @app.post("/manipulate")
135
  def manipulate(req: ManipulateRequest):
136
  try:
137
- logger.debug(f"Manipulate request: {req}")
138
  encoding = np.array(req.encoding)
139
  direction = np.array(req.direction)
140
  manipulated = encoding + req.alpha * direction
@@ -148,7 +157,7 @@ def manipulate(req: ManipulateRequest):
148
  @app.post("/attribute_direction")
149
  def attribute_direction(req: AttributeDirectionRequest):
150
  try:
151
- logger.debug(f"Attribute direction request: {req}")
152
  latents = np.array(req.latents)
153
  finder = LatentDirectionFinder(latents)
154
 
 
1
  from fastapi import FastAPI, HTTPException, Request
2
  from fastapi.responses import JSONResponse
3
  from fastapi.middleware.cors import CORSMiddleware
4
+ from pydantic import BaseModel, Field
5
+ from typing import List, Optional, Dict, Any
6
  import numpy as np
7
  import base64
8
  import logging
 
10
  import traceback
11
  import io
12
  from PIL import Image
13
+ import json
14
 
15
  from faceforge_core.latent_explorer import LatentSpaceExplorer
16
  from faceforge_core.attribute_directions import LatentDirectionFinder
 
28
 
29
  class PointIn(BaseModel):
30
  text: str
31
+ encoding: Optional[List[float]] = Field(None)
32
+ xy_pos: Optional[List[float]] = Field(None)
33
 
34
  class GenerateRequest(BaseModel):
35
  prompts: List[str]
36
+ positions: Optional[List[List[float]]] = Field(None)
37
  mode: str = "distance"
38
+ player_pos: Optional[List[float]] = Field(None)
39
 
40
  class ManipulateRequest(BaseModel):
41
  encoding: List[float]
 
44
 
45
  class AttributeDirectionRequest(BaseModel):
46
  latents: List[List[float]]
47
+ labels: Optional[List[int]] = Field(None)
48
  n_components: Optional[int] = 10
49
 
50
  # --- FastAPI app ---
 
82
  return {"message": "FaceForge API is running"}
83
 
84
  @app.post("/generate")
85
+ async def generate_image(req: GenerateRequest):
86
  try:
87
+ logger.debug(f"Generate image request: {json.dumps(req.dict(), default=str)}")
88
+
89
+ # Log request schema for debugging
90
+ logger.debug(f"Request schema: {GenerateRequest.schema_json()}")
91
 
92
  # Clear existing points
93
  explorer.points = []
 
127
  pil_img.save(buffer, format="PNG")
128
  img_b64 = base64.b64encode(buffer.getvalue()).decode("utf-8")
129
 
130
+ # Prepare response
131
+ response = {"status": "success", "image": img_b64}
132
+ logger.debug(f"Response structure: {list(response.keys())}")
133
+ logger.debug(f"Image base64 length: {len(img_b64)}")
134
+
135
  logger.debug("Image generated successfully")
136
+ return response
137
 
138
  except Exception as e:
139
  logger.error(f"Error in generate_image: {str(e)}")
 
143
  @app.post("/manipulate")
144
  def manipulate(req: ManipulateRequest):
145
  try:
146
+ logger.debug(f"Manipulate request: {json.dumps(req.dict(), default=str)}")
147
  encoding = np.array(req.encoding)
148
  direction = np.array(req.direction)
149
  manipulated = encoding + req.alpha * direction
 
157
  @app.post("/attribute_direction")
158
  def attribute_direction(req: AttributeDirectionRequest):
159
  try:
160
+ logger.debug(f"Attribute direction request: {json.dumps(req.dict(), default=str)}")
161
  latents = np.array(req.latents)
162
  finder = LatentDirectionFinder(latents)
163
 
faceforge_ui/app.py CHANGED
@@ -8,6 +8,7 @@ import logging
8
  import sys
9
  import traceback
10
  import os
 
11
 
12
  # Configure logging
13
  logging.basicConfig(
@@ -17,6 +18,10 @@ logging.basicConfig(
17
  )
18
  logger = logging.getLogger("faceforge_ui")
19
 
 
 
 
 
20
  # API configuration
21
  API_URL = os.environ.get("API_URL", "http://localhost:8000")
22
  logger.info(f"Using API URL: {API_URL}")
@@ -39,32 +44,47 @@ def generate_image(prompts, mode, player_x, player_y):
39
  "player_pos": [float(player_x), float(player_y)]
40
  }
41
 
 
 
42
  # Make API call
43
  try:
44
  resp = requests.post(f"{API_URL}/generate", json=req, timeout=30)
 
45
 
46
  if resp.ok:
47
- data = resp.json()
48
-
49
- if "image" in data:
50
- img_b64 = data["image"]
51
- img_bytes = base64.b64decode(img_b64)
52
 
53
- try:
54
- # For testing, create a simple colored image if decode fails
 
 
 
55
  try:
56
- img = Image.frombytes("RGB", (256, 256), img_bytes)
57
- except:
58
- # Fallback to create a test image
59
- img = Image.new("RGB", (256, 256), (int(player_x*128)+128, 100, int(player_y*128)+128))
60
-
61
- return img, "Image generated successfully"
62
- except Exception as e:
63
- logger.error(f"Error decoding image: {e}")
64
- return None, f"Error decoding image: {str(e)}"
65
- else:
66
- return None, "No image in API response"
 
 
 
 
 
 
 
 
 
 
67
  else:
 
68
  return None, f"API error: {resp.status_code}"
69
 
70
  except requests.exceptions.RequestException as e:
@@ -73,29 +93,67 @@ def generate_image(prompts, mode, player_x, player_y):
73
 
74
  except Exception as e:
75
  logger.error(f"Unexpected error: {e}")
 
76
  return None, f"Error: {str(e)}"
77
 
78
  # Create a simplified Gradio interface to avoid schema issues
79
- demo = gr.Interface(
80
- fn=generate_image,
81
- inputs=[
82
- gr.Textbox(label="Prompts (comma-separated)", value="A photo of a cat, A photo of a dog"),
83
- gr.Radio(["distance", "circle"], value="distance", label="Sampling Mode"),
84
- gr.Slider(-1.0, 1.0, value=0.0, label="Player X"),
85
- gr.Slider(-1.0, 1.0, value=0.0, label="Player Y")
86
- ],
87
- outputs=[
88
- gr.Image(label="Generated Image", type="pil"),
89
- gr.Textbox(label="Status")
90
- ],
91
- title="FaceForge Latent Space Explorer",
92
- description="Interactively explore and edit faces in latent space.",
93
- allow_flagging="never"
94
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
 
 
96
  if __name__ == "__main__":
97
- logger.info("Starting Gradio app")
98
  try:
 
 
 
 
 
 
99
  # Check if we're running in Hugging Face Spaces
100
  if "SPACE_ID" in os.environ:
101
  logger.info("Running in Hugging Face Space")
 
8
  import sys
9
  import traceback
10
  import os
11
+ import json
12
 
13
  # Configure logging
14
  logging.basicConfig(
 
18
  )
19
  logger = logging.getLogger("faceforge_ui")
20
 
21
+ # Add more debug loggers for gradio internals
22
+ logging.getLogger("gradio").setLevel(logging.DEBUG)
23
+ logging.getLogger("gradio_client").setLevel(logging.DEBUG)
24
+
25
  # API configuration
26
  API_URL = os.environ.get("API_URL", "http://localhost:8000")
27
  logger.info(f"Using API URL: {API_URL}")
 
44
  "player_pos": [float(player_x), float(player_y)]
45
  }
46
 
47
+ logger.debug(f"Request payload: {json.dumps(req)}")
48
+
49
  # Make API call
50
  try:
51
  resp = requests.post(f"{API_URL}/generate", json=req, timeout=30)
52
+ logger.debug(f"API response status: {resp.status_code}")
53
 
54
  if resp.ok:
55
+ try:
56
+ data = resp.json()
57
+ logger.debug(f"API response structure: {list(data.keys())}")
 
 
58
 
59
+ if "image" in data:
60
+ img_b64 = data["image"]
61
+ logger.debug(f"Image base64 length: {len(img_b64)}")
62
+ img_bytes = base64.b64decode(img_b64)
63
+
64
  try:
65
+ # For testing, create a simple colored image if decode fails
66
+ try:
67
+ img = Image.open(io.BytesIO(img_bytes))
68
+ logger.debug(f"Image decoded successfully: {img.size} {img.mode}")
69
+ except Exception as e:
70
+ logger.error(f"Failed to decode image from bytes: {e}, creating test image")
71
+ # Fallback to create a test image
72
+ img = Image.new("RGB", (256, 256), (int(player_x*128)+128, 100, int(player_y*128)+128))
73
+
74
+ return img, "Image generated successfully"
75
+ except Exception as e:
76
+ logger.error(f"Error processing image: {e}")
77
+ logger.debug(traceback.format_exc())
78
+ return None, f"Error processing image: {str(e)}"
79
+ else:
80
+ logger.warning("No image field in API response")
81
+ return None, "No image in API response"
82
+ except Exception as e:
83
+ logger.error(f"Error parsing API response: {e}")
84
+ logger.debug(f"Raw response: {resp.text[:500]}")
85
+ return None, f"Error parsing API response: {str(e)}"
86
  else:
87
+ logger.error(f"API error: {resp.status_code}, {resp.text[:500]}")
88
  return None, f"API error: {resp.status_code}"
89
 
90
  except requests.exceptions.RequestException as e:
 
93
 
94
  except Exception as e:
95
  logger.error(f"Unexpected error: {e}")
96
+ logger.debug(traceback.format_exc())
97
  return None, f"Error: {str(e)}"
98
 
99
  # Create a simplified Gradio interface to avoid schema issues
100
+ # Use basic components without custom schemas
101
+ def create_demo():
102
+ with gr.Blocks(title="FaceForge Latent Space Explorer") as demo:
103
+ gr.Markdown("# FaceForge Latent Space Explorer")
104
+ gr.Markdown("Interactively explore and edit faces in latent space.")
105
+
106
+ with gr.Row():
107
+ with gr.Column(scale=3):
108
+ prompts_input = gr.Textbox(
109
+ label="Prompts (comma-separated)",
110
+ value="A photo of a cat, A photo of a dog",
111
+ lines=2
112
+ )
113
+ mode_input = gr.Radio(
114
+ choices=["distance", "circle"],
115
+ value="distance",
116
+ label="Sampling Mode"
117
+ )
118
+ player_x_input = gr.Slider(
119
+ minimum=-1.0,
120
+ maximum=1.0,
121
+ value=0.0,
122
+ step=0.1,
123
+ label="Player X"
124
+ )
125
+ player_y_input = gr.Slider(
126
+ minimum=-1.0,
127
+ maximum=1.0,
128
+ value=0.0,
129
+ step=0.1,
130
+ label="Player Y"
131
+ )
132
+
133
+ generate_btn = gr.Button("Generate")
134
+
135
+ with gr.Column(scale=5):
136
+ output_image = gr.Image(label="Generated Image")
137
+ output_status = gr.Textbox(label="Status")
138
+
139
+ generate_btn.click(
140
+ fn=generate_image,
141
+ inputs=[prompts_input, mode_input, player_x_input, player_y_input],
142
+ outputs=[output_image, output_status]
143
+ )
144
+
145
+ return demo
146
 
147
+ # Only start if this file is run directly, not when imported
148
  if __name__ == "__main__":
149
+ logger.info("Starting Gradio app directly from app.py")
150
  try:
151
+ # Print Gradio version for debugging
152
+ logger.info(f"Gradio version: {gr.__version__}")
153
+
154
+ # Create demo
155
+ demo = create_demo()
156
+
157
  # Check if we're running in Hugging Face Spaces
158
  if "SPACE_ID" in os.environ:
159
  logger.info("Running in Hugging Face Space")
main.py CHANGED
@@ -1,20 +1,57 @@
1
- from latent_space_explorer import GameConfig, LatentSpaceExplorer
 
 
 
2
 
3
- if __name__ == "__main__":
4
- config = GameConfig(
5
- call_every = 100
6
- )
 
 
 
 
 
 
 
7
 
8
- explorer = LatentSpaceExplorer(config)
9
 
10
- explorer.set_prompts(
11
- [
12
- "A photo of a cat",
13
- "A space-aged ferrari",
14
- "artwork of the titanic hitting an iceberg",
15
- "a photo of a dog"
16
- ]
17
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
- while True:
20
- explorer.update()
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Main entry point for FaceForge application
4
+ """
5
 
6
+ import os
7
+ import logging
8
+ import sys
9
+ import traceback
10
+
11
+ # Configure logging
12
+ logging.basicConfig(
13
+ level=logging.DEBUG,
14
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
15
+ handlers=[logging.StreamHandler(sys.stdout)]
16
+ )
17
 
18
+ logger = logging.getLogger("faceforge")
19
 
20
+ def main():
21
+ """Main function to start the FaceForge application."""
22
+ try:
23
+ # Apply the patch for Gradio
24
+ logger.info("Applying Gradio patch...")
25
+ try:
26
+ from patch_gradio_utils import apply_patch
27
+ if apply_patch():
28
+ logger.info("Gradio patch applied successfully.")
29
+ else:
30
+ logger.warning("Failed to apply Gradio patch. The app may encounter errors.")
31
+ except Exception as e:
32
+ logger.warning(f"Error applying Gradio patch: {e}")
33
+ logger.debug(traceback.format_exc())
34
+
35
+ # Import and run the appropriate app
36
+ if os.environ.get("FACEFORGE_MODE", "ui").lower() == "api":
37
+ logger.info("Starting in API mode")
38
+ from faceforge_api.main import app
39
+ import uvicorn
40
+ uvicorn.run(app, host="0.0.0.0", port=8000)
41
+ else:
42
+ logger.info("Starting in UI mode")
43
+ from faceforge_ui.app import create_demo
44
+ demo = create_demo()
45
+ demo.launch(server_name="0.0.0.0", share=False)
46
+
47
+ except ImportError as e:
48
+ logger.critical(f"Import error: {e}. Please check your dependencies.")
49
+ logger.debug(traceback.format_exc())
50
+ sys.exit(1)
51
+ except Exception as e:
52
+ logger.critical(f"Unexpected error: {e}")
53
+ logger.debug(traceback.format_exc())
54
+ sys.exit(1)
55
 
56
+ if __name__ == "__main__":
57
+ main()
patch_gradio_utils.py ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Patch for gradio_client.utils._json_schema_to_python_type function
4
+ to handle boolean schema values properly.
5
+
6
+ This patch adds a check for boolean schema values before trying to access them as dictionaries.
7
+ """
8
+
9
+ import importlib
10
+ import logging
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+ def apply_patch():
15
+ """Apply the monkey patch to fix the TypeError in gradio_client.utils._json_schema_to_python_type."""
16
+ try:
17
+ # Import the module
18
+ import gradio_client.utils as utils
19
+
20
+ # Store the original function
21
+ original_func = utils._json_schema_to_python_type
22
+
23
+ # Define the patched function
24
+ def patched_json_schema_to_python_type(schema, defs=None):
25
+ """Patched version that handles boolean schemas."""
26
+ if schema is None:
27
+ return "None"
28
+
29
+ # Handle boolean schema values
30
+ if isinstance(schema, bool):
31
+ return str(schema).lower()
32
+
33
+ # Continue with the original function for non-boolean schemas
34
+ return original_func(schema, defs)
35
+
36
+ # Apply the patch
37
+ utils._json_schema_to_python_type = patched_json_schema_to_python_type
38
+
39
+ # Also patch the get_type function
40
+ original_get_type = utils.get_type
41
+
42
+ def patched_get_type(schema):
43
+ """Patched version of get_type that handles boolean schemas."""
44
+ if isinstance(schema, bool):
45
+ return "bool"
46
+ return original_get_type(schema)
47
+
48
+ utils.get_type = patched_get_type
49
+
50
+ logger.info("Successfully applied patch to gradio_client.utils._json_schema_to_python_type")
51
+ return True
52
+ except Exception as e:
53
+ logger.error(f"Failed to apply patch: {e}")
54
+ import traceback
55
+ logger.debug(traceback.format_exc())
56
+ return False
57
+
58
+ if __name__ == "__main__":
59
+ # Set up logging
60
+ logging.basicConfig(level=logging.DEBUG)
61
+
62
+ # Apply the patch
63
+ if apply_patch():
64
+ print("Patch applied successfully.")
65
+ else:
66
+ print("Failed to apply patch.")
requirements.txt CHANGED
@@ -3,6 +3,6 @@ pygame
3
  torch
4
  torchvision
5
  fastapi
6
- gradio
7
  pytest
8
  scikit-learn
 
3
  torch
4
  torchvision
5
  fastapi
6
+ gradio==4.44.1
7
  pytest
8
  scikit-learn