{html.escape(item.get('company', '-'))}
{severity_badge(item.get('severity', ''))}{html.escape(item.get('reason', '-'))}
" + f"Действие: {html.escape(item.get('recommended_action', '-'))}
" + "diff --git a/clickhouse-1c/ai/company_intelligence_api.py b/clickhouse-1c/ai/company_intelligence_api.py index 0edb673..fff15fe 100644 --- a/clickhouse-1c/ai/company_intelligence_api.py +++ b/clickhouse-1c/ai/company_intelligence_api.py @@ -2,17 +2,19 @@ from __future__ import annotations import argparse +import html import json import os from datetime import UTC, datetime from decimal import Decimal from pathlib import Path from typing import Any +from urllib.parse import quote import clickhouse_connect import uvicorn from fastapi import FastAPI, HTTPException, Query -from fastapi.responses import PlainTextResponse +from fastapi.responses import HTMLResponse, PlainTextResponse def parse_args() -> argparse.Namespace: @@ -66,6 +68,424 @@ def load_latest_manager_brief() -> dict[str, Any]: return json.loads(latest_path.read_text(encoding="utf-8")) +def grafana_company_dashboard_url() -> str: + return os.getenv( + "AW_1C_MANAGER_BRIEF_GRAFANA_URL", + "http://10.10.10.11:3000/d/1c-file-companies/1c-file-company-intelligence", + ) + + +def fmt_number(value: Any) -> str: + if value is None or value == "": + return "-" + if isinstance(value, float): + return f"{value:,.2f}".replace(",", " ").replace(".", ",") + if isinstance(value, int): + return f"{value:,}".replace(",", " ") + return str(value) + + +def severity_badge(severity: str) -> str: + tone = { + "critical": "critical", + "high": "high", + "medium": "medium", + "low": "low", + "none": "none", + }.get((severity or "").lower(), "none") + return f'{html.escape(severity or "none")}' + + +def render_manager_brief_html(payload: dict[str, Any]) -> str: + brief = payload.get("brief", {}) + context = payload.get("context", {}) + summary = context.get("portfolio_summary", {}) + freshness = context.get("freshness", []) + top_risks = brief.get("top_risks", []) + top_forecasts = brief.get("top_forecasts", []) + actions = brief.get("actions", []) + caveats = brief.get("caveats", []) + render_mode = payload.get("render_mode", "unknown") + generated_at = payload.get("generated_at", "") + history_url = "/api/1/analytics-1c/manager/brief/history" + json_url = "/api/1/analytics-1c/manager/brief/latest" + md_url = "/api/1/analytics-1c/manager/brief/latest.md" + grafana_url = grafana_company_dashboard_url() + + freshness_rows = [] + for item in freshness: + status = "stale" if item.get("stale") else "fresh" + freshness_rows.append( + "
{html.escape(item.get('reason', '-'))}
" + f"Действие: {html.escape(item.get('recommended_action', '-'))}
" + "Прогноз 30д: {html.escape(item.get('forecast_30d', '-'))}
" + f"{html.escape(item.get('interpretation', '-'))}
" + f"Карточка компании" + "Нет данных.
'} +Нет данных.
'} +| Источник | +Последняя отметка | +Отставание, ч | +Статус | +
|---|