style: 修复2个文件ruff告警+格式化对齐(smart_asset_selector + test_ai_service) #759
@@ -18,7 +18,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import math
|
||||
from dataclasses import dataclass
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -278,9 +277,7 @@ class SmartAssetSelector:
|
||||
# 分桶
|
||||
short_bucket = [d for d in scored if d.duration is not None and d.duration < _SHORT_BUCKET_MAX]
|
||||
medium_bucket = [
|
||||
d
|
||||
for d in scored
|
||||
if d.duration is not None and _SHORT_BUCKET_MAX <= d.duration < _MEDIUM_BUCKET_MAX
|
||||
d for d in scored if d.duration is not None and _SHORT_BUCKET_MAX <= d.duration < _MEDIUM_BUCKET_MAX
|
||||
]
|
||||
long_bucket = [d for d in scored if d.duration is not None and d.duration >= _MEDIUM_BUCKET_MAX]
|
||||
unknown_bucket = [d for d in scored if d.duration is None]
|
||||
@@ -295,7 +292,7 @@ class SmartAssetSelector:
|
||||
selected_ids: set[str] = set()
|
||||
|
||||
# 先按配额从每个桶取
|
||||
for bucket, name in zip(buckets, bucket_names):
|
||||
for bucket, _name in zip(buckets, bucket_names, strict=False):
|
||||
quota = min(base_quota, len(bucket))
|
||||
if quota <= 0:
|
||||
continue
|
||||
|
||||
@@ -20,8 +20,8 @@ sys.path.insert(0, "apps/api")
|
||||
from app.services.ai_service import ( # noqa: E402
|
||||
TITLE_STYLES,
|
||||
_generate_titles_fallback,
|
||||
_parse_titles_from_response,
|
||||
_parse_semantic_match_response,
|
||||
_parse_titles_from_response,
|
||||
_semantic_match_fallback,
|
||||
generate_smart_titles,
|
||||
semantic_match_assets,
|
||||
@@ -76,7 +76,7 @@ class TestTitleParsing(unittest.TestCase):
|
||||
|
||||
def test_parse_markdown_code_block_json(self):
|
||||
"""解析 markdown 代码块包裹的 JSON."""
|
||||
content = "```json\n[\"标题1\", \"标题2\"]\n```"
|
||||
content = '```json\n["标题1", "标题2"]\n```'
|
||||
result = _parse_titles_from_response(content)
|
||||
self.assertEqual(len(result), 2)
|
||||
|
||||
@@ -209,9 +209,7 @@ class TestGenerateSmartTitles(unittest.TestCase):
|
||||
mock_client = MagicMock()
|
||||
mock_client.is_available = True
|
||||
# 返回无法解析的内容(只有一个标题且格式异常)
|
||||
mock_client.chat_completion = MagicMock(
|
||||
return_value="一段文字说明,不是标题列表"
|
||||
)
|
||||
mock_client.chat_completion = MagicMock(return_value="一段文字说明,不是标题列表")
|
||||
with patch("app.services.ai_service.get_doubao_client", return_value=mock_client):
|
||||
result = generate_smart_titles("测试视频", "viral", 5)
|
||||
# 只有1个有效标题,不足2个触发降级
|
||||
@@ -223,7 +221,7 @@ class TestTitleStyles(unittest.TestCase):
|
||||
|
||||
def test_all_styles_have_required_fields(self):
|
||||
"""所有风格都有必要字段."""
|
||||
for key, info in TITLE_STYLES.items():
|
||||
for _key, info in TITLE_STYLES.items():
|
||||
self.assertIn("name", info)
|
||||
self.assertIn("description", info)
|
||||
self.assertIn("examples", info)
|
||||
@@ -310,12 +308,14 @@ class TestSemanticMatchParsing(unittest.TestCase):
|
||||
|
||||
def test_parse_matches_list_format(self):
|
||||
"""解析 {matches: [...]} 格式."""
|
||||
content = json.dumps({
|
||||
"matches": [
|
||||
{"asset_id": "a1", "score": 0.9},
|
||||
{"asset_id": "a2", "score": 0.7},
|
||||
]
|
||||
})
|
||||
content = json.dumps(
|
||||
{
|
||||
"matches": [
|
||||
{"asset_id": "a1", "score": 0.9},
|
||||
{"asset_id": "a2", "score": 0.7},
|
||||
]
|
||||
}
|
||||
)
|
||||
result = _parse_semantic_match_response(content, ["a1", "a2"])
|
||||
self.assertIsNotNone(result)
|
||||
self.assertAlmostEqual(result["a1"], 0.9)
|
||||
@@ -323,10 +323,12 @@ class TestSemanticMatchParsing(unittest.TestCase):
|
||||
|
||||
def test_parse_array_format(self):
|
||||
"""解析数组格式."""
|
||||
content = json.dumps([
|
||||
{"id": "x1", "score": 0.5},
|
||||
{"id": "x2", "score": 0.88},
|
||||
])
|
||||
content = json.dumps(
|
||||
[
|
||||
{"id": "x1", "score": 0.5},
|
||||
{"id": "x2", "score": 0.88},
|
||||
]
|
||||
)
|
||||
result = _parse_semantic_match_response(content, ["x1", "x2"])
|
||||
self.assertIsNotNone(result)
|
||||
self.assertAlmostEqual(result["x1"], 0.5)
|
||||
@@ -341,7 +343,7 @@ class TestSemanticMatchParsing(unittest.TestCase):
|
||||
|
||||
def test_parse_markdown_code_block(self):
|
||||
"""解析markdown代码块."""
|
||||
content = "```json\n{\"a1\": 0.7}\n```"
|
||||
content = '```json\n{"a1": 0.7}\n```'
|
||||
result = _parse_semantic_match_response(content, ["a1", "a2"])
|
||||
# 只有1个素材评分,少于一半(需要至少1个,max(1, 2//2)=1)
|
||||
self.assertIsNotNone(result)
|
||||
@@ -396,9 +398,7 @@ class TestSemanticMatchAssets(unittest.TestCase):
|
||||
"""豆包调用成功路径."""
|
||||
mock_client = MagicMock()
|
||||
mock_client.is_available = True
|
||||
mock_client.chat_completion = MagicMock(
|
||||
return_value=json.dumps({"a1": 0.9, "a2": 0.5, "a3": 0.2})
|
||||
)
|
||||
mock_client.chat_completion = MagicMock(return_value=json.dumps({"a1": 0.9, "a2": 0.5, "a3": 0.2}))
|
||||
with patch("app.services.ai_service.get_doubao_client", return_value=mock_client):
|
||||
result = semantic_match_assets("风景视频", self._make_assets())
|
||||
self.assertEqual(result["source"], "doubao")
|
||||
|
||||
Reference in New Issue
Block a user