From 0581f0943aad45fae70bb34e61fa219121d64b8f Mon Sep 17 00:00:00 2001 From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com> Date: Mon, 2 Sep 2024 19:15:49 -0400 Subject: default content for columns in preview templates --- src/client/apis/gpt/GPT.ts | 2 +- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 65 ++++++++++++++++++---- .../views/nodes/DataVizBox/DocCreatorMenu.tsx | 39 +++++++------ 3 files changed, 77 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts index 0d1d77f06..ba8106c4d 100644 --- a/src/client/apis/gpt/GPT.ts +++ b/src/client/apis/gpt/GPT.ts @@ -58,7 +58,7 @@ const callTypeMap: { [type: string]: GPTCallOpts } = { }, template: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'You will be given a list of field descriptions for multiple templates in the format {field #0: “description”}{field #1: “description”}{...}, and a list of column descriptions in the format {“title”: “description}{...}. Your job is to match columns with fields based on their descriptions. Your output should be in the following JSON format: {“Template title”:{“#”: “title”, “#”: “title”, “#”: “title” …}, “Template title”:{“#”: “title”, “#”: “title”, “#”: “title” …}} where “Template title” represents the template, # represents the field # and “title” the title of the column assigned to it. A filled out example might look like {“fivefield2”:{0:”Name”, 1:”Image”, 2:”Caption”, 3:”Position”, 4:”Stats”}, “fivefield3”:{0:”Image”, 1:”Name”, 2:”Caption”, 3:”Stats”, 4:”Position”}. Include one object for each template. IT IS VERY IMPORTANT THAT YOU ONLY INCLUDE TEXT IN THE FORMAT ABOVE, WITH NO ADDITIONS WHATSOEVER. Do not include extraneous ‘#’ characters, ‘column’ for columns, or ‘template’ for templates: ONLY THE TITLES AND NUMBERS. Do this for each template whose fields are described. The descriptions are as follows: ' }, vizsum: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'Your job is to provide brief descriptions for columns in a dataset based on example rows. Your descriptions should be geared towards how each column’s data might fit together into a visual template. Would they make good titles, main focuses, captions, descriptions, etc. Pay special attention to connections between columns, i.e. is there one column that specifically seems to describe/be related to another more than the rest? You should provide your analysis in JSON format like so: {“col1”:”description”, “col2”:”description”, …}. DO NOT INCLUDE ANY OTHER TEXT, ONLY THE JSON.'}, - vizsum2: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'Your job is to provide structured information on columns in a dataset based on example rows. You will categorize each column in two ways: by type and size. The size categories are as follows: tiny (one or two words), small (a sentence/multiple words), medium (a few sentences), large (a longer paragraph), and huge (a very long or multiple paragraphs). The type categories are as follows: visual (links/file paths to images, pdfs, maps, or any other visual media type), and text (plain text that isn’t a link/file path). Visual media should be assumed to have size “medium” “large” or “huge”. You will give your responses in JSON format, like so: {“col1”:{“type”:”text”, “size”:”small”}, “col2”:{“type”:”visual”, “size”:”medium”}, …}. DO NOT INCLUDE ANY OTHER TEXT, ONLY THE JSON.'} + vizsum2: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'Your job is to provide structured information on columns in a dataset based on example rows. You will categorize each column in two ways: by type and size. The size categories are as follows: tiny (one or two words), small (a sentence/multiple words), medium (a few sentences), large (a longer paragraph), and huge (a very long or multiple paragraphs). The type categories are as follows: visual (links/file paths to images, pdfs, maps, or any other visual media type), and text (plain text that isn’t a link/file path). Visual media should be assumed to have size “medium” “large” or “huge”. You will give your responses in JSON format, like so: {“title (of column)”:{“type”:”text”, “size”:”small”}, “title (of column)”:{“type”:”visual”, “size”:”medium”}, …}. DO NOT INCLUDE ANY OTHER TEXT, ONLY THE JSON.'} }; let lastCall = ''; let lastResp = ''; diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index c72aa1711..6888d5f1e 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -155,26 +155,43 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { this._specialHighlightedRow = row; } - @action setColumnType = (field: string, type: TemplateFieldType) => { - const colInfo = this.colsInfo.get(field); - if (colInfo) { colInfo.type = type }; + @action setColumnType = (colTitle: string, type: TemplateFieldType) => { + const colInfo = this.colsInfo.get(colTitle); + console.log(colInfo) + if (colInfo) { + colInfo.type = type; + } else { + this.colsInfo.set(colTitle, {title: colTitle, desc: '', type: type, size: TemplateFieldSize.MEDIUM}) + } + console.log(colInfo?.title, colInfo?.type) } - @action setColumnSize = (field: string, size: TemplateFieldSize) => { - const colInfo = this.colsInfo.get(field); - if (colInfo) { colInfo.size = size }; + @action setColumnSize = (colTitle: string, size: TemplateFieldSize) => { + const colInfo = this.colsInfo.get(colTitle); + if (colInfo) { + colInfo.size = size; + } else { + this.colsInfo.set(colTitle, {title: colTitle, desc: '', type: TemplateFieldType.UNSET, size: size}) + } } - @action setColumnDesc = (field: string, desc: string) => { - const colInfo = this.colsInfo.get(field); + @action setColumnDesc = (colTitle: string, desc: string) => { + const colInfo = this.colsInfo.get(colTitle); if (colInfo) { - if (!desc) { colInfo.desc = this.GPTSummary?.get(field)?.desc ?? ''; } + if (!desc) { colInfo.desc = this.GPTSummary?.get(colTitle)?.desc ?? ''; } else { colInfo.desc = desc; } + } else { + this.colsInfo.set(colTitle, {title: colTitle, desc: desc, type: TemplateFieldType.UNSET, size: TemplateFieldSize.MEDIUM}) } } - @computed get colInfo(){ - return this.colsInfo; + @action setColumnDefault = (colTitle: string, cont: string) => { + const colInfo = this.colsInfo.get(colTitle); + if (colInfo) { + colInfo.defaultContent = cont; + } else { + this.colsInfo.set(colTitle, {title: colTitle, desc: '', type: TemplateFieldType.UNSET, size: TemplateFieldSize.MEDIUM, defaultContent: cont}) + } } @action // pinned / linked anchor doc includes selected rows, graph titles, and graph colors @@ -529,7 +546,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { prompt += '----------- Rows: ' - rowsToCheck.forEach(row => { + rowsToCheck.forEach((row, i) => { prompt += `Row #${row}: ` cols.forEach(col => { prompt += `${col}: ${this.records[row][col]} -----` @@ -539,11 +556,35 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { return prompt; } + updateColDefaults = () => { + let possibleIds: number[] = this.records.map((_, index) => index); + + for (let i = possibleIds.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [possibleIds[i], possibleIds[j]] = [possibleIds[j], possibleIds[i]]; + } + + const rowToCheck = possibleIds[0]; + + const cols = Array.from(Object.keys(this.records[0])).filter(header => header !== '' && header !== undefined); + + cols.forEach(col => { + this.setColumnDefault(col, `${this.records[rowToCheck][col]}`) + }); + } + updateGPTSummary = async () => { this._GPTLoading = true; + this.updateColDefaults(); + const prompt = this.getColSummary(); + const cols = Array.from(Object.keys(this.records[0])).filter(header => header !== '' && header !== undefined); + cols.forEach(col => { + if (!this.colsInfo.get(col)) this.colsInfo.set(col, {title: col, desc: '', size: TemplateFieldSize.MEDIUM, type: TemplateFieldType.UNSET}); + }); + try { const res = await gptAPICall(prompt, GPTCallType.VIZSUM); diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx index fd5e58ae9..e36adc40a 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx @@ -136,8 +136,9 @@ export class DocCreatorMenu extends ObservableReactComponent { } @computed get fieldsInfos(): Col[] { - const colInfo = this._dataViz?.colInfo; - return this.selectedFields.map(field => {return {title: field, type: colInfo?.get(field)?.type ?? TemplateFieldType.UNSET, desc: colInfo?.get(field)?.desc ?? '', size: colInfo?.get(field)?.size ?? TemplateFieldSize.MEDIUM}}).concat(this._columns); + const colInfo = this._dataViz?.colsInfo; + return this.selectedFields.map(field => {return {title: field, type: colInfo?.get(field)?.type ?? TemplateFieldType.UNSET, desc: colInfo?.get(field)?.desc ?? '', size: colInfo?.get(field)?.size ?? TemplateFieldSize.MEDIUM, defaultContent: colInfo?.get(field)?.defaultContent ?? ''}}); + //.concat(this._columns) } @computed get canMakeDocs(){ @@ -429,7 +430,9 @@ export class DocCreatorMenu extends ObservableReactComponent { // this.createEmptyTemplate(temp, assignments); - this.generatePresetTemplates([TemplateLayouts.FourField001, TemplateLayouts.FourField002], this.fieldsInfos); + this.generatePresetTemplates(this.findValidTemplates(this.fieldsInfos, TemplateLayouts.allTemplates), this.fieldsInfos); + // console.log(this._dataViz?.colsInfo.get("IMG")?.size, this._dataViz?.colsInfo.get("IMG")?.type) + // console.log(this.fieldsInfos) }; @action addField = () => { @@ -533,7 +536,7 @@ export class DocCreatorMenu extends ObservableReactComponent { findValidTemplates = (cols: Col[], templates: TemplateDocInfos[]) => { - const validTemplates: string[] = []; + let validTemplates: any[] = []; templates.forEach(template => { const numFields = template.fields.length; const matches = this.matchesForTemplate(template, cols); @@ -542,6 +545,7 @@ export class DocCreatorMenu extends ObservableReactComponent { } }) + validTemplates = validTemplates.map(title => TemplateLayouts.fieldByTitle(title)); return validTemplates; }; @@ -579,7 +583,7 @@ export class DocCreatorMenu extends ObservableReactComponent { template.height, template.width, col.title, - '', + col.defaultContent ?? '', field.opts ); @@ -630,7 +634,7 @@ export class DocCreatorMenu extends ObservableReactComponent { compileColDescriptions = (cols: Col[]): string => { let descriptions: string = ''; - cols.forEach(col => descriptions += `{"${col.title} column: ${col.desc}} `); + cols.forEach(col => descriptions += `{title: ${col.title}, size: ${col.size}, type: ${col.type}, descreiption: ${col.desc}} `); return descriptions; }; @@ -644,8 +648,6 @@ export class DocCreatorMenu extends ObservableReactComponent { const inputText = fieldDescriptions.concat(colDescriptions); - console.log(inputText) - ++this._callCount; const origCount = this._callCount; @@ -659,18 +661,15 @@ export class DocCreatorMenu extends ObservableReactComponent { if (res && this._callCount === origCount) { this._GPTLoading = false; const assignments: {[templateTitle: string]: {[field: string]: string}} = JSON.parse(res); - console.log(assignments); const brokenDownAssignments: [TemplateDocInfos, {[field: number]: Col}][] = []; Object.entries(assignments).forEach(([tempTitle, assignment]) => { const template = TemplateLayouts.fieldByTitle(tempTitle); - console.log('template', template) - if (!template) {console.log('returned'); return}; + if (!template) return; + console.log(assignments) const toObj = Object.entries(assignment).reduce((a, [fieldNum, colTitle]) => { - console.log('hey', a, fieldNum, colTitle) a[Number(fieldNum)] = this.getColByTitle(colTitle); return a; }, {} as { [field: number]: Col }); - console.log('obj', toObj) brokenDownAssignments.push([template, toObj]) }) return brokenDownAssignments; @@ -1213,6 +1212,7 @@ export type Col = { desc: string; title: string; type: TemplateFieldType; + defaultContent?: string; } type Field = { @@ -1295,7 +1295,7 @@ export class FieldFuncs { } currTextHeight = rowsCount * currFontSize * (uppercase ? 1.25 : 1); - console.log(rowsCount, currTextHeight) + //console.log(rowsCount, currTextHeight) currFontSize += 1; } @@ -1342,14 +1342,14 @@ export class FieldFuncs { const bool = true; - const docWithBasicOpts = (Docs.Create.TextDocument)('Fluorite is a very', { + const docWithBasicOpts = (Docs.Create.TextDocument)(content, { isDefaultTemplateDoc: true, _height: height, _width: width, title: title, x: coord.x, y: coord.y, - _text_fontSize: `${FieldFuncs.calculateFontSize(width, height, 'Fluorite is a very', true)}` , + _text_fontSize: `${FieldFuncs.calculateFontSize(width, height, content, true)}` , backgroundColor: opts.backgroundColor ?? '', text_fontColor: opts.color, contentBold: opts.fontBold, @@ -1401,6 +1401,12 @@ export class FieldFuncs { export class TemplateLayouts { + public static get allTemplates(): TemplateDocInfos[] { + return Object.values(TemplateLayouts).filter( + value => typeof value === 'object' && value !== null && 'title' in value + ) as TemplateDocInfos[]; + } + public static fieldByTitle = (title: string): TemplateDocInfos | undefined => { switch (title){ case 'fourfield1': @@ -1438,6 +1444,7 @@ export class TemplateLayouts { backgroundColor: 'transparent', color: '#F1F0E9', contentXCentering: 'h-center', + fontBold: true, } }, { tl: [-.87, -.83], -- cgit v1.2.3-70-g09d2