fix(02): revise plan 02-02 based on checker feedback
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
phase: 02-platform-skills
|
||||
plan: 02
|
||||
type: execute
|
||||
wave: 1
|
||||
wave: 2
|
||||
depends_on: [02-01]
|
||||
files_modified:
|
||||
- kb_pipeline/platforms/__init__.py
|
||||
@@ -24,6 +24,7 @@ must_haves:
|
||||
- "内容保存为Markdown文件(YAML Frontmatter + 正文)"
|
||||
- "403错误触发降级策略(API -> Playwright)"
|
||||
- "网络错误自动重试3次"
|
||||
- "失败时记录错误原因到workflow_state.json"
|
||||
artifacts:
|
||||
- path: "kb_pipeline/platforms/base.py"
|
||||
provides: "平台适配器基类"
|
||||
@@ -48,12 +49,16 @@ must_haves:
|
||||
to: "kb-bilibili-metadata/bilibili_extractor.py"
|
||||
via: "BilibiliExtractor class"
|
||||
pattern: "from kb_bilibili_metadata"
|
||||
- from: "kb_pipeline/platforms/bilibili.py"
|
||||
to: "kb_pipeline/state.py"
|
||||
via: "WorkflowStateManager.mark_step_failed"
|
||||
pattern: "mark_step_failed"
|
||||
---
|
||||
|
||||
<objective>
|
||||
创建 B站平台适配器,封装视频和专栏的元数据提取与内容获取逻辑,复用现有 BilibiliExtractor 实现。
|
||||
|
||||
Purpose: 为 B站视频和专栏提供统一的元数据提取和内容下载接口,支持错误重试和降级策略。
|
||||
Purpose: 为 B站视频和专栏提供统一的元数据提取和内容下载接口,支持错误重试、降级策略和状态记录。
|
||||
Output: PlatformAdapter 基类、BilibiliAdapter 实现类
|
||||
</objective>
|
||||
|
||||
@@ -96,6 +101,23 @@ class StepOutput(BaseModel):
|
||||
success: bool
|
||||
error_message: Optional[str]
|
||||
completed_at: datetime
|
||||
|
||||
class WorkflowState(BaseModel):
|
||||
content_id: str
|
||||
platform: str
|
||||
source_url: str
|
||||
steps: Dict[str, StepRecord]
|
||||
|
||||
def mark_step_failed(self, step_name: str, error_message: str) -> None:
|
||||
"""标记步骤失败,记录错误信息"""
|
||||
```
|
||||
|
||||
From kb_pipeline/state.py:
|
||||
```python
|
||||
class WorkflowStateManager:
|
||||
def load(self) -> Optional[WorkflowState]: ...
|
||||
def save(self, state: WorkflowState) -> None: ...
|
||||
def get_or_create(self, content_id, platform, source_url) -> WorkflowState: ...
|
||||
```
|
||||
|
||||
From kb_pipeline/errors.py:
|
||||
@@ -200,13 +222,14 @@ DEFAULT_HEADERS = {
|
||||
</task>
|
||||
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 2: Implement BilibiliAdapter for video metadata</name>
|
||||
<name>Task 2: Implement BilibiliAdapter for video metadata with state recording</name>
|
||||
<files>kb_pipeline/platforms/bilibili.py, tests/test_platforms/test_bilibili.py</files>
|
||||
<behavior>
|
||||
- Test 1: fetch_metadata("BVxxx", "video") 返回正确的视频元数据
|
||||
- Test 2: 403错误时触发降级策略(API -> Playwright)
|
||||
- Test 3: 网络错误自动重试3次
|
||||
- Test 4: get_output_filename 返回正确格式 "bilibili_BVxxx_metadata.json"
|
||||
- Test 5: 失败时调用 WorkflowStateManager.mark_step_failed() 记录错误
|
||||
</behavior>
|
||||
<action>
|
||||
创建 kb_pipeline/platforms/bilibili.py:
|
||||
@@ -214,24 +237,32 @@ DEFAULT_HEADERS = {
|
||||
from kb_pipeline.platforms.base import PlatformAdapter
|
||||
from kb_pipeline.errors import NetworkError, AuthError
|
||||
from kb_pipeline.retry import retry_on_network_error
|
||||
from kb_pipeline.state import WorkflowStateManager
|
||||
from kb_bilibili_metadata.bilibili_extractor import BilibiliExtractor
|
||||
|
||||
class BilibiliAdapter(PlatformAdapter):
|
||||
PLATFORM = "bilibili"
|
||||
|
||||
def __init__(self, headless: bool = True, timeout: int = 30):
|
||||
def __init__(self, headless: bool = True, timeout: int = 30, state_manager: Optional[WorkflowStateManager] = None):
|
||||
self.extractor = BilibiliExtractor(headless=headless, timeout=timeout)
|
||||
self.state_manager = state_manager
|
||||
|
||||
def get_content_type(self, url: str) -> str:
|
||||
# 从 URL 识别 video 或 article
|
||||
|
||||
@retry_on_network_error
|
||||
async def fetch_metadata(self, content_id: str, content_type: str) -> Dict[str, Any]:
|
||||
if content_type == "video":
|
||||
return self.extractor.extract_video_metadata(content_id)
|
||||
elif content_type == "article":
|
||||
return self.extractor.extract_article_metadata(content_id)
|
||||
raise ValueError(f"Unsupported content type: {content_type}")
|
||||
try:
|
||||
if content_type == "video":
|
||||
return self.extractor.extract_video_metadata(content_id)
|
||||
elif content_type == "article":
|
||||
return self.extractor.extract_article_metadata(content_id)
|
||||
raise ValueError(f"Unsupported content type: {content_type}")
|
||||
except (NetworkError, AuthError) as e:
|
||||
# 记录失败原因到状态文件
|
||||
if self.state_manager:
|
||||
self.state_manager.mark_step_failed("metadata", str(e))
|
||||
raise
|
||||
|
||||
async def fetch_content(self, content_id: str, content_type: str) -> str:
|
||||
# 视频内容获取留给 Phase 3 (ASR)
|
||||
@@ -246,11 +277,12 @@ DEFAULT_HEADERS = {
|
||||
- 使用 mock 模拟 BilibiliExtractor 的返回值
|
||||
- 测试视频元数据提取
|
||||
- 测试错误处理和重试机制
|
||||
- 测试失败时状态记录到 WorkflowStateManager
|
||||
</action>
|
||||
<verify>
|
||||
<automated>pytest tests/test_platforms/test_bilibili.py::test_video_metadata -x -v</automated>
|
||||
</verify>
|
||||
<done>BilibiliAdapter 能正确提取B站视频元数据,支持错误重试</done>
|
||||
<done>BilibiliAdapter 能正确提取B站视频元数据,支持错误重试和状态记录</done>
|
||||
</task>
|
||||
|
||||
<task type="auto" tdd="true">
|
||||
@@ -328,6 +360,7 @@ DEFAULT_HEADERS = {
|
||||
- [ ] BilibiliAdapter 正确提取B站专栏内容和元数据
|
||||
- [ ] 内容保存为 Markdown 格式,包含 YAML Frontmatter
|
||||
- [ ] 网络错误自动重试3次
|
||||
- [ ] 403/超时错误触发降级策略,记录失败原因到 workflow_state.json
|
||||
- [ ] 所有测试通过(至少 8 个测试用例)
|
||||
</success_criteria>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user