diff options
author | Nathan-SR <144961007+Nathan-SR@users.noreply.github.com> | 2025-04-03 03:36:07 -0400 |
---|---|---|
committer | Nathan-SR <144961007+Nathan-SR@users.noreply.github.com> | 2025-04-03 03:36:07 -0400 |
commit | e9bc998554515ecbe86f7d00b01d3cf5d2048b6e (patch) | |
tree | e6dde2332dbe01a24a292f851b13b1dd3ae7c3df /src | |
parent | e22bdd2db60954445c41f7e2ca75a8944de5288f (diff) |
Firefly integration and some UI changes
Diffstat (limited to 'src')
6 files changed, 229 insertions, 115 deletions
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss index 57f4a1e94..48e09d12f 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss @@ -277,18 +277,6 @@ scrollbar-width: none; } -.docCreatorMenu-preview-container { - display: grid; - grid-template-columns: repeat(2, 140px); - grid-template-rows: 140px; - grid-auto-rows: 141px; - overflow-y: scroll; - margin: 0px; - margin-top: 0px; - width: 100%; - height: 100%; -} - .docCreatorMenu-expanded-template-preview { display: flex; flex-direction: column; @@ -297,6 +285,7 @@ position: relative; width: 100%; height: 100%; + flex-grow: 1; .top-panel{ width: 100%; @@ -322,15 +311,12 @@ display: flex; justify-content: center; align-items: center; - width: 113px; - height: 113px; - margin-top: 10px; - margin-left: 10px; + height: 100%; + aspect-ratio: 1; color: none; border: 1px solid rgb(163, 163, 163); border-radius: 5px; box-shadow: 5px 5px rgb(29, 29, 31); - flex: 0 0 auto; &:hover{ background-color: rgb(72, 72, 73); @@ -394,17 +380,42 @@ } } +.docCreatorMenu-variation-prompt-input { + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: center; + margin: 5px; + gap: 15px; + height: 30px; + width: 100%; +} + +.docCreatorMenu-variation-prompt-input-textbox { + height: 100%; + width: 80%; + color: white; + margin-top: 1%; + margin-bottom: 1%; + margin-left: 5%; + background-color: rgb(50, 50, 50); + border-radius: 5px; +} + +.docCreatorMenu-variations-tab { + flex-grow: .5; +} + .docCreatorMenu-section { display: flex; flex-direction: column; align-items: center; position: relative; + flex-grow: 1; + height: 100%; margin: 0px; margin-top: 0px; margin-bottom: 0px; - width: 100%; - height: 200; - flex: 0 0 auto; } .docCreatorMenu-GPT-options-container { @@ -422,12 +433,14 @@ .docCreatorMenu-templates-preview-window { display: flex; flex-direction: row; - //justify-content: center; + justify-content: flex-start; align-items: center; overflow-y: scroll; + gap: 10px; + margin: 5px; position: relative; color: black; - height: 125px; + height: 100%; width: calc(100% - 10px); -ms-overflow-style: none; scrollbar-width: none; @@ -463,6 +476,12 @@ } } +.docCreatorMenu-templates-displays { + display: flex; + flex-direction: column; + height: 100%; +} + .docCreatorMenu-section-title { border: 1px solid rgb(163, 163, 163); border-top: 0px; @@ -1057,4 +1076,4 @@ } -} +}
\ No newline at end of file diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx index 6d37f8f0f..0c5ae58a3 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx @@ -31,6 +31,8 @@ import { TemplateField, ViewType } from './TemplateFieldTypes/TemplateField'; import { Template } from './Template'; import { TemplateFieldSize, TemplateFieldType, TemplateLayouts } from './TemplateBackend'; import { TemplateManager } from './TemplateManager'; +import { DrawingFillHandler } from '../../../smartdraw/DrawingFillHandler'; +import { CgPathIntersect } from 'react-icons/cg'; export enum LayoutType { FREEFORM = 'Freeform', @@ -72,7 +74,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> // eslint-disable-next-line no-use-before-define static Instance: DocCreatorMenu; - private DEBUG_MODE: boolean = false; + private DEBUG_MODE: boolean = true; private _disposers: { [name: string]: IDisposer } = {}; private _ref: HTMLDivElement | null = null; private templateManager: TemplateManager; @@ -91,6 +93,12 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> @observable _layout: { type: LayoutType; yMargin: number; xMargin: number; columns?: number; repeat: number } = { type: LayoutType.FREEFORM, yMargin: 10, xMargin: 10, columns: 3, repeat: 0 }; @observable _savedLayouts: DataVizTemplateLayout[] = []; @observable _expandedPreview: Doc | undefined = undefined; + @observable _variationsTab: boolean = false; + @observable _numVarsToGenerate: number = 3; + @observable _loadingVariants: boolean = false; + @observable _currentVariations: Doc[] = []; + @observable _variationPrompt: string = 'Use this template to generate an empty baseball card template.'; + _previewWindow: HTMLDivElement | null = null; @observable _suggestedTemplates: Template[] = []; @observable _suggestedTemplatePreviews: { doc: Doc; template: Template }[] = []; @@ -129,6 +137,10 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> this.templateManager = new TemplateManager(TemplateLayouts.allTemplates); } + setContainerRef: React.LegacyRef<HTMLDivElement> = (node) => { + this._previewWindow = node; + }; + @action setDataViz = (dataViz: DataVizBox) => { this._dataViz = dataViz; this._selectedTemplate = undefined; @@ -493,6 +505,42 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> this.forceUpdate(); }; + @action setVariationTab = (open: boolean) => { + this._variationsTab = open; + if (this._previewWindow && open) { + this._previewWindow.style.height = String(Number(this._previewWindow.clientHeight) * .6); + } else if (this._previewWindow && !open) { + this._previewWindow.style.height = String(Number(this._previewWindow.clientHeight) * 5/3); + } + } + + generateVariations = async (onDoc: Doc): Promise<Doc[]> => { + this._loadingVariants = true; + this.variationDocss = []; + const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView; + + const clone: Doc = (await Doc.MakeClone(onDoc)).clone; + mainCollection.addDocument(clone); + clone.x = 10000; + clone.y = 10000; + + await DrawingFillHandler.drawingToImage(clone, 100, this._variationPrompt, undefined, this) + + this._loadingVariants = false; + + return this.variationDocss; + } + + @observable variationDocss: Doc[] = [] + + @action addVariationDoc = (doc: Doc) => { + this.variationDocss.push(doc); + const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView; + mainCollection.addDocument(doc); + doc.x = 10000; + doc.y = 10000; + } + generateGPTImage = async (prompt: string): Promise<string | undefined> => { try { const res = await gptImageCall(prompt); @@ -768,31 +816,71 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> this._expandedPreview = template?.doc; //Docs.Create.FreeformDocument([doc], { _height: NumListCast(doc._height)[0], _width: NumListCast(doc._width)[0], title: ''}); }; + @action setVariationPrompt = (prompt: string) => { + this._variationPrompt = prompt; + } + get editingWindow() { const rendered = !this._expandedPreview ? null : ( - <div className="docCreatorMenu-expanded-template-preview"> - <DocumentView - Document={this._expandedPreview} - isContentActive={emptyFunction} - addDocument={returnFalse} - moveDocument={returnFalse} - removeDocument={returnFalse} - PanelWidth={() => this._menuDimensions.width - 10} - PanelHeight={() => this._menuDimensions.height - 60} - ScreenToLocalTransform={() => new Transform(-this._pageX - 5, -this._pageY - 35, 1)} - renderDepth={5} - whenChildContentsActiveChanged={emptyFunction} - focus={emptyFunction} - styleProvider={DefaultStyleProvider} - addDocTab={DocumentViewInternal.addDocTabFunc} - pinToPres={() => undefined} - childFilters={returnEmptyFilter} - childFiltersByRanges={returnEmptyFilter} - searchFilterDocs={returnEmptyDoclist} - fitContentsToBox={returnFalse} - fitWidth={returnFalse} - /> - </div> + <> + <div className="docCreatorMenu-expanded-template-preview" ref={this.setContainerRef}> + { this._previewWindow ? <DocumentView + Document={this._expandedPreview} + isContentActive={emptyFunction} + addDocument={returnFalse} + moveDocument={returnFalse} + removeDocument={returnFalse} + PanelWidth={() => this._previewWindow?.clientWidth ?? 1000 - 10} + PanelHeight={() => this._previewWindow?.clientHeight ?? 1000 - 60} + ScreenToLocalTransform={() => new Transform(-this._pageX - 5, -this._pageY - 35, 1)} + renderDepth={5} + whenChildContentsActiveChanged={emptyFunction} + focus={emptyFunction} + styleProvider={DefaultStyleProvider} + addDocTab={DocumentViewInternal.addDocTabFunc} + pinToPres={() => undefined} + childFilters={returnEmptyFilter} + childFiltersByRanges={returnEmptyFilter} + searchFilterDocs={returnEmptyDoclist} + fitContentsToBox={returnFalse} + fitWidth={returnFalse} + /> : null + } + </div> + { this._variationsTab ? + <div className="docCreatorMenu-section"> + <div className="docCreatorMenu-section-topbar"> + <div className="docCreatorMenu-section-title" style={{color: 'white'}}>Variations</div> + <button className="docCreatorMenu-menu-button section-reveal-options" onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => (this._menuContent = 'dashboard')))}> + <FontAwesomeIcon icon="gear" /> + </button> + </div> + <div className="docCreatorMenu-templates-preview-window"> + {this._currentVariations.map(variant => + <div className="docCreatorMenu-preview-window"> + {this.docPreview(variant)} + </div> + )} + </div> + <div className="docCreatorMenu-variation-prompt-input"> + <textarea + className="docCreatorMenu-variation-prompt-input-textbox" + onChange={e => this.setVariationPrompt(e.target.value)} + defaultValue={''} + placeholder={'Enter a custom prompt here (optional)'} + /> + <button className="docCreatorMenu-menu-button" + onPointerDown={e => this.setUpButtonClick(e, async () => { + this._currentVariations = await this.generateVariations(this._currEditingTemplate?.getRenderedDoc()!); + }) + }> + <FontAwesomeIcon icon="arrows-rotate" /> + </button> + </div> + </div> + : null + } + </> ); return ( @@ -813,50 +901,46 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> }> <FontAwesomeIcon icon="minimize" /> </button> - <button - className="docCreatorMenu-menu-button section-reveal-options top-right-lower" - onPointerDown={e => - this.setUpButtonClick(e, () => { - this._currEditingTemplate?.printFieldInfo(); - /*this._currEditingTemplate?.resetToBase();*/ this.setExpandedView(this._currEditingTemplate); - }) - }> - <FontAwesomeIcon icon="arrows-rotate" color="white" /> + <button className="docCreatorMenu-menu-button section-reveal-options top-right" onPointerDown={e => this.setUpButtonClick(e, async () => { + if (!this._currEditingTemplate) return; + this.setVariationTab(!this._variationsTab); + })}> + <FontAwesomeIcon icon="lightbulb" /> </button> </div> </div> ); } + docPreview = (doc: Doc | undefined) => + !doc ? null : ( + <DocumentView + Document={doc} + isContentActive={emptyFunction} // !!! should be return false + addDocument={returnFalse} + moveDocument={returnFalse} + removeDocument={returnFalse} + PanelWidth={() => this._menuDimensions.height * .3} + PanelHeight={() => this._menuDimensions.height * .3} + ScreenToLocalTransform={() => new Transform(-this._pageX - 5, -this._pageY - 35, 1)} + renderDepth={1} + whenChildContentsActiveChanged={emptyFunction} + focus={emptyFunction} + styleProvider={DefaultStyleProvider} + addDocTab={this._props.addDocTab} + pinToPres={() => undefined} + childFilters={returnEmptyFilter} + childFiltersByRanges={returnEmptyFilter} + searchFilterDocs={returnEmptyDoclist} + fitContentsToBox={returnFalse} + fitWidth={returnFalse} + hideDecorations={true} + /> + ); + get templatesPreviewContents() { const GPTOptions = <div></div>; - const previewDoc = (doc: Doc | undefined, template: Template) => - !doc ? null : ( - <DocumentView - Document={doc} - isContentActive={emptyFunction} // !!! should be return false - addDocument={returnFalse} - moveDocument={returnFalse} - removeDocument={returnFalse} - PanelWidth={() => (this._selectedTemplate === template ? 104 : 111)} - PanelHeight={() => (this._selectedTemplate === template ? 104 : 111)} - ScreenToLocalTransform={() => new Transform(-this._pageX - 5, -this._pageY - 35, 1)} - renderDepth={1} - whenChildContentsActiveChanged={emptyFunction} - focus={emptyFunction} - styleProvider={DefaultStyleProvider} - addDocTab={this._props.addDocTab} - pinToPres={() => undefined} - childFilters={returnEmptyFilter} - childFiltersByRanges={returnEmptyFilter} - searchFilterDocs={returnEmptyDoclist} - fitContentsToBox={returnFalse} - fitWidth={returnFalse} - hideDecorations={true} - /> - ); - //<img className='docCreatorMenu-preview-image expanded' src={this._expandedPreview.icon!.url.href.replace(".png", "_o.png")} /> return ( @@ -864,8 +948,8 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> {this._expandedPreview ? ( this.editingWindow ) : ( - <div> - <div className="docCreatorMenu-section" style={{ height: this._GPTOpt ? 200 : 200 }}> + <div className="docCreatorMenu-templates-displays"> + <div className="docCreatorMenu-section"> <div className="docCreatorMenu-section-topbar"> <div className="docCreatorMenu-section-title">Suggested Templates</div> <button className="docCreatorMenu-menu-button section-reveal-options" onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => (this._menuContent = 'dashboard')))}> @@ -892,6 +976,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> onPointerDown={e => this.setUpButtonClick(e, () => { this.setExpandedView(template); + this.forceUpdate(); }) }> <FontAwesomeIcon icon="magnifying-glass" color="white" /> @@ -899,7 +984,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> <button className="option-button right" onPointerDown={e => this.setUpButtonClick(e, () => this.addUserTemplate(template))}> <FontAwesomeIcon icon="plus" color="white" /> </button> - {previewDoc(template.getRenderedDoc(), template)} + {this.docPreview(template.getRenderedDoc())} </div> )) )} @@ -946,7 +1031,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> <button className="option-button right" onPointerDown={e => this.setUpButtonClick(e, () => this.removeUserTemplate(template))}> <FontAwesomeIcon icon="minus" color="white" /> </button> - {previewDoc(template.getRenderedDoc(), template)} + {this.docPreview(template.getRenderedDoc())} </div> ))} </div> @@ -1396,4 +1481,4 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> </div> ); } -} +}
\ No newline at end of file diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.ts index 9b0fac3a6..a6d2136f4 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.ts +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateBackend.ts @@ -765,4 +765,4 @@ export class TemplateLayouts { }, ], }; -} +}
\ No newline at end of file diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/StaticContentField.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/StaticContentField.ts index 7049bb56f..af3618106 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/StaticContentField.ts +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/StaticContentField.ts @@ -45,7 +45,7 @@ export class TextTemplateField extends StaticContentField { initRenderDoc(settings: FieldSettings) { settings.opts.title = settings.title ?? ''; - settings.opts.text_fontSize = TemplateFieldUtils.calculateFontSize(this._dimensions?.width ?? 10, this._dimensions?.height ?? 10, '', true) + ''; + settings.opts._text_fontSize = TemplateFieldUtils.calculateFontSize(this._dimensions?.width ?? 10, this._dimensions?.height ?? 10, '', true) + ''; this._renderDoc = Docs.Create.TextDocument('', settings.opts); return this; } diff --git a/src/client/views/smartdraw/DrawingFillHandler.tsx b/src/client/views/smartdraw/DrawingFillHandler.tsx index f92037e93..3d21029ab 100644 --- a/src/client/views/smartdraw/DrawingFillHandler.tsx +++ b/src/client/views/smartdraw/DrawingFillHandler.tsx @@ -1,20 +1,21 @@ import { imageUrlToBase64 } from '../../../ClientUtils'; -import { Doc, StrListCast } from '../../../fields/Doc'; +import { Doc, DocListCast, StrListCast } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { List } from '../../../fields/List'; -import { DocCast, ImageCast } from '../../../fields/Types'; +import { DocCast, ImageCast, NumCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; import { Upload } from '../../../server/SharedMediaTypes'; import { gptDescribeImage } from '../../apis/gpt/GPT'; import { Docs } from '../../documents/Documents'; import { Networking } from '../../Network'; +import { DocCreatorMenu } from '../nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu'; import { DocumentView, DocumentViewInternal } from '../nodes/DocumentView'; import { OpenWhere } from '../nodes/OpenWhere'; import { AspectRatioLimits, FireflyDimensionsMap, FireflyImageDimensions, FireflyStylePresets } from './FireflyConstants'; const DashDropboxId = '2m86iveqdr9vzsa'; export class DrawingFillHandler { - static drawingToImage = async (drawing: Doc, strength: number, user_prompt: string, styleDoc?: Doc, flexDimensions?: boolean) => { + static drawingToImage = async (drawing: Doc, strength: number, user_prompt: string, styleDoc?: Doc, fromDocCreator?: DocCreatorMenu) => { const docData = drawing[DocData]; const tags = StrListCast(docData.tags).map(tag => tag.slice(1)); const styles = tags.filter(tag => FireflyStylePresets.has(tag)); @@ -44,31 +45,39 @@ export class DrawingFillHandler { return imageUrlToBase64(structureUrl) .then(gptDescribeImage) .then((prompt, newPrompt = user_prompt || prompt) => - Networking.PostToServer('/queryFireflyImageFromStructure', { prompt: `${newPrompt}`, width: flexDimensions ? aspectRatio * 2000 : dims.width, height: flexDimensions ? (1 - aspectRatio) * 2000 : dims.height, structureUrl, strength, presets: styles, styleUrl }) + Networking.PostToServer('/queryFireflyImageFromStructure', { prompt: `${newPrompt}`, width: dims.width, height: dims.height, structureUrl, strength, presets: styles, styleUrl }) .then(res => { + console.log('res is: ', res) const genratedDocs = DocCast(drawing.ai_firefly_generatedDocs) ?? Docs.Create.MasonryDocument([], { _width: 400, _height: 400 }); drawing[DocData].ai_firefly_generatedDocs = genratedDocs; - (res as Upload.ImageInformation[]).map(info => - Doc.AddDocToList( - genratedDocs, - undefined, - Docs.Create.ImageDocument(info.accessPaths.agnostic.client, { - ai: 'firefly', - 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, - }), - undefined, - undefined, - true - ) - ); - if (!DocumentView.getFirstDocumentView(genratedDocs)) DocumentViewInternal.addDocTabFunc(genratedDocs, OpenWhere.addRight); + (res as Upload.ImageInformation[]).map(info => { + const doc = Docs.Create.ImageDocument(info.accessPaths.agnostic.client, { + ai: 'firefly', + 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, + }) + if (!fromDocCreator) { + Doc.AddDocToList( + genratedDocs, + undefined, + doc, + undefined, + undefined, + true + ); + } else { + fromDocCreator.addVariationDoc(doc); + } + }); + if (!DocumentView.getFirstDocumentView(genratedDocs) && !fromDocCreator) { + DocumentViewInternal.addDocTabFunc(genratedDocs, OpenWhere.addRight); + } }) .catch(e => { if (e.toString().includes('Dropbox') && confirm('Create image failed. Try authorizing DropBox?\r\n' + e.toString().replace(/^[^"]*/, ''))) { diff --git a/src/server/ApiManagers/FireflyManager.ts b/src/server/ApiManagers/FireflyManager.ts index e75ede9df..e5e030b0f 100644 --- a/src/server/ApiManagers/FireflyManager.ts +++ b/src/server/ApiManagers/FireflyManager.ts @@ -302,7 +302,8 @@ export default class FireflyManager extends ApiManager { .then(dropboxStructureUrl => { if (dropboxStructureUrl instanceof Error) { _invalid(res, dropboxStructureUrl.message); - throw new Error('Error uploading images to dropbox'); + console.log('res:', res, 'error: ', dropboxStructureUrl, 'message: ', dropboxStructureUrl.message) + //throw new Error('Error uploading images to dropbox'); } return { styleUrl, structureUrl: dropboxStructureUrl }; }) |