@@ -13,37 +13,32 @@ import { ajax } from "discourse/lib/ajax";
1313import { popupAjaxError } from " discourse/lib/ajax-error" ;
1414import { bind } from " discourse/lib/decorators" ;
1515import { i18n } from " discourse-i18n" ;
16+ import DiffStreamer from " ../../lib/diff-streamer" ;
1617import SmoothStreamer from " ../../lib/smooth-streamer" ;
1718import AiIndicatorWave from " ../ai-indicator-wave" ;
18- import { cancel , later } from " @ember/runloop" ;
19-
20- const WORD_TYPING_DELAY = 200 ;
2119
2220export default class ModalDiffModal extends Component {
2321 @service currentUser;
2422 @service messageBus;
2523
2624 @tracked loading = false ;
27- @tracked diff ;
25+ @tracked diffStreamer = new DiffStreamer ( this . args . model . selectedText ) ;
2826 @tracked suggestion = " " ;
29- @tracked isStreaming = false ;
30- @tracked lastResultText = " " ;
31- // @tracked
32- // smoothStreamer = new SmoothStreamer(
33- // () => this.suggestion,
34- // (newValue) => (this.suggestion = newValue)
35- // );
36- @tracked finalDiff = " " ;
37- @tracked words = [];
38- originalWords = [];
39- typingTimer = null ;
40- currentWordIndex = 0 ;
27+ @tracked
28+ smoothStreamer = new SmoothStreamer (
29+ () => this .suggestion ,
30+ (newValue ) => (this .suggestion = newValue)
31+ );
4132
4233 constructor () {
4334 super (... arguments );
4435 this .suggestChanges ();
4536 }
4637
38+ get isStreaming () {
39+ return this .diffStreamer .isStreaming || this .smoothStreamer .isStreaming ;
40+ }
41+
4742 @bind
4843 subscribe () {
4944 const channel = " /discourse-ai/ai-helper/stream_composer_suggestion" ;
@@ -56,93 +51,21 @@ export default class ModalDiffModal extends Component {
5651 this .messageBus .subscribe (channel, this .updateResult );
5752 }
5853
59- compareText (oldText = " " , newText = " " , opts = {}) {
60- const oldWords = oldText .trim ().split (/ \s + / );
61- const newWords = newText .trim ().split (/ \s + / );
62-
63- const diff = [];
64- let i = 0 ;
65-
66- while (i < newWords .length ) {
67- const oldWord = oldWords[i];
68- const newWord = newWords[i];
69-
70- let wordHTML;
71- if (oldWord === undefined ) {
72- wordHTML = ` <ins>${ newWord} </ins>` ;
73- } else if (oldWord !== newWord) {
74- wordHTML = ` <del>${ oldWord} </del> <ins>${ newWord} </ins>` ;
75- } else {
76- wordHTML = newWord;
77- }
78-
79- if (i === newWords .length - 1 && opts .markLastWord ) {
80- wordHTML = ` <mark class="highlight">${ wordHTML} </mark>` ;
81- }
82-
83- diff .push (wordHTML);
84- i++ ;
85- }
86-
87- return diff .join (" " );
88- }
89-
9054 @action
9155 async updateResult (result ) {
9256 this .loading = false ;
9357
94- const newText = result .result ;
95- const diffText = newText .slice (this .lastResultText .length ).trim ();
96- const newWords = diffText .split (/ \s + / ).filter (Boolean );
97-
98- if (newWords .length > 0 ) {
99- this .words .push (... newWords);
100- if (! this .typingTimer ) {
101- this .streamNextWord ();
102- }
103- }
104-
105- if (result .done ) {
106- // this.finalDiff = result.diff;
107- }
108-
109- this .lastResultText = newText;
110- this .isStreaming = ! result .done ;
111- }
112-
113- streamNextWord () {
114- if (this .currentWordIndex === this .words .length ) {
115- this .diff = this .compareText (
116- this .args .model .selectedText ,
117- this .suggestion ,
118- { markLastWord: false }
119- );
120- }
121-
122- if (this .currentWordIndex < this .words .length ) {
123- this .suggestion += this .words [this .currentWordIndex ] + " " ;
124- this .diff = this .compareText (
125- this .args .model .selectedText ,
126- this .suggestion ,
127- { markLastWord: true }
128- );
129-
130- this .currentWordIndex ++ ;
131- this .typingTimer = later (this , this .streamNextWord , WORD_TYPING_DELAY );
58+ if (this .args .model .showResultAsDiff ) {
59+ this .diffStreamer .updateResult (result, " result" );
13260 } else {
133- this .typingTimer = null ;
61+ this .smoothStreamer . updateResult (result, " result " ) ;
13462 }
13563 }
13664
13765 @action
13866 async suggestChanges () {
139- // this.smoothStreamer.resetStreaming();
140- this .diff = null ;
141- this .suggestion = " " ;
142- this .loading = true ;
143- this .lastResultText = " " ;
144- this .words = [];
145- this .currentWordIndex = 0 ;
67+ this .smoothStreamer .resetStreaming ();
68+ this .diffStreamer .reset ();
14669
14770 try {
14871 return await ajax (" /discourse-ai/ai-helper/stream_suggestion" , {
@@ -170,6 +93,13 @@ export default class ModalDiffModal extends Component {
17093 this .suggestion
17194 );
17295 }
96+
97+ if (this .args .model .showResultAsDiff && this .diffStreamer .suggestion ) {
98+ this .args .model .toolbarEvent .replaceText (
99+ this .args .model .selectedText ,
100+ this .diffStreamer .suggestion
101+ );
102+ }
173103 }
174104
175105 <template >
@@ -189,20 +119,18 @@ export default class ModalDiffModal extends Component {
189119 class ={{concatClass
190120 " composer-ai-helper-modal__suggestion"
191121 " streamable-content"
122+ ( if this . isStreaming " streaming" )
123+ ( if @ model.showResultAsDiff " inline-diff" )
192124 }}
193125 >
194- {{!-- <CookText @rawText={{this.diff}} class="cooked" /> --}}
195- {{htmlSafe this . diff}}
196- {{!-- <div class="composer-ai-helper-modal__old-value">
197- {{@model.selectedText}}
198- {{!-- {{#if this.smoothStreamer.isStreaming}}
199- <CookText
200- @rawText={{this.smoothStreamer.renderedText}}
201- class="cooked"
202- />
126+ {{#if @ model.showResultAsDiff }}
127+ {{htmlSafe this . diffStreamer.diff}}
203128 {{else }}
204- {{#if this.diff}}
205- {{htmlSafe this.diff}}
129+ {{#if this . smoothStreamer.isStreaming }}
130+ <CookText
131+ @ rawText ={{this .smoothStreamer.renderedText }}
132+ class =" cooked"
133+ />
206134 {{else }}
207135 <div class =" composer-ai-helper-modal__old-value" >
208136 {{@ model.selectedText }}
@@ -214,7 +142,7 @@ export default class ModalDiffModal extends Component {
214142 />
215143 </div >
216144 {{/if }}
217- {{/if}} --}}
145+ {{/if }}
218146 </div >
219147 {{/if }}
220148 </div >
@@ -232,6 +160,7 @@ export default class ModalDiffModal extends Component {
232160 {{else }}
233161 <DButton
234162 class =" btn-primary confirm"
163+ @ disabled ={{this .isStreaming }}
235164 @ action ={{this .triggerConfirmChanges }}
236165 @ label =" discourse_ai.ai_helper.context_menu.confirm"
237166 />
0 commit comments