lizhengwei

jira:NYJ-1540 desc: add my_logger.py

1 import os 1 import os
2 import time 2 import time
3 -import logging 3 +
  4 +
  5 +
4 from aabd.base.enhance_dict import value_or_default 6 from aabd.base.enhance_dict import value_or_default
5 7
6 -logger = logging.getLogger(__name__) 8 +
7 9
8 from utils.football_replay_video_event_by_llm import FootballReplayVideoEvent 10 from utils.football_replay_video_event_by_llm import FootballReplayVideoEvent
9 from utils.football_replay_match_live import FootballReplayMatchLive 11 from utils.football_replay_match_live import FootballReplayMatchLive
10 12
  13 +from utils.my_logger import get_logger
  14 +
  15 +logger = get_logger()
  16 +
11 class FootballReplayMatch: 17 class FootballReplayMatch:
12 def __init__(self, settings): 18 def __init__(self, settings):
13 self.settings = settings 19 self.settings = settings
@@ -93,25 +99,25 @@ class FootballReplayMatch: @@ -93,25 +99,25 @@ class FootballReplayMatch:
93 start_time = time.time() 99 start_time = time.time()
94 replay_det_info = self.det_goal_replay(replay_info, task_id) 100 replay_det_info = self.det_goal_replay(replay_info, task_id)
95 end_time = time.time() 101 end_time = time.time()
96 - logger.info(f"判断是否是进球耗时: {end_time - start_time} 秒")  
97 - print(f"判断是否是进球耗时: {end_time - start_time} 秒") 102 + logger.info(f"Goal_recognition_all_cost_time:{end_time-start_time:.2f}seconds")
  103 + # print(f"判断是否是进球耗时: {end_time - start_time} 秒")
98 replay_event_name = replay_det_info.get('event_name', '') 104 replay_event_name = replay_det_info.get('event_name', '')
99 if replay_event_name == '进球': 105 if replay_event_name == '进球':
100 matched_event = self.match_by_llm(replay_info, goal_live_events, task_id) 106 matched_event = self.match_by_llm(replay_info, goal_live_events, task_id)
101 if matched_event is None: 107 if matched_event is None:
102 - logger.info(f"{task_id}_LLM认为视频{replay_info['url']}_{replay_start_utc}_{replay_end_utc} 是进球但是未能找到匹配的事件")  
103 - print(f"{task_id}_LLM认为视频{replay_info['url']}_{replay_start_utc}_{replay_end_utc} 是进球但是未能找到匹配的事件") 108 + logger.info(f"{task_id}_LLM_think_{replay_info['url']}_{replay_start_utc}_{replay_end_utc}_is_goal_but_no_matched_event")
  109 + # print(f"{task_id}_LLM认为视频{replay_info['url']}_{replay_start_utc}_{replay_end_utc} 是进球但是未能找到匹配的事件")
104 else: 110 else:
105 matched_event_id = matched_event.get('video_id') 111 matched_event_id = matched_event.get('video_id')
106 - logger.info(f"{task_id}_LLM认为视频{replay_info['url']}_{replay_start_utc}_{replay_end_utc} 对应的进球的事件视频是{matched_event_id}")  
107 - print(f"{task_id}_LLM认为视频{replay_info['url']}_{replay_start_utc}_{replay_end_utc} 对应的进球的事件视频是{matched_event_id}") 112 + logger.info(f"{task_id}_LLM_think_{replay_info['url']}_{replay_start_utc}_{replay_end_utc}_matched_with_{matched_event_id}")
  113 + # print(f"{task_id}_LLM认为视频{replay_info['url']}_{replay_start_utc}_{replay_end_utc} 对应的进球的事件视频是{matched_event_id}")
108 else: 114 else:
109 - logger.info(f"{task_id}_LLM判断{replay_info['url']}_{replay_start_utc}_{replay_end_utc} 不是进球,无需匹配")  
110 - print(f"{task_id}_LLM判断{replay_info['url']}_{replay_start_utc}_{replay_end_utc} 不是进球,无需匹配") 115 + logger.info(f"{task_id}_LLM_think_{replay_info['url']}_{replay_start_utc}_{replay_end_utc}_is_not_goal_no_need_match")
  116 + # print(f"{task_id}_LLM判断{replay_info['url']}_{replay_start_utc}_{replay_end_utc} 不是进球,无需匹配")
111 else: 117 else:
112 matched_event_id = matched_event.get('id') 118 matched_event_id = matched_event.get('id')
113 - logger.info(f"{task_id}_通过时间找到匹配认为视频{replay_info['url']}_{replay_start_utc}_{replay_end_utc} 对应的进球的事件视频是{matched_event_id}")  
114 - print(f"{task_id}_通过时间找到匹配认为视频{replay_info['url']}_{replay_start_utc}_{replay_end_utc} 对应的进球的事件视频是{matched_event_id}") 119 + logger.info(f"{task_id}_matched_by_time{replay_info['url']}_{replay_start_utc}_{replay_end_utc}_matched_with_{matched_event_id}")
  120 + # print(f"{task_id}_通过时间找到匹配认为视频{replay_info['url']}_{replay_start_utc}_{replay_end_utc} 对应的进球的事件视频是{matched_event_id}")
115 return { 121 return {
116 "id": task_id, 122 "id": task_id,
117 "match_id": match_id, 123 "match_id": match_id,
@@ -20,6 +20,10 @@ try: @@ -20,6 +20,10 @@ try:
20 except ImportError: 20 except ImportError:
21 from .api import FootballReplayMatch 21 from .api import FootballReplayMatch
22 22
  23 +
  24 +
  25 +
  26 +
23 from pathlib import Path 27 from pathlib import Path
24 def get_video_files_pathlib(folder_path, extensions=None): 28 def get_video_files_pathlib(folder_path, extensions=None):
25 if extensions is None: 29 if extensions is None:
@@ -32,7 +36,7 @@ def get_video_files_pathlib(folder_path, extensions=None): @@ -32,7 +36,7 @@ def get_video_files_pathlib(folder_path, extensions=None):
32 if f.is_file() and f.suffix.lower() in extensions] 36 if f.is_file() and f.suffix.lower() in extensions]
33 return sorted(image_files) 37 return sorted(image_files)
34 38
35 -def _fake_settings(match_by_time_threshold: int = 30): 39 +def _fake_settings(match_by_time_threshold: int = 30, cache_dir_tag: str = "test"):
36 """构造一个 settings 伪对象,兼容 api.py 中的 value_or_default 读取逻辑。""" 40 """构造一个 settings 伪对象,兼容 api.py 中的 value_or_default 读取逻辑。"""
37 return SimpleNamespace( 41 return SimpleNamespace(
38 match_by_time_threshold=match_by_time_threshold, 42 match_by_time_threshold=match_by_time_threshold,
@@ -41,18 +45,34 @@ def _fake_settings(match_by_time_threshold: int = 30): @@ -41,18 +45,34 @@ def _fake_settings(match_by_time_threshold: int = 30):
41 temperature=0.7, 45 temperature=0.7,
42 api_key='no_key' 46 api_key='no_key'
43 ), 47 ),
44 - common=SimpleNamespace(cache_dir="/root/lzw/tmp_0527_replay_cache_08/videos_cache",  
45 - task_log_dir="/root/lzw/tmp_0527_replay_cache_08/tasks_log" 48 + common=SimpleNamespace(cache_dir=f"/root/lzw/tmp_0528_replay_cache_{cache_dir_tag}/videos_cache",
  49 + task_log_dir=f"/root/lzw/tmp_0528_replay_cache_{cache_dir_tag}/tasks_log"
46 ), 50 ),
47 save_frames_enable=True, 51 save_frames_enable=True,
48 ) 52 )
49 53
50 54
  55 +def get_replays_and_events_pair():
  56 +
  57 + videos_dir = rf"/root/lzw/finished"
  58 +
  59 + dir_pairs = []
  60 + for video_name in sorted(os.listdir(videos_dir)):
51 61
  62 + live_dir = os.path.join(videos_dir, video_name, 'live')
  63 + live_video_dir = os.path.join(live_dir, 'videos')
52 64
53 -def get_event_list(): 65 + replays_dir = os.path.join(videos_dir, video_name, 'replays')
  66 + replay_videos_dir = os.path.join(replays_dir, 'videos')
  67 +
  68 + dir_pairs.append((replay_videos_dir, live_video_dir))
  69 + return dir_pairs
  70 +
  71 +
  72 +
  73 +def get_event_list(events_mp4_dir):
54 # url = "http://video.mam.miguvideo.com/mnt6/fastclip3/wsc/2026/04/29/df760b8d15394cbc9ed0d0a4a9c4b786_1080PS/29133605/vodtmp/3b3e99cf4ca84c3782503d8817242de2.m3u8" 74 # url = "http://video.mam.miguvideo.com/mnt6/fastclip3/wsc/2026/04/29/df760b8d15394cbc9ed0d0a4a9c4b786_1080PS/29133605/vodtmp/3b3e99cf4ca84c3782503d8817242de2.m3u8"
55 - events_mp4_dir = r"/root/lzw/69e4ed7c872d573c9554510b-auto-10154973/goal" 75 + # events_mp4_dir = r"/root/lzw/finished/69dd5845dd0412067b8d5587-auto-1776074760653/live/videos"
56 76
57 events_mp4_names = get_video_files_pathlib(events_mp4_dir) 77 events_mp4_names = get_video_files_pathlib(events_mp4_dir)
58 78
@@ -60,7 +80,7 @@ def get_event_list(): @@ -60,7 +80,7 @@ def get_event_list():
60 for mp4 in events_mp4_names: 80 for mp4 in events_mp4_names:
61 mp4_path = os.path.join(events_mp4_dir, mp4) 81 mp4_path = os.path.join(events_mp4_dir, mp4)
62 event_lis.append({ 82 event_lis.append({
63 - "id": f"event_{mp4.split('.')[0]}", 83 + "id": mp4,
64 "type": "1", 84 "type": "1",
65 "url": mp4_path, 85 "url": mp4_path,
66 # "event_utc": None 86 # "event_utc": None
@@ -73,7 +93,7 @@ def _base_data(i, replay_path, event_lis): @@ -73,7 +93,7 @@ def _base_data(i, replay_path, event_lis):
73 "id": f"task_{str(i).zfill(3)}", 93 "id": f"task_{str(i).zfill(3)}",
74 "match_id": f"match_{str(i).zfill(3)}", 94 "match_id": f"match_{str(i).zfill(3)}",
75 "replay": { 95 "replay": {
76 - "id": f"replay_{str(i).zfill(3)}", 96 + "id": os.path.basename(replay_path),
77 "url": replay_path, 97 "url": replay_path,
78 # "start_utc": None, 98 # "start_utc": None,
79 # "end_utc": None 99 # "end_utc": None
@@ -82,24 +102,36 @@ def _base_data(i, replay_path, event_lis): @@ -82,24 +102,36 @@ def _base_data(i, replay_path, event_lis):
82 } 102 }
83 103
84 104
85 -class TestReplayMatchEvent(unittest.TestCase):  
86 105
87 - @patch("utils.football_replay_match_live.FootballReplayMatchLive")  
88 - @patch("utils.football_replay_video_event_by_llm.FootballReplayVideoEvent")  
89 - def test_match_by_time_success(self, mock_video_cls, mock_live_cls): 106 +
  107 +
  108 +
  109 +def test_match_by_time_success():
90 # """场景1:时间差在阈值内,直接通过 match_by_time 命中。""" 110 # """场景1:时间差在阈值内,直接通过 match_by_time 命中。"""
91 - settings = _fake_settings(match_by_time_threshold=10) # threshold = 30 * 1000 = 30000 ms 111 +
  112 + replays_and_events_pair = get_replays_and_events_pair()
  113 +
  114 + for replays_mp4_dir, events_mp4_dir in replays_and_events_pair:
  115 + print(100*"=")
  116 + print(f"replays_mp4_dir: {replays_mp4_dir}, events_mp4_dir: {events_mp4_dir}")
  117 +
  118 + tag = os.path.basename(os.path.dirname(os.path.dirname(replays_mp4_dir)))
  119 + settings = _fake_settings(match_by_time_threshold=30, cache_dir_tag=tag) # threshold = 30 * 1000 = 30000 ms
  120 +
  121 +
92 frm = FootballReplayMatch(settings) 122 frm = FootballReplayMatch(settings)
93 123
94 - replays_mp4_dir = "/root/lzw/69e4ed7c872d573c9554510b-auto-10154973/replay" 124 + # replays_mp4_dir = "/root/lzw/finished/69dd5845dd0412067b8d5587-auto-1776074760653/replays/videos"
95 relays_mp4_names = get_video_files_pathlib(replays_mp4_dir) 125 relays_mp4_names = get_video_files_pathlib(replays_mp4_dir)
96 126
97 - event_list = get_event_list() 127 +
  128 + # events_mp4_dir = r"/root/lzw/finished/69dd5845dd0412067b8d5587-auto-1776074760653/live/videos"
  129 + event_list = get_event_list(events_mp4_dir)
98 130
99 all_time = 0.0 131 all_time = 0.0
100 max_time = 0.0 132 max_time = 0.0
101 for i, replay_name in enumerate(relays_mp4_names): 133 for i, replay_name in enumerate(relays_mp4_names):
102 - print(100*"*" + f"replay_name: {replay_name}") 134 + print(100*"*")
103 replay_path = os.path.join(replays_mp4_dir, replay_name) 135 replay_path = os.path.join(replays_mp4_dir, replay_name)
104 data = _base_data(i+1, replay_path, event_list) 136 data = _base_data(i+1, replay_path, event_list)
105 137
@@ -115,13 +147,31 @@ class TestReplayMatchEvent(unittest.TestCase): @@ -115,13 +147,31 @@ class TestReplayMatchEvent(unittest.TestCase):
115 print(result) 147 print(result)
116 print() 148 print()
117 print() 149 print()
118 - print()  
119 150
120 print(100*"#") 151 print(100*"#")
121 print(f"max_time: {max_time}") 152 print(f"max_time: {max_time}")
122 print(f"all_time: {all_time}") 153 print(f"all_time: {all_time}")
123 # exit() 154 # exit()
124 155
  156 +
  157 +
  158 +
  159 +if __name__ == "__main__":
  160 + test_match_by_time_success()
  161 +
  162 +
  163 +
  164 +
  165 +
  166 +
  167 +
  168 +
  169 +
  170 +
  171 +
  172 +
  173 +
  174 +
125 # self.assertEqual(result["id"], "task_001") 175 # self.assertEqual(result["id"], "task_001")
126 # self.assertEqual(result["match_id"], "match_001") 176 # self.assertEqual(result["match_id"], "match_001")
127 # self.assertEqual(result["replay_id"], "replay_001") 177 # self.assertEqual(result["replay_id"], "replay_001")
@@ -245,7 +295,3 @@ class TestReplayMatchEvent(unittest.TestCase): @@ -245,7 +295,3 @@ class TestReplayMatchEvent(unittest.TestCase):
245 295
246 # with self.assertRaises(KeyError): 296 # with self.assertRaises(KeyError):
247 # frm.replay_match_event(data) 297 # frm.replay_match_event(data)
248 -  
249 -  
250 -if __name__ == "__main__":  
251 - unittest.main()  
1 import re 1 import re
2 import json 2 import json
  3 +import time
3 import os.path 4 import os.path
4 from pathlib import Path 5 from pathlib import Path
5 from datetime import timedelta 6 from datetime import timedelta
@@ -9,9 +10,14 @@ from langchain_openai import ChatOpenAI @@ -9,9 +10,14 @@ from langchain_openai import ChatOpenAI
9 10
10 try: 11 try:
11 from .llm_image import Video2Frame 12 from .llm_image import Video2Frame
  13 + from .my_logger import get_logger
12 except: 14 except:
13 from llm_image import Video2Frame 15 from llm_image import Video2Frame
  16 + from my_logger import get_logger
14 17
  18 +
  19 +
  20 +logger = get_logger()
15 # req_prompt = """ 21 # req_prompt = """
16 # # Role 22 # # Role
17 # 你是一名拥有20年经验的足球视频技术分析师,擅长结合**视觉画面**与**解说音频(ASR)**进行跨镜头的事件匹配。你能通过解说员的描述锁定时间背景,并通过视觉特征确认物理细节。 23 # 你是一名拥有20年经验的足球视频技术分析师,擅长结合**视觉画面**与**解说音频(ASR)**进行跨镜头的事件匹配。你能通过解说员的描述锁定时间背景,并通过视觉特征确认物理细节。
@@ -192,11 +198,14 @@ class FootballReplayMatchLive: @@ -192,11 +198,14 @@ class FootballReplayMatchLive:
192 user_contents.append({'type': "text", "text": "\n请根据上述片段进行匹配并按要求输出结果/no_think\n"}) 198 user_contents.append({'type': "text", "text": "\n请根据上述片段进行匹配并按要求输出结果/no_think\n"})
193 system_message = SystemMessage(content=req_prompt) 199 system_message = SystemMessage(content=req_prompt)
194 user_message = HumanMessage(content=user_contents) 200 user_message = HumanMessage(content=user_contents)
195 - result = self.model.invoke([system_message, user_message]).content  
196 201
  202 + start_time = time.time()
  203 + result = self.model.invoke([system_message, user_message]).content
  204 + end_time = time.time()
  205 + logger.info(f"match_once_invoke_cost_time:{end_time-start_time:.2f}seconds")
197 206
198 # print(100*"3") 207 # print(100*"3")
199 - # print(result) 208 + # logger.info(f"match once invoke result: {result}")
200 # print(100*"4") 209 # print(100*"4")
201 # try: 210 # try:
202 # result_json = json.loads(result) 211 # result_json = json.loads(result)
@@ -299,7 +308,7 @@ class FootballReplayMatchLive: @@ -299,7 +308,7 @@ class FootballReplayMatchLive:
299 start=event_start, 308 start=event_start,
300 end=event_end, 309 end=event_end,
301 roi=None, 310 roi=None,
302 - max_px_area=400_000, 311 + max_px_area=300_000,
303 prompt_start="\n【回放片段信息】\n", 312 prompt_start="\n【回放片段信息】\n",
304 prompt_end=f"\n回放解说内容:无\n" 313 prompt_end=f"\n回放解说内容:无\n"
305 ) 314 )
1 import json 1 import json
  2 +import time
2 import os.path 3 import os.path
3 from pathlib import Path 4 from pathlib import Path
4 5
  6 +
  7 +
5 from langchain_core.messages import SystemMessage, HumanMessage 8 from langchain_core.messages import SystemMessage, HumanMessage
6 from langchain_openai import ChatOpenAI 9 from langchain_openai import ChatOpenAI
7 10
8 try: 11 try:
9 from .llm_image import Video2Frame 12 from .llm_image import Video2Frame
  13 + from .my_logger import get_logger
10 except: 14 except:
11 from llm_image import Video2Frame 15 from llm_image import Video2Frame
  16 + from my_logger import get_logger
  17 +
  18 +
  19 +
  20 +logger = get_logger()
12 21
13 22
14 req_prompt = """ 23 req_prompt = """
@@ -108,7 +117,12 @@ class FootballReplayVideoEvent: @@ -108,7 +117,12 @@ class FootballReplayVideoEvent:
108 system_message = SystemMessage(content=req_prompt) 117 system_message = SystemMessage(content=req_prompt)
109 video_message = HumanMessage(content=contents) 118 video_message = HumanMessage(content=contents)
110 # asr_message = HumanMessage(content=f"解说内容:{asr_text}") 119 # asr_message = HumanMessage(content=f"解说内容:{asr_text}")
  120 +
  121 + start_time = time.time()
111 result = self.model.invoke([system_message, video_message]).content 122 result = self.model.invoke([system_message, video_message]).content
  123 + end_time = time.time()
  124 + logger.info(f"video_event_invoke_cost_time:{end_time-start_time:.2f}seconds")
  125 + # logger.info(f"video event invoke result: {result}")
112 try: 126 try:
113 result_json = json.loads(result) 127 result_json = json.loads(result)
114 except json.JSONDecodeError: 128 except json.JSONDecodeError:
  1 +import os
  2 +import time
  3 +import logging
  4 +from functools import lru_cache
  5 +
  6 +@lru_cache(maxsize=1)
  7 +def get_logger():
  8 + name = "football_replay_match"
  9 + logger = logging.getLogger(name)
  10 + logger.setLevel(logging.INFO)
  11 +
  12 + # 1. 配置日志输出格式
  13 + # 修改点:增加了 %(filename)s:%(lineno)d 来显示文件名和行号
  14 + formatter = logging.Formatter(
  15 + '%(asctime)s.%(msecs)03d - %(name)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s',
  16 + datefmt='%Y-%m-%d %H:%M:%S'
  17 + )
  18 +
  19 + # 2. 创建控制台处理器
  20 + console_handler = logging.StreamHandler()
  21 + console_handler.setFormatter(formatter)
  22 + logger.addHandler(console_handler)
  23 +
  24 + # 3. 创建文件处理器
  25 + log_dir = "logs"
  26 + if not os.path.exists(log_dir):
  27 + os.makedirs(log_dir)
  28 +
  29 + log_file = os.path.join(log_dir, f"run_{time.strftime('%Y%m%d')}.log")
  30 + file_handler = logging.FileHandler(log_file, encoding='utf-8')
  31 + file_handler.setFormatter(formatter)
  32 + logger.addHandler(file_handler)
  33 +
  34 + return logger