Showing
4 changed files
with
49 additions
and
21 deletions
| @@ -23,9 +23,12 @@ class FootballReplayMatch: | @@ -23,9 +23,12 @@ class FootballReplayMatch: | ||
| 23 | self.videoMatchLive = FootballReplayMatchLive(llm_base_url, model_name, temperature, 'no_key', self.cache_dir, save_frames_enable) | 23 | self.videoMatchLive = FootballReplayMatchLive(llm_base_url, model_name, temperature, 'no_key', self.cache_dir, save_frames_enable) |
| 24 | 24 | ||
| 25 | def match_by_time(self, replay, events): | 25 | def match_by_time(self, replay, events): |
| 26 | + | ||
| 26 | start_utc = replay.get('start_utc') | 27 | start_utc = replay.get('start_utc') |
| 27 | 28 | ||
| 28 | - events = [(start_utc - e.get('event_utc'), e) for e in events] | 29 | + events = [(start_utc - e.get('event_utc'), e) for e in events if e.get('event_utc') is not None] |
| 30 | + if len(events) == 0: | ||
| 31 | + return None | ||
| 29 | events.sort(key=lambda x: x[0]) | 32 | events.sort(key=lambda x: x[0]) |
| 30 | 33 | ||
| 31 | target_index = next((i for i, e in enumerate(events) if e[0] > 0), -1) # 找到第一个 event_utc 早于 start_utc 的事件 | 34 | target_index = next((i for i, e in enumerate(events) if e[0] > 0), -1) # 找到第一个 event_utc 早于 start_utc 的事件 |
| @@ -80,6 +83,7 @@ class FootballReplayMatch: | @@ -80,6 +83,7 @@ class FootballReplayMatch: | ||
| 80 | goal_live_events = [e for e in live_events if str(e.get('type', '')) == '1'] | 83 | goal_live_events = [e for e in live_events if str(e.get('type', '')) == '1'] |
| 81 | 84 | ||
| 82 | matched_event = self.match_by_time(replay_info, goal_live_events) | 85 | matched_event = self.match_by_time(replay_info, goal_live_events) |
| 86 | + # print(f"{task_id}_match_by_time matched_event: {matched_event}") | ||
| 83 | if matched_event is None: | 87 | if matched_event is None: |
| 84 | replay_det_info = self.det_goal_replay(replay_info, task_id) | 88 | replay_det_info = self.det_goal_replay(replay_info, task_id) |
| 85 | replay_event_name = replay_det_info.get('event_name', '') | 89 | replay_event_name = replay_det_info.get('event_name', '') |
| @@ -9,7 +9,7 @@ api_test.py - 对 api.py 中 FootballReplayMatch.replay_match_event 的单元测 | @@ -9,7 +9,7 @@ api_test.py - 对 api.py 中 FootballReplayMatch.replay_match_event 的单元测 | ||
| 9 | 5. 无进球事件 / events 为空 | 9 | 5. 无进球事件 / events 为空 |
| 10 | 6. 边界:缺少 replay 键时抛出异常 | 10 | 6. 边界:缺少 replay 键时抛出异常 |
| 11 | """ | 11 | """ |
| 12 | - | 12 | +import time |
| 13 | import unittest | 13 | import unittest |
| 14 | from types import SimpleNamespace | 14 | from types import SimpleNamespace |
| 15 | from unittest.mock import MagicMock, patch | 15 | from unittest.mock import MagicMock, patch |
| @@ -25,7 +25,7 @@ def _fake_settings(match_by_time_threshold: int = 30): | @@ -25,7 +25,7 @@ def _fake_settings(match_by_time_threshold: int = 30): | ||
| 25 | return SimpleNamespace( | 25 | return SimpleNamespace( |
| 26 | match_by_time_threshold=match_by_time_threshold, | 26 | match_by_time_threshold=match_by_time_threshold, |
| 27 | llm=SimpleNamespace(base_url="http://192.168.1.59:11434/v1", model_name="Qwen3.6-35B-A3B-UD-Q8_K_XL.gguf", temperature=0.7), | 27 | llm=SimpleNamespace(base_url="http://192.168.1.59:11434/v1", model_name="Qwen3.6-35B-A3B-UD-Q8_K_XL.gguf", temperature=0.7), |
| 28 | - common=SimpleNamespace(cache_dir="/root/lzw/tmp_0518_replay_cache0521_07/videos_cache", task_log_dir="/root/lzw/tmp_0518_replay_cache0521_07/tasks_log"), | 28 | + common=SimpleNamespace(cache_dir="/root/lzw/tmp_0526_replay_cache0526/videos_cache", task_log_dir="/root/lzw/tmp_0526_replay_cache0526/tasks_log"), |
| 29 | save_frames_enable=True, | 29 | save_frames_enable=True, |
| 30 | ) | 30 | ) |
| 31 | 31 | ||
| @@ -33,20 +33,32 @@ def _fake_settings(match_by_time_threshold: int = 30): | @@ -33,20 +33,32 @@ def _fake_settings(match_by_time_threshold: int = 30): | ||
| 33 | def _base_data(): | 33 | def _base_data(): |
| 34 | """返回一份基础伪数据,replay.start_utc = 1000(毫秒)。""" | 34 | """返回一份基础伪数据,replay.start_utc = 1000(毫秒)。""" |
| 35 | 35 | ||
| 36 | - url = "http://video.mam.miguvideo.com/mnt6/fastclip3/wsc/2026/04/29/df760b8d15394cbc9ed0d0a4a9c4b786_1080PS/29133605/vodtmp/3b3e99cf4ca84c3782503d8817242de2.m3u8" | 36 | + # url = "http://video.mam.miguvideo.com/mnt6/fastclip3/wsc/2026/04/29/df760b8d15394cbc9ed0d0a4a9c4b786_1080PS/29133605/vodtmp/3b3e99cf4ca84c3782503d8817242de2.m3u8" |
| 37 | return { | 37 | return { |
| 38 | "id": "task_001", | 38 | "id": "task_001", |
| 39 | "match_id": "match_001", | 39 | "match_id": "match_001", |
| 40 | "replay": { | 40 | "replay": { |
| 41 | "id": "replay_001", | 41 | "id": "replay_001", |
| 42 | - "url": url, | ||
| 43 | - "start_utc": 1777444502543, | ||
| 44 | - "end_utc": 1777444531063 | 42 | + "url": "/root/lzw/finished/69dd5845dd0412067b8d5587-auto-1776074760653/replays/videos/00_14_32_080-00_15_10_560.mp4", |
| 43 | + "start_utc": 5_000, | ||
| 44 | + "end_utc": 21_000 | ||
| 45 | }, | 45 | }, |
| 46 | "events": [ | 46 | "events": [ |
| 47 | - {"id": "event_001", "type": "1", "url": url, "event_utc": 1777444502543-40000}, | ||
| 48 | - {"id": "event_002", "type": "1", "url": url, "event_utc": 1777444502543-20000}, | ||
| 49 | - {"id": "event_003", "type": "1", "url": url, "event_utc": 1777444531063+20000} | 47 | + {"id": "event_001", |
| 48 | + "type": "1", | ||
| 49 | + "url": "/root/lzw/finished/69dd5845dd0412067b8d5587-auto-1776074760653/live/videos/00-14-09-052.mp4", | ||
| 50 | + "event_utc": None | ||
| 51 | + }, | ||
| 52 | + {"id": "event_002", | ||
| 53 | + "type": "1", | ||
| 54 | + "url": "/root/lzw/finished/69dd5845dd0412067b8d5587-auto-1776074760653/live/videos/00-38-40-052.mp4", | ||
| 55 | + "event_utc": None | ||
| 56 | + }, | ||
| 57 | + {"id": "event_003", | ||
| 58 | + "type": "1", | ||
| 59 | + "url": "/root/lzw/finished/69dd5845dd0412067b8d5587-auto-1776074760653/live/videos/01-36-04-972.mp4", | ||
| 60 | + "event_utc": None | ||
| 61 | + } | ||
| 50 | ], | 62 | ], |
| 51 | } | 63 | } |
| 52 | 64 | ||
| @@ -61,7 +73,11 @@ class TestReplayMatchEvent(unittest.TestCase): | @@ -61,7 +73,11 @@ class TestReplayMatchEvent(unittest.TestCase): | ||
| 61 | frm = FootballReplayMatch(settings) | 73 | frm = FootballReplayMatch(settings) |
| 62 | 74 | ||
| 63 | data = _base_data() | 75 | data = _base_data() |
| 76 | + | ||
| 77 | + start_time = time.time() | ||
| 64 | result = frm.replay_match_event(data) | 78 | result = frm.replay_match_event(data) |
| 79 | + end_time = time.time() | ||
| 80 | + print(f"cost time:{end_time - start_time}") | ||
| 65 | 81 | ||
| 66 | print(result) | 82 | print(result) |
| 67 | # exit() | 83 | # exit() |
| @@ -4,6 +4,7 @@ import subprocess | @@ -4,6 +4,7 @@ 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 os | ||
| 7 | from urllib.parse import urlparse | 8 | from urllib.parse import urlparse |
| 8 | import cv2 | 9 | import cv2 |
| 9 | from aabd.stream_chain import video2frames | 10 | from aabd.stream_chain import video2frames |
| @@ -73,9 +74,9 @@ class Video2Frame: | @@ -73,9 +74,9 @@ class Video2Frame: | ||
| 73 | 74 | ||
| 74 | def to_frames(self, url, cache=None, fps=None, start=None, end=None, roi=None, max_px_area=None) -> list: | 75 | def to_frames(self, url, cache=None, fps=None, start=None, end=None, roi=None, max_px_area=None) -> list: |
| 75 | video_root_path = self.get_root_path(url, cache) | 76 | video_root_path = self.get_root_path(url, cache) |
| 76 | - | ||
| 77 | - video_root_path = video_root_path / f"{start}-{end}-{'_'.join(roi) if roi else 'None'}-{max_px_area}" | ||
| 78 | - download_video_path = video_root_path / "video.mp4" | 77 | + video_name = os.path.basename(urlparse(url).path) |
| 78 | + video_root_path = video_root_path / f"{video_name}--{start}-{end}-{'_'.join(roi) if roi else 'None'}-{max_px_area}" | ||
| 79 | + download_video_path = video_root_path / video_name | ||
| 79 | 80 | ||
| 80 | if not download_video_path.exists(): | 81 | if not download_video_path.exists(): |
| 81 | logger.info(f"download_video: {url} -> {download_video_path}") | 82 | logger.info(f"download_video: {url} -> {download_video_path}") |
| @@ -86,7 +87,7 @@ class Video2Frame: | @@ -86,7 +87,7 @@ class Video2Frame: | ||
| 86 | 87 | ||
| 87 | cache_dir = video_root_path | 88 | cache_dir = video_root_path |
| 88 | cache_frames = cache_dir / "frames" | 89 | cache_frames = cache_dir / "frames" |
| 89 | - cache_name = cache_dir / "data.json" | 90 | + cache_name = cache_dir / f"{video_name}.json" |
| 90 | 91 | ||
| 91 | if cache_name.exists(): | 92 | if cache_name.exists(): |
| 92 | logger.info(f"use_cache: {cache_name}") | 93 | logger.info(f"use_cache: {cache_name}") |
| @@ -6,7 +6,8 @@ import json | @@ -6,7 +6,8 @@ import json | ||
| 6 | 6 | ||
| 7 | 7 | ||
| 8 | def batch_match(): | 8 | def batch_match(): |
| 9 | - cache_dir = "/root/lzw/tmp_0518_replay_cache03" | 9 | + cache_dir = "/root/lzw/tmp_0526_replay_02/videos_cache" |
| 10 | + task_log_dir = "/root/lzw/tmp_0526_replay_02/tasks_log" | ||
| 10 | replay_match_live = FootballReplayMatchLive(base_url="http://192.168.1.59:11434/v1", | 11 | replay_match_live = FootballReplayMatchLive(base_url="http://192.168.1.59:11434/v1", |
| 11 | model="Qwen3.6-35B-A3B-UD-Q8_K_XL.gguf", | 12 | model="Qwen3.6-35B-A3B-UD-Q8_K_XL.gguf", |
| 12 | temperature=0.7, | 13 | temperature=0.7, |
| @@ -61,14 +62,20 @@ def batch_match(): | @@ -61,14 +62,20 @@ def batch_match(): | ||
| 61 | 62 | ||
| 62 | # replay_asr_text = qwen_asr.asr(replay_video_path, cache_path=replay_asr_path) | 63 | # replay_asr_text = qwen_asr.asr(replay_video_path, cache_path=replay_asr_path) |
| 63 | replay_asr_text = '' | 64 | replay_asr_text = '' |
| 64 | - replay_pack = {"url": "http://video.mam.miguvideo.com/mnt6/fastclip3/wsc/2026/04/29/df760b8d15394cbc9ed0d0a4a9c4b786_1080PS/29133605/vodtmp/3b3e99cf4ca84c3782503d8817242de2.m3u8", | ||
| 65 | - "start_utc": 1777444502543, | ||
| 66 | - "end_utc": 1777444531063, | 65 | + # replay_pack = {"url": "http://video.mam.miguvideo.com/mnt6/fastclip3/wsc/2026/04/29/df760b8d15394cbc9ed0d0a4a9c4b786_1080PS/29133605/vodtmp/3b3e99cf4ca84c3782503d8817242de2.m3u8", |
| 66 | + # "start_utc": 1777444502543, | ||
| 67 | + # "end_utc": 1777444531063, | ||
| 68 | + # "asr_text": '无' | ||
| 69 | + # } | ||
| 70 | + | ||
| 71 | + replay_pack = {"url": "/root/lzw/finished/69dd5845dd0412067b8d5587-auto-1776074760653/replays/videos/00_14_32_080-00_15_10_560.mp4", | ||
| 72 | + "start_utc": 5_000, | ||
| 73 | + "end_utc": 21_000, | ||
| 67 | "asr_text": '无' | 74 | "asr_text": '无' |
| 68 | } | 75 | } |
| 69 | 76 | ||
| 70 | - replay_goals = fbrv.video_event(replay_pack, cache_dir=cache_dir) | ||
| 71 | - if replay_goals['event_name'] == '无进球': | 77 | + replay_goals = fbrv.video_event(replay_pack, cache_dir=os.path.join(cache_dir, "replays"), task_log_dir=os.path.join(task_log_dir, "task_001")) |
| 78 | + if replay_goals['event_name'] == '未进球': | ||
| 72 | continue | 79 | continue |
| 73 | # replay_pack = {"video_path": replay_video_path, "asr_text": replay_asr_text} | 80 | # replay_pack = {"video_path": replay_video_path, "asr_text": replay_asr_text} |
| 74 | 81 | ||
| @@ -77,7 +84,7 @@ def batch_match(): | @@ -77,7 +84,7 @@ def batch_match(): | ||
| 77 | start_time = time.time() | 84 | start_time = time.time() |
| 78 | print("Start matching...") | 85 | print("Start matching...") |
| 79 | print(f"len(live_packs): {len(live_packs)}") | 86 | print(f"len(live_packs): {len(live_packs)}") |
| 80 | - result = replay_match_live.match_batch(replay_pack, live_packs, max_parallel=2, cache_dir=cache_dir) | 87 | + result = replay_match_live.match_batch(replay_pack, live_packs, max_parallel=2, cache_dir=os.path.join(cache_dir, "events"), task_log_dir=os.path.join(task_log_dir, "task_001")) |
| 81 | end_time = time.time() | 88 | end_time = time.time() |
| 82 | print(f"Time taken for matching: {end_time - start_time:.2f} seconds") | 89 | print(f"Time taken for matching: {end_time - start_time:.2f} seconds") |
| 83 | print(replay_video_path) | 90 | print(replay_video_path) |
-
Please register or login to post a comment