d-e-e-k-11 commited on
Commit
ca72ed3
·
verified ·
1 Parent(s): 0cfb54a

Upload folder using huggingface_hub

Browse files
Files changed (11) hide show
  1. .gitignore +16 -0
  2. .hfignore +16 -0
  3. Dockerfile +28 -0
  4. README.md +48 -10
  5. app.py +72 -0
  6. bird_vs_drone_model.h5 +3 -0
  7. final_model.h5 +3 -0
  8. requirements.txt +7 -0
  9. static/css/style.css +244 -0
  10. templates/index.html +142 -0
  11. upload_to_hf.py +49 -0
.gitignore ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Dataset/
2
+ data/
3
+ .git/
4
+ __pycache__/
5
+ *.pyc
6
+ .ipynb_checkpoints/
7
+ training_history.png
8
+ history.json
9
+ prepare_data.py
10
+ train_model.py
11
+ test_api.py
12
+ predict_test.py
13
+ plot_history.py
14
+ implementation_plan.md
15
+ static/uploads/*
16
+ !static/uploads/.gitkeep
.hfignore ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Dataset/
2
+ data/
3
+ .git/
4
+ __pycache__/
5
+ *.pyc
6
+ .ipynb_checkpoints/
7
+ training_history.png
8
+ history.json
9
+ prepare_data.py
10
+ train_model.py
11
+ test_api.py
12
+ predict_test.py
13
+ plot_history.py
14
+ implementation_plan.md
15
+ static/uploads/*
16
+ !static/uploads/.gitkeep
Dockerfile ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use official Python image
2
+ FROM python:3.10-slim
3
+
4
+ # Set working directory
5
+ WORKDIR /app
6
+
7
+ # Install system dependencies for OpenCV
8
+ RUN apt-get update && apt-get install -y \
9
+ libgl1-mesa-glx \
10
+ libglib2.0-0 \
11
+ && rm -rf /var/lib/apt/lists/*
12
+
13
+ # Copy requirements and install dependencies
14
+ COPY requirements.txt .
15
+ RUN pip install --no-cache-dir -r requirements.txt
16
+ RUN pip install --no-cache-dir gunicorn
17
+
18
+ # Copy application code
19
+ COPY . .
20
+
21
+ # Create uploads directory
22
+ RUN mkdir -p static/uploads && chmod 777 static/uploads
23
+
24
+ # Expose port 7860
25
+ EXPOSE 7860
26
+
27
+ # Run the application with gunicorn
28
+ CMD ["gunicorn", "--bind", "0.0.0.0:7860", "app:app"]
README.md CHANGED
@@ -1,10 +1,48 @@
1
- ---
2
- title: Bird Vs Drone Image Classification Using Deep Learning
3
- emoji: 🔥
4
- colorFrom: red
5
- colorTo: gray
6
- sdk: docker
7
- pinned: false
8
- ---
9
-
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Bird vs Drone Classification
3
+ emoji: 🦅🛸
4
+ colorFrom: blue
5
+ colorTo: indigo
6
+ sdk: docker
7
+ app_port: 7860
8
+ pinned: false
9
+ ---
10
+
11
+ # Bird vs Drone Image Classification
12
+
13
+ An end-to-end deep learning project to classify airborne objects into "Bird" or "Drone" categories using a Convolutional Neural Network (MobileNetV2).
14
+
15
+ ## Features
16
+ - **Deep Learning Model**: MobileNetV2 based architecture for fast and accurate classification.
17
+ - **Data Pipeline**: Automated conversion from YOLO detection labels to classification datasets.
18
+ - **Web Interface**: Premium glassmorphic UI for real-time inference.
19
+ - **Data Augmentation**: Robust training using rotation, flip, and zoom augmentations.
20
+
21
+ ## Project Structure
22
+ - `prepare_data.py`: Prepares the dataset manifests.
23
+ - `train_model.py`: Trains the model on a subset of the 20k+ images.
24
+ - `app.py`: Flask application for the web interface.
25
+ - `templates/` & `static/`: Frontend assets.
26
+ - `bird_vs_drone_model.h5`: The trained model weights.
27
+
28
+ ## Installation
29
+ ```bash
30
+ pip install -r requirements.txt
31
+ ```
32
+
33
+ ## Usage
34
+ 1. **Prepare Data**:
35
+ ```bash
36
+ python prepare_data.py
37
+ ```
38
+ 2. **Train Model**:
39
+ ```bash
40
+ python train_model.py
41
+ ```
42
+ 3. **Run Web App**:
43
+ ```bash
44
+ python app.py
45
+ ```
46
+
47
+ ## Results
48
+ The system provides a confidence score and a visual analysis of the uploaded target, distinguishing between natural avian flight and synthetic drone movement.
app.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, render_template, request, jsonify
2
+ import tensorflow as tf
3
+ from tensorflow.keras.preprocessing import image
4
+ import numpy as np
5
+ import os
6
+ from werkzeug.utils import secure_filename
7
+
8
+ app = Flask(__name__)
9
+ app.config['UPLOAD_FOLDER'] = 'static/uploads'
10
+ os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
11
+
12
+ # Load model
13
+ MODEL_PATH = 'bird_vs_drone_model.h5'
14
+ model = None
15
+
16
+ def get_model():
17
+ global model
18
+ if model is None:
19
+ if os.path.exists(MODEL_PATH):
20
+ model = tf.keras.models.load_model(MODEL_PATH)
21
+ elif os.path.exists('final_model.h5'):
22
+ model = tf.keras.models.load_model('final_model.h5')
23
+ return model
24
+
25
+ @app.route('/')
26
+ def index():
27
+ return render_template('index.html')
28
+
29
+ @app.route('/predict', methods=['POST'])
30
+ def predict():
31
+ if 'file' not in request.files:
32
+ return jsonify({'error': 'No file uploaded'})
33
+
34
+ file = request.files['file']
35
+ if file.filename == '':
36
+ return jsonify({'error': 'No file selected'})
37
+
38
+ if file:
39
+ filename = secure_filename(file.filename)
40
+ filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
41
+ file.save(filepath)
42
+
43
+ # Preprocess
44
+ img = image.load_img(filepath, target_size=(224, 224))
45
+ img_array = image.img_to_array(img) / 255.0
46
+ img_array = np.expand_dims(img_array, axis=0)
47
+
48
+ # Predict
49
+ m = get_model()
50
+ if m is None:
51
+ return jsonify({'error': 'Model not found. Please train the model first.'})
52
+
53
+ prediction = m.predict(img_array)[0][0]
54
+
55
+ # Result
56
+ # Class index 0 is Bird, 1 is Drone (based on our generator)
57
+ # Binary generator usually sorts class names alphabetically: ['Bird', 'Drone']
58
+ # So Bird = 0, Drone = 1.
59
+ # prediction > 0.5 means Drone
60
+
61
+ label = 'Drone' if prediction > 0.5 else 'Bird'
62
+ confidence = float(prediction) if label == 'Drone' else float(1 - prediction)
63
+
64
+ return jsonify({
65
+ 'label': label,
66
+ 'confidence': f"{confidence*100:.2f}%",
67
+ 'image_url': f"/static/uploads/{filename}"
68
+ })
69
+
70
+ if __name__ == '__main__':
71
+ port = int(os.environ.get('PORT', 7860))
72
+ app.run(host='0.0.0.0', port=port)
bird_vs_drone_model.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:75e0a7d7ea6daef662441afa2e2d8fee3aab4808c5aee59cedd61a1a3c97212d
3
+ size 11507656
final_model.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:75e0a7d7ea6daef662441afa2e2d8fee3aab4808c5aee59cedd61a1a3c97212d
3
+ size 11507656
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ tensorflow>=2.15.0
2
+ pandas
3
+ flask
4
+ numpy
5
+ werkzeug
6
+ opencv-python-headless
7
+ gunicorn
static/css/style.css ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ :root {
2
+ --primary: #00d2ff;
3
+ --secondary: #3a7bd5;
4
+ --dark: #0f172a;
5
+ --glass: rgba(255, 255, 255, 0.05);
6
+ --glass-border: rgba(255, 255, 255, 0.1);
7
+ --text: #f8fafc;
8
+ }
9
+
10
+ * {
11
+ margin: 0;
12
+ padding: 0;
13
+ box-sizing: border-box;
14
+ }
15
+
16
+ body {
17
+ font-family: 'Outfit', sans-serif;
18
+ background: radial-gradient(circle at top left, #1e293b, #0f172a);
19
+ color: var(--text);
20
+ min-height: 100vh;
21
+ display: flex;
22
+ justify-content: center;
23
+ padding: 2rem;
24
+ }
25
+
26
+ .container {
27
+ max-width: 900px;
28
+ width: 100%;
29
+ }
30
+
31
+ header {
32
+ text-align: center;
33
+ margin-bottom: 3rem;
34
+ animation: fadeInDown 0.8s ease-out;
35
+ }
36
+
37
+ .logo {
38
+ display: flex;
39
+ align-items: center;
40
+ justify-content: center;
41
+ gap: 1rem;
42
+ margin-bottom: 0.5rem;
43
+ }
44
+
45
+ .logo i {
46
+ font-size: 2.5rem;
47
+ color: var(--primary);
48
+ }
49
+
50
+ header h1 {
51
+ font-size: 2.5rem;
52
+ font-weight: 600;
53
+ letter-spacing: -0.025em;
54
+ background: linear-gradient(to right, var(--primary), var(--secondary));
55
+ -webkit-background-clip: text;
56
+ background-clip: text;
57
+ color: transparent;
58
+ }
59
+
60
+ header p {
61
+ color: #94a3b8;
62
+ font-size: 1.1rem;
63
+ }
64
+
65
+ .glass-card {
66
+ background: var(--glass);
67
+ backdrop-filter: blur(12px);
68
+ border: 1px solid var(--glass-border);
69
+ border-radius: 1.5rem;
70
+ padding: 2rem;
71
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
72
+ transition: transform 0.3s ease;
73
+ }
74
+
75
+ .upload-section {
76
+ margin-bottom: 2rem;
77
+ text-align: center;
78
+ }
79
+
80
+ .drop-zone {
81
+ border: 2px dashed var(--glass-border);
82
+ border-radius: 1rem;
83
+ padding: 3rem 2rem;
84
+ cursor: pointer;
85
+ transition: all 0.3s ease;
86
+ margin-bottom: 1.5rem;
87
+ }
88
+
89
+ .drop-zone:hover, .drop-zone.active {
90
+ border-color: var(--primary);
91
+ background: rgba(0, 210, 255, 0.05);
92
+ }
93
+
94
+ .drop-zone i {
95
+ font-size: 3rem;
96
+ color: var(--primary);
97
+ margin-bottom: 1rem;
98
+ }
99
+
100
+ .btn-primary {
101
+ background: linear-gradient(135deg, var(--primary), var(--secondary));
102
+ color: white;
103
+ border: none;
104
+ padding: 1rem 2.5rem;
105
+ border-radius: 0.75rem;
106
+ font-size: 1.1rem;
107
+ font-weight: 600;
108
+ cursor: pointer;
109
+ transition: all 0.3s ease;
110
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3);
111
+ }
112
+
113
+ .btn-primary:hover:not(:disabled) {
114
+ transform: translateY(-2px);
115
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.4);
116
+ }
117
+
118
+ .btn-primary:disabled {
119
+ opacity: 0.5;
120
+ cursor: not-allowed;
121
+ }
122
+
123
+ .result-card {
124
+ display: flex;
125
+ gap: 2rem;
126
+ align-items: center;
127
+ animation: fadeInUp 0.6s ease-out;
128
+ }
129
+
130
+ .image-preview {
131
+ position: relative;
132
+ width: 300px;
133
+ height: 300px;
134
+ border-radius: 1rem;
135
+ overflow: hidden;
136
+ border: 1px solid var(--glass-border);
137
+ }
138
+
139
+ .image-preview img {
140
+ width: 100%;
141
+ height: 100%;
142
+ object-fit: cover;
143
+ }
144
+
145
+ .scan-line {
146
+ position: absolute;
147
+ top: 0;
148
+ left: 0;
149
+ width: 100%;
150
+ height: 2px;
151
+ background: var(--primary);
152
+ box-shadow: 0 0 15px var(--primary);
153
+ animation: scan 2.5s linear infinite;
154
+ }
155
+
156
+ .analysis-info {
157
+ flex: 1;
158
+ }
159
+
160
+ .analysis-info h2 {
161
+ font-size: 1.5rem;
162
+ margin-bottom: 1.5rem;
163
+ color: #cbd5e1;
164
+ }
165
+
166
+ .result-item {
167
+ margin-bottom: 1.5rem;
168
+ }
169
+
170
+ .result-item .label {
171
+ display: block;
172
+ color: #94a3b8;
173
+ margin-bottom: 0.5rem;
174
+ font-size: 0.9rem;
175
+ text-transform: uppercase;
176
+ letter-spacing: 0.05em;
177
+ }
178
+
179
+ .badge {
180
+ padding: 0.5rem 1rem;
181
+ border-radius: 2rem;
182
+ font-weight: 600;
183
+ font-size: 1.2rem;
184
+ display: inline-block;
185
+ }
186
+
187
+ .badge.bird {
188
+ background: rgba(34, 197, 94, 0.2);
189
+ color: #4ade80;
190
+ border: 1px solid rgba(34, 197, 94, 0.3);
191
+ }
192
+
193
+ .badge.drone {
194
+ background: rgba(239, 68, 68, 0.2);
195
+ color: #f87171;
196
+ border: 1px solid rgba(239, 68, 68, 0.3);
197
+ }
198
+
199
+ .progress-bar {
200
+ width: 100%;
201
+ height: 8px;
202
+ background: var(--glass);
203
+ border-radius: 4px;
204
+ overflow: hidden;
205
+ margin-bottom: 0.5rem;
206
+ }
207
+
208
+ .progress-fill {
209
+ height: 100%;
210
+ background: var(--primary);
211
+ width: 0;
212
+ transition: width 1s ease-out;
213
+ }
214
+
215
+ footer {
216
+ text-align: center;
217
+ margin-top: 4rem;
218
+ color: #64748b;
219
+ font-size: 0.9rem;
220
+ }
221
+
222
+ @keyframes scan {
223
+ 0% { top: 0; }
224
+ 100% { top: 100%; }
225
+ }
226
+
227
+ @keyframes fadeInUp {
228
+ from { opacity: 0; transform: translateY(20px); }
229
+ to { opacity: 1; transform: translateY(0); }
230
+ }
231
+
232
+ @keyframes fadeInDown {
233
+ from { opacity: 0; transform: translateY(-20px); }
234
+ to { opacity: 1; transform: translateY(0); }
235
+ }
236
+
237
+ @media (max-width: 768px) {
238
+ .result-card {
239
+ flex-direction: column;
240
+ }
241
+ .image-preview {
242
+ width: 100%;
243
+ }
244
+ }
templates/index.html ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>SkyGuard | Bird vs Drone Classifier</title>
7
+ <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
8
+ <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600&display=swap" rel="stylesheet">
9
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/js/all.min.js"></script>
10
+ </head>
11
+ <body>
12
+ <div class="container">
13
+ <header>
14
+ <div class="logo">
15
+ <i class="fas fa-shield-alt"></i>
16
+ <h1>SkyGuard AI</h1>
17
+ </div>
18
+ <p>Advanced Aerial Identification System</p>
19
+ </header>
20
+
21
+ <main>
22
+ <div class="glass-card upload-section">
23
+ <div class="drop-zone" id="drop-zone">
24
+ <i class="fas fa-cloud-upload-alt"></i>
25
+ <p>Drag & drop or Click to Upload Image</p>
26
+ <input type="file" id="file-input" hidden accept="image/*">
27
+ </div>
28
+ <button id="predict-btn" class="btn-primary" disabled>Analyze Target</button>
29
+ </div>
30
+
31
+ <div class="result-section" id="result-section" style="display: none;">
32
+ <div class="glass-card result-card">
33
+ <div class="image-preview">
34
+ <img id="preview-img" src="" alt="Target Analysis">
35
+ <div class="scan-line"></div>
36
+ </div>
37
+ <div class="analysis-info">
38
+ <h2>Analysis Results</h2>
39
+ <div class="result-item">
40
+ <span class="label">Classification:</span>
41
+ <span id="res-label" class="value badge">---</span>
42
+ </div>
43
+ <div class="result-item">
44
+ <span class="label">Confidence:</span>
45
+ <div class="progress-bar">
46
+ <div id="res-conf-bar" class="progress-fill" style="width: 0%"></div>
47
+ </div>
48
+ <span id="res-conf-text" class="value">0%</span>
49
+ </div>
50
+ </div>
51
+ </div>
52
+ </div>
53
+ </main>
54
+
55
+ <footer>
56
+ <p>&copy; 2026 Deep Learning Aerial Surveillance Project</p>
57
+ </footer>
58
+ </div>
59
+
60
+ <script>
61
+ const dropZone = document.getElementById('drop-zone');
62
+ const fileInput = document.getElementById('file-input');
63
+ const predictBtn = document.getElementById('predict-btn');
64
+ const resultSection = document.getElementById('result-section');
65
+ const previewImg = document.getElementById('preview-img');
66
+ const resLabel = document.getElementById('res-label');
67
+ const resConfText = document.getElementById('res-conf-text');
68
+ const resConfBar = document.getElementById('res-conf-bar');
69
+
70
+ let selectedFile = null;
71
+
72
+ dropZone.onclick = () => fileInput.click();
73
+
74
+ fileInput.onchange = (e) => {
75
+ selectedFile = e.target.files[0];
76
+ if (selectedFile) {
77
+ const reader = new FileReader();
78
+ reader.onload = (e) => {
79
+ previewImg.src = e.target.result;
80
+ resultSection.style.display = 'block';
81
+ predictBtn.disabled = false;
82
+ // Reset labels
83
+ resLabel.textContent = '---';
84
+ resLabel.className = 'value badge';
85
+ resConfText.textContent = '0%';
86
+ resConfBar.style.width = '0%';
87
+ };
88
+ reader.readAsDataURL(selectedFile);
89
+ }
90
+ };
91
+
92
+ predictBtn.onclick = async () => {
93
+ if (!selectedFile) return;
94
+
95
+ predictBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Analyzing...';
96
+ predictBtn.disabled = true;
97
+
98
+ const formData = new FormData();
99
+ formData.append('file', selectedFile);
100
+
101
+ try {
102
+ const response = await fetch('/predict', {
103
+ method: 'POST',
104
+ body: formData
105
+ });
106
+ const data = await response.json();
107
+
108
+ if (data.error) {
109
+ alert(data.error);
110
+ } else {
111
+ resLabel.textContent = data.label;
112
+ resLabel.classList.add(data.label.toLowerCase());
113
+ resConfText.textContent = data.confidence;
114
+ resConfBar.style.width = data.confidence;
115
+
116
+ // Smooth scroll to results
117
+ resultSection.scrollIntoView({ behavior: 'smooth' });
118
+ }
119
+ } catch (error) {
120
+ console.error('Error:', error);
121
+ alert('Analysis failed. Check console for details.');
122
+ } finally {
123
+ predictBtn.innerHTML = 'Analyze Target';
124
+ predictBtn.disabled = false;
125
+ }
126
+ };
127
+
128
+ // Drag and Drop
129
+ dropZone.ondragover = (e) => {
130
+ e.preventDefault();
131
+ dropZone.classList.add('active');
132
+ };
133
+ dropZone.ondragleave = () => dropZone.classList.remove('active');
134
+ dropZone.ondrop = (e) => {
135
+ e.preventDefault();
136
+ dropZone.classList.remove('active');
137
+ fileInput.files = e.dataTransfer.files;
138
+ fileInput.onchange({ target: fileInput });
139
+ };
140
+ </script>
141
+ </body>
142
+ </html>
upload_to_hf.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from huggingface_hub import HfApi, create_repo
3
+
4
+ # Configuration
5
+ REPO_NAME = "Bird-vs-Drone-image-classification-using-Deep-Learning"
6
+ USERNAME = "d-e-e-k-11" # Your Hugging Face username
7
+ REPO_ID = f"{USERNAME}/{REPO_NAME}"
8
+
9
+ api = HfApi()
10
+
11
+ def upload():
12
+ print(f"Starting upload to https://huggingface.co/spaces/{REPO_ID}")
13
+
14
+ try:
15
+ # 1. Create the repo if it doesn't exist
16
+ print(f"Checking if repo {REPO_ID} exists...")
17
+ create_repo(repo_id=REPO_ID, repo_type="space", space_sdk="docker", exist_ok=True)
18
+
19
+ # 2. Upload the folder while ignoring the large dataset
20
+ print("Hashing files and uploading (ignoring Dataset/ and data/)...")
21
+ # We use a custom ignore list to be 100% sure
22
+ ignore_patterns = [
23
+ "Dataset/*",
24
+ "data/*",
25
+ ".git/*",
26
+ "__pycache__/*",
27
+ "*.pyc",
28
+ "training_history.png",
29
+ "history.json"
30
+ ]
31
+
32
+ api.upload_folder(
33
+ folder_path=".",
34
+ repo_id=REPO_ID,
35
+ repo_type="space",
36
+ ignore_patterns=ignore_patterns,
37
+ delete_patterns=None # Set to "Dataset/*" etc if you want to clean remote
38
+ )
39
+
40
+ print(f"\nSuccess! Your app is live at: https://huggingface.co/spaces/{REPO_ID}")
41
+ print("Note: It may take a few minutes for the Docker container to build on Hugging Face.")
42
+
43
+ except Exception as e:
44
+ print(f"\nError: {e}")
45
+ print("\nIf you are not logged in, run: huggingface-cli login")
46
+ print("Or provide a token in the script.")
47
+
48
+ if __name__ == "__main__":
49
+ upload()