diff options
| author | bobzel <zzzman@gmail.com> | 2025-06-23 13:26:59 -0400 |
|---|---|---|
| committer | bobzel <zzzman@gmail.com> | 2025-06-23 13:26:59 -0400 |
| commit | 35bd9e51f7cef551382025a5459d68eddd8f028b (patch) | |
| tree | 8edab8e8e283d06bdeba632959fd51e1488c4af5 /src/client/views/InkTranscription.tsx | |
| parent | e7a96fa043cfc9c3c426e09bbef42c8df88a45f6 (diff) | |
fixed invalidations to not trigger creating new refs when ref= was assigned to an anonymous function. fixed scribble erase to not delete everything it overlaps, just things it intersects with or contains. fixed ink to have a Math mode and fixed math recognition myscript calls.
Diffstat (limited to 'src/client/views/InkTranscription.tsx')
| -rw-r--r-- | src/client/views/InkTranscription.tsx | 182 |
1 files changed, 94 insertions, 88 deletions
diff --git a/src/client/views/InkTranscription.tsx b/src/client/views/InkTranscription.tsx index 6220033d4..32ca5f56b 100644 --- a/src/client/views/InkTranscription.tsx +++ b/src/client/views/InkTranscription.tsx @@ -32,7 +32,7 @@ export class InkTranscription extends React.Component { // eslint-disable-next-line @typescript-eslint/no-explicit-any @observable _iinkEditor: any = undefined; // eslint-disable-next-line @typescript-eslint/no-explicit-any - private lastJiix: any; + @observable _iinkMathEditor: any = undefined; private currGroup?: Doc; private collectionFreeForm?: CollectionFreeFormView; @@ -44,7 +44,7 @@ export class InkTranscription extends React.Component { @action // eslint-disable-next-line @typescript-eslint/no-explicit-any setMathRef = async (r: any) => { - if (!this._textRegister && r) { + if (!this._mathRegister && r) { const options = { configuration: { server: { @@ -55,19 +55,17 @@ export class InkTranscription extends React.Component { protocol: 'WEBSOCKET', }, recognition: { - type: 'TEXT', - lang: 'en_US', - text: { - mimeTypes: ['application/vnd.myscript.jiix'] as 'application/vnd.myscript.jiix'[], + type: 'MATH', + math: { + mimeTypes: ['application/x-latex'] as unknown as 'application/vnd.myscript.jiix'[], }, }, }, }; - await iink.Editor.load(r, 'INKV2', options); - - this._textRegister = r; + this._iinkMathEditor = await iink.Editor.load(r, 'INKV2', options); + this._mathRegister = r; // eslint-disable-next-line @typescript-eslint/no-explicit-any - r?.addEventListener('exported', (e: any) => this.exportInk(e, this._textRef)); + r?.addEventListener('exported', (e: any) => this.exportInk(e)); return (this._textRef = r); } @@ -97,12 +95,14 @@ export class InkTranscription extends React.Component { this._iinkEditor = await iink.Editor.load(r, 'INKV2', options); this._textRegister = r; // eslint-disable-next-line @typescript-eslint/no-explicit-any - r?.addEventListener('exported', (e: any) => this.exportInk(e, this._textRef)); + r?.addEventListener('exported', (e: any) => this.exportInk(e)); return (this._textRef = r); } }; + _ffview: CollectionFreeFormView | undefined; + /** * Handles processing Dash Doc data for ink transcription. * @@ -110,7 +110,7 @@ export class InkTranscription extends React.Component { * @param inkDocs the ink docs contained within the selected group * @param math boolean whether to do math transcription or not */ - transcribeInk = (groupDoc: Doc | undefined, inkDocs: Doc[], math: boolean) => { + transcribeInk = (ffview: CollectionFreeFormView, groupDoc: Doc | undefined, inkDocs: Doc[], math: boolean) => { if (!groupDoc) return; const validInks = inkDocs.filter(s => s.type === DocumentType.INK); @@ -126,13 +126,10 @@ export class InkTranscription extends React.Component { strokes.push(d.inkData.map(pd => inkStroke.ptToScreen({ X: pd.X, Y: pd.Y }))); times.push(authorTime); }); + this._ffview = ffview; this.currGroup = groupDoc; const pointerData = strokes.map((stroke, i) => this.inkJSON(stroke, times[i])); - if (math) { - this._iinkEditor.importPointEvents(pointerData); - } else { - this._iinkEditor.importPointEvents(pointerData); - } + (math ? this._iinkMathEditor : this._iinkEditor).importPointEvents(pointerData); }; convertPointsToString(points: InkData[]): string { return points[0].map(point => `new Point(${point.X}, ${point.Y})`).join(','); @@ -204,83 +201,92 @@ export class InkTranscription extends React.Component { * @param ref the ref to the editor */ // eslint-disable-next-line @typescript-eslint/no-explicit-any - exportInk = async (e: any, ref: any) => { - const exports = e.detail['application/vnd.myscript.jiix']; - if (exports) { - if (exports['type'] == 'Math') { - const latex = exports['application/x-latex']; - if (this.currGroup) { - this.currGroup.text = latex; - this.currGroup.title = latex; - } + exportInk = (e: { detail: { [key: string]: string } }) => { + const exports = e.detail; + if (exports['application/x-latex']) { + const latex = exports['application/x-latex']; + if (this.currGroup) { + this.currGroup.text = latex; + this.currGroup.title = latex; + } - ref.editor.clear(); - } else if (exports['type'] == 'Text') { - if (exports['application/vnd.myscript.jiix']) { - this.lastJiix = JSON.parse(exports['application/vnd.myscript.jiix']); - // map timestamp to strokes - const timestampWord = new Map<number, string>(); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - this.lastJiix.words.map((word: any) => { - if (word.items) { - word.items.forEach((i: { id: string; timestamp: string; X: Array<number>; Y: Array<number>; F: Array<number> }) => { - const ms = Date.parse(i.timestamp); - timestampWord.set(ms, word.label); - }); - } + this._ffview?.addDocument( + Docs.Create.EquationDocument(latex, { + title: '', + x: this.currGroup?.x as number, + y: (this.currGroup?.y as number) + (this.currGroup?.height as number), + nativeHeight: 40, + _height: 50, + nativeWidth: 40, + _width: 50, + }) + ); + // this.showRecogBox(latex as string); + this._iinkMathEditor.clear(); + } else if (exports['application/vnd.myscript.jiix']) { + const lastJiix = exports['application/vnd.myscript.jiix'] as unknown as { words: string[]; label: string }; + // map timestamp to strokes + const timestampWord = new Map<number, string>(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + lastJiix.words.map((word: any) => { + if (word.items) { + word.items.forEach((i: { id: string; timestamp: string; X: Array<number>; Y: Array<number>; F: Array<number> }) => { + const ms = Date.parse(i.timestamp); + timestampWord.set(ms, word.label); }); - - const wordInkDocMap = new Map<string, Doc[]>(); - if (this.currGroup) { - const docList = DocListCast(this.currGroup.data); - docList.forEach((inkDoc: Doc) => { - // just having the times match up and be a unique value (actual timestamp doesn't matter) - const ms = (DateCast(inkDoc.author_date)?.getDate().getTime() ?? 0) + 14400000; - const word = timestampWord.get(ms); - if (!word) { - return; - } - const entry = wordInkDocMap.get(word); - if (entry) { - entry.push(inkDoc); - wordInkDocMap.set(word, entry); - } else { - const newEntry = [inkDoc]; - wordInkDocMap.set(word, newEntry); - } - }); - if (this.lastJiix.words.length > 1) this.subgroupsTranscriptions(wordInkDocMap); - } } - const text = exports['label']; + }); - if (this.currGroup && text) { - DocumentView.getDocumentView(this.currGroup)?.ComponentView?.updateIcon?.(); - const image = await this.getIcon(); - const { href } = (image as URLField).url; - const hrefParts = href.split('.'); - const hrefComplete = `${hrefParts[0]}_o.${hrefParts[1]}`; - let response; - try { - const hrefBase64 = await imageUrlToBase64(hrefComplete); - response = await gptHandwriting(hrefBase64); - } catch { - console.error('Error getting image'); - } - const textBoxText = 'iink: ' + text + '\n' + '\n' + 'ChatGPT: ' + response; - this.currGroup.transcription = response; - this.currGroup.title = response; - if (!this.currGroup.hasTextBox) { - const newDoc = Docs.Create.TextDocument(textBoxText, { title: '', x: this.currGroup.x as number, y: (this.currGroup.y as number) + (this.currGroup.height as number) }); - newDoc.height = 200; - this.collectionFreeForm?.addDocument(newDoc); - this.currGroup.hasTextBox = true; + const wordInkDocMap = new Map<string, Doc[]>(); + if (this.currGroup) { + DocListCast(this.currGroup.data).forEach((inkDoc: Doc) => { + // just having the times match up and be a unique value (actual timestamp doesn't matter) + const ms = (DateCast(inkDoc.author_date)?.getDate().getTime() ?? 0) + 14400000; + const word = timestampWord.get(ms); + if (word) { + const entry = wordInkDocMap.get(word); + if (entry) { + entry.push(inkDoc); + wordInkDocMap.set(word, entry); + } else { + const newEntry = [inkDoc]; + wordInkDocMap.set(word, newEntry); + } } - ref.editor.clear(); - } + }); + if (lastJiix.words.length > 1) this.subgroupsTranscriptions(wordInkDocMap); } + this.showRecogBox(lastJiix.label); + this._iinkEditor.clear(); } }; + private showRecogBox(text: string) { + if (this.currGroup) { + let response; + // DocumentView.getDocumentView(this.currGroup)?.ComponentView?.updateIcon?.(); + // const image = await this.getIcon(); + // const { href } = (image as URLField).url; + // const hrefParts = href.split('.'); + // const hrefComplete = `${hrefParts[0]}_o.${hrefParts[1]}`; + // try { + // const hrefBase64 = await imageUrlToBase64(hrefComplete); + // response = await gptHandwriting(hrefBase64); + // } catch { + // console.error('Error getting image'); + // } + const textBoxText = 'iink: ' + text + '\n' + '\n' + 'ChatGPT: ' + response; + + this.currGroup.transcription = response; + this.currGroup.title = response; + if (!this.currGroup.hasTextBox) { + const newDoc = Docs.Create.TextDocument(textBoxText, { title: '', x: this.currGroup.x as number, y: (this.currGroup.y as number) + (this.currGroup.height as number) }); + newDoc.height = 200; + this.collectionFreeForm?.addDocument(newDoc); + this.currGroup.hasTextBox = true; + } + } + } + /** * gets the icon of the collection that was just made * @returns the image of the collection @@ -299,7 +305,7 @@ export class InkTranscription extends React.Component { */ createInkGroup() { // TODO nda - if document being added to is a inkGrouping then we can just add to that group - if (Doc.ActiveTool === InkTool.Ink && Doc.ActiveInk === InkInkTool.Write) { + if (Doc.ActiveTool === InkTool.Ink && [InkInkTool.Write, InkInkTool.Math].includes(Doc.ActiveInk)) { CollectionFreeFormView.collectionsWithUnprocessedInk.forEach(ffView => { // TODO: nda - will probably want to go through ffView unprocessed docs and then see if any of the inksToGroup docs are in it and only use those const selected = ffView.unprocessedDocs; @@ -309,7 +315,7 @@ export class InkTranscription extends React.Component { ); ffView.unprocessedDocs = []; - InkTranscription.Instance.transcribeInk(newCollection, selected, false); + InkTranscription.Instance.transcribeInk(ffView, newCollection, selected, Doc.ActiveInk === InkInkTool.Math); }); } CollectionFreeFormView.collectionsWithUnprocessedInk.clear(); |
