diff options
author | Sophie Zhang <sophie_zhang@brown.edu> | 2023-10-19 02:14:16 -0400 |
---|---|---|
committer | Sophie Zhang <sophie_zhang@brown.edu> | 2023-10-19 02:14:16 -0400 |
commit | 414abda35b79c2d670451df8938740bd891881e1 (patch) | |
tree | 17e7e56bbc8ad0baf17a78d718f161a10ad28f16 | |
parent | 1efba5a6a80cba09633426fc8cb42be4bf9b2e74 (diff) |
fixed key events (chatbox)
-rw-r--r-- | src/client/apis/gpt/GPT.ts | 9 | ||||
-rw-r--r-- | src/client/views/nodes/trails/PresBox.scss | 3 | ||||
-rw-r--r-- | src/client/views/nodes/trails/PresBox.tsx | 81 |
3 files changed, 74 insertions, 19 deletions
diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts index 66689f2f6..6806802f3 100644 --- a/src/client/apis/gpt/GPT.ts +++ b/src/client/apis/gpt/GPT.ts @@ -25,8 +25,13 @@ const configuration = new Configuration({ const openai = new OpenAIApi(configuration); const gptTrailSlideCustomization = async (inputText: string) => { - const prompt = - 'We are adding customization to a slide in a presentation. Given a natural language input, translate it into a json with the required fields: [title, presentation_transition, presentation_effect, and config_zoom]. title is the title/name of the slide. presentation_transition is a number in milliseconds for how long it should take to transition to a slide. presentation_effect is an effect applied to the slide when we transition to it. Its only possible values are: [None, Fade in, Flip, Rotate, Bounce, Roll]. config zoom is a number from 0 to 1.0 indicating the percentage we should be zooming into the slide. If the input does not contain info a specific key, please set their value to null. Please only return the json with these keys and their values.'; + let prompt = + 'We are adding customization to a slide in a presentation. Given a natural language input, translate it into a json with the required fields: [title, presentation_transition, presentation_movement, presentation_effect, config_zoom, presentation_effectDirection].'; + + prompt += + 'title is the title/name of the slide. presentation_transition is a number in milliseconds for how long it should take to transition to a slide. presentation_movement is how the slide is moved onscreen. Its only possible values are: [none, center, zoom, pan, jump]. If the input contains zoom, make sure to set presentation_movement to zoom. presentation_effect is an effect applied to the slide when we transition to it. Its only possible values are: [None, Fade in, Flip, Rotate, Bounce, Roll]. presentation_effectDirection is what direction the slide comes in from. Its only possible values are: [Enter from left, Enter from right, Enter from bottom, Enter from Top, Enter from center]. config_zoom is a number from 0 to 1.0 indicating the percentage we should be zooming into the slide.'; + + prompt += 'If the input does not contain info a specific key, please set their value to null. Please only return the json with these keys and their values.'; try { const response = await openai.createChatCompletion({ diff --git a/src/client/views/nodes/trails/PresBox.scss b/src/client/views/nodes/trails/PresBox.scss index 370b155fd..1b76a39ad 100644 --- a/src/client/views/nodes/trails/PresBox.scss +++ b/src/client/views/nodes/trails/PresBox.scss @@ -34,9 +34,6 @@ .pres-chatbox { outline: none; border: none; - font-size: 16px; - letter-spacing: 1px; - color: #404040; } } diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 051a1fbfd..0d5edcd83 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -36,6 +36,7 @@ import { DocFocusOptions, DocumentView, OpenWhere, OpenWhereMod } from '../Docum import { FieldView, FieldViewProps } from '../FieldView'; import { ScriptingBox } from '../ScriptingBox'; import './PresBox.scss'; +import ReactLoading from 'react-loading'; import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums'; import { IconButton, Type } from 'browndash-components'; import { AiOutlineSend } from 'react-icons/ai'; @@ -112,10 +113,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { @observable _forceKeyEvents: boolean = false; // GPT + private _inputref: HTMLTextAreaElement | null = null; @observable chatActive: boolean = false; @observable chatInput: string = ''; public slideToModify: Doc | null = null; @observable isRecording: boolean = false; + @observable isLoading: boolean = false; @action setChatInput = (input: string) => { @@ -123,6 +126,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { }; @action + setIsLoading = (isLoading: boolean) => { + this.isLoading = isLoading; + }; + + @action public setChatActive = (active: boolean) => { this.chatActive = active; }; @@ -272,6 +280,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { // GPT recordDictation = () => { + this.setIsRecording(true); + this.setChatInput(''); DictationManager.Controls.listen({ interimHandler: this.setDictationContent, continuous: { indefinite: false }, @@ -281,17 +291,38 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { } }); }; - stopDictation = (abort: boolean) => DictationManager.Controls.stop(!abort); + stopDictation = (abort: boolean) => { + this.setIsRecording(false); + DictationManager.Controls.stop(!abort); + }; setDictationContent = (value: string) => { this.setChatInput(value); + // // Get the current cursor position + // if (!this._inputref) return; + // const cursorPosition = this._inputref.selectionStart; + // const currentValue = this.chatInput; + + // // split before and after + // const textBeforeCursor = currentValue.slice(0, cursorPosition); + // const textAfterCursor = currentValue.slice(cursorPosition); + + // // insertion + // const updatedText = textBeforeCursor + value + textAfterCursor; + + // // Update the textarea value + // this.setChatInput(updatedText); + + // // set new cursor pos + // const newCursorPosition = cursorPosition + value.length; + // this._inputref.setSelectionRange(newCursorPosition, newCursorPosition); }; @action customizeWithGPT = 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 gptTrailSlideCustomization(input); if (typeof res === 'string') { @@ -307,6 +338,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { } catch (err) { console.error(err); } + this.setIsLoading(false); }; //TODO: al: it seems currently that tempMedia doesn't stop onslidechange after clicking the button; the time the tempmedia stop depends on the start & end time @@ -1280,6 +1312,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { @action keyEvents = (e: KeyboardEvent) => { if (e.target instanceof HTMLInputElement) return; + if (e.target instanceof HTMLTextAreaElement) return; let handled = false; const anchorNode = document.activeElement as HTMLDivElement; if (anchorNode && anchorNode.className?.includes('lm_title')) return; @@ -2742,17 +2775,31 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { {this.chatActive && ( <div className="presBox-chatbox"> <div style={{ alignSelf: 'flex-end' }}> - <IconButton - type={Type.PRIM} - color={StrCast(Doc.UserDoc().userVariantColor)} - tooltip="Close" - icon={<BiX size={'16px'} />} - onClick={() => { - this.setChatActive(false); - }} - /> + {this.isLoading ? ( + <ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} width={14} height={14} /> + ) : ( + <IconButton + type={Type.PRIM} + color={StrCast(Doc.UserDoc().userVariantColor)} + tooltip="Close" + icon={<BiX size={'16px'} />} + onClick={() => { + this.setChatActive(false); + }} + /> + )} </div> + {/* <div + contentEditable={true} + onInput={e => { + const newContent = e.currentTarget.innerHTML; + console.log('content', newContent); + this.setChatInput(newContent); + }}> + {this.chatInput} + </div> */} <TextareaAutosize + ref={r => (this._inputref = r)} minRows={3} placeholder="Customize..." className="pres-chatbox" @@ -2761,10 +2808,16 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { onChange={e => { this.setChatInput(e.target.value); }} - onSelect={e => { + // onSelect={e => { + // this.stopDictation(true); + // }} + onKeyDown={e => { + // if (e.key === 'Enter') { + // this.customizeWithGPT(this.chatInput); + // } this.stopDictation(true); + e.stopPropagation(); }} - onKeyDown={e => e.stopPropagation()} onKeyPress={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()} onClick={e => e.stopPropagation()} @@ -2787,7 +2840,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { /> <IconButton type={Type.TERT} - color={StrCast(Doc.UserDoc().userVariantColor)} + color={!this.isLoading ? StrCast(Doc.UserDoc().userVariantColor) : '#7c7c7c'} tooltip="Send" icon={<AiOutlineSend size={'16px'} />} onClick={() => { |