ViniciusKhan commited on
Commit
63ee0ea
·
1 Parent(s): 41c6570

Fix: package inits + waitress + dynamic

Browse files
Files changed (3) hide show
  1. Dockerfile +3 -8
  2. requirements.txt +2 -2
  3. src/main.py +16 -34
Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- # Dockerfile — Hugging Face Space (Flask via gunicorn)
2
  FROM python:3.11-slim
3
 
4
  ENV DEBIAN_FRONTEND=noninteractive \
@@ -12,23 +12,18 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
12
 
13
  WORKDIR /app
14
 
15
- # Requisitos
16
  COPY requirements.txt /app/requirements.txt
17
  RUN pip install --upgrade pip && pip install -r /app/requirements.txt
18
 
19
- # Código
20
  COPY src /app/src
21
  COPY README.md /app/README.md
22
 
23
- # Variáveis padrão
24
  ENV PYTHONPATH=/app
25
  ENV MPLBACKEND=Agg
26
- # CORS e secret (ajuste origens se necessário)
27
  ENV ALLOWED_ORIGINS="https://viniciuskanh.github.io,http://localhost:3000,http://localhost:5173"
28
  ENV SECRET_KEY="cleansight-secret"
29
 
30
- # Expor porta padrão local (no HF ela será sobrescrita por $PORT)
31
  EXPOSE 7860
32
 
33
- # Use $PORT dinâmico do HF; fallback local mantém usabilidade
34
- CMD ["bash","-lc","exec gunicorn -w ${WEB_CONCURRENCY:-2} -k gthread -b 0.0.0.0:${PORT:-7860} src.main:app --timeout ${TIMEOUT:-120}"]
 
1
+ # Dockerfile — Hugging Face Space (Flask via waitress)
2
  FROM python:3.11-slim
3
 
4
  ENV DEBIAN_FRONTEND=noninteractive \
 
12
 
13
  WORKDIR /app
14
 
 
15
  COPY requirements.txt /app/requirements.txt
16
  RUN pip install --upgrade pip && pip install -r /app/requirements.txt
17
 
 
18
  COPY src /app/src
19
  COPY README.md /app/README.md
20
 
 
21
  ENV PYTHONPATH=/app
22
  ENV MPLBACKEND=Agg
 
23
  ENV ALLOWED_ORIGINS="https://viniciuskanh.github.io,http://localhost:3000,http://localhost:5173"
24
  ENV SECRET_KEY="cleansight-secret"
25
 
 
26
  EXPOSE 7860
27
 
28
+ # Usa a porta dinâmica do Space ($PORT). Fallback para 7860 local.
29
+ CMD ["bash","-lc","python -c 'import os;print(\"PORT=\",os.environ.get(\"PORT\"));from waitress import serve;from src.main import app;serve(app, host=\"0.0.0.0\", port=int(os.environ.get(\"PORT\",7860)))'"]
requirements.txt CHANGED
@@ -1,10 +1,10 @@
1
  Flask==3.0.3
2
  flask-cors==4.0.1
 
3
  chardet==5.2.0
4
  matplotlib==3.8.4
5
  numpy==1.26.4
6
  pandas==2.2.2
7
- ydata-profiling==4.8.3
8
  plotly==5.24.1
9
  scikit-learn==1.4.2
10
- gunicorn==21.2.0
 
1
  Flask==3.0.3
2
  flask-cors==4.0.1
3
+ waitress==2.1.2
4
  chardet==5.2.0
5
  matplotlib==3.8.4
6
  numpy==1.26.4
7
  pandas==2.2.2
 
8
  plotly==5.24.1
9
  scikit-learn==1.4.2
10
+ ydata-profiling==4.8.3
src/main.py CHANGED
@@ -1,55 +1,40 @@
1
  # src/main.py
2
- import os
3
- import sys
4
-
5
- # Garante que "src" esteja no PYTHONPATH (não altere)
6
  sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
7
 
8
- from flask import Flask, send_from_directory, jsonify
9
  from flask_cors import CORS
10
  from src.routes.preprocessing_enhanced import preprocessing_bp
11
 
12
  def create_app():
13
  app = Flask(__name__, static_folder=os.path.join(os.path.dirname(__file__), 'static'))
14
  app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'cleansight-secret')
15
- app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024 # 100MB
16
 
17
- # CORS: somente os domínios permitidos
18
- allowed_origins = os.environ.get(
19
  "ALLOWED_ORIGINS",
20
- "http://localhost:3000,http://localhost:5173,https://viniciuskanh.github.io"
21
  ).split(",")
 
22
 
23
- CORS(app, resources={r"/api/*": {"origins": allowed_origins}}, supports_credentials=False)
24
-
25
- # Blueprints
26
- app.register_blueprint(preprocessing_bp, url_prefix='/api')
27
 
28
- # Healthcheck
29
  @app.get("/health")
30
  def health():
31
  return jsonify({"status": "ok"}), 200
32
 
33
- # Raiz/estáticos (opcional para desenvolvimento local)
34
  @app.route('/', defaults={'path': ''})
35
  @app.route('/<path:path>')
36
  def serve(path):
37
- static_folder_path = app.static_folder
38
- if static_folder_path is None:
39
- return "Static folder not configured", 404
 
 
 
40
 
41
- if path != "" and os.path.exists(os.path.join(static_folder_path, path)):
42
- return send_from_directory(static_folder_path, path)
43
- else:
44
- index_path = os.path.join(static_folder_path, 'index.html')
45
- if os.path.exists(index_path):
46
- return send_from_directory(static_folder_path, 'index.html')
47
- else:
48
- return "index.html not found", 404
49
-
50
- # Cabeçalhos de segurança básicos
51
  @app.after_request
52
- def set_headers(resp):
53
  resp.headers["X-Content-Type-Options"] = "nosniff"
54
  resp.headers["X-Frame-Options"] = "DENY"
55
  resp.headers["X-XSS-Protection"] = "1; mode=block"
@@ -57,10 +42,7 @@ def create_app():
57
 
58
  return app
59
 
60
-
61
  app = create_app()
62
 
63
- if __name__ == '__main__':
64
- # Para rodar localmente
65
- port = int(os.environ.get('PORT', 5000))
66
- app.run(host='0.0.0.0', port=port, debug=True)
 
1
  # src/main.py
2
+ import os, sys
 
 
 
3
  sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
4
 
5
+ from flask import Flask, jsonify, send_from_directory
6
  from flask_cors import CORS
7
  from src.routes.preprocessing_enhanced import preprocessing_bp
8
 
9
  def create_app():
10
  app = Flask(__name__, static_folder=os.path.join(os.path.dirname(__file__), 'static'))
11
  app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'cleansight-secret')
12
+ app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024
13
 
14
+ allowed = os.environ.get(
 
15
  "ALLOWED_ORIGINS",
16
+ "https://viniciuskanh.github.io,http://localhost:3000,http://localhost:5173"
17
  ).split(",")
18
+ CORS(app, resources={r"/api/*": {"origins": allowed}})
19
 
20
+ app.register_blueprint(preprocessing_bp, url_prefix="/api")
 
 
 
21
 
 
22
  @app.get("/health")
23
  def health():
24
  return jsonify({"status": "ok"}), 200
25
 
 
26
  @app.route('/', defaults={'path': ''})
27
  @app.route('/<path:path>')
28
  def serve(path):
29
+ sf = app.static_folder
30
+ if sf and path and os.path.exists(os.path.join(sf, path)):
31
+ return send_from_directory(sf, path)
32
+ if sf and os.path.exists(os.path.join(sf, 'index.html')):
33
+ return send_from_directory(sf, 'index.html')
34
+ return "index.html not found", 404
35
 
 
 
 
 
 
 
 
 
 
 
36
  @app.after_request
37
+ def headers(resp):
38
  resp.headers["X-Content-Type-Options"] = "nosniff"
39
  resp.headers["X-Frame-Options"] = "DENY"
40
  resp.headers["X-XSS-Protection"] = "1; mode=block"
 
42
 
43
  return app
44
 
 
45
  app = create_app()
46
 
47
+ if __name__ == "__main__":
48
+ app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 5000)), debug=True)