aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/smartdraw/SmartDrawHandler.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/smartdraw/SmartDrawHandler.tsx')
-rw-r--r--src/client/views/smartdraw/SmartDrawHandler.tsx409
1 files changed, 0 insertions, 409 deletions
diff --git a/src/client/views/smartdraw/SmartDrawHandler.tsx b/src/client/views/smartdraw/SmartDrawHandler.tsx
deleted file mode 100644
index d24cc9d50..000000000
--- a/src/client/views/smartdraw/SmartDrawHandler.tsx
+++ /dev/null
@@ -1,409 +0,0 @@
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, makeObservable, observable } from 'mobx';
-import { observer } from 'mobx-react';
-import React from 'react';
-import { SettingsManager } from '../../util/SettingsManager';
-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 { 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';
-
-export interface DrawingOptions {
- text: string;
- complexity: number;
- size: number;
- autoColor: boolean;
- x: number;
- y: number;
-}
-
-@observer
-export class SmartDrawHandler extends ObservableReactComponent<{}> {
- static Instance: SmartDrawHandler;
-
- @observable private _display: boolean = false;
- @observable private _pageX: number = 0;
- @observable private _pageY: number = 0;
- @observable private _yRelativeToTop: boolean = true;
- @observable private _isLoading: boolean = false;
- @observable private _userInput: string = '';
- @observable private _showOptions: boolean = false;
- @observable private _showEditBox: boolean = false;
- @observable private _showRegenerate: boolean = false;
- @observable private _complexity: number = 5;
- @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 = () => {};
- private _deleteFunc: (doc?: Doc) => void = () => {};
- private _lastInput: DrawingOptions = { text: '', complexity: 5, size: 300, autoColor: true, x: 0, y: 0 };
- private _lastResponse: string = '';
- private _selectedDoc: Doc | undefined = undefined;
-
- constructor(props: any) {
- super(props);
- makeObservable(this);
- SmartDrawHandler.Instance = this;
- }
-
- @action
- setUserInput = (input: string) => {
- this._userInput = input;
- };
-
- @action
- setRegenInput = (input: string) => {
- this._regenInput = input;
- };
-
- @action
- setShowOptions = () => {
- this._showOptions = !this._showOptions;
- };
-
- @action
- setComplexity = (val: number) => {
- this._complexity = val;
- };
-
- @action
- setSize = (val: number) => {
- this._size = val;
- };
-
- @action
- setAutoColor = () => {
- 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) => {
- this._pageX = x;
- this._pageY = y;
- this._display = true;
- this._addFunc = addFunc;
- this._deleteFunc = deleteFunc;
- };
-
- @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) => {
- this._selectedDoc = DocumentView.SelectedDocs().lastElement();
- const docData = this._selectedDoc[DocData];
- this._addFunc = addFunc;
- this._deleteFunc = deleteFunc;
- this._pageX = x;
- this._pageY = y;
- 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 };
- };
-
- @action
- hideSmartDrawHandler = () => {
- this._showRegenerate = false;
- this._display = false;
- this._isLoading = false;
- this._showOptions = false;
- this._userInput = '';
- this._complexity = 5;
- this._size = 300;
- this._autoColor = true;
- // this._regenInput = ''
- };
-
- @action
- hideRegenerate = () => {
- this._showRegenerate = false;
- this._isLoading = false;
- this._regenInput = '';
- };
-
- _errorOccurredOnce = false;
- @action
- drawWithGPT = async (e: React.PointerEvent<Element>, 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._isLoading = true;
- this._showOptions = false;
- try {
- const res = await gptAPICall(`"${input}", "${this._complexity}", "${this._size}"`, GPTCallType.DRAW, undefined, true);
- if (!res) {
- console.error('GPT call failed');
- return;
- }
- console.log(res);
- await this.parseResponse(e, res, { X: e.clientX, Y: e.clientY }, false);
- this.hideSmartDrawHandler();
- this._showRegenerate = true;
- this._errorOccurredOnce = false;
- } catch (err) {
- if (this._errorOccurredOnce) {
- console.error('GPT call failed', err);
- this._errorOccurredOnce = false;
- } else {
- this._errorOccurredOnce = true;
- this.drawWithGPT(e, input);
- }
- }
- this._isLoading = false;
- };
-
- @action
- edit = () => {
- this._showEditBox = !this._showEditBox;
- };
-
- @action
- regenerate = async (e: React.PointerEvent<Element>) => {
- this._isLoading = true;
- 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}`;
- } else {
- res = await gptAPICall(`"${this._lastInput.text}", "${this._lastInput.complexity}", "${this._lastInput.size}"`, GPTCallType.DRAW, undefined, true);
- }
- if (!res) {
- console.error('GPT call failed');
- return;
- }
- console.log(res);
- this.parseResponse(e, res, { X: this._lastInput.x, Y: this._lastInput.y }, true);
- } catch (err) {
- console.error('GPT call failed', err);
- }
- this._isLoading = false;
- this._regenInput = '';
- this._showEditBox = false;
- };
-
- @action
- parseResponse = async (e: React.PointerEvent<Element>, res: string, startPoint: { X: number; Y: number }, regenerate: boolean) => {
- const svg = res.match(/<svg[^>]*>([\s\S]*?)<\/svg>/g);
- 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([
- convertedBezier.map(point => {
- return { X: point.X + startPoint.X - this._size / 1.5, Y: point.Y + startPoint.Y - this._size / 2 };
- }),
- (regenerate ? this._lastInput.autoColor : this._autoColor) ? child.attributes.stroke : undefined,
- (regenerate ? this._lastInput.autoColor : this._autoColor) ? child.attributes.fill : undefined,
- ]);
- });
- if (regenerate) {
- this._deleteFunc(this._selectedDoc);
- this._addFunc(e, strokeData, this._lastInput, svg[0], this._selectedDoc);
- } else {
- this._addFunc(e, strokeData, this._lastInput, svg[0]);
- }
- }
- };
-
- render() {
- if (this._display) {
- return (
- <div
- id="label-handler"
- className="contextMenu-cont"
- style={{
- display: this._display ? '' : 'none',
- left: this._pageX,
- ...(this._yRelativeToTop ? { top: Math.max(0, this._pageY) } : { bottom: this._pageY }),
- background: SettingsManager.userBackgroundColor,
- color: SettingsManager.userColor,
- }}>
- <div>
- <IconButton
- tooltip={'Cancel'}
- onClick={() => {
- this.hideSmartDrawHandler();
- this.hideRegenerate();
- }}
- icon={<FontAwesomeIcon icon="xmark" />}
- color={SettingsManager.userColor}
- style={{ width: '19px' }}
- />
- <input
- aria-label="label-input"
- id="new-label"
- type="text"
- style={{ color: 'black' }}
- value={this._userInput}
- onChange={e => {
- this.setUserInput(e.target.value);
- }}
- placeholder="Enter item to draw"
- />
- <Button
- style={{ alignSelf: 'flex-end' }}
- text="Send"
- icon={this._isLoading ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <AiOutlineSend />}
- iconPlacement="right"
- color={SettingsManager.userColor}
- onClick={e => {
- this.drawWithGPT(e as React.PointerEvent<Element>, this._userInput);
- }}
- />
- </div>
- {this._showOptions && (
- <>
- <div style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-around' }}>
- <div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', width: '30%' }}>
- Auto color
- <Switch
- sx={{
- '& .MuiSwitch-switchBase.Mui-checked': {
- color: SettingsManager.userColor,
- },
- '& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track': {
- backgroundColor: SettingsManager.userVariantColor,
- },
- }}
- defaultChecked={true}
- size="small"
- onChange={this.setAutoColor}
- />
- </div>
- <div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', width: '31%' }}>
- Complexity
- <Slider
- sx={{
- '& .MuiSlider-thumb': {
- color: SettingsManager.userColor,
- '&.Mui-focusVisible, &:hover, &.Mui-active': {
- boxShadow: `0px 0px 0px 8px${SettingsManager.userColor.slice(0, 7)}10`,
- },
- },
- '& .MuiSlider-track': {
- color: SettingsManager.userVariantColor,
- },
- '& .MuiSlider-rail': {
- color: SettingsManager.userColor,
- },
- }}
- style={{ width: '80%' }}
- min={1}
- max={10}
- step={1}
- size="small"
- value={this._complexity}
- onChange={(e, val) => {
- this.setComplexity(val as number);
- }}
- valueLabelDisplay="auto"
- />
- </div>
- <div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center', width: '39%' }}>
- Size (in pixels)
- <Slider
- sx={{
- '& .MuiSlider-thumb': {
- color: SettingsManager.userColor,
- '&.Mui-focusVisible, &:hover, &.Mui-active': {
- boxShadow: `0px 0px 0px 8px${SettingsManager.userColor.slice(0, 7)}20`,
- },
- },
- '& .MuiSlider-track': {
- color: SettingsManager.userVariantColor,
- },
- '& .MuiSlider-rail': {
- color: SettingsManager.userColor,
- },
- }}
- style={{ width: '80%' }}
- min={50}
- max={700}
- step={10}
- size="small"
- value={this._size}
- onChange={(e, val) => {
- this.setSize(val as number);
- }}
- valueLabelDisplay="auto"
- />
- </div>
- </div>
- </>
- )}
- </div>
- );
- } else if (this._showRegenerate) {
- return (
- <div
- id="smartdraw-options-menu"
- className="contextMenu-cont"
- style={{
- left: this._pageX,
- ...(this._yRelativeToTop ? { top: Math.max(0, this._pageY) } : { bottom: this._pageY }),
- background: SettingsManager.userBackgroundColor,
- color: SettingsManager.userColor,
- }}>
- <div
- style={{
- display: 'flex',
- flexDirection: 'row',
- }}>
- <IconButton
- 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>);
- }}
- />
- <IconButton tooltip="Edit with GPT" icon={<FontAwesomeIcon icon="pen-to-square" />} color={SettingsManager.userColor} onClick={this.edit} />
- {this._showEditBox && (
- <div
- style={{
- display: 'flex',
- flexDirection: 'row',
- }}>
- <input
- aria-label="Edit instructions input"
- id="regen-input"
- type="text"
- style={{ color: 'black' }}
- value={this._regenInput}
- onChange={e => {
- this.setRegenInput(e.target.value);
- }}
- placeholder="Edit instructions"
- />
- <Button
- style={{ alignSelf: 'flex-end' }}
- text="Send"
- 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>);
- }}
- />
- </div>
- )}
- </div>
- </div>
- );
- } else {
- return <></>;
- }
- }
-}