sonia2025 commited on
Commit
5f81abb
·
verified ·
1 Parent(s): 00d7dee

Upload 6 files

Browse files
Files changed (6) hide show
  1. Dockerfile +8 -0
  2. app.py +62 -0
  3. requirements.txt +5 -0
  4. static/preview.js +33 -0
  5. templates/.DS_Store +0 -0
  6. templates/index.html +29 -0
Dockerfile ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.12-slim
2
+ WORKDIR /app
3
+ COPY requirements.txt .
4
+ RUN pip install --no-cache-dir -r requirements.txt
5
+ COPY . .
6
+ ENV PORT 10000
7
+ EXPOSE 10000
8
+ CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:10000", "--workers", "1"]
app.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import hashlib
3
+ import cv2
4
+ from flask import Flask, render_template, request, jsonify, send_from_directory
5
+ from ultralytics import YOLO
6
+ from huggingface_hub import hf_hub_download
7
+
8
+ # ----- 下載模型 -----
9
+ MODEL_REPO = "sonia2025/best.pt" # 改成你 HF 上的 repo 名稱
10
+ MODEL_FILENAME = "best.pt"
11
+
12
+ # 這行會把 best.pt 下載到本地快取目錄
13
+ weights_path = hf_hub_download(repo_id=MODEL_REPO, filename=MODEL_FILENAME)
14
+
15
+ # 印出 hash 以便驗證
16
+ with open(weights_path, "rb") as f:
17
+ print(">> Loaded weights sha256:", hashlib.sha256(f.read()).hexdigest())
18
+
19
+ # 載入模型
20
+ model = YOLO(weights_path)
21
+
22
+ # ----- Flask App -----
23
+ app = Flask(__name__)
24
+
25
+ # 上傳/輸出資料夾
26
+ UPLOAD_FOLDER = os.path.join(app.root_path, "uploads")
27
+ OUTPUT_FOLDER = os.path.join(app.root_path, "outputs")
28
+ os.makedirs(UPLOAD_FOLDER, exist_ok=True)
29
+ os.makedirs(OUTPUT_FOLDER, exist_ok=True)
30
+
31
+ @app.route("/", methods=["GET", "POST"])
32
+ def index():
33
+ if request.method == "POST":
34
+ try:
35
+ file = request.files["image"]
36
+ img_path = os.path.join(UPLOAD_FOLDER, file.filename)
37
+ file.save(img_path)
38
+
39
+ # 推論 & 標註
40
+ results = model(img_path)
41
+ annotated = results[0].plot()
42
+
43
+ # 存檔
44
+ out_path = os.path.join(OUTPUT_FOLDER, file.filename)
45
+ cv2.imwrite(out_path, annotated)
46
+
47
+ print("DEBUG -> out_path:", out_path, "exists?", os.path.exists(out_path))
48
+
49
+ # 回傳
50
+ return send_from_directory(OUTPUT_FOLDER, file.filename, mimetype="image/jpeg")
51
+
52
+ except Exception as e:
53
+ app.logger.error("Detection error", exc_info=e)
54
+ return jsonify({"error": str(e)}), 500
55
+
56
+ # GET 時顯示頁面
57
+ return render_template("index.html")
58
+
59
+ if __name__ == "__main__":
60
+ # 讀取 Dockerfile 設定的環境變數 PORT
61
+ port = int(os.environ.get("PORT", 5000))
62
+ app.run(host="0.0.0.0", port=port, debug=True)
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ flask
2
+ ultralytics
3
+ opencv-python
4
+ gunicorn
5
+ huggingface-hub
static/preview.js ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const input = document.getElementById('image-input');
2
+ const preview = document.getElementById('preview');
3
+ const result = document.getElementById('result');
4
+ const form = document.getElementById('upload-form');
5
+
6
+ input.addEventListener('change', () => {
7
+ const file = input.files[0];
8
+ if (!file) return;
9
+ const reader = new FileReader();
10
+ reader.onload = e => {
11
+ preview.src = e.target.result;
12
+ preview.style.display = 'block';
13
+ };
14
+ reader.readAsDataURL(file);
15
+ });
16
+
17
+ // 表單送出後,顯示伺服器回傳的效果圖
18
+ form.addEventListener('submit', async e => {
19
+ e.preventDefault();
20
+ const formData = new FormData(form);
21
+
22
+ const resp = await fetch('/', {
23
+ method: 'POST',
24
+ body: formData
25
+ });
26
+ if (!resp.ok) {
27
+ alert('辨識失敗');
28
+ return;
29
+ }
30
+ const blob = await resp.blob();
31
+ result.src = URL.createObjectURL(blob);
32
+ result.style.display = 'block';
33
+ });
templates/.DS_Store ADDED
Binary file (6.15 kB). View file
 
templates/index.html ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="zh-Hant">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <title>台灣黑熊辨識 Demo</title>
6
+ </head>
7
+ <body>
8
+ <h1>台灣黑熊影像辨識</h1>
9
+
10
+ <form id="upload-form" method="POST" enctype="multipart/form-data">
11
+ <input type="file" id="image-input" name="image" accept="image/*" required />
12
+ <button type="submit">上傳並辨識</button>
13
+ </form>
14
+
15
+ <!-- 顯示上傳前預覽 -->
16
+ <div>
17
+ <h3>上傳預覽:</h3>
18
+ <img id="preview" src="#" style="max-width: 400px; display: none;" />
19
+ </div>
20
+
21
+ <!-- 顯示辨識後結果 -->
22
+ <div>
23
+ <h3>辨識結果:</h3>
24
+ <img id="result" src="#" style="max-width: 400px; display: none;" />
25
+ </div>
26
+
27
+ <script src="{{ url_for('static', filename='preview.js') }}"></script>
28
+ </body>
29
+ </html>