diff options
Diffstat (limited to 'src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx')
-rw-r--r-- | src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx | 172 |
1 files changed, 96 insertions, 76 deletions
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx index 379a33a99..ea38430ca 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx @@ -61,7 +61,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { @observable _selectedTemplate: Template | undefined = undefined; @observable _currEditingTemplate: Template | undefined = undefined; - @observable _userCreatedColumns: Col[] = []; + @observable _userCreatedFields: Col[] = []; @observable _selectedCols: { title: string; type: string; desc: string }[] | undefined = []; @observable _layout: { type: LayoutType; yMargin: number; xMargin: number; columns?: number; repeat: number } = { type: LayoutType.FREEFORM, yMargin: 10, xMargin: 10, columns: 3, repeat: 0 }; @@ -175,7 +175,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { return col; }) - .concat(this._userCreatedColumns); + .concat(this._userCreatedFields); } @computed get canMakeDocs() { @@ -360,14 +360,14 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { return undefined; } - @action updateSelectedTemplate = (template: Template) => { + @action updateSelectedTemplate = async (template: Template) => { if (this._selectedTemplate === template) { this._selectedTemplate = undefined; return; } else { this._selectedTemplate = template; template.renderUpdates(); - this._fullyRenderedDocs = this.createDocsFromTemplate(template) ?? []; + this._fullyRenderedDocs = await this.createDocsFromTemplate(template) ?? []; this.updateRenderedDocCollection(); } }; @@ -410,15 +410,15 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { }; @action addField = () => { - const newFields: Col[] = this._userCreatedColumns.concat([{ title: '', type: TemplateFieldType.UNSET, desc: '', sizes: [] }]); - this._userCreatedColumns = newFields; + const newFields: Col[] = this._userCreatedFields.concat([{ title: '', type: TemplateFieldType.UNSET, desc: '', sizes: [] }]); + this._userCreatedFields = newFields; }; @action removeField = (field: { title: string; type: string; desc: string }) => { if (this._dataViz?.axes.includes(field.title)) { this._dataViz.selectAxes(this._dataViz.axes.filter(col => col !== field.title)); } else { - const toRemove = this._userCreatedColumns.filter(f => f === field); + const toRemove = this._userCreatedFields.filter(f => f === field); if (!toRemove) return; if (toRemove.length > 1) { @@ -427,10 +427,10 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { } } - if (this._userCreatedColumns.length === 1) { - this._userCreatedColumns = []; + if (this._userCreatedFields.length === 1) { + this._userCreatedFields = []; } else { - this._userCreatedColumns.splice(this._userCreatedColumns.indexOf(toRemove[0]), 1); + this._userCreatedFields.splice(this._userCreatedFields.indexOf(toRemove[0]), 1); } } }; @@ -498,22 +498,6 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { * @returns a doc containing the fully rendered template */ applyGPTContentToTemplate = async (template: Template, assignments: { [field: string]: Col }): Promise<Template | undefined> => { - const wordLimit = (size: TemplateFieldSize) => { - switch (size) { - case TemplateFieldSize.TINY: - return 2; - case TemplateFieldSize.SMALL: - return 5; - case TemplateFieldSize.MEDIUM: - return 20; - case TemplateFieldSize.LARGE: - return 50; - case TemplateFieldSize.HUGE: - return 100; - default: - return 10; - } - }; const generateAndLoadImage = async (fieldNum: string, col: Col, prompt: string) => { const url = await this.generateGPTImage(prompt); @@ -523,44 +507,17 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { field.setTitle(col.title); }; - const GPTTextCalls = Object.entries(assignments).filter(([str, col]) => col.type === TemplateFieldType.TEXT); - const GPTIMGCalls = Object.entries(assignments).filter(([str, col]) => col.type === TemplateFieldType.VISUAL); - - if (!GPTTextCalls && !GPTIMGCalls) return; - - const stringifyGPTInfo = (calls: [string, Col][]): string => { - let string: string = '*** COLUMN INFO:'; - calls.forEach(([fieldNum, col]) => { - string += `--- title: ${col.title}, prompt: ${col.desc}, word limit: ${wordLimit(col.sizes[0])} words, assigned field: ${fieldNum} ---`; - }); - return (string += ' ***'); - }; - - const GPTTextAssignment = stringifyGPTInfo(GPTTextCalls); - + const GPTTextCalls = Object.entries(assignments).filter(([str, col]) => col.type === TemplateFieldType.TEXT && this._userCreatedFields.includes(col)); + const GPTIMGCalls = Object.entries(assignments).filter(([str, col]) => col.type === TemplateFieldType.VISUAL && this._userCreatedFields.includes(col)); let fieldContent: string = template.compiledContent; if (GPTTextCalls.length) { - try { - const prompt = fieldContent + GPTTextAssignment; - - const res = await gptAPICall(`${++this._callCount}: ${prompt}`, GPTCallType.FILL); - - if (res) { - const assignments: { [title: string]: { number: string; content: string } } = JSON.parse(res); - //console.log('assignments', GPTAssignments, 'assignment string', GPTAssignmentString, 'field content', fieldContent, 'response', res, 'assignments', assignments); - Object.entries(assignments).forEach(([title, info]) => { - const field: Field = template.getFieldByID(Number(info.number)); - const col = this.getColByTitle(title); + const promises = GPTTextCalls.map(([str, col]) => { + return this.renderGPTTextCall(template, col, Number(str)); + }); - field.setContent(info.content ?? '', FieldContentType.STRING); - field.setTitle(col.title); - }); - } - } catch (err) { - console.log(err); - } + await Promise.all(promises); } if (GPTIMGCalls.length) { @@ -634,7 +591,7 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { const toObj = Object.entries(assignment).reduce( (a, [fieldID, colTitle]) => { const col = this.getColByTitle(colTitle); - if (!this._userCreatedColumns.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 fields + 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 fields const field = template.getFieldByID(Number(fieldID)); //console.log(field); field.setContent(col.defaultContent ?? '', col.type === TemplateFieldType.VISUAL ? FieldContentType.IMAGE : FieldContentType.STRING); @@ -676,38 +633,101 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps> { }); }; - createDocsFromTemplate = (template: Template) => { + renderGPTTextCall = async (template: Template, col: Col, fieldNum: number): Promise<boolean> => { + const wordLimit = (size: TemplateFieldSize) => { + switch (size) { + case TemplateFieldSize.TINY: + return 2; + case TemplateFieldSize.SMALL: + return 5; + case TemplateFieldSize.MEDIUM: + return 20; + case TemplateFieldSize.LARGE: + return 50; + case TemplateFieldSize.HUGE: + return 100; + default: + return 10; + } + }; + + const textAssignment = `--- title: ${col.title}, prompt: ${col.desc}, word limit: ${wordLimit(col.sizes[0])} words, assigned field: ${fieldNum} ---`; + + let fieldContent: string = template.compiledContent; + + try { + const prompt = fieldContent + textAssignment; + + const res = await gptAPICall(`${++this._callCount}: ${prompt}`, GPTCallType.FILL); + + console.log('prompt: ', prompt, ' response: ', res); + + if (res) { + const assignments: { [title: string]: { number: string; content: string } } = JSON.parse(res); + Object.entries(assignments).forEach(([title, info]) => { + const field: Field = template.getFieldByID(Number(info.number)); + const col = this.getColByTitle(title); + + field.setContent(info.content ?? '', FieldContentType.STRING); + field.setTitle(col.title); + }); + } + } catch (err) { + console.log(err); + } + + return true; + } + + createDocsFromTemplate = async (template: Template) => { const dv = this._dataViz; if (!dv) return; const fields: string[] = Array.from(Object.keys(dv.records[0])); const selectedRows = NumListCast(dv.layoutDoc.dataViz_selectedRows); - - const fieldContents: {[title: string]: string}[] = selectedRows.map(row => { - let values: {[title: string]: string} = {}; + + const rowContents: { [title: string]: string }[] = selectedRows.map(row => { + let values: { [title: string]: string } = {}; fields.forEach(col => { values[col] = dv.records[row][col]; }); - + return values; }); + + const processContent = async (content: {[title: string]: string}) => { + const templateCopy = template.cloneBase(); + + console.log('rows: ', content, '---------------- fields: ', fields) - - const renderedDocs: Doc[] = []; - - fieldContents.forEach(content => { fields.filter(title => title).forEach(title => { - const field = template.getFieldByTitle(title); - if (field === undefined){ - return; - } + const field = templateCopy.getFieldByTitle(title); + console.log('field: ', field); + if (field === undefined) { return }; field.setContent(content[title]); }); - - renderedDocs.push(template.mainField.renderedDoc()); - }); + + const gptPromises = this._userCreatedFields.map(field => { + const title = field.title; + const templateField = templateCopy.getFieldByTitle(title); + if (templateField === undefined) { return }; + const templatefieldID = templateField.getID; + + return this.renderGPTTextCall(templateCopy, field, templatefieldID); + }); + + await Promise.all(gptPromises); + + console.log(templateCopy); + return templateCopy.mainField.renderedDoc(); + }; + + const promises = rowContents.map(content => processContent(content)); + + const renderedDocs = await Promise.all(promises); return renderedDocs; } + addRenderedCollectionToMainview = () => { const collection = this._renderedDocCollection; |