diff --git a/apps/worker/video_processing/render_adapter.py b/apps/worker/video_processing/render_adapter.py index 7323e94c8..7bf06ef4e 100755 --- a/apps/worker/video_processing/render_adapter.py +++ b/apps/worker/video_processing/render_adapter.py @@ -366,12 +366,12 @@ class RenderAdapter: failed_clip_ids: list[str] = [] seen_asset_ids: set[str] = set() - # 批量查询素材的 file_url(OSS 存储路径) + # 批量查询素材的 storage_key(OSS 存储路径) clip_asset_ids = [c.asset_id for c in clips if c.asset_id] asset_storage_map: dict[str, str] = {} if clip_asset_ids: assets = self._db.query(AssetModel).filter(AssetModel.id.in_(clip_asset_ids)).all() - asset_storage_map = {a.id: a.file_url for a in assets if a.file_url} + asset_storage_map = {a.id: a.storage_key for a in assets if a.storage_key} for clip in clips: asset_id = clip.asset_id @@ -468,8 +468,8 @@ class RenderAdapter: from packages.adapters.sqlalchemy_impl.models import AssetModel model = self._db.query(AssetModel).filter(AssetModel.id == asset_id).first() - if model and model.file_url: - storage_key = model.file_url + if model and model.storage_key: + storage_key = model.storage_key logger.info("[plan_id=%s] [BGM] 从素材库下载: asset_id=%s", plan_id, asset_id) ok = download_asset(storage_key, bgm_file) if ok and bgm_file.exists() and bgm_file.stat().st_size > 0: diff --git a/apps/worker/worker_app/tasks/edit_plan_generation.py b/apps/worker/worker_app/tasks/edit_plan_generation.py index bba9f5cdd..9fce84cc6 100755 --- a/apps/worker/worker_app/tasks/edit_plan_generation.py +++ b/apps/worker/worker_app/tasks/edit_plan_generation.py @@ -472,14 +472,14 @@ def render_edit_plan(self, plan_id: str) -> dict: rendered_clip_ids: list[str] = [] failed_clip_ids: list[str] = [] - # 预先批量查询所有素材的 storage_key(file_url) + # 预先批量查询所有素材的 storage_key from packages.adapters.sqlalchemy_impl.models import AssetModel clip_asset_ids = [c.asset_id for c in clips if c.asset_id] asset_storage_map: dict[str, str] = {} if clip_asset_ids: assets = db.query(AssetModel).filter(AssetModel.id.in_(clip_asset_ids)).all() - asset_storage_map = {a.id: a.file_url for a in assets if a.file_url} + asset_storage_map = {a.id: a.storage_key for a in assets if a.storage_key} for clip in clips: if not clip.asset_id: diff --git a/apps/worker/worker_app/tasks/generation.py b/apps/worker/worker_app/tasks/generation.py index c425608cd..a9f988d86 100755 --- a/apps/worker/worker_app/tasks/generation.py +++ b/apps/worker/worker_app/tasks/generation.py @@ -537,8 +537,8 @@ def _prepare_bgm_track( session = SessionLocal() try: model = session.query(AssetModel).filter(AssetModel.id == asset_id).first() - if model and model.file_url: - storage_key = model.file_url + if model and model.storage_key: + storage_key = model.storage_key logger.info("[task_id=%s] [BGM] 从素材库下载: asset_id=%s", task_id, asset_id) ok = download_asset(storage_key, bgm_file) if ok and bgm_file.exists() and bgm_file.stat().st_size > 0: diff --git a/packages/adapters/sqlalchemy_impl/asset_repository.py b/packages/adapters/sqlalchemy_impl/asset_repository.py index 801679ac3..a36cfa133 100755 --- a/packages/adapters/sqlalchemy_impl/asset_repository.py +++ b/packages/adapters/sqlalchemy_impl/asset_repository.py @@ -72,6 +72,7 @@ class SQLAlchemyAssetRepository: file_type=(asset.mime_type.split("/")[0] if "/" in asset.mime_type else asset.mime_type), file_size=asset.file_size, file_url=asset.storage_key, + storage_key=asset.storage_key, thumbnail_url=asset.thumbnail_url, duration=asset.duration, width=asset.width, @@ -100,6 +101,7 @@ class SQLAlchemyAssetRepository: model.name = asset.name model.file_size = asset.file_size model.file_url = asset.storage_key + model.storage_key = asset.storage_key model.thumbnail_url = asset.thumbnail_url model.duration = asset.duration model.width = asset.width @@ -299,7 +301,7 @@ class SQLAlchemyAssetRepository: project_id=model.project_id, library_id=model.asset_library_id, name=model.name, - storage_key=model.file_url, + storage_key=model.storage_key or model.file_url, mime_type=mime_type, file_size=int(model.file_size or 0), thumbnail_url=model.thumbnail_url, diff --git a/packages/adapters/sqlalchemy_impl/models.py b/packages/adapters/sqlalchemy_impl/models.py index a851eedde..c3d2c0446 100755 --- a/packages/adapters/sqlalchemy_impl/models.py +++ b/packages/adapters/sqlalchemy_impl/models.py @@ -75,6 +75,8 @@ class AssetModel(Base): file_size = Column(Integer, nullable=False) # file_url: 完整可访问的 URL,用于客户端直接访问文件 file_url = Column(String(1000), nullable=False) + # storage_key: OSS 存储键,用于内部下载上传 + storage_key = Column(String(500), nullable=False, default="", server_default="") thumbnail_url = Column(String(1000), nullable=True) duration = Column(Float, nullable=True) width = Column(Float, nullable=True) diff --git a/tests/unit/test_render_adapter.py b/tests/unit/test_render_adapter.py index e5f2ef79d..13a15fe00 100755 --- a/tests/unit/test_render_adapter.py +++ b/tests/unit/test_render_adapter.py @@ -77,7 +77,7 @@ def _make_adapter( Args: plan: 模拟的剪辑计划 clips: 模拟的片段列表 - asset_url_map: asset_id → file_url 映射,用于 mock assets 表查询 + asset_url_map: asset_id → storage_key 映射,用于 mock assets 表查询 Returns: (adapter, mock_plan_repo, mock_clip_repo) @@ -91,7 +91,7 @@ def _make_adapter( for aid, url in asset_url_map.items(): m = MagicMock() m.id = aid - m.file_url = url + m.storage_key = url mock_assets.append(m) mock_query.all.return_value = mock_assets mock_query.filter.return_value = mock_query @@ -521,17 +521,17 @@ class TestRenderPlan: class TestDownloadAssets: @staticmethod def _make_mock_db(asset_url_map: dict[str, str]): - """构造 mock db,根据 asset_id 返回对应的 AssetModel.file_url。""" + """构造 mock db,根据 asset_id 返回对应的 AssetModel.storage_key。""" mock_db = MagicMock() mock_query = MagicMock() def _fake_filter(query): # 模拟 .filter(AssetModel.id.in_([...])).all() mock_assets = [] - for asset_id, file_url in asset_url_map.items(): + for asset_id, storage_key in asset_url_map.items(): mock_asset = MagicMock() mock_asset.id = asset_id - mock_asset.file_url = file_url + mock_asset.storage_key = storage_key mock_assets.append(mock_asset) mock_query.all.return_value = mock_assets return mock_query @@ -565,7 +565,7 @@ class TestDownloadAssets: assert len(rendered_ids) == 2 assert len(failed_ids) == 0 assert mock_download.call_count == 2 - # 验证传给 download_asset 的是 file_url 而非 asset_id + # 验证传给 download_asset 的是 storage_key 而非 asset_id call_keys = [call[0][0] for call in mock_download.call_args_list] assert "https://bucket.oss.com/videos/key1.mp4" in call_keys assert "https://bucket.oss.com/videos/key2.mp4" in call_keys @@ -670,14 +670,14 @@ class TestDownloadAssets: assert "c2" in rendered_ids @patch("video_processing.render_adapter.download_asset") - def test_asset_without_file_url_skipped(self, mock_download, tmp_path): - """素材在assets表中无file_url时跳过下载,标记为失败。""" - # 构造返回 asset 但 file_url 为空 + def test_asset_without_storage_key_skipped(self, mock_download, tmp_path): + """素材在assets表中无storage_key时跳过下载,标记为失败。""" + # 构造返回 asset 但 storage_key 为空 mock_db = MagicMock() mock_query = MagicMock() mock_asset = MagicMock() mock_asset.id = "asset_no_url" - mock_asset.file_url = "" + mock_asset.storage_key = "" mock_query.all.return_value = [mock_asset] mock_query.filter.return_value = mock_query mock_db.query.return_value = mock_query