mirror of
https://github.com/discourse/discourse-ai.git
synced 2025-06-30 19:42:17 +00:00
UX: Use new DStatTiles reusable component from core (#1025)
For the Spam and Usage tabs in admin
This commit is contained in:
parent
94b85ece80
commit
222e2cf4f9
@ -6,6 +6,7 @@ import { action } from "@ember/object";
|
|||||||
import { LinkTo } from "@ember/routing";
|
import { LinkTo } from "@ember/routing";
|
||||||
import { service } from "@ember/service";
|
import { service } from "@ember/service";
|
||||||
import DButton from "discourse/components/d-button";
|
import DButton from "discourse/components/d-button";
|
||||||
|
import DStatTiles from "discourse/components/d-stat-tiles";
|
||||||
import DToggleSwitch from "discourse/components/d-toggle-switch";
|
import DToggleSwitch from "discourse/components/d-toggle-switch";
|
||||||
import DTooltip from "discourse/components/d-tooltip";
|
import DTooltip from "discourse/components/d-tooltip";
|
||||||
import withEventValue from "discourse/helpers/with-event-value";
|
import withEventValue from "discourse/helpers/with-event-value";
|
||||||
@ -121,7 +122,7 @@ export default class AiSpam extends Component {
|
|||||||
|
|
||||||
get metrics() {
|
get metrics() {
|
||||||
const detected = {
|
const detected = {
|
||||||
label: "discourse_ai.spam.spam_detected",
|
label: i18n("discourse_ai.spam.spam_detected"),
|
||||||
value: this.stats.spam_detected,
|
value: this.stats.spam_detected,
|
||||||
};
|
};
|
||||||
if (this.args.model.flagging_username) {
|
if (this.args.model.flagging_username) {
|
||||||
@ -131,17 +132,19 @@ export default class AiSpam extends Component {
|
|||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
label: "discourse_ai.spam.scanned_count",
|
label: i18n("discourse_ai.spam.scanned_count"),
|
||||||
value: this.stats.scanned_count,
|
value: this.stats.scanned_count,
|
||||||
},
|
},
|
||||||
detected,
|
detected,
|
||||||
{
|
{
|
||||||
label: "discourse_ai.spam.false_positives",
|
label: i18n("discourse_ai.spam.false_positives"),
|
||||||
value: this.stats.false_positives,
|
value: this.stats.false_positives,
|
||||||
|
tooltip: i18n("discourse_ai.spam.stat_tooltips.incorrectly_flagged"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "discourse_ai.spam.false_negatives",
|
label: i18n("discourse_ai.spam.false_negatives"),
|
||||||
value: this.stats.false_negatives,
|
value: this.stats.false_negatives,
|
||||||
|
tooltip: i18n("discourse_ai.spam.stat_tooltips.missed_spam"),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -220,22 +223,16 @@ export default class AiSpam extends Component {
|
|||||||
class="ai-spam__stats"
|
class="ai-spam__stats"
|
||||||
>
|
>
|
||||||
<:content>
|
<:content>
|
||||||
<div class="ai-spam__metrics">
|
<DStatTiles as |tiles|>
|
||||||
{{#each this.metrics as |metric|}}
|
{{#each this.metrics as |metric|}}
|
||||||
<div class="ai-spam__metrics-item">
|
<tiles.Tile
|
||||||
<span class="ai-spam__metrics-label">{{i18n
|
@label={{metric.label}}
|
||||||
metric.label
|
@url={{metric.href}}
|
||||||
}}</span>
|
@value={{metric.value}}
|
||||||
{{#if metric.href}}
|
@tooltip={{metric.tooltip}}
|
||||||
<a href={{metric.href}} class="ai-spam__metrics-value">
|
/>
|
||||||
{{metric.value}}
|
|
||||||
</a>
|
|
||||||
{{else}}
|
|
||||||
<span class="ai-spam__metrics-value">{{metric.value}}</span>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</DStatTiles>
|
||||||
</:content>
|
</:content>
|
||||||
</AdminConfigAreaCard>
|
</AdminConfigAreaCard>
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,6 +7,7 @@ import { service } from "@ember/service";
|
|||||||
import { eq, gt, lt } from "truth-helpers";
|
import { eq, gt, lt } from "truth-helpers";
|
||||||
import ConditionalLoadingSpinner from "discourse/components/conditional-loading-spinner";
|
import ConditionalLoadingSpinner from "discourse/components/conditional-loading-spinner";
|
||||||
import DButton from "discourse/components/d-button";
|
import DButton from "discourse/components/d-button";
|
||||||
|
import DStatTiles from "discourse/components/d-stat-tiles";
|
||||||
import DateTimeInputRange from "discourse/components/date-time-input-range";
|
import DateTimeInputRange from "discourse/components/date-time-input-range";
|
||||||
import avatar from "discourse/helpers/avatar";
|
import avatar from "discourse/helpers/avatar";
|
||||||
import concatClass from "discourse/helpers/concat-class";
|
import concatClass from "discourse/helpers/concat-class";
|
||||||
@ -124,6 +125,36 @@ export default class AiUsage extends Component {
|
|||||||
return normalized;
|
return normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get metrics() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: i18n("discourse_ai.usage.total_requests"),
|
||||||
|
value: this.data.summary.total_requests,
|
||||||
|
tooltip: i18n("discourse_ai.usage.stat_tooltips.total_requests"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: i18n("discourse_ai.usage.total_tokens"),
|
||||||
|
value: this.data.summary.total_tokens,
|
||||||
|
tooltip: i18n("discourse_ai.usage.stat_tooltips.total_tokens"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: i18n("discourse_ai.usage.request_tokens"),
|
||||||
|
value: this.data.summary.total_request_tokens,
|
||||||
|
tooltip: i18n("discourse_ai.usage.stat_tooltips.request_tokens"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: i18n("discourse_ai.usage.response_tokens"),
|
||||||
|
value: this.data.summary.total_response_tokens,
|
||||||
|
tooltip: i18n("discourse_ai.usage.stat_tooltips.response_tokens"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: i18n("discourse_ai.usage.cached_tokens"),
|
||||||
|
value: this.data.summary.total_cached_tokens,
|
||||||
|
tooltip: i18n("discourse_ai.usage.stat_tooltips.cached_tokens"),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
get chartConfig() {
|
get chartConfig() {
|
||||||
if (!this.data?.data) {
|
if (!this.data?.data) {
|
||||||
return;
|
return;
|
||||||
@ -344,53 +375,16 @@ export default class AiUsage extends Component {
|
|||||||
class="ai-usage__summary"
|
class="ai-usage__summary"
|
||||||
>
|
>
|
||||||
<:content>
|
<:content>
|
||||||
<div class="ai-usage__summary-stats">
|
<DStatTiles as |tiles|>
|
||||||
<div class="ai-usage__summary-stat">
|
{{#each this.metrics as |metric|}}
|
||||||
<span class="label">{{i18n
|
<tiles.Tile
|
||||||
"discourse_ai.usage.total_requests"
|
@label={{metric.label}}
|
||||||
}}</span>
|
@href={{metric.href}}
|
||||||
<span
|
@value={{metric.value}}
|
||||||
class="value"
|
@tooltip={{metric.tooltip}}
|
||||||
title={{this.data.summary.total_requests}}
|
/>
|
||||||
>{{number this.data.summary.total_requests}}</span>
|
{{/each}}
|
||||||
</div>
|
</DStatTiles>
|
||||||
<div class="ai-usage__summary-stat">
|
|
||||||
<span class="label">{{i18n
|
|
||||||
"discourse_ai.usage.total_tokens"
|
|
||||||
}}</span>
|
|
||||||
<span
|
|
||||||
class="value"
|
|
||||||
title={{this.data.summary.total_tokens}}
|
|
||||||
>{{number this.data.summary.total_tokens}}</span>
|
|
||||||
</div>
|
|
||||||
<div class="ai-usage__summary-stat">
|
|
||||||
<span class="label">{{i18n
|
|
||||||
"discourse_ai.usage.request_tokens"
|
|
||||||
}}</span>
|
|
||||||
<span
|
|
||||||
class="value"
|
|
||||||
title={{this.data.summary.total_request_tokens}}
|
|
||||||
>{{number this.data.summary.total_request_tokens}}</span>
|
|
||||||
</div>
|
|
||||||
<div class="ai-usage__summary-stat">
|
|
||||||
<span class="label">{{i18n
|
|
||||||
"discourse_ai.usage.response_tokens"
|
|
||||||
}}</span>
|
|
||||||
<span
|
|
||||||
class="value"
|
|
||||||
title={{this.data.summary.total_response_tokens}}
|
|
||||||
>{{number this.data.summary.total_response_tokens}}</span>
|
|
||||||
</div>
|
|
||||||
<div class="ai-usage__summary-stat">
|
|
||||||
<span class="label">{{i18n
|
|
||||||
"discourse_ai.usage.cached_tokens"
|
|
||||||
}}</span>
|
|
||||||
<span
|
|
||||||
class="value"
|
|
||||||
title={{this.data.summary.total_cached_tokens}}
|
|
||||||
>{{number this.data.summary.total_cached_tokens}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</:content>
|
</:content>
|
||||||
</AdminConfigAreaCard>
|
</AdminConfigAreaCard>
|
||||||
|
|
||||||
|
@ -45,37 +45,6 @@
|
|||||||
&__stats {
|
&__stats {
|
||||||
margin-top: 2em;
|
margin-top: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__stats-title {
|
|
||||||
margin-bottom: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__metrics {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
||||||
gap: 1em;
|
|
||||||
margin-bottom: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__metrics-item {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
padding: 1em;
|
|
||||||
background: var(--primary-very-low);
|
|
||||||
border-radius: 0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__metrics-label {
|
|
||||||
color: var(--primary-medium);
|
|
||||||
font-size: 0.875em;
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__metrics-value {
|
|
||||||
color: var(--primary);
|
|
||||||
font-size: 1.5em;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.spam-test-modal {
|
.spam-test-modal {
|
||||||
|
@ -68,32 +68,6 @@
|
|||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__summary-stats {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
||||||
gap: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__summary-stat {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
padding: 1em;
|
|
||||||
background: var(--primary-very-low);
|
|
||||||
border-radius: 0.25em;
|
|
||||||
|
|
||||||
.label {
|
|
||||||
color: var(--primary-medium);
|
|
||||||
font-size: 0.875em;
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.value {
|
|
||||||
color: var(--primary);
|
|
||||||
font-size: 1.5em;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__charts {
|
&__charts {
|
||||||
margin-top: 2em;
|
margin-top: 2em;
|
||||||
}
|
}
|
||||||
|
@ -157,6 +157,9 @@ en:
|
|||||||
run: "Run test"
|
run: "Run test"
|
||||||
spam: "Spam"
|
spam: "Spam"
|
||||||
not_spam: "Not spam"
|
not_spam: "Not spam"
|
||||||
|
stat_tooltips:
|
||||||
|
incorrectly_flagged: "Items that the AI bot flagged as spam where moderators disagreed"
|
||||||
|
missed_spam: "Items flagged by the community as spam that were not detected by the AI bot, which moderators agreed with"
|
||||||
|
|
||||||
usage:
|
usage:
|
||||||
short_title: "Usage"
|
short_title: "Usage"
|
||||||
@ -182,6 +185,12 @@ en:
|
|||||||
no_models: "No model usage data found"
|
no_models: "No model usage data found"
|
||||||
no_features: "No feature usage data found"
|
no_features: "No feature usage data found"
|
||||||
subheader_description: "Tokens are the basic units that LLMs use to understand and generate text, usage data may affect costs."
|
subheader_description: "Tokens are the basic units that LLMs use to understand and generate text, usage data may affect costs."
|
||||||
|
stat_tooltips:
|
||||||
|
total_requests: "All requests made to LLMs through Discourse"
|
||||||
|
total_tokens: "All the tokens used when prompting an LLM"
|
||||||
|
request_tokens: "Tokens used when the LLM tries to understand what you are saying"
|
||||||
|
response_tokens: "Tokens used when the LLM responds to your prompt"
|
||||||
|
cached_tokens: "Previously processed request tokens that the LLM reuses to optimize performance and cost"
|
||||||
periods:
|
periods:
|
||||||
last_day: "Last 24 hours"
|
last_day: "Last 24 hours"
|
||||||
last_week: "Last week"
|
last_week: "Last week"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user