From 39d02461d9c530996cdcd5fbac4fe3a932550c4a Mon Sep 17 00:00:00 2001 From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com> Date: Mon, 2 Sep 2024 05:11:55 -0400 Subject: gpt provides more basic info + slight refactor started (ofc it didn't work first try >_<) --- src/client/apis/gpt/GPT.ts | 6 +- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 59 +++++++++++----- .../views/nodes/DataVizBox/DocCreatorMenu.tsx | 79 ++++++++++++---------- 3 files changed, 90 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts index f1e7b600b..0d1d77f06 100644 --- a/src/client/apis/gpt/GPT.ts +++ b/src/client/apis/gpt/GPT.ts @@ -13,7 +13,8 @@ enum GPTCallType { MERMAID = 'mermaid', DATA = 'data', TEMPLATE = "template", - VIZSUM = 'vizsum' + VIZSUM = 'vizsum', + VIZSUM2 = 'vizsum2' } type GPTCallOpts = { @@ -56,7 +57,8 @@ const callTypeMap: { [type: string]: GPTCallOpts } = { 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 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.'} + 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.'} }; let lastCall = ''; let lastResp = ''; diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 82df141fa..c72aa1711 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -33,7 +33,7 @@ import { LineChart } from './components/LineChart'; import { PieChart } from './components/PieChart'; import { TableBox } from './components/TableBox'; import { LinkManager } from '../../../util/LinkManager'; -import { DataVizTemplateInfo, DataVizTemplateLayout, DocCreatorMenu, LayoutType, TemplateFieldType } from './DocCreatorMenu'; +import { Col, DataVizTemplateInfo, DataVizTemplateLayout, DocCreatorMenu, TemplateFieldSize, LayoutType, TemplateFieldType } from './DocCreatorMenu'; import { CollectionFreeFormView, MarqueeView } from '../../collections/collectionFreeForm'; import { PrefetchProxy } from '../../../../fields/Proxy'; import { AclAdmin, AclAugment, AclEdit } from '../../../../fields/DocSymbols'; @@ -43,6 +43,7 @@ import { listSpec } from '../../../../fields/Schema'; import { ObjectField } from '../../../../fields/ObjectField'; import { Id } from '../../../../fields/FieldSymbols'; import { GPTCallType, gptAPICall } from '../../../apis/gpt/GPT'; +import { TbSortDescendingShapes } from 'react-icons/tb'; export enum DataVizView { TABLE = 'table', @@ -64,9 +65,8 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { @observable _marqueeing: number[] | undefined = undefined; @observable _savedAnnotations = new ObservableMap(); @observable _specialHighlightedRow: number | undefined = undefined; - @observable GPTSummary: ObservableMap | undefined = undefined; - @observable colDescriptions: ObservableMap = new ObservableMap(); - @observable fieldTypes: ObservableMap = new ObservableMap(); + @observable GPTSummary: ObservableMap | undefined = undefined; + @observable colsInfo: ObservableMap = new ObservableMap(); @observable _GPTLoading: boolean = false; constructor(props: FieldViewProps) { @@ -155,24 +155,26 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { this._specialHighlightedRow = row; } - @action setFieldType = (field: string, type: TemplateFieldType) => { - this.fieldTypes?.set(field, type); + @action setColumnType = (field: string, type: TemplateFieldType) => { + const colInfo = this.colsInfo.get(field); + if (colInfo) { colInfo.type = type }; } - @action setFieldDesc = (field: string, desc: string) => { - if (!desc) { - this.colDescriptions.set(field, this.GPTSummary?.get(field) ?? ''); - } else { - this.colDescriptions.set(field, desc); - } + @action setColumnSize = (field: string, size: TemplateFieldSize) => { + const colInfo = this.colsInfo.get(field); + if (colInfo) { colInfo.size = size }; } - getFieldType = (field: string): TemplateFieldType => { - return this.fieldTypes?.get(field) ?? TemplateFieldType.UNSET; + @action setColumnDesc = (field: string, desc: string) => { + const colInfo = this.colsInfo.get(field); + if (colInfo) { + if (!desc) { colInfo.desc = this.GPTSummary?.get(field)?.desc ?? ''; } + else { colInfo.desc = desc; } + } } - getFieldDescription = (field: string): string => { - return this.colDescriptions?.get(field) ?? ''; + @computed get colInfo(){ + return this.colsInfo; } @action // pinned / linked anchor doc includes selected rows, graph titles, and graph colors @@ -549,8 +551,29 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { this.GPTSummary = new ObservableMap(); const descs: {[col: string]: string} = JSON.parse(res); for (const [key, val] of Object.entries(descs)) { - this.GPTSummary.set(key, val); - if (!this.colDescriptions.get(key)) this.colDescriptions.set(key, val); + this.GPTSummary.set(key, {desc: val}); + if (!this.colsInfo.get(key)?.desc) this.setColumnDesc(key, val); + } + } + } catch (err) { + console.error(err); + } + + try { + const res = await gptAPICall('Info:' + prompt, GPTCallType.VIZSUM2); + + if (res) { + !this.GPTSummary && (this.GPTSummary = new ObservableMap()); + const info: {[col: string]: {type: TemplateFieldType, size: TemplateFieldSize}} = JSON.parse(res); + console.log(info) + for (const [key, val] of Object.entries(info)) { + const colSummary = this.GPTSummary.get(key); + if (colSummary) { + colSummary.size = val.size; + colSummary.type = val.type; + this.setColumnType(key, val.type); + this.setColumnSize(key, val.size); + } } } diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx index fc29531d1..fd5e58ae9 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx @@ -136,7 +136,8 @@ export class DocCreatorMenu extends ObservableReactComponent { } @computed get fieldsInfos(): Col[] { - return this.selectedFields.map(field => {return {title: field, type: this._dataViz?.getFieldType(field) ?? TemplateFieldType.UNSET, desc: this._dataViz?.getFieldDescription(field) ?? '', size: FieldSize.MEDIUM}}).concat(this._columns); + 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); } @computed get canMakeDocs(){ @@ -419,10 +420,10 @@ export class DocCreatorMenu extends ObservableReactComponent { const temp = TemplateLayouts.FourField001; - const img: Col = {type: TemplateFieldType.VISUAL, title: 'Image', desc: 'description whpoo', size: FieldSize.LARGE}; - const capt1: Col = {type: TemplateFieldType.TEXT, title: 'Type', desc: 'description hey', size: FieldSize.TINY}; - const capt2: Col = {type: TemplateFieldType.TEXT, title: 'Locality', desc: '', size: FieldSize.TINY}; - const desc: Col = {type: TemplateFieldType.TEXT, title: 'Description', desc: '', size: FieldSize.LARGE}; + const img: Col = {type: TemplateFieldType.VISUAL, title: 'Image', desc: 'description whpoo', size: TemplateFieldSize.LARGE}; + const capt1: Col = {type: TemplateFieldType.TEXT, title: 'Type', desc: 'description hey', size: TemplateFieldSize.TINY}; + const capt2: Col = {type: TemplateFieldType.TEXT, title: 'Locality', desc: '', size: TemplateFieldSize.TINY}; + const desc: Col = {type: TemplateFieldType.TEXT, title: 'Description', desc: '', size: TemplateFieldSize.LARGE}; // const assignments = {'0': img, '1': capt1, '2': capt2, '3': desc} @@ -432,7 +433,7 @@ export class DocCreatorMenu extends ObservableReactComponent { }; @action addField = () => { - const newFields: Col[] = this._columns.concat([{title: '', type: TemplateFieldType.UNSET, desc: '', size: FieldSize.MEDIUM}]) + const newFields: Col[] = this._columns.concat([{title: '', type: TemplateFieldType.UNSET, desc: '', size: TemplateFieldSize.MEDIUM}]) this._columns = newFields; }; @@ -459,16 +460,25 @@ export class DocCreatorMenu extends ObservableReactComponent { setFieldType = (column: Col, type: TemplateFieldType) => { if (this.selectedFields.includes(column.title)) { - this._dataViz?.setFieldType(column.title, type); + this._dataViz?.setColumnType(column.title, type); } else { column.type = type; } this.forceUpdate(); }; + setFieldSize = (column: Col, size: TemplateFieldSize) => { + if (this.selectedFields.includes(column.title)) { + this._dataViz?.setColumnSize(column.title, size); + } else { + column.size = size; + } + this.forceUpdate(); + }; + setFieldDesc = (column: Col, desc: string) => { if (this.selectedFields.includes(column.title)) { - this._dataViz?.setFieldDesc(column.title, desc); + this._dataViz?.setColumnDesc(column.title, desc); } else { column.desc = desc; } @@ -1045,9 +1055,9 @@ export class DocCreatorMenu extends ObservableReactComponent {
File
- + -