fix(agent-office/blog): generate/market/review 비동기 task 폴링 추가

blog-lab의 generate/market/review 엔드포인트는 task_id만 즉시 반환하고
BackgroundTask로 실제 작업을 수행한다. 기존 코드는 응답에서 바로
post_id를 꺼내려 해 항상 'generate did not return post_id' 실패.

공통 폴링 헬퍼 _await_task로 research처럼 status=succeeded 대기하도록
수정. 점수는 review 완료 후 post를 다시 읽어 review_score로 판정.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-16 00:12:24 +09:00
parent 447c6babc3
commit ae4f0d4270

View File

@@ -49,49 +49,50 @@ class BlogAgent(BaseAgent):
await self.transition("working", f"리서치: {keyword}", task_id)
asyncio.create_task(self._run_pipeline(task_id, keyword))
async def _await_task(self, step: str, task_id: str, timeout_sec: int = 240) -> Optional[int]:
"""blog-lab BackgroundTask 완료 폴링. 완료 시 result_id 반환."""
attempts = max(1, timeout_sec // 5)
for _ in range(attempts):
await asyncio.sleep(5)
status = await service_proxy.blog_task_status(task_id)
s = status.get("status")
if s == "succeeded":
return status.get("result_id")
if s == "failed":
raise Exception(f"{step} failed: {status.get('error')}")
raise Exception(f"{step} timeout ({timeout_sec}s 내 완료되지 않음)")
async def _run_pipeline(self, task_id: str, keyword: str) -> None:
try:
# 1) 리서치 시작 (백그라운드 task)
# 1) 리서치
research = await service_proxy.blog_research(keyword)
research_task_id = research.get("task_id")
keyword_id = None
# 2) 리서치 완료까지 폴링 (최대 3분)
timed_out = True
for _ in range(36):
await asyncio.sleep(5)
status = await service_proxy.blog_task_status(research_task_id)
if status.get("status") == "succeeded":
keyword_id = status.get("result_id")
timed_out = False
break
if status.get("status") == "failed":
raise Exception(f"research failed: {status.get('error')}")
if timed_out:
raise Exception("research timeout (3분 내 완료되지 않음)")
keyword_id = await self._await_task("research", research.get("task_id"), 180)
if not keyword_id:
raise Exception("research succeeded but result_id missing")
# 3) 작가 단계
# 2) 작가 단계 (비동기)
await self.transition("working", f"글 생성: {keyword}", task_id)
gen = await service_proxy.blog_generate(keyword_id)
post_id = gen.get("post_id") or gen.get("id")
post_id = await self._await_task("generate", gen.get("task_id"), 300)
if not post_id:
raise Exception("generate did not return post_id")
raise Exception("generate succeeded but post_id missing")
# 4) 마케터 단계
# 3) 마케터 단계 (비동기)
await self.transition("working", "링크 삽입 중", task_id)
await service_proxy.blog_market(post_id)
mkt = await service_proxy.blog_market(post_id)
await self._await_task("market", mkt.get("task_id"), 180)
# 5) 평가자 단계
# 4) 평가자 단계 (비동기)
await self.transition("working", "품질 리뷰 중", task_id)
review = await service_proxy.blog_review(post_id)
score = review.get("score")
passed = review.get("passed", False)
rev = await service_proxy.blog_review(post_id)
await self._await_task("review", rev.get("task_id"), 180)
post = await service_proxy.blog_get_post(post_id)
title = post.get("title", "(제목 없음)")
excerpt = (post.get("body") or "")[:300]
post_after = await service_proxy.blog_get_post(post_id)
score = post_after.get("review_score")
passed = (score or 0) >= 42
title = post_after.get("title", "(제목 없음)")
excerpt = (post_after.get("body") or "")[:300]
update_task_status(task_id, "pending", {
"keyword": keyword,