Karim Krklec commited on
Commit
afca779
Β·
1 Parent(s): a641ed5

Deploy: dodani Dockerfile, requirements, static serving

Browse files
Files changed (4) hide show
  1. .gitattributes +2 -0
  2. Dockerfile +42 -0
  3. app.py +23 -10
  4. requirements.txt +15 -0
.gitattributes CHANGED
@@ -1 +1,3 @@
 
 
1
  model/classifier.pkl filter=lfs diff=lfs merge=lfs -text
 
1
+ # Git LFS tracking β€” classifier.pkl is ~183 MB, over GitHub's 100 MB hard limit.
2
+ # HF Spaces git also uses LFS for large files.
3
  model/classifier.pkl filter=lfs diff=lfs merge=lfs -text
Dockerfile ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Hugging Face Spaces β€” Docker deployment
2
+ # Builds React frontend, then runs Flask backend which serves everything.
3
+ # HF Spaces expects the app on port 7860.
4
+
5
+ FROM python:3.11-slim
6
+
7
+ # ── System deps ──────────────────────────────────────────────────────────────
8
+ RUN apt-get update && apt-get install -y --no-install-recommends \
9
+ curl \
10
+ nodejs \
11
+ npm \
12
+ && rm -rf /var/lib/apt/lists/*
13
+
14
+ WORKDIR /app
15
+
16
+ # ── Python dependencies ───────────────────────────────────────────────────────
17
+ COPY requirements.txt .
18
+ RUN pip install --no-cache-dir -r requirements.txt
19
+
20
+ # ── Build React frontend ──────────────────────────────────────────────────────
21
+ COPY frontend/package.json frontend/package-lock.json* ./frontend/
22
+ RUN cd frontend && npm install
23
+
24
+ COPY frontend/ ./frontend/
25
+ RUN cd frontend && npm run build
26
+
27
+ # ── Backend source + trained model ───────────────────────────────────────────
28
+ COPY app.py classifier.py feature_extraction.py language_config.py ./
29
+ COPY model/ ./model/
30
+
31
+ # ── Runtime config ────────────────────────────────────────────────────────────
32
+ ENV PORT=7860
33
+ EXPOSE 7860
34
+
35
+ # Single worker because the sklearn model is not thread-safe during load;
36
+ # increase --workers if you switch to a thread-safe serving strategy.
37
+ CMD ["gunicorn", \
38
+ "--bind", "0.0.0.0:7860", \
39
+ "--timeout", "300", \
40
+ "--workers", "1", \
41
+ "--threads", "4", \
42
+ "app:app"]
app.py CHANGED
@@ -21,7 +21,7 @@ import difflib
21
  import warnings
22
  warnings.filterwarnings("ignore")
23
 
24
- from flask import Flask, request, jsonify
25
  from flask_cors import CORS
26
 
27
  from classifier import predict, ucitaj_model
@@ -34,6 +34,9 @@ from feature_extraction import extract_all_features, analyze_lines
34
 
35
  app = Flask(__name__)
36
 
 
 
 
37
  # CORS dopuΕ‘ta React frontendu (localhost:3000) da komunicira s ovim serverom
38
  CORS(app, resources={r"/api/*": {"origins": "*"}})
39
 
@@ -328,14 +331,30 @@ def similarity():
328
 
329
 
330
  # ─────────────────────────────────────────────────────────────────────────────
331
- # POKRETANJE
332
  # ─────────────────────────────────────────────────────────────────────────────
333
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
  if __name__ == "__main__":
 
335
  print("\n" + "=" * 50)
336
  print(" AI Code Detector β€” Backend")
337
  print("=" * 50)
338
- print(" Server pokrenut na: http://localhost:5000")
339
  print(" API rute:")
340
  print(" GET /api/health")
341
  print(" POST /api/analyze")
@@ -343,10 +362,4 @@ if __name__ == "__main__":
343
  print(" POST /api/similarity")
344
  print("\n Zaustavi server s Ctrl+C")
345
  print("=" * 50 + "\n")
346
-
347
- app.run(
348
- host="0.0.0.0",
349
- port=5000,
350
- debug=True,
351
- threaded=True, # potrebno za streaming β€” svaki zahtjev u svom threadu
352
- )
 
21
  import warnings
22
  warnings.filterwarnings("ignore")
23
 
24
+ from flask import Flask, request, jsonify, send_from_directory
25
  from flask_cors import CORS
26
 
27
  from classifier import predict, ucitaj_model
 
34
 
35
  app = Flask(__name__)
36
 
37
+ # Putanja do buildan React aplikacije (postoji samo u produkciji)
38
+ FRONTEND_BUILD = os.path.join(os.path.dirname(__file__), "frontend", "dist")
39
+
40
  # CORS dopuΕ‘ta React frontendu (localhost:3000) da komunicira s ovim serverom
41
  CORS(app, resources={r"/api/*": {"origins": "*"}})
42
 
 
331
 
332
 
333
  # ─────────────────────────────────────────────────────────────────────────────
334
+ # SERVIRANJE REACT FRONTENDA (produkcija)
335
  # ─────────────────────────────────────────────────────────────────────────────
336
 
337
+ @app.route("/", defaults={"path": ""})
338
+ @app.route("/<path:path>")
339
+ def serve_frontend(path):
340
+ """
341
+ Servira buildan React app za sve rute koje nisu /api/*.
342
+ Potrebno za client-side routing (React Router).
343
+ """
344
+ if os.path.isdir(FRONTEND_BUILD):
345
+ target = os.path.join(FRONTEND_BUILD, path)
346
+ if path and os.path.exists(target):
347
+ return send_from_directory(FRONTEND_BUILD, path)
348
+ return send_from_directory(FRONTEND_BUILD, "index.html")
349
+ return jsonify({"error": "Frontend nije buildΠ°Π½. Pokreni: cd frontend && npm run build"}), 404
350
+
351
+
352
  if __name__ == "__main__":
353
+ port = int(os.environ.get("PORT", 5000))
354
  print("\n" + "=" * 50)
355
  print(" AI Code Detector β€” Backend")
356
  print("=" * 50)
357
+ print(f" Server pokrenut na: http://localhost:{port}")
358
  print(" API rute:")
359
  print(" GET /api/health")
360
  print(" POST /api/analyze")
 
362
  print(" POST /api/similarity")
363
  print("\n Zaustavi server s Ctrl+C")
364
  print("=" * 50 + "\n")
365
+ app.run(host="0.0.0.0", port=port, debug=False, threaded=True)
 
 
 
 
 
 
requirements.txt ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ flask==3.1.3
2
+ flask-cors==6.0.2
3
+ numpy==2.4.1
4
+ scikit-learn==1.8.0
5
+ gunicorn==23.0.0
6
+ tree-sitter==0.23.2
7
+ tree-sitter-python==0.21.0
8
+ tree-sitter-javascript==0.21.4
9
+ tree-sitter-java==0.21.0
10
+ tree-sitter-cpp==0.22.0
11
+ tree-sitter-c==0.21.3
12
+ tree-sitter-go==0.21.0
13
+ tree-sitter-rust==0.21.2
14
+ tree-sitter-ruby==0.21.0
15
+ tree-sitter-typescript==0.21.2