diff options
author | Nathan-SR <144961007+Nathan-SR@users.noreply.github.com> | 2024-08-21 04:07:22 -0400 |
---|---|---|
committer | Nathan-SR <144961007+Nathan-SR@users.noreply.github.com> | 2024-08-21 04:07:22 -0400 |
commit | 888c710b55f747bdeadcf2e862e6dde69d4450c0 (patch) | |
tree | eb04bd8e227297ccb190fb832a95d999487208a3 /src | |
parent | c28390cedfc909ff8e96e4527b75699e1529410c (diff) |
GPT summaries
Diffstat (limited to 'src')
-rw-r--r-- | src/client/apis/gpt/GPT.ts | 7 | ||||
-rw-r--r-- | src/client/views/nodes/DataVizBox/DataVizBox.tsx | 63 | ||||
-rw-r--r-- | src/client/views/nodes/DataVizBox/DocCreatorMenu.scss | 6 | ||||
-rw-r--r-- | src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx | 8 |
4 files changed, 75 insertions, 9 deletions
diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts index 18601b4af..365e7a804 100644 --- a/src/client/apis/gpt/GPT.ts +++ b/src/client/apis/gpt/GPT.ts @@ -12,7 +12,8 @@ enum GPTCallType { DESCRIBE = 'describe', MERMAID = 'mermaid', DATA = 'data', - TEMPLATE = "template" + TEMPLATE = "template", + VIZSUM = 'vizsum' } type GPTCallOpts = { @@ -54,9 +55,9 @@ const callTypeMap: { [type: string]: GPTCallOpts } = { temp: 0, 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 are a designer creating basic template options for a user given a set of fields. Your only job is adding blank rectangles to a canvas, one for each field. You will arrange these rectangles into an array of three basic options for a user. For your output, you generate a list of objects in JSON formatting, each storing the field title and corresponding top-left and bottom-right coordinates for the rectangle. The units for your coordinates are -1 to 1 on each axis. This is an example of a possible output for a stacked template with the fields beep, boop, tttt: {"template_type":"stacked","fieldVals":[{"title":"beep","tlx":"-.7","tly":"-.9","brx":".7","bry":"-.7"},{"title":"boop","tlx":"-.9","tly":"-.4","brx":".9","bry":"0"},{"title":"tttt","tlx":"-.9","tly":".1","brx":".9","bry":".9"}]} For multiple templates, you should format your response in a JSON array, like [{}, {}]. Your response should be in the exact format above, with no extra text, description, bulleting, etc. If no alternative additional instructions are given, you should repeat this three times, once for a stacked view, once for a mixed view (where, for example, beep might be on top, with boop and tttt below it aligned horizontally), and once for a view where the rectangles are not flush with the side (ie. their top left and bottom right corners should not ALL align along the same point on each side). If one or more fields are some variation of image (ie. IMG, image, photo, etc.), make that rectangle the central focus (bigger, centered, etc.) AND put its "title" field in $$__$$. Fields SHOULD BE IN DIFFERENT ORDERS from template to template (ie. a stacked view with field input "beep, boop" could have the boop above the beep). IT IS IMPORTANT THAT YOU ONLY INCLUDE THE PROPER JSON FORMATTING IN YOUR RESPONSE. IT IS ALSO IMPORTANT THAT NO RECTANGLES OVERLAP. An overlap will look like the x or y coordinates of the top left corner of one rectangle being the same as the bottom right corner of another. There should always be at least a .1 gap. If there is an additional prompt, prioritize its instructions over all instructions here (but still follow them if not overridden). No matter what, ALWAYS GIVE THREE OPTIONS'} + template: { model: 'gpt-4-turbo', maxTokens: 512, temp: 0.5, prompt: 'You are a designer creating basic template options for a user given a set of fields. Your only job is adding blank rectangles to a canvas, one for each field. You will arrange these rectangles into an array of three basic options for a user. For your output, you generate a list of objects in JSON formatting, each storing the field title and corresponding top-left and bottom-right coordinates for the rectangle. The units for your coordinates are -1 to 1 on each axis. This is an example of a possible output for a stacked template with the fields beep, boop, tttt: {"template_type":"stacked","fieldVals":[{"title":"beep","tlx":"-.7","tly":"-.9","brx":".7","bry":"-.7"},{"title":"boop","tlx":"-.9","tly":"-.4","brx":".9","bry":"0"},{"title":"tttt","tlx":"-.9","tly":".1","brx":".9","bry":".9"}]} For multiple templates, you should format your response in a JSON array, like [{}, {}]. Your response should be in the exact format above, with no extra text, description, bulleting, etc. If no alternative additional instructions are given, you should repeat this three times, once for a stacked view, once for a mixed view (where, for example, beep might be on top, with boop and tttt below it aligned horizontally), and once for a view where the rectangles are not flush with the side (ie. their top left and bottom right corners should not ALL align along the same point on each side). If one or more fields are some variation of image (ie. IMG, image, photo, etc.), make that rectangle the central focus (bigger, centered, etc.) AND put its "title" field in $$__$$. Fields SHOULD BE IN DIFFERENT ORDERS from template to template (ie. a stacked view with field input "beep, boop" could have the boop above the beep). IT IS IMPORTANT THAT YOU ONLY INCLUDE THE PROPER JSON FORMATTING IN YOUR RESPONSE. IT IS ALSO IMPORTANT THAT NO RECTANGLES OVERLAP. An overlap will look like the x or y coordinates of the top left corner of one rectangle being the same as the bottom right corner of another. There should always be at least a .1 gap. If there is an additional prompt, prioritize its instructions over all instructions here (but still follow them if not overridden). No matter what, ALWAYS GIVE THREE OPTIONS'}, + 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.'} }; - let lastCall = ''; let lastResp = ''; /** diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index c0b05b082..808bc182a 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -63,6 +63,8 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { @observable _marqueeing: number[] | undefined = undefined; @observable _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>(); @observable _specialHighlightedRow: number | undefined = undefined; + @observable _GPTSummary: ObservableMap<string, string> | undefined = undefined; + @observable _GPTLoading: boolean = false; constructor(props: FieldViewProps) { super(props); @@ -352,13 +354,12 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { }, { fireImmediately: true } ); + this._disposers.contentSummary = reaction( + () => this.records, + () => this.updateGPTSummary() + ); } - // recs = () => { - // let csvStr: string = ''; - // this.records[rowId][col] - // } - fetchData = () => { if (!this.Document.dataViz_asSchema) { DataVizBox.dataset.set(CsvCast(this.dataDoc[this.fieldKey]).url.href, []); // assign temporary dataset as a lock to prevent duplicate server requests @@ -476,6 +477,58 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { GPTPopup.Instance.generateDataAnalysis(); }); + getColSummary = (): string => { + 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 rowsToCheck = possibleIds.slice(0, Math.min(10, this.records.length)); + + let prompt: string = 'Col titles: '; + + const cols = Array.from(Object.keys(this.records[0])).filter(header => header !== '' && header !== undefined); + + cols.forEach((col, i) => { + prompt += `Col #${i}: ${col} ------` + }) + + prompt += '----------- Rows: ' + + rowsToCheck.forEach(row => { + prompt += `Row #${row}: ` + cols.forEach(col => { + prompt += `${col}: ${this.records[row][col]} -----` + }) + }) + + return prompt; + } + + updateGPTSummary = async () => { + this._GPTLoading = true; + + const prompt = this.getColSummary(); + + try { + const res = await gptAPICall(prompt, GPTCallType.VIZSUM); + + if (res) { + 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); + } + + console.log(res, descs); + } + } catch (err) { + console.error(err); + } + } + getPossibleTemplates = (): Doc[] => { const linkedDocs: Doc[] = LinkManager.Instance.getAllRelatedLinks(this.Document).map(d => DocCast(LinkManager.getOppositeAnchor(d, this.Document))); const linkedCollections: Doc[] = linkedDocs.filter(doc => doc.type === 'config').map(doc => DocCast(doc.annotationOn)); diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss b/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss index baed9009b..9b3a02e0f 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss @@ -757,6 +757,7 @@ margin: 5px; margin-top: 0px; border-radius: 3px; + flex: 0 0 auto; .properties-wrapper { display: flex; @@ -826,6 +827,11 @@ border-radius: 3px; width: 100%; height: 100%; + resize: none; + + ::-webkit-scrollbar-track { + background: none; + } } .top-right { diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx index d3117da22..3218b9765 100644 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx +++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx @@ -413,6 +413,8 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps & Co // const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView; // mainCollection.addDocument(doc); + //this._dataViz?.getRandomSample(); + console.log(this._dataViz?._GPTSummary?.get('IMG')) } get templatesPreviewContents(){ @@ -809,10 +811,14 @@ export class DocCreatorMenu extends ObservableReactComponent<FieldViewProps & Co </div> </div> </div> - <textarea className='field-description-container' placeholder={'Enter description to enhance template generation'} /> + <textarea className='field-description-container' placeholder={'Add a description to help with template generation.'} /> + this._dataViz?._GPTSummary?.get(field.title) ?? <button className='docCreatorMenu-menu-button section-reveal-options top-right' onPointerDown={e => this.setUpButtonClick(e, () => this.removeField(field))}> <FontAwesomeIcon icon='trash'/> </button> + <button className='docCreatorMenu-menu-button section-reveal-options top-right' onPointerDown={e => this.setUpButtonClick(e, () => this.removeField(field))}> + <FontAwesomeIcon icon='lightbulb'/> + </button> </div> )} </div> |