diff --git a/index.html b/index.html
index 2df80cd..ce17f4c 100644
--- a/index.html
+++ b/index.html
@@ -509,16 +509,18 @@ function calcRow(r){
/* Стресс-тест (та же логика, что используется в расчёте): долг вместе с гарантиями +10%, EBITDA −15%, проценты +20%, капитал −5%.
Расчёт — исходный calcRow() на изменённой копии строки; null-значения сохраняются. */
function stressRow(r){
+ /* «Долг вместе с гарантиями +10%» — оба компонента (debt и guar) растут ровно на 10%,
+ поэтому c.debt + c.guar = (r.debt + r.guar) * 1.10 */
+ const d = r.debt==null ? 0 : r.debt;
+ const g = r.guar==null ? 0 : r.guar;
const c = {...r};
- c.debt = (isNum(r.debt) ? r.debt : 0) * 1.10;
+ if(isNum(r.debt)) c.debt = d*1.10; else c.debt = (d+g)*1.10;
+ if(isNum(r.guar)) c.guar = g*1.10;
if(isNum(r.ebitda)) c.ebitda = r.ebitda * 0.85;
if(isNum(r.interest)) c.interest = r.interest * 1.20;
if(isNum(r.equity)) c.equity = r.equity * 0.95;
const res = calcRow(c);
- return {...res, debtStress: res.debt==null?null:+res.debt.toFixed(3),
- ebitdaStress: res.e==null?null:+res.e.toFixed(3),
- interestStress: res.i==null?null:+res.i.toFixed(3),
- equityStress: res.q==null?null:+res.q.toFixed(3)};
+ return {...res};
}
/* ---------- registry ---------- */
@@ -618,7 +620,6 @@ function renderCalc(){
t.innerHTML = h;
$('#kpi').innerHTML = `
${S.registry.length}компаний/периодов
${cnt.green}зелёная зона
${cnt.yellow}жёлтая зона
${cnt.red}красная зона
${cnt.na}без оценки (нет целей/порогов)
`;
}
-function kfmt(v){ if(v==null) return '—'; if(v===Infinity) return '∞'; if(typeof v==='string') return esc(v); return nf2.format(v); }
function zoneChip(z){ const nm = z==='na' ? 'н/д' : ZNAME[z]; return `${nm}`; }
function renderStress(){
const t = $('#stressTable'); if(!t) return;
@@ -626,11 +627,15 @@ function renderStress(){
let h = `| Компания | К1 Долг/EBITDA (база → стресс) | Зона стресс | К2 EBITDA/Проценты (база → стресс) | Зона стресс | К3 Долг/Капитал (база → стресс) | Зона стресс | Итоговая зона (стресс) |
`;
for(const r of S.registry){
const b = calcRow(r), s = stressRow(r);
- const arrow = (base, stress) => `${kfmt(base)} → ${kfmt(stress)}`;
+ const arrow = (base, stress, ebBase, ebStress) => {
+ const fb = base===Infinity ? '∞' : (b.ebNeg?'EBITDA ≤ 0':fmtX(base));
+ const fs = stress===Infinity ? '∞' : (s.ebNeg?'EBITDA ≤ 0':fmtX(stress));
+ return `${fb} → ${fs} | `;
+ };
h += `| ${esc(displayName(r.key,r.name))} |
- ${arrow(b.k1, s.k1)} | ${zoneChip(s.z1)} |
- ${arrow(b.k2, s.k2)} | ${zoneChip(s.z2)} |
- ${arrow(b.k3, s.k3)} | ${zoneChip(s.z3)} |
+ ${arrow(b.k1, s.k1, b.ebNeg, s.ebNeg)}${zoneChip(s.z1)} |
+ ${arrow(b.k2, s.k2, b.ebNeg, s.ebNeg)}${zoneChip(s.z2)} |
+ ${arrow(b.k3, s.k3, false, false)}${zoneChip(s.z3)} |
${zoneChip(s.worst)} |
`;
}
t.innerHTML = h;
@@ -1381,16 +1386,29 @@ $('#btnAiMap').onclick = async () => {
};
/* ===================== AGENT CHAT ===================== */
+/* Готовое экранные отображение (2 знака) + точное значение (6 знаков) — без повторного округления со стороны ИИ */
+const f3 = v => !isNum(v) ? null : +v.toFixed(3);
+const f6 = v => v==null ? null : +v.toFixed(6);
+const k6 = v => (v===Infinity?'inf':f6(v));
+const k2 = v => (v===Infinity?'∞':(v==null?'':nf2.format(v)));
function stressRows(){
- return S.registry.map(r=>({компания: displayName(r.key,r.name), период:r.period, ...stressRow(r)}));
+ return S.registry.map(r=>{ const s=stressRow(r); return {
+ компания: displayName(r.key,r.name), период:r.period,
+ К1:{значение:k6(s.k1), на_экране:s.ebNeg?'EBITDA ≤ 0':k2(s.k1), зона:s.z1},
+ К2:{значение:k6(s.k2), на_экране:s.ebNeg?'EBITDA ≤ 0':k2(s.k2), зона:s.z2},
+ К3:{значение:k6(s.k3), на_экране:k2(s.k3), зона:s.z3},
+ итог:s.worst }; });
}
function agentContext(){
const rows = S.registry.map(r=>{ const c=calcRow(r); return {
компания: displayName(r.key,r.name), период:r.period, источник:r.source,
- долг_млрд:+((r.debt||0)).toFixed(3), гарантии_млрд:+((r.guar||0)).toFixed(3), итого_долг_млрд:+c.debt.toFixed(3),
- ebitda_12м_млрд: isNum(r.ebitda)?+r.ebitda.toFixed(3):null, проценты_12м_млрд:isNum(r.interest)?+r.interest.toFixed(3):null, капитал_млрд:isNum(r.equity)?+r.equity.toFixed(3):null,
- К1: c.ebNeg?'EBITDA<=0':(isNum(c.k1)?+c.k1.toFixed(3):null), К2: c.ebNeg?'EBITDA<=0':(c.k2===Infinity?'inf':(isNum(c.k2)?+c.k2.toFixed(3):null)), К3: isNum(c.k3)?+c.k3.toFixed(3):null,
- цели:{К1:c.p.t1,К2:c.p.t2,К3:c.p.t3}, пороги:{К1:c.p.p1,К2:c.p.p2,К3:c.p.p3}, зоны:{К1:c.z1,К2:c.z2,К3:c.z3,итог:c.worst},
+ долг_млрд:f3((r.debt||0)), гарантии_млрд:f3((r.guar||0)), итого_долг_млрд:f3(c.debt),
+ ebitda_12м_млрд:f3(r.ebitda), проценты_12м_млрд:f3(r.interest), капитал_млрд:f3(r.equity),
+ К1:{значение:c.ebNeg?'EBITDA<=0':k6(c.k1), на_экране:c.ebNeg?'EBITDA ≤ 0':k2(c.k1)},
+ К2:{значение:c.ebNeg?'EBITDA<=0':k6(c.k2), на_экране:c.ebNeg?'EBITDA ≤ 0':k2(c.k2)},
+ К3:{значение:k6(c.k3), на_экране:k2(c.k3)},
+ цели:{К1:c.p.t1,К2:c.p.t2,К3:c.p.t3}, пороги:{К1:c.p.p1,К2:c.p.p2,К3:c.p.p3},
+ зоны:{К1:c.z1,К2:c.z2,К3:c.z3,итог:c.worst},
месяцев:r.months||12, ltm:r.ltm!==false, примечание:r.note||'' }; });
return JSON.stringify(rows);
}
@@ -1402,8 +1420,9 @@ ${$('#methodText').value}
${$('#agentExtra').value.trim()?'Дополнительные указания пользователя: '+$('#agentExtra').value.trim():''}
Данные реестра и расчёта (JSON):
${agentContext()}
-Стресс-тест (уже пересчитан: долг +10%, EBITDA −15%, процентные расходы +20%, капитал −5%) — используй только эти значения, не пересчитывай самостоятельно (JSON):
-${JSON.stringify(stressRows())}`;
+Стресс-тест (уже пересчитан: долг вместе с гарантиями +10%, EBITDA −15%, процентные расходы +20%, капитал −5%) — используй только эти значения, не пересчитывай самостоятельно (JSON):
+${JSON.stringify(stressRows())}
+Правило вывода коэффициентов: при упоминании значений К1–К3 в ответе бери готовые на_экране (2 знака, запятая — десятичный разделитель, «x» не добавлять), не округляй «значение» (6 знаков) самостоятельно; «значение» использовать только для вычислений в формулах.`;
}
function chatAppend(role, text){ const log=$('#chatLog'); const d=document.createElement('div'); d.className='msg '+role; d.textContent=text; log.appendChild(d); log.scrollTop=log.scrollHeight; return d; }
async function chatSend(q){