aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/apis/gpt/GPT.ts2
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu.scss10
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx99
3 files changed, 69 insertions, 42 deletions
diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts
index 8eb7151b4..144b49bde 100644
--- a/src/client/apis/gpt/GPT.ts
+++ b/src/client/apis/gpt/GPT.ts
@@ -54,7 +54,7 @@ const callTypeMap: { [type: string]: GPTCallOpts } = {
temp: 0,
prompt: 'List unique differences between the content of the UserAnswer and Rubric. Before each difference, label it and provide any additional information the UserAnswer missed and explain it in second person without separating it into UserAnswer and Rubric content and additional information. If there are no differences, say correct',
},
- template: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'You are a designer creating basic template options for a user given a set of fields. Your only job is adding blank rectangles to a canvas, one for each field. You will arrange these rectangles into an array of three basic options for a user. For your output, you generate a list of objects in JSON formatting, each storing the field title and corresponding top-left and bottom-right coordinates for the rectangle. The units for your coordinates are -1 to 1 on each axis. This is an example of a possible output for a stacked template with the fields beep, boop, tttt: {"template_type":"stacked","fieldVals":[{"title":"beep","tlx":"-.7","tly":"-.9","brx":".7","bry":"-.7"},{"title":"boop","tlx":"-.9","tly":"-.4","brx":".9","bry":"0"},{"title":"tttt","tlx":"-.9","tly":".1","brx":".9","bry":".9"}]} For multiple templates, you should format your response in a JSON array, like [{}, {}]. Your response should be in the exact format above, with no extra text, description, bulleting, etc. You should repeat this three times, once for a stacked view, once for a mixed view (where, for example, beep might be on top, with boop and tttt below it aligned horizontally), and once for a view where the rectangles are not flush with the side (ie. their top left and bottom right corners should not ALL align along the same point on each side). If one or more fields are some variation of image (ie. IMG, image, photo, etc.), make that rectangle the central focus (bigger, centered, etc.) AND put its "title" field in $$__$$ (ie, "title":"$$img$$", !!IMPORTANT!!). Fields SHOULD BE IN DIFFERENT ORDERS from template to template (ie. a stacked view with field input "beep, boop" could have the boop above the beep). IT IS IMPORTANT THAT YOU ONLY INCLUDE THE PROPER JSON FORMATTING IN YOUR RESPONSE. IT IS ALSO IMPORTANT THAT NO RECTANGLES OVERLAP'}
+ template: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'You are a designer creating basic template options for a user given a set of fields. Your only job is adding blank rectangles to a canvas, one for each field. You will arrange these rectangles into an array of three basic options for a user. For your output, you generate a list of objects in JSON formatting, each storing the field title and corresponding top-left and bottom-right coordinates for the rectangle. The units for your coordinates are -1 to 1 on each axis. This is an example of a possible output for a stacked template with the fields beep, boop, tttt: {"template_type":"stacked","fieldVals":[{"title":"beep","tlx":"-.7","tly":"-.9","brx":".7","bry":"-.7"},{"title":"boop","tlx":"-.9","tly":"-.4","brx":".9","bry":"0"},{"title":"tttt","tlx":"-.9","tly":".1","brx":".9","bry":".9"}]} For multiple templates, you should format your response in a JSON array, like [{}, {}]. Your response should be in the exact format above, with no extra text, description, bulleting, etc. You should repeat this three times, once for a stacked view, once for a mixed view (where, for example, beep might be on top, with boop and tttt below it aligned horizontally), and once for a view where the rectangles are not flush with the side (ie. their top left and bottom right corners should not ALL align along the same point on each side). If one or more fields are some variation of image (ie. IMG, image, photo, etc.), make that rectangle the central focus (bigger, centered, etc.) AND put its "title" field in $$__$$. Fields SHOULD BE IN DIFFERENT ORDERS from template to template (ie. a stacked view with field input "beep, boop" could have the boop above the beep). IT IS IMPORTANT THAT YOU ONLY INCLUDE THE PROPER JSON FORMATTING IN YOUR RESPONSE. IT IS ALSO IMPORTANT THAT NO RECTANGLES OVERLAP'}
};
let lastCall = '';
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss b/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss
index ca6534379..3e97e9d08 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss
@@ -341,6 +341,12 @@
bottom: 0px;
left: 0px;
}
+
+ &.top-left {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ }
}
&:hover .option-button {
@@ -385,6 +391,10 @@
width: calc(100% - 10px);
-ms-overflow-style: none;
scrollbar-width: none;
+
+ .loading-spinner {
+ justify-self: center;
+ }
}
.docCreatorMenu-section-topbar {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
index 3e5fc156e..ee154994e 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx
@@ -4,7 +4,7 @@ import { observer } from 'mobx-react';
import * as React from 'react';
import { returnAll, returnFalse, setupMoveUpEvents } from '../../../../ClientUtils';
import { Doc, NumListCast, StrListCast } from '../../../../fields/Doc';
-import { DocCast, ImageCast, ScriptCast } from '../../../../fields/Types';
+import { DocCast, ImageCast, ScriptCast, StrCast } from '../../../../fields/Types';
import { ImageField } from '../../../../fields/URLField';
import { emptyFunction } from '../../../../Utils';
import { SnappingManager } from '../../../util/SnappingManager';
@@ -23,6 +23,7 @@ import { Docs } from '../../../documents/Documents';
import { OpenWhere } from '../OpenWhere';
import { IDisposer } from 'mobx-utils';
import { LightboxView } from '../../LightboxView';
+import ReactLoading from 'react-loading';
export enum LayoutType {
Stacked = 'stacked',
@@ -53,6 +54,7 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
@observable _GPTOpt: boolean = false;
@observable _userPrompt: string = '';
@observable _callCount: number = 0;
+ @observable _GPTLoading: boolean = false;
@observable _pageX: number = 0;
@observable _pageY: number = 0;
@@ -83,7 +85,7 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
super(props);
makeObservable(this);
DocCreatorMenu.Instance = this;
- setTimeout(() => this.generateTemplates(''));
+ //setTimeout(() => this.generateTemplates(''));
}
@action setDataViz = (dataViz: DataVizBox) => { this._dataViz = dataViz };
@@ -182,7 +184,7 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
document.addEventListener('pointerup', this.onPointerUp);
this._disposers.templates = reaction(() => this._templateDocs.slice(), (docs) => docs.map(this.getIcon));
this._disposers.gpt = reaction(() => this._GPTTemplates.slice(), (docs) => docs.map(this.getIcon));
- this._disposers.columns = reaction(() => this._dataViz?.layoutDoc._dataViz_axes, () => {console.log(true); this.generateTemplates('')})
+ //this._disposers.columns = reaction(() => this._dataViz?.layoutDoc._dataViz_axes, () => {this.generateTemplates('')})
this._disposers.lightbox = reaction(() => LightboxView.LightboxDoc(), doc => { doc ? this._shouldDisplay && this.closeMenu() : !this._shouldDisplay && this.openMenu()})
}
@@ -322,13 +324,17 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
let prompt: string = `(#${origCount}) Please generate for the fields:`;
this.selectedFields?.forEach(field => prompt += ` ${field},`)
- prompt += ` Additional prompt: ${inputText}`;
+ prompt += ` (-----NOT A FIELD-----) Additional prompt: ${inputText}`;
console.log(prompt)
+ this._GPTLoading = true;
+
try {
const res = await gptAPICall(prompt, GPTCallType.TEMPLATE);
if (res && this._callCount === origCount) {
+ this._GPTTemplates = [];
+ this._GPTLoading = false;
const templates: {template_type: string, fieldVals: {title: string, tlx: string, tly: string, brx: string, bry: string}[]}[] = JSON.parse(res);
this.createGeneratedTemplates(templates, 500, 500);
}
@@ -348,11 +354,12 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
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 });
+ console.log(field.title);
+ 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 });
+ const template = Docs.Create.FreeformDocument(fields, { _height: tempHeight, _width: tempWidth, title: layout.template_type, x: 40000, y: 40000 });
mainCollection.addDocument(template);
@@ -371,6 +378,10 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
Doc.UnBrushDoc(doc);
}
+ removeTemplate = (doc: Doc) => {
+ this._templateDocs.splice(this._templateDocs.indexOf(doc), 1);
+ }
+
get templatesPreviewContents(){
const renderedTemplates: Doc[] = [];
@@ -380,43 +391,46 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
return (
<div className='docCreatorMenu-templates-view'>
<div className='docCreatorMenu-section' style={{height: this._GPTOpt ? 200 : 165}}>
- <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, () => this._GPTOpt = !this._GPTOpt)}>
- <FontAwesomeIcon icon='gear'/>
- </button>
- </div>
- <div className='docCreatorMenu-templates-preview-window'>
- {this._GPTTemplates?.map(doc =>
-
- //<div className='docCreatorMenu-preview-window empty'/>
- ({icon: ImageCast(doc.icon), doc})).filter(info => info.icon && info.doc).map(info =>
- <div
- className='docCreatorMenu-preview-window'
- style={{
- border: this._selectedTemplate === info.doc ? `solid 3px ${Colors.MEDIUM_BLUE}` : '',
- boxShadow: this._selectedTemplate === info.doc ? `0 0 15px rgba(68, 118, 247, .8)` : ''
- }}
- onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedTemplate(info.doc)))}>
- <button className='option-button left' onPointerDown={e => this.setUpButtonClick(e, () => {this.editTemplate(info.doc)})}>
- <FontAwesomeIcon icon='pencil' color='black'/>
- </button>
- <button className='option-button right' onPointerDown={e => this.setUpButtonClick(e, () => this._templateDocs.push(info.doc))}>
- <FontAwesomeIcon icon='plus' color='black'/>
- </button>
- <img className='docCreatorMenu-preview-image' src={info.icon!.url.href.replace(".png", "_o.png")} />
- </div>
- )}
- </div>
- {this._GPTOpt ? (<div className='docCreatorMenu-GPT-options'>
- <div className='docCreatorMenu-GPT-options-container'>
- <button className='docCreatorMenu-menu-button' onPointerDown={e => this.setUpButtonClick(e, () => this.generateTemplates(this._userPrompt))}>
- <FontAwesomeIcon icon='arrows-rotate'/>
+ <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, () => this._GPTOpt = !this._GPTOpt)}>
+ <FontAwesomeIcon icon='gear'/>
</button>
- <input className='docCreatorMenu-GPT-prompt-input' placeholder='Additional prompt:' onChange={e => this._userPrompt = e.target.value}/>
</div>
- {this._GPTOpt ? GPTOptions : null}
- </div>) : null}
+ <div className='docCreatorMenu-templates-preview-window' style={{justifyContent: this._GPTLoading ? 'center' : ''}}>
+ {this._GPTLoading ? (
+ <div className="loading-spinner">
+ <ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} />
+ </div>
+ ) : (
+ this._GPTTemplates?.map(doc =>
+ ({icon: ImageCast(doc.icon), doc})).filter(info => info.icon && info.doc).map(info =>
+ <div
+ className='docCreatorMenu-preview-window'
+ style={{
+ border: this._selectedTemplate === info.doc ? `solid 3px ${Colors.MEDIUM_BLUE}` : '',
+ boxShadow: this._selectedTemplate === info.doc ? `0 0 15px rgba(68, 118, 247, .8)` : ''
+ }}
+ onPointerDown={e => this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedTemplate(info.doc)))}>
+ <button className='option-button left' onPointerDown={e => this.setUpButtonClick(e, () => {this.editTemplate(info.doc)})}>
+ <FontAwesomeIcon icon='pencil' color='black'/>
+ </button>
+ <button className='option-button right' onPointerDown={e => this.setUpButtonClick(e, () => this._templateDocs.push(info.doc))}>
+ <FontAwesomeIcon icon='plus' color='black'/>
+ </button>
+ <img className='docCreatorMenu-preview-image' src={info.icon!.url.href.replace(".png", "_o.png")} />
+ </div>
+ ))}
+ </div>
+ {this._GPTOpt ? (<div className='docCreatorMenu-GPT-options'>
+ <div className='docCreatorMenu-GPT-options-container'>
+ <button className='docCreatorMenu-menu-button' onPointerDown={e => this.setUpButtonClick(e, () => this.generateTemplates(this._userPrompt))}>
+ <FontAwesomeIcon icon='arrows-rotate'/>
+ </button>
+ <input className='docCreatorMenu-GPT-prompt-input' placeholder='Additional prompt:' onChange={e => this._userPrompt = e.target.value}/>
+ </div>
+ {this._GPTOpt ? GPTOptions : null}
+ </div>) : null}
</div>
<hr className='docCreatorMenu-option-divider full no-margin'/>
<div className='docCreatorMenu-section'>
@@ -445,6 +459,9 @@ export class DocCreatorMenu extends ObservableReactComponent<{}> {
<button className='option-button left' onPointerDown={e => this.setUpButtonClick(e, () => {this.editTemplate(info.doc)})}>
<FontAwesomeIcon icon='pencil' color='black'/>
</button>
+ <button className='option-button right' onPointerDown={e => this.setUpButtonClick(e, () => {this.removeTemplate(info.doc)})}>
+ <FontAwesomeIcon icon='trash' color='black'/>
+ </button>
<img className='docCreatorMenu-preview-image' src={info.icon!.url.href.replace(".png", "_o.png")} />
</div>
)})}