From 4949c68f38049da55ceaa3e95ea155f38d6a3748 Mon Sep 17 00:00:00 2001 From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com> Date: Thu, 8 Aug 2024 10:38:35 -0400 Subject: UI for GPT templates in doccreator menu --- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 45 ------- .../views/nodes/DataVizBox/DocCreatorMenu.scss | 128 ++++++++++++++++-- .../views/nodes/DataVizBox/DocCreatorMenu.tsx | 147 ++++++++++++++++----- src/client/views/nodes/ImageBox.tsx | 1 + 4 files changed, 228 insertions(+), 93 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index c5a1da1da..a6d3bfa49 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -568,51 +568,6 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { this.applyLayout(templateInfo, docs); } - generateTemplates = async () => { - try { - const res = await gptAPICall('Please generate for the fields: Image, Description, Divider, Response', GPTCallType.TEMPLATE); - - if (res) { - const templates: {template_type: string, fieldVals: {title: string, tlx: string, tly: string, brx: string, bry: string}[]}[] = JSON.parse(res); - this.createGeneratedTemplates(templates, 500, 500); - //console.log(res); - } - } catch (err) { - console.error(err); - } - - } - - createGeneratedTemplates = (layouts: {template_type: string, fieldVals: {title: string, tlx: string, tly: string, brx: string, bry: string}[]}[], tempWidth: number, tempHeight: number) => { - const mainCollection = this.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView; - - layouts.forEach(layout => { - const fields: Doc[] = layout.fieldVals.map(field => { - const left: number = Number(field.tlx) * tempWidth / 2; const top: number = Number(field.tly) * tempHeight / 2; //prettier-ignore - const right: number = Number(field.brx) * tempWidth / 2; const bottom: number = Number(field.bry) * tempHeight / 2; //prettier-ignore - const height = bottom - top; const width = right - left; //prettier-ignore - const doc = !field.title.includes('$$') ? Docs.Create.TextDocument('', { _height: height, _width: width, title: field.title, x: left, y: top, _text_fontSize: `${height/2}` }) : Docs.Create.ImageDocument('', { _height: height, _width: 250, title: field.title.replace(/$$/g, ''), x: left, y: top }); - return doc; - }); - - const template = Docs.Create.FreeformDocument(fields, { _height: tempHeight, _width: tempWidth, title: layout.template_type, x: 400, y: 400 }); - mainCollection.addDocument(template); - }); - } - - createBasicTemplates = (colsToLayout: {width: number, height: number, x: number, y: number, title: string}[]) => { - const mainCollection = this.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView; - - const fields: Doc[] = colsToLayout.map(layout => { - const field = Docs.Create.TextDocument('', { _height: layout.height, _width: layout.width, title: layout.title, x: layout.x, y: layout.y }); - return field; - }); - - const template = Docs.Create.FreeformDocument(fields, { _height: 500, _width: 500, title: 'template', x: 400, y: 400 }) - - mainCollection.addDocument(template); - } - /** * creates a new dataviz document filter from this one * it appears to the right of this document, with the diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss b/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss index b3bacb13c..e2b4014bd 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss @@ -22,14 +22,14 @@ } .docCreatorMenu-menu-button { - width: 30px; - height: 30px; + width: 25px; + height: 25px; background: whitesmoke; - background-color: rgb(34, 34, 37); + background-color: rgb(50, 50, 50); border-radius: 5px; border: 1px solid rgb(180, 180, 180); padding: 0px; - font-size: 14px; + font-size: 13px; //box-shadow: 3px 3px rgb(29, 29, 31); &:hover { @@ -222,7 +222,7 @@ .docCreatorMenu-option-divider { border-top: 1px solid rgb(180, 180, 180); - width: 80%; + width: 95%; margin-top: 10px; margin-bottom: 10px; } @@ -256,6 +256,18 @@ // DocCreatorMenu templates preview CSS //-------------------------------------------------------------------------------------------------------------------------------------------- +.docCreatorMenu-templates-view { + display: flex; + flex-direction: column; + justify-content: center; + align-items: flex-start; + margin: 5px; + margin-top: 0px; + width: calc(100% - 10px); + height: calc(100% - 30px); + border: 1px solid rgb(180, 180, 180); + border-radius: 5px; +} .docCreatorMenu-preview-container { display: grid; @@ -263,20 +275,18 @@ grid-template-rows: 140px; grid-auto-rows: 141px; overflow-y: scroll; - margin: 5px; + margin: 0px; margin-top: 0px; - width: calc(100% - 10px); - height: calc(100% - 30px); - border: 1px solid rgb(180, 180, 180); - border-radius: 5px; + width: 100%; + height: 100%; } .docCreatorMenu-preview-window { display: flex; justify-content: center; align-items: center; - width: 125px; - height: 125px; + width: 113px; + height: 113px; margin-top: 10px; margin-left: 10px; border: 1px solid rgb(163, 163, 163); @@ -295,9 +305,103 @@ &.empty { font-size: 35px; + flex: 0 0 auto; + + &.GPT { + margin-top: 0px; + } + } +} + +.docCreatorMenu-section { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + position: relative; + margin: 0px; + width: 100%; + height: 250; + flex: 0 0 auto; +} + +.docCreatorMenu-GPT-options-container { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + position: relative; + width: auto; + margin: 0px; + margin-top: 5px; + padding: 0px; +} + +.docCreatorMenu-GPT-templates-preview { + display: flex; + flex-direction: row; + //justify-content: center; + align-items: center; + overflow-y: scroll; + position: relative; + height: 125px; + width: calc(100% - 10px); + -ms-overflow-style: none; + scrollbar-width: none; +} + +.docCreatorMenu-section-topbar { + position: relative; + display: flex; + flex-direction: row; + width: 100%; + + .section-reveal-options { + margin: 0px; + margin-left: auto; + border: 0px; + background: none; + } +} + +.docCreatorMenu-section-title { + border: 1px solid rgb(163, 163, 163); + border-top: 0px; + border-left: 0px; + border-bottom-right-radius: 5px; + font-size: 12px; + padding: 2px; + padding-left: 3px; + padding-right: 3px; + margin-bottom: 3px; +} + +.docCreatorMenu-GPT-generate { + height: 30px; + width: 30px; + background-color: rgb(176, 229, 149); + border: 1px solid rgb(126, 219, 80); + border-radius: 5px; + padding: 0px; + font-size: 14px; + color: white; + letter-spacing: 1px; + flex: 0 0 auto; + + &:hover { + background-color: rgb(129, 223, 83); + border: 2px solid rgb(80, 185, 28); } } +.docCreatorMenu-GPT-prompt-input { + width: 140px; + overflow-y: scroll; + border: 1px solid rgb(180, 180, 180); + background-color: rgb(35, 35, 35); + border-radius: 3px; +} + //------------------------------------------------------------------------------------------------------------------------------------------ // DocCreatorMenu options CSS //-------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx index 411257ff7..781cbcb55 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx @@ -3,7 +3,7 @@ import { IReactionDisposer, ObservableMap, action, computed, makeObservable, obs import { observer } from 'mobx-react'; import * as React from 'react'; import { returnAll, returnFalse, setupMoveUpEvents } from '../../../../ClientUtils'; -import { Doc, NumListCast } from '../../../../fields/Doc'; +import { Doc, NumListCast, StrListCast } from '../../../../fields/Doc'; import { DocCast, ImageCast } from '../../../../fields/Types'; import { ImageField } from '../../../../fields/URLField'; import { emptyFunction } from '../../../../Utils'; @@ -17,6 +17,9 @@ import { Id } from '../../../../fields/FieldSymbols'; import { Colors, IconButton, Size } from 'browndash-components'; import { MakeTemplate } from '../../../util/DropConverter'; import { DragManager } from '../../../util/DragManager'; +import { GPTCallType, gptAPICall } from '../../../apis/gpt/GPT'; +import { CollectionFreeFormView } from '../../collections/collectionFreeForm/CollectionFreeFormView'; +import { Docs } from '../../../documents/Documents'; export enum LayoutType { Stacked = 'stacked', @@ -41,6 +44,10 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> { @observable _layoutPreviewScale: number = 1; @observable _savedLayouts: DataVizTemplateLayout[] = []; + @observable _GPTTemplates: Doc[] | undefined = undefined; + @observable _GPTOpt: boolean = false; + @observable _userPrompt: string = ''; + @observable _pageX: number = 0; @observable _pageY: number = 0; @observable _indicatorX: number | undefined = undefined; @@ -105,6 +112,10 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> { } } + @computed get selectedFields(){ + return StrListCast(this._dataViz?.layoutDoc._dataViz_axes); + } + @computed get canMakeDocs(){ return this._selectedTemplate !== undefined && this._layout !== undefined; } @@ -254,8 +265,8 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> { if (this._initDimensions.y === undefined) this._initDimensions.y = this._pageY; const {height, width, x, y} = this._initDimensions; - this._menuDimensions.width = Math.max(100, scale.x * width); - this._menuDimensions.height = Math.max(100, scale.y * height); + this._menuDimensions.width = Math.max(300, scale.x * width); + this._menuDimensions.height = Math.max(200, scale.y * height); this._pageX = x + translation.x; this._pageY = y + translation.y; }; @@ -293,10 +304,104 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> { && this._layout.columns === layout.columns; } + generateTemplates = async (inputText: string) => { + let prompt: string = 'Please generate for the fields:'; + this.selectedFields?.forEach(field => prompt += ` ${field},`) + prompt += ` Additional prompt: ${inputText}`; + + try { + const res = await gptAPICall(prompt, GPTCallType.TEMPLATE); + + if (res) { + const templates: {template_type: string, fieldVals: {title: string, tlx: string, tly: string, brx: string, bry: string}[]}[] = JSON.parse(res); + this.createGeneratedTemplates(templates, 500, 500); + } + } catch (err) { + console.error(err); + } + + } + + createGeneratedTemplates = (layouts: {template_type: string, fieldVals: {title: string, tlx: string, tly: string, brx: string, bry: string}[]}[], tempWidth: number, tempHeight: number) => { + const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView; + + layouts.forEach(layout => { + const fields: Doc[] = layout.fieldVals.map(field => { + const left: number = Number(field.tlx) * tempWidth / 2; const top: number = Number(field.tly) * tempHeight / 2; //prettier-ignore + const right: number = Number(field.brx) * tempWidth / 2; const bottom: number = Number(field.bry) * tempHeight / 2; //prettier-ignore + const height = bottom - top; + const width = right - left; + const doc = !field.title.includes('$$') ? Docs.Create.TextDocument('', { _height: height, _width: width, title: field.title, x: left, y: top, _text_fontSize: `${height/2}` }) : Docs.Create.ImageDocument('', { _height: height, _width: width, title: field.title.replace(/$$/g, ''), x: left, y: top }); + return doc; + }); + + const template = Docs.Create.FreeformDocument(fields, { _height: tempHeight, _width: tempWidth, title: layout.template_type, x: 400, y: 400 }); + mainCollection.addDocument(template); + }); + } + get templatesPreviewContents(){ const renderedTemplates: Doc[] = []; + + const GPTOptions = +
+ + return ( -
+
+
+
Suggested Templates
+ +
+
+
+
+
+
+
+ {this._GPTOpt ? (
+
+ + +
+ {this._GPTOpt ? GPTOptions : null} +
) : null} +
+
+
+
+
Your Templates
+ +
+
+
this.setUpButtonClick(e, this.basicTemplateTest)} + > + +
+ {this._templateDocs.map(doc => ({icon: ImageCast(doc.icon), doc})).filter(info => info.icon && info.doc).map(info => { + if (renderedTemplates.includes(info.doc)) return undefined; + renderedTemplates.push(info.doc); + return (
this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedTemplate(info.doc)))}> + +
+ )})} +
+
+ {/*
{this._templateDocs.map(doc => ({icon: ImageCast(doc.icon), doc})).filter(info => info.icon && info.doc).map(info => { if (renderedTemplates.includes(info.doc)) return undefined; @@ -316,6 +421,7 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> { >
+
*/} ); } @@ -546,12 +652,7 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> { } basicTemplateTest = () => { - const temps: {width: number; height: number; x: number; y: number; title: string}[] = [ - {width: 200, height: 50, x: -100, y: -200, title: 'title'}, - {width: 300, height: 300, x: -150, y: -100, title: 'image'}, - {width: 200, height: 50, x: -100, y: -200, title: 'description'}, - ] - this._dataViz?.generateTemplates(); + this.generateTemplates(this._userPrompt); //this._dataViz?.createBasicTemplates(temps); } @@ -609,31 +710,6 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> { return (
{!this._shouldDisplay ? undefined : - <> - {/*
this.onPointerMove(e)} - onPointerDown={e => - setupMoveUpEvents( - this, - e, - (e) => { - this._draggingIndicator = true; - this._startPos = {x: 0, y: 0}; - this._startPos.x = e.pageX - (this._ref?.getBoundingClientRect().left ?? 0); - this._startPos.y = e.pageY - (this._ref?.getBoundingClientRect().top ?? 0); - return true; - }, - emptyFunction, - undoable(clickEv => { - clickEv.stopPropagation(); - }, 'drag menu') - ) - }/> */}
this._ref = r} @@ -681,7 +757,6 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
{this.renderSelectedViewType}
- }
) diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 92a5a1533..faea05104 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -295,6 +295,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent() { @computed get nativeSize() { TraceMobx(); + if (this.paths.length && this.paths[0].includes('icon-hi')) return { nativeWidth: NumCast(this.layoutDoc._width), nativeHeight: NumCast(this.layoutDoc._height), nativeOrientation: 0} const nativeWidth = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth'], NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth'], 500)); const nativeHeight = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight'], NumCast(this.layoutDoc[this.fieldKey + '_nativeHeight'], 500)); const nativeOrientation = NumCast(this.dataDoc[this.fieldKey + '_nativeOrientation'], 1); -- cgit v1.2.3-70-g09d2