Pārlūkot izejas kodu

Merge branch 'dev' of http://gogs.seec.seecoder.cn/ZhaoFengShan/PoseCorrection into dev

Bob Huang 3 gadi atpakaļ
vecāks
revīzija
c37a081faf

+ 14 - 2
backend_refactor/app.py

@@ -1,12 +1,13 @@
 import logging
+import os
 
-from flask import Flask
+from flask import Flask, send_from_directory
 from flask_cors import CORS
 
 import route.analyze
 import route.result
 import route.upload
-from config import VERSION_PREFIX, MAX_CONTENT_LENGTH, MYSQL_URI
+from config import VERSION_PREFIX, MAX_CONTENT_LENGTH, MYSQL_URI, UPLOAD_DIR
 from db import db
 from route.util import make_response
 from pool.thread_pool import init_workers
@@ -31,11 +32,22 @@ with app.app_context():
 
 init_workers()
 
+try:
+    os.mkdir(UPLOAD_DIR + "/result")
+except:
+    pass
+
+
 @app.route("/")
 def hello_world():
     return "<p>Hello, World!</p>"
 
 
+@app.route("/file/<path:name>")
+def download_file(name):
+    return send_from_directory(UPLOAD_DIR + '/result/', name)
+
+
 @app.errorhandler(413)
 def error_handler(e):
     logging.exception(e)

+ 1 - 0
backend_refactor/config/__init__.py

@@ -3,5 +3,6 @@ import os
 VERSION_PREFIX = "/v1/"
 UPLOAD_DIR = "/data/"
 MAX_CONTENT_LENGTH = 100 * 1024 * 1024
+FILE_URL = "http://106.15.1.178:8090/file/"
 
 MYSQL_URI = f'mysql://{os.environ["MYSQL_USER"]}:{os.environ["MYSQL_PASSWORD"]}@{os.environ["MYSQL_ADDRESS"]}/{os.environ["MYSQL_DATABASE"]}'

+ 1 - 1
backend_refactor/pool/thread_pool.py

@@ -22,4 +22,4 @@ class Pool:
 	def submit(job, callback):
 		q.put((job, callback))
 
-pool = Pool()
+pool = Pool()

+ 12 - 12
backend_refactor/service/ai/video/classify/jump.py

@@ -12,40 +12,40 @@ def classify_jump(re):
         ret = ret + "The movement process is terrible and needs to be improved. "
 
     if re["1"]["is_prepared"]:
-        if float(re["1"]["first_score"]) > 85:
+        if float(re["1"]["score"]) > 85:
             ret = ret + "Your upper and lower body movements are coordinated, and the setup position is perfect. "
-        elif float(re["1"]["first_score"]) > 75:
+        elif float(re["1"]["score"]) > 75:
             ret = ret + "Your upper and lower body movements are coordinated, but the setup position is not standard enough. "
-        elif float(re["1"]["first_score"]) > 65:
+        elif float(re["1"]["score"]) > 65:
             ret = ret + "The setup position is not standard enough. Take more practice."
         else:
             ret = ret + "The setup position is far from standard, see some relevant video to correct posture."
     else:
         ret = ret + "Lack the setup position. "
 
-    if float(re["2"]["second_score"]) > 85:
+    if float(re["2"]["score"]) > 85:
         ret = ret + "The upper part of the body is slightly forward, and the push is fast and powerful. "
-    elif float(re["2"]["second_score"]) > 75:
+    elif float(re["2"]["score"]) > 75:
         ret = ret + "The upper part of the body is slightly forward, and the push is fast and powerful. "
-    elif float(re["2"]["second_score"]) > 65:
+    elif float(re["2"]["score"]) > 65:
         ret = ret + "There is no front drive on the upper body, and the push is fast and powerful. "
     else:
         ret = ret + "The upper body has no front drive, and the push-off is not fast and powerful. "
 
-    if float(re["3"]["third_score"]) > 85:
+    if float(re["3"]["score"]) > 85:
         ret = ret + "The pedal and the hand swing are very harmonious. "
-    elif float(re["3"]["third_score"]) > 75:
+    elif float(re["3"]["score"]) > 75:
         ret = ret + "Pedal and hand swing are not in harmony. "
-    elif float(re["3"]["third_score"]) > 65:
+    elif float(re["3"]["score"]) > 65:
         ret = ret + "Foot pedal and hand swing are not coordinated. "
     else:
         ret = ret + "Foot pedal and hand swing are not coordinated. "
 
-    if float(re["4"]["forth_score"]) > 80:
+    if float(re["4"]["score"]) > 80:
         ret = ret + "The air stretch is full.  "
-    elif float(re["4"]["forth_score"]) > 70:
+    elif float(re["4"]["score"]) > 70:
         ret = ret + "The air stretch is not sufficient. "
-    elif float(re["4"]["forth_score"]) > 60:
+    elif float(re["4"]["score"]) > 60:
         ret = ret + "The air stretch is insufficient. "
     else:
         ret = ret + "There is no stretch in the air. "

+ 6 - 6
backend_refactor/service/ai/video/classify/jumpwithboth.py

@@ -9,20 +9,20 @@ def classify_jumpwithboth(re):
     else:
         ret = ret + "The movement process is terrible and needs to be improved. "
 
-    if float(re["1"]["first_score"]) > 85:
+    if float(re["1"]["score"]) > 85:
         ret = ret + "You did the good jump in the air.  "
-    elif float(re["1"]["first_score"]) > 75:
+    elif float(re["1"]["score"]) > 75:
         ret = ret + "Your jumping in the air is not up to standard. "
-    elif float(re["1"]["first_score"]) > 60:
+    elif float(re["1"]["score"]) > 60:
         ret = ret + "Your jumping in the air needs a lot of improvement. "
     else:
         ret = ret + "Your jumping in the air is far from standard, see some relevant video to correct posture. "
 
-    if float(re["2"]["second_score"]) > 85:
+    if float(re["2"]["score"]) > 85:
         ret = ret + "You did the good landing action.  "
-    elif float(re["2"]["second_score"]) > 75:
+    elif float(re["2"]["score"]) > 75:
         ret = ret + "Your landing action is not up to standard. "
-    elif float(re["2"]["second_score"]) > 60:
+    elif float(re["2"]["score"]) > 60:
         ret = ret + "Your landing action needs a lot of improvement. "
     else:
         ret = ret + "Your landing action is far from standard, see some relevant video to correct posture. "

+ 7 - 7
backend_refactor/service/ai/video/classify/pingban.py

@@ -9,24 +9,24 @@ def classify_pingban(re):
     else:
         ret = ret + "The movement process is terrible and needs to be improved. "
 
-    if re["1"]["no_first_posture"] == "true":
+    if not re["1"]["is_prepared"]:
         ret = ret + "Lack the setup position. "
     else:
-        if float(re["1"]["first_score"]) > 80:
+        if float(re["1"]["score"]) > 80:
             ret = ret + "The setup position is good. "
-        elif float(re["1"]["first_score"]) > 70:
+        elif float(re["1"]["score"]) > 70:
             ret = ret + "The setup position is not bad. "
-        elif float(re["1"]["first_score"]) > 60:
+        elif float(re["1"]["score"]) > 60:
             ret = ret + "The setup position is not standard enough. Take more practice."
         else:
             ret = ret + "The setup position is far from standard, see some relevant video to correct posture."
 
     if float(re["2"]["elbow_right_angle"]) > 120 or float(re["2"]["elbow_left_angle"]) > 120:
-        if float(re["2"]["second_score"]) > 84:
+        if float(re["2"]["score"]) > 84:
             ret = ret + "The core strength is good. "
-        elif float(re["2"]["second_score"]) > 75:
+        elif float(re["2"]["score"]) > 75:
             ret = ret + "The core strength is not bad. "
-        elif float(re["2"]["second_score"]) > 65:
+        elif float(re["2"]["score"]) > 65:
             ret = ret + "Need to do more to promote the core strength. "
         else:
             ret = ret + "The core strength need to be improved. "

+ 6 - 6
backend_refactor/service/ai/video/classify/tennisthrow.py

@@ -9,11 +9,11 @@ def classify_tennisthrow(re):
     else:
         ret = ret + "The movement process is terrible and needs to be improved. "
 
-    if float(re["1"]["first_score"]) > 85:
+    if float(re["1"]["score"]) > 85:
         ret = ret + "The setup position is good. "
-    elif float(re["1"]["first_score"]) > 75:
+    elif float(re["1"]["score"]) > 75:
         ret = ret + "The setup position is not bad. "
-    elif float(re["1"]["first_score"]) > 65:
+    elif float(re["1"]["score"]) > 65:
         ret = ret + "The setup position is not standard enough. Take more practice. "
     else:
         ret = ret + "The setup position is far from standard, see some relevant video to correct posture. "
@@ -23,11 +23,11 @@ def classify_tennisthrow(re):
     else:
         ret = ret + "Your knees are not bent in place and need some improvement. "
 
-    if float(re["2"]["second_score"])>85:
+    if float(re["2"]["score"]) > 85:
         ret = ret + "When you throw the tennis ball, your action is standard. "
-    elif float(re["2"]["second_score"])>75:
+    elif float(re["2"]["score"]) > 75:
         ret = ret + "You don't throw the tennis ball very well. "
-    elif float(re["2"]["second_score"])>65:
+    elif float(re["2"]["score"]) > 65:
         ret = ret + "You need to improve your motion when you throw the tennis ball. "
     else:
         ret = ret + "When you throw the tennis ball, your action is far from standard, see some relevant video to correct posture. "

+ 6 - 6
backend_refactor/service/ai/video/classify/turnaround.py

@@ -12,20 +12,20 @@ def classify_turnaround(re):
         ret = ret + "Pay attention to arm bending during running. "
     else:
         ret = ret + "Not bad arm posture during the run. "
-    if float(re["1"]["first_score"]) > 85:
+    if float(re["1"]["score"]) > 85:
         ret = ret + "The leg muscle is good. "
-    elif float(re["1"]["first_score"]) > 75:
+    elif float(re["1"]["score"]) > 75:
         ret = ret + "The leg muscle is not bad, but still need to do more practise. "
-    elif float(re["1"]["first_score"]) > 60:
+    elif float(re["1"]["score"]) > 60:
         ret = ret + "Need to do more to promote leg muscle strength. "
     else:
         ret = ret + "The leg muscle is weak and the position needs to be improved. "
 
-    if float(re["2"]["second_score"]) > 88:
+    if float(re["2"]["score"]) > 88:
         ret = ret + "Your movements when you touch the obstacles are very standard. "
-    elif float(re["2"]["second_score"]) > 78:
+    elif float(re["2"]["score"]) > 78:
         ret = ret + "The action when you touch the obstacle is not very standard. "
-    elif float(re["2"]["second_score"]) > 65:
+    elif float(re["2"]["score"]) > 65:
         ret = ret + "The way you touch the obstacles needs a lot of improvement. "
     else:
         ret = ret + "You may have questions about what to do when you touch an obstacle, see some relevant video to correct posture."

+ 12 - 11
backend_refactor/service/ai/video/inner_analyze.py

@@ -1,4 +1,5 @@
 import math
+import logging
 
 
 def angle(v1, v2):
@@ -54,11 +55,11 @@ def cal_angle(point_a, point_b, point_c):
 
 def analyse_npy_side_juanfu(data):
     result = {}
-    data = data[0]
 
-    # if len(data) != 25:
-    #     logging.warning("Data len is not 25, skipping.")
-    #     return
+    # if len(data) == 0:
+    #     #     logging.warning("Data len is not 25, skipping.")
+    #     return False
+    data = data[0]
 
     nose_x = data[0][0]
     nose_y = data[0][1]
@@ -134,11 +135,11 @@ def analyse_npy_side_gaotaitui(data):
 
 def analyse_npy_side_shendun(data):
     result = {}
-    data = data[0]
 
-    # if len(data) != 25:
-    #     logging.warning("Data len is not 25, skipping.")
-    #     return
+    # if len(data) == 0:
+    #     #     logging.warning("Data len is not 25, skipping.")
+    #     return False
+    data = data[0]
 
     hip_r_x = data[9][0]
     hip_r_y = data[9][1]
@@ -179,9 +180,9 @@ def analyse_npy_side_shendun(data):
 
 def analyse_npy_side_jump(data):
     result = {}
-    # if len(data) != 25:
-    #     logging.warning("Data len is not 25, skipping.")
-    #     return
+    if not data:
+        #     # logging.warning("Data len is not 25, skipping.")
+        return result
 
     data = data[0]
 

+ 6 - 4
backend_refactor/service/ai/video/video_score/balancebeam.py

@@ -37,8 +37,10 @@ def cal_second_score(list):
                 item["elbow_left_angle"]) == 0 or float(item["neck_left_angle"]) == 0:
             num = num - 1
         else:
-            score = cal_ratio(item["neck_right_angle"], 90) * 30 + cal_ratio(item["neck_left_angle"], 90) * 30 + cal_ratio(item["elbow_right_angle"],
-                                                                               180) * 20 + cal_ratio(
+            score = cal_ratio(item["neck_right_angle"], 90) * 30 + cal_ratio(item["neck_left_angle"],
+                                                                             90) * 30 + cal_ratio(
+                item["elbow_right_angle"],
+                180) * 20 + cal_ratio(
                 item["elbow_left_angle"],
                 180) * 20
             sum_score = sum_score + score
@@ -53,7 +55,7 @@ def cal_balancebeam(result):
 
     satisfied_pics = []
     highest_wrist = 1000
-    highest_wrist_index = 0
+    highest_wrist_index = list(result.keys())[0]
     begin_index = 0
     finish_index = 0
     is_begin = False
@@ -80,7 +82,7 @@ def cal_balancebeam(result):
     re["1"]["number_of_satisfied"] = len(satisfied_pics)
     re["1"]["begin_index"] = begin_index
     re["1"]["finish_index"] = finish_index
-    re["1"]["highest_wrist_index"] = highest_wrist_index
+    re["1"]["index"] = highest_wrist_index
     re["1"]["total_score"] = round(total_score, 2)
     print("finish capturing postures and calculating scores")
     print("result-----------")

+ 14 - 14
backend_refactor/service/ai/video/video_score/jump.py

@@ -46,7 +46,7 @@ def cal_jump(result):
     # first socre
     min_wrist_height = float(result[list(result.keys())[0]]["wrist_heigh"])
     min_hip_angle = float(result[list(result.keys())[0]]["hip_right_angle"])
-    min_wrist_index = 0
+    min_wrist_index = list(result.keys())[0]
     for index in result:
         if float(result[index]["leg_heigh"]) >= initial_ankle_height - 3:
             if float(result[index]["hip_right_angle"]) <= min_hip_angle and float(
@@ -83,8 +83,8 @@ def cal_jump(result):
         float(result_ig[min_wrist_index]["ankle_left_angle"]), 90) * 10), 2)
 
     re["1"] = result_ig[min_wrist_index]
-    re["1"]["first_score"] = round(first_score, 2)
-    re["1"]["first_score_index"] = min_wrist_index
+    re["1"]["score"] = round(first_score, 2)
+    re["1"]["index"] = min_wrist_index
     re["1"]["is_prepared"] = is_prepared
     # second socre
     result_ig = is_zero(result_ig, min_hip_angle_index)
@@ -96,12 +96,12 @@ def cal_jump(result):
                           cal_ratio(float(result_ig[min_hip_angle_index][
                                               "ankle_left_angle"]), 85) * 10), 2)
     re["2"] = result_ig[min_hip_angle_index]
-    re["2"]["second_score"] = round(second_score, 2)
-    re["2"]["second_score_index"] = min_hip_angle_index
+    re["2"]["score"] = round(second_score, 2)
+    re["2"]["index"] = min_hip_angle_index
     # third score
     max_hip_angle = float(result[min_hip_angle_index]["knee_right_angle"])
-    max_hip_index = "1"
-    highest_ankle_index = "1"
+    max_hip_index = list(result.keys())[0]
+    highest_ankle_index = list(result.keys())[0]
     min_ankle_height = initial_ankle_height
     for index in result:
         if float(index) > float(leave_index):
@@ -124,8 +124,8 @@ def cal_jump(result):
         result_ig[max_hip_index]["ankle_left_angle"], 165) * 20
 
     re["3"] = result_ig[max_hip_index]
-    re["3"]["third_score"] = round(third_score, 2)
-    re["3"]["third_score_index"] = max_hip_index
+    re["3"]["score"] = round(third_score, 2)
+    re["3"]["index"] = max_hip_index
     # forth score
     result_ig = is_zero(result_ig, highest_ankle_index)
     forth_score = cal_ratio(result_ig[highest_ankle_index]["hip_right_angle"], 180) * 25 + cal_ratio(
@@ -134,11 +134,11 @@ def cal_jump(result):
         result_ig[highest_ankle_index]["knee_left_angle"], 55) * 25
 
     re["4"] = result_ig[highest_ankle_index]
-    re["4"]["forth_score"] = round(forth_score, 2)
-    re["4"]["forth_score_index"] = highest_ankle_index
+    re["4"]["score"] = round(forth_score, 2)
+    re["4"]["index"] = highest_ankle_index
     # fifth score
     lowest_ankle_height = float(result[reland_index]["leg_heigh"])
-    lowest_ankle_index = "1"
+    lowest_ankle_index = list(result.keys())[0]
     for index in result:
         if int(index) <= int(highest_ankle_index):
             continue
@@ -158,8 +158,8 @@ def cal_jump(result):
         result_ig[lowest_ankle_index]["ankle_left_angle"], 90) * 10
 
     re["5"] = result_ig[lowest_ankle_index]
-    re["5"]["fifth_score"] = round(fifth_score, 2)
-    re["5"]["fifth_score_index"] = lowest_ankle_index
+    re["5"]["score"] = round(fifth_score, 2)
+    re["5"]["index"] = lowest_ankle_index
     if is_prepared:
         re["5"]["total_score"] = round(
             0.1 * first_score + 0.2 * second_score + 0.3 * third_score + 0.3 * forth_score + 0.1 * fifth_score, 2)

+ 5 - 5
backend_refactor/service/ai/video/video_score/jumpwithboth.py

@@ -70,7 +70,7 @@ def cal_jumpwithboth(result):
     result_ig = result
     re = {}
     highest_ankle = 10000
-    highest_ankle_index = 0
+    highest_ankle_index = list(result.keys())[0]
 
     for index in result:
         if float(result[index]["leg_heigh"]) < float(highest_ankle) and float(
@@ -82,8 +82,8 @@ def cal_jumpwithboth(result):
     first_score = cal_average_score([result_ig[highest_ankle_index]], 1)
     re["1"] = result_ig[highest_ankle_index]
     re["1"]["highest_ankle"] = highest_ankle
-    re["1"]["highest_ankle_index"] = highest_ankle_index
-    re["1"]["first_score"] = first_score
+    re["1"]["index"] = highest_ankle_index
+    re["1"]["score"] = first_score
 
     # second score
     reload_pics_index = []
@@ -100,8 +100,8 @@ def cal_jumpwithboth(result):
     second_score = cal_average_score(reload_pics, 2)
     re["2"] = result_ig[reload_pics_index[0]]
     re["2"]["number_of_satisfied"] = len(reload_pics)
-    re["2"]["index_of_satisfied"] = reload_pics_index
-    re["2"]["second_score"] = second_score
+    re["2"]["index"] = reload_pics_index
+    re["2"]["score"] = second_score
     re["2"]["total_score"] = round(0.6 * first_score + 0.4 * second_score, 2)
     print("finish capturing postures and calculating scores")
     print("result-----------")

+ 20 - 10
backend_refactor/service/ai/video/video_score/pingban.py

@@ -1,3 +1,6 @@
+import logging
+
+
 def cal_ratio(measured_angle, max_angle):
     num1 = float(measured_angle)
     num2 = float(max_angle)
@@ -55,10 +58,12 @@ def cal_pingban(result):
     # whether it has prepared posture
     is_prepared = False
     for index in result:
+        if len(result[index]) == 0:
+            continue
         if float(result[index]["knee_right_angle"]) < 100 and float(result[index]["knee_left_angle"]) < 100:
             is_prepared = True
     # prepared posture: when knee at its lowest,number is highest
-    first_index = "1"
+    first_index = list(result.keys())[0]
     first_score = 0
     if is_prepared:
         lowest_knee = float(result_ig[list(result.keys())[0]]["knee_heigh"])
@@ -73,14 +78,15 @@ def cal_pingban(result):
                                                                            180) * 20 + cal_ratio(
             result_ig[first_index]["elbow_left_angle"], 180) * 20
         re["1"] = result_ig[first_index]
-        re["1"]["first_score"] = round(first_score, 2)
-        re["1"]["first_index"] = first_index
+        re["1"]["score"] = round(first_score, 2)
+        re["1"]["index"] = first_index
+        re["1"]["is_prepared"] = True
     else:
         re["1"] = result_ig[list(result.keys())[0]]
-        re["1"]["no_first_posture"] = "true"
+        re["1"]["is_prepared"] = False
     # second posture
     max_knee_angle = float(result_ig[list(result.keys())[0]]["hip_right_angle"])
-    max_knee_angle_index = "1"
+    max_knee_angle_index = list(result.keys())[0]
     second_pics = []
     satisfied_index = []
     for index in result:
@@ -91,17 +97,21 @@ def cal_pingban(result):
                 result_ig = is_zero(result_ig, index)
                 satisfied_index.append(index)
                 second_pics.append(result_ig[index])
-                if float(result[index]["hip_right_angle"]) > float(max_knee_angle):
-                    max_knee_angle = result[index]["hip_right_angle"]
-                    max_knee_angle_index = index
+            if float(result[index]["hip_right_angle"]) > float(max_knee_angle):
+                max_knee_angle = result[index]["hip_right_angle"]
+                max_knee_angle_index = index
+    if len(satisfied_index) == 0:
+        result_ig = is_zero(result_ig, max_knee_angle_index)
+        satisfied_index.append(max_knee_angle_index)
+        second_pics.append(result_ig[max_knee_angle_index])
     pingban_2_score = cal_second_score(second_pics)
     total_score = pingban_2_score
     if first_score != 0:
         total_score = round(0.05 * first_score + 0.95 * pingban_2_score, 2)
     re["2"] = result_ig[max_knee_angle_index]
     re["2"]["number_of_satisfied"] = len(second_pics)
-    re["2"]["satisfied_index"] = satisfied_index
-    re["2"]["second_score"] = round(pingban_2_score, 2)
+    re["2"]["index"] = satisfied_index
+    re["2"]["score"] = round(pingban_2_score, 2)
     re["2"]["max_knee_angle"] = max_knee_angle
     re["2"]["max_knee_angle_index"] = max_knee_angle_index
     re["2"]["total_score"] = round(total_score, 2)

+ 2 - 2
backend_refactor/service/ai/video/video_score/sitforward.py

@@ -35,7 +35,7 @@ def cal_sitforward(result):
     result_ig = result
     re = {}
     highest_wrist_x = result[list(result.keys())[0]]["wrist_x"]
-    highest_weist_index = 0
+    highest_weist_index = list(result.keys())[0]
 
     for index in result:
         if float(result[index]["wrist_x"]) < float(highest_wrist_x) and float(result[index]["wrist_x"]) != 0:
@@ -51,7 +51,7 @@ def cal_sitforward(result):
 
     re["1"] = result[highest_weist_index]
     re["1"]["highest_wrist_x"] = highest_wrist_x
-    re["1"]["highest_weist_index"] = highest_weist_index
+    re["1"]["index"] = highest_weist_index
     re["1"]["total_score"] = total_score
     print("finish capturing postures and calculating scores")
     print("result-----------")

+ 3 - 3
backend_refactor/service/ai/video/video_score/standing.py

@@ -61,13 +61,13 @@ def cal_standing(result):
     result_ig = result
     re = {}
     mode = "knee_left_angle"
-    begin_index = 0
+    begin_index = list(result.keys())[0]
     finish_index = 0
     highest_ankle_index = 0
     highest_ankle = 1000
     satisfied_pics = []
     minest_knee_angle = 180
-    minest_knee_angle_index = 0
+    minest_knee_angle_index = list(result.keys())[0]
 
     for index in result:
         if float(result[index]["knee_right_angle"]) < 165:
@@ -98,7 +98,7 @@ def cal_standing(result):
     re["1"] = result[minest_knee_angle_index]
     re["1"]["mode"] = mode
     re["1"]["minest_knee_angle"] = minest_knee_angle
-    re["1"]["minest_knee_angle_index"] = minest_knee_angle_index
+    re["1"]["index"] = minest_knee_angle_index
     re["1"]["total_score"] = minest_knee_score
 
     # re["1"]["begin_index"] = begin_index

+ 5 - 5
backend_refactor/service/ai/video/video_score/tennisthrow.py

@@ -95,7 +95,7 @@ def cal_tennisthrow(result):
     result_ig = is_zero(result_ig, highest_wrist_index)
     third_score = cal_average_score(result_ig[highest_wrist_index], hand, 3)
     # first score
-    farrest_distance_index = 0
+    farrest_distance_index = list(result.keys())[0]
     farrest_distance = 0
     for index in result:
         if float(index) < float(highest_wrist_index):
@@ -115,14 +115,14 @@ def cal_tennisthrow(result):
     result_ig = is_zero(result_ig, farrest_distance_index)
     first_score = cal_average_score(result_ig[farrest_distance_index], hand, 1)
     re["1"] = result_ig[farrest_distance_index]
-    re["1"]["farrest_distance_index"] = farrest_distance_index
+    re["1"]["index"] = farrest_distance_index
     re["1"]["farrest_distance"] = farrest_distance
-    re["1"]["first_score"] = first_score
+    re["1"]["score"] = first_score
 
     re["2"] = result_ig[highest_wrist_index]
-    re["2"]["highest_wrist_index"] = highest_wrist_index
+    re["2"]["index"] = highest_wrist_index
     re["2"]["highest_wrist"] = highest_wrist
-    re["2"]["second_score"] = third_score
+    re["2"]["score"] = third_score
     re["2"]["total_score"] = round(first_score * 0.3 + third_score * 0.7, 2)
 
     print("finish capturing postures and calculating scores")

+ 15 - 11
backend_refactor/service/ai/video/video_score/turnaround.py

@@ -52,9 +52,9 @@ def cal_average_score(list, mode):
         if mode == 1:
             is_clean = check_elbow(item)
             if (is_clean):
-                if abs(float(item["ankle_right_angle"])-float(item["ankle_left_angle"]))>60:
-                    if abs(float(item["ankle_right_angle"])-110)>abs(float(item["ankle_left_angle"])-110):
-                        item["ankle_right_angle"]=item["ankle_left_angle"]
+                if abs(float(item["ankle_right_angle"]) - float(item["ankle_left_angle"])) > 60:
+                    if abs(float(item["ankle_right_angle"]) - 110) > abs(float(item["ankle_left_angle"]) - 110):
+                        item["ankle_right_angle"] = item["ankle_left_angle"]
                         score = cal_ratio(item["elbow_right_angle"], 95) * 20 + cal_ratio(item["elbow_left_angle"],
                                                                                           95) * 20 + cal_ratio(
                             item["ankle_left_angle"],
@@ -101,7 +101,7 @@ def cal_turnaround(result):
     re = {}
     satisfied_pics = []
     max_distance = 0
-    max_distance_index = 0
+    max_distance_index = list(result.keys())[0]
     key_index = 0
     satisfied_index = []
     for index in result:
@@ -114,17 +114,21 @@ def cal_turnaround(result):
             result_ig = is_zero(result_ig, index)
             satisfied_index.append(index)
             satisfied_pics.append(result_ig[index])
-        # if float(result[index]["foot_distance"]) > float(max_distance):
-        #     max_distance = result[index]["foot_distance"]
-        #     max_distance_index = index
+        if float(result[index]["foot_distance"]) > float(max_distance):
+            max_distance = result[index]["foot_distance"]
+            max_distance_index = index
         key_index += 1
+    if len(satisfied_index) == 0:
+        result_ig = is_zero(result_ig, max_distance_index)
+        satisfied_index.append(max_distance_index)
+        satisfied_pics.append(result_ig[max_distance_index])
     first_score = cal_average_score(satisfied_pics, 1)
     re["1"] = result_ig[satisfied_index[0]]
     # re["1"]["max_distance"] = max_distance
     # re["1"]["max_distance_index"] = max_distance_index
-    re["1"]["satisfied_index"] = satisfied_index
+    re["1"]["index"] = satisfied_index
     re["1"]["number_of_satisfied"] = len(satisfied_pics)
-    re["1"]["first_score"] = first_score
+    re["1"]["score"] = first_score
 
     # second score
     lowest_midhip = 0
@@ -140,8 +144,8 @@ def cal_turnaround(result):
 
     re["2"] = result_ig[lowest_midhip_index]
     re["2"]["lowest_midhip"] = lowest_midhip
-    re["2"]["lowest_midhip_index"] = lowest_midhip_index
-    re["2"]["second_score"] = second_score
+    re["2"]["index"] = lowest_midhip_index
+    re["2"]["score"] = second_score
     re["2"]["total_score"] = round(0.7 * first_score + 0.3 * second_score, 2)
     print("finish capturing postures and calculating scores")
     print("result-----------")

+ 6 - 5
backend_refactor/service/photo_analyzer.py

@@ -3,7 +3,7 @@ from typing import Callable
 
 import cv2
 
-from config import UPLOAD_DIR
+from config import UPLOAD_DIR, FILE_URL
 from service.ai.photo.standing_photo import *
 from service.ai.util.torch_openpose import torch_openpose
 from service.ai.util.util import draw_bodypose
@@ -25,7 +25,7 @@ class StandingPhotoAnalyzer(BasePhotoAnalyzer):
 
     def analyze(self, callback: Callable) -> None:
         try:
-            callback("RUNNING",progress=0)
+            callback("RUNNING", progress=0)
             photos = []
             npys = []
 
@@ -45,10 +45,11 @@ class StandingPhotoAnalyzer(BasePhotoAnalyzer):
                 canvas = copy.deepcopy(ori_img)
                 canvas = draw_bodypose(canvas, poses, 'body_25')
 
-                cv2.imwrite(UPLOAD_DIR + '{}.result.jpg'.format(i), canvas)
-                photos.append(UPLOAD_DIR + '{}.result.jpg'.format(i))
+                cv2.imwrite(UPLOAD_DIR + 'result/{}.result.jpg'.format(i), canvas)
+                photos.append(FILE_URL + '{}.result.jpg'.format(i))
 
-            callback("FINISHED", result={"analysis": {"advice": {"front": npys[0], "right": npys[1]}}})
+            callback("FINISHED", result={"data": {"front": {"file": photos[0]}, "right": {"file": photos[1]}},
+                                         "advice": {"front": npys[0], "right": npys[1]}})
         except Exception as e:
             callback("ERROR", error=e)
             raise e

+ 32 - 20
backend_refactor/service/video_analyzer.py

@@ -5,20 +5,20 @@ from typing import Callable
 
 import cv2
 
-from config import UPLOAD_DIR
+from config import UPLOAD_DIR, FILE_URL
 from service.ai.util.torch_openpose import torch_openpose
 from service.ai.util.util import draw_bodypose
+from service.ai.video.classify.balancebeam import classify_balancebeam
 from service.ai.video.classify.gaotaitui import classify_gaotaitui
 from service.ai.video.classify.juanfu import classify_juanfu
-from service.ai.video.classify.shendun import classify_shendun
-from service.ai.video.classify.turnaround import classify_turnaround
-from service.ai.video.classify.standing import classify_standing
-from service.ai.video.classify.pingban import classify_pingban
-from service.ai.video.classify.balancebeam import classify_balancebeam
 from service.ai.video.classify.jump import classify_jump
 from service.ai.video.classify.jumpwithboth import classify_jumpwithboth
+from service.ai.video.classify.pingban import classify_pingban
+from service.ai.video.classify.shendun import classify_shendun
 from service.ai.video.classify.sitforward import classify_sitforward
+from service.ai.video.classify.standing import classify_standing
 from service.ai.video.classify.tennisthrow import classify_tennisthrow
+from service.ai.video.classify.turnaround import classify_turnaround
 from service.ai.video.inner_analyze import analyse_npy_side_jump, analyse_npy_side_juanfu, analyse_npy_side_shendun, \
     analyse_npy_side_gaotaitui
 from service.ai.video.video_score.balancebeam import cal_balancebeam
@@ -61,14 +61,16 @@ def run_openpose_for_npy_and_video(video_uuid, callback: Callable):
                 results[str(c)] = poses  # this is evil, but the AI code expect it to be so.
 
                 canvas = draw_bodypose(frame, poses, 'body_25')
+                cv2.imwrite(UPLOAD_DIR + "result/" + video_uuid + "." + str(c) + ".jpg", canvas)
 
                 if out is None:
-                    out = cv2.VideoWriter(UPLOAD_DIR + video_uuid + ".result.mp4", cv2.VideoWriter_fourcc(*"mp4v"), FPS,
+                    out = cv2.VideoWriter(UPLOAD_DIR + "result/" + video_uuid + ".result.mp4",
+                                          cv2.VideoWriter_fourcc(*"vp90"), FPS,
                                           (canvas.shape[1], canvas.shape[0]))  # So fucking stupid
                 out.write(canvas)
 
             c += 1
-            callback("RUNNING", progress=min(99,int(100*c/(total_frames/sampling_fps))))
+            callback("RUNNING", progress=min(99, int(100 * c / (total_frames / sampling_fps))))
         else:
             break
 
@@ -98,7 +100,15 @@ class BaseVideoAnalyzer:
             else:  # read cache
                 self.results = pickle.load(open(PICKLE_DUMP_PATH, "rb"))
 
-            callback("FINISHED", result=self._do_analyze())
+            result = {**self._do_analyze(), "file": FILE_URL + self.video_uuid + ".result.mp4"}
+            # inject file url here
+            try:
+                for i in result['data']:
+                    result['data'][i]['file'] = FILE_URL + self.video_uuid + "." + result['data'][i]['index'] + ".jpg"
+            except Exception as e:
+                logging.warning("file index in data not found, %s" % e)
+
+            callback("FINISHED", result=result)
         except Exception as e:
             callback("ERROR", error=e)
             raise e
@@ -107,75 +117,77 @@ class BaseVideoAnalyzer:
 class JumpVideoAnalyzer(BaseVideoAnalyzer):
     def _do_analyze(self):
         self.results = {k: analyse_npy_side_jump(v) for k, v in self.results.items()}
+        self.results = {k: v for k, v in self.results.items() if v != {}}
         raw = cal_jump(self.results)[1]
-        return {"raw": raw, "analysis": classify_jump(raw)}
+        return classify_jump(raw)
 
 
 class PingbanVideoAnalyzer(BaseVideoAnalyzer):
     def _do_analyze(self):
         self.results = {k: analyse_npy_side_jump(v) for k, v in self.results.items()}
+        self.results = {k: v for k, v in self.results.items() if v != {}}
         raw = cal_pingban(self.results)[1]
-        return {"raw": raw, "analysis": classify_pingban(raw)}
+        return classify_pingban(raw)
 
 
 class JuanfuVideoAnalyzer(BaseVideoAnalyzer):
     def _do_analyze(self):
         self.results = {k: analyse_npy_side_juanfu(v) for k, v in self.results.items()}
         raw = ignore_data_juanfu(self.results)[1]
-        return {"raw": raw, "analysis": classify_juanfu(raw)}
+        return classify_juanfu(raw)
 
 
 class ShendunVideoAnalyzer(BaseVideoAnalyzer):
     def _do_analyze(self):
         self.results = {k: analyse_npy_side_shendun(v) for k, v in self.results.items()}
         raw = ignore_data_shendun(self.results)[1]
-        return {"raw": raw, "analysis": classify_shendun(raw)}
+        return classify_shendun(raw)
 
 
 class GaotaituiVideoAnalyzer(BaseVideoAnalyzer):
     def _do_analyze(self):
         self.results = {k: analyse_npy_side_gaotaitui(v) for k, v in self.results.items()}
         raw = ignore_data_gaotaitui(self.results)[1]
-        return {"raw": raw, "analysis": classify_gaotaitui(raw)}
+        return classify_gaotaitui(raw)
 
 
 class TurnaroundVideoAnalyzer(BaseVideoAnalyzer):
     def _do_analyze(self):
         self.results = {k: analyse_npy_side_jump(v) for k, v in self.results.items()}
         raw = cal_turnaround(self.results)[1]
-        return {"raw": raw, "analysis": classify_turnaround(raw)}
+        return classify_turnaround(raw)
 
 
 class TennisthrowVideoAnalyzer(BaseVideoAnalyzer):
     def _do_analyze(self):
         self.results = {k: analyse_npy_side_jump(v) for k, v in self.results.items()}
         raw = cal_tennisthrow(self.results)[1]
-        return {"raw": raw, "analysis": classify_tennisthrow(raw)}
+        return classify_tennisthrow(raw)
 
 
 class JumpwithbothVideoAnalyzer(BaseVideoAnalyzer):
     def _do_analyze(self):
         self.results = {k: analyse_npy_side_jump(v) for k, v in self.results.items()}
         raw = cal_jumpwithboth(self.results)[1]
-        return {"raw": raw, "analysis": classify_jumpwithboth(raw)}
+        return classify_jumpwithboth(raw)
 
 
 class SitforwardVideoAnalyzer(BaseVideoAnalyzer):
     def _do_analyze(self):
         self.results = {k: analyse_npy_side_jump(v) for k, v in self.results.items()}
         raw = cal_sitforward(self.results)[1]
-        return {"raw": raw, "analysis": classify_sitforward(raw)}
+        return classify_sitforward(raw)
 
 
 class BalancebeamVideoAnalyzer(BaseVideoAnalyzer):
     def _do_analyze(self):
         self.results = {k: analyse_npy_side_jump(v) for k, v in self.results.items()}
         raw = cal_balancebeam(self.results)[1]
-        return {"raw": raw, "analysis": classify_balancebeam(raw)}
+        return classify_balancebeam(raw)
 
 
 class StandingVideoAnalyzer(BaseVideoAnalyzer):
     def _do_analyze(self):
         self.results = {k: analyse_npy_side_jump(v) for k, v in self.results.items()}
         raw = cal_standing(self.results)[1]
-        return {"raw": raw, "analysis": classify_standing(raw)}
+        return classify_standing(raw)

+ 90 - 0
frontend_refactor/package-lock.json

@@ -12,6 +12,7 @@
         "@testing-library/jest-dom": "^5.16.5",
         "@testing-library/react": "^13.4.0",
         "@testing-library/user-event": "^13.5.0",
+        "ahooks": "^3.7.1",
         "antd": "^4.23.4",
         "axios": "^0.27.2",
         "eslint": "8.22.0",
@@ -3903,6 +3904,11 @@
         "node": ">=8"
       }
     },
+    "node_modules/@types/js-cookie": {
+      "version": "2.2.7",
+      "resolved": "https://registry.npmmirror.com/@types/js-cookie/-/js-cookie-2.2.7.tgz",
+      "integrity": "sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA=="
+    },
     "node_modules/@types/json-schema": {
       "version": "7.0.11",
       "resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.11.tgz",
@@ -4496,6 +4502,32 @@
         "node": ">= 6.0.0"
       }
     },
+    "node_modules/ahooks": {
+      "version": "3.7.1",
+      "resolved": "https://registry.npmmirror.com/ahooks/-/ahooks-3.7.1.tgz",
+      "integrity": "sha512-9fooKjhScNyJaIPnlWd13LkY1gQYqv3BqwSA9ynHg1ZUtDqAICuCRoedV97ylrEL6QqI4zeq3bO3lQxkfWVNcg==",
+      "dependencies": {
+        "@types/js-cookie": "^2.x.x",
+        "ahooks-v3-count": "^1.0.0",
+        "dayjs": "^1.9.1",
+        "intersection-observer": "^0.12.0",
+        "js-cookie": "^2.x.x",
+        "lodash": "^4.17.21",
+        "resize-observer-polyfill": "^1.5.1",
+        "screenfull": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+      }
+    },
+    "node_modules/ahooks-v3-count": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/ahooks-v3-count/-/ahooks-v3-count-1.0.0.tgz",
+      "integrity": "sha512-V7uUvAwnimu6eh/PED4mCDjE7tokeZQLKlxg9lCTMPhN+NjsSbtdacByVlR1oluXQzD3MOw55wylDmQo4+S9ZQ=="
+    },
     "node_modules/ajv": {
       "version": "6.12.6",
       "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz",
@@ -8514,6 +8546,11 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/intersection-observer": {
+      "version": "0.12.2",
+      "resolved": "https://registry.npmmirror.com/intersection-observer/-/intersection-observer-0.12.2.tgz",
+      "integrity": "sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg=="
+    },
     "node_modules/ipaddr.js": {
       "version": "2.0.1",
       "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz",
@@ -10715,6 +10752,11 @@
         "node": ">=10"
       }
     },
+    "node_modules/js-cookie": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmmirror.com/js-cookie/-/js-cookie-2.2.1.tgz",
+      "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ=="
+    },
     "node_modules/js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -14458,6 +14500,14 @@
         "node": ">= 10.13.0"
       }
     },
+    "node_modules/screenfull": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmmirror.com/screenfull/-/screenfull-5.2.0.tgz",
+      "integrity": "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/scroll-into-view-if-needed": {
       "version": "2.2.29",
       "resolved": "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.29.tgz",
@@ -19364,6 +19414,11 @@
         }
       }
     },
+    "@types/js-cookie": {
+      "version": "2.2.7",
+      "resolved": "https://registry.npmmirror.com/@types/js-cookie/-/js-cookie-2.2.7.tgz",
+      "integrity": "sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA=="
+    },
     "@types/json-schema": {
       "version": "7.0.11",
       "resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.11.tgz",
@@ -19857,6 +19912,26 @@
         "debug": "4"
       }
     },
+    "ahooks": {
+      "version": "3.7.1",
+      "resolved": "https://registry.npmmirror.com/ahooks/-/ahooks-3.7.1.tgz",
+      "integrity": "sha512-9fooKjhScNyJaIPnlWd13LkY1gQYqv3BqwSA9ynHg1ZUtDqAICuCRoedV97ylrEL6QqI4zeq3bO3lQxkfWVNcg==",
+      "requires": {
+        "@types/js-cookie": "^2.x.x",
+        "ahooks-v3-count": "^1.0.0",
+        "dayjs": "^1.9.1",
+        "intersection-observer": "^0.12.0",
+        "js-cookie": "^2.x.x",
+        "lodash": "^4.17.21",
+        "resize-observer-polyfill": "^1.5.1",
+        "screenfull": "^5.0.0"
+      }
+    },
+    "ahooks-v3-count": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/ahooks-v3-count/-/ahooks-v3-count-1.0.0.tgz",
+      "integrity": "sha512-V7uUvAwnimu6eh/PED4mCDjE7tokeZQLKlxg9lCTMPhN+NjsSbtdacByVlR1oluXQzD3MOw55wylDmQo4+S9ZQ=="
+    },
     "ajv": {
       "version": "6.12.6",
       "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz",
@@ -23013,6 +23088,11 @@
         "side-channel": "^1.0.4"
       }
     },
+    "intersection-observer": {
+      "version": "0.12.2",
+      "resolved": "https://registry.npmmirror.com/intersection-observer/-/intersection-observer-0.12.2.tgz",
+      "integrity": "sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg=="
+    },
     "ipaddr.js": {
       "version": "2.0.1",
       "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz",
@@ -24716,6 +24796,11 @@
         }
       }
     },
+    "js-cookie": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmmirror.com/js-cookie/-/js-cookie-2.2.1.tgz",
+      "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ=="
+    },
     "js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -27401,6 +27486,11 @@
         "ajv-keywords": "^3.5.2"
       }
     },
+    "screenfull": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmmirror.com/screenfull/-/screenfull-5.2.0.tgz",
+      "integrity": "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA=="
+    },
     "scroll-into-view-if-needed": {
       "version": "2.2.29",
       "resolved": "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.29.tgz",

+ 1 - 0
frontend_refactor/package.json

@@ -7,6 +7,7 @@
     "@testing-library/jest-dom": "^5.16.5",
     "@testing-library/react": "^13.4.0",
     "@testing-library/user-event": "^13.5.0",
+    "ahooks": "^3.7.1",
     "antd": "^4.23.4",
     "axios": "^0.27.2",
     "eslint": "8.22.0",

+ 4 - 2
frontend_refactor/src/App.js

@@ -1,11 +1,12 @@
 import SubmitForm from "./containers/SubmitForm";
 import TaskList from "./containers/TaskList";
 import "./App.css"
-import {useState} from "react";
+import {useLocalStorageState} from "ahooks";
+import {Button} from "antd";
 
 function App() {
 
-    const [tasks, setTasks] = useState([]);
+    const [tasks, setTasks] = useLocalStorageState("tasks", {defaultValue: []});
 
     function newTaskAdded(uuid) {
         setTasks([uuid, ...tasks])
@@ -14,6 +15,7 @@ function App() {
     return (
         <div>
             <SubmitForm onNewTask={newTaskAdded}/>
+            <Button danger style={{margin: "0 auto", marginTop: 30, marginLeft: "10%"}} onClick={() => (setTasks([]))}>清空已有任务列表</Button>
             <TaskList tasks={tasks}/>
         </div>
     );

+ 6 - 1
frontend_refactor/src/containers/SubmitForm.js

@@ -20,6 +20,7 @@ const types = [
     ["VIDEO_SQUAT", "深蹲视频分析"]
 ]
 
+
 class SubmitForm extends React.Component {
 
     res = {}
@@ -43,6 +44,10 @@ class SubmitForm extends React.Component {
             data: this.res
         }).then(r => {
             this.props.onNewTask(r.data.data.task_uuid)
+            message.success("提交任务成功!")
+            setTimeout(() => {
+                this.setState({submitted: false})
+            }, 2000)
         }).catch(e => {
             message.error("提交出错: " + JSON.stringify(e))
             this.setState({submitted: false})
@@ -67,7 +72,7 @@ class SubmitForm extends React.Component {
     render() {
         return (
             <div>
-                <Card style={{height: "40%", width: "80%", margin: "0 auto", marginTop: 30}}>
+                <Card style={{height: "40%", width: "80%", margin: "0 auto"}}>
                     <Select defaultValue={types[0]} style={{width: 200}} onChange={this.choiceChange}>
                         {types.map(x => <Select.Option key={x[0]} value={x[0]}>{x[1]}</Select.Option>)}
                     </Select>

+ 146 - 36
frontend_refactor/src/containers/TaskList.js

@@ -1,7 +1,148 @@
 import React from "react";
-import {Collapse, Divider, Progress} from "antd";
+import {Card, Collapse, Descriptions, Progress, Skeleton, Statistic} from "antd";
 import axios from "axios";
 import {BACKEND_URL} from "../config";
+import {Divider} from "antd/es";
+
+
+function showAnalysis(key, data) {
+
+    let table = {
+        elbow_right_angle: "右胳膊⻆度",
+        elbow_left_angle: "左胳膊⻆度",
+        hip_right_angle: "右侧躯⼲-臀-⼤腿⻆度",
+        hip_left_angle: "左侧躯⼲-臀-⼤腿⻆度",
+        knee_right_angle: "右膝盖⻆度",
+        knee_left_angle: "左膝盖⻆度",
+        ankle_right_angle: "右侧⼤脚趾-脚踝-⼩腿⻆度",
+        ankle_left_angle: "左侧⼤脚趾-脚踝-⼩腿⻆度",
+        ankle_small_right_angle: "右侧⼩脚趾-脚踝-⼩腿⻆度",
+        ankle_small_left_angle: "左侧⼩脚趾-脚踝-⼩腿⻆度",
+        neck_right_angle: "右侧胳膊-脖⼦-躯⼲⻆度",
+        neck_left_angle: "左侧胳膊-脖⼦-躯⼲⻆度",
+        should_right_angle: "右侧胳膊-肩膀-脖⼦⻆度",
+        should_left_angle: "左侧胳膊-肩膀-脖⼦⻆度",
+        neck_centre_angle: "左胳膊-脖⼦-右胳膊⻆度",
+        is_prepared: "是否有准备动作"
+    }
+
+    if (table[key] !== undefined) {
+        return <Descriptions.Item label={table[key]}>{String(data)}</Descriptions.Item>
+    } else {
+        return <></>
+    }
+}
+
+function renderResult(x, data) {
+    if (data === undefined) {
+        return (
+            <Collapse.Panel header={"任务 ID: " + x} key={x}>
+                <Skeleton/>
+            </Collapse.Panel>
+        );
+    }
+
+    let progress = data.status === "FINISHED" ? 100 : data.progress
+    if (progress === undefined) {
+        progress = 0;
+    }
+
+    let progress_status
+    let progress_text = "队列中"
+    switch (data.status) {
+        case "ERROR":
+            progress_status = "exception"
+            progress_text = "运行出现未知错误, 请复制上方的任务 ID 向我们报告问题."
+            break
+        case "FINISHED":
+            progress_status = "success"
+            progress_text = "已完成"
+            break
+        case "RUNNING":
+            progress_status = "active"
+            progress_text = "分析中"
+            break
+        default:
+            progress_status = "active"
+    }
+
+    let result = data.result
+    let video_element = <></>
+
+    let advice = ""
+    let analysis = []
+
+    let advice_element = <></>
+
+    if (result !== undefined) {
+        if (result.file !== undefined) {
+            video_element = (
+                <Card type="inner" title="运动3D还原">
+                    <video controls style={{width: "80%"}}>
+                        <source src={result.file}/>
+                    </video>
+                </Card>
+            )
+        }
+
+        advice = result.advice
+
+        if (data.type === "PHOTO_STANDING") {
+            advice_element = advice['front'].filter(x => typeof x === 'string').concat(advice['right'].filter(x => typeof x === 'string')).map(x => <>{x}<br/></>)
+        } else {
+            advice_element = <p>{advice}</p>
+        }
+
+        for (const key in result.data) {
+
+            analysis.push(<h3>关键动作: {key}</h3>)
+
+            analysis.push(result.data[key]['file'] !== undefined && <><img style={{width: "80%"}} src={result.data[key]['file']} alt="动作图片"/><br/></>)
+            analysis.push(result.data[key]['score'] !== undefined && <><Progress type="circle" percent={result.data[key]['score']} format={percent => `${percent} 分`} strokeColor={{
+                '0%': '#108ee9',
+                '100%': '#87d068',
+            }} /><br/></>)
+
+            let detail_items = []
+            for (const k in result.data[key]) {
+                detail_items.push(showAnalysis(k, result.data[key][k]))
+            }
+
+            analysis.push(<Descriptions bordered>{detail_items}</Descriptions>)
+
+            analysis.push(<Divider/>)
+        }
+    }
+
+
+    return (
+        <Collapse.Panel header={"任务 ID: " + x} key={x}>
+
+            <Card type="inner" title="分析进度">
+                <p>状态: {progress_text}</p>
+                <p><Progress style={{width: "50%"}} percent={progress} status={progress_status}/></p>
+            </Card>
+
+            {
+                progress_status === "success" && (
+                    <>
+                        {video_element}
+
+                        <Card type="inner" title="分析建议">
+                            {advice_element}
+                        </Card>
+
+                        <Card type="inner" title="详细数据">
+                            {analysis}
+                        </Card>
+                    </>
+                )
+            }
+
+        </Collapse.Panel>
+    );
+}
+
 
 class TaskList extends React.Component {
 
@@ -13,12 +154,12 @@ class TaskList extends React.Component {
         this.timer = setInterval(() => {
             this.props.tasks.forEach((x) => {
 
-                if (!(x in this.state.details) || this.state.details[x]['status'] == 'RUNNING' || this.state.details[x]['status'] == 'QUEUEING') {
+                if (!(x in this.state.details) || this.state.details[x]['status'] === 'RUNNING' || this.state.details[x]['status'] === 'QUEUEING') {
                     axios.get(BACKEND_URL + "/result/" + x).then(r => {
-                        this.state.details[x] = r.data.data
-                        this.setState(this.state.details)
+                        this.setState({details: {...this.state.details, [x]: r.data.data}})
                     })
                 }
+
             })
         }, 2000)
     }
@@ -32,38 +173,7 @@ class TaskList extends React.Component {
             <div>
                 <Collapse style={{height: "40%", width: "80%", margin: "0 auto", marginTop: 30}}>
                     {
-                        this.props.tasks.map(x => {
-
-                            const details = this.state.details[x]
-
-                            if (details === undefined) {
-                                return <></>;
-                            }
-
-                            let data = ""
-                            let advice = ""
-                            let raw = ""
-                            let progress = details.status === "FINISHED" ? 100 : details.progress
-
-
-                            try {
-                                raw = JSON.stringify(details)
-                                data = JSON.stringify(details.result.analysis.data)
-                                advice = JSON.stringify(details.result.analysis.advice)
-                            } catch (e) {
-
-                            }
-
-                            return (
-                                <Collapse.Panel header={"任务 ID: " + x} key={x}>
-                                    <p>状态: {details.status}</p>
-                                    <p><Progress style={{width: "50%"}} percent={progress} status={details.status !== "ERROR" ? "active" : "exception"} /></p>
-                                    <p>建议: {advice}</p>
-                                    <p>评分: {data}</p>
-                                    <p>原始数据: {raw}</p>
-                                </Collapse.Panel>
-                            )
-                        })
+                        this.props.tasks.map(x => renderResult(x, this.state.details[x]))
                     }
                 </Collapse>
             </div>