mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-23 08:58:11 -07:00
next: ai part 3
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
import { createChart } from "../../../../chart/index.js";
|
||||
import { units } from "../../../../chart/units.js";
|
||||
import { colors } from "../../../../utils/colors.js";
|
||||
import { createMetric } from "../../../tools/metrics/index.js";
|
||||
|
||||
/** @typedef {import("../../../storage.js").ChartArtifact} ChartArtifact */
|
||||
|
||||
/** @param {ChartArtifact} artifact */
|
||||
export function createAskChart(artifact) {
|
||||
const section = document.createElement("section");
|
||||
const spec = artifact.chart;
|
||||
|
||||
section.dataset.askChart = "";
|
||||
try {
|
||||
const chart = {
|
||||
title: spec.title,
|
||||
unit: units[spec.unit],
|
||||
defaultType: spec.view,
|
||||
defaultScale: spec.scale,
|
||||
series: spec.series.map((item) => ({
|
||||
label: item.label,
|
||||
color: colors[item.color],
|
||||
metric: createMetric(item.path),
|
||||
})),
|
||||
};
|
||||
section.append(createChart(chart, `ask-${artifact.id}`));
|
||||
} catch {
|
||||
section.dataset.state = "unavailable";
|
||||
section.textContent = "Chart unavailable";
|
||||
}
|
||||
return section;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
main[data-page="ask"] [data-ask-chart] {
|
||||
margin-top: 1rem;
|
||||
|
||||
&[data-state="unavailable"] {
|
||||
color: var(--gray);
|
||||
}
|
||||
|
||||
figure[data-chart="series"] {
|
||||
--chart-plot-height: 16rem;
|
||||
--chart-reserved-ui-height: 5rem;
|
||||
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 48rem) {
|
||||
main[data-page="ask"] [data-ask-chart] figure[data-chart="series"] {
|
||||
--chart-plot-height: 13rem;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
import { renderMarkdown } from "../../markdown.js";
|
||||
import { formatDuration } from "../../timing.js";
|
||||
import { createAskChart } from "./chart/index.js";
|
||||
|
||||
/** @typedef {"user" | "assistant"} MessageRole */
|
||||
|
||||
@@ -15,16 +17,84 @@ export function setMessageContent(content, role, text) {
|
||||
/**
|
||||
* @param {MessageRole} role
|
||||
* @param {string} text
|
||||
* @param {Object} [metadata]
|
||||
* @param {import("../../storage.js").StoredArtifact[]} [metadata.artifacts]
|
||||
* @param {number} [metadata.elapsedMs]
|
||||
* @param {import("../../timing.js").ResponseStep[]} [metadata.steps]
|
||||
*/
|
||||
export function createAskMessage(role, text) {
|
||||
export function createAskMessage(role, text, metadata = {}) {
|
||||
const { artifacts = [], elapsedMs, steps = [] } = metadata;
|
||||
const item = document.createElement("li");
|
||||
const label = document.createElement("strong");
|
||||
const content = document.createElement("div");
|
||||
const responseSteps = role === "assistant"
|
||||
? document.createElement("ol")
|
||||
: undefined;
|
||||
const responseTime = role === "assistant"
|
||||
? document.createElement("small")
|
||||
: undefined;
|
||||
|
||||
/** @param {import("../../storage.js").StoredArtifact[]} nextArtifacts */
|
||||
function setArtifacts(nextArtifacts) {
|
||||
item.querySelectorAll(":scope > [data-ask-chart]").forEach((chart) => {
|
||||
chart.remove();
|
||||
});
|
||||
const charts = nextArtifacts
|
||||
.filter((artifact) => artifact.type === "chart")
|
||||
.map(createAskChart);
|
||||
|
||||
if (responseSteps) responseSteps.before(...charts);
|
||||
else item.append(...charts);
|
||||
}
|
||||
|
||||
/** @param {import("../../timing.js").ResponseStep[]} nextSteps */
|
||||
function setSteps(nextSteps) {
|
||||
if (!responseSteps) return;
|
||||
|
||||
responseSteps.replaceChildren(...nextSteps.map((step) => {
|
||||
const item = document.createElement("li");
|
||||
const name = document.createElement("span");
|
||||
const duration = document.createElement("time");
|
||||
|
||||
name.textContent = step.label;
|
||||
if (step.elapsedMs === undefined) item.dataset.active = "";
|
||||
else duration.textContent = formatDuration(step.elapsedMs);
|
||||
item.append(name, duration);
|
||||
return item;
|
||||
}));
|
||||
responseSteps.hidden = !nextSteps.length;
|
||||
}
|
||||
|
||||
/** @param {number | undefined} nextElapsedMs */
|
||||
function setElapsed(nextElapsedMs) {
|
||||
if (!responseTime) return;
|
||||
|
||||
const visible =
|
||||
typeof nextElapsedMs === "number" &&
|
||||
Number.isFinite(nextElapsedMs) &&
|
||||
nextElapsedMs >= 0;
|
||||
responseTime.hidden = !visible;
|
||||
responseTime.textContent = visible
|
||||
? `${formatDuration(nextElapsedMs)} total`
|
||||
: "";
|
||||
}
|
||||
|
||||
item.dataset.role = role;
|
||||
label.append(role === "user" ? "You" : "Assistant");
|
||||
setMessageContent(content, role, text);
|
||||
item.append(label, content);
|
||||
if (responseSteps) {
|
||||
responseSteps.dataset.responseSteps = "";
|
||||
item.append(responseSteps);
|
||||
}
|
||||
if (responseTime) {
|
||||
responseTime.dataset.responseTime = "";
|
||||
responseTime.title = "Response time";
|
||||
item.append(responseTime);
|
||||
}
|
||||
setArtifacts(artifacts);
|
||||
setSteps(steps);
|
||||
setElapsed(elapsedMs);
|
||||
|
||||
return { item, content };
|
||||
return { item, content, setArtifacts, setSteps, setElapsed };
|
||||
}
|
||||
|
||||
@@ -107,6 +107,32 @@ main[data-page="ask"] [data-ask-conversation] > ol > li {
|
||||
color: color-mix(in oklch, var(--white) 72%, transparent);
|
||||
}
|
||||
}
|
||||
|
||||
> :is(ol[data-response-steps], small[data-response-time]) {
|
||||
color: color-mix(in oklch, var(--white) 38%, transparent);
|
||||
font-size: var(--font-size-xs);
|
||||
font-variant-numeric: tabular-nums;
|
||||
line-height: var(--line-height-xs);
|
||||
}
|
||||
|
||||
> ol[data-response-steps] {
|
||||
display: grid;
|
||||
width: min(100%, 18rem);
|
||||
gap: 0.1rem;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
|
||||
> li {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
gap: 1rem;
|
||||
|
||||
&[data-active] > span::after {
|
||||
content: "…";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 48rem) {
|
||||
|
||||
Reference in New Issue
Block a user