diff options
Diffstat (limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx')
-rw-r--r-- | src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx | 261 |
1 files changed, 100 insertions, 161 deletions
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx index ed2e20843..48fea91e2 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx @@ -34,8 +34,9 @@ import { TemplateManager } from './Backend/TemplateManager'; import { DrawingFillHandler } from '../../../smartdraw/DrawingFillHandler'; import { CgPathIntersect } from 'react-icons/cg'; import { StaticContentField } from './TemplateFieldTypes/StaticContentField'; -import { SuggestedTemplatesWindow } from './Menu/SuggestedTemplatesWindow'; -import { TemplateMenuGPTManager } from './Backend/TemplateMenuGPTManager'; +import { TemplateMenuAIUtils } from './Backend/TemplateMenuAIUtils' +import { TemplateSidescrollView } from './Menu/TemplatesSidescrollDisplay'; +import { TemplateEditingWindow } from './Menu/TemplateEditingWindow'; export enum LayoutType { FREEFORM = 'Freeform', @@ -91,7 +92,6 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> private _disposers: { [name: string]: IDisposer } = {}; private _ref: HTMLDivElement | null = null; private templateManager: TemplateManager; - private GPTManager: TemplateMenuGPTManager; @observable _fullyRenderedDocs: Doc[] = []; // collection of templates filled in with content @observable _renderedDocCollection: Doc | undefined = undefined; // fullyRenderedDocs in a parent collection @@ -102,27 +102,16 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> @observable _currEditingTemplate: Template | undefined = undefined; @observable _userCreatedFields: Col[] = []; - @observable _selectedCols: { title: string; type: string; desc: string }[] | undefined = []; @observable _collapsedCols: String[] = []; //any columns whose options panels are hidden @observable _conditions: Conditional[] = []; @observable _currEditingConditional: Conditional = {} as Conditional; @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 }[] = []; - @observable _GPTOpt: boolean = false; - @observable _callCount: number = 0; @observable _GPTLoading: boolean = false; - @observable _DOCCC: Doc | undefined; @observable _pageX: number = 0; @observable _pageY: number = 0; @@ -133,9 +122,8 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> @observable _startPos?: { x: number; y: number }; @observable _shouldDisplay: boolean = false; - @observable _menuContent: 'templates' | 'options' | 'saved' | 'dashboard' = 'templates'; + @observable _menuContent: 'templates' | 'options' | 'saved' | 'dashboard' | 'templateEditing' = 'templates'; @observable _dragging: boolean = false; - @observable _draggingIndicator: boolean = false; @observable _dataViz?: DataVizBox; @observable _interactionLock: boolean | undefined; @observable _snapPt: { x: number; y: number } = { x: 0, y: 0 }; @@ -145,20 +133,14 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> @observable _resizeUndo: UndoManager.Batch | undefined = undefined; @observable _initDimensions: { width: number; height: number; x?: number; y?: number } = { width: 300, height: 400, x: undefined, y: undefined }; @observable _menuDimensions: { width: number; height: number } = { width: 400, height: 400 }; - @observable _editing: boolean = false; constructor(props: DocCreateMenuProps) { super(props); makeObservable(this); DocCreatorMenu.Instance = this; this.templateManager = new TemplateManager(TemplateLayouts.allTemplates); - this.GPTManager = new TemplateMenuGPTManager(); } - setContainerRef: React.LegacyRef<HTMLDivElement> = (node) => { - this._previewWindow = node; - }; - @action setDataViz = (dataViz: DataVizBox) => { this._dataViz = dataViz; this._selectedTemplate = undefined; @@ -392,7 +374,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> } @action updateRenderedPreviewCollection = async (template: Template) => { - this._fullyRenderedDocs = this._dataViz ? ((await this.createDocsFromTemplate(this._dataViz, template)).filter(doc => doc).map(doc => doc!) ?? []) : []; + this._fullyRenderedDocs = this._dataViz ? ((await this.templateManager.createDocsFromTemplate(this._dataViz, template, this.fieldsInfos, this.DEBUG_MODE)).filter(doc => doc).map(doc => doc!) ?? []) as unknown as Doc[] : []; this.updateRenderedDocCollection(); }; @@ -517,19 +499,88 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> this.forceUpdate(); }; - generatePresetTemplates = async (debug: boolean) => { + compileFieldDescriptions = (templates: Template[]): string => { + let descriptions: string = ''; + templates.forEach(template => { + descriptions += `---------- NEW TEMPLATE TO INCLUDE: The title is: ${template.title}. Its fields are: `; + descriptions += template.descriptionSummary; + }); + + return descriptions; + }; + + compileColDescriptions = (cols: Col[]): string => { + let descriptions: string = ' ------------- COL DESCRIPTIONS START HERE:'; + cols.forEach(col => (descriptions += `{title: ${col.title}, sizes: ${String(col.sizes)}, type: ${col.type}, descreiption: ${col.desc}} `)); + + return descriptions; + }; + + getColByTitle = (title: string) => { + return this.fieldsInfos.filter(col => col.title === title)[0]; + }; + + @action + assignColsToFields = async (templates: Template[], cols: Col[]): Promise<[Template, { [field: number]: Col }][]> => { + const fieldDescriptions: string = this.compileFieldDescriptions(templates); + const colDescriptions: string = this.compileColDescriptions(cols); + + const inputText = fieldDescriptions.concat(colDescriptions); + + const prompt: string = `(${Math.random() * 100000}) ${inputText}`; + + this._GPTLoading = true; + + try { + const res = await gptAPICall(prompt, GPTCallType.TEMPLATE); + + if (res) { + const assignments: { [templateTitle: string]: { [fieldID: string]: string } } = JSON.parse(res); + const brokenDownAssignments: [Template, { [fieldID: number]: Col }][] = []; + + Object.entries(assignments).forEach(([tempTitle, assignment]) => { + const template = templates.filter(temp => temp.title === tempTitle)[0]; + if (!template) return; + const toObj = Object.entries(assignment).reduce( + (a, [fieldID, colTitle]) => { + const col = this.getColByTitle(colTitle); + if (!this._userCreatedFields.includes(col)) { + // do the following for any fields not added by the user; will change in the future, for now only GPT content works with user-added field + const field = template.getFieldByID(Number(fieldID)); + field.setContent(col.defaultContent ?? '', col.type === TemplateFieldType.VISUAL ? ViewType.IMG : ViewType.TEXT); + field.setTitle(col.title); + } else { + a[Number(fieldID)] = this.getColByTitle(colTitle); + } + return a; + }, + {} as { [field: number]: Col } + ); + brokenDownAssignments.push([template, toObj]); + }); + + return brokenDownAssignments; + } + } catch (err) { + console.error(err); + } + + return []; + }; + + generatePresetTemplates = async () => { const templates: Template[] = []; - if (debug) { + if (this.DEBUG_MODE) { templates.push(...this.templateManager.templates); } else { this._dataViz?.updateColDefaults(); templates.push(...this.templateManager.getValidTemplates(this.fieldsInfos)); - const assignments = await this.GPTManager.assignColsToFields(templates, this.fieldsInfos); + const assignments = await this.assignColsToFields(templates, this.fieldsInfos); - const renderedTemplatePromises = assignments.map(([template, assgns]) => this.GPTManager.applyGPTContentToTemplate(template, assgns)); + const renderedTemplatePromises = assignments.map(([template, assgns]) => TemplateMenuAIUtils.applyGPTContentToTemplate(template, assgns)); await Promise.all(renderedTemplatePromises); } @@ -542,16 +593,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> ); }; - @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[]> => { + generateVariations = async (onDoc: Doc, prompt: string): Promise<Doc[]> => { this._loadingVariants = true; this.variationDocss = []; const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView; @@ -561,7 +603,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> clone.x = 10000; clone.y = 10000; - await DrawingFillHandler.drawingToImage(clone, 100, this._variationPrompt, undefined, this) + await DrawingFillHandler.drawingToImage(clone, 100, prompt, undefined, this) this._loadingVariants = false; @@ -591,130 +633,15 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> @action setExpandedView = (template: Template | undefined) => { this._currEditingTemplate = template; - 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" 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 ( - <div className="docCreatorMenu-expanded-template-preview"> - <div className="top-panel" /> - {rendered} - <div className="right-buttons-panel"> - <button - className="docCreatorMenu-menu-button section-reveal-options top-right" - onPointerDown={e => - this.setUpButtonClick(e, () => { - if (!this._currEditingTemplate) return; - if (this._currEditingTemplate === this._selectedTemplate) { - this.updateRenderedPreviewCollection(this._currEditingTemplate); - } - this.setExpandedView(undefined); - }) - }> - <FontAwesomeIcon icon="minimize" /> - </button> - <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> - ); - } + if (template) { + this._menuContent = 'templateEditing'; + } else { + this._menuContent = 'templates'; + } - 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} - /> - ); + //Docs.Create.FreeformDocument([doc], { _height: NumListCast(doc._height)[0], _width: NumListCast(doc._width)[0], title: ''}); + }; @action updateXMargin = (input: string) => { this._layout.xMargin = Number(input); @@ -1137,7 +1064,19 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps> get renderSelectedViewType() { switch (this._menuContent) { - case 'templates': return <SuggestedTemplatesWindow menu={this} setupButtonClick={this.setUpButtonClick}/>; + case 'templates': + return <TemplateSidescrollView + title={'Suggested Templates'} + menu={this} + setupButtonClick={this.setUpButtonClick} + templates={this._suggestedTemplates} + /> + case 'templateEditing': + return <TemplateEditingWindow + setupButtonClick={this.setUpButtonClick} + template={this._currEditingTemplate as Template} + menu={this} + /> case 'options': return this.optionsMenuContents; case 'dashboard': return this.dashboardContents; } // prettier-ignore |