From ed5a7755eba7563c01bc3cc40840d0ebb6cd8826 Mon Sep 17 00:00:00 2001 From: Zachary Zhang Date: Wed, 6 Mar 2024 19:46:09 -0500 Subject: add diagram document --- src/client/views/nodes/DiagramBox.tsx | 86 +++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 src/client/views/nodes/DiagramBox.tsx (limited to 'src/client/views/nodes/DiagramBox.tsx') diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx new file mode 100644 index 000000000..e2af0b670 --- /dev/null +++ b/src/client/views/nodes/DiagramBox.tsx @@ -0,0 +1,86 @@ +import { action, computed, makeObservable, observable } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { emptyFunction, setupMoveUpEvents } from '../../../Utils'; +import { Doc, Opt } from '../../../fields/Doc'; +import { DocCast, NumCast, StrCast } from '../../../fields/Types'; +import { Docs } from '../../documents/Documents'; +import { DragManager } from '../../util/DragManager'; +import { undoBatch } from '../../util/UndoManager'; +import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; +import { StyleProp } from '../StyleProvider'; +import './ComparisonBox.scss'; +import { FieldView, FieldViewProps } from './FieldView'; +import { PinProps, PresBox } from './trails'; +import mermaid from 'mermaid'; + +interface MermaidProps { + chart: String; + } + +class Mermaid extends React.Component { + componentDidMount() { + mermaid.contentLoaded(); + } + render() { + return
{this.props.chart}
; + } + } + +@observer +export class DiagramBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { + + public static LayoutString(fieldKey: string) { + return FieldView.LayoutString(DiagramBox, fieldKey); + } + constructor(props: FieldViewProps) { + super(props); + makeObservable(this); + mermaid.initialize({ startOnLoad: true }); + } + + @observable _animating = ''; + + @computed get clipWidth() { + return NumCast(this.layoutDoc[this.clipWidthKey], 50); + } + get clipWidthKey() { + return '_' + this._props.fieldKey + '_clipWidth'; + } + + componentDidMount() { + this._props.setContentViewBox?.(this); + } + getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { + const anchor = Docs.Create.ConfigDocument({ + title: 'CompareAnchor:' + this.Document.title, + // set presentation timing properties for restoring view + presentation_transition: 1000, + annotationOn: this.Document, + }); + if (anchor) { + if (!addAsAnnotation) anchor.backgroundColor = 'transparent'; + /* addAsAnnotation &&*/ this.addDocument(anchor); + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), clippable: true } }, this.Document); + return anchor; + } + return this.Document; + }; + docStyleProvider = (doc: Opt, props: Opt, property: string): any => { + if (property === StyleProp.PointerEvents) return 'none'; + return this._props.styleProvider?.(doc, props, property); + }; + _closeRef = React.createRef(); + render() { + return ( +
+ B; + B-->C; + B-->D[hi]; + `}/> +
+ ); + } +} -- cgit v1.2.3-70-g09d2 From ec89fe170a810c0a83b9347ec9f024e0ff9c2568 Mon Sep 17 00:00:00 2001 From: Zachary Zhang Date: Sun, 10 Mar 2024 13:10:43 -0400 Subject: test --- src/client/documents/Documents.ts | 1 + src/client/util/CurrentUserUtils.ts | 5 +- src/client/views/nodes/DiagramBox.tsx | 88 ++++++++++++++++------------------- 3 files changed, 45 insertions(+), 49 deletions(-) (limited to 'src/client/views/nodes/DiagramBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index ade5e718c..a6e229ba7 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -252,6 +252,7 @@ export class DocumentOptions { layout_hideLinkButton?: BOOLt = new BoolInfo('whether the blue link counter button should be hidden'); layout_hideDecorationTitle?: BOOLt = new BoolInfo('whether to suppress the document decortations title when selected'); _layout_hideContextMenu?: BOOLt = new BoolInfo('whether the context menu can be shown'); + layout_diagramEditor?: STRt = new StrInfo("specify the JSX string for a diagram editor view") layout_borderRounding?: string; _layout_modificationDate?: DATEt = new DateInfo('last modification date of doc layout', false); _layout_nativeDimEditable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers', false); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 8275ec6b8..0279ca2c4 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -31,6 +31,7 @@ import { ScriptingGlobals } from "./ScriptingGlobals"; import { ColorScheme } from "./SettingsManager"; import { SnappingManager } from "./SnappingManager"; import { UndoManager } from "./UndoManager"; +import { CollectionView } from "../views/collections/CollectionView"; interface Button { // DocumentOptions fields a button can set @@ -248,7 +249,7 @@ export class CurrentUserUtils { {key: "Collection", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 150, _height: 100, _layout_fitWidth: true }}, {key: "Webpage", creator: opts => Docs.Create.WebDocument("",opts), opts: { _width: 400, _height: 512, _nativeWidth: 850, data_useCors: true, }}, {key: "Comparison", creator: Docs.Create.ComparisonDocument, opts: { _width: 300, _height: 300 }}, - {key: "Diagram", creator: Docs.Create.DiagramDocument, opts: { _width: 300, _height: 300 }}, + {key: "Diagram", creator: Docs.Create.DiagramDocument, opts: { _width: 300, _height: 300, _type_collection: CollectionViewType.Freeform, layout_diagramEditor: CollectionView.LayoutString("data") }, scripts: { onPaint: `toggleDetail(documentView, "diagramEditor","")`}}, {key: "Audio", creator: opts => Docs.Create.AudioDocument(nullAudio, opts),opts: { _width: 200, _height: 100, }}, {key: "Map", creator: opts => Docs.Create.MapDocument([], opts), opts: { _width: 800, _height: 600, _layout_fitWidth: true, }}, {key: "Screengrab", creator: Docs.Create.ScreenshotDocument, opts: { _width: 400, _height: 200 }}, @@ -281,7 +282,7 @@ export class CurrentUserUtils { { toolTip: "Tap or drag to create a collection", title: "Col", icon: "folder", dragFactory: doc.emptyCollection as Doc, clickFactory: DocCast(doc.emptyTab)}, { toolTip: "Tap or drag to create a webpage", title: "Web", icon: "globe-asia", dragFactory: doc.emptyWebpage as Doc, clickFactory: DocCast(doc.emptyWebpage)}, { toolTip: "Tap or drag to create a comparison box", title: "Compare", icon: "columns", dragFactory: doc.emptyComparison as Doc, clickFactory: DocCast(doc.emptyComparison)}, - { toolTip: "Tap or drag to create a diagram", title: "Diagram", icon: "circle", dragFactory: doc.emptyDiagram as Doc, clickFactory: DocCast(doc.emptyDiagram)}, + { toolTip: "Tap or drag to create a diagram", title: "Diagram", icon: "tree", dragFactory: doc.emptyDiagram as Doc, clickFactory: DocCast(doc.emptyDiagram)}, { toolTip: "Tap or drag to create an audio recorder", title: "Audio", icon: "microphone", dragFactory: doc.emptyAudio as Doc, clickFactory: DocCast(doc.emptyAudio), openFactoryLocation: OpenWhere.overlay}, { toolTip: "Tap or drag to create a map", title: "Map", icon: "map-marker-alt", dragFactory: doc.emptyMap as Doc, clickFactory: DocCast(doc.emptyMap)}, { toolTip: "Tap or drag to create a screen grabber", title: "Grab", icon: "photo-video", dragFactory: doc.emptyScreengrab as Doc, clickFactory: DocCast(doc.emptyScreengrab), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}}, diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx index e2af0b670..376dff15d 100644 --- a/src/client/views/nodes/DiagramBox.tsx +++ b/src/client/views/nodes/DiagramBox.tsx @@ -1,85 +1,79 @@ -import { action, computed, makeObservable, observable } from 'mobx'; +import { makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { emptyFunction, setupMoveUpEvents } from '../../../Utils'; -import { Doc, Opt } from '../../../fields/Doc'; -import { DocCast, NumCast, StrCast } from '../../../fields/Types'; -import { Docs } from '../../documents/Documents'; -import { DragManager } from '../../util/DragManager'; -import { undoBatch } from '../../util/UndoManager'; import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import './ComparisonBox.scss'; import { FieldView, FieldViewProps } from './FieldView'; import { PinProps, PresBox } from './trails'; import mermaid from 'mermaid'; +import { Doc, DocListCast } from '../../../fields/Doc'; +import { List } from '../../../fields/List'; interface MermaidProps { - chart: String; - } + chart: String; +} class Mermaid extends React.Component { componentDidMount() { - mermaid.contentLoaded(); + mermaid.contentLoaded(); } render() { - return
{this.props.chart}
; + return
{this.props.chart}
; } - } +} @observer export class DiagramBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { - + @observable chartContent: string = ''; + public static LayoutString(fieldKey: string) { return FieldView.LayoutString(DiagramBox, fieldKey); } constructor(props: FieldViewProps) { super(props); makeObservable(this); - mermaid.initialize({ startOnLoad: true }); + //this.createMermaidCode(); + this.chartContent = 'graph LR;A-->B;B-->C; B-->D[hello];'; } - @observable _animating = ''; - - @computed get clipWidth() { - return NumCast(this.layoutDoc[this.clipWidthKey], 50); - } - get clipWidthKey() { - return '_' + this._props.fieldKey + '_clipWidth'; - } - componentDidMount() { this._props.setContentViewBox?.(this); + mermaid.initialize({ startOnLoad: true }); } - getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { - const anchor = Docs.Create.ConfigDocument({ - title: 'CompareAnchor:' + this.Document.title, - // set presentation timing properties for restoring view - presentation_transition: 1000, - annotationOn: this.Document, - }); - if (anchor) { - if (!addAsAnnotation) anchor.backgroundColor = 'transparent'; - /* addAsAnnotation &&*/ this.addDocument(anchor); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), clippable: true } }, this.Document); - return anchor; + createMermaidCode = (): void => { + if (this.Document.data instanceof List) { + let docArray: Doc[] = DocListCast(this.Document.data); + let mermaidCode = 'graph LR;'; + docArray.map(doc => { + if (doc.title == 'rectangle') { + DocListCast(this.Document.data).map(lineDoc => { + if ((lineDoc.title == 'stroke' || lineDoc.title == 'line') && typeof lineDoc.x === 'number' && typeof doc.x === 'number' && typeof doc.width === 'number'&& typeof doc.height === 'number'&& typeof doc.y === 'number'&& typeof lineDoc.y === 'number') { + if (lineDoc.x < doc.x + doc.width + (doc.width + doc.x) * 0.1 && lineDoc.x > doc.x&&lineDoc.y>doc.y&&lineDoc.y { + if (doc2.title == 'rectangle' && typeof lineDoc.x === 'number' && typeof lineDoc.width === 'number' && typeof doc2.x === 'number' && typeof doc2.width === 'number'&& typeof doc2.y === 'number'&& typeof doc2.height === 'number'&& typeof lineDoc.y === 'number') { + if (lineDoc.x + lineDoc.width > doc2.x - (doc2.x - doc2.width) * 0.1 && lineDoc.x + lineDoc.width < doc2.x + doc2.width &&lineDoc.y>doc2.y&&lineDoc.y' + doc2.title + Math.floor(doc2.x).toString() + ';'; + const indexToRemove = docArray.findIndex(doc => doc === lineDoc); + if (indexToRemove !== -1) { + docArray.splice(indexToRemove, 1); + } + } + } + }); + } + } + }); + } + this.chartContent = mermaidCode; + }); } - return this.Document; - }; - docStyleProvider = (doc: Opt, props: Opt, property: string): any => { - if (property === StyleProp.PointerEvents) return 'none'; - return this._props.styleProvider?.(doc, props, property); }; - _closeRef = React.createRef(); render() { + console.log(this.chartContent) return (
- B; - B-->C; - B-->D[hi]; - `}/> +
); } -- cgit v1.2.3-70-g09d2 From 84e75f944a45c3b98ec70c75d2abc47051b10b03 Mon Sep 17 00:00:00 2001 From: Zachary Zhang Date: Tue, 12 Mar 2024 16:28:39 -0400 Subject: test --- src/client/views/nodes/DiagramBox.tsx | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) (limited to 'src/client/views/nodes/DiagramBox.tsx') diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx index 376dff15d..9ff2d27d2 100644 --- a/src/client/views/nodes/DiagramBox.tsx +++ b/src/client/views/nodes/DiagramBox.tsx @@ -48,11 +48,35 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im docArray.map(doc => { if (doc.title == 'rectangle') { DocListCast(this.Document.data).map(lineDoc => { - if ((lineDoc.title == 'stroke' || lineDoc.title == 'line') && typeof lineDoc.x === 'number' && typeof doc.x === 'number' && typeof doc.width === 'number'&& typeof doc.height === 'number'&& typeof doc.y === 'number'&& typeof lineDoc.y === 'number') { - if (lineDoc.x < doc.x + doc.width + (doc.width + doc.x) * 0.1 && lineDoc.x > doc.x&&lineDoc.y>doc.y&&lineDoc.y doc.x && lineDoc.y > doc.y && lineDoc.y < doc.y + doc.height) { DocListCast(this.Document.data).map(doc2 => { - if (doc2.title == 'rectangle' && typeof lineDoc.x === 'number' && typeof lineDoc.width === 'number' && typeof doc2.x === 'number' && typeof doc2.width === 'number'&& typeof doc2.y === 'number'&& typeof doc2.height === 'number'&& typeof lineDoc.y === 'number') { - if (lineDoc.x + lineDoc.width > doc2.x - (doc2.x - doc2.width) * 0.1 && lineDoc.x + lineDoc.width < doc2.x + doc2.width &&lineDoc.y>doc2.y&&lineDoc.y doc2.x - (doc2.x - doc2.width) * 0.1 && + lineDoc.x + lineDoc.width < doc2.x + doc2.width && + lineDoc.y > doc2.y && + lineDoc.y < doc2.y + doc2.height && + typeof doc.x === 'number' && + typeof doc.width === 'number' + ) { mermaidCode += doc.title + Math.floor(doc.x).toString() + '-->' + doc2.title + Math.floor(doc2.x).toString() + ';'; const indexToRemove = docArray.findIndex(doc => doc === lineDoc); if (indexToRemove !== -1) { @@ -70,7 +94,7 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im } }; render() { - console.log(this.chartContent) + console.log(this.ScreenToLocalBoxXf().scale(2)); return (
-- cgit v1.2.3-70-g09d2 From 2ca4e70cd030fb9199d149060adf1b1d7c07857c Mon Sep 17 00:00:00 2001 From: Zachary Zhang Date: Tue, 12 Mar 2024 16:40:40 -0400 Subject: fix --- src/client/documents/Documents.ts | 1 + src/client/util/CurrentUserUtils.ts | 2 ++ src/client/views/nodes/DiagramBox.scss | 3 +++ src/client/views/nodes/DiagramBox.tsx | 2 +- 4 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 src/client/views/nodes/DiagramBox.scss (limited to 'src/client/views/nodes/DiagramBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 2f177b62a..96f4e4597 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -276,6 +276,7 @@ export class DocumentOptions { layout_hideDecorationTitle?: BOOLt = new BoolInfo('whether to suppress the document decortations title when selected'); _layout_hideContextMenu?: BOOLt = new BoolInfo('whether the context menu can be shown'); layout_diagramEditor?: STRt = new StrInfo("specify the JSX string for a diagram editor view") + layout_hideContextMenu?: BOOLt = new BoolInfo('whether the context menu can be shown'); layout_borderRounding?: string; _layout_modificationDate?: DATEt = new DateInfo('last modification date of doc layout', false); _layout_nativeDimEditable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers', false); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index a41fd8796..18b37ffd1 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -33,6 +33,8 @@ import { ColorScheme } from "./SettingsManager"; import { SnappingManager } from "./SnappingManager"; import { UndoManager } from "./UndoManager"; import { CollectionView } from "../views/collections/CollectionView"; +import { LabelBox } from "../views/nodes/LabelBox"; +import { ImageBox } from "../views/nodes/ImageBox"; interface Button { // DocumentOptions fields a button can set diff --git a/src/client/views/nodes/DiagramBox.scss b/src/client/views/nodes/DiagramBox.scss new file mode 100644 index 000000000..50d9a6573 --- /dev/null +++ b/src/client/views/nodes/DiagramBox.scss @@ -0,0 +1,3 @@ +.mermaid{ + width:100%; +} \ No newline at end of file diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx index 9ff2d27d2..e162360f8 100644 --- a/src/client/views/nodes/DiagramBox.tsx +++ b/src/client/views/nodes/DiagramBox.tsx @@ -3,7 +3,7 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; -import './ComparisonBox.scss'; +import './DiagramBox.scss'; import { FieldView, FieldViewProps } from './FieldView'; import { PinProps, PresBox } from './trails'; import mermaid from 'mermaid'; -- cgit v1.2.3-70-g09d2 From 868668efbdbfaa50c0203d133cd2401e65ec5281 Mon Sep 17 00:00:00 2001 From: Zachary Zhang Date: Sun, 17 Mar 2024 12:50:32 -0400 Subject: fix bug with mermaid diagram changing scale on zoom --- package-lock.json | 3 ++- src/client/views/nodes/DiagramBox.scss | 12 ++++++++--- src/client/views/nodes/DiagramBox.tsx | 39 ++++++++++++++++++++++++++++------ 3 files changed, 44 insertions(+), 10 deletions(-) (limited to 'src/client/views/nodes/DiagramBox.tsx') diff --git a/package-lock.json b/package-lock.json index 7b86365c2..253356c07 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32257,7 +32257,8 @@ "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true }, "node_modules/textarea-caret": { "version": "3.1.0", diff --git a/src/client/views/nodes/DiagramBox.scss b/src/client/views/nodes/DiagramBox.scss index 50d9a6573..9ceac15df 100644 --- a/src/client/views/nodes/DiagramBox.scss +++ b/src/client/views/nodes/DiagramBox.scss @@ -1,3 +1,9 @@ -.mermaid{ - width:100%; -} \ No newline at end of file +.mermaid { + svg { + g { + g{ + + } + } + } +} diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx index e162360f8..a2fb7e2c8 100644 --- a/src/client/views/nodes/DiagramBox.tsx +++ b/src/client/views/nodes/DiagramBox.tsx @@ -34,12 +34,41 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im super(props); makeObservable(this); //this.createMermaidCode(); - this.chartContent = 'graph LR;A-->B;B-->C; B-->D[hello];'; + this.chartContent = 'flowchart LR;A-->B:::wide;B-->C:::wide; B-->D[hello];'; } componentDidMount() { this._props.setContentViewBox?.(this); - mermaid.initialize({ startOnLoad: true }); + // (window as any)["callb"] = (x: any) => { + // alert(x); + // }; + mermaid.initialize({ + securityLevel: "loose", + startOnLoad: true, + flowchart: { useMaxWidth: true, htmlLabels: true, curve: 'cardinal' }, + }); + + const renderMermaid = async (str: string) => { + try { + const { svg, bindFunctions } = await mermaid2(str); + return { svg, bindFunctions }; + } catch (error) { + console.error("Error rendering mermaid diagram:", error); + return { svg: "", bindFunctions: undefined }; + } + }; + const mermaid2 = async (str: string) => { + return await mermaid.render("graph" + Date.now(), str); + }; + renderMermaid(this.chartContent).then(({ svg, bindFunctions }) => { + const dashDiv = document.getElementById('dashDiv'); + if (dashDiv) { + dashDiv.innerHTML = svg; + if (bindFunctions) { + bindFunctions(dashDiv); + } + } + }); } createMermaidCode = (): void => { if (this.Document.data instanceof List) { @@ -94,11 +123,9 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im } }; render() { - console.log(this.ScreenToLocalBoxXf().scale(2)); + console.log(this.ScreenToLocalBoxXf().Scale); return ( -
- -
+
); } } -- cgit v1.2.3-70-g09d2 From dc0ee4595e37042db3adf60b002d7baf77cb24ae Mon Sep 17 00:00:00 2001 From: Zachary Zhang Date: Tue, 2 Apr 2024 16:34:11 -0400 Subject: test --- src/client/views/nodes/DiagramBox.scss | 9 -- src/client/views/nodes/DiagramBox.tsx | 152 ++++++++++++++++++--------------- 2 files changed, 83 insertions(+), 78 deletions(-) (limited to 'src/client/views/nodes/DiagramBox.tsx') diff --git a/src/client/views/nodes/DiagramBox.scss b/src/client/views/nodes/DiagramBox.scss index 9ceac15df..e69de29bb 100644 --- a/src/client/views/nodes/DiagramBox.scss +++ b/src/client/views/nodes/DiagramBox.scss @@ -1,9 +0,0 @@ -.mermaid { - svg { - g { - g{ - - } - } - } -} diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx index a2fb7e2c8..3b9e9d952 100644 --- a/src/client/views/nodes/DiagramBox.tsx +++ b/src/client/views/nodes/DiagramBox.tsx @@ -9,23 +9,10 @@ import { PinProps, PresBox } from './trails'; import mermaid from 'mermaid'; import { Doc, DocListCast } from '../../../fields/Doc'; import { List } from '../../../fields/List'; - -interface MermaidProps { - chart: String; -} - -class Mermaid extends React.Component { - componentDidMount() { - mermaid.contentLoaded(); - } - render() { - return
{this.props.chart}
; - } -} +import { RichTextField } from '../../../fields/RichTextField'; @observer export class DiagramBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { - @observable chartContent: string = ''; public static LayoutString(fieldKey: string) { return FieldView.LayoutString(DiagramBox, fieldKey); @@ -33,15 +20,11 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im constructor(props: FieldViewProps) { super(props); makeObservable(this); - //this.createMermaidCode(); - this.chartContent = 'flowchart LR;A-->B:::wide;B-->C:::wide; B-->D[hello];'; + //this.chartContent = 'flowchart LR;A-->B:::wide;B-->C:::wide; B-->D[hello];'; } componentDidMount() { this._props.setContentViewBox?.(this); - // (window as any)["callb"] = (x: any) => { - // alert(x); - // }; mermaid.initialize({ securityLevel: "loose", startOnLoad: true, @@ -50,17 +33,17 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im const renderMermaid = async (str: string) => { try { - const { svg, bindFunctions } = await mermaid2(str); + const { svg, bindFunctions } = await mermaidDiagram(str); return { svg, bindFunctions }; } catch (error) { console.error("Error rendering mermaid diagram:", error); return { svg: "", bindFunctions: undefined }; } }; - const mermaid2 = async (str: string) => { + const mermaidDiagram = async (str: string) => { return await mermaid.render("graph" + Date.now(), str); }; - renderMermaid(this.chartContent).then(({ svg, bindFunctions }) => { + renderMermaid(this.createMermaidCode()).then(({ svg, bindFunctions }) => { const dashDiv = document.getElementById('dashDiv'); if (dashDiv) { dashDiv.innerHTML = svg; @@ -70,62 +53,93 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im } }); } - createMermaidCode = (): void => { + createMermaidCode = (): string => { + let mermaidCode = 'graph LR;'; if (this.Document.data instanceof List) { let docArray: Doc[] = DocListCast(this.Document.data); - let mermaidCode = 'graph LR;'; - docArray.map(doc => { - if (doc.title == 'rectangle') { - DocListCast(this.Document.data).map(lineDoc => { - if ( - (lineDoc.title == 'stroke' || lineDoc.title == 'line') && - typeof lineDoc.x === 'number' && - typeof doc.x === 'number' && - typeof doc.width === 'number' && - typeof doc.height === 'number' && - typeof doc.y === 'number' && - typeof lineDoc.y === 'number' - ) { - if (lineDoc.x < doc.x + doc.width + (doc.width + doc.x) * 0.1 && lineDoc.x > doc.x && lineDoc.y > doc.y && lineDoc.y < doc.y + doc.height) { - DocListCast(this.Document.data).map(doc2 => { - if ( - doc2.title == 'rectangle' && - typeof lineDoc.x === 'number' && - typeof lineDoc.width === 'number' && - typeof doc2.x === 'number' && - typeof doc2.width === 'number' && - typeof doc2.y === 'number' && - typeof doc2.height === 'number' && - typeof lineDoc.y === 'number' - ) { - if ( - lineDoc.x + lineDoc.width > doc2.x - (doc2.x - doc2.width) * 0.1 && - lineDoc.x + lineDoc.width < doc2.x + doc2.width && - lineDoc.y > doc2.y && - lineDoc.y < doc2.y + doc2.height && - typeof doc.x === 'number' && - typeof doc.width === 'number' - ) { - mermaidCode += doc.title + Math.floor(doc.x).toString() + '-->' + doc2.title + Math.floor(doc2.x).toString() + ';'; - const indexToRemove = docArray.findIndex(doc => doc === lineDoc); - if (indexToRemove !== -1) { - docArray.splice(indexToRemove, 1); - } - } - } - }); + let rectangleArray = docArray.filter(doc => doc.title == 'rectangle'||doc.title=='circle'); + let lineArray = docArray.filter(doc => doc.title == 'line' || doc.title == 'stroke'); + let textArray=docArray.filter(doc=>doc.type=='rich text') + for (let i = 0; i < rectangleArray.length; i++) { + const rectangle = rectangleArray[i]; + for (let j = 0; j < lineArray.length; j++) { + const line = lineArray[j]; + if(this.isLineInFirstBox(rectangle,line)){ + for (let k = 0; k < rectangleArray.length; k++) { + const rectangle2 = rectangleArray[k]; + if (this.isLineInSecondBox(rectangle2, line)&& + typeof rectangle.x === 'number' && + typeof rectangle2.x === 'number') { + mermaidCode += Math.abs(rectangle.x) +this.getTextInBox(rectangle,textArray) + '---' + Math.abs(rectangle2.x)+ this.getTextInBox(rectangle2,textArray)+ ';'; } } - }); + } } - this.chartContent = mermaidCode; - }); + } } - }; + console.log(mermaidCode); + return mermaidCode; + } + getTextInBox=(box: Doc,richTextArray: Doc[]):string=>{ + for(let i=0;ibox.x&&textDoc.xbox.y&&textDoc.y{ + if( + typeof line.x === 'number' && + typeof box.x === 'number' && + typeof box.width === 'number' && + typeof box.height === 'number' && + typeof box.y === 'number' && + typeof line.y === 'number') { + return line.x < box.x + box.width + (box.width + box.x) * 0.1 && + line.x > box.x && + line.y > box.y && + line.y < box.y + box.height + } + else{ + return false; + } + } + isLineInSecondBox=(box:Doc,line:Doc):boolean=>{ + if ( + typeof line.x === 'number' && + typeof line.width === 'number' && + typeof box.x === 'number' && + typeof box.width === 'number' && + typeof box.y === 'number' && + typeof box.height === 'number' && + typeof line.y === 'number') { + return line.x + line.width > box.x - (box.x - box.width) * 0.1 && + line.x + line.width < box.x + box.width && + line.y > box.y && + line.y < box.y + box.height; + } + else{ + return false; + } + } render() { - console.log(this.ScreenToLocalBoxXf().Scale); return (
); } } + -- cgit v1.2.3-70-g09d2 From 1809abeb1cb837ef9d43d19b7cf286b33ad8789d Mon Sep 17 00:00:00 2001 From: Zachary Zhang Date: Thu, 4 Apr 2024 13:47:40 -0400 Subject: add ai mermaids --- src/client/apis/gpt/GPT.ts | 6 +- src/client/views/nodes/DiagramBox.tsx | 207 ++++++++++++++++++++-------------- 2 files changed, 128 insertions(+), 85 deletions(-) (limited to 'src/client/views/nodes/DiagramBox.tsx') diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts index fb51278ae..49c56f04e 100644 --- a/src/client/apis/gpt/GPT.ts +++ b/src/client/apis/gpt/GPT.ts @@ -4,6 +4,7 @@ enum GPTCallType { SUMMARY = 'summary', COMPLETION = 'completion', EDIT = 'edit', + MERMAID='mermaid' } type GPTCallOpts = { @@ -17,8 +18,10 @@ const callTypeMap: { [type: string]: GPTCallOpts } = { summary: { model: 'gpt-3.5-turbo-instruct', maxTokens: 256, temp: 0.5, prompt: 'Summarize this text in simpler terms: ' }, edit: { model: 'gpt-3.5-turbo-instruct', maxTokens: 256, temp: 0.5, prompt: 'Reword this: ' }, completion: { model: 'gpt-3.5-turbo-instruct', maxTokens: 256, temp: 0.5, prompt: '' }, + mermaid:{model:'gpt-3.5-turbo-instruct',maxTokens:256,temp:0,prompt:"Write this in mermaid code (keep in note thatPut this at the end of the code to add colors heres an example and be very care about the order:pie title Example Pie Chart \"Red\" : 25 \"Blue\" : 75%%{init: {'theme': 'base', 'themeVariables': { 'pie1': '#0000FF', 'pie2': '#FF0000'}}}%%): "} }; + /** * Calls the OpenAI API. * @@ -30,7 +33,7 @@ const gptAPICall = async (inputText: string, callType: GPTCallType) => { const opts: GPTCallOpts = callTypeMap[callType]; try { const configuration: ClientOptions = { - apiKey: process.env.OPENAI_KEY, + apiKey: "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", dangerouslyAllowBrowser: true, }; const openai = new OpenAI(configuration); @@ -39,6 +42,7 @@ const gptAPICall = async (inputText: string, callType: GPTCallType) => { max_tokens: opts.maxTokens, temperature: opts.temp, prompt: `${opts.prompt}${inputText}`, + }); return response.choices[0].text; } catch (err) { diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx index 3b9e9d952..64d0d6d78 100644 --- a/src/client/views/nodes/DiagramBox.tsx +++ b/src/client/views/nodes/DiagramBox.tsx @@ -1,4 +1,4 @@ -import { makeObservable, observable } from 'mobx'; +import { makeObservable, observable, action } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; @@ -10,10 +10,11 @@ import mermaid from 'mermaid'; import { Doc, DocListCast } from '../../../fields/Doc'; import { List } from '../../../fields/List'; import { RichTextField } from '../../../fields/RichTextField'; +import { ContextMenu } from '../ContextMenu'; +import { gptAPICall, GPTCallType } from '../../apis/gpt/GPT'; @observer export class DiagramBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { - public static LayoutString(fieldKey: string) { return FieldView.LayoutString(DiagramBox, fieldKey); } @@ -26,7 +27,7 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im componentDidMount() { this._props.setContentViewBox?.(this); mermaid.initialize({ - securityLevel: "loose", + securityLevel: 'loose', startOnLoad: true, flowchart: { useMaxWidth: true, htmlLabels: true, curve: 'cardinal' }, }); @@ -36,110 +37,148 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im const { svg, bindFunctions } = await mermaidDiagram(str); return { svg, bindFunctions }; } catch (error) { - console.error("Error rendering mermaid diagram:", error); - return { svg: "", bindFunctions: undefined }; + console.error('Error rendering mermaid diagram:', error); + return { svg: '', bindFunctions: undefined }; } }; const mermaidDiagram = async (str: string) => { - return await mermaid.render("graph" + Date.now(), str); + return await mermaid.render('graph' + Date.now(), str); }; - renderMermaid(this.createMermaidCode()).then(({ svg, bindFunctions }) => { - const dashDiv = document.getElementById('dashDiv'); - if (dashDiv) { - dashDiv.innerHTML = svg; - if (bindFunctions) { - bindFunctions(dashDiv); + async function renderMermaidAsync(this: DiagramBox) { + try { + const mermaidCode: string = await this.createMermaidCode(); + const { svg, bindFunctions } = await renderMermaid(mermaidCode); + const dashDiv = document.getElementById('dashDiv'); + if (dashDiv) { + dashDiv.innerHTML = svg; + if (bindFunctions) { + bindFunctions(dashDiv); + } } + } catch (error) { + console.error('Error rendering Mermaid:', error); } - }); + } + + renderMermaidAsync.call(this); } - createMermaidCode = (): string => { - let mermaidCode = 'graph LR;'; - if (this.Document.data instanceof List) { - let docArray: Doc[] = DocListCast(this.Document.data); - let rectangleArray = docArray.filter(doc => doc.title == 'rectangle'||doc.title=='circle'); - let lineArray = docArray.filter(doc => doc.title == 'line' || doc.title == 'stroke'); - let textArray=docArray.filter(doc=>doc.type=='rich text') - for (let i = 0; i < rectangleArray.length; i++) { - const rectangle = rectangleArray[i]; - for (let j = 0; j < lineArray.length; j++) { - const line = lineArray[j]; - if(this.isLineInFirstBox(rectangle,line)){ - for (let k = 0; k < rectangleArray.length; k++) { - const rectangle2 = rectangleArray[k]; - if (this.isLineInSecondBox(rectangle2, line)&& - typeof rectangle.x === 'number' && - typeof rectangle2.x === 'number') { - mermaidCode += Math.abs(rectangle.x) +this.getTextInBox(rectangle,textArray) + '---' + Math.abs(rectangle2.x)+ this.getTextInBox(rectangle2,textArray)+ ';'; + + askGPT = async (): Promise => { + try { + let notes = 'mermaid syntax for pie charts do not include %'; + let text = notes + (DocListCast(this.Document.data)[0].text as RichTextField)?.Text; + if (!text) { + console.error('Text extraction failed'); + return; + } + + let res = await gptAPICall(text, GPTCallType.MERMAID); + if (!res) { + console.error('GPT call failed'); + return; + } else { + console.log(res) + return this.removeWords(res); + } + } catch (err) { + console.error('Error:', err); + return; + } + }; + + removeWords(inputStr:string) { + let presetArray=["pie","flowchart","diagramChart","graph TD","flowchart TD","flowchart LR","graph LR"] + const lines = inputStr.split('\n'); + let foundPresetWord = false; + let result = ''; + + for (const line of lines) { + if (!foundPresetWord) { + for (const word of presetArray) { + if (line.toLowerCase().includes(word.toLowerCase())) { + foundPresetWord = true; + result += line + '\n'; + break; + } + } + } else { + result += line + '\n'; + } + } + + return result; + } + + createMermaidCode = async (): Promise => { + let mermaidCode = ''; + let docArray: Doc[] = DocListCast(this.Document.data); + if (docArray.length === 1) { + if (docArray[0].type == 'rich text') { + const gptResponse = await this.askGPT(); + console.log(gptResponse); + if (gptResponse) { + mermaidCode = gptResponse; + } + } + } else { + let mermaidCode = 'graph LR;'; + if (this.Document.data instanceof List) { + let docArray: Doc[] = DocListCast(this.Document.data); + let rectangleArray = docArray.filter(doc => doc.title == 'rectangle' || doc.title == 'circle'); + let lineArray = docArray.filter(doc => doc.title == 'line' || doc.title == 'stroke'); + let textArray = docArray.filter(doc => doc.type == 'rich text'); + for (let i = 0; i < rectangleArray.length; i++) { + const rectangle = rectangleArray[i]; + for (let j = 0; j < lineArray.length; j++) { + const line = lineArray[j]; + if (this.isLineInFirstBox(rectangle, line)) { + for (let k = 0; k < rectangleArray.length; k++) { + const rectangle2 = rectangleArray[k]; + if (this.isLineInSecondBox(rectangle2, line) && typeof rectangle.x === 'number' && typeof rectangle2.x === 'number') { + mermaidCode += Math.abs(rectangle.x) + this.getTextInBox(rectangle, textArray) + '---' + Math.abs(rectangle2.x) + this.getTextInBox(rectangle2, textArray) + ';'; + } } } } } } } - console.log(mermaidCode); + //console.log(mermaidCode); return mermaidCode; - } - getTextInBox=(box: Doc,richTextArray: Doc[]):string=>{ - for(let i=0;ibox.x&&textDoc.xbox.y&&textDoc.y { + for (let i = 0; i < richTextArray.length; i++) { + let textDoc = richTextArray[i]; + if (typeof textDoc.x === 'number' && typeof textDoc.y === 'number' && typeof box.x === 'number' && typeof box.height === 'number' && typeof box.width === 'number' && typeof box.y === 'number') { + if (textDoc.x > box.x && textDoc.x < box.x + box.width && textDoc.y > box.y && textDoc.y < box.y + box.height) { + if (box.title == 'rectangle') { + return '(' + (textDoc.text as RichTextField)?.Text + ')'; } - if(box.title=='circle'){ - return "(("+(textDoc.text as RichTextField)?.Text+"))" + if (box.title == 'circle') { + return '((' + (textDoc.text as RichTextField)?.Text + '))'; } } } } - return "( )"; - } - isLineInFirstBox=(box: Doc,line: Doc):boolean=>{ - if( - typeof line.x === 'number' && - typeof box.x === 'number' && - typeof box.width === 'number' && - typeof box.height === 'number' && - typeof box.y === 'number' && - typeof line.y === 'number') { - return line.x < box.x + box.width + (box.width + box.x) * 0.1 && - line.x > box.x && - line.y > box.y && - line.y < box.y + box.height - } - else{ + return '( )'; + }; + isLineInFirstBox = (box: Doc, line: Doc): boolean => { + if (typeof line.x === 'number' && typeof box.x === 'number' && typeof box.width === 'number' && typeof box.height === 'number' && typeof box.y === 'number' && typeof line.y === 'number') { + return line.x < box.x + box.width + (box.width + box.x) * 0.1 && line.x > box.x && line.y > box.y && line.y < box.y + box.height; + } else { return false; } - } - isLineInSecondBox=(box:Doc,line:Doc):boolean=>{ - if ( - typeof line.x === 'number' && - typeof line.width === 'number' && - typeof box.x === 'number' && - typeof box.width === 'number' && - typeof box.y === 'number' && - typeof box.height === 'number' && - typeof line.y === 'number') { - return line.x + line.width > box.x - (box.x - box.width) * 0.1 && - line.x + line.width < box.x + box.width && - line.y > box.y && - line.y < box.y + box.height; - } - else{ + }; + isLineInSecondBox = (box: Doc, line: Doc): boolean => { + if (typeof line.x === 'number' && typeof line.width === 'number' && typeof box.x === 'number' && typeof box.width === 'number' && typeof box.y === 'number' && typeof box.height === 'number' && typeof line.y === 'number') { + return line.x + line.width > box.x - (box.x - box.width) * 0.1 && line.x + line.width < box.x + box.width && line.y > box.y && line.y < box.y + box.height; + } else { return false; } - } + }; + render() { - return ( -
- ); + return
; } } - -- cgit v1.2.3-70-g09d2 From 8f388d6f7cba5964547fd6a401b4a6c661cf76dc Mon Sep 17 00:00:00 2001 From: Zachary Zhang Date: Tue, 30 Apr 2024 14:55:36 -0400 Subject: ui changes for ai mermaid --- src/client/apis/gpt/GPT.ts | 21 ++-- src/client/views/nodes/DiagramBox.scss | 88 +++++++++++++++ src/client/views/nodes/DiagramBox.tsx | 192 +++++++++++++++++---------------- 3 files changed, 202 insertions(+), 99 deletions(-) (limited to 'src/client/views/nodes/DiagramBox.tsx') diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts index 49c56f04e..027c10e28 100644 --- a/src/client/apis/gpt/GPT.ts +++ b/src/client/apis/gpt/GPT.ts @@ -1,4 +1,5 @@ import { ClientOptions, OpenAI } from 'openai'; +import { ChatCompletionMessageParam } from 'openai/resources'; enum GPTCallType { SUMMARY = 'summary', @@ -18,11 +19,11 @@ const callTypeMap: { [type: string]: GPTCallOpts } = { summary: { model: 'gpt-3.5-turbo-instruct', maxTokens: 256, temp: 0.5, prompt: 'Summarize this text in simpler terms: ' }, edit: { model: 'gpt-3.5-turbo-instruct', maxTokens: 256, temp: 0.5, prompt: 'Reword this: ' }, completion: { model: 'gpt-3.5-turbo-instruct', maxTokens: 256, temp: 0.5, prompt: '' }, - mermaid:{model:'gpt-3.5-turbo-instruct',maxTokens:256,temp:0,prompt:"Write this in mermaid code (keep in note thatPut this at the end of the code to add colors heres an example and be very care about the order:pie title Example Pie Chart \"Red\" : 25 \"Blue\" : 75%%{init: {'theme': 'base', 'themeVariables': { 'pie1': '#0000FF', 'pie2': '#FF0000'}}}%%): "} + mermaid:{model:'gpt-4-turbo',maxTokens:2048,temp:0,prompt:"Write this in mermaid code and only give me the mermaid code (Heres an example of changing color of a pie chart to help you pie title Example \"Red\": 20 \"Blue\": 50 \"Green\": 30 %%{init: {'theme': 'base', 'themeVariables': {'pie1': '#0000FF', 'pie2': '#00FF00', 'pie3': '#FF0000'}}}%% keep in mind that pie1 is the highest since its sorted in descending order. Heres an example of a mindmap: mindmap root((mindmap)) Origins Long history ::icon(fa fa-book) Popularisation British popular psychology author Tony Buzan Research On effectivness
and features On Automatic creation Uses Creative techniques Strategic planning Argument mapping Tools Pen and paper Mermaid. "} }; -/** +/**` * Calls the OpenAI API. * * @param inputText Text to process @@ -37,14 +38,20 @@ const gptAPICall = async (inputText: string, callType: GPTCallType) => { dangerouslyAllowBrowser: true, }; const openai = new OpenAI(configuration); - const response = await openai.completions.create({ + + let messages: ChatCompletionMessageParam[] = [ + { role: 'system', content: opts.prompt }, + { role: 'user', content: inputText }, + ]; + + const response = await openai.chat.completions.create({ model: opts.model, - max_tokens: opts.maxTokens, + messages: messages, temperature: opts.temp, - prompt: `${opts.prompt}${inputText}`, - + max_tokens: opts.maxTokens, }); - return response.choices[0].text; + const content = response.choices[0].message.content; + return content; } catch (err) { console.log(err); return 'Error connecting with API.'; diff --git a/src/client/views/nodes/DiagramBox.scss b/src/client/views/nodes/DiagramBox.scss index e69de29bb..d2749f1ad 100644 --- a/src/client/views/nodes/DiagramBox.scss +++ b/src/client/views/nodes/DiagramBox.scss @@ -0,0 +1,88 @@ +.DIYNodeBox { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + + .DIYNodeBox-wrapper { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + .DIYNodeBox { + /* existing code */ + + .DIYNodeBox-iframe { + height: 100%; + width: 100%; + border: none; + + } + } + + .search-bar { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + padding: 10px; + + input[type="text"] { + flex: 1; + margin-right: 10px; + } + + button { + padding: 5px 10px; + } + } + + .content { + flex: 1; + display: flex; + justify-content: center; + align-items: center; + width:100%; + height:100%; + .diagramBox{ + flex: 1; + display: flex; + justify-content: center; + align-items: center; + width:100%; + height:100%; + svg{ + flex: 1; + display: flex; + justify-content: center; + align-items: center; + width:100%; + height:100%; + } + } + } + + .loading-circle { + position: relative; + width: 50px; + height: 50px; + border-radius: 50%; + border: 3px solid #ccc; + border-top-color: #333; + animation: spin 1s infinite linear; + } + + @keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } + } + } +} \ No newline at end of file diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx index 64d0d6d78..902134fb7 100644 --- a/src/client/views/nodes/DiagramBox.tsx +++ b/src/client/views/nodes/DiagramBox.tsx @@ -12,18 +12,30 @@ import { List } from '../../../fields/List'; import { RichTextField } from '../../../fields/RichTextField'; import { ContextMenu } from '../ContextMenu'; import { gptAPICall, GPTCallType } from '../../apis/gpt/GPT'; +import { ChatCompletionMessageParam } from 'openai/resources/chat/completions'; +import OpenAI, { ClientOptions } from 'openai'; @observer export class DiagramBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(DiagramBox, fieldKey); } + private _ref: React.RefObject = React.createRef(); + private _dragRef = React.createRef(); constructor(props: FieldViewProps) { super(props); makeObservable(this); //this.chartContent = 'flowchart LR;A-->B:::wide;B-->C:::wide; B-->D[hello];'; } + @observable inputValue = ''; + @observable loading = false; + @observable errorMessage = ''; + @observable mermaidCode = ''; + + @action handleInputChange = (e: React.ChangeEvent) => { + this.inputValue = e.target.value; + }; componentDidMount() { this._props.setContentViewBox?.(this); mermaid.initialize({ @@ -31,112 +43,91 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im startOnLoad: true, flowchart: { useMaxWidth: true, htmlLabels: true, curve: 'cardinal' }, }); + } + renderMermaid = async (str:string) => { + try { + const { svg, bindFunctions } = await this.mermaidDiagram(str); + return { svg, bindFunctions }; + } catch (error) { + console.error('Error rendering mermaid diagram:', error); + return { svg: '', bindFunctions: undefined }; + } + }; + mermaidDiagram = async (str:string) => { + return await mermaid.render('graph' + Date.now(), str); + }; - const renderMermaid = async (str: string) => { - try { - const { svg, bindFunctions } = await mermaidDiagram(str); - return { svg, bindFunctions }; - } catch (error) { - console.error('Error rendering mermaid diagram:', error); - return { svg: '', bindFunctions: undefined }; - } - }; - const mermaidDiagram = async (str: string) => { - return await mermaid.render('graph' + Date.now(), str); - }; - async function renderMermaidAsync(this: DiagramBox) { - try { - const mermaidCode: string = await this.createMermaidCode(); - const { svg, bindFunctions } = await renderMermaid(mermaidCode); - const dashDiv = document.getElementById('dashDiv'); - if (dashDiv) { - dashDiv.innerHTML = svg; - if (bindFunctions) { - bindFunctions(dashDiv); - } + async renderMermaidAsync(mermaidCode:string) { + try { + const { svg, bindFunctions } = await this.renderMermaid(mermaidCode); + const dashDiv = document.getElementById('dashDiv'); + if (dashDiv) { + dashDiv.innerHTML = svg; + if (bindFunctions) { + bindFunctions(dashDiv); } - } catch (error) { - console.error('Error rendering Mermaid:', error); } + } catch (error) { + console.error('Error rendering Mermaid:', error); } - - renderMermaidAsync.call(this); } + @action handleRenderClick = () => { + // Call the GPT model and get the HTML output + // const modelOutput = getHtmlOutput(this.inputValue); + // this.htmlCode = modelOutput; + this.generateMermaidCode(); + }; + @action generateMermaidCode=async()=>{ + console.log('Generating Mermaid Code'); + this.loading = true; - askGPT = async (): Promise => { - try { - let notes = 'mermaid syntax for pie charts do not include %'; - let text = notes + (DocListCast(this.Document.data)[0].text as RichTextField)?.Text; - if (!text) { - console.error('Text extraction failed'); - return; - } - - let res = await gptAPICall(text, GPTCallType.MERMAID); - if (!res) { - console.error('GPT call failed'); - return; + let res = await gptAPICall(this.inputValue, GPTCallType.MERMAID); + this.loading = false; + if (res == 'Error connecting with API.') { + // If GPT call failed + console.error('GPT call failed'); + this.errorMessage = 'GPT call failed; please try again.'; + } else if(res!=null){ + // If GPT call succeeded, set htmlCode;;; TODO: check if valid html + if (this.isValidCode(res)) { + this.mermaidCode = res; + console.log('GPT call succeeded:' + res); + this.errorMessage = ''; } else { - console.log(res) - return this.removeWords(res); + console.error('GPT call succeeded but invalid html; please try again.'); + this.errorMessage = 'GPT call succeeded but invalid html; please try again.'; } - } catch (err) { - console.error('Error:', err); - return; } + this.renderMermaidAsync.call(this,this.removeWords(this.mermaidCode)); + this.loading = false; + } + isValidCode = (html: string) => { + return true; }; + removeWords(inputStr:string) { - let presetArray=["pie","flowchart","diagramChart","graph TD","flowchart TD","flowchart LR","graph LR"] - const lines = inputStr.split('\n'); - let foundPresetWord = false; - let result = ''; - - for (const line of lines) { - if (!foundPresetWord) { - for (const word of presetArray) { - if (line.toLowerCase().includes(word.toLowerCase())) { - foundPresetWord = true; - result += line + '\n'; - break; - } - } - } else { - result += line + '\n'; - } - } - - return result; + inputStr=inputStr.replace("```mermaid","") + return inputStr.replace("```",""); } + createMermaidCode = async (): Promise => { - let mermaidCode = ''; - let docArray: Doc[] = DocListCast(this.Document.data); - if (docArray.length === 1) { - if (docArray[0].type == 'rich text') { - const gptResponse = await this.askGPT(); - console.log(gptResponse); - if (gptResponse) { - mermaidCode = gptResponse; - } - } - } else { - let mermaidCode = 'graph LR;'; - if (this.Document.data instanceof List) { - let docArray: Doc[] = DocListCast(this.Document.data); - let rectangleArray = docArray.filter(doc => doc.title == 'rectangle' || doc.title == 'circle'); - let lineArray = docArray.filter(doc => doc.title == 'line' || doc.title == 'stroke'); - let textArray = docArray.filter(doc => doc.type == 'rich text'); - for (let i = 0; i < rectangleArray.length; i++) { - const rectangle = rectangleArray[i]; - for (let j = 0; j < lineArray.length; j++) { - const line = lineArray[j]; - if (this.isLineInFirstBox(rectangle, line)) { - for (let k = 0; k < rectangleArray.length; k++) { - const rectangle2 = rectangleArray[k]; - if (this.isLineInSecondBox(rectangle2, line) && typeof rectangle.x === 'number' && typeof rectangle2.x === 'number') { - mermaidCode += Math.abs(rectangle.x) + this.getTextInBox(rectangle, textArray) + '---' + Math.abs(rectangle2.x) + this.getTextInBox(rectangle2, textArray) + ';'; - } + let mermaidCode = 'graph LR;'; + if (this.Document.data instanceof List) { + let docArray: Doc[] = DocListCast(this.Document.data); + let rectangleArray = docArray.filter(doc => doc.title == 'rectangle' || doc.title == 'circle'); + let lineArray = docArray.filter(doc => doc.title == 'line' || doc.title == 'stroke'); + let textArray = docArray.filter(doc => doc.type == 'rich text'); + for (let i = 0; i < rectangleArray.length; i++) { + const rectangle = rectangleArray[i]; + for (let j = 0; j < lineArray.length; j++) { + const line = lineArray[j]; + if (this.isLineInFirstBox(rectangle, line)) { + for (let k = 0; k < rectangleArray.length; k++) { + const rectangle2 = rectangleArray[k]; + if (this.isLineInSecondBox(rectangle2, line) && typeof rectangle.x === 'number' && typeof rectangle2.x === 'number') { + mermaidCode += Math.abs(rectangle.x) + this.getTextInBox(rectangle, textArray) + '---' + Math.abs(rectangle2.x) + this.getTextInBox(rectangle2, textArray) + ';'; } } } @@ -179,6 +170,23 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im }; render() { - return
; + console.log(this.loading) + return( +
+
+
+ + +
+
+ {this.mermaidCode ? ( +
+ ) : ( +
{this.loading ?
:
{this.errorMessage ? this.errorMessage : 'Insert prompt to generate diagram'}
}
+ )} +
+
+
+ ); } } -- cgit v1.2.3-70-g09d2 From becb6c46c176acf57fe24315f45ffe99f3ed0c76 Mon Sep 17 00:00:00 2001 From: Zachary Zhang Date: Wed, 1 May 2024 21:02:48 -0400 Subject: asd --- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 ++ src/client/views/nodes/DiagramBox.tsx | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'src/client/views/nodes/DiagramBox.tsx') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 791124f50..a0c878ee6 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1495,6 +1495,8 @@ export class CollectionFreeFormView extends CollectionSubView (this._layoutElements = this.doLayoutComputation(computation.newPool, computation.computedElementData)), { fireImmediately: true } ); + console.log("Asdasdasda"+this.childDocs) + console.log(DocListCast(this.Document.data)); } static replaceCanvases(oldDiv: HTMLElement, newDiv: HTMLElement) { diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx index 902134fb7..2e77d1796 100644 --- a/src/client/views/nodes/DiagramBox.tsx +++ b/src/client/views/nodes/DiagramBox.tsx @@ -14,6 +14,10 @@ import { ContextMenu } from '../ContextMenu'; import { gptAPICall, GPTCallType } from '../../apis/gpt/GPT'; import { ChatCompletionMessageParam } from 'openai/resources/chat/completions'; import OpenAI, { ClientOptions } from 'openai'; +import { line } from 'd3'; +import { InkingStroke } from '../InkingStroke'; +import { DocumentManager } from '../../util/DocumentManager'; +import { C } from '@fullcalendar/core/internal-common'; @observer export class DiagramBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { @@ -22,10 +26,11 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im } private _ref: React.RefObject = React.createRef(); private _dragRef = React.createRef(); + private chartContent:string constructor(props: FieldViewProps) { super(props); makeObservable(this); - //this.chartContent = 'flowchart LR;A-->B:::wide;B-->C:::wide; B-->D[hello];'; + this.chartContent = 'flowchart LR;A-->B:::wide;B-->C:::wide; B-->D[hello];'; } @observable inputValue = ''; @@ -43,6 +48,10 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im startOnLoad: true, flowchart: { useMaxWidth: true, htmlLabels: true, curve: 'cardinal' }, }); + this.renderMermaidAsync.call(this,this.chartContent); + this.mermaidCode=this.chartContent + this.createMermaidCode() + } renderMermaid = async (str:string) => { try { @@ -119,6 +128,10 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im let rectangleArray = docArray.filter(doc => doc.title == 'rectangle' || doc.title == 'circle'); let lineArray = docArray.filter(doc => doc.title == 'line' || doc.title == 'stroke'); let textArray = docArray.filter(doc => doc.type == 'rich text'); + console.log(docArray) + console.log(this.childDocs + .map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.()))); + console.log(this.Document.data.filter(inkView => inkView?.ComponentView instanceof InkingStroke)) for (let i = 0; i < rectangleArray.length; i++) { const rectangle = rectangleArray[i]; for (let j = 0; j < lineArray.length; j++) { @@ -170,7 +183,6 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im }; render() { - console.log(this.loading) return(
-- cgit v1.2.3-70-g09d2 From c6512a23a4eeba55115c5538bdb5b00a5b3d1848 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 1 May 2024 21:22:41 -0400 Subject: quick fix to documentView problem --- src/client/views/nodes/DiagramBox.tsx | 89 +++++++++++++++++------------------ 1 file changed, 44 insertions(+), 45 deletions(-) (limited to 'src/client/views/nodes/DiagramBox.tsx') diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx index 2e77d1796..efec9c7e2 100644 --- a/src/client/views/nodes/DiagramBox.tsx +++ b/src/client/views/nodes/DiagramBox.tsx @@ -26,7 +26,7 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im } private _ref: React.RefObject = React.createRef(); private _dragRef = React.createRef(); - private chartContent:string + private chartContent: string; constructor(props: FieldViewProps) { super(props); makeObservable(this); @@ -48,12 +48,11 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im startOnLoad: true, flowchart: { useMaxWidth: true, htmlLabels: true, curve: 'cardinal' }, }); - this.renderMermaidAsync.call(this,this.chartContent); - this.mermaidCode=this.chartContent - this.createMermaidCode() - + this.renderMermaidAsync.call(this, this.chartContent); + this.mermaidCode = this.chartContent; + this.createMermaidCode(); } - renderMermaid = async (str:string) => { + renderMermaid = async (str: string) => { try { const { svg, bindFunctions } = await this.mermaidDiagram(str); return { svg, bindFunctions }; @@ -62,11 +61,11 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im return { svg: '', bindFunctions: undefined }; } }; - mermaidDiagram = async (str:string) => { + mermaidDiagram = async (str: string) => { return await mermaid.render('graph' + Date.now(), str); }; - async renderMermaidAsync(mermaidCode:string) { + async renderMermaidAsync(mermaidCode: string) { try { const { svg, bindFunctions } = await this.renderMermaid(mermaidCode); const dashDiv = document.getElementById('dashDiv'); @@ -86,7 +85,7 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im // this.htmlCode = modelOutput; this.generateMermaidCode(); }; - @action generateMermaidCode=async()=>{ + @action generateMermaidCode = async () => { console.log('Generating Mermaid Code'); this.loading = true; @@ -96,7 +95,7 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im // If GPT call failed console.error('GPT call failed'); this.errorMessage = 'GPT call failed; please try again.'; - } else if(res!=null){ + } else if (res != null) { // If GPT call succeeded, set htmlCode;;; TODO: check if valid html if (this.isValidCode(res)) { this.mermaidCode = res; @@ -107,20 +106,18 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im this.errorMessage = 'GPT call succeeded but invalid html; please try again.'; } } - this.renderMermaidAsync.call(this,this.removeWords(this.mermaidCode)); + this.renderMermaidAsync.call(this, this.removeWords(this.mermaidCode)); this.loading = false; - } + }; isValidCode = (html: string) => { return true; }; - - removeWords(inputStr:string) { - inputStr=inputStr.replace("```mermaid","") - return inputStr.replace("```",""); + removeWords(inputStr: string) { + inputStr = inputStr.replace('```mermaid', ''); + return inputStr.replace('```', ''); } - createMermaidCode = async (): Promise => { let mermaidCode = 'graph LR;'; if (this.Document.data instanceof List) { @@ -128,24 +125,26 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im let rectangleArray = docArray.filter(doc => doc.title == 'rectangle' || doc.title == 'circle'); let lineArray = docArray.filter(doc => doc.title == 'line' || doc.title == 'stroke'); let textArray = docArray.filter(doc => doc.type == 'rich text'); - console.log(docArray) - console.log(this.childDocs - .map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.()))); - console.log(this.Document.data.filter(inkView => inkView?.ComponentView instanceof InkingStroke)) - for (let i = 0; i < rectangleArray.length; i++) { - const rectangle = rectangleArray[i]; - for (let j = 0; j < lineArray.length; j++) { - const line = lineArray[j]; - if (this.isLineInFirstBox(rectangle, line)) { - for (let k = 0; k < rectangleArray.length; k++) { - const rectangle2 = rectangleArray[k]; - if (this.isLineInSecondBox(rectangle2, line) && typeof rectangle.x === 'number' && typeof rectangle2.x === 'number') { - mermaidCode += Math.abs(rectangle.x) + this.getTextInBox(rectangle, textArray) + '---' + Math.abs(rectangle2.x) + this.getTextInBox(rectangle2, textArray) + ';'; + console.log(docArray); + setTimeout(() => { + console.log(docArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.()))); + console.log(docArray.filter(inkView => inkView?.ComponentView instanceof InkingStroke)); + + for (let i = 0; i < rectangleArray.length; i++) { + const rectangle = rectangleArray[i]; + for (let j = 0; j < lineArray.length; j++) { + const line = lineArray[j]; + if (this.isLineInFirstBox(rectangle, line)) { + for (let k = 0; k < rectangleArray.length; k++) { + const rectangle2 = rectangleArray[k]; + if (this.isLineInSecondBox(rectangle2, line) && typeof rectangle.x === 'number' && typeof rectangle2.x === 'number') { + mermaidCode += Math.abs(rectangle.x) + this.getTextInBox(rectangle, textArray) + '---' + Math.abs(rectangle2.x) + this.getTextInBox(rectangle2, textArray) + ';'; + } } } } } - } + }); } //console.log(mermaidCode); return mermaidCode; @@ -183,22 +182,22 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im }; render() { - return( -
-
-
- - -
-
- {this.mermaidCode ? ( -
- ) : ( -
{this.loading ?
:
{this.errorMessage ? this.errorMessage : 'Insert prompt to generate diagram'}
}
- )} + return ( +
+
+
+ + +
+
+ {this.mermaidCode ? ( +
+ ) : ( +
{this.loading ?
:
{this.errorMessage ? this.errorMessage : 'Insert prompt to generate diagram'}
}
+ )} +
-
); } } -- cgit v1.2.3-70-g09d2 From 90dd101b601add39b2e03a2e1235a74e45c69d5c Mon Sep 17 00:00:00 2001 From: Zachary Zhang Date: Thu, 2 May 2024 01:48:47 -0400 Subject: change algorithm to include stroke points --- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 - src/client/views/nodes/DiagramBox.tsx | 57 ++++++++++++++-------- 2 files changed, 37 insertions(+), 22 deletions(-) (limited to 'src/client/views/nodes/DiagramBox.tsx') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index a0c878ee6..791124f50 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1495,8 +1495,6 @@ export class CollectionFreeFormView extends CollectionSubView (this._layoutElements = this.doLayoutComputation(computation.newPool, computation.computedElementData)), { fireImmediately: true } ); - console.log("Asdasdasda"+this.childDocs) - console.log(DocListCast(this.Document.data)); } static replaceCanvases(oldDiv: HTMLElement, newDiv: HTMLElement) { diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx index efec9c7e2..5254a4fe0 100644 --- a/src/client/views/nodes/DiagramBox.tsx +++ b/src/client/views/nodes/DiagramBox.tsx @@ -50,7 +50,7 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im }); this.renderMermaidAsync.call(this, this.chartContent); this.mermaidCode = this.chartContent; - this.createMermaidCode(); + this.chartContent= this.createMermaidCode(); } renderMermaid = async (str: string) => { try { @@ -118,26 +118,50 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im return inputStr.replace('```', ''); } - createMermaidCode = async (): Promise => { + createMermaidCode() { let mermaidCode = 'graph LR;'; if (this.Document.data instanceof List) { let docArray: Doc[] = DocListCast(this.Document.data); let rectangleArray = docArray.filter(doc => doc.title == 'rectangle' || doc.title == 'circle'); let lineArray = docArray.filter(doc => doc.title == 'line' || doc.title == 'stroke'); let textArray = docArray.filter(doc => doc.type == 'rich text'); - console.log(docArray); setTimeout(() => { - console.log(docArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.()))); - console.log(docArray.filter(inkView => inkView?.ComponentView instanceof InkingStroke)); - - for (let i = 0; i < rectangleArray.length; i++) { + let inkStrokeArray=lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())) + .filter(inkView => inkView?.ComponentView instanceof InkingStroke) + console.log(inkStrokeArray.length) + let inkingStrokeArray=inkStrokeArray.map(stroke=>stroke?.ComponentView) + for (let i = 0; i < rectangleArray.length; i++) { const rectangle = rectangleArray[i]; for (let j = 0; j < lineArray.length; j++) { - const line = lineArray[j]; - if (this.isLineInFirstBox(rectangle, line)) { + let inkStrokeXArray=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.map(coord=>coord.X) + let inkStrokeYArray=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.map(coord=>coord.Y) + let minX=Math.min(...inkStrokeXArray) + let minY=Math.min(...inkStrokeYArray) + let inkScaleX=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleX + let inkScaleY=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleY + let StartX:number=0 + let StartY:number=0 + let EndX:number=0 + let EndY:number=0 + if(typeof docArray[j].x==='number'&&typeof docArray[j].y==='number'&&typeof (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[j]==='number'){ + StartX=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[j].X*inkScaleX-minX*inkScaleX + StartY=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[j].Y*inkScaleY-minY*inkScaleY+lineArray[j]?.y + EndX=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.length-1].X*inkScaleX-minX*inkScaleX+docArray[j].x + EndY=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.length-1].Y*inkScaleY-minY*inkScaleY+docArray[j].y + } + console.log((inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData) + console.log((inkingStrokeArray[j] as InkingStroke)?.inkScaledData()) + console.log(EndX) + console.log(EndY) + console.log(docArray[j].title) + console.log(docArray[j].x) + console.log(docArray[j].y) + console.log(docArray[j].width) + console.log(docArray[j].height) + if (this.isPointInBox(rectangle, [StartX,StartY])) { for (let k = 0; k < rectangleArray.length; k++) { const rectangle2 = rectangleArray[k]; - if (this.isLineInSecondBox(rectangle2, line) && typeof rectangle.x === 'number' && typeof rectangle2.x === 'number') { + if (this.isPointInBox(rectangle2, [EndX,EndY]) && typeof rectangle.x === 'number' && typeof rectangle2.x === 'number') { mermaidCode += Math.abs(rectangle.x) + this.getTextInBox(rectangle, textArray) + '---' + Math.abs(rectangle2.x) + this.getTextInBox(rectangle2, textArray) + ';'; } } @@ -166,16 +190,9 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im } return '( )'; }; - isLineInFirstBox = (box: Doc, line: Doc): boolean => { - if (typeof line.x === 'number' && typeof box.x === 'number' && typeof box.width === 'number' && typeof box.height === 'number' && typeof box.y === 'number' && typeof line.y === 'number') { - return line.x < box.x + box.width + (box.width + box.x) * 0.1 && line.x > box.x && line.y > box.y && line.y < box.y + box.height; - } else { - return false; - } - }; - isLineInSecondBox = (box: Doc, line: Doc): boolean => { - if (typeof line.x === 'number' && typeof line.width === 'number' && typeof box.x === 'number' && typeof box.width === 'number' && typeof box.y === 'number' && typeof box.height === 'number' && typeof line.y === 'number') { - return line.x + line.width > box.x - (box.x - box.width) * 0.1 && line.x + line.width < box.x + box.width && line.y > box.y && line.y < box.y + box.height; + isPointInBox = (box: Doc, line: number[]): boolean => { + if (typeof line[0] === 'number' && typeof box.x === 'number' && typeof box.width === 'number' && typeof box.height === 'number' && typeof box.y === 'number' && typeof line[1] === 'number') { + return line[0] < box.x + box.width&& line[0] > box.x && line[1] > box.y && line[1] < box.y + box.height; } else { return false; } -- cgit v1.2.3-70-g09d2 From c32c2b48258c0d104921ecdbd6eeb514a814595e Mon Sep 17 00:00:00 2001 From: Zachary Zhang Date: Mon, 6 May 2024 18:39:52 -0400 Subject: fix mermaid code generator from drawing, does not render --- src/client/views/nodes/DiagramBox.tsx | 77 +++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 31 deletions(-) (limited to 'src/client/views/nodes/DiagramBox.tsx') diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx index 5254a4fe0..27f9d2a86 100644 --- a/src/client/views/nodes/DiagramBox.tsx +++ b/src/client/views/nodes/DiagramBox.tsx @@ -18,6 +18,7 @@ import { line } from 'd3'; import { InkingStroke } from '../InkingStroke'; import { DocumentManager } from '../../util/DocumentManager'; import { C } from '@fullcalendar/core/internal-common'; +import { Docs } from '../../documents/Documents'; @observer export class DiagramBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { @@ -26,11 +27,10 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im } private _ref: React.RefObject = React.createRef(); private _dragRef = React.createRef(); - private chartContent: string; + private chartContent: string="graph L;"; constructor(props: FieldViewProps) { super(props); makeObservable(this); - this.chartContent = 'flowchart LR;A-->B:::wide;B-->C:::wide; B-->D[hello];'; } @observable inputValue = ''; @@ -41,16 +41,21 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im @action handleInputChange = (e: React.ChangeEvent) => { this.inputValue = e.target.value; }; - componentDidMount() { + async componentDidMount() { + console.log(this.chartContent) this._props.setContentViewBox?.(this); mermaid.initialize({ securityLevel: 'loose', startOnLoad: true, flowchart: { useMaxWidth: true, htmlLabels: true, curve: 'cardinal' }, }); - this.renderMermaidAsync.call(this, this.chartContent); - this.mermaidCode = this.chartContent; - this.chartContent= this.createMermaidCode(); + this.mermaidCode = "asdasdasd"; + if(this.chartContent!="graph LR;"){ + this.chartContent=await this.createMermaidCode() + //console.log(this.chartContent) + } + this.renderMermaidAsync(this.chartContent) + this.testInkingStroke() } renderMermaid = async (str: string) => { try { @@ -112,66 +117,76 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im isValidCode = (html: string) => { return true; }; + testInkingStroke=()=>{ + if (this.Document.data instanceof List) { + let docArray: Doc[] = DocListCast(this.Document.data); + let lineArray = docArray.filter(doc => doc.title == 'line' || doc.title == 'stroke'); + setTimeout(() => { + let inkStrokeArray=lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())) + .filter(inkView => inkView?.ComponentView instanceof InkingStroke) + console.log(inkStrokeArray) + }); + } + } removeWords(inputStr: string) { inputStr = inputStr.replace('```mermaid', ''); return inputStr.replace('```', ''); } - createMermaidCode() { + async createMermaidCode() { let mermaidCode = 'graph LR;'; if (this.Document.data instanceof List) { let docArray: Doc[] = DocListCast(this.Document.data); let rectangleArray = docArray.filter(doc => doc.title == 'rectangle' || doc.title == 'circle'); let lineArray = docArray.filter(doc => doc.title == 'line' || doc.title == 'stroke'); let textArray = docArray.filter(doc => doc.type == 'rich text'); - setTimeout(() => { - let inkStrokeArray=lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())) - .filter(inkView => inkView?.ComponentView instanceof InkingStroke) - console.log(inkStrokeArray.length) + const timeoutPromise = () => new Promise(resolve => { + setTimeout(resolve, 0); + }); + await timeoutPromise(); + let inkStrokeArray=lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())) + .filter(inkView => inkView?.ComponentView instanceof InkingStroke) + if(inkStrokeArray[0]){ let inkingStrokeArray=inkStrokeArray.map(stroke=>stroke?.ComponentView) for (let i = 0; i < rectangleArray.length; i++) { const rectangle = rectangleArray[i]; for (let j = 0; j < lineArray.length; j++) { let inkStrokeXArray=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.map(coord=>coord.X) let inkStrokeYArray=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.map(coord=>coord.Y) - let minX=Math.min(...inkStrokeXArray) - let minY=Math.min(...inkStrokeYArray) + let minX:number=Math.min(...inkStrokeXArray) + let minY:number=Math.min(...inkStrokeYArray) let inkScaleX=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleX let inkScaleY=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleY let StartX:number=0 let StartY:number=0 let EndX:number=0 let EndY:number=0 - if(typeof docArray[j].x==='number'&&typeof docArray[j].y==='number'&&typeof (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[j]==='number'){ - StartX=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[j].X*inkScaleX-minX*inkScaleX - StartY=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[j].Y*inkScaleY-minY*inkScaleY+lineArray[j]?.y - EndX=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.length-1].X*inkScaleX-minX*inkScaleX+docArray[j].x - EndY=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.length-1].Y*inkScaleY-minY*inkScaleY+docArray[j].y - } - console.log((inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData) - console.log((inkingStrokeArray[j] as InkingStroke)?.inkScaledData()) - console.log(EndX) - console.log(EndY) - console.log(docArray[j].title) - console.log(docArray[j].x) - console.log(docArray[j].y) - console.log(docArray[j].width) - console.log(docArray[j].height) + StartX=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[j].X*inkScaleX-minX*inkScaleX+(lineArray[j]?.x as number) + StartY=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[j].Y*inkScaleY-minY*inkScaleY+(lineArray[j]?.y as number) + EndX=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.length-1].X*inkScaleX-minX*inkScaleX+(lineArray[j].x as number) + EndY=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.length-1].Y*inkScaleY-minY*inkScaleY+(lineArray[j].y as number) if (this.isPointInBox(rectangle, [StartX,StartY])) { for (let k = 0; k < rectangleArray.length; k++) { const rectangle2 = rectangleArray[k]; if (this.isPointInBox(rectangle2, [EndX,EndY]) && typeof rectangle.x === 'number' && typeof rectangle2.x === 'number') { + mermaidCode += Math.abs(rectangle.x) + this.getTextInBox(rectangle, textArray) + '---' + Math.abs(rectangle2.x) + this.getTextInBox(rectangle2, textArray) + ';'; + //console.log(mermaidCode) } } } } } - }); + } + } - //console.log(mermaidCode); - return mermaidCode; + console.log(this) + this.addDocument(Docs.Create.TextDocument("asd", { title:"hellotitle", x: 0, y: 0 })); + let docArray: Doc[] = DocListCast(this.Document.data); + console.log(docArray.length) + //console.log(mermaidCode) + return mermaidCode }; getTextInBox = (box: Doc, richTextArray: Doc[]): string => { -- cgit v1.2.3-70-g09d2 From db9b7f9282a0fd921a45275c3bb0cfe7e1d055f9 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 6 May 2024 19:20:00 -0400 Subject: fixed adding collection from DiagramBox --- src/client/views/nodes/DiagramBox.tsx | 85 +++++++++++++++++------------------ 1 file changed, 40 insertions(+), 45 deletions(-) (limited to 'src/client/views/nodes/DiagramBox.tsx') diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx index 27f9d2a86..8a31f634b 100644 --- a/src/client/views/nodes/DiagramBox.tsx +++ b/src/client/views/nodes/DiagramBox.tsx @@ -19,6 +19,7 @@ import { InkingStroke } from '../InkingStroke'; import { DocumentManager } from '../../util/DocumentManager'; import { C } from '@fullcalendar/core/internal-common'; import { Docs } from '../../documents/Documents'; +import { NumCast } from '../../../fields/Types'; @observer export class DiagramBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { @@ -27,7 +28,7 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im } private _ref: React.RefObject = React.createRef(); private _dragRef = React.createRef(); - private chartContent: string="graph L;"; + private chartContent: string = 'graph L;'; constructor(props: FieldViewProps) { super(props); makeObservable(this); @@ -42,20 +43,20 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im this.inputValue = e.target.value; }; async componentDidMount() { - console.log(this.chartContent) + console.log(this.chartContent); this._props.setContentViewBox?.(this); mermaid.initialize({ securityLevel: 'loose', startOnLoad: true, flowchart: { useMaxWidth: true, htmlLabels: true, curve: 'cardinal' }, }); - this.mermaidCode = "asdasdasd"; - if(this.chartContent!="graph LR;"){ - this.chartContent=await this.createMermaidCode() + this.mermaidCode = 'asdasdasd'; + if (this.chartContent != 'graph LR;') { + this.chartContent = await this.createMermaidCode(); //console.log(this.chartContent) } - this.renderMermaidAsync(this.chartContent) - this.testInkingStroke() + this.renderMermaidAsync(this.chartContent); + this.testInkingStroke(); } renderMermaid = async (str: string) => { try { @@ -117,17 +118,16 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im isValidCode = (html: string) => { return true; }; - testInkingStroke=()=>{ + testInkingStroke = () => { if (this.Document.data instanceof List) { let docArray: Doc[] = DocListCast(this.Document.data); let lineArray = docArray.filter(doc => doc.title == 'line' || doc.title == 'stroke'); setTimeout(() => { - let inkStrokeArray=lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())) - .filter(inkView => inkView?.ComponentView instanceof InkingStroke) - console.log(inkStrokeArray) + let inkStrokeArray = lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).filter(inkView => inkView?.ComponentView instanceof InkingStroke); + console.log(inkStrokeArray); }); } - } + }; removeWords(inputStr: string) { inputStr = inputStr.replace('```mermaid', ''); @@ -141,36 +141,35 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im let rectangleArray = docArray.filter(doc => doc.title == 'rectangle' || doc.title == 'circle'); let lineArray = docArray.filter(doc => doc.title == 'line' || doc.title == 'stroke'); let textArray = docArray.filter(doc => doc.type == 'rich text'); - const timeoutPromise = () => new Promise(resolve => { - setTimeout(resolve, 0); - }); + const timeoutPromise = () => + new Promise(resolve => { + setTimeout(resolve, 0); + }); await timeoutPromise(); - let inkStrokeArray=lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())) - .filter(inkView => inkView?.ComponentView instanceof InkingStroke) - if(inkStrokeArray[0]){ - let inkingStrokeArray=inkStrokeArray.map(stroke=>stroke?.ComponentView) - for (let i = 0; i < rectangleArray.length; i++) { + let inkStrokeArray = lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).filter(inkView => inkView?.ComponentView instanceof InkingStroke); + if (inkStrokeArray[0]) { + let inkingStrokeArray = inkStrokeArray.map(stroke => stroke?.ComponentView); + for (let i = 0; i < rectangleArray.length; i++) { const rectangle = rectangleArray[i]; for (let j = 0; j < lineArray.length; j++) { - let inkStrokeXArray=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.map(coord=>coord.X) - let inkStrokeYArray=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.map(coord=>coord.Y) - let minX:number=Math.min(...inkStrokeXArray) - let minY:number=Math.min(...inkStrokeYArray) - let inkScaleX=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleX - let inkScaleY=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleY - let StartX:number=0 - let StartY:number=0 - let EndX:number=0 - let EndY:number=0 - StartX=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[j].X*inkScaleX-minX*inkScaleX+(lineArray[j]?.x as number) - StartY=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[j].Y*inkScaleY-minY*inkScaleY+(lineArray[j]?.y as number) - EndX=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.length-1].X*inkScaleX-minX*inkScaleX+(lineArray[j].x as number) - EndY=(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.length-1].Y*inkScaleY-minY*inkScaleY+(lineArray[j].y as number) - if (this.isPointInBox(rectangle, [StartX,StartY])) { + let inkStrokeXArray = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.map(coord => coord.X); + let inkStrokeYArray = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.map(coord => coord.Y); + let minX: number = Math.min(...inkStrokeXArray); + let minY: number = Math.min(...inkStrokeYArray); + let inkScaleX = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleX; + let inkScaleY = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleY; + let StartX: number = 0; + let StartY: number = 0; + let EndX: number = 0; + let EndY: number = 0; + StartX = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[j].X * inkScaleX - minX * inkScaleX + (lineArray[j]?.x as number); + StartY = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[j].Y * inkScaleY - minY * inkScaleY + (lineArray[j]?.y as number); + EndX = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.length - 1].X * inkScaleX - minX * inkScaleX + (lineArray[j].x as number); + EndY = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.length - 1].Y * inkScaleY - minY * inkScaleY + (lineArray[j].y as number); + if (this.isPointInBox(rectangle, [StartX, StartY])) { for (let k = 0; k < rectangleArray.length; k++) { const rectangle2 = rectangleArray[k]; - if (this.isPointInBox(rectangle2, [EndX,EndY]) && typeof rectangle.x === 'number' && typeof rectangle2.x === 'number') { - + if (this.isPointInBox(rectangle2, [EndX, EndY]) && typeof rectangle.x === 'number' && typeof rectangle2.x === 'number') { mermaidCode += Math.abs(rectangle.x) + this.getTextInBox(rectangle, textArray) + '---' + Math.abs(rectangle2.x) + this.getTextInBox(rectangle2, textArray) + ';'; //console.log(mermaidCode) } @@ -179,15 +178,11 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im } } } - } - console.log(this) - this.addDocument(Docs.Create.TextDocument("asd", { title:"hellotitle", x: 0, y: 0 })); - let docArray: Doc[] = DocListCast(this.Document.data); - console.log(docArray.length) + this._props.addDocument?.(Docs.Create.TextDocument('asd', { title: 'hellotitle', x: NumCast(this.Document.x) + NumCast(this.layoutDoc._width), y: NumCast(this.Document.y) })); //console.log(mermaidCode) - return mermaidCode - }; + return mermaidCode; + } getTextInBox = (box: Doc, richTextArray: Doc[]): string => { for (let i = 0; i < richTextArray.length; i++) { @@ -207,7 +202,7 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im }; isPointInBox = (box: Doc, line: number[]): boolean => { if (typeof line[0] === 'number' && typeof box.x === 'number' && typeof box.width === 'number' && typeof box.height === 'number' && typeof box.y === 'number' && typeof line[1] === 'number') { - return line[0] < box.x + box.width&& line[0] > box.x && line[1] > box.y && line[1] < box.y + box.height; + return line[0] < box.x + box.width && line[0] > box.x && line[1] > box.y && line[1] < box.y + box.height; } else { return false; } -- cgit v1.2.3-70-g09d2 From d1c053e3630cab14647af65db05fffc18a7efef3 Mon Sep 17 00:00:00 2001 From: Zachary Zhang Date: Tue, 7 May 2024 17:01:08 -0400 Subject: add saving of mermaid diagram code with text box --- src/client/views/nodes/DiagramBox.tsx | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) (limited to 'src/client/views/nodes/DiagramBox.tsx') diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx index 8a31f634b..c45b9a8be 100644 --- a/src/client/views/nodes/DiagramBox.tsx +++ b/src/client/views/nodes/DiagramBox.tsx @@ -28,7 +28,6 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im } private _ref: React.RefObject = React.createRef(); private _dragRef = React.createRef(); - private chartContent: string = 'graph L;'; constructor(props: FieldViewProps) { super(props); makeObservable(this); @@ -43,7 +42,6 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im this.inputValue = e.target.value; }; async componentDidMount() { - console.log(this.chartContent); this._props.setContentViewBox?.(this); mermaid.initialize({ securityLevel: 'loose', @@ -51,11 +49,12 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im flowchart: { useMaxWidth: true, htmlLabels: true, curve: 'cardinal' }, }); this.mermaidCode = 'asdasdasd'; - if (this.chartContent != 'graph LR;') { - this.chartContent = await this.createMermaidCode(); - //console.log(this.chartContent) + await this.createMermaidCode(); + let docArray: Doc[] = DocListCast(this.Document.data); + let mermaidCodeDoc = docArray.filter(doc => doc.title == 'mermaidCodeTitle') + if(mermaidCodeDoc[0]){ + this.renderMermaidAsync((mermaidCodeDoc[0].text as RichTextField).Text); } - this.renderMermaidAsync(this.chartContent); this.testInkingStroke(); } renderMermaid = async (str: string) => { @@ -135,7 +134,6 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im } async createMermaidCode() { - let mermaidCode = 'graph LR;'; if (this.Document.data instanceof List) { let docArray: Doc[] = DocListCast(this.Document.data); let rectangleArray = docArray.filter(doc => doc.title == 'rectangle' || doc.title == 'circle'); @@ -148,6 +146,7 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im await timeoutPromise(); let inkStrokeArray = lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).filter(inkView => inkView?.ComponentView instanceof InkingStroke); if (inkStrokeArray[0]) { + let mermaidCode = 'graph LR;'; let inkingStrokeArray = inkStrokeArray.map(stroke => stroke?.ComponentView); for (let i = 0; i < rectangleArray.length; i++) { const rectangle = rectangleArray[i]; @@ -177,13 +176,28 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im } } } + DocumentManager.Instance.AddViewRenderedCb(this.Document, (docViewForYourCollection) => { + if (docViewForYourCollection && docViewForYourCollection.ComponentView) { + if (docViewForYourCollection.ComponentView.addDocument&&docViewForYourCollection.ComponentView.removeDocument) { + let docArray: Doc[] = DocListCast(this.Document.data); + let mermaidCodeDoc = docArray.filter(doc => doc.title == 'mermaidCodeTitle') + if(mermaidCodeDoc[0]){ + console.log(mermaidCodeDoc[0].title) + } + docViewForYourCollection.ComponentView?.removeDocument(mermaidCodeDoc) + let newDoc=Docs.Create.TextDocument(mermaidCode, { title: 'mermaidCodeTitle', x: NumCast(this.Document.x) + NumCast(this.layoutDoc._width), y: NumCast(this.Document.y) }) + docViewForYourCollection.ComponentView?.addDocument(newDoc) + } + } + }); } } - this._props.addDocument?.(Docs.Create.TextDocument('asd', { title: 'hellotitle', x: NumCast(this.Document.x) + NumCast(this.layoutDoc._width), y: NumCast(this.Document.y) })); + let docArray: Doc[] = DocListCast(this._props.Document.data) + console.log(docArray.length) + this.Document.data //console.log(mermaidCode) - return mermaidCode; - } + } getTextInBox = (box: Doc, richTextArray: Doc[]): string => { for (let i = 0; i < richTextArray.length; i++) { let textDoc = richTextArray[i]; -- cgit v1.2.3-70-g09d2 From 33fabe4ae82a697e753953af471abdd3aa34e2a2 Mon Sep 17 00:00:00 2001 From: Zachary Zhang Date: Wed, 8 May 2024 10:39:13 -0400 Subject: change to saving mermaid code in text box title --- src/client/views/nodes/DiagramBox.tsx | 51 ++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 18 deletions(-) (limited to 'src/client/views/nodes/DiagramBox.tsx') diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx index c45b9a8be..553d55ac4 100644 --- a/src/client/views/nodes/DiagramBox.tsx +++ b/src/client/views/nodes/DiagramBox.tsx @@ -1,4 +1,4 @@ -import { makeObservable, observable, action } from 'mobx'; +import { makeObservable, observable, action ,reaction} from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; @@ -49,13 +49,25 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im flowchart: { useMaxWidth: true, htmlLabels: true, curve: 'cardinal' }, }); this.mermaidCode = 'asdasdasd'; - await this.createMermaidCode(); let docArray: Doc[] = DocListCast(this.Document.data); let mermaidCodeDoc = docArray.filter(doc => doc.title == 'mermaidCodeTitle') if(mermaidCodeDoc[0]){ this.renderMermaidAsync((mermaidCodeDoc[0].text as RichTextField).Text); } - this.testInkingStroke(); + else{ + DocumentManager.Instance.AddViewRenderedCb(this.Document, (docViewForYourCollection) => { + if (docViewForYourCollection && docViewForYourCollection.ComponentView) { + if (docViewForYourCollection.ComponentView.addDocument&&docViewForYourCollection.ComponentView.removeDocument) { + let newDoc=Docs.Create.TextDocument("mermaidCodeTitle", { title: "", x: 9999 + NumCast(this.layoutDoc._width), y: 9999 }) + docViewForYourCollection.ComponentView?.addDocument(newDoc) + } + } + }); + } + reaction(() => DocListCast(this.Document.data), + docs=> this.createMermaidCode(), + {fireImmediately: true} + ) } renderMermaid = async (str: string) => { try { @@ -134,6 +146,9 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im } async createMermaidCode() { + console.log("i just ran") + let mermaidCode="" + let diagramExists=false if (this.Document.data instanceof List) { let docArray: Doc[] = DocListCast(this.Document.data); let rectangleArray = docArray.filter(doc => doc.title == 'rectangle' || doc.title == 'circle'); @@ -146,7 +161,7 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im await timeoutPromise(); let inkStrokeArray = lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).filter(inkView => inkView?.ComponentView instanceof InkingStroke); if (inkStrokeArray[0]) { - let mermaidCode = 'graph LR;'; + mermaidCode = 'graph LR;'; let inkingStrokeArray = inkStrokeArray.map(stroke => stroke?.ComponentView); for (let i = 0; i < rectangleArray.length; i++) { const rectangle = rectangleArray[i]; @@ -169,6 +184,7 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im for (let k = 0; k < rectangleArray.length; k++) { const rectangle2 = rectangleArray[k]; if (this.isPointInBox(rectangle2, [EndX, EndY]) && typeof rectangle.x === 'number' && typeof rectangle2.x === 'number') { + diagramExists=true mermaidCode += Math.abs(rectangle.x) + this.getTextInBox(rectangle, textArray) + '---' + Math.abs(rectangle2.x) + this.getTextInBox(rectangle2, textArray) + ';'; //console.log(mermaidCode) } @@ -176,25 +192,24 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im } } } - DocumentManager.Instance.AddViewRenderedCb(this.Document, (docViewForYourCollection) => { - if (docViewForYourCollection && docViewForYourCollection.ComponentView) { - if (docViewForYourCollection.ComponentView.addDocument&&docViewForYourCollection.ComponentView.removeDocument) { - let docArray: Doc[] = DocListCast(this.Document.data); - let mermaidCodeDoc = docArray.filter(doc => doc.title == 'mermaidCodeTitle') - if(mermaidCodeDoc[0]){ - console.log(mermaidCodeDoc[0].title) - } - docViewForYourCollection.ComponentView?.removeDocument(mermaidCodeDoc) - let newDoc=Docs.Create.TextDocument(mermaidCode, { title: 'mermaidCodeTitle', x: NumCast(this.Document.x) + NumCast(this.layoutDoc._width), y: NumCast(this.Document.y) }) - docViewForYourCollection.ComponentView?.addDocument(newDoc) + } + } + if(diagramExists){ + DocumentManager.Instance.AddViewRenderedCb(this.Document, (docViewForYourCollection) => { + if (docViewForYourCollection && docViewForYourCollection.ComponentView) { + if (docViewForYourCollection.ComponentView.addDocument&&docViewForYourCollection.ComponentView.removeDocument) { + let docArray: Doc[] = DocListCast(this.Document.data); + docArray=docArray.filter(doc => doc.type == 'rich text') + let mermaidCodeDoc = docArray.filter(doc => (doc.text as RichTextField).Text == 'mermaidCodeTitle') + if(mermaidCodeDoc[0]){ + mermaidCodeDoc[0].title=mermaidCode } } - }); - } + } + }); } let docArray: Doc[] = DocListCast(this._props.Document.data) console.log(docArray.length) - this.Document.data //console.log(mermaidCode) } -- cgit v1.2.3-70-g09d2 From 1af901727a79a6d132875f2468fa25dabbbae894 Mon Sep 17 00:00:00 2001 From: Zachary Zhang Date: Wed, 8 May 2024 18:16:13 -0400 Subject: fix bug with generation of wrong mermaid code --- package-lock.json | 32 +++++++++++-- package.json | 2 +- src/client/views/nodes/DiagramBox.tsx | 85 +++++++++++++++++++++-------------- 3 files changed, 81 insertions(+), 38 deletions(-) (limited to 'src/client/views/nodes/DiagramBox.tsx') diff --git a/package-lock.json b/package-lock.json index 49ff43210..2e191b933 100644 --- a/package-lock.json +++ b/package-lock.json @@ -128,7 +128,7 @@ "mathquill": "^0.10.1-a", "md5-file": "^5.0.0", "memorystream": "^0.3.1", - "mermaid": "^10.8.0", + "mermaid": "^10.9.0", "mobile-detect": "^1.4.5", "mobx": "^6.12.0", "mobx-react": "^9.1.0", @@ -22598,6 +22598,29 @@ "node": ">=12.0.0" } }, + "node_modules/katex": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.10.tgz", + "integrity": "sha512-ZiqaC04tp2O5utMsl2TEZTXxa6WSC4yo0fv5ML++D3QZv/vx2Mct0mTlRx3O+uUkjfuAgOkzsCmq5MiUEsDDdA==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "engines": { + "node": ">= 12" + } + }, "node_modules/kdbush": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz", @@ -23562,9 +23585,9 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" }, "node_modules/mermaid": { - "version": "10.8.0", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-10.8.0.tgz", - "integrity": "sha512-9CzfSreRjdDJxX796+jW4zjEq0DVw5xVF0nWsqff8OTbrt+ml0TZ5PyYUjjUZJa2NYxYJZZXewEquxGiM8qZEA==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-10.9.0.tgz", + "integrity": "sha512-swZju0hFox/B/qoLKK0rOxxgh8Cf7rJSfAUc1u8fezVihYMvrJAS45GzAxTVf4Q+xn9uMgitBcmWk7nWGXOs/g==", "dependencies": { "@braintree/sanitize-url": "^6.0.1", "@types/d3-scale": "^4.0.3", @@ -23577,6 +23600,7 @@ "dayjs": "^1.11.7", "dompurify": "^3.0.5", "elkjs": "^0.9.0", + "katex": "^0.16.9", "khroma": "^2.0.0", "lodash-es": "^4.17.21", "mdast-util-from-markdown": "^1.3.0", diff --git a/package.json b/package.json index ca48bfd0e..78b556fac 100644 --- a/package.json +++ b/package.json @@ -211,7 +211,7 @@ "mathquill": "^0.10.1-a", "md5-file": "^5.0.0", "memorystream": "^0.3.1", - "mermaid": "^10.8.0", + "mermaid": "^10.9.0", "mobile-detect": "^1.4.5", "mobx": "^6.12.0", "mobx-react": "^9.1.0", diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx index 553d55ac4..1b8290652 100644 --- a/src/client/views/nodes/DiagramBox.tsx +++ b/src/client/views/nodes/DiagramBox.tsx @@ -50,9 +50,15 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im }); this.mermaidCode = 'asdasdasd'; let docArray: Doc[] = DocListCast(this.Document.data); - let mermaidCodeDoc = docArray.filter(doc => doc.title == 'mermaidCodeTitle') + let mermaidCodeDoc = docArray.filter(doc => doc.type == 'rich text') + mermaidCodeDoc=mermaidCodeDoc.filter(doc=>(doc.text as RichTextField).Text=='mermaidCodeTitle') if(mermaidCodeDoc[0]){ - this.renderMermaidAsync((mermaidCodeDoc[0].text as RichTextField).Text); + if(typeof mermaidCodeDoc[0].title=='string'){ + console.log(mermaidCodeDoc[0].title) + if(mermaidCodeDoc[0].title!=""){ + this.renderMermaidAsync(mermaidCodeDoc[0].title); + } + } } else{ DocumentManager.Instance.AddViewRenderedCb(this.Document, (docViewForYourCollection) => { @@ -64,10 +70,15 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im } }); } - reaction(() => DocListCast(this.Document.data), - docs=> this.createMermaidCode(), - {fireImmediately: true} - ) + reaction( + () => DocListCast(this.Document.data), + docs => { + console.log("reaction happened") + this.createMermaidCode(); + + }, + { fireImmediately: true } + ); } renderMermaid = async (str: string) => { try { @@ -146,7 +157,6 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im } async createMermaidCode() { - console.log("i just ran") let mermaidCode="" let diagramExists=false if (this.Document.data instanceof List) { @@ -159,34 +169,40 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im setTimeout(resolve, 0); }); await timeoutPromise(); + lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).forEach(inkView => { + const componentView = inkView?.ComponentView; + if (componentView) { + console.log(componentView.constructor.name, componentView); // Print instance type and object + } + }); let inkStrokeArray = lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).filter(inkView => inkView?.ComponentView instanceof InkingStroke); + console.log(lineArray.length) + console.log(inkStrokeArray.length) if (inkStrokeArray[0]) { mermaidCode = 'graph LR;'; let inkingStrokeArray = inkStrokeArray.map(stroke => stroke?.ComponentView); for (let i = 0; i < rectangleArray.length; i++) { const rectangle = rectangleArray[i]; for (let j = 0; j < lineArray.length; j++) { - let inkStrokeXArray = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.map(coord => coord.X); - let inkStrokeYArray = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.map(coord => coord.Y); - let minX: number = Math.min(...inkStrokeXArray); - let minY: number = Math.min(...inkStrokeYArray); let inkScaleX = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleX; let inkScaleY = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleY; - let StartX: number = 0; - let StartY: number = 0; - let EndX: number = 0; - let EndY: number = 0; - StartX = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[j].X * inkScaleX - minX * inkScaleX + (lineArray[j]?.x as number); - StartY = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[j].Y * inkScaleY - minY * inkScaleY + (lineArray[j]?.y as number); - EndX = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.length - 1].X * inkScaleX - minX * inkScaleX + (lineArray[j].x as number); - EndY = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData[(inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.length - 1].Y * inkScaleY - minY * inkScaleY + (lineArray[j].y as number); - if (this.isPointInBox(rectangle, [StartX, StartY])) { + let inkStrokeXArray = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.map(coord => coord.X).map(doc=>doc*inkScaleX); + let inkStrokeYArray = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.map(coord => coord.Y).map(doc=>doc*inkScaleY); + //console.log(inkingStrokeArray.length) + //console.log(lineArray.length) + let minX: number = Math.min(...inkStrokeXArray); + let minY: number = Math.min(...inkStrokeYArray); + let startX = inkStrokeXArray[0] - minX + (lineArray[j]?.x as number); + let startY = inkStrokeYArray[0] - minY + (lineArray[j]?.y as number); + let endX = inkStrokeXArray[inkStrokeXArray.length - 1]- minX + (lineArray[j].x as number); + let endY = inkStrokeYArray[inkStrokeYArray.length - 1]- minY + (lineArray[j].y as number); + if (this.isPointInBox(rectangle, [startX, startY])) { for (let k = 0; k < rectangleArray.length; k++) { const rectangle2 = rectangleArray[k]; - if (this.isPointInBox(rectangle2, [EndX, EndY]) && typeof rectangle.x === 'number' && typeof rectangle2.x === 'number') { + if (this.isPointInBox(rectangle2, [endX, endY]) && typeof rectangle.x === 'number' && typeof rectangle2.x === 'number') { diagramExists=true mermaidCode += Math.abs(rectangle.x) + this.getTextInBox(rectangle, textArray) + '---' + Math.abs(rectangle2.x) + this.getTextInBox(rectangle2, textArray) + ';'; - //console.log(mermaidCode) + } } } @@ -194,25 +210,28 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im } } } - if(diagramExists){ - DocumentManager.Instance.AddViewRenderedCb(this.Document, (docViewForYourCollection) => { - if (docViewForYourCollection && docViewForYourCollection.ComponentView) { - if (docViewForYourCollection.ComponentView.addDocument&&docViewForYourCollection.ComponentView.removeDocument) { - let docArray: Doc[] = DocListCast(this.Document.data); - docArray=docArray.filter(doc => doc.type == 'rich text') - let mermaidCodeDoc = docArray.filter(doc => (doc.text as RichTextField).Text == 'mermaidCodeTitle') - if(mermaidCodeDoc[0]){ + DocumentManager.Instance.AddViewRenderedCb(this.Document, (docViewForYourCollection) => { + if (docViewForYourCollection && docViewForYourCollection.ComponentView) { + if (docViewForYourCollection.ComponentView.addDocument&&docViewForYourCollection.ComponentView.removeDocument) { + let docArray: Doc[] = DocListCast(this.Document.data); + docArray=docArray.filter(doc => doc.type == 'rich text') + let mermaidCodeDoc = docArray.filter(doc => (doc.text as RichTextField).Text == 'mermaidCodeTitle') + if(mermaidCodeDoc[0]){ + if(diagramExists){ mermaidCodeDoc[0].title=mermaidCode } + else{ + mermaidCodeDoc[0].title="" + } } } - }); - } + } + }); let docArray: Doc[] = DocListCast(this._props.Document.data) - console.log(docArray.length) //console.log(mermaidCode) } + getTextInBox = (box: Doc, richTextArray: Doc[]): string => { for (let i = 0; i < richTextArray.length; i++) { let textDoc = richTextArray[i]; -- cgit v1.2.3-70-g09d2 From bd82ad3ebefebd4e8354007568ca27f3e2f13a9b Mon Sep 17 00:00:00 2001 From: Zachary Zhang Date: Fri, 10 May 2024 13:05:24 -0400 Subject: small change in gpt prompty --- src/client/apis/gpt/GPT.ts | 2 +- src/client/views/nodes/DiagramBox.tsx | 38 ++++++++++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 4 deletions(-) (limited to 'src/client/views/nodes/DiagramBox.tsx') diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts index 027c10e28..cde408382 100644 --- a/src/client/apis/gpt/GPT.ts +++ b/src/client/apis/gpt/GPT.ts @@ -19,7 +19,7 @@ const callTypeMap: { [type: string]: GPTCallOpts } = { summary: { model: 'gpt-3.5-turbo-instruct', maxTokens: 256, temp: 0.5, prompt: 'Summarize this text in simpler terms: ' }, edit: { model: 'gpt-3.5-turbo-instruct', maxTokens: 256, temp: 0.5, prompt: 'Reword this: ' }, completion: { model: 'gpt-3.5-turbo-instruct', maxTokens: 256, temp: 0.5, prompt: '' }, - mermaid:{model:'gpt-4-turbo',maxTokens:2048,temp:0,prompt:"Write this in mermaid code and only give me the mermaid code (Heres an example of changing color of a pie chart to help you pie title Example \"Red\": 20 \"Blue\": 50 \"Green\": 30 %%{init: {'theme': 'base', 'themeVariables': {'pie1': '#0000FF', 'pie2': '#00FF00', 'pie3': '#FF0000'}}}%% keep in mind that pie1 is the highest since its sorted in descending order. Heres an example of a mindmap: mindmap root((mindmap)) Origins Long history ::icon(fa fa-book) Popularisation British popular psychology author Tony Buzan Research On effectivness
and features On Automatic creation Uses Creative techniques Strategic planning Argument mapping Tools Pen and paper Mermaid. "} + mermaid:{model:'gpt-4-turbo',maxTokens:2048,temp:0,prompt:"(Heres an example of changing color of a pie chart to help you pie title Example \"Red\": 20 \"Blue\": 50 \"Green\": 30 %%{init: {'theme': 'base', 'themeVariables': {'pie1': '#0000FF', 'pie2': '#00FF00', 'pie3': '#FF0000'}}}%% keep in mind that pie1 is the highest since its sorted in descending order. Heres an example of a mindmap: mindmap root((mindmap)) Origins Long history ::icon(fa fa-book) Popularisation British popular psychology author Tony Buzan Research On effectivness
and features On Automatic creation Uses Creative techniques Strategic planning Argument mapping Tools Pen and paper Mermaid. "} }; diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx index 1b8290652..1813e6097 100644 --- a/src/client/views/nodes/DiagramBox.tsx +++ b/src/client/views/nodes/DiagramBox.tsx @@ -113,11 +113,43 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im // this.htmlCode = modelOutput; this.generateMermaidCode(); }; - @action generateMermaidCode = async () => { + printTitle(){ + let docArray: Doc[] = DocListCast(this.Document.data); + let mermaidCodeDoc = docArray.filter(doc => doc.type == 'rich text') + mermaidCodeDoc=mermaidCodeDoc.filter(doc=>(doc.text as RichTextField).Text=='mermaidCodeTitle') + console.log(mermaidCodeDoc[0].title) + if(mermaidCodeDoc[0]){ + console.log(mermaidCodeDoc[0].title) + if(typeof mermaidCodeDoc[0].title=='string'){ + console.log(mermaidCodeDoc[0].title) + if(mermaidCodeDoc[0].title!=""){ + console.log("you have to see me") + } + } + } + } + @action async generateMermaidCode() { console.log('Generating Mermaid Code'); this.loading = true; - - let res = await gptAPICall(this.inputValue, GPTCallType.MERMAID); + let prompt="" + // let docArray: Doc[] = DocListCast(this.Document.data); + // let mermaidCodeDoc = docArray.filter(doc => doc.type == 'rich text') + // mermaidCodeDoc=mermaidCodeDoc.filter(doc=>(doc.text as RichTextField).Text=='mermaidCodeTitle') + // if(mermaidCodeDoc[0]){ + // console.log(mermaidCodeDoc[0].title) + // if(typeof mermaidCodeDoc[0].title=='string'){ + // console.log(mermaidCodeDoc[0].title) + // if(mermaidCodeDoc[0].title!=""){ + // prompt="Edit this code "+this.inputValue+": "+mermaidCodeDoc[0].title + // console.log("you have to see me") + // } + // } + // } + // else{ + prompt="Write this in mermaid code and only give me the mermaid code: "+this.inputValue + console.log("there is no text save") + //} + let res = await gptAPICall(prompt, GPTCallType.MERMAID); this.loading = false; if (res == 'Error connecting with API.') { // If GPT call failed -- cgit v1.2.3-70-g09d2 From 8c1b420a143e4b72ec551277887c211ca6ca003b Mon Sep 17 00:00:00 2001 From: Zachary Zhang Date: Wed, 15 May 2024 15:26:39 -0400 Subject: add feature to add text onto line --- src/client/views/nodes/DiagramBox.tsx | 122 +++++++++++++++------------------- 1 file changed, 54 insertions(+), 68 deletions(-) (limited to 'src/client/views/nodes/DiagramBox.tsx') diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx index 1813e6097..c69c3d683 100644 --- a/src/client/views/nodes/DiagramBox.tsx +++ b/src/client/views/nodes/DiagramBox.tsx @@ -20,6 +20,8 @@ import { DocumentManager } from '../../util/DocumentManager'; import { C } from '@fullcalendar/core/internal-common'; import { Docs } from '../../documents/Documents'; import { NumCast } from '../../../fields/Types'; +import { LinkManager } from '../../util/LinkManager'; +import { CsvCast, DocCast, StrCast } from '../../../fields/Types'; @observer export class DiagramBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { @@ -60,6 +62,8 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im } } } + //this will create a text doc far away where the user cant to save the mermaid code, where it will then be accessed when flipped to the diagram box side + //the code is stored in the title since it is much easier to change than in the text else{ DocumentManager.Instance.AddViewRenderedCb(this.Document, (docViewForYourCollection) => { if (docViewForYourCollection && docViewForYourCollection.ComponentView) { @@ -70,12 +74,13 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im } }); } + console.log(this.Document.title) + //this is so that ever time a new doc, text node or ink node, is created, this.createMermaidCode will run which will create a save reaction( () => DocListCast(this.Document.data), docs => { console.log("reaction happened") - this.createMermaidCode(); - + this.convertDrawingToMermaidCode(); }, { fireImmediately: true } ); @@ -96,7 +101,7 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im async renderMermaidAsync(mermaidCode: string) { try { const { svg, bindFunctions } = await this.renderMermaid(mermaidCode); - const dashDiv = document.getElementById('dashDiv'); + const dashDiv = document.getElementById('dashDiv'+this.Document.title); if (dashDiv) { dashDiv.innerHTML = svg; if (bindFunctions) { @@ -108,26 +113,8 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im } } @action handleRenderClick = () => { - // Call the GPT model and get the HTML output - // const modelOutput = getHtmlOutput(this.inputValue); - // this.htmlCode = modelOutput; this.generateMermaidCode(); }; - printTitle(){ - let docArray: Doc[] = DocListCast(this.Document.data); - let mermaidCodeDoc = docArray.filter(doc => doc.type == 'rich text') - mermaidCodeDoc=mermaidCodeDoc.filter(doc=>(doc.text as RichTextField).Text=='mermaidCodeTitle') - console.log(mermaidCodeDoc[0].title) - if(mermaidCodeDoc[0]){ - console.log(mermaidCodeDoc[0].title) - if(typeof mermaidCodeDoc[0].title=='string'){ - console.log(mermaidCodeDoc[0].title) - if(mermaidCodeDoc[0].title!=""){ - console.log("you have to see me") - } - } - } - } @action async generateMermaidCode() { console.log('Generating Mermaid Code'); this.loading = true; @@ -172,23 +159,12 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im isValidCode = (html: string) => { return true; }; - testInkingStroke = () => { - if (this.Document.data instanceof List) { - let docArray: Doc[] = DocListCast(this.Document.data); - let lineArray = docArray.filter(doc => doc.title == 'line' || doc.title == 'stroke'); - setTimeout(() => { - let inkStrokeArray = lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).filter(inkView => inkView?.ComponentView instanceof InkingStroke); - console.log(inkStrokeArray); - }); - } - }; - removeWords(inputStr: string) { inputStr = inputStr.replace('```mermaid', ''); return inputStr.replace('```', ''); } - - async createMermaidCode() { + //method to convert the drawings on collection node side the mermaid code + async convertDrawingToMermaidCode() { let mermaidCode="" let diagramExists=false if (this.Document.data instanceof List) { @@ -201,17 +177,11 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im setTimeout(resolve, 0); }); await timeoutPromise(); - lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).forEach(inkView => { - const componentView = inkView?.ComponentView; - if (componentView) { - console.log(componentView.constructor.name, componentView); // Print instance type and object - } - }); let inkStrokeArray = lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).filter(inkView => inkView?.ComponentView instanceof InkingStroke); - console.log(lineArray.length) console.log(inkStrokeArray.length) - if (inkStrokeArray[0]) { - mermaidCode = 'graph LR;'; + console.log(lineArray.length) + if (inkStrokeArray[0]&&inkStrokeArray.length==lineArray.length) { + mermaidCode = 'graph TD;'; let inkingStrokeArray = inkStrokeArray.map(stroke => stroke?.ComponentView); for (let i = 0; i < rectangleArray.length; i++) { const rectangle = rectangleArray[i]; @@ -220,8 +190,9 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im let inkScaleY = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleY; let inkStrokeXArray = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.map(coord => coord.X).map(doc=>doc*inkScaleX); let inkStrokeYArray = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkData.map(coord => coord.Y).map(doc=>doc*inkScaleY); - //console.log(inkingStrokeArray.length) - //console.log(lineArray.length) + console.log(inkingStrokeArray.length) + console.log(lineArray.length) + //need to minX and minY to since the inkStroke.x and.y is not relative to the doc. so I have to do some calcluations let minX: number = Math.min(...inkStrokeXArray); let minY: number = Math.min(...inkStrokeYArray); let startX = inkStrokeXArray[0] - minX + (lineArray[j]?.x as number); @@ -233,37 +204,52 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im const rectangle2 = rectangleArray[k]; if (this.isPointInBox(rectangle2, [endX, endY]) && typeof rectangle.x === 'number' && typeof rectangle2.x === 'number') { diagramExists=true - mermaidCode += Math.abs(rectangle.x) + this.getTextInBox(rectangle, textArray) + '---' + Math.abs(rectangle2.x) + this.getTextInBox(rectangle2, textArray) + ';'; - + const linkedDocs:Doc[] = LinkManager.Instance.getAllRelatedLinks(lineArray[j]) + .map(d => DocCast(LinkManager.getOppositeAnchor(d, lineArray[j]))) + console.log(linkedDocs.length) + if(linkedDocs.length!=0){ + let linkedText=((linkedDocs[0].text as RichTextField).Text) + mermaidCode += Math.abs(rectangle.x) + this.getTextInBox(rectangle, textArray) + '-->|'+linkedText+"|" + Math.abs(rectangle2.x) + this.getTextInBox(rectangle2, textArray) + ';'; + } + else{ + mermaidCode += Math.abs(rectangle.x) + this.getTextInBox(rectangle, textArray) + '-->' + Math.abs(rectangle2.x) + this.getTextInBox(rectangle2, textArray) + ';'; + } } } } } } - } - } - DocumentManager.Instance.AddViewRenderedCb(this.Document, (docViewForYourCollection) => { - if (docViewForYourCollection && docViewForYourCollection.ComponentView) { - if (docViewForYourCollection.ComponentView.addDocument&&docViewForYourCollection.ComponentView.removeDocument) { - let docArray: Doc[] = DocListCast(this.Document.data); - docArray=docArray.filter(doc => doc.type == 'rich text') - let mermaidCodeDoc = docArray.filter(doc => (doc.text as RichTextField).Text == 'mermaidCodeTitle') - if(mermaidCodeDoc[0]){ - if(diagramExists){ - mermaidCodeDoc[0].title=mermaidCode - } - else{ - mermaidCodeDoc[0].title="" + //this will save the text + DocumentManager.Instance.AddViewRenderedCb(this.Document, (docViewForYourCollection) => { + if (docViewForYourCollection && docViewForYourCollection.ComponentView) { + if (docViewForYourCollection.ComponentView.addDocument&&docViewForYourCollection.ComponentView.removeDocument) { + let docArray: Doc[] = DocListCast(this.Document.data); + docArray=docArray.filter(doc => doc.type == 'rich text') + let mermaidCodeDoc = docArray.filter(doc => (doc.text as RichTextField).Text == 'mermaidCodeTitle') + if(mermaidCodeDoc[0]){ + if(diagramExists){ + mermaidCodeDoc[0].title=mermaidCode + } + else{ + mermaidCodeDoc[0].title="" + } + } } } - } + }); } - }); - let docArray: Doc[] = DocListCast(this._props.Document.data) - //console.log(mermaidCode) - + } } - + testInkingStroke = () => { + if (this.Document.data instanceof List) { + let docArray: Doc[] = DocListCast(this.Document.data); + let lineArray = docArray.filter(doc => doc.title == 'line' || doc.title == 'stroke'); + setTimeout(() => { + let inkStrokeArray = lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).filter(inkView => inkView?.ComponentView instanceof InkingStroke); + console.log(inkStrokeArray); + }); + } + }; getTextInBox = (box: Doc, richTextArray: Doc[]): string => { for (let i = 0; i < richTextArray.length; i++) { let textDoc = richTextArray[i]; @@ -298,7 +284,7 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im
{this.mermaidCode ? ( -
+
) : (
{this.loading ?
:
{this.errorMessage ? this.errorMessage : 'Insert prompt to generate diagram'}
}
)} -- cgit v1.2.3-70-g09d2 From f51ce092018a8b452d5e178ddd2a1e5a2c38cc77 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 20 May 2024 16:25:06 -0400 Subject: lint cleanup for diagrams. reorg of some gpt stuff. --- src/client/apis/gpt/GPT.ts | 26 +----- src/client/apis/gpt/PresCustomization.ts | 133 +++++++++++++++++++++++++++ src/client/apis/gpt/customization.ts | 133 --------------------------- src/client/apis/gpt/setup.ts | 23 ----- src/client/views/nodes/DiagramBox.tsx | 150 ++++++++++++++----------------- src/client/views/pdf/AnchorMenu.tsx | 5 +- 6 files changed, 204 insertions(+), 266 deletions(-) create mode 100644 src/client/apis/gpt/PresCustomization.ts delete mode 100644 src/client/apis/gpt/customization.ts (limited to 'src/client/views/nodes/DiagramBox.tsx') diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts index cca9d58f3..05007960d 100644 --- a/src/client/apis/gpt/GPT.ts +++ b/src/client/apis/gpt/GPT.ts @@ -1,5 +1,5 @@ -import { ClientOptions, OpenAI } from 'openai'; import { ChatCompletionMessageParam } from 'openai/resources'; +import { openai } from './setup'; enum GPTCallType { SUMMARY = 'summary', @@ -68,12 +68,7 @@ const gptAPICall = async (inputTextIn: string, callType: GPTCallType, prompt?: a const opts: GPTCallOpts = callTypeMap[callType]; if (lastCall === inputText) return lastResp; try { - const configuration: ClientOptions = { - apiKey: process.env.OPENAI_KEY, - dangerouslyAllowBrowser: true, - }; lastCall = inputText; - const openai = new OpenAI(configuration); const usePrompt = prompt ? opts.prompt + prompt : opts.prompt; const messages: ChatCompletionMessageParam[] = [ @@ -96,12 +91,6 @@ const gptAPICall = async (inputTextIn: string, callType: GPTCallType, prompt?: a }; const gptImageCall = async (prompt: string, n?: number) => { try { - const configuration: ClientOptions = { - apiKey: process.env.OPENAI_KEY, - dangerouslyAllowBrowser: true, - }; - - const openai = new OpenAI(configuration); const response = await openai.images.generate({ prompt: prompt, n: n ?? 1, @@ -114,14 +103,8 @@ const gptImageCall = async (prompt: string, n?: number) => { } return undefined; }; - const gptGetEmbedding = async (src: string): Promise => { try { - const configuration: ClientOptions = { - apiKey: process.env.OPENAI_KEY, - dangerouslyAllowBrowser: true, - }; - const openai = new OpenAI(configuration); const embeddingResponse = await openai.embeddings.create({ model: 'text-embedding-3-large', input: [src], @@ -137,15 +120,8 @@ const gptGetEmbedding = async (src: string): Promise => { return []; } }; - const gptImageLabel = async (src: string): Promise => { try { - const configuration: ClientOptions = { - apiKey: process.env.OPENAI_KEY, - dangerouslyAllowBrowser: true, - }; - - const openai = new OpenAI(configuration); const response = await openai.chat.completions.create({ model: 'gpt-4o', messages: [ diff --git a/src/client/apis/gpt/PresCustomization.ts b/src/client/apis/gpt/PresCustomization.ts new file mode 100644 index 000000000..2262886a2 --- /dev/null +++ b/src/client/apis/gpt/PresCustomization.ts @@ -0,0 +1,133 @@ +import { openai } from './setup'; + +export enum CustomizationType { + PRES_TRAIL_SLIDE = 'trails', +} + +interface PromptInfo { + description: string; + features: { name: string; description: string; values?: string[] }[]; +} +const prompts: { [key: string]: PromptInfo } = { + trails: { + description: + 'We are customizing the properties and transition of a slide in a presentation. You are given the current properties of the slide in a json with the fields [title, presentation_transition, presentation_effect, config_zoom, presentation_effectDirection], as well as the prompt for how the user wants to change it. Return a json with the required fields: [title, presentation_transition, presentation_effect, config_zoom, presentation_effectDirection] by applying the changes in the prompt to the current state of the slide.', + features: [], + }, +}; + +// Allows you to register properties that are customizable +export const addCustomizationProperty = (type: CustomizationType, name: string, description: string, values?: string[]) => { + values ? prompts[type].features.push({ name, description, values }) : prompts[type].features.push({ name, description }); +}; + +// All the registered fields, make sure to update during registration, this +// includes most fields but is not yet fully comprehensive +export const gptSlideProperties = [ + 'title', + 'config_zoom', + 'presentation_transition', + 'presentation_easeFunc', + 'presentation_effect', + 'presentation_effectDirection', + 'presentation_effectTiming', + 'presentation_playAudio', + 'presentation_zoomText', + 'presentation_hideBefore', + 'presentation_hide', + 'presentation_hideAfter', + 'presentation_openInLightbox', +]; + +// Registers slide properties +const setupPresSlideCustomization = () => { + addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'title', 'is the title/name of the slide.'); + addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_transition', 'is a number in milliseconds for how long it should take to transition/move to a slide.'); + addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_easeFunc', 'is the easing function for the movement to the slide.', ['Ease', 'Ease In', 'Ease Out', 'Ease Out', 'Ease In Out', 'Linear']); + + addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_effect', 'is an effect applied to the slide when we transition to it.', ['None', 'Expand', 'Fade in', 'Bounce', 'Flip', 'Rotate', 'Roll']); + addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_effectDirection', 'is what direction the effect is applied.', ['Enter from left', 'Enter from right', 'Enter from bottom', 'Enter from Top', 'Enter from center']); + addCustomizationProperty( + CustomizationType.PRES_TRAIL_SLIDE, + 'presentation_effectTiming', + "is a json object of the format: {type: string, stiffness: number, damping: number, mass: number}. Type is always “custom”. Controls the spring-based timing of the presentation effect animation. 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 match the user's description of how they want to animate the effect." + ); + + addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'config_zoom', 'is a number from 0 to 1.0 indicating the percentage we should zoom into the slide.'); + + // boolean values + addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_playAudio', 'is a boolean value indicating if we should play audio when we go to the slide.'); + addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_zoomText', 'is a boolean value indicating if we should zoom into text selections when we go to the slide.'); + addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_hideBefore', 'is a boolean value indicating if we should hide the slide before going to it.'); + addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_hide', 'is a boolean value indicating if we should hide the slide during the presentation.'); + addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_hideAfter', 'is a boolean value indicating if we should hide the slide after going to it.'); + addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_openInLightbox', 'is a boolean value indicating if we should open the slide in an overlay or lightbox view during the presentation.'); +}; + +setupPresSlideCustomization(); + +export const getSlideTransitionSuggestions = async (inputText: string) => { + /** + * Prompt: Generate an entrance animations from slower and gentler + * to bouncier and more high energy + * + * Format: + * { + * name: Slow Fade, Quick Flip, Springy + * effect: BOUNCE + * effectDirection: LEFT + * timingConfig: { + * } + * } + */ + + const prompt = + "I want to generate four distinct types of slide effect animations. Return a json of the form {effect: string, direction: string, stiffness: number, damping: number, mass: number}[] with four elements. Effect is the type of animation; its only possible values are ['Expand', 'Fade in', 'Bounce', 'Flip', 'Rotate', 'Roll']. Direction is the direction that the animation starts from; its only possible values are ['Enter from left', 'Enter from right', 'Enter from bottom', 'Enter from Top', 'Enter from center']. 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[]) => { + let prompt = prompts.trails.description; + + prompts.trails.features.forEach(feature => { + prompt += feature.name + ' ' + feature.description; + if (feature.values) { + prompt += `Its only possible values are [${feature.values.join(', ')}].`; + } + }); + + prompt += 'Set unchanged values to null and make sure you include new properties if they are specified in the prompt even if they do not exist in current properties. Please only return the json with the keys described and their values.'; + + try { + const response = await openai.chat.completions.create({ + model: 'gpt-4', + messages: [ + { role: 'system', content: prompt }, + { role: 'user', content: `Prompt: ${inputText}, Current properties: ${JSON.stringify(properties)}` }, + ], + temperature: 0, + max_tokens: 1000, + }); + return response.choices[0].message?.content; + } catch (err) { + console.log(err); + return 'Error connecting with API.'; + } +}; diff --git a/src/client/apis/gpt/customization.ts b/src/client/apis/gpt/customization.ts deleted file mode 100644 index 2262886a2..000000000 --- a/src/client/apis/gpt/customization.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { openai } from './setup'; - -export enum CustomizationType { - PRES_TRAIL_SLIDE = 'trails', -} - -interface PromptInfo { - description: string; - features: { name: string; description: string; values?: string[] }[]; -} -const prompts: { [key: string]: PromptInfo } = { - trails: { - description: - 'We are customizing the properties and transition of a slide in a presentation. You are given the current properties of the slide in a json with the fields [title, presentation_transition, presentation_effect, config_zoom, presentation_effectDirection], as well as the prompt for how the user wants to change it. Return a json with the required fields: [title, presentation_transition, presentation_effect, config_zoom, presentation_effectDirection] by applying the changes in the prompt to the current state of the slide.', - features: [], - }, -}; - -// Allows you to register properties that are customizable -export const addCustomizationProperty = (type: CustomizationType, name: string, description: string, values?: string[]) => { - values ? prompts[type].features.push({ name, description, values }) : prompts[type].features.push({ name, description }); -}; - -// All the registered fields, make sure to update during registration, this -// includes most fields but is not yet fully comprehensive -export const gptSlideProperties = [ - 'title', - 'config_zoom', - 'presentation_transition', - 'presentation_easeFunc', - 'presentation_effect', - 'presentation_effectDirection', - 'presentation_effectTiming', - 'presentation_playAudio', - 'presentation_zoomText', - 'presentation_hideBefore', - 'presentation_hide', - 'presentation_hideAfter', - 'presentation_openInLightbox', -]; - -// Registers slide properties -const setupPresSlideCustomization = () => { - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'title', 'is the title/name of the slide.'); - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_transition', 'is a number in milliseconds for how long it should take to transition/move to a slide.'); - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_easeFunc', 'is the easing function for the movement to the slide.', ['Ease', 'Ease In', 'Ease Out', 'Ease Out', 'Ease In Out', 'Linear']); - - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_effect', 'is an effect applied to the slide when we transition to it.', ['None', 'Expand', 'Fade in', 'Bounce', 'Flip', 'Rotate', 'Roll']); - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_effectDirection', 'is what direction the effect is applied.', ['Enter from left', 'Enter from right', 'Enter from bottom', 'Enter from Top', 'Enter from center']); - addCustomizationProperty( - CustomizationType.PRES_TRAIL_SLIDE, - 'presentation_effectTiming', - "is a json object of the format: {type: string, stiffness: number, damping: number, mass: number}. Type is always “custom”. Controls the spring-based timing of the presentation effect animation. 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 match the user's description of how they want to animate the effect." - ); - - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'config_zoom', 'is a number from 0 to 1.0 indicating the percentage we should zoom into the slide.'); - - // boolean values - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_playAudio', 'is a boolean value indicating if we should play audio when we go to the slide.'); - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_zoomText', 'is a boolean value indicating if we should zoom into text selections when we go to the slide.'); - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_hideBefore', 'is a boolean value indicating if we should hide the slide before going to it.'); - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_hide', 'is a boolean value indicating if we should hide the slide during the presentation.'); - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_hideAfter', 'is a boolean value indicating if we should hide the slide after going to it.'); - addCustomizationProperty(CustomizationType.PRES_TRAIL_SLIDE, 'presentation_openInLightbox', 'is a boolean value indicating if we should open the slide in an overlay or lightbox view during the presentation.'); -}; - -setupPresSlideCustomization(); - -export const getSlideTransitionSuggestions = async (inputText: string) => { - /** - * Prompt: Generate an entrance animations from slower and gentler - * to bouncier and more high energy - * - * Format: - * { - * name: Slow Fade, Quick Flip, Springy - * effect: BOUNCE - * effectDirection: LEFT - * timingConfig: { - * } - * } - */ - - const prompt = - "I want to generate four distinct types of slide effect animations. Return a json of the form {effect: string, direction: string, stiffness: number, damping: number, mass: number}[] with four elements. Effect is the type of animation; its only possible values are ['Expand', 'Fade in', 'Bounce', 'Flip', 'Rotate', 'Roll']. Direction is the direction that the animation starts from; its only possible values are ['Enter from left', 'Enter from right', 'Enter from bottom', 'Enter from Top', 'Enter from center']. 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[]) => { - let prompt = prompts.trails.description; - - prompts.trails.features.forEach(feature => { - prompt += feature.name + ' ' + feature.description; - if (feature.values) { - prompt += `Its only possible values are [${feature.values.join(', ')}].`; - } - }); - - prompt += 'Set unchanged values to null and make sure you include new properties if they are specified in the prompt even if they do not exist in current properties. Please only return the json with the keys described and their values.'; - - try { - const response = await openai.chat.completions.create({ - model: 'gpt-4', - messages: [ - { role: 'system', content: prompt }, - { role: 'user', content: `Prompt: ${inputText}, Current properties: ${JSON.stringify(properties)}` }, - ], - temperature: 0, - max_tokens: 1000, - }); - return response.choices[0].message?.content; - } catch (err) { - console.log(err); - return 'Error connecting with API.'; - } -}; diff --git a/src/client/apis/gpt/setup.ts b/src/client/apis/gpt/setup.ts index 7084f38bf..f648542f2 100644 --- a/src/client/apis/gpt/setup.ts +++ b/src/client/apis/gpt/setup.ts @@ -1,31 +1,8 @@ -// import { Configuration, OpenAIApi } from 'openai'; import { ClientOptions, OpenAI } from 'openai'; -export enum GPTCallType { - SUMMARY = 'summary', - COMPLETION = 'completion', - EDIT = 'edit', - FLASHCARD = 'flashcard', -} - -export type GPTCallOpts = { - model: string; - maxTokens: number; - temp: number; - prompt: string; -}; - -export const callTypeMap: { [type: string]: GPTCallOpts } = { - summary: { model: 'text-davinci-003', maxTokens: 256, temp: 0.5, prompt: 'Summarize this text in simpler terms: ' }, - edit: { model: 'text-davinci-003', maxTokens: 256, temp: 0.5, prompt: 'Reword this: ' }, - completion: { model: 'text-davinci-003', maxTokens: 256, temp: 0.5, prompt: '' }, -}; - const configuration: ClientOptions = { apiKey: process.env.OPENAI_KEY, dangerouslyAllowBrowser: true, }; export const openai = new OpenAI(configuration); - -// export const openai = new OpenAIApi(configuration); diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx index fa7e5868a..32969fa53 100644 --- a/src/client/views/nodes/DiagramBox.tsx +++ b/src/client/views/nodes/DiagramBox.tsx @@ -1,31 +1,23 @@ -import { makeObservable, observable, action, reaction } from 'mobx'; +import mermaid from 'mermaid'; +import { action, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; -import { StyleProp } from '../StyleProvider'; -import './DiagramBox.scss'; -import { FieldView, FieldViewProps } from './FieldView'; -import { PinProps, PresBox } from './trails'; -import mermaid from 'mermaid'; import { Doc, DocListCast } from '../../../fields/Doc'; import { List } from '../../../fields/List'; import { RichTextField } from '../../../fields/RichTextField'; -import { ContextMenu } from '../ContextMenu'; -import { gptAPICall, GPTCallType } from '../../apis/gpt/GPT'; -import { ChatCompletionMessageParam } from 'openai/resources/chat/completions'; -import OpenAI, { ClientOptions } from 'openai'; -import { line } from 'd3'; -import { InkingStroke } from '../InkingStroke'; -import { DocumentManager } from '../../util/DocumentManager'; -import { C } from '@fullcalendar/core/internal-common'; +import { DocCast, NumCast } from '../../../fields/Types'; +import { GPTCallType, gptAPICall } from '../../apis/gpt/GPT'; +import { DocumentType } from '../../documents/DocumentTypes'; import { Docs } from '../../documents/Documents'; -import { NumCast } from '../../../fields/Types'; +import { DocumentManager } from '../../util/DocumentManager'; import { LinkManager } from '../../util/LinkManager'; -import { CsvCast, DocCast, StrCast } from '../../../fields/Types'; -import { DocumentType } from '../../documents/DocumentTypes'; +import { ViewBoxAnnotatableComponent } from '../DocComponent'; +import { InkingStroke } from '../InkingStroke'; +import './DiagramBox.scss'; +import { FieldView, FieldViewProps } from './FieldView'; @observer -export class DiagramBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { +export class DiagramBox extends ViewBoxAnnotatableComponent() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(DiagramBox, fieldKey); } @@ -52,37 +44,34 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im flowchart: { useMaxWidth: true, htmlLabels: true, curve: 'cardinal' }, }); this.mermaidCode = 'asdasdasd'; - let docArray: Doc[] = DocListCast(this.Document.data); - let mermaidCodeDoc = docArray.filter(doc => doc.type == 'rich text'); - mermaidCodeDoc = mermaidCodeDoc.filter(doc => (doc.text as RichTextField).Text == 'mermaidCodeTitle'); + const docArray: Doc[] = DocListCast(this.Document.data); + let mermaidCodeDoc = docArray.filter(doc => doc.type === 'rich text'); + mermaidCodeDoc = mermaidCodeDoc.filter(doc => (doc.text as RichTextField).Text === 'mermaidCodeTitle'); if (mermaidCodeDoc[0]) { - if (typeof mermaidCodeDoc[0].title == 'string') { + if (typeof mermaidCodeDoc[0].title === 'string') { console.log(mermaidCodeDoc[0].title); - if (mermaidCodeDoc[0].title != '') { + if (mermaidCodeDoc[0].title !== '') { this.renderMermaidAsync(mermaidCodeDoc[0].title); } } } - //this will create a text doc far away where the user cant to save the mermaid code, where it will then be accessed when flipped to the diagram box side - //the code is stored in the title since it is much easier to change than in the text + // this will create a text doc far away where the user cant to save the mermaid code, where it will then be accessed when flipped to the diagram box side + // the code is stored in the title since it is much easier to change than in the text else { DocumentManager.Instance.AddViewRenderedCb(this.Document, docViewForYourCollection => { if (docViewForYourCollection && docViewForYourCollection.ComponentView) { if (docViewForYourCollection.ComponentView.addDocument && docViewForYourCollection.ComponentView.removeDocument) { - let newDoc = Docs.Create.TextDocument('mermaidCodeTitle', { title: '', x: 9999 + NumCast(this.layoutDoc._width), y: 9999 }); + const newDoc = Docs.Create.TextDocument('mermaidCodeTitle', { title: '', x: 9999 + NumCast(this.layoutDoc._width), y: 9999 }); docViewForYourCollection.ComponentView?.addDocument(newDoc); } } }); } console.log(this.Document.title); - //this is so that ever time a new doc, text node or ink node, is created, this.createMermaidCode will run which will create a save + // this is so that ever time a new doc, text node or ink node, is created, this.createMermaidCode will run which will create a save reaction( () => DocListCast(this.Document.data), - docs => { - console.log('reaction happened'); - this.convertDrawingToMermaidCode(); - }, + () => this.convertDrawingToMermaidCode(), { fireImmediately: true } ); } @@ -95,9 +84,7 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im return { svg: '', bindFunctions: undefined }; } }; - mermaidDiagram = async (str: string) => { - return await mermaid.render('graph' + Date.now(), str); - }; + mermaidDiagram = async (str: string) => mermaid.render('graph' + Date.now(), str); async renderMermaidAsync(mermaidCode: string) { try { @@ -136,14 +123,14 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im // else{ prompt = 'Write this in mermaid code and only give me the mermaid code: ' + this.inputValue; console.log('there is no text save'); - //} - let res = await gptAPICall(prompt, GPTCallType.MERMAID); + // } + const res = await gptAPICall(prompt, GPTCallType.MERMAID); this.loading = false; - if (res == 'Error connecting with API.') { + if (res === 'Error connecting with API.') { // If GPT call failed console.error('GPT call failed'); this.errorMessage = 'GPT call failed; please try again.'; - } else if (res != null) { + } else if (res !== null) { // If GPT call succeeded, set htmlCode;;; TODO: check if valid html if (this.isValidCode(res)) { this.mermaidCode = res; @@ -157,55 +144,53 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im this.renderMermaidAsync.call(this, this.removeWords(this.mermaidCode)); this.loading = false; } - isValidCode = (html: string) => { - return true; - }; - removeWords(inputStr: string) { - inputStr = inputStr.replace('```mermaid', ''); + isValidCode = (html: string) => true; + removeWords(inputStrIn: string) { + const inputStr = inputStrIn.replace('```mermaid', ''); return inputStr.replace('```', ''); } - //method to convert the drawings on collection node side the mermaid code + // method to convert the drawings on collection node side the mermaid code async convertDrawingToMermaidCode() { let mermaidCode = ''; let diagramExists = false; if (this.Document.data instanceof List) { - let docArray: Doc[] = DocListCast(this.Document.data); - let rectangleArray = docArray.filter(doc => doc.title == 'rectangle' || doc.title == 'circle'); - let lineArray = docArray.filter(doc => doc.title == 'line' || doc.title == 'stroke'); - let textArray = docArray.filter(doc => doc.type == 'rich text'); + const docArray: Doc[] = DocListCast(this.Document.data); + const rectangleArray = docArray.filter(doc => doc.title === 'rectangle' || doc.title === 'circle'); + const lineArray = docArray.filter(doc => doc.title === 'line' || doc.title === 'stroke'); + const textArray = docArray.filter(doc => doc.type === 'rich text'); const timeoutPromise = () => new Promise(resolve => { setTimeout(resolve, 0); }); await timeoutPromise(); - let inkStrokeArray = lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).filter(inkView => inkView?.ComponentView instanceof InkingStroke); + const inkStrokeArray = lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).filter(inkView => inkView?.ComponentView instanceof InkingStroke); console.log(inkStrokeArray.length); console.log(lineArray.length); - if (inkStrokeArray[0] && inkStrokeArray.length == lineArray.length) { + if (inkStrokeArray[0] && inkStrokeArray.length === lineArray.length) { mermaidCode = 'graph TD;'; - let inkingStrokeArray = inkStrokeArray.map(stroke => stroke?.ComponentView); + const inkingStrokeArray = inkStrokeArray.map(stroke => stroke?.ComponentView); for (let i = 0; i < rectangleArray.length; i++) { const rectangle = rectangleArray[i]; for (let j = 0; j < lineArray.length; j++) { - let inkScaleX = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleX; - let inkScaleY = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleY; - let inkStrokeXArray = (inkingStrokeArray[j] as InkingStroke) + const inkScaleX = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleX; + const inkScaleY = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleY; + const inkStrokeXArray = (inkingStrokeArray[j] as InkingStroke) ?.inkScaledData() .inkData.map(coord => coord.X) .map(doc => doc * inkScaleX); - let inkStrokeYArray = (inkingStrokeArray[j] as InkingStroke) + const inkStrokeYArray = (inkingStrokeArray[j] as InkingStroke) ?.inkScaledData() .inkData.map(coord => coord.Y) .map(doc => doc * inkScaleY); console.log(inkingStrokeArray.length); console.log(lineArray.length); - //need to minX and minY to since the inkStroke.x and.y is not relative to the doc. so I have to do some calcluations - let minX: number = Math.min(...inkStrokeXArray); - let minY: number = Math.min(...inkStrokeYArray); - let startX = inkStrokeXArray[0] - minX + (lineArray[j]?.x as number); - let startY = inkStrokeYArray[0] - minY + (lineArray[j]?.y as number); - let endX = inkStrokeXArray[inkStrokeXArray.length - 1] - minX + (lineArray[j].x as number); - let endY = inkStrokeYArray[inkStrokeYArray.length - 1] - minY + (lineArray[j].y as number); + // need to minX and minY to since the inkStroke.x and.y is not relative to the doc. so I have to do some calcluations + const minX: number = Math.min(...inkStrokeXArray); + const minY: number = Math.min(...inkStrokeYArray); + const startX = inkStrokeXArray[0] - minX + (lineArray[j]?.x as number); + const startY = inkStrokeYArray[0] - minY + (lineArray[j]?.y as number); + const endX = inkStrokeXArray[inkStrokeXArray.length - 1] - minX + (lineArray[j].x as number); + const endY = inkStrokeYArray[inkStrokeYArray.length - 1] - minY + (lineArray[j].y as number); if (this.isPointInBox(rectangle, [startX, startY])) { for (let k = 0; k < rectangleArray.length; k++) { const rectangle2 = rectangleArray[k]; @@ -213,8 +198,8 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im diagramExists = true; const linkedDocs: Doc[] = LinkManager.Instance.getAllRelatedLinks(lineArray[j]).map(d => DocCast(LinkManager.getOppositeAnchor(d, lineArray[j]))); console.log(linkedDocs.length); - if (linkedDocs.length != 0) { - let linkedText = (linkedDocs[0].text as RichTextField).Text; + if (linkedDocs.length !== 0) { + const linkedText = (linkedDocs[0].text as RichTextField).Text; mermaidCode += Math.abs(rectangle.x) + this.getTextInBox(rectangle, textArray) + '-->|' + linkedText + '|' + Math.abs(rectangle2.x) + this.getTextInBox(rectangle2, textArray) + ';'; } else { mermaidCode += Math.abs(rectangle.x) + this.getTextInBox(rectangle, textArray) + '-->' + Math.abs(rectangle2.x) + this.getTextInBox(rectangle2, textArray) + ';'; @@ -224,13 +209,13 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im } } } - //this will save the text + // this will save the text DocumentManager.Instance.AddViewRenderedCb(this.Document, docViewForYourCollection => { if (docViewForYourCollection && docViewForYourCollection.ComponentView) { if (docViewForYourCollection.ComponentView.addDocument && docViewForYourCollection.ComponentView.removeDocument) { - let docArray: Doc[] = DocListCast(this.Document.data); - docArray = docArray.filter(doc => doc.type == 'rich text'); - let mermaidCodeDoc = docArray.filter(doc => (doc.text as RichTextField).Text == 'mermaidCodeTitle'); + let docs: Doc[] = DocListCast(this.Document.data); + docs = docs.filter(doc => doc.type === 'rich text'); + const mermaidCodeDoc = docs.filter(doc => (doc.text as RichTextField).Text === 'mermaidCodeTitle'); if (mermaidCodeDoc[0]) { if (diagramExists) { mermaidCodeDoc[0].title = mermaidCode; @@ -246,24 +231,24 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im } testInkingStroke = () => { if (this.Document.data instanceof List) { - let docArray: Doc[] = DocListCast(this.Document.data); - let lineArray = docArray.filter(doc => doc.title == 'line' || doc.title == 'stroke'); + const docArray: Doc[] = DocListCast(this.Document.data); + const lineArray = docArray.filter(doc => doc.title === 'line' || doc.title === 'stroke'); setTimeout(() => { - let inkStrokeArray = lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).filter(inkView => inkView?.ComponentView instanceof InkingStroke); + const inkStrokeArray = lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).filter(inkView => inkView?.ComponentView instanceof InkingStroke); console.log(inkStrokeArray); }); } }; getTextInBox = (box: Doc, richTextArray: Doc[]): string => { for (let i = 0; i < richTextArray.length; i++) { - let textDoc = richTextArray[i]; + const textDoc = richTextArray[i]; if (typeof textDoc.x === 'number' && typeof textDoc.y === 'number' && typeof box.x === 'number' && typeof box.height === 'number' && typeof box.width === 'number' && typeof box.y === 'number') { if (textDoc.x > box.x && textDoc.x < box.x + box.width && textDoc.y > box.y && textDoc.y < box.y + box.height) { - if (box.title == 'rectangle') { - return '(' + (textDoc.text as RichTextField)?.Text + ')'; + if (box.title === 'rectangle') { + return '(' + ((textDoc.text as RichTextField)?.Text ?? '') + ')'; } - if (box.title == 'circle') { - return '((' + (textDoc.text as RichTextField)?.Text + '))'; + if (box.title === 'circle') { + return '((' + ((textDoc.text as RichTextField)?.Text ?? '') + '))'; } } } @@ -273,9 +258,8 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im isPointInBox = (box: Doc, line: number[]): boolean => { if (typeof line[0] === 'number' && typeof box.x === 'number' && typeof box.width === 'number' && typeof box.height === 'number' && typeof box.y === 'number' && typeof line[1] === 'number') { return line[0] < box.x + box.width && line[0] > box.x && line[1] > box.y && line[1] < box.y + box.height; - } else { - return false; } + return false; }; render() { @@ -284,13 +268,15 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() im
- +
{this.mermaidCode ? ( -
+
) : ( -
{this.loading ?
:
{this.errorMessage ? this.errorMessage : 'Insert prompt to generate diagram'}
}
+
{this.loading ?
:
{this.errorMessage ? this.errorMessage : 'Insert prompt to generate diagram'}
}
)}
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index 745e809db..2f6824466 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -7,15 +7,14 @@ import { ColorResult } from 'react-color'; import { ClientUtils, returnFalse, setupMoveUpEvents } from '../../../ClientUtils'; import { emptyFunction, unimplementedFunction } from '../../../Utils'; import { Doc, Opt } from '../../../fields/Doc'; -import { gptAPICall } from '../../apis/gpt/GPT'; -import { GPTCallType } from '../../apis/gpt/setup'; +import { GPTCallType, gptAPICall } from '../../apis/gpt/GPT'; +import { Docs } from '../../documents/Documents'; import { SettingsManager } from '../../util/SettingsManager'; import { AntimodeMenu, AntimodeMenuProps } from '../AntimodeMenu'; import { LinkPopup } from '../linking/LinkPopup'; import { DocumentView } from '../nodes/DocumentView'; import './AnchorMenu.scss'; import { GPTPopup, GPTPopupMode } from './GPTPopup/GPTPopup'; -import { Docs } from '../../documents/Documents'; @observer export class AnchorMenu extends AntimodeMenu { -- cgit v1.2.3-70-g09d2