File size: 9,284 Bytes
df0d440
 
 
be16e3e
105430f
ed25dd4
b17860b
840bb85
c507cd4
d8ef608
2d3c414
df0d440
840bb85
105430f
0a8537c
d562d13
f66696f
df0d440
2d3c414
 
 
105430f
4acae3e
c2fcab3
161d980
e548086
f66696f
105430f
a7f0ae3
105430f
4acae3e
105430f
c2fcab3
105430f
 
16ac16b
 
f296b4f
4dd8b9b
7114c54
4acae3e
 
696f1ca
105430f
c2fcab3
105430f
3787a8c
4acae3e
105430f
9a98ec7
105430f
696f1ca
c2fcab3
3787a8c
e720316
be16e3e
df0d440
c507cd4
2d3c414
c507cd4
 
 
 
 
 
2d3c414
 
 
 
 
 
 
 
 
 
 
3787a8c
 
2d3c414
 
a49b159
 
 
 
 
 
 
 
 
4dd8b9b
 
 
 
a49b159
 
 
d562d13
 
df0d440
 
f66696f
 
df0d440
d562d13
df0d440
105430f
df0d440
 
c507cd4
6cbb81f
2d3c414
3787a8c
d8ef608
be16e3e
 
715f512
 
be16e3e
52063f0
 
 
 
 
43498e1
4dd8b9b
2b81936
 
4dd8b9b
2069c30
d562d13
43498e1
fb0868b
 
 
 
14c5f38
75856bb
3bf0eab
75856bb
 
83dfc8d
 
 
 
 
c507cd4
d8ef608
c507cd4
 
 
 
 
4dd8b9b
72231fb
079e149
c507cd4
2d3c414
3787a8c
c2fcab3
 
3787a8c
4dd8b9b
2beb357
83dfc8d
 
 
 
3787a8c
 
c2fcab3
4dd8b9b
f66696f
 
 
 
 
 
 
27d4de9
4dd8b9b
3787a8c
 
c2fcab3
 
3787a8c
c2fcab3
 
3787a8c
 
c2fcab3
 
2d3c414
d562d13
 
 
 
 
 
 
 
 
 
 
 
c2fcab3
 
 
 
 
2d3c414
4dd8b9b
2beb357
2d3c414
c2fcab3
2d3c414
c2fcab3
2b81936
2d3c414
52063f0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
df0d440
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0c120b4
 
be16e3e
 
0c120b4
 
df0d440
 
be16e3e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
import os
import time
import numpy as np
from PIL import Image
import torchvision.transforms as transforms
from pathlib import Path
from ultralytics import YOLO
import io
import base64
import uuid
import glob
from tensorflow import keras
from flask import Flask, jsonify, request, render_template, send_file
import torch
from collections import Counter
import psutil
from gradio_client import Client, handle_file

# Disable tensorflow warnings
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'

load_type = 'local'

MODEL_YOLO = "yolo11_detect_best_241024_1.pt"
MODEL_DIR = "./artifacts/models"
YOLO_DIR = "./artifacts/yolo"
GRADIO_URL = "https://50094cfbc694a82dea.gradio.live/"
#REPO_ID = "1vash/mnist_demo_model"

# Load the saved YOLO model into memory
if load_type == 'local':
    # 本地模型路徑
    model_path = f'{MODEL_DIR}/{MODEL_YOLO}'
    if not os.path.exists(model_path):
        raise FileNotFoundError(f"Model file not found at {model_path}")
        
    model = YOLO(model_path)

    print("***** 1. LOAD YOLO MODEL DONE *****")
    #model.eval()  # 設定模型為推理模式
elif load_type == 'remote_hub_download':
    from huggingface_hub import hf_hub_download

    # 從 Hugging Face Hub 下載模型
    model_path = hf_hub_download(repo_id=REPO_ID, filename=MODEL_YOLO)
    model = torch.load(model_path)
    #model.eval()
elif load_type == 'remote_hub_from_pretrained':
    # 使用 Hugging Face Hub 預訓練的模型方式下載
    os.environ['TRANSFORMERS_CACHE'] = str(Path(MODEL_DIR).absolute())
    from huggingface_hub import from_pretrained

    model = from_pretrained(REPO_ID, filename=MODEL_YOLO, cache_dir=MODEL_DIR)
    #model.eval()
else:
    raise AssertionError('No load type is specified!')


# image to base64
def image_to_base64(image_path):
    with open(image_path, "rb") as image_file:
        encoded_string = base64.b64encode(image_file.read()).decode('utf-8')
        return encoded_string


# 抓取指定路徑下的所有 JPG 檔案
def get_jpg_files(path):
  """
  Args:
    path: 要搜尋的目錄路徑。
  Returns:
    一個包含所有 JPG 檔案路徑的列表。
  """
  return glob.glob(os.path.join(path, "*.jpg"))

# 使用範例
# image_folder = '/content/drive/MyDrive/chiikawa'  # 替換成你的目錄路徑
# jpg_files = get_jpg_files(image_folder)


def check_memory_usage():
    # Get memory details
    memory_info = psutil.virtual_memory()
    
    total_memory = memory_info.total / (1024 * 1024)  # Convert bytes to MB
    available_memory = memory_info.available / (1024 * 1024)
    used_memory = memory_info.used / (1024 * 1024)
    memory_usage_percent = memory_info.percent
    
    print(f"^^^^^^ Total Memory: {total_memory:.2f} MB ^^^^^^")
    print(f"^^^^^^ Available Memory: {available_memory:.2f} MB ^^^^^^")
    print(f"^^^^^^ Used Memory: {used_memory:.2f} MB ^^^^^^")
    print(f"^^^^^^ Memory Usage (%): {memory_usage_percent}% ^^^^^^")

# Run the function
check_memory_usage()


# Initialize the Flask application
app = Flask(__name__)
# # Initialize the ClipModel at the start
# clip_model = ClipModel()



# API route for prediction(YOLO)
@app.route('/predict', methods=['POST'])
def predict():

    #user_id = request.args.get('user_id') 
    file = request.files['image']
    message_id = request.form.get('message_id') #str(uuid.uuid4())
    
    if 'image' not in request.files:
        # Handle if no file is selected
        return jsonify({"error": "No image part"}), 400
        #return 'No file selected'

    # 讀取圖像
    try:
        image_data = Image.open(file)
    except Exception as e:
        return jsonify({'error': str(e)}), 400
        
    print("***** 2. Start YOLO predict *****")
    # Make a prediction using YOLO
    results = model(image_data)
    print ("===== YOLO predict result:",results,"=====")
    print("***** YOLO predict DONE *****")
    
    check_memory_usage()
    
    # 檢查 YOLO 是否返回了有效的結果
    if results is None or len(results) == 0:
        return jsonify({'error': 'No results from YOLO model'}), 400

    saved_images = []
    
    # 儲存辨識後的圖片到指定資料夾
    for result in results:

        encoded_images=[]
        element_list =[]
        top_k_words =[]
        
        # 保存圖片
        result.save_crop(f"{YOLO_DIR}/{message_id}")
        
        num_detections = len(result.boxes)  # Get the number of detections
        labels = result.boxes.cls  # Get predicted label IDs
        label_names = [model.names[int(label)] for label in labels]  # Convert to names

        print(f"====== 3. YOLO label_names: {label_names}======")

        element_counts = Counter(label_names)

        for element, count in element_counts.items():
            
            yolo_path = f"{YOLO_DIR}/{message_id}/{element}"
            yolo_file = get_jpg_files(yolo_path)

            print(f"***** 處理:{yolo_path} *****")

            if len(yolo_file) == 0:
                print(f"警告:{element} 沒有找到相關的 JPG 檔案")
                continue

            element_list.append(element)
            
            for yolo_img in yolo_file: # 每張切圖yolo_img
                print("***** 4. START CLIP *****")
                client = Client(GRADIO_URL)
                clip_result = client.predict(
                    image=handle_file(yolo_img),
                    top_k=3,
                    api_name="/predict"
                )
                top_k_words.append(clip_result) # CLIP預測3個結果(top_k_words)
                #encoded_images.append(image_to_base64(yolo_img))
                print(f"===== CLIP result:{top_k_words} =====\n")

            # if element_counts[element] > 1: #某隻角色的數量>1
            #     yolo_path = f"{YOLO_DIR}/{message_id}/{element}"
            #     yolo_file = get_jpg_files(yolo_path)

            #     for yolo_img in yolo_file: # 取得每張圖的路徑
            #         encoded_images.append(image_to_base64(yolo_img))

            # else  : #某隻角色的數量=1
            #     yolo_path = f"{YOLO_DIR}/{message_id}/{element}/im.jpg.jpg"
            #     encoded_images.append(image_to_base64(yolo_path))
                
        ## 建立回應資料
        # response_data = {
        #     'message_id': message_id,
        #     'description': element_list,
        #     'images': [
        #         {
        #             'encoded_image': encoded_image,
        #             'description_list': top_k_words
        #         }
        #         for encoded_image, description_list in zip(encoded_images, top_k_words)
        #     ]
        # }
        # response_data = {
        #     'message_id': message_id,
        #     'images': encoded_images,
        #     'description': element_list
        # }
        
        return jsonify(top_k_words), 200 #jsonify(response_data)
            
        # for label_name in label_names:
        #     yolo_file=f"{YOLO_DIR}/{message_id}/{label_name}/im.jpg.jpg"
        #     # 將圖片轉換為 base64 編碼
        #     encoded_images.append(image_to_base64(yolo_file))

    
    # # dictionary is not a JSON: https://www.quora.com/What-is-the-difference-between-JSON-and-a-dictionary
    # # flask.jsonify vs json.dumps https://sentry.io/answers/difference-between-json-dumps-and-flask-jsonify/
    # # The flask.jsonify() function returns a Response object with Serializable JSON and content_type=application/json.
    # return jsonify(response)


# # Helper function to preprocess the image
# def preprocess_image(image_data):
#     """Preprocess image for YOLO Model Inference

#     :param image_data: Raw image (PIL.Image)
#     :return: image: Preprocessed Image (Tensor)
#     """
#     # Define the YOLO input size (example 640x640, you can modify this based on your model)
#     input_size = (640, 640)

#     # Define transformation: Resize the image, convert to Tensor, and normalize pixel values
#     transform = transforms.Compose([
#         transforms.Resize(input_size),       # Resize to YOLO input size
#         transforms.ToTensor(),               # Convert image to PyTorch Tensor (通道數、影像高度和寬度)
#         transforms.Normalize([0.0, 0.0, 0.0], [1.0, 1.0, 1.0])  # Normalization (if needed)
#     ])

#     # Apply transformations to the image
#     image = transform(image_data)

#     # Add batch dimension (1, C, H, W) since YOLO expects a batch
#     image = image.unsqueeze(0)

#     return image


# API route for health check
@app.route('/health', methods=['GET'])
def health():
    """
    Health check API to ensure the application is running.
    Returns "OK" if the application is healthy.
    Demo Usage: "curl http://localhost:5000/health" or using alias "curl http://127.0.0.1:5000/health"
    """
    return 'OK'


# API route for version
@app.route('/version', methods=['GET'])
def version():
    """
    Returns the version of the application.
    Demo Usage: "curl http://127.0.0.1:5000/version" or using alias "curl http://127.0.0.1:5000/version"
    """
    return '1.0'


@app.route("/")
def hello_world():
    return render_template("index.html")
    # return "<p>Hello, Team!</p>"


# Start the Flask application
if __name__ == '__main__':
    app.run(debug=True)