From 09e179107c4e414760503253ee0921ece4d25cae Mon Sep 17 00:00:00 2001 From: samruk_3 Date: Mon, 21 Sep 2026 16:45:28 +0000 Subject: [PATCH] fix: Alem error reasons, real file link + recalc button, error counts as submitted, Alem call docs --- .gitignore | 3 +- dashboard.html | 104 +++++++++++++++++++++++++++++++++++-------------- lib/alem.js | 57 ++++++++++++++++++++++++--- server.js | 32 +++++++++++---- 4 files changed, 154 insertions(+), 42 deletions(-) diff --git a/.gitignore b/.gitignore index afdbd90..5ed8592 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,6 @@ uploads/ .vibe42-run.log .vibe42-run.pid .env - +package-lock.json .kfu-svod-pw.txt +.kfu-data/ diff --git a/dashboard.html b/dashboard.html index 6ea522f..9a92e1b 100644 --- a/dashboard.html +++ b/dashboard.html @@ -25,12 +25,23 @@ .kfu-dot.yellow { background: var(--kt-ai-warning, var(--kt-ai-warn-token)); } .kfu-dot.red { background: var(--kt-ai-danger); } .kfu-dot.none { background: var(--kt-ai-fg-faint, var(--kt-ai-fg-faint)); } - .kfu-table-wrap { overflow-x: auto; border: 1px solid var(--kt-ai-card-border); border-radius: 12px; background: var(--kt-ai-card-bg); } - table.kfu-t { width: 100%; border-collapse: collapse; font-size: 13px; min-width: 1180px; } - .kfu-t th { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--kt-ai-card-border); font-weight: 600; font-size: 12px; color: var(--kt-ai-fg-muted); white-space: nowrap; background: var(--kt-ai-bg); position: sticky; top: 0; } - .kfu-t td { padding: 10px 12px; border-bottom: 1px solid var(--kt-ai-card-border); vertical-align: top; } + .kfu-table-wrap { border: 1px solid var(--kt-ai-card-border); border-radius: 12px; background: var(--kt-ai-card-bg); } + table.kfu-t { width: 100%; table-layout: fixed; border-collapse: collapse; font-size: 13px; } + .kfu-t th { text-align: left; padding: 8px 8px; border-bottom: 1px solid var(--kt-ai-card-border); font-weight: 600; font-size: 11.5px; color: var(--kt-ai-fg-muted); white-space: nowrap; background: var(--kt-ai-bg); overflow: hidden; text-overflow: ellipsis; } + .kfu-t td { padding: 8px 8px; border-bottom: 1px solid var(--kt-ai-card-border); vertical-align: top; overflow: hidden; text-overflow: clip; } + .kfu-t td.company-cell { white-space: normal; word-break: break-word; } + .kfu-sub { font-size: 12px; color: var(--kt-ai-fg-muted); margin-top: 2px; } + .kfu-toggle { background: none; border: 0; color: var(--kt-ai-primary); cursor: pointer; font-size: 12px; padding: 2px 0; margin-top: 4px; } + .kfu-toggle:hover { text-decoration: underline; } + .kfu-rowdetail { padding: 10px 14px 12px; background: var(--kt-ai-bg); } + .kfu-err { margin-top: 4px; font-size: 11.5px; color: var(--kt-ai-danger); max-width: 320px; } + .kfu-alem-note { font-size: 11px; color: var(--kt-ai-fg-faint, var(--kt-ai-fg-muted)); line-height: 1.55; margin-top: 10px; padding: 8px 12px; background: var(--kt-ai-card-bg); border: 1px dashed var(--kt-ai-card-border); border-radius: 10px; } + .kfu-alem-note code { font-size: 10.5px; color: var(--kt-ai-fg); } + .kfu-rowdetail .kfu-cell { margin-bottom: 6px; font-size: 12.5px; color: var(--kt-ai-fg); } + .kfu-rowdetail .lbl { font-size: 11.5px; color: var(--kt-ai-fg-muted); } .kfu-t tr:last-child td { border-bottom: 0; } - .kfu-t td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; } + .kfu-t td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 12.5px; } + .kfu-t th.num { text-align: right; } .kfu-t td.company { font-weight: 600; white-space: nowrap; max-width: 230px; overflow: hidden; text-overflow: ellipsis; } .kfu-zone { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; white-space: nowrap; } .kfu-flags { font-size: 12px; color: var(--kt-ai-fg-muted); max-width: 260px; } @@ -81,12 +92,15 @@
+ + + + - + - - + @@ -94,21 +108,21 @@ - - +
КомпанияКомпания СтатусКогда загруженКомментарий дочкиЗагружен Долг EBITDA 12М Проц. расходы 12МК1 К2 К3Зона компанииЗамечания агентаЗона
+

Как считается: дочка загружает файл → приложение создаёт сессию в Alem: POST /api/v1/open-api/conversation (заголовок Authorization: Bearer …, body {template_id, title, user_id}) → затем текст отчёта уходит в POST /api/v1/open-api/conversation/{session_id}/send (поле content) → ответ приходит SSE-потоком, итог — в последнем событии message_result.detail.full_content, которое приложение разбирает как JSON. Ключи и template_id задаются в настройках приложения, в код не попадают.

Настройки

-