DEV: First version

showing message bus error, but it kinda works? wip on a fix.
This commit is contained in:
Keegan George 2024-11-12 20:42:19 -08:00
parent 9551b1a4d1
commit 3ce8d943a7
No known key found for this signature in database
GPG Key ID: 91B40E38537AC000
2 changed files with 71 additions and 42 deletions

View File

@ -19,8 +19,7 @@ import I18n from "discourse-i18n";
import DMenu from "float-kit/components/d-menu"; import DMenu from "float-kit/components/d-menu";
import DTooltip from "float-kit/components/d-tooltip"; import DTooltip from "float-kit/components/d-tooltip";
import AiSummarySkeleton from "../../components/ai-summary-skeleton"; import AiSummarySkeleton from "../../components/ai-summary-skeleton";
import smoothStreamText from "../../modifiers/smooth-stream-text";
const STREAMED_TEXT_SPEED = 15;
export default class AiSummaryBox extends Component { export default class AiSummaryBox extends Component {
@service siteSettings; @service siteSettings;
@ -36,10 +35,7 @@ export default class AiSummaryBox extends Component {
@tracked canRegenerate = false; @tracked canRegenerate = false;
@tracked loading = false; @tracked loading = false;
@tracked isStreaming = false; @tracked isStreaming = false;
@tracked streamedText = ""; @tracked haltAnimation = false;
@tracked currentIndex = 0;
typingTimer = null;
streamedTextLength = 0;
get outdatedSummaryWarningText() { get outdatedSummaryWarningText() {
let outdatedText = I18n.t("summary.outdated"); let outdatedText = I18n.t("summary.outdated");
@ -55,8 +51,6 @@ export default class AiSummaryBox extends Component {
} }
resetSummary() { resetSummary() {
this.streamedText = "";
this.currentIndex = 0;
this.text = ""; this.text = "";
this.summarizedOn = null; this.summarizedOn = null;
this.summarizedBy = null; this.summarizedBy = null;
@ -145,26 +139,6 @@ export default class AiSummaryBox extends Component {
}); });
} }
typeCharacter() {
if (this.streamedTextLength < this.text.length) {
this.streamedText += this.text.charAt(this.streamedTextLength);
this.streamedTextLength++;
this.typingTimer = later(this, this.typeCharacter, STREAMED_TEXT_SPEED);
} else {
this.typingTimer = null;
}
}
onTextUpdate() {
// Reset only if theres a new summary to process
if (this.typingTimer) {
cancel(this.typingTimer);
}
this.typeCharacter();
}
@bind @bind
async _updateSummary(update) { async _updateSummary(update) {
const topicSummary = { const topicSummary = {
@ -173,13 +147,13 @@ export default class AiSummaryBox extends Component {
...update.ai_topic_summary, ...update.ai_topic_summary,
}; };
const newText = topicSummary.raw || ""; const newText = topicSummary.raw || "";
this.text = newText;
this.loading = false; this.loading = false;
if (update.done) { if (update.done) {
this.text = newText; this.text = newText;
this.streamedText = newText;
this.displayedTextLength = newText.length;
this.isStreaming = false; this.isStreaming = false;
this.haltAnimation = true;
this.summarizedOn = shortDateNoYear( this.summarizedOn = shortDateNoYear(
moment(topicSummary.updated_at, "YYYY-MM-DD HH:mm:ss Z") moment(topicSummary.updated_at, "YYYY-MM-DD HH:mm:ss Z")
); );
@ -187,16 +161,6 @@ export default class AiSummaryBox extends Component {
this.newPostsSinceSummary = topicSummary.new_posts_since_summary; this.newPostsSinceSummary = topicSummary.new_posts_since_summary;
this.outdated = topicSummary.outdated; this.outdated = topicSummary.outdated;
this.canRegenerate = topicSummary.outdated && topicSummary.can_regenerate; this.canRegenerate = topicSummary.outdated && topicSummary.can_regenerate;
// Clear pending animations
if (this.typingTimer) {
cancel(this.typingTimer);
this.typingTimer = null;
}
} else if (newText.length > this.text.length) {
this.text = newText;
this.isStreaming = true;
this.onTextUpdate();
} }
} }
@ -260,8 +224,13 @@ export default class AiSummaryBox extends Component {
{{#if this.loading}} {{#if this.loading}}
<AiSummarySkeleton /> <AiSummarySkeleton />
{{else}} {{else}}
<div class="generated-summary cooked"> <div
<CookText @rawText={{this.streamedText}} /> class="generated-summary"
{{smoothStreamText this.text this.haltAnimation}}
>
{{#if this.haltAnimation}}
<CookText @rawText={{this.text}} />
{{/if}}
</div> </div>
{{#if this.summarizedOn}} {{#if this.summarizedOn}}
<div class="summarized-on"> <div class="summarized-on">

View File

@ -0,0 +1,60 @@
import { cancel, later } from "@ember/runloop";
import { htmlSafe } from "@ember/template";
import Modifier from "ember-modifier";
import { cook } from "discourse/lib/text";
const STREAMED_TEXT_SPEED = 15;
export default class SmoothStreamTextModifier extends Modifier {
typingTimer = null;
displayedText = "";
modify(element, [text, haltAnimation]) {
if (haltAnimation) {
return;
}
this._startTypingAnimation(element, text);
}
async _startTypingAnimation(element, text) {
if (this.typingTimer) {
cancel(this.typingTimer);
}
if (this.displayedText.length === 0) {
element.innerHTML = "";
}
this._typeCharacter(element, text);
}
async _typeCharacter(element, text) {
if (this.displayedText.length < text.length) {
this.displayedText += text.charAt(this.displayedText.length);
try {
const cookedText = await cook(this.displayedText);
element.classList.add("cooked");
element.innerHTML = htmlSafe(cookedText);
} catch (error) {
console.error("Error cooking text during typing: ", error);
}
this.typingTimer = later(
this,
this._typeCharacter,
element,
text,
STREAMED_TEXT_SPEED
);
} else {
this.typingTimer = null;
}
}
willRemove() {
if (this.typingTimer) {
cancel(this.typingTimer);
}
}
}