Showing
5 changed files
with
55 additions
and
16 deletions
| @@ -24,7 +24,8 @@ llm: | @@ -24,7 +24,8 @@ llm: | ||
| 24 | base_url: http://192.168.1.59:11434/v1 | 24 | base_url: http://192.168.1.59:11434/v1 |
| 25 | model_name: Qwen3.6-35B-A3B-UD-Q8_K_XL.gguf | 25 | model_name: Qwen3.6-35B-A3B-UD-Q8_K_XL.gguf |
| 26 | temperature: 0.7 | 26 | temperature: 0.7 |
| 27 | - | 27 | + api_key: "no_key" |
| 28 | + | ||
| 28 | common: | 29 | common: |
| 29 | cache_dir: ./videos_cache | 30 | cache_dir: ./videos_cache |
| 30 | task_log_dir: ./tasks_log | 31 | task_log_dir: ./tasks_log |
| @@ -22,12 +22,16 @@ class FootballReplayMatch: | @@ -22,12 +22,16 @@ class FootballReplayMatch: | ||
| 22 | llm_base_url = value_or_default(settings.llm.base_url, None) | 22 | llm_base_url = value_or_default(settings.llm.base_url, None) |
| 23 | model_name = value_or_default(settings.llm.model_name, None) | 23 | model_name = value_or_default(settings.llm.model_name, None) |
| 24 | temperature = value_or_default(settings.llm.temperature, 0.7) | 24 | temperature = value_or_default(settings.llm.temperature, 0.7) |
| 25 | + api_key = value_or_default(settings.llm.api_key, 'no_key') | ||
| 26 | + | ||
| 25 | self.cache_dir = value_or_default(settings.common.cache_dir, None) | 27 | self.cache_dir = value_or_default(settings.common.cache_dir, None) |
| 26 | self.task_log_dir = value_or_default(settings.common.task_log_dir, None) | 28 | self.task_log_dir = value_or_default(settings.common.task_log_dir, None) |
| 27 | save_frames_enable = value_or_default(settings.save_frames_enable, False) | 29 | save_frames_enable = value_or_default(settings.save_frames_enable, False) |
| 28 | 30 | ||
| 29 | - self.videoEventRecognition = FootballReplayVideoEvent(llm_base_url, model_name, temperature, 'no_key', self.cache_dir, save_frames_enable) | ||
| 30 | - self.videoMatchLive = FootballReplayMatchLive(llm_base_url, model_name, temperature, 'no_key', self.cache_dir, save_frames_enable) | 31 | + |
| 32 | + | ||
| 33 | + self.videoEventRecognition = FootballReplayVideoEvent(llm_base_url, model_name, temperature, api_key, self.cache_dir, save_frames_enable) | ||
| 34 | + self.videoMatchLive = FootballReplayMatchLive(llm_base_url, model_name, temperature, api_key, self.cache_dir, save_frames_enable) | ||
| 31 | 35 | ||
| 32 | def match_by_time(self, replay, events): | 36 | def match_by_time(self, replay, events): |
| 33 | 37 | ||
| @@ -103,7 +107,10 @@ class FootballReplayMatch: | @@ -103,7 +107,10 @@ class FootballReplayMatch: | ||
| 103 | # print(f"判断是否是进球耗时: {end_time - start_time} 秒") | 107 | # print(f"判断是否是进球耗时: {end_time - start_time} 秒") |
| 104 | replay_event_name = replay_det_info.get('event_name', '') | 108 | replay_event_name = replay_det_info.get('event_name', '') |
| 105 | if replay_event_name == '进球': | 109 | if replay_event_name == '进球': |
| 110 | + start_time1 = time.time() | ||
| 106 | matched_event = self.match_by_llm(replay_info, goal_live_events, task_id) | 111 | matched_event = self.match_by_llm(replay_info, goal_live_events, task_id) |
| 112 | + end_time1 = time.time() | ||
| 113 | + logger.info(f"LLM_match_all_cost_time:{end_time1-start_time1:.2f}seconds") | ||
| 107 | if matched_event is None: | 114 | if matched_event is None: |
| 108 | logger.info(f"{task_id}_LLM_think_{replay_info['url']}_{replay_start_utc}_{replay_end_utc}_is_goal_but_no_matched_event") | 115 | 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} 是进球但是未能找到匹配的事件") | 116 | # print(f"{task_id}_LLM认为视频{replay_info['url']}_{replay_start_utc}_{replay_end_utc} 是进球但是未能找到匹配的事件") |
| @@ -45,8 +45,8 @@ def _fake_settings(match_by_time_threshold: int = 30, cache_dir_tag: str = "test | @@ -45,8 +45,8 @@ def _fake_settings(match_by_time_threshold: int = 30, cache_dir_tag: str = "test | ||
| 45 | temperature=0.7, | 45 | temperature=0.7, |
| 46 | api_key='no_key' | 46 | api_key='no_key' |
| 47 | ), | 47 | ), |
| 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" | 48 | + common=SimpleNamespace(cache_dir=f"/root/lzw/tmp_0601_replay_cache_{cache_dir_tag}/videos_cache", |
| 49 | + task_log_dir=f"/root/lzw/tmp_0601_replay_cache_{cache_dir_tag}/tasks_log" | ||
| 50 | ), | 50 | ), |
| 51 | save_frames_enable=True, | 51 | save_frames_enable=True, |
| 52 | ) | 52 | ) |
| @@ -112,6 +112,8 @@ def test_match_by_time_success(): | @@ -112,6 +112,8 @@ def test_match_by_time_success(): | ||
| 112 | replays_and_events_pair = get_replays_and_events_pair() | 112 | replays_and_events_pair = get_replays_and_events_pair() |
| 113 | 113 | ||
| 114 | for replays_mp4_dir, events_mp4_dir in replays_and_events_pair: | 114 | for replays_mp4_dir, events_mp4_dir in replays_and_events_pair: |
| 115 | + # replays_mp4_dir = "/root/lzw/finished/69e5102bfd87d43d09bba90d-auto-10154993/replays/videos" | ||
| 116 | + # events_mp4_dir = r"/root/lzw/finished/69e5102bfd87d43d09bba90d-auto-10154993/live/videos" | ||
| 115 | print(100*"=") | 117 | print(100*"=") |
| 116 | print(f"replays_mp4_dir: {replays_mp4_dir}, events_mp4_dir: {events_mp4_dir}") | 118 | print(f"replays_mp4_dir: {replays_mp4_dir}, events_mp4_dir: {events_mp4_dir}") |
| 117 | 119 | ||
| @@ -121,13 +123,15 @@ def test_match_by_time_success(): | @@ -121,13 +123,15 @@ def test_match_by_time_success(): | ||
| 121 | 123 | ||
| 122 | frm = FootballReplayMatch(settings) | 124 | frm = FootballReplayMatch(settings) |
| 123 | 125 | ||
| 124 | - # replays_mp4_dir = "/root/lzw/finished/69dd5845dd0412067b8d5587-auto-1776074760653/replays/videos" | 126 | + |
| 125 | relays_mp4_names = get_video_files_pathlib(replays_mp4_dir) | 127 | relays_mp4_names = get_video_files_pathlib(replays_mp4_dir) |
| 126 | 128 | ||
| 127 | 129 | ||
| 128 | - # events_mp4_dir = r"/root/lzw/finished/69dd5845dd0412067b8d5587-auto-1776074760653/live/videos" | 130 | + |
| 129 | event_list = get_event_list(events_mp4_dir) | 131 | event_list = get_event_list(events_mp4_dir) |
| 130 | 132 | ||
| 133 | + | ||
| 134 | + | ||
| 131 | all_time = 0.0 | 135 | all_time = 0.0 |
| 132 | max_time = 0.0 | 136 | max_time = 0.0 |
| 133 | for i, replay_name in enumerate(relays_mp4_names): | 137 | for i, replay_name in enumerate(relays_mp4_names): |
| @@ -4,15 +4,22 @@ import subprocess | @@ -4,15 +4,22 @@ import subprocess | ||
| 4 | import sys | 4 | import sys |
| 5 | from pathlib import Path | 5 | from pathlib import Path |
| 6 | from typing import Optional | 6 | from typing import Optional |
| 7 | +import time | ||
| 7 | import os | 8 | import os |
| 8 | from urllib.parse import urlparse | 9 | from urllib.parse import urlparse |
| 9 | import cv2 | 10 | import cv2 |
| 10 | from aabd.stream_chain import video2frames | 11 | from aabd.stream_chain import video2frames |
| 11 | import json | 12 | import json |
| 12 | -import logging | 13 | + |
| 13 | import hashlib | 14 | import hashlib |
| 14 | 15 | ||
| 15 | -logger = logging.getLogger(__name__) | 16 | +try: |
| 17 | + from .my_logger import get_logger | ||
| 18 | +except: | ||
| 19 | + | ||
| 20 | + from my_logger import get_logger | ||
| 21 | + | ||
| 22 | +logger = get_logger() | ||
| 16 | 23 | ||
| 17 | _IS_ABSOLUTE_UTC_THRESHOLD = 1_000_000_000 | 24 | _IS_ABSOLUTE_UTC_THRESHOLD = 1_000_000_000 |
| 18 | 25 | ||
| @@ -81,7 +88,10 @@ class Video2Frame: | @@ -81,7 +88,10 @@ class Video2Frame: | ||
| 81 | if not download_video_path.exists(): | 88 | if not download_video_path.exists(): |
| 82 | logger.info(f"download_video: {url} -> {download_video_path}") | 89 | logger.info(f"download_video: {url} -> {download_video_path}") |
| 83 | video_root_path.mkdir(parents=True, exist_ok=True) | 90 | video_root_path.mkdir(parents=True, exist_ok=True) |
| 91 | + start_time = time.time() | ||
| 84 | download_to_mp4(url, str(download_video_path), duration=None) | 92 | download_to_mp4(url, str(download_video_path), duration=None) |
| 93 | + end_time = time.time() | ||
| 94 | + logger.info(f"download_video_cost_time:{end_time - start_time:.2f}seconds") | ||
| 85 | logger.info(f"video_path: {download_video_path}") | 95 | logger.info(f"video_path: {download_video_path}") |
| 86 | 96 | ||
| 87 | 97 | ||
| @@ -95,6 +105,7 @@ class Video2Frame: | @@ -95,6 +105,7 @@ class Video2Frame: | ||
| 95 | with cache_name.open('r', encoding='utf-8') as f: | 105 | with cache_name.open('r', encoding='utf-8') as f: |
| 96 | return json.load(f) | 106 | return json.load(f) |
| 97 | else: | 107 | else: |
| 108 | + start_time = time.time() | ||
| 98 | cache_dir.mkdir(parents=True, exist_ok=True) | 109 | cache_dir.mkdir(parents=True, exist_ok=True) |
| 99 | data = { | 110 | data = { |
| 100 | 'fps': fps, | 111 | 'fps': fps, |
| @@ -104,7 +115,7 @@ class Video2Frame: | @@ -104,7 +115,7 @@ class Video2Frame: | ||
| 104 | cache_frames.mkdir(parents=True, exist_ok=True) | 115 | cache_frames.mkdir(parents=True, exist_ok=True) |
| 105 | for f in self.iter_mp4(str(download_video_path), start, end, fps): | 116 | for f in self.iter_mp4(str(download_video_path), start, end, fps): |
| 106 | frame = f['frame'] | 117 | frame = f['frame'] |
| 107 | - time = f['src_frame_time'] | 118 | + duration = f['src_frame_time'] |
| 108 | fps = f['fps'] | 119 | fps = f['fps'] |
| 109 | data['fps'] = fps | 120 | data['fps'] = fps |
| 110 | if roi is not None: | 121 | if roi is not None: |
| @@ -116,10 +127,10 @@ class Video2Frame: | @@ -116,10 +127,10 @@ class Video2Frame: | ||
| 116 | _, buffer = cv2.imencode('.jpg', frame) | 127 | _, buffer = cv2.imencode('.jpg', frame) |
| 117 | b64_str = base64.b64encode(buffer).decode('utf-8') | 128 | b64_str = base64.b64encode(buffer).decode('utf-8') |
| 118 | 129 | ||
| 119 | - data['frames'].append({'time': time, 'image': b64_str}) | 130 | + data['frames'].append({'time': duration, 'image': b64_str}) |
| 120 | 131 | ||
| 121 | if self.save_frames_enable: | 132 | if self.save_frames_enable: |
| 122 | - frame_path = cache_frames / f"{time:015d}.jpg" | 133 | + frame_path = cache_frames / f"{duration:015d}.jpg" |
| 123 | cv2.imwrite(frame_path, frame) | 134 | cv2.imwrite(frame_path, frame) |
| 124 | 135 | ||
| 125 | cache_name.parent.mkdir(parents=True, exist_ok=True) | 136 | cache_name.parent.mkdir(parents=True, exist_ok=True) |
| @@ -127,6 +138,8 @@ class Video2Frame: | @@ -127,6 +138,8 @@ class Video2Frame: | ||
| 127 | with cache_name.open('w', encoding='utf-8') as f: | 138 | with cache_name.open('w', encoding='utf-8') as f: |
| 128 | json.dump(data, f, indent=4) | 139 | json.dump(data, f, indent=4) |
| 129 | logger.info(f"save_cache: {cache_name}") | 140 | logger.info(f"save_cache: {cache_name}") |
| 141 | + end_time = time.time() | ||
| 142 | + logger.info(f"to_frames_cost_time:{end_time - start_time:.2f}seconds") | ||
| 130 | return data | 143 | return data |
| 131 | 144 | ||
| 132 | def to_llm_contents(self, url, cache=None, fps=None, start=None, end=None, roi=None, max_px_area=None, | 145 | def to_llm_contents(self, url, cache=None, fps=None, start=None, end=None, roi=None, max_px_area=None, |
| @@ -2,6 +2,7 @@ import os | @@ -2,6 +2,7 @@ import os | ||
| 2 | import time | 2 | import time |
| 3 | import logging | 3 | import logging |
| 4 | from functools import lru_cache | 4 | from functools import lru_cache |
| 5 | +from logging.handlers import TimedRotatingFileHandler # 引入按时间切割的处理器 | ||
| 5 | 6 | ||
| 6 | @lru_cache(maxsize=1) | 7 | @lru_cache(maxsize=1) |
| 7 | def get_logger(): | 8 | def get_logger(): |
| @@ -10,7 +11,6 @@ def get_logger(): | @@ -10,7 +11,6 @@ def get_logger(): | ||
| 10 | logger.setLevel(logging.INFO) | 11 | logger.setLevel(logging.INFO) |
| 11 | 12 | ||
| 12 | # 1. 配置日志输出格式 | 13 | # 1. 配置日志输出格式 |
| 13 | - # 修改点:增加了 %(filename)s:%(lineno)d 来显示文件名和行号 | ||
| 14 | formatter = logging.Formatter( | 14 | formatter = logging.Formatter( |
| 15 | '%(asctime)s.%(msecs)03d - %(name)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s', | 15 | '%(asctime)s.%(msecs)03d - %(name)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s', |
| 16 | datefmt='%Y-%m-%d %H:%M:%S' | 16 | datefmt='%Y-%m-%d %H:%M:%S' |
| @@ -21,13 +21,27 @@ def get_logger(): | @@ -21,13 +21,27 @@ def get_logger(): | ||
| 21 | console_handler.setFormatter(formatter) | 21 | console_handler.setFormatter(formatter) |
| 22 | logger.addHandler(console_handler) | 22 | logger.addHandler(console_handler) |
| 23 | 23 | ||
| 24 | - # 3. 创建文件处理器 | 24 | + # 3. 创建按天自动切割的文件处理器 |
| 25 | log_dir = "logs" | 25 | log_dir = "logs" |
| 26 | if not os.path.exists(log_dir): | 26 | if not os.path.exists(log_dir): |
| 27 | os.makedirs(log_dir) | 27 | os.makedirs(log_dir) |
| 28 | 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') | 29 | + # 基础日志文件名 |
| 30 | + base_log_file = os.path.join(log_dir, "run.log") | ||
| 31 | + | ||
| 32 | + # TimedRotatingFileHandler 参数说明: | ||
| 33 | + # when='midnight' : 每天凌晨自动切割 | ||
| 34 | + # interval=1 : 每1个单位(即每天)切割一次 | ||
| 35 | + # backupCount=30 : 保留最近30天的日志,超出的会自动删除(防止硬盘被写满) | ||
| 36 | + # encoding='utf-8': 防止中文乱码 | ||
| 37 | + file_handler = TimedRotatingFileHandler( | ||
| 38 | + base_log_file, | ||
| 39 | + when='midnight', | ||
| 40 | + interval=1, | ||
| 41 | + backupCount=30, | ||
| 42 | + encoding='utf-8' | ||
| 43 | + ) | ||
| 44 | + file_handler.suffix = "%Y%m%d" # 切割后的旧日志会自动带上日期后缀,如 run.log.20260601 | ||
| 31 | file_handler.setFormatter(formatter) | 45 | file_handler.setFormatter(formatter) |
| 32 | logger.addHandler(file_handler) | 46 | logger.addHandler(file_handler) |
| 33 | 47 |
-
Please register or login to post a comment