detectkit 0.23.0__tar.gz → 0.23.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {detectkit-0.23.0/detectkit.egg-info → detectkit-0.23.2}/PKG-INFO +1 -1
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/__init__.py +1 -1
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/autotune/html_labeler.py +58 -5
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/autotune/label_server.py +4 -1
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/commands/autotune.py +1 -1
- {detectkit-0.23.0 → detectkit-0.23.2/detectkit.egg-info}/PKG-INFO +1 -1
- {detectkit-0.23.0 → detectkit-0.23.2}/LICENSE +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/MANIFEST.in +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/README.md +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/alerting/__init__.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/alerting/channels/__init__.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/alerting/channels/base.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/alerting/channels/branding.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/alerting/channels/email.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/alerting/channels/factory.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/alerting/channels/mattermost.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/alerting/channels/slack.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/alerting/channels/telegram.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/alerting/channels/webhook.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/alerting/orchestrator/__init__.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/alerting/orchestrator/_base.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/alerting/orchestrator/_cooldown.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/alerting/orchestrator/_decision.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/alerting/orchestrator/_dispatch.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/alerting/orchestrator/_recovery.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/alerting/orchestrator/_types.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/alerting/orchestrator/orchestrator.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/autotune/__init__.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/autotune/_base.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/autotune/_types.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/autotune/autotuner.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/autotune/config_emitter.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/autotune/crossval.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/autotune/detector_select.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/autotune/distribution.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/autotune/grid_search.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/autotune/labels.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/autotune/result.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/autotune/scoring.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/autotune/seasonality_search.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/autotune/settings.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/autotune/window_select.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/__init__.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/_output.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/assets/claude/CLAUDE.section.md +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/assets/claude/rules/alerting.md +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/assets/claude/rules/autotune.md +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/assets/claude/rules/cli.md +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/assets/claude/rules/detectors.md +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/assets/claude/rules/metrics.md +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/assets/claude/rules/overview.md +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/assets/claude/rules/project.md +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/assets/claude/skills/dtk-autotune/SKILL.md +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/assets/claude/skills/dtk-feedback/SKILL.md +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/assets/claude/skills/dtk-new-metric/SKILL.md +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/assets/claude/skills/dtk-setup-project/SKILL.md +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/commands/__init__.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/commands/clean.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/commands/init.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/commands/init_claude.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/commands/run.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/commands/test_alert.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/commands/unlock.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/main.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/config/__init__.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/config/metric_config.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/config/profile.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/config/project_config.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/config/validator.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/core/__init__.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/core/interval.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/core/models.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/database/__init__.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/database/_sql_manager.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/database/clickhouse_manager.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/database/internal_tables/__init__.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/database/internal_tables/_alert_states.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/database/internal_tables/_autotune_runs.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/database/internal_tables/_base.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/database/internal_tables/_datapoints.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/database/internal_tables/_detections.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/database/internal_tables/_maintenance.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/database/internal_tables/_metrics.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/database/internal_tables/_schema.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/database/internal_tables/_tasks.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/database/internal_tables/manager.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/database/manager.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/database/mysql_manager.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/database/postgres_manager.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/database/tables.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/detectors/__init__.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/detectors/base.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/detectors/factory.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/detectors/seasonality.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/detectors/statistical/__init__.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/detectors/statistical/_windowed.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/detectors/statistical/iqr.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/detectors/statistical/mad.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/detectors/statistical/manual_bounds.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/detectors/statistical/zscore.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/loaders/__init__.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/loaders/metric_loader.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/loaders/query_template.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/orchestration/__init__.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/orchestration/error_dispatch.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/orchestration/task_manager/__init__.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/orchestration/task_manager/_alert_step.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/orchestration/task_manager/_base.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/orchestration/task_manager/_detect_step.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/orchestration/task_manager/_load_step.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/orchestration/task_manager/_types.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/orchestration/task_manager/manager.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/utils/__init__.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/utils/datetime_utils.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/utils/env_interpolation.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/utils/json_utils.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit/utils/stats.py +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit.egg-info/SOURCES.txt +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit.egg-info/dependency_links.txt +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit.egg-info/entry_points.txt +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit.egg-info/requires.txt +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/detectkit.egg-info/top_level.txt +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/pyproject.toml +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/requirements.txt +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/setup.cfg +0 -0
- {detectkit-0.23.0 → detectkit-0.23.2}/setup.py +0 -0
|
@@ -4,7 +4,7 @@ detectk - Anomaly Detection for Time-Series Metrics
|
|
|
4
4
|
A Python library for data analysts and engineers to monitor metrics with automatic anomaly detection.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
__version__ = "0.23.
|
|
7
|
+
__version__ = "0.23.2"
|
|
8
8
|
|
|
9
9
|
from detectkit.core.interval import Interval
|
|
10
10
|
from detectkit.core.models import ColumnDefinition, TableModel
|
|
@@ -58,6 +58,11 @@ _TEMPLATE = """<!doctype html>
|
|
|
58
58
|
.brand span { color: var(--faint); font-size: 12px; }
|
|
59
59
|
h1 { font-size: 18px; line-height: 1.3; margin: 0 0 6px; color: var(--paper); font-weight: 600; }
|
|
60
60
|
h1 code { color: var(--clay); font-family: var(--mono); font-size: .82em; }
|
|
61
|
+
.ichip { display:inline-flex; align-items:center; gap:6px; vertical-align: middle; margin-left: 8px;
|
|
62
|
+
font-family: var(--mono); font-size: 12px; font-weight: 500; color: var(--paper);
|
|
63
|
+
background: rgba(209,91,54,0.16); border: 1px solid var(--clay); border-radius: 999px; padding: 3px 10px; }
|
|
64
|
+
.ichip .d { width:6px; height:6px; border-radius:50%; background: var(--clay); }
|
|
65
|
+
.ichip b { color: var(--clay); font-weight: 700; }
|
|
61
66
|
.hint { color: var(--faint); font-size: 13px; margin: 0 0 18px; line-height: 1.55; }
|
|
62
67
|
.hint code, code.k { color: var(--term-text); font-family: var(--mono); font-size: 12px;
|
|
63
68
|
background: var(--term-surface); border: 1px solid var(--term-border); border-radius: 5px; padding: 1px 6px; }
|
|
@@ -106,7 +111,8 @@ _TEMPLATE = """<!doctype html>
|
|
|
106
111
|
<svg viewBox="0 0 100 100" aria-hidden="true"><rect x="3" y="3" width="94" height="94" rx="26" fill="#D15B36"/><polyline points="14,62 36,62 50,22 64,62 86,62" fill="none" stroke="#FBF9F3" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/><circle cx="50" cy="22" r="6.5" fill="#FBF9F3"/></svg>
|
|
107
112
|
<b>detectkit</b><span>· incident labeler</span>
|
|
108
113
|
</div>
|
|
109
|
-
<h1>Label incidents — <code>__METRIC__</code
|
|
114
|
+
<h1>Label incidents — <code>__METRIC__</code><span id="intervalchip" class="ichip"
|
|
115
|
+
title="The metric's sampling interval — the spacing between points, taken straight from the metric."></span></h1>
|
|
110
116
|
<p class="hint">Click-drag across the chart to mark each real incident, add a short description, then
|
|
111
117
|
<b>Export</b>. Save the file into <code class="k">incidents/__METRIC__/</code> and run
|
|
112
118
|
<code class="k">dtk autotune --select __METRIC__ --incidents incidents/__METRIC__/</code></p>
|
|
@@ -138,6 +144,9 @@ const DATA = __PAYLOAD__;
|
|
|
138
144
|
// and Export POSTs straight into incidents/<metric>/. As a static file it is null,
|
|
139
145
|
// and Export falls back to a browser download.
|
|
140
146
|
const SAVE_URL = __SAVE_URL__;
|
|
147
|
+
// The metric's sampling interval (seconds). Passed straight from the metric when
|
|
148
|
+
// known; otherwise inferred from the median spacing of points.
|
|
149
|
+
const INTERVAL_S = __INTERVAL__;
|
|
141
150
|
const pts = DATA.points.map(p => ({ts: Date.parse(p.t.replace(' ','T')+'Z'), v: p.v}));
|
|
142
151
|
const N = pts.length;
|
|
143
152
|
const vraw = pts.filter(p => p.v !== null).map(p => p.v);
|
|
@@ -242,7 +251,35 @@ function draw() {
|
|
|
242
251
|
ctx.fillStyle='rgba(240,173,78,0.28)'; ctx.fillRect(Math.min(x0,x1), M.t*dpr, Math.abs(x1-x0), plotH()); }
|
|
243
252
|
drawSeries(ctx, px, py, viewMin, viewMax, M.l*dpr, plotW(), '#d15b36', 1.5);
|
|
244
253
|
ctx.restore();
|
|
245
|
-
if (
|
|
254
|
+
if (dragging && !ovAct) drawDragLabel();
|
|
255
|
+
else if (hover && !ovAct) drawHover();
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Live time readout while marking/resizing/moving an incident, so you can place
|
|
259
|
+
// an edge precisely (an edge shows old → new; move/new show the resulting span).
|
|
260
|
+
function drawDragLabel() {
|
|
261
|
+
let text, atTs;
|
|
262
|
+
if (dragging.mode==='new') {
|
|
263
|
+
const a=Math.min(dragging.a,dragging.b), b=Math.max(dragging.a,dragging.b);
|
|
264
|
+
text = fmtTs(a)+' → '+fmtTs(b); atTs = dragging.b;
|
|
265
|
+
} else { const iv=incidents[dragging.i]; if (!iv) return;
|
|
266
|
+
if (dragging.mode==='edge') {
|
|
267
|
+
const old = dragging.edge==='a' ? dragging.a0 : dragging.b0;
|
|
268
|
+
const cur = dragging.edge==='a' ? iv.a : iv.b;
|
|
269
|
+
text = (dragging.edge==='a' ? 'start: ' : 'end: ') + fmtTs(old) + ' → ' + fmtTs(cur);
|
|
270
|
+
atTs = cur;
|
|
271
|
+
} else { text = fmtTs(iv.a) + ' → ' + fmtTs(iv.b); atTs = (iv.a+iv.b)/2; }
|
|
272
|
+
}
|
|
273
|
+
const X = clamp(px(atTs), M.l*dpr, c.width-M.r*dpr);
|
|
274
|
+
ctx.font=(11*dpr)+'px ui-monospace, monospace';
|
|
275
|
+
const tw=ctx.measureText(text).width, bw=tw+14*dpr, bh=22*dpr, by=M.t*dpr+2;
|
|
276
|
+
let bx = X - bw/2;
|
|
277
|
+
if (bx < M.l*dpr) bx = M.l*dpr;
|
|
278
|
+
if (bx+bw > c.width-M.r*dpr) bx = c.width-M.r*dpr-bw;
|
|
279
|
+
ctx.fillStyle='rgba(27,25,22,0.96)'; ctx.strokeStyle='#d15b36'; ctx.lineWidth=1*dpr;
|
|
280
|
+
ctx.fillRect(bx, by, bw, bh); ctx.strokeRect(bx, by, bw, bh);
|
|
281
|
+
ctx.fillStyle='#f5f1e8'; ctx.textAlign='left'; ctx.textBaseline='middle';
|
|
282
|
+
ctx.fillText(text, bx+7*dpr, by+bh/2);
|
|
246
283
|
}
|
|
247
284
|
|
|
248
285
|
function drawHover() {
|
|
@@ -309,7 +346,8 @@ c.addEventListener('mousedown', e => {
|
|
|
309
346
|
const hit = hitIncident(e.clientX), t = tsAt(e.clientX);
|
|
310
347
|
if (hit && hit.edge==='move') { const iv=incidents[hit.i];
|
|
311
348
|
dragging={mode:'move', i:hit.i, grab:t, a0:iv.a, b0:iv.b, sx:e.clientX, cx:e.clientX}; }
|
|
312
|
-
else if (hit)
|
|
349
|
+
else if (hit) { const iv=incidents[hit.i];
|
|
350
|
+
dragging={mode:'edge', i:hit.i, edge:hit.edge, a0:iv.a, b0:iv.b, sx:e.clientX, cx:e.clientX}; }
|
|
313
351
|
else dragging={mode:'new', a:t, b:t, sx:e.clientX, cx:e.clientX};
|
|
314
352
|
});
|
|
315
353
|
c.addEventListener('mousemove', e => { if (ovAct) return;
|
|
@@ -426,19 +464,33 @@ function drawAll() { draw(); drawOverview();
|
|
|
426
464
|
function fit() { dpr = window.devicePixelRatio || 1;
|
|
427
465
|
c.width=c.clientWidth*dpr; c.height=c.clientHeight*dpr;
|
|
428
466
|
ov.width=ov.clientWidth*dpr; ov.height=ov.clientHeight*dpr; drawAll(); }
|
|
467
|
+
function fmtInterval(s) { if (s<=0) return '?';
|
|
468
|
+
if (s%86400===0) return (s/86400)+'d'; if (s%3600===0) return (s/3600)+'h';
|
|
469
|
+
if (s%60===0) return (s/60)+'min'; return s+'s'; }
|
|
470
|
+
function medianIntervalSec() { if (N<2) return 0;
|
|
471
|
+
const d=[]; for (let i=1;i<N;i++) d.push(pts[i].ts-pts[i-1].ts);
|
|
472
|
+
d.sort((a,b)=>a-b); return Math.round(d[Math.floor(d.length/2)]/1000); }
|
|
473
|
+
const intervalSec = (typeof INTERVAL_S==='number' && INTERVAL_S>0) ? INTERVAL_S : medianIntervalSec();
|
|
474
|
+
document.getElementById('intervalchip').innerHTML =
|
|
475
|
+
'<span class="d"></span>interval <b>'+fmtInterval(intervalSec)+'</b>';
|
|
429
476
|
window.addEventListener('resize', fit); fit(); render();
|
|
430
477
|
</script>
|
|
431
478
|
"""
|
|
432
479
|
|
|
433
480
|
|
|
434
481
|
def render_labeler_html(
|
|
435
|
-
metric_name: str,
|
|
482
|
+
metric_name: str,
|
|
483
|
+
data: dict[str, np.ndarray],
|
|
484
|
+
*,
|
|
485
|
+
save_url: str | None = None,
|
|
486
|
+
interval_seconds: int | None = None,
|
|
436
487
|
) -> str:
|
|
437
488
|
"""Return a self-contained HTML labeler page for *metric_name*'s series.
|
|
438
489
|
|
|
439
490
|
With ``save_url`` (set by ``dtk autotune --label``'s local server) the page's
|
|
440
491
|
Export button POSTs the labels straight to that endpoint; without it (a static
|
|
441
|
-
file) Export falls back to a browser download.
|
|
492
|
+
file) Export falls back to a browser download. ``interval_seconds`` is the
|
|
493
|
+
metric's sampling interval shown as a chip (inferred from the data if omitted).
|
|
442
494
|
"""
|
|
443
495
|
import json
|
|
444
496
|
|
|
@@ -452,5 +504,6 @@ def render_labeler_html(
|
|
|
452
504
|
return (
|
|
453
505
|
_TEMPLATE.replace("__PAYLOAD__", payload)
|
|
454
506
|
.replace("__SAVE_URL__", json.dumps(save_url))
|
|
507
|
+
.replace("__INTERVAL__", json.dumps(interval_seconds))
|
|
455
508
|
.replace("__METRIC__", metric_name)
|
|
456
509
|
)
|
|
@@ -126,7 +126,10 @@ def build_label_server(
|
|
|
126
126
|
server.incidents_dir = incidents_dir
|
|
127
127
|
server.interval_seconds = interval_seconds
|
|
128
128
|
server.html = render_labeler_html(
|
|
129
|
-
metric_name,
|
|
129
|
+
metric_name,
|
|
130
|
+
data,
|
|
131
|
+
save_url=f"http://127.0.0.1:{port}/save?token={token}",
|
|
132
|
+
interval_seconds=interval_seconds,
|
|
130
133
|
)
|
|
131
134
|
return server, f"http://127.0.0.1:{port}/?token={token}"
|
|
132
135
|
|
|
@@ -348,7 +348,7 @@ def _tune_one(
|
|
|
348
348
|
if label:
|
|
349
349
|
click.echo(click.style(f"Processing metric: {name}", fg="cyan", bold=True))
|
|
350
350
|
if no_serve:
|
|
351
|
-
html = render_labeler_html(name, data)
|
|
351
|
+
html = render_labeler_html(name, data, interval_seconds=interval_seconds)
|
|
352
352
|
out = project_root / "metrics" / f"{metric_path.stem}__labeler.html"
|
|
353
353
|
out.write_text(html, encoding="utf-8")
|
|
354
354
|
click.echo(f" Wrote labeler: {out.relative_to(project_root)}")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/assets/claude/skills/dtk-autotune/SKILL.md
RENAMED
|
File without changes
|
{detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/assets/claude/skills/dtk-feedback/SKILL.md
RENAMED
|
File without changes
|
{detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/assets/claude/skills/dtk-new-metric/SKILL.md
RENAMED
|
File without changes
|
{detectkit-0.23.0 → detectkit-0.23.2}/detectkit/cli/assets/claude/skills/dtk-setup-project/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|