diff --git a/api/timeline.php b/api/timeline.php index 03f36e0..2561aeb 100644 --- a/api/timeline.php +++ b/api/timeline.php @@ -8,7 +8,7 @@ dbnToolsRequireMethod('POST'); dbnToolsRequireAuth(); $input = dbnToolsJsonInput(1500000); $language = dbnToolsNormalizeLanguage($input['language'] ?? 'en'); -$_validEngines = ['nova_lite', 'azure_mini', 'azure_full']; +$_validEngines = ['nova_lite', 'azure_mini', 'azure_full', 'claude_haiku', 'claude_sonnet']; $_requestedEngine = in_array((string)($input['engine'] ?? ''), $_validEngines, true) ? (string)$input['engine'] : 'azure_mini'; diff --git a/assets/css/tools.css b/assets/css/tools.css index 774a013..b6271fb 100644 --- a/assets/css/tools.css +++ b/assets/css/tools.css @@ -849,6 +849,29 @@ p { font-size: 0.82rem; } +.confidence-low-flag { + color: #d97706; + font-size: 0.88rem; + margin-left: 4px; + vertical-align: middle; + flex-shrink: 0; +} + +.timeline-bullets { + margin: 4px 0 0 0; + padding-left: 1.25em; + list-style: disc; +} + +.timeline-bullet { + margin: 4px 0; + line-height: 1.45; +} + +.timeline-bullet .timeline-excerpt { + margin-top: 2px; +} + .confidence-badge { font-size: 0.7rem; font-weight: 600; diff --git a/assets/js/tools.js b/assets/js/tools.js index d5dc037..23bb7c7 100644 --- a/assets/js/tools.js +++ b/assets/js/tools.js @@ -221,9 +221,9 @@ const REDACT_I18N = { const TIMELINE_I18N = { en: { timelineEngine: 'Engine', - timelineEngineAzureMini: 'Azure gpt-4o-mini', - timelineEngineAzureFull: 'Azure gpt-4o', - timelineEngineHint: 'gpt-4o-mini: 1 credit — fast, handles most timelines well. gpt-4o: 2 credits — higher accuracy for complex multi-actor cases.', + timelineEngineAzureMini: 'Standard', + timelineEngineAzureFull: 'Deep', + timelineEngineHint: 'Standard uses Claude Haiku 4.5 — fast and accurate for most documents (1 credit). Deep uses Claude Sonnet 4.6 — better for complex multi-actor cases (2 credits).', timelineAdvancedToggle: 'Advanced settings', timelineFocus: 'Focus', timelineFocusAll: 'All events', @@ -262,9 +262,9 @@ const TIMELINE_I18N = { }, no: { timelineEngine: 'Motor', - timelineEngineAzureMini: 'Azure gpt-4o-mini', - timelineEngineAzureFull: 'Azure gpt-4o', - timelineEngineHint: 'gpt-4o-mini: 1 kreditt — rask, håndterer de fleste tidslinjer godt. gpt-4o: 2 kreditter — høyere nøyaktighet for komplekse saker med mange aktører.', + timelineEngineAzureMini: 'Standard', + timelineEngineAzureFull: 'Dyp', + timelineEngineHint: 'Standard bruker Claude Haiku 4.5 — rask og nøyaktig for de fleste dokumenter (1 kreditt). Dyp bruker Claude Sonnet 4.6 — bedre for komplekse saker med mange aktører (2 kreditter).', timelineAdvancedToggle: 'Avanserte innstillinger', timelineFocus: 'Fokus', timelineFocusAll: 'Alle hendelser', @@ -303,9 +303,9 @@ const TIMELINE_I18N = { }, uk: { timelineEngine: 'Рушій', - timelineEngineAzureMini: 'Azure gpt-4o-mini', - timelineEngineAzureFull: 'Azure gpt-4o', - timelineEngineHint: 'gpt-4o-mini: 1 кредит — швидко, добре справляється з більшістю хронологій. gpt-4o: 2 кредити — вища точність для складних справ з багатьма учасниками.', + timelineEngineAzureMini: 'Стандарт', + timelineEngineAzureFull: 'Глибокий', + timelineEngineHint: 'Стандарт використовує Claude Haiku 4.5 — швидко і точно для більшості документів (1 кредит). Глибокий використовує Claude Sonnet 4.6 — краще для складних справ (2 кредити).', timelineAdvancedToggle: 'Розширені налаштування', timelineFocus: 'Фокус', timelineFocusAll: 'Всі події', @@ -344,9 +344,9 @@ const TIMELINE_I18N = { }, pl: { timelineEngine: 'Silnik', - timelineEngineAzureMini: 'Azure gpt-4o-mini', - timelineEngineAzureFull: 'Azure gpt-4o', - timelineEngineHint: 'gpt-4o-mini: 1 kredyt — szybki, sprawdza się w większości osi czasu. gpt-4o: 2 kredyty — wyższa dokładność dla złożonych spraw z wieloma uczestnikami.', + timelineEngineAzureMini: 'Standard', + timelineEngineAzureFull: 'Zaawansowany', + timelineEngineHint: 'Standard używa Claude Haiku 4.5 — szybki i dokładny dla większości dokumentów (1 kredyt). Zaawansowany używa Claude Sonnet 4.6 — lepszy dla złożonych spraw z wieloma uczestnikami (2 kredyty).', timelineAdvancedToggle: 'Ustawienia zaawansowane', timelineFocus: 'Fokus', timelineFocusAll: 'Wszystkie zdarzenia', @@ -1854,38 +1854,89 @@ function renderTimeline(events, grouped = false) { } return '
No matching events.
'; } - const MONTH_NAMES = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; + const MONTHS = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; + function fmtDate(d) { + if (!d || !/^\d{4}-\d{2}-\d{2}/.test(d)) return d || 'unknown'; + const [y, m, day] = d.split('-'); + return `${parseInt(day, 10)} ${MONTHS[parseInt(m, 10) - 1] || m} ${y}`; + } + // Group consecutive events with the same date + actor into one card + const groups = []; + for (const ev of events) { + const key = `${ev.date || ''}||${ev.actor || ''}`; + const last = groups[groups.length - 1]; + if (last && last.key === key) { + last.events.push(ev); + } else { + groups.push({ key, date: ev.date || '', actor: ev.actor || '', events: [ev] }); + } + } + const CONF_RANK = { high: 0, medium: 1, low: 2 }; let lastGroupKey = null; - const items = events.map((ev) => { - const conf = ev.confidence || 'medium'; - let groupHeader = ''; - if (grouped && /^\d{4}-\d{2}/.test(ev.date || '')) { - const year = ev.date.slice(0, 4); - const mon = ev.date.slice(5, 7); + const items = groups.map((grp) => { + let monthHeader = ''; + if (grouped && /^\d{4}-\d{2}/.test(grp.date)) { + const year = grp.date.slice(0, 4); + const mon = grp.date.slice(5, 7); const key = `${year}-${mon}`; if (key !== lastGroupKey) { const prevYear = lastGroupKey ? lastGroupKey.slice(0, 4) : null; - const label = (year !== prevYear) + const label = year !== prevYear ? year - : `${MONTH_NAMES[parseInt(mon, 10) - 1] || mon} ${year}`; - groupHeader = `${escapeHtml(ev.event || '')}
+ ${excerptHtml} +${escapeHtml(ev.event || '')}
- ${excerptHtml} + ${escapeHtml(grp.actor || 'unknown actor')} +Quick uses Amazon Bedrock nova-lite (fast, cheap). Standard and Deep use Azure OpenAI.
+Standard uses Claude Haiku 4.5 — fast and accurate for most documents. Deep uses Claude Sonnet 4.6 — better for complex multi-actor cases.