- pipeline: fetch/extract/normalize/categorize/validate/llm_extract/raw/orchestrator - analytics: dynamics, spreads/arbitrage, seasonality, anomalies, alerts, forecast - dashboard: FastAPI + Plotly (overview/products/product/countries/alerts/quality/sources) - scheduler (APScheduler 07:30), digest (Telegram/SMTP dry-run), demo_data - SQLite (PORTABLE) with idempotent upserts, quarantine, alerts dedup - truthfulness: LLM quote-verified, source link + date on every price - tests: 13 passed, 1 skipped (robots port)
28 lines
884 B
Python
28 lines
884 B
Python
"""AgroMarket Price Agent — dashboard server entrypoint.
|
|
|
|
Run with uvicorn: uvicorn src.dashboard.app:app --host 0.0.0.0 --port $PORT
|
|
Or directly: python3 -m src.dashboard.run
|
|
"""
|
|
from __future__ import annotations
|
|
import logging
|
|
import os
|
|
|
|
|
|
def main() -> None:
|
|
import uvicorn
|
|
logging.basicConfig(level=logging.INFO,
|
|
format="%(asctime)s %(levelname)s %(name)s %(message)s")
|
|
port = int(os.environ.get("PORT", "8000"))
|
|
host = os.environ.get("DASHBOARD_HOST", "0.0.0.0")
|
|
# Make sure the DB exists and demo data is loaded (idempotent)
|
|
from .. import db
|
|
from ..analytics.alerts import generate_alerts
|
|
_ = db.source_health() # touch schema
|
|
generate_alerts()
|
|
uvicorn.run("src.dashboard.app:app", host=host, port=port,
|
|
log_level="info", reload=False, workers=1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|