This adds some new visualizations and styles and reports and cleans up some existing styles and class names. Daily activity rhythm <img width="1588" height="412" alt="image" src="https://github.com/user-attachments/assets/0c7980e4-7bb6-4e08-9957-24c3c5718572" /> Helping new members <img width="1456" height="310" alt="image" src="https://github.com/user-attachments/assets/096a13da-ab63-45d4-9b68-53a01df62a78" /> Chat activity <img width="1442" height="926" alt="image" src="https://github.com/user-attachments/assets/07ce2cab-1963-4918-a9ff-805c251a1377" /> Assigns <img width="1388" height="844" alt="image" src="https://github.com/user-attachments/assets/ee49c6ee-2da6-4bfa-b500-715ed7ceb13a" /> AI usage <img width="1442" height="1254" alt="image" src="https://github.com/user-attachments/assets/b382bffb-010d-4072-9144-cb7e6a8680e3" /> Invitations <img width="1486" height="1346" alt="image" src="https://github.com/user-attachments/assets/020f68a9-69d2-46ed-9f38-b0d5e98d02de" /> Writing analysis <img width="917" height="409" alt="image" src="https://github.com/user-attachments/assets/1147427c-513f-4737-8f28-99bfc6f4aff9" /> --------- Co-authored-by: awesomerobot <[email protected]> Co-authored-by: Martin Brennan <[email protected]>
177 lines
5.3 KiB
Plaintext
177 lines
5.3 KiB
Plaintext
import Component from "@glimmer/component";
|
|
import { get } from "@ember/helper";
|
|
import { action } from "@ember/object";
|
|
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
|
import willDestroy from "@ember/render-modifiers/modifiers/will-destroy";
|
|
import { service } from "@ember/service";
|
|
import number from "discourse/helpers/number";
|
|
import { i18n } from "discourse-i18n";
|
|
|
|
export default class AiUsage extends Component {
|
|
@service currentUser;
|
|
|
|
matrixInterval = null;
|
|
|
|
get totalRequests() {
|
|
return this.args.report.data.total_requests ?? 0;
|
|
}
|
|
|
|
get totalTokens() {
|
|
return this.args.report.data.total_tokens ?? 0;
|
|
}
|
|
|
|
get successRate() {
|
|
return this.args.report.data.success_rate ?? 0;
|
|
}
|
|
|
|
get featureUsage() {
|
|
return Object.entries(this.args.report.data.feature_usage ?? {})
|
|
.filter(([name]) => name && name.trim().length > 0)
|
|
.slice(0, 3);
|
|
}
|
|
|
|
get modelUsage() {
|
|
return Object.entries(this.args.report.data.model_usage ?? {})
|
|
.filter(([name]) => name && name.trim().length > 0)
|
|
.slice(0, 3);
|
|
}
|
|
|
|
@action
|
|
formatFeatureName(featureName) {
|
|
return featureName.replace(/_/g, " ");
|
|
}
|
|
|
|
@action
|
|
setupMatrix(element) {
|
|
const canvas = element;
|
|
const ctx = canvas.getContext("2d");
|
|
|
|
canvas.width = element.offsetWidth;
|
|
canvas.height = element.offsetHeight;
|
|
|
|
const characters =
|
|
"01アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン";
|
|
const fontSize = 14;
|
|
const columns = Math.floor(canvas.width / fontSize);
|
|
const drops = Array(columns).fill(1);
|
|
|
|
const draw = () => {
|
|
ctx.fillStyle = "rgba(0, 0, 0, 0.05)";
|
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
|
|
ctx.fillStyle = "#0f0";
|
|
ctx.font = `${fontSize}px monospace`;
|
|
|
|
for (let i = 0; i < drops.length; i++) {
|
|
const char = characters[Math.floor(Math.random() * characters.length)];
|
|
const x = i * fontSize;
|
|
const y = drops[i] * fontSize;
|
|
|
|
ctx.fillText(char, x, y);
|
|
|
|
if (y > canvas.height && Math.random() > 0.975) {
|
|
drops[i] = 0;
|
|
}
|
|
|
|
drops[i]++;
|
|
}
|
|
};
|
|
|
|
this.matrixInterval = setInterval(draw, 33);
|
|
}
|
|
|
|
@action
|
|
cleanupMatrix() {
|
|
if (this.matrixInterval) {
|
|
clearInterval(this.matrixInterval);
|
|
}
|
|
}
|
|
|
|
<template>
|
|
<div class="rewind-report-page --ai-usage">
|
|
<div class="matrix-container">
|
|
<canvas
|
|
class="matrix-rain"
|
|
{{didInsert this.setupMatrix}}
|
|
{{willDestroy this.cleanupMatrix}}
|
|
></canvas>
|
|
|
|
<div class="matrix-content">
|
|
<h2 class="matrix-title">
|
|
<div class="matrix-subhead">
|
|
{{i18n
|
|
"discourse_rewind.reports.ai_usage.wake_up"
|
|
username=this.currentUser.username
|
|
}}
|
|
</div>
|
|
{{i18n "discourse_rewind.reports.ai_usage.system_title"}}
|
|
</h2>
|
|
|
|
<div class="matrix-stats">
|
|
<div class="matrix-stat">
|
|
<div class="matrix-stat__label">
|
|
{{i18n "discourse_rewind.reports.ai_usage.total_requests"}}
|
|
</div>
|
|
<div class="matrix-stat__value">
|
|
{{number this.totalRequests}}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="matrix-stat">
|
|
<div class="matrix-stat__label">
|
|
{{i18n "discourse_rewind.reports.ai_usage.total_tokens"}}
|
|
</div>
|
|
<div class="matrix-stat__value">{{number this.totalTokens}}</div>
|
|
</div>
|
|
|
|
<div class="matrix-stat">
|
|
<div class="matrix-stat__label">
|
|
{{i18n "discourse_rewind.reports.ai_usage.success_rate"}}
|
|
</div>
|
|
<div class="matrix-stat__value">
|
|
<span class="number">
|
|
{{this.successRate}}%
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{#if this.featureUsage.length}}
|
|
<div class="matrix-section">
|
|
<div class="matrix-section__title">>
|
|
{{i18n "discourse_rewind.reports.ai_usage.section_features"}}
|
|
</div>
|
|
<div class="matrix-list">
|
|
{{#each this.featureUsage as |entry|}}
|
|
<div class="matrix-list__item">
|
|
<span class="matrix-list__name">
|
|
{{this.formatFeatureName (get entry "0")}}
|
|
</span>
|
|
<span class="matrix-list__count">{{get entry "1"}}</span>
|
|
</div>
|
|
{{/each}}
|
|
</div>
|
|
</div>
|
|
{{/if}}
|
|
|
|
{{#if this.modelUsage.length}}
|
|
<div class="matrix-section">
|
|
<div class="matrix-section__title">>
|
|
{{i18n "discourse_rewind.reports.ai_usage.section_models"}}
|
|
</div>
|
|
<div class="matrix-list">
|
|
{{#each this.modelUsage as |entry|}}
|
|
<div class="matrix-list__item">
|
|
<span class="matrix-list__name">{{get entry "0"}}</span>
|
|
<span class="matrix-list__count">{{get entry "1"}}</span>
|
|
</div>
|
|
{{/each}}
|
|
</div>
|
|
</div>
|
|
{{/if}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
}
|