fix(agent-office): YouTubeResearchAgent 품질 개선 (동시실행 가드·에러 로깅·타입 수정)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,15 +1,20 @@
|
|||||||
# agent-office/app/agents/youtube.py
|
# agent-office/app/agents/youtube.py
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import logging
|
||||||
from datetime import date
|
from datetime import date
|
||||||
|
|
||||||
|
import httpx
|
||||||
|
|
||||||
from .base import BaseAgent
|
from .base import BaseAgent
|
||||||
from ..db import add_youtube_research_job, update_youtube_research_job
|
from ..db import add_youtube_research_job, update_youtube_research_job, add_log
|
||||||
from ..youtube_researcher import (
|
from ..youtube_researcher import (
|
||||||
TARGET_COUNTRIES, TREND_KEYWORDS,
|
TARGET_COUNTRIES, TREND_KEYWORDS, MUSIC_LAB_URL,
|
||||||
fetch_youtube_trending, fetch_google_trends, fetch_billboard_top20,
|
fetch_youtube_trending, fetch_google_trends, fetch_billboard_top20,
|
||||||
push_to_music_lab,
|
push_to_music_lab,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class YouTubeResearchAgent(BaseAgent):
|
class YouTubeResearchAgent(BaseAgent):
|
||||||
agent_id = "youtube"
|
agent_id = "youtube"
|
||||||
@@ -20,6 +25,8 @@ class YouTubeResearchAgent(BaseAgent):
|
|||||||
|
|
||||||
async def on_command(self, command: str, params: dict) -> dict:
|
async def on_command(self, command: str, params: dict) -> dict:
|
||||||
if command == "research":
|
if command == "research":
|
||||||
|
if self.state == "working":
|
||||||
|
return {"ok": False, "message": "이미 수집 중"}
|
||||||
countries = params.get("countries", TARGET_COUNTRIES)
|
countries = params.get("countries", TARGET_COUNTRIES)
|
||||||
asyncio.create_task(self._run_research(countries))
|
asyncio.create_task(self._run_research(countries))
|
||||||
return {"ok": True, "message": f"리서치 시작: {countries}"}
|
return {"ok": True, "message": f"리서치 시작: {countries}"}
|
||||||
@@ -59,15 +66,15 @@ class YouTubeResearchAgent(BaseAgent):
|
|||||||
|
|
||||||
async def send_weekly_report(self) -> None:
|
async def send_weekly_report(self) -> None:
|
||||||
"""매주 월요일 08:00 — 주간 인사이트 텔레그램 발송."""
|
"""매주 월요일 08:00 — 주간 인사이트 텔레그램 발송."""
|
||||||
import httpx
|
|
||||||
from ..youtube_researcher import MUSIC_LAB_URL
|
|
||||||
try:
|
try:
|
||||||
async with httpx.AsyncClient(timeout=10.0) as client:
|
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||||
resp = await client.get(f"{MUSIC_LAB_URL}/api/music/market/report/latest")
|
resp = await client.get(f"{MUSIC_LAB_URL}/api/music/market/report/latest")
|
||||||
if resp.status_code != 200:
|
if resp.status_code != 200:
|
||||||
return
|
return
|
||||||
report = resp.json()
|
report = resp.json()
|
||||||
except Exception:
|
except Exception as e:
|
||||||
|
add_log(self.agent_id, f"주간 리포트 조회 실패: {e}", level="error")
|
||||||
|
logger.error("send_weekly_report: music-lab 조회 실패: %s", e)
|
||||||
return
|
return
|
||||||
|
|
||||||
top = report.get("top_genres", [])[:3]
|
top = report.get("top_genres", [])[:3]
|
||||||
@@ -81,5 +88,6 @@ class YouTubeResearchAgent(BaseAgent):
|
|||||||
try:
|
try:
|
||||||
from ..telegram_bot import send_message
|
from ..telegram_bot import send_message
|
||||||
await send_message(text)
|
await send_message(text)
|
||||||
except (ImportError, Exception):
|
except (ImportError, Exception) as e:
|
||||||
pass
|
add_log(self.agent_id, f"주간 리포트 텔레그램 발송 실패: {e}", level="error")
|
||||||
|
logger.error("send_weekly_report: 텔레그램 발송 실패: %s", e)
|
||||||
|
|||||||
@@ -542,7 +542,7 @@ def update_youtube_research_job(
|
|||||||
def get_latest_youtube_research_job() -> Optional[Dict[str, Any]]:
|
def get_latest_youtube_research_job() -> Optional[Dict[str, Any]]:
|
||||||
with _conn() as conn:
|
with _conn() as conn:
|
||||||
row = conn.execute(
|
row = conn.execute(
|
||||||
"SELECT * FROM youtube_research_jobs ORDER BY started_at DESC LIMIT 1"
|
"SELECT * FROM youtube_research_jobs ORDER BY id DESC LIMIT 1"
|
||||||
).fetchone()
|
).fetchone()
|
||||||
if not row:
|
if not row:
|
||||||
return None
|
return None
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ def activity_feed(limit: int = 50, offset: int = 0):
|
|||||||
# --- Realestate Agent Push Endpoint ---
|
# --- Realestate Agent Push Endpoint ---
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from typing import List, Dict, Any
|
from typing import List, Dict, Any, Optional
|
||||||
|
|
||||||
|
|
||||||
class RealestateNotifyBody(BaseModel):
|
class RealestateNotifyBody(BaseModel):
|
||||||
@@ -208,8 +208,8 @@ class YouTubeResearchBody(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
@app.post("/api/agent-office/youtube/research")
|
@app.post("/api/agent-office/youtube/research")
|
||||||
async def trigger_youtube_research(body: YouTubeResearchBody = None):
|
async def trigger_youtube_research(body: Optional[YouTubeResearchBody] = None):
|
||||||
agent = AGENT_REGISTRY.get("youtube")
|
agent = get_agent("youtube")
|
||||||
if not agent:
|
if not agent:
|
||||||
raise HTTPException(status_code=503, detail="YouTubeResearchAgent 없음")
|
raise HTTPException(status_code=503, detail="YouTubeResearchAgent 없음")
|
||||||
params = {}
|
params = {}
|
||||||
|
|||||||
Reference in New Issue
Block a user