Spaces:
Sleeping
Sleeping
Sean Carnahan
commited on
Commit
·
fef15d6
1
Parent(s):
5dd4f2e
Fix HF Spaces deployment: Add proper path handling and model loading
Browse files- Dockerfile +6 -1
- app.py +25 -63
Dockerfile
CHANGED
@@ -15,8 +15,13 @@ RUN pip install --no-cache-dir -r requirements.txt
|
|
15 |
# Create necessary directories with proper permissions
|
16 |
RUN mkdir -p /code/static/uploads \
|
17 |
&& mkdir -p /code/logs \
|
|
|
18 |
&& chmod -R 777 /code/static/uploads \
|
19 |
-
&& chmod -R 777 /code/logs
|
|
|
|
|
|
|
|
|
20 |
|
21 |
# Copy the rest of the application
|
22 |
COPY . .
|
|
|
15 |
# Create necessary directories with proper permissions
|
16 |
RUN mkdir -p /code/static/uploads \
|
17 |
&& mkdir -p /code/logs \
|
18 |
+
&& mkdir -p /code/external/BodybuildingPoseClassifier \
|
19 |
&& chmod -R 777 /code/static/uploads \
|
20 |
+
&& chmod -R 777 /code/logs \
|
21 |
+
&& chmod -R 777 /code/external
|
22 |
+
|
23 |
+
# Copy the model file first
|
24 |
+
COPY external/BodybuildingPoseClassifier/bodybuilding_pose_classifier.h5 /code/external/BodybuildingPoseClassifier/
|
25 |
|
26 |
# Copy the rest of the application
|
27 |
COPY . .
|
app.py
CHANGED
@@ -49,90 +49,52 @@ file_handler = logging.FileHandler(os.path.join(log_dir, 'app.log'))
|
|
49 |
file_handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
|
50 |
logger.addHandler(file_handler)
|
51 |
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
gc.collect()
|
65 |
-
log_memory_usage()
|
66 |
-
except Exception as e:
|
67 |
-
logger.error(f"Error in cleanup_memory: {e}")
|
68 |
-
|
69 |
-
def wrap_text(text: str, font_face: int, font_scale: float, thickness: int, max_width: int) -> list[str]:
|
70 |
-
"""Wrap text to fit within max_width."""
|
71 |
-
if not text:
|
72 |
-
return []
|
73 |
-
|
74 |
-
lines = []
|
75 |
-
words = text.split(' ')
|
76 |
-
current_line = ''
|
77 |
-
|
78 |
-
for word in words:
|
79 |
-
# Check width if current_line + word fits
|
80 |
-
test_line = current_line + word + ' '
|
81 |
-
(text_width, _), _ = cv2.getTextSize(test_line.strip(), font_face, font_scale, thickness)
|
82 |
-
|
83 |
-
if text_width <= max_width:
|
84 |
-
current_line = test_line
|
85 |
-
else:
|
86 |
-
# Word doesn't fit, so current_line (without the new word) is a complete line
|
87 |
-
lines.append(current_line.strip())
|
88 |
-
# Start new line with the current word
|
89 |
-
current_line = word + ' '
|
90 |
-
# If a single word is too long, it will still overflow. Handle by breaking word if necessary (future enhancement)
|
91 |
-
(single_word_width, _), _ = cv2.getTextSize(word.strip(), font_face, font_scale, thickness)
|
92 |
-
if single_word_width > max_width:
|
93 |
-
# For now, just add the long word and let it overflow, or truncate it.
|
94 |
-
# A more complex solution would break the word.
|
95 |
-
lines.append(word.strip()) # Add the long word as its own line
|
96 |
-
current_line = '' # Reset current_line as the long word is handled
|
97 |
-
|
98 |
-
if current_line.strip(): # Add the last line
|
99 |
-
lines.append(current_line.strip())
|
100 |
-
|
101 |
-
return lines if lines else [text] # Ensure at least the original text is returned if no wrapping happens
|
102 |
-
|
103 |
-
app = Flask(__name__, static_url_path='/static', static_folder='static')
|
104 |
CORS(app, resources={r"/*": {"origins": "*"}})
|
105 |
|
106 |
-
app.config['UPLOAD_FOLDER'] =
|
107 |
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024 # 100MB max file size
|
108 |
|
109 |
-
# Ensure upload directory exists
|
110 |
-
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
|
111 |
-
|
112 |
# Load CNN model for bodybuilding pose classification
|
113 |
try:
|
114 |
logger.info("Loading CNN model...")
|
115 |
-
cnn_model_path = '
|
|
|
|
|
116 |
if not os.path.exists(cnn_model_path):
|
117 |
raise FileNotFoundError(f"CNN model not found at {cnn_model_path}")
|
118 |
-
|
|
|
|
|
119 |
logger.info("CNN model loaded successfully")
|
120 |
except Exception as e:
|
121 |
logger.error(f"Error loading CNN model: {e}")
|
|
|
122 |
raise
|
123 |
|
124 |
cnn_class_labels = ['side_chest', 'front_double_biceps', 'back_double_biceps', 'front_lat_spread', 'back_lat_spread']
|
125 |
|
126 |
def predict_pose_cnn(img_path):
|
127 |
try:
|
128 |
-
cleanup_memory()
|
129 |
if gpus:
|
130 |
logger.info("[CNN_DEBUG] Using GPU for CNN prediction")
|
131 |
with tf.device('/GPU:0'):
|
132 |
img = image.load_img(img_path, target_size=(150, 150))
|
133 |
img_array = image.img_to_array(img)
|
134 |
img_array = np.expand_dims(img_array, axis=0) / 255.0
|
135 |
-
predictions = cnn_model.predict(img_array, verbose=0)
|
136 |
predicted_class = np.argmax(predictions, axis=1)
|
137 |
confidence = float(np.max(predictions))
|
138 |
else:
|
@@ -141,7 +103,7 @@ def predict_pose_cnn(img_path):
|
|
141 |
img = image.load_img(img_path, target_size=(150, 150))
|
142 |
img_array = image.img_to_array(img)
|
143 |
img_array = np.expand_dims(img_array, axis=0) / 255.0
|
144 |
-
predictions = cnn_model.predict(img_array, verbose=0)
|
145 |
predicted_class = np.argmax(predictions, axis=1)
|
146 |
confidence = float(np.max(predictions))
|
147 |
|
@@ -149,10 +111,10 @@ def predict_pose_cnn(img_path):
|
|
149 |
return cnn_class_labels[predicted_class[0]], confidence
|
150 |
except Exception as e:
|
151 |
logger.error(f"[CNN_ERROR] Exception during CNN prediction: {e}")
|
152 |
-
traceback.
|
153 |
raise
|
154 |
finally:
|
155 |
-
cleanup_memory()
|
156 |
|
157 |
@app.route('/static/uploads/<path:filename>')
|
158 |
def serve_video(filename):
|
|
|
49 |
file_handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
|
50 |
logger.addHandler(file_handler)
|
51 |
|
52 |
+
# Define base paths
|
53 |
+
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
54 |
+
STATIC_DIR = os.path.join(BASE_DIR, 'static')
|
55 |
+
UPLOAD_DIR = os.path.join(STATIC_DIR, 'uploads')
|
56 |
+
MODEL_DIR = os.path.join(BASE_DIR, 'external', 'BodybuildingPoseClassifier')
|
57 |
+
|
58 |
+
# Ensure all required directories exist
|
59 |
+
for directory in [STATIC_DIR, UPLOAD_DIR, MODEL_DIR, log_dir]:
|
60 |
+
os.makedirs(directory, exist_ok=True)
|
61 |
+
logger.info(f"Ensured directory exists: {directory}")
|
62 |
+
|
63 |
+
app = Flask(__name__, static_url_path='/static', static_folder=STATIC_DIR)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
CORS(app, resources={r"/*": {"origins": "*"}})
|
65 |
|
66 |
+
app.config['UPLOAD_FOLDER'] = UPLOAD_DIR
|
67 |
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024 # 100MB max file size
|
68 |
|
|
|
|
|
|
|
69 |
# Load CNN model for bodybuilding pose classification
|
70 |
try:
|
71 |
logger.info("Loading CNN model...")
|
72 |
+
cnn_model_path = os.path.join(MODEL_DIR, 'bodybuilding_pose_classifier.h5')
|
73 |
+
logger.info(f"Looking for model at: {cnn_model_path}")
|
74 |
+
|
75 |
if not os.path.exists(cnn_model_path):
|
76 |
raise FileNotFoundError(f"CNN model not found at {cnn_model_path}")
|
77 |
+
|
78 |
+
# Load model with custom_objects to handle any custom layers
|
79 |
+
cnn_model = load_model(cnn_model_path, compile=False)
|
80 |
logger.info("CNN model loaded successfully")
|
81 |
except Exception as e:
|
82 |
logger.error(f"Error loading CNN model: {e}")
|
83 |
+
logger.error(traceback.format_exc())
|
84 |
raise
|
85 |
|
86 |
cnn_class_labels = ['side_chest', 'front_double_biceps', 'back_double_biceps', 'front_lat_spread', 'back_lat_spread']
|
87 |
|
88 |
def predict_pose_cnn(img_path):
|
89 |
try:
|
90 |
+
cleanup_memory()
|
91 |
if gpus:
|
92 |
logger.info("[CNN_DEBUG] Using GPU for CNN prediction")
|
93 |
with tf.device('/GPU:0'):
|
94 |
img = image.load_img(img_path, target_size=(150, 150))
|
95 |
img_array = image.img_to_array(img)
|
96 |
img_array = np.expand_dims(img_array, axis=0) / 255.0
|
97 |
+
predictions = cnn_model.predict(img_array, verbose=0)
|
98 |
predicted_class = np.argmax(predictions, axis=1)
|
99 |
confidence = float(np.max(predictions))
|
100 |
else:
|
|
|
103 |
img = image.load_img(img_path, target_size=(150, 150))
|
104 |
img_array = image.img_to_array(img)
|
105 |
img_array = np.expand_dims(img_array, axis=0) / 255.0
|
106 |
+
predictions = cnn_model.predict(img_array, verbose=0)
|
107 |
predicted_class = np.argmax(predictions, axis=1)
|
108 |
confidence = float(np.max(predictions))
|
109 |
|
|
|
111 |
return cnn_class_labels[predicted_class[0]], confidence
|
112 |
except Exception as e:
|
113 |
logger.error(f"[CNN_ERROR] Exception during CNN prediction: {e}")
|
114 |
+
logger.error(traceback.format_exc())
|
115 |
raise
|
116 |
finally:
|
117 |
+
cleanup_memory()
|
118 |
|
119 |
@app.route('/static/uploads/<path:filename>')
|
120 |
def serve_video(filename):
|