import { action, makeAutoObservable } from 'mobx'; import { Col } from '../DocCreatorMenu'; import { FieldSettings } from '../TemplateFieldTypes/TemplateField'; import { Template } from '../Template'; import { Doc, NumListCast } from '../../../../../../fields/Doc'; import { DataVizBox } from '../../DataVizBox'; import { TemplateFieldType } from '../TemplateBackend'; import { TemplateMenuAIUtils } from './TemplateMenuAIUtils'; export type Conditional = { field: string; operator: '=' | '>' | '<'; condition: string; target: 'self' | 'template'; attribute: string; value: string; } export class TemplateManager { templates: Template[] = []; conditionalFieldLogic: Record = {}; constructor(templateSettings: FieldSettings[]) { makeAutoObservable(this); this.templates = this.initializeTemplates(templateSettings); } initializeTemplates = (templateSettings: FieldSettings[]) => templateSettings.map(settings => { return new Template(settings)}); getValidTemplates = (cols: Col[]) => this.templates.filter(template => template.isValidTemplate(cols)); addTemplate = (newTemplate: Template) => this.templates.push(newTemplate); removeTemplate = (template: Template) => { this.templates.splice(this.templates.indexOf(template), 1); template.cleanup(); }; addFieldCondition = (fieldTitle: string, condition: Conditional) => { if (this.conditionalFieldLogic[fieldTitle] === undefined) { this.conditionalFieldLogic[fieldTitle] = [condition]; } else { this.conditionalFieldLogic[fieldTitle].push(condition); } } removeFieldCondition = (fieldTitle: string, condition: Conditional) => { if (this.conditionalFieldLogic[fieldTitle]) { this.conditionalFieldLogic[fieldTitle] = this.conditionalFieldLogic[fieldTitle].filter(cond => cond !== condition); } } createDocsFromTemplate = action((dv: DataVizBox, template: Template, cols: Col[], debug: boolean = false) => { const fields = Array.from(Object.keys(dv.records[0])); const processContent = async (content: { [title: string]: string }) => { const templateCopy = template.clone(); fields .filter(title => title) .forEach(title => { const field = templateCopy.getFieldByTitle(title); field && field.setContent(content[title], field.viewType); }); const gptFunc = (type: TemplateFieldType) => (type === TemplateFieldType.VISUAL ? TemplateMenuAIUtils.renderGPTImageCall : TemplateMenuAIUtils.renderGPTTextCall); 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(); templateCopy.applyConditionalLogic(this.conditionalFieldLogic); return templateCopy.getRenderedDoc(); }; const rowContents = debug ? [{}, {}, {}, {}] : NumListCast(dv.layoutDoc.dataViz_selectedRows).map(row => fields.reduce( (values, col) => { values[col] = dv.records[row][col]; return values; }, {} as { [title: string]: string } ) ); return Promise.all(rowContents.map(processContent)).then( action(renderedDocs => { return renderedDocs; }) ); }); }