diff options
Diffstat (limited to 'src/client/views/smartdraw/SmartDrawHandler.tsx')
-rw-r--r-- | src/client/views/smartdraw/SmartDrawHandler.tsx | 95 |
1 files changed, 59 insertions, 36 deletions
diff --git a/src/client/views/smartdraw/SmartDrawHandler.tsx b/src/client/views/smartdraw/SmartDrawHandler.tsx index d24cc9d50..24046bb83 100644 --- a/src/client/views/smartdraw/SmartDrawHandler.tsx +++ b/src/client/views/smartdraw/SmartDrawHandler.tsx @@ -7,15 +7,16 @@ import { ObservableReactComponent } from '../ObservableReactComponent'; import { Button, IconButton } from 'browndash-components'; import ReactLoading from 'react-loading'; import { AiOutlineSend } from 'react-icons/ai'; -// import './ImageLabelHandler.scss'; import { gptAPICall, GPTCallType } from '../../apis/gpt/GPT'; -import { InkData } from '../../../fields/InkField'; +import { InkData, InkTool } from '../../../fields/InkField'; import { SVGToBezier } from '../../util/bezierFit'; const { parse } = require('svgson'); import { Slider, Switch } from '@mui/material'; import { Doc } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { DocumentView } from '../nodes/DocumentView'; +import { BoolCast, NumCast, StrCast } from '../../../fields/Types'; +import './SmartDrawHandler.scss'; export interface DrawingOptions { text: string; @@ -43,7 +44,8 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { @observable private _size: number = 200; @observable private _autoColor: boolean = true; @observable private _regenInput: string = ''; - private _addFunc: (e: React.PointerEvent<Element>, strokeList: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => void = () => {}; + @observable private _canInteract: boolean = true; + private _addFunc: (strokeList: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => void = () => {}; private _deleteFunc: (doc?: Doc) => void = () => {}; private _lastInput: DrawingOptions = { text: '', complexity: 5, size: 300, autoColor: true, x: 0, y: 0 }; private _lastResponse: string = ''; @@ -57,12 +59,12 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { @action setUserInput = (input: string) => { - this._userInput = input; + if (this._canInteract) this._userInput = input; }; @action setRegenInput = (input: string) => { - this._regenInput = input; + if (this._canInteract) this._regenInput = input; }; @action @@ -72,21 +74,21 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { @action setComplexity = (val: number) => { - this._complexity = val; + if (this._canInteract) this._complexity = val; }; @action setSize = (val: number) => { - this._size = val; + if (this._canInteract) this._size = val; }; @action setAutoColor = () => { - this._autoColor = !this._autoColor; + if (this._canInteract) this._autoColor = !this._autoColor; }; @action - displaySmartDrawHandler = (x: number, y: number, addFunc: (e: React.PointerEvent<Element>, strokeData: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => void, deleteFunc: (doc?: Doc) => void) => { + displaySmartDrawHandler = (x: number, y: number, addFunc: (strokeData: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => void, deleteFunc: (doc?: Doc) => void) => { this._pageX = x; this._pageY = y; this._display = true; @@ -95,16 +97,18 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { }; @action - displayRegenerate = (x: number, y: number, addFunc: (e: React.PointerEvent<Element>, strokeData: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => void, deleteFunc: (doc?: Doc) => void) => { + displayRegenerate = (x: number, y: number, addFunc: (strokeData: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => void, deleteFunc: (doc?: Doc) => void) => { this._selectedDoc = DocumentView.SelectedDocs().lastElement(); const docData = this._selectedDoc[DocData]; this._addFunc = addFunc; this._deleteFunc = deleteFunc; this._pageX = x; this._pageY = y; + this._display = false; this._showRegenerate = true; - this._lastResponse = docData.drawingData as string; - this._lastInput = { text: docData.drawingInput as string, complexity: docData.drawingComplexity as number, size: docData.drawingSize as number, autoColor: docData.drawingColored as boolean, x: this._pageX, y: this._pageY }; + this._showEditBox = false; + this._lastResponse = StrCast(docData.drawingData); + this._lastInput = { text: StrCast(docData.drawingInput), complexity: NumCast(docData.drawingComplexity), size: NumCast(docData.drawingSize), autoColor: BoolCast(docData.drawingColored), x: this._pageX, y: this._pageY }; }; @action @@ -117,7 +121,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { this._complexity = 5; this._size = 300; this._autoColor = true; - // this._regenInput = '' + Doc.ActiveTool = InkTool.None; }; @action @@ -127,12 +131,25 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { this._regenInput = ''; }; + @action + handleKeyPress = async (event: React.KeyboardEvent) => { + if (event.key === 'Enter') { + if (this._showRegenerate) { + this.regenerate(); + } else { + await this.drawWithGPT({ X: this._pageX, Y: this._pageY }, this._userInput); + this._userInput = ''; + } + } + }; + _errorOccurredOnce = false; @action - drawWithGPT = async (e: React.PointerEvent<Element>, input: string) => { + drawWithGPT = async (startPt: { X: number; Y: number }, input: string) => { if (input === '') return; - this._lastInput = { text: input, complexity: this._complexity, size: this._size, autoColor: this._autoColor, x: e.clientX, y: e.clientY }; + this._lastInput = { text: input, complexity: this._complexity, size: this._size, autoColor: this._autoColor, x: startPt.X, y: startPt.Y }; this._isLoading = true; + this._canInteract = false; this._showOptions = false; try { const res = await gptAPICall(`"${input}", "${this._complexity}", "${this._size}"`, GPTCallType.DRAW, undefined, true); @@ -141,20 +158,22 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { return; } console.log(res); - await this.parseResponse(e, res, { X: e.clientX, Y: e.clientY }, false); + const strokeData = await this.parseResponse(res, startPt, false); this.hideSmartDrawHandler(); this._showRegenerate = true; this._errorOccurredOnce = false; + this._isLoading = false; + this._canInteract = true; + return strokeData; } catch (err) { if (this._errorOccurredOnce) { console.error('GPT call failed', err); this._errorOccurredOnce = false; } else { this._errorOccurredOnce = true; - this.drawWithGPT(e, input); + this.drawWithGPT(startPt, input); } } - this._isLoading = false; }; @action @@ -163,14 +182,15 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { }; @action - regenerate = async (e: React.PointerEvent<Element>) => { + regenerate = async () => { this._isLoading = true; + this._canInteract = false; try { let res; if (this._regenInput !== '') { const prompt: string = `This is your previously generated svg code: ${this._lastResponse} for the user input "${this._lastInput.text}". Please regenerate it with the provided specifications.`; res = await gptAPICall(`"${this._regenInput}"`, GPTCallType.DRAW, prompt, true); - this._lastInput.text = `${this._lastInput.text} + ${this._regenInput}`; + this._lastInput.text = `${this._lastInput.text} ~~~ ${this._regenInput}`; } else { res = await gptAPICall(`"${this._lastInput.text}", "${this._lastInput.complexity}", "${this._lastInput.size}"`, GPTCallType.DRAW, undefined, true); } @@ -179,25 +199,26 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { return; } console.log(res); - this.parseResponse(e, res, { X: this._lastInput.x, Y: this._lastInput.y }, true); + this.parseResponse(res, { X: this._lastInput.x, Y: this._lastInput.y }, true); } catch (err) { console.error('GPT call failed', err); } this._isLoading = false; + this._canInteract = true; this._regenInput = ''; this._showEditBox = false; }; @action - parseResponse = async (e: React.PointerEvent<Element>, res: string, startPoint: { X: number; Y: number }, regenerate: boolean) => { + parseResponse = async (res: string, startPoint: { X: number; Y: number }, regenerate: boolean) => { const svg = res.match(/<svg[^>]*>([\s\S]*?)<\/svg>/g); + console.log(svg); console.log('start point is', startPoint); if (svg) { this._lastResponse = svg[0]; const svgObject = await parse(svg[0]); const svgStrokes: any = svgObject.children; const strokeData: [InkData, string, string][] = []; - console.log('autocolor is', this._autoColor); svgStrokes.forEach((child: any) => { const convertedBezier: InkData = SVGToBezier(child.name, child.attributes); strokeData.push([ @@ -210,10 +231,11 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { }); if (regenerate) { this._deleteFunc(this._selectedDoc); - this._addFunc(e, strokeData, this._lastInput, svg[0], this._selectedDoc); + this._addFunc(strokeData, this._lastInput, svg[0], this._selectedDoc); } else { - this._addFunc(e, strokeData, this._lastInput, svg[0]); + this._addFunc(strokeData, this._lastInput, svg[0]); } + return { data: strokeData, lastInput: this._lastInput, lastRes: svg[0] }; } }; @@ -222,7 +244,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { return ( <div id="label-handler" - className="contextMenu-cont" + className="smart-draw-handler" style={{ display: this._display ? '' : 'none', left: this._pageX, @@ -242,8 +264,9 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { style={{ width: '19px' }} /> <input - aria-label="label-input" - id="new-label" + aria-label="Smart Draw Input" + className="smartdraw-input" + id="smartdraw-input" type="text" style={{ color: 'black' }} value={this._userInput} @@ -251,7 +274,9 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { this.setUserInput(e.target.value); }} placeholder="Enter item to draw" + onKeyDown={this.handleKeyPress} /> + <IconButton tooltip="Advanced Options" icon={<FontAwesomeIcon icon={this._showOptions ? 'caret-down' : 'caret-right'} />} color={SettingsManager.userColor} style={{ width: '14px' }} onClick={this.setShowOptions} /> <Button style={{ alignSelf: 'flex-end' }} text="Send" @@ -259,7 +284,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { iconPlacement="right" color={SettingsManager.userColor} onClick={e => { - this.drawWithGPT(e as React.PointerEvent<Element>, this._userInput); + this.drawWithGPT({ X: e.clientX, Y: e.clientY }, this._userInput); }} /> </div> @@ -349,7 +374,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { return ( <div id="smartdraw-options-menu" - className="contextMenu-cont" + className="smart-draw-handler" style={{ left: this._pageX, ...(this._yRelativeToTop ? { top: Math.max(0, this._pageY) } : { bottom: this._pageY }), @@ -365,9 +390,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { tooltip="Regenerate" icon={this._isLoading && this._regenInput === '' ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <FontAwesomeIcon icon={'rotate'} />} color={SettingsManager.userColor} - onClick={e => { - this.regenerate(e as React.PointerEvent<Element>); - }} + onClick={this.regenerate} /> <IconButton tooltip="Edit with GPT" icon={<FontAwesomeIcon icon="pen-to-square" />} color={SettingsManager.userColor} onClick={this.edit} /> {this._showEditBox && ( @@ -378,6 +401,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { }}> <input aria-label="Edit instructions input" + className="smartdraw-input" id="regen-input" type="text" style={{ color: 'black' }} @@ -385,6 +409,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { onChange={e => { this.setRegenInput(e.target.value); }} + onKeyDown={this.handleKeyPress} placeholder="Edit instructions" /> <Button @@ -393,9 +418,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { icon={this._isLoading && this._regenInput !== '' ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <AiOutlineSend />} iconPlacement="right" color={SettingsManager.userColor} - onClick={e => { - this.regenerate(e as React.PointerEvent<Element>); - }} + onClick={this.regenerate} /> </div> )} |