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 compute_right_knee_angle(pose: list) -> float:
13
-
14
  """
15
- Computes the knee angle.
16
 
17
  Args:
18
- pose (list): list of keypoints
19
 
20
  Returns:
21
- knee_angle (float): knee angle
22
  """
23
 
24
- right_hip = pose[joints_id_dict['right_hip']]
25
- right_knee = pose[joints_id_dict['right_knee']]
26
- right_ankle = pose[joints_id_dict['right_ankle']]
27
-
28
- knee_angle = calculate_angle(right_hip, right_knee, right_ankle)
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
- print(knee_angle)
 
31
 
32
- return str(knee_angle)
 
 
 
 
 
 
 
 
33
 
34
  @tool
35
- def get_keypoints_from_path(video_path: str):
36
  """
37
- Get keypoints from a video.
 
38
 
39
  Args:
40
- video_path (str): path to the video
41
- model (YOLO): model to use
42
 
43
  Returns:
44
- keypoints (list): list of keypoints
45
  """
 
 
 
 
 
46
 
47
- keypoints = []
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 compute_right_knee_angle tool for information.",
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(model, video_path):
26
-
 
27
  keypoints = []
28
  results = model(video_path, save=True, show_conf=False, show_boxes=False)
29
- for frame in results:
30
- keypoints.append(frame.keypoints.xy)
 
 
 
31
 
32
- return keypoints
 
 
 
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 compute_left_knee_angle(pose):
57
-
58
- """
59
- Computes the knee angle.
60
-
61
- Args:
62
- pose (dict): pose dictionary
63
-
64
- Returns:
65
- knee_angle (float): knee angle
66
- """
67
-
68
- left_hip = pose[0][joints_id_dict['left_hip']]
69
- left_knee = pose[0][joints_id_dict['left_knee']]
70
- left_ankle = pose[0][joints_id_dict['left_ankle']]
71
-
72
- knee_angle = calculate_angle(left_hip, left_knee, left_ankle)
73
-
74
- return knee_angle
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