aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/apis/gpt/customization.ts24
-rw-r--r--src/client/views/nodes/trails/PresBox.scss5
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx186
3 files changed, 170 insertions, 45 deletions
diff --git a/src/client/apis/gpt/customization.ts b/src/client/apis/gpt/customization.ts
index a1ab2bd5f..9c751f8bd 100644
--- a/src/client/apis/gpt/customization.ts
+++ b/src/client/apis/gpt/customization.ts
@@ -39,7 +39,7 @@ const setupPresSlideCustomization = () => {
setupPresSlideCustomization();
-export const getSlideTransitionSuggestions = async (inputText: string, properties: any) => {
+export const getSlideTransitionSuggestions = async (inputText: string, history?: string) => {
/**
* Prompt: Generate an entrance animations from slower and gentler
* to bouncier and more high energy
@@ -56,7 +56,27 @@ export const getSlideTransitionSuggestions = async (inputText: string, propertie
* }
* }
*/
- const res = await new Promise(resolve => resolve('result'));
+
+ const prompt =
+ "I want to generate four distinct types of slide effect animations. Return a json of the form {effect: string, stiffness: number, damping: number, mass: number}[] with four elements. Effect is the type of animation; its only possible values are ['Zoom', 'Fade in', 'Bounce', 'Flip', 'Rotate', 'Roll']. Stiffness, damping, and mass Stiffness, damping, and mass control the physics-based properties of spring animations. This is used to create a more natural looking timing, bouncy effects, etc. Use spring physics to adjust these parameters to animate the effect.";
+
+ const customInput = inputText ?? 'Make them as contrasting as possible with different effects and timings ranging from gentle to energetic.';
+
+ try {
+ const response = await openai.chat.completions.create({
+ model: 'gpt-4',
+ messages: [
+ { role: 'system', content: prompt },
+ { role: 'user', content: `${customInput}` },
+ ],
+ temperature: 0,
+ max_tokens: 1000,
+ });
+ return response.choices[0].message?.content;
+ } catch (err) {
+ console.log(err);
+ return 'Error connecting with API.';
+ }
};
export const gptTrailSlideCustomization = async (inputText: string, properties: any | any[], applyToWhole?: boolean) => {
diff --git a/src/client/views/nodes/trails/PresBox.scss b/src/client/views/nodes/trails/PresBox.scss
index 09de4b0f4..7a2733146 100644
--- a/src/client/views/nodes/trails/PresBox.scss
+++ b/src/client/views/nodes/trails/PresBox.scss
@@ -40,11 +40,12 @@
.presBox-effect-row {
display: flex;
- gap: 4px;
+ gap: 8px;
margin: 4px;
}
.presBox-effect-container {
+ cursor: pointer;
overflow: hidden;
position: relative;
width: 80px;
@@ -61,7 +62,7 @@
top: 20px;
left: 20px;
border-radius: 4px;
- // default bg
+ // default bg
background-color: rgb(37, 161, 255);
}
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 9644935b2..67f787b1e 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -42,13 +42,13 @@ import ReactTextareaAutosize from 'react-textarea-autosize';
import { Button, Dropdown, DropdownType, IconButton, Toggle, ToggleType, Type } from 'browndash-components';
import { BiMicrophone, BiX } from 'react-icons/bi';
import { AiOutlineSend } from 'react-icons/ai';
-import { gptSlideProperties, gptTrailSlideCustomization } from '../../../apis/gpt/customization';
+import { getSlideTransitionSuggestions, gptSlideProperties, gptTrailSlideCustomization } from '../../../apis/gpt/customization';
import { DictationManager } from '../../../util/DictationManager';
import CubicBezierEditor, { TIMING_DEFAULT_MAPPINGS } from './CubicBezierEditor';
import Slider from '@mui/material/Slider';
import { FaArrowDown, FaArrowLeft, FaArrowRight, FaArrowUp, FaCompressArrowsAlt } from 'react-icons/fa';
import SpringAnimationPreview from './SlideEffectPreview';
-import { effectTimings, SpringType, springMappings, effectItems, easeItems, movementItems, SpringSettings, presEffectDefaultTimings } from './SpringUtils';
+import { effectTimings, SpringType, springMappings, effectItems, easeItems, movementItems, SpringSettings, presEffectDefaultTimings, AnimationSettings } from './SpringUtils';
import SlideEffect from './SlideEffect';
export interface pinDataTypes {
@@ -121,18 +121,58 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
// GPT
private _inputref: HTMLTextAreaElement | null = null;
+ private _inputref2: HTMLTextAreaElement | null = null;
@observable chatActive: boolean = false;
@observable chatInput: string = '';
public slideToModify: Doc | null = null;
@observable isRecording: boolean = false;
@observable isLoading: boolean = false;
+ @observable generatedAnimations: AnimationSettings[] = [
+ {
+ effect: PresEffect.Bounce,
+ stiffness: 400,
+ damping: 15,
+ mass: 1,
+ },
+ {
+ effect: PresEffect.Fade,
+ stiffness: 100,
+ damping: 15,
+ mass: 1,
+ },
+ {
+ effect: PresEffect.Flip,
+ stiffness: 100,
+ damping: 15,
+ mass: 1,
+ },
+ {
+ effect: PresEffect.Roll,
+ stiffness: 100,
+ damping: 15,
+ mass: 1,
+ },
+ ];
+
+ @action
+ setGeneratedAnimations = (settings: AnimationSettings[]) => {
+ this.generatedAnimations = settings;
+ };
+
+ @observable animationChat: string = '';
+
@action
setChatInput = (input: string) => {
this.chatInput = input;
};
@action
+ setAnimationChat = (input: string) => {
+ this.animationChat = input;
+ };
+
+ @action
setIsLoading = (isLoading: boolean) => {
this.isLoading = isLoading;
};
@@ -367,6 +407,41 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
};
@action
+ customizeAnimations = async (input: string) => {
+ // const testInput = 'change title to Customized Slide, transition for 2.3s with fade in effect';
+ // if (!this.slideToModify) return;
+ this.setIsLoading(true);
+
+ try {
+ const res = await getSlideTransitionSuggestions(this.animationChat);
+ console.log('GPT Result:', res);
+ if (typeof res === 'string') {
+ const resObj = JSON.parse(res);
+ console.log('Parsed GPT Result ', resObj);
+ // this.activeItem
+ this.setGeneratedAnimations(resObj as AnimationSettings[]);
+ // this.updateEffect(resObj.effect as PresEffect, false);
+ // this.updateEffectTiming(this.activeItem, {
+ // type: SpringType.CUSTOM,
+ // stiffness: resObj.stiffness,
+ // damping: resObj.damping,
+ // mass: resObj.mass,
+ // });
+
+ // for (let key in resObj) {
+ // if (resObj[key]) {
+ // console.log('typeof property', typeof resObj[key]);
+ // this.activeItem[key] = resObj[key];
+ // }
+ // }
+ }
+ } catch (err) {
+ console.error(err);
+ }
+ this.setIsLoading(false);
+ };
+
+ @action
customizeWithGPT = async (input: string) => {
// const testInput = 'change title to Customized Slide, transition for 2.3s with fade in effect';
// if (!this.slideToModify) return;
@@ -2176,35 +2251,26 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<div className="presBox-gpt-chat">
<p>Customize with GPT</p>
<div className="pres-chat">
- <div className="pres-chatbox-container">
+ <div
+ className="pres-chatbox-container"
+ onClick={e => {
+ e.stopPropagation();
+ }}>
<ReactTextareaAutosize
ref={r => (this._inputref = r)}
minRows={1}
- placeholder="Customize..."
+ placeholder="Get animation suggestions..."
className="pres-chatbox"
autoFocus={true}
- value={this.chatInput}
+ value={this.animationChat}
onChange={e => {
- this.setChatInput(e.target.value);
+ this.setAnimationChat(e.target.value);
}}
onKeyDown={e => {
this.stopDictation(true);
e.stopPropagation();
}}
/>
- <IconButton
- type={Type.TERT}
- color={this.isRecording ? '#2bcaff' : StrCast(Doc.UserDoc().userVariantColor)}
- tooltip="Record"
- icon={<BiMicrophone size={'16px'} />}
- onClick={() => {
- if (!this.isRecording) {
- this.recordDictation();
- } else {
- this.stopDictation(true);
- }
- }}
- />
</div>
<Button
style={{ alignSelf: 'flex-end' }}
@@ -2214,34 +2280,72 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
iconPlacement="right"
color={StrCast(Doc.UserDoc().userVariantColor)}
onClick={() => {
- this.customizeWithGPT(this.chatInput);
+ this.customizeAnimations(this.animationChat);
}}
/>
</div>
</div>
{/* Preview Animations */}
- <div className="presBox-effect-row">
- <div className="presBox-effect-container">
- <SlideEffect dir={PresEffectDirection.Left as PresEffectDirection} presEffect={PresEffect.Bounce} tension={100} friction={15} mass={1} infinite>
- <div className="presBox-effect-demo-box"></div>
- </SlideEffect>
- </div>
- <div className="presBox-effect-container">
- <SlideEffect dir={PresEffectDirection.Left as PresEffectDirection} presEffect={PresEffect.Fade} tension={100} friction={15} mass={1} infinite>
- <div className="presBox-effect-demo-box" style={{ backgroundColor: '#4925ff' }}></div>
- </SlideEffect>
- </div>
- </div>
- <div className="presBox-effect-row">
- <div className="presBox-effect-container">
- <SlideEffect dir={PresEffectDirection.Left as PresEffectDirection} presEffect={PresEffect.Flip} tension={100} friction={15} mass={1} infinite>
- <div className="presBox-effect-demo-box" style={{ top: 0, left: 0, backgroundColor: '#a825ff' }}></div>
- </SlideEffect>
+ <div>
+ <div className="presBox-effect-row">
+ <div className="presBox-effect-container">
+ <SlideEffect
+ key={JSON.stringify(this.generatedAnimations[0])}
+ dir={PresEffectDirection.Left as PresEffectDirection}
+ presEffect={this.generatedAnimations[0].effect as PresEffect}
+ tension={this.generatedAnimations[0].stiffness}
+ friction={this.generatedAnimations[0].damping}
+ mass={this.generatedAnimations[0].mass}
+ infinite>
+ <div
+ className="presBox-effect-demo-box"
+ style={{ top: this.generatedAnimations[0].effect === PresEffect.Flip ? 0 : '20px', left: this.generatedAnimations[0].effect === PresEffect.Flip ? 0 : '20px' }}></div>
+ </SlideEffect>
+ </div>
+ <div className="presBox-effect-container">
+ <SlideEffect
+ key={JSON.stringify(this.generatedAnimations[1])}
+ dir={PresEffectDirection.Left as PresEffectDirection}
+ presEffect={this.generatedAnimations[1].effect as PresEffect}
+ tension={this.generatedAnimations[1].stiffness}
+ friction={this.generatedAnimations[1].damping}
+ mass={this.generatedAnimations[1].mass}
+ infinite>
+ <div
+ className="presBox-effect-demo-box"
+ style={{ top: this.generatedAnimations[1].effect === PresEffect.Flip ? 0 : '20px', left: this.generatedAnimations[1].effect === PresEffect.Flip ? 0 : '20px', backgroundColor: '#4925ff' }}></div>
+ </SlideEffect>
+ </div>
</div>
- <div className="presBox-effect-container">
- <SlideEffect dir={PresEffectDirection.Left as PresEffectDirection} presEffect={PresEffect.Roll} tension={100} friction={15} mass={1} infinite>
- <div className="presBox-effect-demo-box" style={{ backgroundColor: '#ff2599' }}></div>
- </SlideEffect>
+ <div className="presBox-effect-row">
+ <div className="presBox-effect-container">
+ <SlideEffect
+ key={JSON.stringify(this.generatedAnimations[2])}
+ dir={PresEffectDirection.Left as PresEffectDirection}
+ presEffect={this.generatedAnimations[2].effect as PresEffect}
+ tension={this.generatedAnimations[2].stiffness}
+ friction={this.generatedAnimations[2].damping}
+ mass={this.generatedAnimations[2].mass}
+ infinite>
+ <div
+ className="presBox-effect-demo-box"
+ style={{ top: this.generatedAnimations[2].effect === PresEffect.Flip ? 0 : '20px', left: this.generatedAnimations[2].effect === PresEffect.Flip ? 0 : '20px', backgroundColor: '#a825ff' }}></div>
+ </SlideEffect>
+ </div>
+ <div className="presBox-effect-container">
+ <SlideEffect
+ key={JSON.stringify(this.generatedAnimations[3])}
+ dir={PresEffectDirection.Left as PresEffectDirection}
+ presEffect={this.generatedAnimations[3].effect as PresEffect}
+ tension={this.generatedAnimations[3].stiffness}
+ friction={this.generatedAnimations[3].damping}
+ mass={this.generatedAnimations[3].mass}
+ infinite>
+ <div
+ className="presBox-effect-demo-box"
+ style={{ top: this.generatedAnimations[3].effect === PresEffect.Flip ? 0 : '20px', left: this.generatedAnimations[3].effect === PresEffect.Flip ? 0 : '20px', backgroundColor: '#ff2599' }}></div>
+ </SlideEffect>
+ </div>
</div>
</div>
</div>