aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/apis/gpt/GPT.ts1
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts31
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateMenuAIUtils.ts23
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx17
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingScreen.tsx0
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx4
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts6
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DynamicField.ts25
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/StaticContentField.ts5
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts16
-rw-r--r--src/client/views/nodes/ImageBox.scss2
11 files changed, 82 insertions, 48 deletions
diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts
index 57a229569..d7b378958 100644
--- a/src/client/apis/gpt/GPT.ts
+++ b/src/client/apis/gpt/GPT.ts
@@ -221,6 +221,7 @@ const gptAPICall = async (inputTextIn: string, callType: GPTCallType, prompt?: s
const gptImageCall = async (prompt: string, n?: number) => {
try {
const response = await openai.images.generate({
+ model: 'dall-e-3',
prompt: prompt,
n: n ?? 1,
size: '1024x1024',
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts
index ef7dbc7ab..d11f05766 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateManager.ts
@@ -53,11 +53,11 @@ export class TemplateManager {
}
}
- createDocsFromTemplate = action((dv: DataVizBox, template: Template, csvColumns: Col[], debug: boolean = false) => {
+ createDocsFromTemplate = action((dv: DataVizBox, template: Template, cols: Col[], debug: boolean = false) => {
const fields = Array.from(Object.keys(dv.records[0]));
- const processContent = (content: { [title: string]: string }) => {
- const templateCopy = template.cloneBase();
+ const processContent = async (content: { [title: string]: string }) => {
+ const templateCopy = template.clone();
fields
.filter(title => title)
@@ -67,14 +67,22 @@ export class TemplateManager {
});
const gptFunc = (type: TemplateFieldType) => (type === TemplateFieldType.VISUAL ? TemplateMenuAIUtils.renderGPTImageCall : TemplateMenuAIUtils.renderGPTTextCall);
- const gptPromises = csvColumns
- .filter(field => field.type !== TemplateFieldType.UNSET && field.AIGenerated)
- .map(field => {
- const templateField = templateCopy.getFieldByTitle(field.title);
- if (templateField !== undefined) {
- return gptFunc(field.type)(templateCopy, field, templateField.getID);
- }
- });
+ const applyGPTContent = async () => {
+ const promises = cols
+ .filter(field => field.AIGenerated)
+ .map(field => {
+ const templateField = templateCopy.getFieldByTitle(field.title);
+ if (templateField !== undefined) {
+ return gptFunc(field.type)(templateCopy, field, templateField.getID);
+ }
+ return null;
+ })
+ .filter(p => p !== null);
+
+ await Promise.all(promises);
+ };
+
+ await applyGPTContent();
return templateCopy.getRenderedDoc();
};
@@ -90,6 +98,7 @@ export class TemplateManager {
{} as { [title: string]: string }
)
);
+
return Promise.all(rowContents.map(processContent)).then(
action(renderedDocs => {
return renderedDocs;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateMenuAIUtils.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateMenuAIUtils.ts
index 446fe3442..9bc2bfce2 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateMenuAIUtils.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Backend/TemplateMenuAIUtils.ts
@@ -27,12 +27,13 @@ export class TemplateMenuAIUtils {
}
};
- public static renderGPTImageCall = async (template: Template, col: Col, fieldNumber: number | undefined): Promise<boolean> => {
- const generateAndLoadImage = async (fieldNum: string, column: Col, prompt: string) => {
+ public static renderGPTImageCall = async (template: Template, col: Col, fieldNumber: number): Promise<boolean> => {
+ const generateAndLoadImage = async (id: number, prompt: string) => {
const url = await this.generateGPTImage(prompt);
- const field: TemplateField = template.getFieldByID(Number(fieldNum));
+ var field: TemplateField = template.getFieldByID(id);
field.setContent(url ?? '', ViewType.IMG);
+ field = template.getFieldByID(id);
field.setTitle(col.title);
};
@@ -40,14 +41,14 @@ export class TemplateMenuAIUtils {
try {
const sysPrompt =
- 'Your job is to create a prompt for an AI image generator to help it generate an image based on existing content in a template and a user prompt. Your prompt should focus heavily on visual elements to help the image generator; avoid unecessary info that might distract it. ONLY INCLUDE THE PROMPT, NO OTHER TEXT OR EXPLANATION. The existing content is as follows: ' +
+ `#${Math.random() * 100}: Your job is to create a prompt for an AI image generator to help it generate an image based on existing content in a template and a user prompt. Your prompt should focus heavily on visual elements to help the image generator; avoid unecessary info that might distract it. ONLY INCLUDE THE PROMPT, NO OTHER TEXT OR EXPLANATION. The existing content is as follows: ` +
fieldContent +
' **** The user prompt is: ' +
col.desc;
const prompt = await gptAPICall(sysPrompt, GPTCallType.COMPLETEPROMPT);
- await generateAndLoadImage(String(fieldNumber), col, prompt);
+ await generateAndLoadImage(fieldNumber, prompt);
} catch (e) {
console.log(e);
}
@@ -104,20 +105,20 @@ export class TemplateMenuAIUtils {
* @returns a doc containing the fully rendered template
*/
public static applyGPTContentToTemplate = async (template: Template, assignments: { [field: string]: Col }): Promise<Template | undefined> => {
- const GPTTextCalls = Object.entries(assignments).filter(([, col]) => col.type === TemplateFieldType.TEXT && !col.AIGenerated);
- const GPTIMGCalls = Object.entries(assignments).filter(([, col]) => col.type === TemplateFieldType.VISUAL && !col.AIGenerated);
+ const GPTTextCalls = Object.entries(assignments).filter(([, col]) => col.type === TemplateFieldType.TEXT && col.AIGenerated);
+ const GPTIMGCalls = Object.entries(assignments).filter(([, col]) => col.type === TemplateFieldType.VISUAL && col.AIGenerated);
if (GPTTextCalls.length) {
- const promises = GPTTextCalls.map(([str, col]) => {
- return TemplateMenuAIUtils.renderGPTTextCall(template, col, Number(str));
+ const promises = GPTTextCalls.map(([id, col]) => {
+ return TemplateMenuAIUtils.renderGPTTextCall(template, col, Number(id));
});
await Promise.all(promises);
}
if (GPTIMGCalls.length) {
- const promises = GPTIMGCalls.map(async ([fieldNum, col]) => {
- return TemplateMenuAIUtils.renderGPTImageCall(template, col, Number(fieldNum));
+ const promises = GPTIMGCalls.map(async ([id, col]) => {
+ return TemplateMenuAIUtils.renderGPTImageCall(template, col, Number(id));
});
await Promise.all(promises);
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index 7beb93636..8a98399b6 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -374,6 +374,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
}
@action updateRenderedPreviewCollection = async (template: Template) => {
+ this._docsRendering = true;
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();
};
@@ -384,7 +385,6 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
return;
} else {
this._selectedTemplate = template;
- //template.renderUpdates();
this.updateRenderedPreviewCollection(template);
}
};
@@ -434,7 +434,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
};
@action addField = () => {
- const newFields: Col[] = this._userCreatedFields.concat([{ title: '', type: TemplateFieldType.UNSET, desc: '', sizes: [] }]);
+ const newFields: Col[] = this._userCreatedFields.concat([{ title: '', type: TemplateFieldType.UNSET, desc: '', sizes: [], AIGenerated: true }]);
this._userCreatedFields = newFields;
};
@@ -544,10 +544,10 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
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));
+ if (!col.AIGenerated) {
+ var field = template.getFieldByID(Number(fieldID));
field.setContent(col.defaultContent ?? '', col.type === TemplateFieldType.VISUAL ? ViewType.IMG : ViewType.TEXT);
+ field = template.getFieldByID(Number(fieldID));
field.setTitle(col.title);
} else {
a[Number(fieldID)] = this.getColByTitle(colTitle);
@@ -602,7 +602,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
clone.x = 10000;
clone.y = 10000;
- await DrawingFillHandler.drawingToImage(clone, 100, prompt, undefined, this)
+ await DrawingFillHandler.drawingToImage(clone, 100, prompt, clone, this)
return this.variations;
}
@@ -762,10 +762,9 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
this._renderedDocCollection = collection;
- // const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView;
- // mainCollection.addDocument(collection);
+ this._docsRendering = false;
- console.log('changed to: ', collection);
+ this.forceUpdate();
};
layoutPreviewContents = action(() => {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingScreen.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingScreen.tsx
deleted file mode 100644
index e69de29bb..000000000
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingScreen.tsx
+++ /dev/null
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx
index 8b58ac1cf..df6b791c7 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Menu/TemplateEditingWindow.tsx
@@ -86,9 +86,9 @@ export class TemplateEditingWindow extends ObservableReactComponent<TemplateEdit
onPointerDown={e => this._props.setupButtonClick(e, async () => {
this._props.menu._variations = [];
this._loading = true;
- this._variationURLs = await this._props.menu.generateVariations(this._props.template.getRenderedDoc()!, this.fireflyPrompt);
+ this._variationURLs = await this._props.menu.generateVariations(this._props.template.clone(false).getRenderedDoc()!, this.fireflyPrompt);
this._variationURLs.forEach(url => {
- const newTemplate: Template = this._props.template.cloneBase();
+ const newTemplate: Template = this._props.template.clone(true);
this._props.menu._variations.push(newTemplate);
});
this._loading = false;
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
index 1dc6692a2..10724c9f7 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
@@ -57,7 +57,7 @@ export class Template {
//dispose each subfields disposers, etc.
};
- cloneBase = () => new Template(this._mainField?.makeClone(undefined) ?? TemplateLayouts.BasicSettings);
+ clone = (withContent: boolean = false) => new Template(this._mainField?.makeClone(undefined, withContent) ?? TemplateLayouts.BasicSettings);
getRenderedDoc = () => this.doc;
@@ -130,9 +130,7 @@ export class Template {
});
}
- this._mainField.addField(field);
-
- this._mainField.refreshRenderedDoc();
+ this._mainField.makeBackgroundField(field)
}
getMatches = (cols: Col[]): number[][] => {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DynamicField.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DynamicField.ts
index 5fba68c14..fc520ba47 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DynamicField.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/DynamicField.ts
@@ -11,6 +11,7 @@ import { FieldSettings, TemplateField, ViewType } from './TemplateField';
export class DynamicField extends TemplateField {
protected _disposers: { [name: string]: IDisposer } = {};
protected _subfields: TemplateField[] = [];
+ protected backgroundField: TemplateField | undefined;
get getSubfields() {
return this._subfields;
@@ -72,11 +73,31 @@ export class DynamicField extends TemplateField {
addChildToDocument = (doc: Doc) => this._renderDoc && Doc.SetContainer(doc, this._renderDoc);
+ makeBackgroundField = (field: TemplateField) => {
+ if (this.backgroundField && this.backgroundField !== field) {
+ this.removeField(this.backgroundField);
+ this.backgroundField = undefined;
+ }
+ if (field && field !== this.backgroundField) {
+ this.addField(field);
+ this.backgroundField = field;
+ }
+ this.refreshRenderedDoc();
+ }
+
matches = (): Array<number> => [];
- makeClone(parent?: DynamicField) {
+ makeClone(parent?: DynamicField, withContent: boolean = false) {
const dynClone = super.makeClone(parent) as DynamicField;
- dynClone._subfields = this.getSubfields.map(cloneField => cloneField.makeClone(dynClone));
+ dynClone._subfields = this.getSubfields.map(field => {
+ if (field === this.backgroundField) {
+ const backgroundField: TemplateField = field.makeClone(dynClone, true);
+ dynClone.makeBackgroundField(backgroundField);
+ return backgroundField;
+ } else {
+ return field.makeClone(dynClone, withContent)
+ }
+ });
if (dynClone._renderDoc) {
dynClone._renderDoc[DocData].data = new List<Doc>(dynClone.getSubfields.filter(sub => sub.renderedDoc).map(sub => sub.renderedDoc!));
}
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/StaticContentField.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/StaticContentField.ts
index 420d03076..112f37cc6 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/StaticContentField.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/StaticContentField.ts
@@ -37,6 +37,11 @@ export class ImageTemplateField extends StaticContentField {
this._renderDoc = Docs.Create.ImageDocument(this._content, settings.opts);
return this;
}
+
+ updateDocSetting(setting: string, newVal: string) {
+ if (setting === 'backgroundColor') return;
+ super.updateDocSetting(setting, newVal);
+ }
}
export class TextTemplateField extends StaticContentField {
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts
index e2779968d..bc6b13c76 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/TemplateFieldTypes/TemplateField.ts
@@ -67,22 +67,23 @@ export abstract class TemplateField {
setTitle = (title: string) => {
this._title = title;
- this._renderDoc && (this._renderDoc.title = title);
+ this.settings.title = title;
+ if (this._renderDoc) this._renderDoc.title = title
};
getTitle = () => this._title;
- updateDocSetting = (setting: string, newVal: string) => {
+ updateDocSetting(setting: string, newVal: string) {
if (this._renderDoc) this._renderDoc[setting] = newVal;
const settings: {[s: string]: string } = {[setting]: newVal}
Object.assign(this.settings.opts, settings);
}
- makeClone(parent?: TemplateField) {
+ makeClone(parent?: TemplateField, withContent: boolean = false) {
const settings: FieldSettings = structuredClone(this._settings);
const cloned = TemplateField.CreateField(settings, this._id, parent, true); // create a value for this.Document/subfields that we want to ignore
- this._renderDoc && Doc.MakeClone(this._renderDoc).then(({ clone }) => (cloned._renderDoc = clone));
- cloned._title = this._title;
+ cloned.setTitle(this._title);
cloned._dimensions = this._dimensions;
+ withContent && cloned.setContent(this.getContent());
return cloned;
}
@@ -91,9 +92,8 @@ export abstract class TemplateField {
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
changeFieldType = (newType: ViewType): TemplateField => {
- const newSettings = this._settings;
- newSettings.viewType = newType;
- const newField = TemplateField.CreateField(newSettings, this._id, this._parent, true);
+ this._settings.viewType = newType;
+ const newField = TemplateField.CreateField(this._settings, this._id, this._parent, true);
this._parent?.exchangeFields(newField, this);
return newField;
};
diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss
index 3d6942e6f..5625f2f56 100644
--- a/src/client/views/nodes/ImageBox.scss
+++ b/src/client/views/nodes/ImageBox.scss
@@ -105,7 +105,7 @@
display: flex;
height: 100%;
img {
- object-fit: contain;
+ // object-fit: contain;
height: 100%;
}