diff --git a/data/agromarket_report.xlsx b/data/agromarket_report.xlsx index 7cd4e0b..a1fd6f5 100644 Binary files a/data/agromarket_report.xlsx and b/data/agromarket_report.xlsx differ diff --git a/src/dashboard/app.py b/src/dashboard/app.py index 199cfd7..427bf31 100644 --- a/src/dashboard/app.py +++ b/src/dashboard/app.py @@ -310,11 +310,20 @@ def product_page(product_id: str, days: int = Query(30, ge=7, le=180)) -> HTMLRe f"{html.escape(r['source_id'])} · {html.escape(r['region'])} " f"{r['first_d']} → {r['last_d']} · {r['n']} записей" for r in src_rows) or "
" + "Демо-данные (источник demo_*). Подключите реальный источник на " + "странице «Источники», чтобы увидеть живые цены." + "
" if all_demo else "" + ) body = _render("product", - PRODUCT=html.escape(product_id), - PRODUCT_LABEL=html.escape(product_id.replace("_", " ")), - LATEST_VAL=f"{val:,.1f}" if val else "—", - LATEST_AS_OF=as_of or "—", + PRODUCT=html.escape(product_id), + PRODUCT_LABEL=html.escape(product_id.replace("_", " ")), + DEMO_BANNER=demo_banner, + LATEST_VAL=f"{val:,.1f}" if val else "—", + LATEST_AS_OF=as_of or "—", LATEST_REGION=html.escape(region or "—"), LATEST_SRC_URL=html.escape(src_url or ""), LATEST_FRAGMENT=html.escape(frag[:120] if frag else "—"), @@ -534,6 +543,33 @@ def api_arbitrage(product: str, from_: str = "KZ", to: str = "TJ", return a +@app.get("/api/products") +def api_products() -> dict: + """id → best label, for the overview search field. + Uses category/subcategory as the human label (ru from taxonomy).""" + import yaml + try: + with open(config.TAXONOMY_PATH, "r", encoding="utf-8") as f: + tax = yaml.safe_load(f) or {} + except Exception: + tax = {} + sub_label = {} + for c in tax.get("categories", []): + for s in c.get("subcategories", []): + sub_label[(c.get("category") or c.get("id"), s.get("id"))] = s.get("label_ru") or s.get("label") or s.get("id") + cat_label = {c.get("category") or c.get("id"): c.get("label_ru") or c.get("label") or (c.get("category") or c.get("id")) + for c in tax.get("categories", [])} + out = {} + for r in db.all_products(): + cat = r.get("category") or "" + sub = r.get("subcategory") or "" + pid = r["product"] + # best label: prefer sub label, fall back to sub id readable + lbl = sub_label.get((cat, sub), (sub.replace("_", " ").capitalize() if sub else pid)) + out[pid] = lbl + return {"products": out} + + @app.get("/healthz") def healthz() -> dict: return {"ok": True, "time": date.today().isoformat()} diff --git a/src/dashboard/templates/overview.html b/src/dashboard/templates/overview.html index 9c3305b..6cab35c 100644 --- a/src/dashboard/templates/overview.html +++ b/src/dashboard/templates/overview.html @@ -1,8 +1,62 @@ -Демо: {{ TODAY }}. Все цены в тг/кг. Карантин = данные, прошедшие валидацию и отправленные на проверку.
+Демо-набор данных от {{ TODAY }}. Все цены в тг/кг. «Карантин» — записи, отправленные на проверку.
+ Демо-данные (сгенерированы для примера). Чтобы увидеть живые цены, подключите реальный источник + на странице Источники или загрузите CSV/HTML оттуда же. +
+