aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/apis/gpt/customization.ts63
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx29
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx5
3 files changed, 94 insertions, 3 deletions
diff --git a/src/client/apis/gpt/customization.ts b/src/client/apis/gpt/customization.ts
index db91e45a7..42f112f88 100644
--- a/src/client/apis/gpt/customization.ts
+++ b/src/client/apis/gpt/customization.ts
@@ -84,6 +84,68 @@ export const gptTrailSlideCustomization = async (inputText: string) => {
}
};
+// 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; content: string }[]) => {
+ let prompt =
+ 'I want to layout documents in a 2d space in an organized fashion with padding of about 50 units around each document, importantly making sure they do not overlap. I also want you to group documents by their content, with space separating semantic categories. Given a json array of documents containing their width and heights in this form: {width: number, height: number, content: string}[], give me a json array in this form: {x: number, y: number}[] corresponding to the documents in the same order 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.';
+ }
+};
+
// 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.';
@@ -121,6 +183,7 @@ export const generatePalette = async (inputData: StyleInput, useImageData: boole
{ 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 });
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 8e415a407..fb9d42bc7 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -55,7 +55,7 @@ import './CollectionFreeFormView.scss';
import { MarqueeView } from './MarqueeView';
import { PropertiesView } from '../../PropertiesView';
import { ExtractColors } from '../../ExtractColors';
-import { StyleInputDocument } from '../../../apis/gpt/customization';
+import { smartLayout, smartLayout2, StyleInputDocument } from '../../../apis/gpt/customization';
import { RichTextField } from '../../../../fields/RichTextField';
import { extname } from 'path';
@@ -1659,6 +1659,31 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return url.href.replace(ext, '_m' + ext);
}
+ // gpt layout
+ @action
+ gptLayout = async () => {
+ const docLayouts = this.childDocs.map(doc => ({
+ width: NumCast(doc.width),
+ height: NumCast(doc.height),
+ content: StrCast(doc.title),
+ }));
+ console.log(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);
+ };
+
// gpt styling
@action
gptStyling = async () => {
@@ -1740,7 +1765,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
optionItems.push({ description: (this._showAnimTimeline ? 'Close' : 'Open') + ' Animation Timeline', event: action(() => (this._showAnimTimeline = !this._showAnimTimeline)), icon: 'eye' });
this._props.renderDepth && optionItems.push({ description: 'Use Background Color as Default', event: () => (Cast(Doc.UserDoc().emptyCollection, Doc, null)._backgroundColor = StrCast(this.layoutDoc._backgroundColor)), icon: 'palette' });
this._props.renderDepth && optionItems.push({ description: 'Fit Content Once', event: this.fitContentOnce, icon: 'object-group' });
+ // Want to condense into a Smart Organize button
this._props.renderDepth && optionItems.push({ description: 'Style with AI', event: this.gptStyling, icon: 'paint-brush' });
+ this._props.renderDepth && optionItems.push({ description: 'Smart Layout', event: this.gptLayout, icon: 'object-group' });
if (!Doc.noviceMode) {
optionItems.push({ description: (!Doc.NativeWidth(this.layoutDoc) || !Doc.NativeHeight(this.layoutDoc) ? 'Freeze' : 'Unfreeze') + ' Aspect', event: this.toggleNativeDimensions, icon: 'snowflake' });
}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index f9cef1a60..460f2a1c6 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -67,6 +67,7 @@ import { RichTextMenu, RichTextMenuPlugin } from './RichTextMenu';
import { RichTextRules } from './RichTextRules';
import { schema } from './schema_rts';
import { SummaryView } from './SummaryView';
+import { isDarkMode } from '../../../util/reportManager/reportManagerUtils';
// import * as applyDevTools from 'prosemirror-dev-tools';
@observer
export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
@@ -1153,7 +1154,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
if (BoolCast(Doc.UserDoc().settingBgColor)) return;
console.log('checking bg color 2');
let fontColor = '#000000';
- if (isDarkMode(StrCast(this.rootDoc._backgroundColor))) {
+ if (isDarkMode(StrCast(this.Document._backgroundColor))) {
fontColor = '#ffffff';
}
// set text to white
@@ -1188,7 +1189,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
{ fireImmediately: true }
);
this._disposers.bgColor = reaction(
- () => this.rootDoc._backgroundColor,
+ () => this.Document._backgroundColor,
color => this.checkBackgroundColor()
);
this._disposers.componentHeights = reaction(