Spaces:
Sleeping
Sleeping
Théo Rousseaux
commited on
Commit
•
5730896
1
Parent(s):
006c8dd
squat agent working
Browse files
Modules/PoseEstimation/pose_agent.py
CHANGED
@@ -1,66 +1,86 @@
|
|
1 |
-
from Modules.PoseEstimation.pose_estimator import calculate_angle, joints_id_dict, model
|
2 |
from langchain.tools import tool
|
3 |
from langchain.agents import AgentExecutor, create_tool_calling_agent
|
4 |
from langchain_core.prompts import ChatPromptTemplate
|
5 |
from langchain_core.messages import HumanMessage
|
6 |
from langchain_mistralai.chat_models import ChatMistralAI
|
|
|
|
|
|
|
|
|
|
|
7 |
|
8 |
# If api_key is not passed, default behavior is to use the `MISTRAL_API_KEY` environment variable.
|
9 |
llm = ChatMistralAI(model='mistral-large-latest', api_key="i5jSJkCFNGKfgIztloxTMjfckiFbYBj4")
|
10 |
|
11 |
@tool
|
12 |
-
def
|
13 |
-
|
14 |
"""
|
15 |
-
|
16 |
|
17 |
Args:
|
18 |
-
|
19 |
|
20 |
Returns:
|
21 |
-
|
22 |
"""
|
23 |
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
|
30 |
-
|
|
|
31 |
|
32 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
|
34 |
@tool
|
35 |
-
def
|
36 |
"""
|
37 |
-
|
|
|
38 |
|
39 |
Args:
|
40 |
-
|
41 |
-
model (YOLO): model to use
|
42 |
|
43 |
Returns:
|
44 |
-
|
45 |
"""
|
|
|
|
|
|
|
|
|
|
|
46 |
|
47 |
-
|
48 |
-
results = model(video_path, save=True, show_conf=False, show_boxes=False)
|
49 |
-
for frame in results:
|
50 |
-
tensor = frame.keypoints.xy[0]
|
51 |
-
keypoints.append(tensor.tolist())
|
52 |
-
|
53 |
-
return keypoints
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
tools = [compute_right_knee_angle]
|
58 |
|
59 |
prompt = ChatPromptTemplate.from_messages(
|
60 |
[
|
61 |
(
|
62 |
"system",
|
63 |
-
"You are a helpful assistant. Make sure to use the
|
64 |
),
|
65 |
("placeholder", "{chat_history}"),
|
66 |
("human", "{input}"),
|
@@ -71,4 +91,6 @@ prompt = ChatPromptTemplate.from_messages(
|
|
71 |
# Construct the Tools agent
|
72 |
agent = create_tool_calling_agent(llm, tools, prompt)
|
73 |
|
74 |
-
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
|
|
|
|
|
|
|
|
1 |
from langchain.tools import tool
|
2 |
from langchain.agents import AgentExecutor, create_tool_calling_agent
|
3 |
from langchain_core.prompts import ChatPromptTemplate
|
4 |
from langchain_core.messages import HumanMessage
|
5 |
from langchain_mistralai.chat_models import ChatMistralAI
|
6 |
+
import os
|
7 |
+
import sys
|
8 |
+
import json
|
9 |
+
sys.path.append(os.getcwd())
|
10 |
+
from Modules.PoseEstimation.pose_estimator import model, compute_right_knee_angle, moving_average
|
11 |
|
12 |
# If api_key is not passed, default behavior is to use the `MISTRAL_API_KEY` environment variable.
|
13 |
llm = ChatMistralAI(model='mistral-large-latest', api_key="i5jSJkCFNGKfgIztloxTMjfckiFbYBj4")
|
14 |
|
15 |
@tool
|
16 |
+
def get_keypoints_from_keypoints(video_path: str) -> str:
|
|
|
17 |
"""
|
18 |
+
Extracts keypoints from a video file.
|
19 |
|
20 |
Args:
|
21 |
+
video_path (str): path to the video file
|
22 |
|
23 |
Returns:
|
24 |
+
file_path (str): path to the JSON file containing the keypoints
|
25 |
"""
|
26 |
|
27 |
+
save_folder='tmp'
|
28 |
+
os.makedirs(save_folder, exist_ok=True)
|
29 |
+
keypoints = []
|
30 |
+
results = model(video_path, save=True, show_conf=False, show_boxes=False)
|
31 |
+
for (i, frame) in enumerate(results):
|
32 |
+
frame_dict = {}
|
33 |
+
frame_dict['frame'] = i
|
34 |
+
frame_dict['keypoints'] = frame.keypoints.xy[0].tolist()
|
35 |
+
keypoints.append(frame_dict)
|
36 |
+
|
37 |
+
file_path = os.path.join(save_folder, 'keypoints.json')
|
38 |
+
with open(file_path, 'w') as f:
|
39 |
+
json.dump(keypoints, f)
|
40 |
+
return file_path
|
41 |
+
|
42 |
+
def compute_right_knee_angle_list(json_path: str) -> list[float]:
|
43 |
+
"""
|
44 |
+
Computes the knee angle from a list of keypoints.
|
45 |
|
46 |
+
Args:
|
47 |
+
json_path (str): path to the JSON file containing the keypoints
|
48 |
|
49 |
+
Returns:
|
50 |
+
right_knee_angle_list (list[float]): list of knee angles
|
51 |
+
"""
|
52 |
+
keypoints_list = json.load(open(json_path))
|
53 |
+
right_knee_angle_list = []
|
54 |
+
for keypoints in keypoints_list:
|
55 |
+
right_knee_angle = compute_right_knee_angle(keypoints['keypoints'])
|
56 |
+
right_knee_angle_list.append(right_knee_angle)
|
57 |
+
return moving_average(right_knee_angle_list, 10)
|
58 |
|
59 |
@tool
|
60 |
+
def check_knee_angle(json_path: str) -> bool:
|
61 |
"""
|
62 |
+
Checks if the minimum knee angle is smaller than a threshold.
|
63 |
+
If the minimum knee angle is smaller than 90 degrees, the squat is considered correct, because it means the user is going deep enough.
|
64 |
|
65 |
Args:
|
66 |
+
json_path (str): path to the JSON file containing the keypoints
|
|
|
67 |
|
68 |
Returns:
|
69 |
+
is_correct (bool): True if the minimum knee angle is smaller than a threshold, False otherwise
|
70 |
"""
|
71 |
+
angles_list = compute_right_knee_angle_list(json_path)
|
72 |
+
for angle in angles_list:
|
73 |
+
if angle < 90:
|
74 |
+
return True
|
75 |
+
return False
|
76 |
|
77 |
+
tools = [get_keypoints_from_keypoints, check_knee_angle]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
|
79 |
prompt = ChatPromptTemplate.from_messages(
|
80 |
[
|
81 |
(
|
82 |
"system",
|
83 |
+
"You are a helpful assistant. Make sure to use the check_knee_angle tool if the user wants to check his movement.",
|
84 |
),
|
85 |
("placeholder", "{chat_history}"),
|
86 |
("human", "{input}"),
|
|
|
91 |
# Construct the Tools agent
|
92 |
agent = create_tool_calling_agent(llm, tools, prompt)
|
93 |
|
94 |
+
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
|
95 |
+
response = agent_executor.invoke({"input": f"Is my squat correct ? The json file is in tmp/keypoints.json."})
|
96 |
+
print(response["output"])
|
Modules/PoseEstimation/pose_estimation.ipynb
CHANGED
The diff for this file is too large to render.
See raw diff
|
|
Modules/PoseEstimation/pose_estimator.py
CHANGED
@@ -1,5 +1,7 @@
|
|
1 |
from ultralytics import YOLO
|
2 |
import numpy as np
|
|
|
|
|
3 |
|
4 |
id_joints_dict = {0: 'nose',
|
5 |
1: 'left_eye',
|
@@ -22,14 +24,21 @@ joints_id_dict = {v: k for k, v in id_joints_dict.items()}
|
|
22 |
|
23 |
model = YOLO('yolov8n-pose.pt')
|
24 |
|
25 |
-
def get_keypoints_from_keypoints(
|
26 |
-
|
|
|
27 |
keypoints = []
|
28 |
results = model(video_path, save=True, show_conf=False, show_boxes=False)
|
29 |
-
for frame in results:
|
30 |
-
|
|
|
|
|
|
|
31 |
|
32 |
-
|
|
|
|
|
|
|
33 |
|
34 |
def calculate_angle(a, b, c):
|
35 |
|
@@ -53,45 +62,25 @@ def calculate_angle(a, b, c):
|
|
53 |
|
54 |
return np.degrees(angle)
|
55 |
|
56 |
-
def
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
def compute_right_knee_angle(pose):
|
77 |
-
|
78 |
-
"""
|
79 |
-
Computes the knee angle.
|
80 |
-
|
81 |
-
Args:
|
82 |
-
pose (dict): pose dictionary
|
83 |
-
|
84 |
-
Returns:
|
85 |
-
knee_angle (float): knee angle
|
86 |
-
"""
|
87 |
-
|
88 |
-
right_hip = pose[0][joints_id_dict['right_hip']]
|
89 |
-
right_knee = pose[0][joints_id_dict['right_knee']]
|
90 |
-
right_ankle = pose[0][joints_id_dict['right_ankle']]
|
91 |
-
|
92 |
-
knee_angle = calculate_angle(right_hip, right_knee, right_ankle)
|
93 |
-
|
94 |
-
return knee_angle
|
95 |
|
96 |
def moving_average(data, window_size):
|
97 |
|
|
|
1 |
from ultralytics import YOLO
|
2 |
import numpy as np
|
3 |
+
import os
|
4 |
+
import json
|
5 |
|
6 |
id_joints_dict = {0: 'nose',
|
7 |
1: 'left_eye',
|
|
|
24 |
|
25 |
model = YOLO('yolov8n-pose.pt')
|
26 |
|
27 |
+
def get_keypoints_from_keypoints(video_path):
|
28 |
+
save_folder='tmp'
|
29 |
+
os.makedirs(save_folder, exist_ok=True)
|
30 |
keypoints = []
|
31 |
results = model(video_path, save=True, show_conf=False, show_boxes=False)
|
32 |
+
for (i, frame) in enumerate(results):
|
33 |
+
frame_dict = {}
|
34 |
+
frame_dict['frame'] = i
|
35 |
+
frame_dict['keypoints'] = frame.keypoints.xy[0].tolist()
|
36 |
+
keypoints.append(frame_dict)
|
37 |
|
38 |
+
file_path = os.path.join(save_folder, 'keypoints.json')
|
39 |
+
with open(file_path, 'w') as f:
|
40 |
+
json.dump(keypoints, f)
|
41 |
+
return file_path
|
42 |
|
43 |
def calculate_angle(a, b, c):
|
44 |
|
|
|
62 |
|
63 |
return np.degrees(angle)
|
64 |
|
65 |
+
def compute_right_knee_angle(keypoints):
|
66 |
+
|
67 |
+
"""
|
68 |
+
Computes the knee angle.
|
69 |
+
|
70 |
+
Args:
|
71 |
+
keypoints (list): list of keypoints
|
72 |
+
|
73 |
+
Returns:
|
74 |
+
knee_angle (float): knee angle
|
75 |
+
"""
|
76 |
+
|
77 |
+
right_hip = keypoints[joints_id_dict['right_hip']]
|
78 |
+
right_knee = keypoints[joints_id_dict['right_knee']]
|
79 |
+
right_ankle = keypoints[joints_id_dict['right_ankle']]
|
80 |
+
|
81 |
+
knee_angle = calculate_angle(right_hip, right_knee, right_ankle)
|
82 |
+
|
83 |
+
return knee_angle
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
|
85 |
def moving_average(data, window_size):
|
86 |
|
tmp/keypoints.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|