Skip to content

Commit 3ce8d94

Browse files
committed
DEV: First version
showing message bus error, but it kinda works? wip on a fix.
1 parent 9551b1a commit 3ce8d94

File tree

2 files changed

+71
-42
lines changed

2 files changed

+71
-42
lines changed

assets/javascripts/discourse/connectors/topic-map-expanded-after/ai-summary-box.gjs

Lines changed: 11 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ import I18n from "discourse-i18n";
1919
import DMenu from "float-kit/components/d-menu";
2020
import DTooltip from "float-kit/components/d-tooltip";
2121
import AiSummarySkeleton from "../../components/ai-summary-skeleton";
22-
23-
const STREAMED_TEXT_SPEED = 15;
22+
import smoothStreamText from "../../modifiers/smooth-stream-text";
2423

2524
export default class AiSummaryBox extends Component {
2625
@service siteSettings;
@@ -36,10 +35,7 @@ export default class AiSummaryBox extends Component {
3635
@tracked canRegenerate = false;
3736
@tracked loading = false;
3837
@tracked isStreaming = false;
39-
@tracked streamedText = "";
40-
@tracked currentIndex = 0;
41-
typingTimer = null;
42-
streamedTextLength = 0;
38+
@tracked haltAnimation = false;
4339

4440
get outdatedSummaryWarningText() {
4541
let outdatedText = I18n.t("summary.outdated");
@@ -55,8 +51,6 @@ export default class AiSummaryBox extends Component {
5551
}
5652

5753
resetSummary() {
58-
this.streamedText = "";
59-
this.currentIndex = 0;
6054
this.text = "";
6155
this.summarizedOn = null;
6256
this.summarizedBy = null;
@@ -145,26 +139,6 @@ export default class AiSummaryBox extends Component {
145139
});
146140
}
147141

148-
typeCharacter() {
149-
if (this.streamedTextLength < this.text.length) {
150-
this.streamedText += this.text.charAt(this.streamedTextLength);
151-
this.streamedTextLength++;
152-
153-
this.typingTimer = later(this, this.typeCharacter, STREAMED_TEXT_SPEED);
154-
} else {
155-
this.typingTimer = null;
156-
}
157-
}
158-
159-
onTextUpdate() {
160-
// Reset only if there’s a new summary to process
161-
if (this.typingTimer) {
162-
cancel(this.typingTimer);
163-
}
164-
165-
this.typeCharacter();
166-
}
167-
168142
@bind
169143
async _updateSummary(update) {
170144
const topicSummary = {
@@ -173,30 +147,20 @@ export default class AiSummaryBox extends Component {
173147
...update.ai_topic_summary,
174148
};
175149
const newText = topicSummary.raw || "";
150+
this.text = newText;
176151
this.loading = false;
177152

178153
if (update.done) {
179154
this.text = newText;
180-
this.streamedText = newText;
181-
this.displayedTextLength = newText.length;
182155
this.isStreaming = false;
156+
this.haltAnimation = true;
183157
this.summarizedOn = shortDateNoYear(
184158
moment(topicSummary.updated_at, "YYYY-MM-DD HH:mm:ss Z")
185159
);
186160
this.summarizedBy = topicSummary.algorithm;
187161
this.newPostsSinceSummary = topicSummary.new_posts_since_summary;
188162
this.outdated = topicSummary.outdated;
189163
this.canRegenerate = topicSummary.outdated && topicSummary.can_regenerate;
190-
191-
// Clear pending animations
192-
if (this.typingTimer) {
193-
cancel(this.typingTimer);
194-
this.typingTimer = null;
195-
}
196-
} else if (newText.length > this.text.length) {
197-
this.text = newText;
198-
this.isStreaming = true;
199-
this.onTextUpdate();
200164
}
201165
}
202166

@@ -260,8 +224,13 @@ export default class AiSummaryBox extends Component {
260224
{{#if this.loading}}
261225
<AiSummarySkeleton />
262226
{{else}}
263-
<div class="generated-summary cooked">
264-
<CookText @rawText={{this.streamedText}} />
227+
<div
228+
class="generated-summary"
229+
{{smoothStreamText this.text this.haltAnimation}}
230+
>
231+
{{#if this.haltAnimation}}
232+
<CookText @rawText={{this.text}} />
233+
{{/if}}
265234
</div>
266235
{{#if this.summarizedOn}}
267236
<div class="summarized-on">
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { cancel, later } from "@ember/runloop";
2+
import { htmlSafe } from "@ember/template";
3+
import Modifier from "ember-modifier";
4+
import { cook } from "discourse/lib/text";
5+
6+
const STREAMED_TEXT_SPEED = 15;
7+
8+
export default class SmoothStreamTextModifier extends Modifier {
9+
typingTimer = null;
10+
displayedText = "";
11+
12+
modify(element, [text, haltAnimation]) {
13+
if (haltAnimation) {
14+
return;
15+
}
16+
this._startTypingAnimation(element, text);
17+
}
18+
19+
async _startTypingAnimation(element, text) {
20+
if (this.typingTimer) {
21+
cancel(this.typingTimer);
22+
}
23+
24+
if (this.displayedText.length === 0) {
25+
element.innerHTML = "";
26+
}
27+
28+
this._typeCharacter(element, text);
29+
}
30+
31+
async _typeCharacter(element, text) {
32+
if (this.displayedText.length < text.length) {
33+
this.displayedText += text.charAt(this.displayedText.length);
34+
35+
try {
36+
const cookedText = await cook(this.displayedText);
37+
element.classList.add("cooked");
38+
element.innerHTML = htmlSafe(cookedText);
39+
} catch (error) {
40+
console.error("Error cooking text during typing: ", error);
41+
}
42+
43+
this.typingTimer = later(
44+
this,
45+
this._typeCharacter,
46+
element,
47+
text,
48+
STREAMED_TEXT_SPEED
49+
);
50+
} else {
51+
this.typingTimer = null;
52+
}
53+
}
54+
55+
willRemove() {
56+
if (this.typingTimer) {
57+
cancel(this.typingTimer);
58+
}
59+
}
60+
}

0 commit comments

Comments
 (0)