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') 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