From d0cbb43ec3fa19f76a570f5e0038bfc72c9f37b9 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 7 May 2025 11:21:53 -0400
Subject: fixed dont_center on Docs in gridview.  fixed ai view screentolocal
 in docView, and made ai view more streamlined.  got rid of ai history sidebar
 in images.   fixed imageeditor to use a mask that doesn't show the original
 conctents.  fixed gptpopup scrolling, turning off of spinner, and improved
 ability to filter Docs

---
 src/client/views/pdf/GPTPopup/GPTPopup.tsx | 149 +++++++++++++++--------------
 1 file changed, 79 insertions(+), 70 deletions(-)

(limited to 'src/client/views/pdf/GPTPopup/GPTPopup.tsx')

diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
index c45d8e052..9fbae5c90 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
@@ -93,7 +93,7 @@ export class GPTPopup extends ObservableReactComponent<object> {
                     this.onGptResponse = (sortResult: string, questionType: GPTDocCommand, args?: string) => this.processGptResponse(selDoc, this._textToDocMap, sortResult, questionType, args);
                     this.onQuizRandom = () => this.randomlyChooseDoc(selDoc.Document, hasChildDocs());
                     this._documentDescriptions = Promise.all(hasChildDocs().map(doc =>
-                            Doc.getDescription(doc).then(text => this._textToDocMap.set(text.trim(), doc) && `${DescriptionSeperator}${text}${DescriptionSeperator}`)
+                            Doc.getDescription(doc).then(text => this._textToDocMap.set(text.replace(/\n/g, ' ').trim(), doc) && `${DescriptionSeperator}${text}${DescriptionSeperator}`)
                         )).then(docDescriptions => docDescriptions.join()); // prettier-ignore
                 }
             },
@@ -406,73 +406,80 @@ export class GPTPopup extends ObservableReactComponent<object> {
     scrollToBottom = () => setTimeout(() => this._messagesEndRef.current?.scrollIntoView({ behavior: 'smooth', block: 'end' }), 50);
 
     gptMenu = () => (
-        <div className="btns-wrapper-gpt">
-            <Button
-                tooltip="Ask Firefly to create images"
-                text="Ask Firefly"
-                onClick={() => this.setMode(GPTPopupMode.FIREFLY)}
-                color={SettingsManager.userColor}
-                background={SettingsManager.userVariantColor}
-                type={Type.TERT}
-                style={{
-                    width: '100%',
-                    height: '40%',
-                    textAlign: 'center',
-                    color: '#ffffff',
-                    fontSize: '16px',
-                    marginBottom: '10px',
-                }}
-            />
-            <Button
-                tooltip="Ask GPT to sort, tag, define, or filter your Docs!"
-                text="Ask GPT"
-                onClick={() => this.setMode(GPTPopupMode.USER_PROMPT)}
-                color={SettingsManager.userColor}
-                background={SettingsManager.userVariantColor}
-                type={Type.TERT}
-                style={{
-                    width: '100%',
-                    height: '40%',
-                    textAlign: 'center',
-                    color: '#ffffff',
-                    fontSize: '16px',
-                    marginBottom: '10px',
-                }}
-            />
-            <Button
-                tooltip="Test your knowledge by verifying answers with ChatGPT"
-                text="Take Quiz"
-                onClick={() => {
-                    this._conversationArray = ['Define the selected card!'];
-                    this.setMode(GPTPopupMode.QUIZ_RESPONSE);
-                    this.onQuizRandom?.();
-                }}
-                color={SettingsManager.userColor}
-                background={SettingsManager.userVariantColor}
-                type={Type.TERT}
-                style={{
-                    width: '100%',
-                    height: '40%',
-                    textAlign: 'center',
-                    color: '#ffffff',
-                    fontSize: '16px',
-                }}
-            />
+        <div style={{ display: 'flex', maxHeight: 'calc(100% - 32px)', overflow: 'auto' }}>
+            <div className="btns-wrapper-gpt">
+                <Button
+                    tooltip="Ask Firefly to create images"
+                    text="Ask Firefly"
+                    onClick={() => this.setMode(GPTPopupMode.FIREFLY)}
+                    color={SettingsManager.userColor}
+                    background={SettingsManager.userVariantColor}
+                    type={Type.TERT}
+                    style={{
+                        width: '100%',
+                        height: '40%',
+                        textAlign: 'center',
+                        color: '#ffffff',
+                        fontSize: '16px',
+                        marginBottom: '10px',
+                    }}
+                />
+                <Button
+                    tooltip="Ask GPT to sort, tag, define, or filter your Docs!"
+                    text="Ask GPT"
+                    onClick={() => this.setMode(GPTPopupMode.USER_PROMPT)}
+                    color={SettingsManager.userColor}
+                    background={SettingsManager.userVariantColor}
+                    type={Type.TERT}
+                    style={{
+                        width: '100%',
+                        height: '40%',
+                        textAlign: 'center',
+                        color: '#ffffff',
+                        fontSize: '16px',
+                        marginBottom: '10px',
+                    }}
+                />
+                <Button
+                    tooltip="Test your knowledge by verifying answers with ChatGPT"
+                    text="Take Quiz"
+                    onClick={() => {
+                        this._conversationArray = ['Define the selected card!'];
+                        this.setMode(GPTPopupMode.QUIZ_RESPONSE);
+                        this.onQuizRandom?.();
+                    }}
+                    color={SettingsManager.userColor}
+                    background={SettingsManager.userVariantColor}
+                    type={Type.TERT}
+                    style={{
+                        width: '100%',
+                        height: '40%',
+                        textAlign: 'center',
+                        color: '#ffffff',
+                        fontSize: '16px',
+                    }}
+                />
+            </div>
         </div>
     );
 
     callGpt = action((mode: GPTPopupMode) => {
         this.setGptProcessing(true);
+        const reset = action(() => {
+            this.setGptProcessing(false);
+            this._userPrompt = '';
+            this._quizAnswer = '';
+        });
         switch (mode) {
             case GPTPopupMode.FIREFLY:
                 this._fireflyArray.push(this._userPrompt);
-                return this.generateFireflyImage(this._userPrompt).then(action(() => (this._userPrompt = '')));
+                return this.generateFireflyImage(this._userPrompt).then(reset);
             case GPTPopupMode.USER_PROMPT:
                 this._conversationArray.push(this._userPrompt);
-                return this.generateUserPromptResponse(this._userPrompt).then(action(() => (this._userPrompt = '')));
+                return this.generateUserPromptResponse(this._userPrompt).then(reset);
             case GPTPopupMode.QUIZ_RESPONSE:
                 this._conversationArray.push(this._quizAnswer);
-                return this.generateQuizAnswerAnalysis(DocumentView.SelectedDocs().lastElement(), this._quizAnswer).then(action(() => (this._quizAnswer = '')));
+                return this.generateQuizAnswerAnalysis(DocumentView.SelectedDocs().lastElement(), this._quizAnswer).then(reset);
         }
     });
 
@@ -490,18 +497,20 @@ export class GPTPopup extends ObservableReactComponent<object> {
     };
 
     gptUserInput = () => (
-        <div className="btns-wrapper-gpt">
-            <div className="chat-wrapper">
-                <div className="chat-bubbles">
-                    {(this._mode === GPTPopupMode.FIREFLY ? this._fireflyArray : this._conversationArray).map((message, index) => (
-                        <div key={index} className={`chat-bubble ${index % 2 === 1 ? 'user-message' : 'chat-message'}`}>
-                            {message}
-                        </div>
-                    ))}
-                    {this._gptProcessing && <div className="chat-bubble chat-message">...</div>}
-                </div>
+        <div style={{ display: 'flex', maxHeight: 'calc(100% - 32px)', overflow: 'auto' }}>
+            <div className="btns-wrapper-gpt">
+                <div className="chat-wrapper">
+                    <div className="chat-bubbles">
+                        {(this._mode === GPTPopupMode.FIREFLY ? this._fireflyArray : this._conversationArray).map((message, index) => (
+                            <div key={index} className={`chat-bubble ${index % 2 === 1 ? 'user-message' : 'chat-message'}`}>
+                                {message}
+                            </div>
+                        ))}
+                        {this._gptProcessing && <div className="chat-bubble chat-message">...</div>}
+                    </div>
 
-                <div ref={this._messagesEndRef} style={{ height: '100px' }} />
+                    <div ref={this._messagesEndRef} style={{ height: '40px' }} />
+                </div>
             </div>
         </div>
     );
@@ -520,7 +529,7 @@ export class GPTPopup extends ObservableReactComponent<object> {
                     onChange={e => onChange(e.target.value)}
                     onKeyDown={e => this.handleKeyPress(e, this._mode)}
                     type="text"
-                    style={{ color: SnappingManager.userColor }}
+                    style={{ color: 'black' }}
                     placeholder={placeholder}
                 />
                 <Button //
@@ -744,7 +753,7 @@ export class GPTPopup extends ObservableReactComponent<object> {
                         onClick={() => this._collectionContext && Doc.setDocFilter(this._collectionContext, 'tags', GPTPopup.ChatTag, 'remove')}
                     />
                     {[GPTPopupMode.USER_PROMPT, GPTPopupMode.QUIZ_RESPONSE, GPTPopupMode.FIREFLY].includes(this._mode) && (
-                        <IconButton color={SettingsManager.userVariantColor} background={SettingsManager.userColor} tooltip="back" icon={<CgCornerUpLeft size="16px" />} onClick={() => (this._mode = GPTPopupMode.GPT_MENU)} />
+                        <IconButton color={SettingsManager.userVariantColor} background={SettingsManager.userColor} tooltip="back" icon={<CgCornerUpLeft size="16px" />} onClick={action(() => (this._mode = GPTPopupMode.GPT_MENU))} />
                     )}
                 </>
             )}
@@ -753,7 +762,7 @@ export class GPTPopup extends ObservableReactComponent<object> {
 
     render() {
         return (
-            <div className="gptPopup-summary-box" style={{ background: SnappingManager.userColor, color: SnappingManager.userBackgroundColor, display: SnappingManager.ChatVisible ? 'flex' : 'none', overflow: 'auto' }}>
+            <div className="gptPopup-summary-box" style={{ background: SnappingManager.userColor, color: SnappingManager.userBackgroundColor, display: SnappingManager.ChatVisible ? 'flex' : 'none' }}>
                 {(() => {
                     //prettier-ignore
                     switch (this._mode) {
-- 
cgit v1.2.3-70-g09d2


From 4b8c4c9277cca69ea3341ca6ddf4c7f5befc78a0 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 7 May 2025 15:46:06 -0400
Subject: cleaned up ai metadata on generated drawings.

---
 src/client/documents/Documents.ts                  |  5 +-
 src/client/util/DocumentManager.ts                 |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 54 ++-----------------
 src/client/views/nodes/ImageBox.tsx                |  6 +--
 src/client/views/pdf/GPTPopup/GPTPopup.tsx         |  4 +-
 src/client/views/smartdraw/DrawingFillHandler.tsx  |  6 +--
 src/client/views/smartdraw/SmartDrawHandler.scss   |  1 +
 src/client/views/smartdraw/SmartDrawHandler.tsx    | 63 +++++++++++-----------
 src/client/views/smartdraw/StickerPalette.tsx      | 12 ++---
 9 files changed, 57 insertions(+), 96 deletions(-)

(limited to 'src/client/views/pdf/GPTPopup/GPTPopup.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index bbe872a91..9b6acef7b 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -519,8 +519,9 @@ export class DocumentOptions {
     card_sort_isDesc?: BOOLt = new BoolInfo('whether the cards are sorted ascending or descending');
 
     ai?: string; // to mark items as ai generated
-    ai_firefly_seed?: number;
-    ai_firefly_prompt?: string;
+    ai_prompt_seed?: NUMt = new NumInfo('seed to GAI engine to make results deterministic');
+    ai_prompt?: STRt = new StrInfo('input prompt to GAI engine');
+    ai_generatedDocs?: List<Doc>; // list of documents generated by GAI engine
 
     /**
      * JSON‐stringified slot configuration for ScrapbookBox
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 3bae2881e..fc8f22cf3 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -349,7 +349,7 @@ export class DocumentManager {
             // bcz: should this delay be an options parameter?
             setTimeout(() => {
                 Doc.linkFollowHighlight(viewSpec ? [docView.Document, viewSpec] : docView.Document, undefined, options.effect);
-                const zoomableText = StrCast(targetDoc.text_html, StrCast(targetDoc.ai_firefly_prompt));
+                const zoomableText = StrCast(targetDoc.text_html, StrCast(targetDoc.ai_prompt));
                 if (options.zoomTextSelections && Doc.IsUnhighlightTimerSet() && contextView && zoomableText) {
                     // if the docView is a text anchor, the contextView is the PDF/Web/Text doc
                     contextView.setTextHtmlOverlay(zoomableText, options.effect);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 05958e6b9..bb3c59eae 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1259,15 +1259,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     /**
      * Adds the created drawing to the freeform canvas and sets the metadata.
      */
-    addDrawing = (doc: Doc, opts: DrawingOptions, gptRes: string, x?: number, y?: number) => {
-        doc.$title = opts.text;
-        doc.$width = opts.size;
-        doc.$ai_drawing_input = opts.text;
-        doc.$ai_drawing_complexity = opts.complexity;
-        doc.$ai_drawing_colored = opts.autoColor;
-        doc.$ai_drawing_size = opts.size;
-        doc.$ai_drawing_data = gptRes;
-        doc.$ai = 'gpt';
+    addDrawing = (doc: Doc, opts: DrawingOptions, x?: number, y?: number) => {
+        doc.$ai_prompt = opts.text;
         this._drawingContainer = doc;
         if (x !== undefined && y !== undefined) {
             [doc.x, doc.y] = this.screenToFreeformContentsXf.transformPoint(x, y);
@@ -1977,7 +1970,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 event: action(() => {
                     SmartDrawHandler.Instance.AddDrawing = this.addDrawing;
                     SmartDrawHandler.Instance.RemoveDrawing = this.removeDrawing;
-                    !SmartDrawHandler.Instance.ShowRegenerate ? SmartDrawHandler.Instance.displayRegenerate(this._downX, this._downY - 10) : SmartDrawHandler.Instance.hideRegenerate();
+                    !SmartDrawHandler.Instance.ShowRegenerate ? SmartDrawHandler.Instance.displayRegenerate(this._downX, this._downY - 10, NumCast(this.layoutDoc[this.scaleFieldKey])) : SmartDrawHandler.Instance.hideRegenerate();
                 }),
                 icon: 'pen-to-square',
             });
@@ -2182,9 +2175,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                             placeholder={this._drawingFillInput || StrCast(this.Document.title) || 'Describe image'}
                             type="text"
                             value={this._drawingFillInput}
-                            onChange={action(e => {
-                                this._drawingFillInput = e.target.value;
-                            })}
+                            onChange={action(e => (this._drawingFillInput = e.target.value))}
                         />
                         <div className="collectionFreeFormView-aiView-strength">
                             <span className="collectionFreeFormView-aiView-similarity">Similarity</span>
@@ -2213,11 +2204,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                                 onClick={undoable(
                                     action(() => {
                                         this._drawingFillLoading = true;
-                                        DrawingFillHandler.drawingToImage(this.props.Document, this._fireflyRefStrength, this._drawingFillInput || StrCast(this.Document.title))?.then(
-                                            action(() => {
-                                                this._drawingFillLoading = false;
-                                            })
-                                        );
+                                        DrawingFillHandler.drawingToImage(this.props.Document, this._fireflyRefStrength, this._drawingFillInput || StrCast(this.Document.title))?.then(action(() => (this._drawingFillLoading = false)));
                                     }),
                                     'create image'
                                 )}
@@ -2225,37 +2212,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                         </div>
                     </div>
                 </div>
-                <div className="collectionfreeformview-aiView-regenerate-container">
-                    <span className="collectionfreeformview-aiView-subtitle">Regenerate</span>
-                    <div className="collectionfreeformview-aiView-regenerate">
-                        <input
-                            className="collectionfreeformview-aiView-input"
-                            aria-label="Edit instructions input"
-                            type="text"
-                            value={this._regenInput}
-                            onChange={action(e => {
-                                this._regenInput = e.target.value;
-                            })}
-                            placeholder="..under development.."
-                        />
-                        <div className="collectionFreeFormView-aiView-regenBtn">
-                            <Button
-                                text="Regenerate"
-                                type={Type.SEC}
-                                icon={this._regenLoading ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <AiOutlineSend />}
-                                iconPlacement="right"
-                                // onClick={action(async () => {
-                                //     this._regenLoading = true;
-                                //     SmartDrawHandler.Instance.CreateDrawingDoc = this.createDrawingDoc;
-                                //     SmartDrawHandler.Instance.AddDrawing = this.addDrawing;
-                                //     SmartDrawHandler.Instance.RemoveDrawing = this.removeDrawing;
-                                //     await SmartDrawHandler.Instance.regenerate([this.Document], undefined, undefined, this._regenInput, true);
-                                //     this._regenLoading = false;
-                                // })}
-                            />
-                        </div>
-                    </div>
-                </div>
             </div>
         );
     };
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index bf6915570..b648f2adb 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -225,7 +225,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                     const drag = de.complete.docDragData.draggedDocuments.lastElement();
                     const dragField = drag[Doc.LayoutDataKey(drag)];
                     const descText = RTFCast(dragField)?.Text || StrCast(dragField) || RTFCast(drag.text)?.Text || StrCast(drag.text) || StrCast(this.Document.title);
-                    const oldPrompt = StrCast(this.Document.ai_firefly_prompt, StrCast(this.Document.title));
+                    const oldPrompt = StrCast(this.Document.ai_prompt, StrCast(this.Document.title));
                     const newPrompt = (text: string) => (oldPrompt ? `${oldPrompt} ~~~ ${text}` : text);
                     DrawingFillHandler.drawingToImage(this.Document, 90, newPrompt(descText), drag)?.then(action(() => (this._regenerateLoading = false)));
                     added = false;
@@ -735,9 +735,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                 <div
                     className="imageBox-regenerateDropTarget"
                     ref={this._regenerateIconRef}
-                    onClick={() => DocCast(this.Document.ai_firefly_generatedDocs) && DocumentView.showDocument(DocCast(this.Document.ai_firefly_generatedDocs)!, { openLocation: OpenWhere.addRight })}
+                    onClick={() => DocCast(this.Document.ai_generatedDocs) && DocumentView.showDocument(DocCast(this.Document.ai_generatedDocs)!, { openLocation: OpenWhere.addRight })}
                     style={{
-                        display: (this._props.isContentActive() && (SnappingManager.CanEmbed || this.Document.ai_firefly_generatedDocs)) || this._regenerateLoading ? 'block' : 'none',
+                        display: (this._props.isContentActive() && (SnappingManager.CanEmbed || this.Document.ai_generatedDocs)) || this._regenerateLoading ? 'block' : 'none',
                         transform: `scale(${this.uiBtnScaling})`,
                         width: this._sideBtnWidth,
                         height: this._sideBtnWidth,
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
index 9fbae5c90..568e48edf 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
@@ -211,7 +211,7 @@ export class GPTPopup extends ObservableReactComponent<object> {
         const selView = DocumentView.Selected().lastElement();
         const selDoc = selView?.Document;
         if (selDoc && (selView._props.renderDepth > 1 || selDoc[Doc.LayoutDataKey(selDoc)] instanceof ImageField)) {
-            const oldPrompt = StrCast(selDoc.ai_firefly_prompt, StrCast(selDoc.title));
+            const oldPrompt = StrCast(selDoc.ai_prompt, StrCast(selDoc.title));
             const newPrompt = oldPrompt ? `${oldPrompt} ~~~ ${imgDesc}` : imgDesc;
             return DrawingFillHandler.drawingToImage(selDoc, 100, newPrompt, selDoc)
                 .then(action(() => (this._userPrompt = '')))
@@ -767,7 +767,7 @@ export class GPTPopup extends ObservableReactComponent<object> {
                     //prettier-ignore
                     switch (this._mode) {
                         case GPTPopupMode.USER_PROMPT:   return this.promptBox("ASK", this._userPrompt, this.setUserPrompt, 'Ask GPT to sort, tag, define, or filter your documents for you!');
-                        case GPTPopupMode.FIREFLY:       return this.promptBox("CREATE", this._userPrompt, this.setUserPrompt, StrCast(DocumentView.Selected().lastElement()?.Document.ai_firefly_prompt, 'Ask Firefly to generate images'));
+                        case GPTPopupMode.FIREFLY:       return this.promptBox("CREATE", this._userPrompt, this.setUserPrompt, StrCast(DocumentView.Selected().lastElement()?.Document.ai_prompt, 'Ask Firefly to generate images'));
                         case GPTPopupMode.QUIZ_RESPONSE: return this.promptBox("QUIZ", this._quizAnswer, this.setQuizAnswer, 'Describe/answer the selected document!');
                         case GPTPopupMode.GPT_MENU:      return this.menuBox();
                         case GPTPopupMode.SUMMARY:       return this.summaryBox();
diff --git a/src/client/views/smartdraw/DrawingFillHandler.tsx b/src/client/views/smartdraw/DrawingFillHandler.tsx
index 2c69284db..f773957e7 100644
--- a/src/client/views/smartdraw/DrawingFillHandler.tsx
+++ b/src/client/views/smartdraw/DrawingFillHandler.tsx
@@ -51,19 +51,19 @@ export class DrawingFillHandler {
                             if (error.includes('Dropbox') && confirm('Create image failed. Try authorizing DropBox?\r\n' + error.replace(/^[^"]*/, ''))) {
                                 return DrawingFillHandler.authorizeDropbox();
                             }
-                            const genratedDocs = DocCast(drawing.ai_firefly_generatedDocs) ?? Docs.Create.MasonryDocument([], { title: StrCast(drawing.title) + ' AI Images', _width: 400, _height: 400 });
-                            drawing.$ai_firefly_generatedDocs = genratedDocs;
+                            const genratedDocs = DocCast(drawing.ai_generatedDocs) ?? Docs.Create.MasonryDocument([], { title: StrCast(drawing.title) + ' AI Images', _width: 400, _height: 400 });
+                            drawing.$ai_generatedDocs = genratedDocs;
                             (res as Upload.ImageInformation[]).map(info =>
                                 Doc.AddDocToList(
                                     genratedDocs,
                                     undefined,
                                     Docs.Create.ImageDocument(info.accessPaths.agnostic.client, {
                                         ai: 'firefly',
+                                        ai_prompt: newPrompt,
                                         tags: new List<string>(['@ai']),
                                         title: newPrompt,
                                         _data_usePath: 'alternate:hover',
                                         data_alternates: new List<Doc>([drawing]),
-                                        ai_firefly_prompt: newPrompt,
                                         _width: 500,
                                         data_nativeWidth: info.nativeWidth,
                                         data_nativeHeight: info.nativeHeight,
diff --git a/src/client/views/smartdraw/SmartDrawHandler.scss b/src/client/views/smartdraw/SmartDrawHandler.scss
index cca7d77c7..e80f1122b 100644
--- a/src/client/views/smartdraw/SmartDrawHandler.scss
+++ b/src/client/views/smartdraw/SmartDrawHandler.scss
@@ -73,5 +73,6 @@
     .edit-box {
         display: flex;
         flex-direction: row;
+        color: black;
     }
 }
diff --git a/src/client/views/smartdraw/SmartDrawHandler.tsx b/src/client/views/smartdraw/SmartDrawHandler.tsx
index a6e221f3e..3976ec39e 100644
--- a/src/client/views/smartdraw/SmartDrawHandler.tsx
+++ b/src/client/views/smartdraw/SmartDrawHandler.tsx
@@ -61,7 +61,6 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
     static Instance: SmartDrawHandler;
 
     private _lastInput: DrawingOptions = { text: '', complexity: 5, size: 350, autoColor: true, x: 0, y: 0 };
-    private _lastResponse: string = '';
     private _selectedDocs: Doc[] = [];
 
     @observable private _display: boolean = false;
@@ -97,7 +96,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
         CollectionFreeForm, FormattedTextBox, StickerPalette) to define how a drawing document should be added
         or removed in their respective locations (to the freeform canvas, to the sticker palette's preview, etc.)
     */
-    public AddDrawing: (doc: Doc, opts: DrawingOptions, gptRes: string, x?: number, y?: number) => void = unimplementedFunction;
+    public AddDrawing: (doc: Doc, opts: DrawingOptions, x?: number, y?: number) => void = unimplementedFunction;
     public RemoveDrawing: (useLastContainer: boolean, doc?: Doc) => void = unimplementedFunction;
     /**
      * This creates the ink document that represents a drawing, so it goes through the strokes that make up the drawing,
@@ -105,7 +104,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
      * classes to customize the way the drawing docs get created. For example, the freeform canvas has a different way of
      * defining document bounds, so CreateDrawingDoc is redefined when that class calls gpt draw functions.
      */
-    public static CreateDrawingDoc: (strokeList: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => Doc | undefined = (strokeList: [InkData, string, string][], opts: DrawingOptions) => {
+    public static CreateDrawingDoc: (strokeList: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => Doc | undefined = (strokeList: [InkData, string, string][], opts: DrawingOptions, gptRes: string) => {
         const drawing: Doc[] = [];
         strokeList.forEach((stroke: [InkData, string, string]) => {
             const bounds = InkField.getBounds(stroke[0]);
@@ -130,7 +129,14 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
             drawing.push(inkDoc);
         });
 
-        return MarqueeView.getCollection(drawing, undefined, true, { left: 1, top: 1, width: 1, height: 1 });
+        const drawn = MarqueeView.getCollection(drawing, undefined, true, { left: 1, top: 1, width: 1, height: 1 });
+
+        drawn.$ai_drawing = true;
+        drawn.$ai_drawing_complexity = opts.complexity;
+        drawn.$ai_drawing_colored = opts.autoColor;
+        drawn.$ai_drawing_size = opts.size;
+        drawn.$ai_drawing_data = gptRes;
+        return drawn;
     };
 
     @action
@@ -146,15 +152,16 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
      * the regenerate popup show by user command.
      */
     @action
-    displayRegenerate = (x: number, y: number) => {
+    displayRegenerate = (x: number, y: number, scale: number) => {
         this._selectedDocs = [DocumentView.SelectedDocs()?.lastElement()];
         [this._pageX, this._pageY] = [x, y];
+        this._scale = scale;
         this._display = false;
         this.ShowRegenerate = true;
         this._showEditBox = false;
         const docData = this._selectedDocs[0];
-        this._lastResponse = StrCast(docData.$drawingData);
-        this._lastInput = { text: StrCast(docData.$ai_drawing_input), complexity: NumCast(docData.$ai_drawing_complexity), size: NumCast(docData.$ai_drawing_size), autoColor: BoolCast(docData.$ai_drawing_colored), x: this._pageX, y: this._pageY };
+        this._regenInput = StrCast(docData.$ai_prompt, StrCast(docData.title));
+        this._lastInput = { text: StrCast(docData.$ai_prompt), complexity: NumCast(docData.$ai_drawing_complexity), size: NumCast(docData.$ai_drawing_size), autoColor: BoolCast(docData.$ai_drawing_colored), x: this._pageX, y: this._pageY };
     };
 
     /**
@@ -168,9 +175,6 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
             this._isLoading = false;
             this._showOptions = false;
             this._userInput = '';
-            this._complexity = 5;
-            this._size = 350;
-            this._autoColor = true;
             Doc.ActiveTool = InkTool.None;
         }
     };
@@ -184,7 +188,6 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
             this.ShowRegenerate = false;
             this._isLoading = false;
             this._regenInput = '';
-            this._lastInput = { text: '', complexity: 5, size: 350, autoColor: true, x: 0, y: 0 };
         }
     };
 
@@ -208,7 +211,9 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
         this._isLoading = true;
         this._canInteract = false;
         if (this.ShowRegenerate) {
-            await this.regenerate(this._selectedDocs, undefined, undefined, this._regenInput).then(action(() => (this._showEditBox = false)));
+            this._lastInput.x = X;
+            this._lastInput.y = Y;
+            await this.regenerate(this._selectedDocs).then(action(() => (this._showEditBox = false)));
         } else {
             this._showOptions = false;
             try {
@@ -234,13 +239,15 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
      */
     drawWithGPT = async (screenPt: { X: number; Y: number }, input: string, complexity: number, size: number, autoColor: boolean) => {
         if (input) {
-            this._lastInput = { text: input, complexity: complexity, size: size, autoColor: autoColor, x: screenPt.X, y: screenPt.Y };
+            this._lastInput = { text: input, complexity, size, autoColor, x: screenPt.X, y: screenPt.Y };
             const res = await gptAPICall(`"${input}", "${complexity}", "${size}"`, GPTCallType.DRAW, undefined, true);
             if (res) {
                 const strokeData = await this.parseSvg(res, { X: 0, Y: 0 }, false, autoColor);
                 const drawingDoc = strokeData && SmartDrawHandler.CreateDrawingDoc(strokeData.data, strokeData.lastInput, strokeData.lastRes);
-                drawingDoc && this.AddDrawing(drawingDoc, this._lastInput, res, screenPt.X, screenPt.Y);
-                drawingDoc && this._selectedDocs.push(drawingDoc);
+                if (drawingDoc) {
+                    this.AddDrawing(drawingDoc, this._lastInput, screenPt.X, screenPt.Y);
+                    this._selectedDocs.push(drawingDoc);
+                }
                 return strokeData;
             } else {
                 console.error('GPT call failed');
@@ -255,7 +262,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
     createImageWithFirefly = (input: string, seed?: number): Promise<FireflyImageData | Doc | undefined> => {
         this._lastInput.text = input;
         return SmartDrawHandler.CreateWithFirefly(input, this._imgDims, seed).then(doc => {
-            doc instanceof Doc && this.AddDrawing(doc, this._lastInput, input, this._pageX, this._pageY);
+            doc instanceof Doc && this.AddDrawing(doc, this._lastInput, this._pageX, this._pageY);
             return doc;
         });
     }; /**
@@ -301,8 +308,8 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
                     _width: Math.min(400, dims.width),
                     _height: (Math.min(400, dims.width) * dims.height) / dims.width,
                     ai: 'firefly',
-                    ai_firefly_seed: +(newseed ?? 0),
-                    ai_firefly_prompt: input,
+                    ai_prompt_seed: +(newseed ?? 0),
+                    ai_prompt: input,
                 });
             })
             .catch(e => {
@@ -316,33 +323,30 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
      * @param doc the drawing Docs to regenerate
      */
     @action
-    regenerate = (drawingDocs: Doc[], lastInput?: DrawingOptions, lastResponse?: string, regenInput?: string, changeInPlace?: boolean) => {
-        if (lastInput) this._lastInput = lastInput;
-        if (lastResponse) this._lastResponse = lastResponse;
+    regenerate = (drawingDocs: Doc[], regenInput?: string, changeInPlace?: boolean) => {
         if (regenInput) this._regenInput = regenInput;
         return Promise.all(
             drawingDocs.map(async doc => {
                 switch (doc.type) {
                     case DocumentType.IMG: {
                         const func = changeInPlace ? this.recreateImageWithFirefly : this.createImageWithFirefly;
-                        const newPrompt = doc.ai_firefly_prompt ? `${doc.ai_firefly_prompt} ~~~ ${this._regenInput}` : this._regenInput;
-                        return this._regenInput ? func(newPrompt, NumCast(doc?.ai_firefly_seed)) : func(this._lastInput.text || StrCast(doc.ai_firefly_prompt));
+                        const newPrompt = doc.ai_prompt && doc.ai_prompt !== this._regenInput ? `${doc.ai_prompt} ~~~ ${this._regenInput}` : this._regenInput;
+                        return this._regenInput ? func(newPrompt, NumCast(doc?.ai_prompt_seed)) : func(this._lastInput.text || StrCast(doc.ai_prompt));
                     }
                     case DocumentType.COL: {
                         try {
                             const res = await (async () => {
                                 if (this._regenInput) {
-                                    const prompt = `This is your previously generated svg code: ${this._lastResponse} for the user input "${this._lastInput.text}". Please regenerate it with the provided specifications.`;
+                                    const prompt = `This is your previously generated svg code: ${doc.$ai_drawing_data} for the user input "${doc.ai_prompt}". Please regenerate it with the provided specifications.`;
                                     this._lastInput.text = `${this._lastInput.text} ~~~ ${this._regenInput}`;
                                     return gptAPICall(`"${this._regenInput}"`, GPTCallType.DRAW, prompt, true);
                                 }
-                                return gptAPICall(`"${this._lastInput.text}", "${this._lastInput.complexity}", "${this._lastInput.size}"`, GPTCallType.DRAW, undefined, true);
+                                return gptAPICall(`"${doc.$ai_prompt}", "${doc.$ai_drawing_complexity}", "${doc.$ai_drawing_size}"`, GPTCallType.DRAW, undefined, true);
                             })();
                             if (res) {
-                                const strokeData = await this.parseSvg(res, { X: this._lastInput.x ?? 0, Y: this._lastInput.y ?? 0 }, true, lastInput?.autoColor || this._autoColor);
-                                this.RemoveDrawing !== unimplementedFunction && this.RemoveDrawing(true, doc);
+                                const strokeData = await this.parseSvg(res, { X: 0, Y: 0 }, true, this._autoColor);
                                 const drawingDoc = strokeData && SmartDrawHandler.CreateDrawingDoc(strokeData.data, strokeData.lastInput, strokeData.lastRes);
-                                drawingDoc && this.AddDrawing(drawingDoc, this._lastInput, res);
+                                drawingDoc && this.AddDrawing(drawingDoc, this._lastInput, this._lastInput.x, this._lastInput.y);
                             } else {
                                 console.error('GPT call failed');
                             }
@@ -363,7 +367,6 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
         const svg = res.match(/<svg[^>]*>([\s\S]*?)<\/svg>/g);
 
         if (svg) {
-            this._lastResponse = svg[0];
             const svgObject = await parse(svg[0]);
             console.log(res, svgObject);
             const svgStrokes: INode[] = svgObject.children;
@@ -664,7 +667,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
             <div className="regenerate-box">
                 <IconButton
                     tooltip="Regenerate"
-                    icon={this._isLoading && this._regenInput === '' ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <FontAwesomeIcon icon={'rotate'} />}
+                    icon={this._isLoading ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <FontAwesomeIcon icon={'rotate'} />}
                     color={SettingsManager.userColor}
                     onClick={() => this.handleSendClick(this._pageX, this._pageY)}
                 />
diff --git a/src/client/views/smartdraw/StickerPalette.tsx b/src/client/views/smartdraw/StickerPalette.tsx
index 0e234e966..6ef3d26ad 100644
--- a/src/client/views/smartdraw/StickerPalette.tsx
+++ b/src/client/views/smartdraw/StickerPalette.tsx
@@ -9,7 +9,7 @@ import ReactLoading from 'react-loading';
 import { returnEmptyFilter, returnFalse, returnTrue } from '../../../ClientUtils';
 import { emptyFunction, numberRange } from '../../../Utils';
 import { Doc, DocListCast, returnEmptyDoclist } from '../../../fields/Doc';
-import { ImageCast, NumCast } from '../../../fields/Types';
+import { ImageCast, NumCast, StrCast } from '../../../fields/Types';
 import { ImageField } from '../../../fields/URLField';
 import { DocumentType } from '../../documents/DocumentTypes';
 import { Docs } from '../../documents/Documents';
@@ -147,9 +147,9 @@ export class StickerPalette extends ObservableReactComponent<StickerPaletteProps
         SmartDrawHandler.Instance.AddDrawing = this.addDrawing;
         this._canInteract = false;
         Promise.all(
-            numberRange(3).map(i => {
+            numberRange(3).map(() => {
                 return this._showRegenerate
-                    ? SmartDrawHandler.Instance.regenerate(prevDrawings, this._opts, this._gptRes[i], this._userInput)
+                    ? SmartDrawHandler.Instance.regenerate(prevDrawings, this._userInput)
                     : SmartDrawHandler.Instance.drawWithGPT({ X: 0, Y: 0 }, this._userInput, this._opts.complexity || 0, this._opts.size || 0, !!this._opts.autoColor);
             })
         ).then(() => {
@@ -161,8 +161,8 @@ export class StickerPalette extends ObservableReactComponent<StickerPaletteProps
     });
 
     @action
-    addDrawing = (drawing: Doc, opts: DrawingOptions, gptRes: string) => {
-        this._gptRes.push(gptRes);
+    addDrawing = (drawing: Doc) => {
+        this._gptRes.push(StrCast(drawing.$ai_drawing_data));
         drawing.$freeform_fitContentsToBox = true;
         Doc.AddDocToList(this._props.Doc, 'data', drawing);
     };
@@ -176,7 +176,7 @@ export class StickerPalette extends ObservableReactComponent<StickerPaletteProps
         const cIndex = NumCast(this._props.Doc.carousel_index);
         const focusedDrawing = DocListCast(this._props.Doc.data)[cIndex];
         focusedDrawing.$title = this._opts.text?.match(/^(.*?)~~~.*$/)?.[1] || this._opts.text;
-        focusedDrawing.$ai_drawing_input = this._opts.text;
+        focusedDrawing.$ai_prompt = this._opts.text;
         focusedDrawing.$ai_drawing_complexity = this._opts.complexity;
         focusedDrawing.$ai_drawing_colored = this._opts.autoColor;
         focusedDrawing.$ai_drawing_size = this._opts.size;
-- 
cgit v1.2.3-70-g09d2

