File size: 6,313 Bytes
eecd79d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0dee6ca
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
eecd79d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16cace9
 
eecd79d
3314249
eecd79d
3314249
cfbb33f
16cace9
 
 
 
 
3846302
16cace9
3314249
16cace9
3314249
 
 
 
 
 
d2c2086
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5fcd2a4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d2c2086
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
"""
Hugging Face Spaces entry point for seg_app.

This file must be at repository root for HF Spaces deployment.

IMPORTANT:
- No heavy imports at module level (lazy loading only)
- Model loading happens on first inference, not at startup
- Gradio app is created on import but models are NOT loaded
"""

import os
import logging
import sys

# Fix OpenMP duplicate library error on Windows
# Must be set BEFORE importing numpy/torch
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"

# Configure logging before other imports
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
logger = logging.getLogger(__name__)

# Validate Python version
if sys.version_info < (3, 8):
    logger.error("Python 3.8+ is required")
    sys.exit(1)


# =============================================================================
# MONKEY-PATCH: Fix Gradio schema serialization bug
# Bug: gradio_client/utils.py crashes when schema has additionalProperties: true
# because it tries to do `if "const" in schema` on a boolean value.
# This patch adds a guard to handle boolean schemas gracefully.
# =============================================================================
def _patch_gradio_schema_bug():
    """Patch the buggy _json_schema_to_python_type function in gradio_client."""
    try:
        import gradio_client.utils as client_utils
        
        # Store original function
        original_func = client_utils._json_schema_to_python_type
        
        def patched_json_schema_to_python_type(schema, defs=None):
            """Patched version that handles boolean schemas."""
            # Handle boolean schema (additionalProperties: true/false)
            if isinstance(schema, bool):
                return "Any" if schema else "None"
            # Handle None schema
            if schema is None:
                return "Any"
            # Call original for normal dict schemas
            return original_func(schema, defs)
        
        # Apply patch
        client_utils._json_schema_to_python_type = patched_json_schema_to_python_type
        logger.info("Applied Gradio schema bug patch")
        
    except Exception as e:
        logger.warning(f"Could not patch Gradio schema bug: {e}")

# Apply patch before any Gradio imports
_patch_gradio_schema_bug()


def create_demo():
    """Create and configure the Gradio demo.
    
    This function is called at import time but does NOT load any models.
    Models are loaded lazily on first inference via the model registry.
    
    Returns:
        Configured Gradio Blocks application
    """
    try:
        # Import settings and configure
        from seg_app.config.settings import (
            APP_SETTINGS,
            configure_logging,
            validate_environment,
            is_hf_spaces,
        )
        
        # Configure logging based on environment
        configure_logging(verbose=not is_hf_spaces())
        
        # Validate environment (warnings only, don't fail startup)
        validate_environment()
        
        # Import the Gradio app (models NOT loaded yet)
        from seg_app.ui.gradio_app import demo
        
        logger.info("Gradio app created successfully (models will load on first use)")
        return demo
        
    except ImportError as e:
        logger.error(f"Failed to import required modules: {e}")
        logger.error("Please ensure all dependencies are installed: pip install -r requirements.txt")
        raise
    except Exception as e:
        logger.error(f"Failed to create Gradio app: {e}")
        raise


# Create the demo at module level (required for HF Spaces)
# This does NOT load models - they are lazy-loaded on first inference
demo = create_demo()

# Launch the app
# HF Spaces runs this file directly with `python app.py`
if __name__ == "__main__":
    import os
    
    if os.environ.get("SPACE_ID"):
        # Running in HF Spaces
        logger.info("Starting seg_app on Hugging Face Spaces...")
        demo.launch(
            server_name="0.0.0.0",
            server_port=7860,
            share=False,
            show_api=False,
        )
    else:
        # Local development
        logger.info("Starting seg_app in local mode...")
        demo.launch(
            server_name="127.0.0.1",
            server_port=7869,
            share=False,
        )


"""

>>  First Launch API server backend: Start the FastAPI backend with uvicorn
    # uvicorn seg_app.api.app:app --reload --host 127.0.0.1 --port 8000
    uvicorn seg_app.backend.api:app --reload --host 127.0.0.1 --port 8000
    
>>  Second, Start the FastAPI Frontend:
    cd seg_app/ui_slicer
    python serve_frontend.py
    
    
>>  Launch Gradio App for seg_app.
    python app.py
    
# Terminal 1: FastAPI Backend
uvicorn seg_app.backend.api:app --reload --host 127.0.0.1 --port 8000

# Terminal 2: Frontend Server
cd seg_app/ui_slicer
python serve_frontend.py






Unified Mode (single server — recommended)
One terminal, one port, serves both frontend + backend:
----------------------
cd /media/vsap/New\ Volume1/medical_webapp/seg_app
conda activate facenet
uvicorn seg_app.backend.api:app --host 127.0.0.1 --port 7860


Split Mode (two terminals — for development)
If you ever need separate frontend/backend (e.g., for hot-reloading the frontend):

Terminal 1 — Backend:
-------------------------
cd /media/vsap/New\ Volume1/medical_webapp/seg_app
conda activate facenet
uvicorn seg_app.backend.api:app --reload --host 127.0.0.1 --port 8000

Terminal 2 — Frontend:
-------------------------
cd /media/vsap/New\ Volume1/medical_webapp/seg_app/seg_app/ui_slicer
conda activate facenet
python serve_frontend.py

⚠️ In split mode, you'll need to temporarily revert api-client.js to use http://localhost:8000 instead of window.location.origin.

You can test locally with Docker first if you want:
--------------------------
docker build -t brain-seg-app .
docker run -p 7860:7860 brain-seg-app
# Open http://localhost:7860



For future pushes
Whenever you make changes locally and want to update the Space:
--------------------------------------------------------------
cd /media/vsap/New\ Volume1/medical_webapp/seg_app
conda activate facenet
git add -A
git commit -m "your commit message"
git push hf main
"""