Spaces:
Runtime error
Runtime error
Karim Krklec commited on
Commit Β·
afca779
1
Parent(s): a641ed5
Deploy: dodani Dockerfile, requirements, static serving
Browse files- .gitattributes +2 -0
- Dockerfile +42 -0
- app.py +23 -10
- 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 |
-
#
|
| 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:
|
| 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
|