From ca8bcb3fedc729fd0d9f222dba4383197a77bf8f Mon Sep 17 00:00:00 2001 From: gahusb Date: Wed, 13 May 2026 23:44:38 +0900 Subject: [PATCH] feat(screener): POST /snapshot/refresh-news-sentiment with telegram_text --- stock-lab/app/screener/router.py | 24 +++++++++++++++++ stock-lab/tests/test_ai_news_router.py | 36 ++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 stock-lab/tests/test_ai_news_router.py diff --git a/stock-lab/app/screener/router.py b/stock-lab/app/screener/router.py index 43c0cfe..57099bb 100644 --- a/stock-lab/app/screener/router.py +++ b/stock-lab/app/screener/router.py @@ -276,6 +276,30 @@ def list_runs(limit: int = 30): ] +# ---------- /snapshot/refresh-news-sentiment ---------- + +from .ai_news import pipeline as _ai_pipeline +from .ai_news import telegram as _ai_telegram + + +@router.post("/snapshot/refresh-news-sentiment") +async def post_refresh_news_sentiment(asof: Optional[str] = None): + asof_date = dt.date.fromisoformat(asof) if asof else dt.date.today() + if asof_date.weekday() >= 5: + return {"asof": asof_date.isoformat(), "status": "skipped_weekend"} + if _is_holiday(asof_date): + return {"asof": asof_date.isoformat(), "status": "skipped_holiday"} + with _conn() as c: + summary = await _ai_pipeline.refresh_daily(c, asof_date) + summary["telegram_text"] = _ai_telegram.build_message( + asof=summary["asof"], + top_pos=summary["top_pos"], top_neg=summary["top_neg"], + tokens_input=summary["tokens_input"], + tokens_output=summary["tokens_output"], + ) + return summary + + @router.get("/runs/{run_id}") def get_run(run_id: int): with _conn() as c: diff --git a/stock-lab/tests/test_ai_news_router.py b/stock-lab/tests/test_ai_news_router.py new file mode 100644 index 0000000..9a37beb --- /dev/null +++ b/stock-lab/tests/test_ai_news_router.py @@ -0,0 +1,36 @@ +import datetime as dt +from unittest.mock import AsyncMock, patch +from fastapi.testclient import TestClient + +from app.main import app + + +def test_refresh_news_sentiment_weekend_skip(): + # 2026-05-16 = Saturday + client = TestClient(app) + resp = client.post( + "/api/stock/screener/snapshot/refresh-news-sentiment?asof=2026-05-16" + ) + assert resp.status_code == 200 + assert resp.json()["status"] == "skipped_weekend" + + +def test_refresh_news_sentiment_weekday_invokes_pipeline(): + fake_summary = { + "asof": "2026-05-13", "updated": 3, "failures": [], + "duration_sec": 1.0, "tokens_input": 100, "tokens_output": 20, + "top_pos": [], "top_neg": [], "model": "m", + } + with patch("app.screener.router._ai_pipeline") as mp, \ + patch("app.screener.router._ai_telegram") as mt: + mp.refresh_daily = AsyncMock(return_value=fake_summary) + mt.build_message = lambda **kw: "BUILT_TEXT" + client = TestClient(app) + resp = client.post( + "/api/stock/screener/snapshot/refresh-news-sentiment?asof=2026-05-13" + ) + assert resp.status_code == 200 + body = resp.json() + assert body["asof"] == "2026-05-13" + assert body["updated"] == 3 + assert body["telegram_text"] == "BUILT_TEXT"