aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSophie Zhang <sophie_zhang@brown.edu>2024-04-10 15:54:26 -0400
committerSophie Zhang <sophie_zhang@brown.edu>2024-04-10 15:54:26 -0400
commit6fc9e5b8eb766ca509f09a5ac7d752be57a864dd (patch)
tree187843cdecc87518a4553d8aa697b6361bf4ba86
parent9e221fdb995d5a489fb34133d2ab98d7907219bd (diff)
remove collection color styling from this branch
-rw-r--r--src/client/apis/gpt/customization.ts151
-rw-r--r--src/client/views/PropertiesView.tsx107
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx68
-rw-r--r--src/client/views/nodes/trails/SlideEffect.tsx1
4 files changed, 5 insertions, 322 deletions
diff --git a/src/client/apis/gpt/customization.ts b/src/client/apis/gpt/customization.ts
index bc3f57210..71467a1e1 100644
--- a/src/client/apis/gpt/customization.ts
+++ b/src/client/apis/gpt/customization.ts
@@ -6,28 +6,6 @@ export enum CustomizationType {
PRES_TRAIL_SLIDE = 'trails',
}
-export interface GeneratedResponse {
- collectionBackgroundColor: string;
- documentsWithColors: DocumentWithColor[];
-}
-
-export interface DocumentWithColor {
- id: number;
- color: string;
-}
-
-export interface StyleInputDocument {
- id: number;
- textContent: string;
- textSize: number;
-}
-
-export interface StyleInput {
- collectionDescription: string;
- documents: StyleInputDocument[];
- imageColors: string[];
-}
-
interface PromptInfo {
description: string;
features: { name: string; description: string; values?: string[] }[];
@@ -98,132 +76,3 @@ export const gptTrailSlideCustomization = async (inputText: string, properties:
return 'Error connecting with API.';
}
};
-
-// layout
-export const smartLayout = async (inputData: { width: number; height: number }[]) => {
- let prompt =
- 'I want to layout documents in a 2d space in a nice, grid-like fashion with nice padding of about 50 units around each document, making sure they do not overlap. Given a json array of documents containing their width and heights in this form: {width: number, height: number}[], give me a json array in this form: {x: number, y: number}[] corresponding to the documents with a nice layout. Return just the json array.';
-
- let messages: ChatCompletionMessageParam[] = [
- { role: 'system', content: prompt },
- { role: 'user', content: JSON.stringify(inputData) },
- ];
-
- console.log('Prompt: ', prompt);
- console.log('Messages: ', messages);
-
- try {
- const response = await openai.chat.completions.create({
- model: 'gpt-4',
- messages: messages,
- temperature: 0.01,
- max_tokens: 2000,
- });
- const content = response.choices[0].message?.content;
- if (content) {
- return content;
- }
- return 'Malformed response.';
- } catch (err) {
- console.log(err);
- return 'Error connecting with API.';
- }
-};
-
-// layout
-export const smartLayout2 = async (inputData: { width: number; height: number }[]) => {
- let prompt =
- 'I want to layout documents in a freeform 2d space in a masonry layout with a padding of around 50 units around each document. Take inspiration from existing UI grid and masonry layout design patterns. Make sure documents do not overlap. Given a json array of documents containing their width and heights in this form: {width: number, height: number}[], give me a json array in this form: {x: number, y: number}[] corresponding to the documents in the same order with the improved layout. Return just the json array.';
-
- let messages: ChatCompletionMessageParam[] = [
- { role: 'system', content: prompt },
- { role: 'user', content: JSON.stringify(inputData) },
- ];
-
- console.log('Prompt: ', prompt);
- console.log('Messages: ', messages);
-
- try {
- const response = await openai.chat.completions.create({
- model: 'gpt-4',
- messages: messages,
- temperature: 0,
- max_tokens: 2000,
- });
- const content = response.choices[0].message?.content;
- if (content) {
- return content;
- }
- return 'Malformed response.';
- } catch (err) {
- console.log(err);
- return 'Error connecting with API.';
- }
-};
-
-// palette / styling
-export const generatePalette = async (inputData: StyleInput, useImageData: boolean, inputText: string, lastResponse?: GeneratedResponse[]) => {
- let prompt = 'Dash is a hypermedia web application that allows users to organize documents of different media types into collections. The user wants you to come up with cohesive color palettes for a collection.';
- prompt +=
- ' The user is going to give you a json object of this format:' +
- JSON.stringify({ collectionDescription: 'string', documents: 'Document[]', imageColors: 'string[]' }) +
- '. The user may follow by giving more specific instructions on what kind of palettes they want. collectionDescription is the title of the collection, which you should create color palettes based on. This is the document format:' +
- JSON.stringify({
- id: 'number',
- textSize: 'number',
- textContent: 'string',
- }) +
- (useImageData ? '. Finally, imageColors are the main hex colors of the images in the collection.' : '. Ignore imageColors.') +
- 'You are going to generate three distinct variants of color palettes for the user to choose from based mostly on collectionDescription, and loosely on the text content and text size of the documents.' +
- (useImageData ? 'You should slightly take imageColors into account, but primarly focus on crafting a palette that matches the text content.' : '') +
- 'The variants should start with a light palette and grow increasingly more intense and vibrant. Return a json array of three objects in this format:' +
- JSON.stringify({
- collectionBackgroundColor: 'string',
- documentsWithColors: 'DocumentWithColor[]',
- }) +
- '. collectionBackgroundColor, should be a string hex value for the background color of the collection. documentsWithColors has the same length and order of the input documents. DocumentWithColor has this format:' +
- JSON.stringify({
- id: 'number',
- color: 'string',
- }) +
- ", and each element’s color is based on the theme of the overall color palette and also by its document’s textContent. Please pay attention to aesthetics of how each document's color complement the background and each other and choose a variety of colors when appropriate.";
-
- // enforce format
- prompt += 'Important: Respond with only the JSON array and no other text.';
-
- // iteration
-
- let messages: ChatCompletionMessageParam[] = [
- { role: 'system', content: prompt },
- { role: 'user', content: JSON.stringify(inputData) },
- ];
-
- // continuing conversation
- if (lastResponse && inputText !== '') {
- messages.push({ role: 'assistant', content: JSON.stringify(lastResponse) });
- messages.push({ role: 'user', content: 'Please modify the previously generated palettes with the following: ' + inputText });
- } else if (inputText !== '') {
- messages.push({ role: 'user', content: inputText });
- }
-
- console.log('Prompt: ', prompt);
- console.log('Messages: ', messages);
-
- try {
- const response = await openai.chat.completions.create({
- model: 'gpt-4',
- messages: messages,
- temperature: 0.1,
- max_tokens: 2000,
- });
- const content = response.choices[0].message?.content;
- console.log(content);
- if (content) {
- return content;
- }
- return 'Malformed response.';
- } catch (err) {
- console.log(err);
- return 'Error connecting with API.';
- }
-};
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 6da46c229..15974b9a7 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -43,7 +43,6 @@ import { KeyValueBox } from './nodes/KeyValueBox';
import { PresBox, PresEffect, PresEffectDirection } from './nodes/trails';
import { ExtractColors } from './ExtractColors';
import TextareaAutosize from 'react-textarea-autosize';
-import { GeneratedResponse, StyleInput, generatePalette } from '../apis/gpt/customization';
import { FaFillDrip } from 'react-icons/fa';
import { LinkBox } from './nodes/LinkBox';
@@ -109,55 +108,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
@observable openStyling: boolean = true;
// GPT styling
- public styleInput: StyleInput | undefined;
- @observable loadingStyles: boolean = false;
- @observable generatedStyles: GeneratedResponse[] = [];
- @observable inputDocs: Doc[] = [];
- @observable selectedStyle: number = -1;
- @observable useImageData = false;
-
- @observable chatInput: string = '';
-
- @action
- setChatInput = (input: string) => {
- this.chatInput = input;
- };
-
- @action
- setLoading = (loading: boolean) => {
- this.loadingStyles = loading;
- };
-
- @action
- gptStyling = async () => {
- // this.generatedStyles = [];
- this.selectedStyle = -1;
- this.setLoading(true);
- console.log('Style input: ', this.styleInput);
-
- if (!this.styleInput) return;
-
- try {
- let res: any;
- if (this.generatedStyles.length === 0) {
- res = await generatePalette(this.styleInput, this.useImageData, this.chatInput);
- } else {
- res = await generatePalette(this.styleInput, this.useImageData, this.chatInput, this.generatedStyles);
- }
- if (typeof res === 'string') {
- console.log('Generated palettes: ', res);
- const resObj = JSON.parse(res) as GeneratedResponse[];
- this.setGeneratedStyles(resObj);
- }
- } catch (err) {
- console.error(err);
- }
- this.setLoading(false);
- };
-
- @action
- setGeneratedStyles = (responses: GeneratedResponse[]) => (this.generatedStyles = responses);
- setInputDocs = (docs: Doc[]) => (this.inputDocs = docs);
+ // removed for now
//Pres Trails booleans:
@observable openPresTransitions: boolean = true;
@@ -1197,60 +1148,6 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
}
};
- @action
- styleCollection = (i: number) => {
- this.selectedStyle = i;
- const resObj = this.generatedStyles[i];
- if (this.selectedDoc && this.selectedDoc.type === 'collection') {
- this.selectedDoc.backgroundColor = resObj.collectionBackgroundColor;
- resObj.documentsWithColors.forEach((elem, i) => (this.inputDocs[i].backgroundColor = elem.color));
- }
- };
-
- // GPT styling
- @computed get stylingSubMenu() {
- return (
- <PropertiesSection title="Styling" isOpen={this.openStyling} setIsOpen={bool => (this.openStyling = bool)} onDoubleClick={() => this.CloseAll()}>
- <div className="propertiesView-content" style={{ position: 'relative', height: 'auto', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '4px' }}>
- {this.generatedStyles.length > 0 &&
- this.generatedStyles.map((style, i) => (
- <div
- key={i}
- className="propertiesView-palette"
- style={{ display: 'flex', gap: '4px', backgroundColor: this.selectedStyle === i ? StrCast(Doc.UserDoc().userVariantColor) : '#00000000' }}
- onClick={() => this.styleCollection(i)}>
- <div style={{ width: '24px', height: '24px', backgroundColor: style.collectionBackgroundColor, borderRadius: '2px' }}></div>
- {ExtractColors.sortColors(style.documentsWithColors.map(doc => ExtractColors.hexToFinalColor(doc.color))).map((c, i) => (
- <div key={i} style={{ width: '24px', height: '24px', backgroundColor: c.hex, borderRadius: '2px' }}></div>
- ))}
- </div>
- ))}
- {this.loadingStyles && 'Generating styles...'}
- <TextareaAutosize
- minRows={3}
- placeholder="Customize..."
- className="styling-chatbox"
- autoFocus={true}
- value={this.chatInput}
- onChange={e => {
- this.setChatInput(e.target.value);
- }}
- onKeyDown={e => {
- e.stopPropagation();
- }}
- />
- <div style={{ display: 'flex', justifyContent: 'flex-end', gap: '16px' }}>
- <div style={{ display: 'flex', gap: '4px', alignItems: 'center' }}>
- <label style={{ margin: '0px' }}>Use Images </label>
- <input style={{ margin: '0px' }} type="checkbox" checked={this.useImageData} onChange={action(e => (this.useImageData = e.target.checked))} />
- </div>
- <Button text={'Regenerate'} type={Type.TERT} color={StrCast(Doc.UserDoc().userVariantColor)} onClick={this.gptStyling} />
- </div>
- </div>
- </PropertiesSection>
- );
- }
-
@computed get filtersSubMenu() {
return (
<PropertiesSection title="Filters" isOpen={this.openFilters} setIsOpen={bool => (this.openFilters = bool)} onDoubleClick={() => this.CloseAll()}>
@@ -1756,7 +1653,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
<div className="propertiesView-name">{this.editableTitle}</div>
<div className="propertiesView-type"> {this.currentType} </div>
- {this.stylingSubMenu}
+ {/* {this.stylingSubMenu} */}
{this.fieldsSubMenu}
{this.optionsSubMenu}
{this.linksSubMenu}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index c5102070a..958117b91 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -55,7 +55,6 @@ import './CollectionFreeFormView.scss';
import { MarqueeView } from './MarqueeView';
import { PropertiesView } from '../../PropertiesView';
import { ExtractColors } from '../../ExtractColors';
-import { smartLayout, smartLayout2, StyleInputDocument } from '../../../apis/gpt/customization';
import { extname } from 'path';
import { RichTextField } from '../../../../fields/RichTextField';
@@ -1688,74 +1687,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
// gpt layout
@action
- gptLayout = async () => {
- const docLayouts = this.childDocs.map(doc => ({
- width: this.roundToRoundNumber(NumCast(doc.width)),
- height: this.roundToRoundNumber(NumCast(doc.height)),
- // content: StrCast(doc.title),
- }));
- console.log('Doc layouts', docLayouts);
-
- const res = await smartLayout2(docLayouts);
- console.log('Smart layout result', res);
- // make type-safe
- const resObj = JSON.parse(res) as any[];
- resObj.forEach((elem, i) => {
- this.childDocs[i].x = elem.x;
- this.childDocs[i].y = elem.y;
- });
-
- // refit collection
- setTimeout(() => {
- this.fitContentOnce();
- }, 500);
- };
+ gptLayout = async () => {};
// gpt styling
@action
- gptStyling = async () => {
- // clear it in properties instead
- if (!PropertiesView.Instance) return;
- this.openProperties();
- PropertiesView.Instance.setGeneratedStyles([]);
- PropertiesView.Instance.selectedStyle = -1;
- PropertiesView.Instance.useImageData = false;
-
- console.log('Title', this.Document.title);
- console.log('bgcolor', this.layoutDoc._backgroundColor);
- // doc.backgroundColor
- const inputDocs = this.childDocs.filter(doc => doc.type == 'rich text');
- const imgDocs = this.childDocs.filter(doc => doc.type == 'image');
- const imgUrls = imgDocs.map(doc => this.choosePath((doc.data as ImageField).url));
-
- const imageElements = await ExtractColors.loadImagesUrl(imgUrls);
- const colors = await Promise.all(imageElements.map(elem => ExtractColors.getImgColors(elem)));
- let colorHexes = colors
- .reduce((acc, curr) => acc.concat(curr), [])
- .map(color => color.hex)
- .slice(0, 10);
- console.log('Hexes', colorHexes);
-
- PropertiesView.Instance?.setInputDocs(inputDocs);
-
- // also pass it colors
- const gptInput: StyleInputDocument[] = inputDocs.map((doc, i) => ({
- id: i,
- textContent: (doc.text as RichTextField)?.Text,
- textSize: 16,
- }));
-
- const collectionDescription = StrCast(this.Document.title);
-
- const styleInput = {
- collectionDescription,
- documents: gptInput,
- imageColors: colorHexes,
- };
-
- PropertiesView.Instance.styleInput = styleInput;
- PropertiesView.Instance.gptStyling();
- };
+ gptStyling = async () => {};
onContextMenu = (e: React.MouseEvent) => {
if (this._props.isAnnotationOverlay || !ContextMenu.Instance) return;
diff --git a/src/client/views/nodes/trails/SlideEffect.tsx b/src/client/views/nodes/trails/SlideEffect.tsx
index eee52c3ec..ba997c62a 100644
--- a/src/client/views/nodes/trails/SlideEffect.tsx
+++ b/src/client/views/nodes/trails/SlideEffect.tsx
@@ -1,6 +1,7 @@
import { useSpring, animated, easings, to } from '@react-spring/web';
import React, { useEffect, useState } from 'react';
import { PresEffect, PresEffectDirection } from './PresEnums';
+import './SlideEffect.scss';
interface Props {
dir: PresEffectDirection;