diff --git a/agent-office/app/agents/insta.py b/agent-office/app/agents/insta.py index 2750879..e455adf 100644 --- a/agent-office/app/agents/insta.py +++ b/agent-office/app/agents/insta.py @@ -56,6 +56,8 @@ class InstaAgent(BaseAgent): requires_approval=False) await self.transition("working", "뉴스 수집·키워드 추출", task_id) try: + prefs = await service_proxy.insta_get_preferences() + add_log(self.agent_id, f"insta preferences: {prefs}", "info", task_id) await self._run_collect_and_extract() kws = await service_proxy.insta_list_keywords(used=False) if auto_select: @@ -147,6 +149,12 @@ class InstaAgent(BaseAgent): return {"ok": False, "message": "keyword_id 필수"} await self._render_and_push(kid) return {"ok": True} + if command == "collect_trends": + await messaging.send_raw("🌐 외부 트렌드 수집 시작") + created = await service_proxy.insta_collect_trends() + st = await self._wait_task(created["task_id"], step="trends_collect", timeout_sec=300) + await messaging.send_raw(f"✅ 트렌드 수집 완료: {st.get('message', '')}") + return {"ok": True, "result": st} return {"ok": False, "message": f"Unknown command: {command}"} async def on_callback(self, action: str, params: dict) -> dict: diff --git a/agent-office/app/service_proxy.py b/agent-office/app/service_proxy.py index a0ca473..a9bb318 100644 --- a/agent-office/app/service_proxy.py +++ b/agent-office/app/service_proxy.py @@ -167,6 +167,41 @@ async def insta_get_asset_bytes(slate_id: int, page: int) -> bytes: return resp.content +async def insta_collect_trends(categories: Optional[list] = None) -> Dict[str, Any]: + payload = {"categories": categories} if categories else {} + resp = await _client.post(f"{INSTA_LAB_URL}/api/insta/trends/collect", json=payload) + resp.raise_for_status() + return resp.json() + + +async def insta_list_trends(source: Optional[str] = None, + category: Optional[str] = None, + days: int = 1) -> List[Dict[str, Any]]: + params: Dict[str, Any] = {"days": days} + if source: + params["source"] = source + if category: + params["category"] = category + resp = await _client.get(f"{INSTA_LAB_URL}/api/insta/trends", params=params) + resp.raise_for_status() + return resp.json().get("items", []) + + +async def insta_get_preferences() -> Dict[str, float]: + resp = await _client.get(f"{INSTA_LAB_URL}/api/insta/preferences") + resp.raise_for_status() + return {p["category"]: p["weight"] for p in resp.json().get("categories", [])} + + +async def insta_put_preferences(weights: Dict[str, float]) -> Dict[str, Any]: + resp = await _client.put( + f"{INSTA_LAB_URL}/api/insta/preferences", + json={"categories": weights}, + ) + resp.raise_for_status() + return resp.json() + + # --- realestate-lab --- async def realestate_collect() -> Dict[str, Any]: diff --git a/agent-office/tests/test_insta_agent_trends.py b/agent-office/tests/test_insta_agent_trends.py new file mode 100644 index 0000000..1f483d1 --- /dev/null +++ b/agent-office/tests/test_insta_agent_trends.py @@ -0,0 +1,73 @@ +import os +import sys +import tempfile + +_fd, _TMP = tempfile.mkstemp(suffix=".db") +os.close(_fd) +os.unlink(_TMP) +os.environ["AGENT_OFFICE_DB_PATH"] = _TMP + +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +from unittest.mock import AsyncMock + +import pytest + +from app.agents.insta import InstaAgent + + +@pytest.fixture(autouse=True) +def _init_db(): + import gc + gc.collect() + if os.path.exists(_TMP): + os.remove(_TMP) + from app.db import init_db + init_db() + yield + gc.collect() + + +@pytest.mark.asyncio +async def test_on_command_collect_trends_dispatches(monkeypatch): + agent = InstaAgent() + fake_collect = AsyncMock(return_value={"task_id": "tcollect"}) + fake_status = AsyncMock(return_value={"status": "succeeded", "result_id": 8, + "message": "naver:5, google:3"}) + + monkeypatch.setattr("app.agents.insta.service_proxy.insta_collect_trends", fake_collect) + monkeypatch.setattr("app.agents.insta.service_proxy.insta_task_status", fake_status) + monkeypatch.setattr("app.agents.insta.messaging.send_raw", AsyncMock(return_value={"ok": True})) + + result = await agent.on_command("collect_trends", {}) + assert result["ok"] is True + fake_collect.assert_awaited() + + +@pytest.mark.asyncio +async def test_on_schedule_loads_preferences(monkeypatch): + """on_schedule이 preferences를 가져오는지 확인.""" + agent = InstaAgent() + + fake_collect = AsyncMock(return_value={"task_id": "t1"}) + fake_extract = AsyncMock(return_value={"task_id": "t2"}) + fake_status = AsyncMock(side_effect=[ + {"status": "succeeded", "result_id": 0}, + {"status": "succeeded", "result_id": 0}, + ]) + fake_keywords = AsyncMock(return_value=[ + {"id": 1, "keyword": "K", "category": "economy", "score": 0.9}, + ]) + fake_prefs = AsyncMock(return_value={"economy": 0.6, "psychology": 0.4}) + + monkeypatch.setattr("app.agents.insta.service_proxy.insta_collect", fake_collect) + monkeypatch.setattr("app.agents.insta.service_proxy.insta_extract", fake_extract) + monkeypatch.setattr("app.agents.insta.service_proxy.insta_task_status", fake_status) + monkeypatch.setattr("app.agents.insta.service_proxy.insta_list_keywords", fake_keywords) + monkeypatch.setattr("app.agents.insta.service_proxy.insta_get_preferences", fake_prefs) + monkeypatch.setattr("app.agents.insta.messaging.send_raw", AsyncMock(return_value={"ok": True})) + + agent.state = "idle" + await agent.on_schedule() + + fake_prefs.assert_awaited()