diff options
Diffstat (limited to 'src/client/views/pdf')
| -rw-r--r-- | src/client/views/pdf/AnchorMenu.tsx | 43 | ||||
| -rw-r--r-- | src/client/views/pdf/GPTPopup.scss | 9 | ||||
| -rw-r--r-- | src/client/views/pdf/GPTPopup.tsx | 19 | ||||
| -rw-r--r-- | src/client/views/pdf/PDFViewer.tsx | 22 |
4 files changed, 92 insertions, 1 deletions
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index c53cc608c..63c8f9145 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -10,6 +10,8 @@ import { SelectionManager } from '../../util/SelectionManager'; import { AntimodeMenu, AntimodeMenuProps } from '../AntimodeMenu'; import { LinkPopup } from '../linking/LinkPopup'; import { ButtonDropdown } from '../nodes/formattedText/RichTextMenu'; +import { gptSummarize } from '../../apis/gpt/Summarization'; +import { GPTPopup } from './GPTPopup'; import './AnchorMenu.scss'; @observer @@ -43,10 +45,30 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { @observable public Highlighting: boolean = false; @observable public Status: 'marquee' | 'annotation' | '' = ''; + // GPT additions (flow 2) + @observable private summarizedText: string = ''; + @observable private showGPTPopup: boolean = false; + @action + setGPTPopupVis = (vis: boolean) => { + this.showGPTPopup = vis; + }; + @action + setSummarizedText = (txt: string) => { + this.summarizedText = txt; + }; + + private selectedText: string = ''; + setSelectedText = (txt: string) => { + this.selectedText = txt; + }; + public onMakeAnchor: () => Opt<Doc> = () => undefined; // Method to get anchor from text search public OnCrop: (e: PointerEvent) => void = unimplementedFunction; public OnClick: (e: PointerEvent) => void = unimplementedFunction; + public OnSummary: (e: PointerEvent) => Promise<void> = () => { + return new Promise(() => {}); + }; public OnAudio: (e: PointerEvent) => void = unimplementedFunction; public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction; public StartCropDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction; @@ -83,11 +105,26 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { () => SelectionManager.Views(), selected => { this._showLinkPopup = false; + this.setGPTPopupVis(false); AnchorMenu.Instance.fadeOut(true); } ); } + getGPTSummary = (e: React.PointerEvent) => { + setupMoveUpEvents(this, e, returnFalse, returnFalse, e => this.OnSummary?.(e)); + }; + + invokeGPT = async (e: React.PointerEvent) => { + this.setGPTPopupVis(true); + const res = await gptSummarize(this.selectedText); + if (res) { + this.setSummarizedText(res); + } else { + this.setSummarizedText('Something went wrong.'); + } + }; + pointerDown = (e: React.PointerEvent) => { setupMoveUpEvents( this, @@ -192,6 +229,12 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { <FontAwesomeIcon icon="comment-alt" size="lg" /> </button> </Tooltip> + <Tooltip key="gpt" title={<div className="dash-tooltip">Summarize with GPT-3</div>}> + <button className="antimodeMenu-button annotate" onPointerDown={this.getGPTSummary} style={{ cursor: 'grab' }}> + <FontAwesomeIcon icon="comment-dots" size="lg" /> + </button> + </Tooltip> + <GPTPopup key="gptpopup" visible={this.showGPTPopup} text={this.summarizedText} /> {AnchorMenu.Instance.OnAudio === unimplementedFunction ? null : ( <Tooltip key="annoaudiotate" title={<div className="dash-tooltip">Click to Record Annotation</div>}> <button className="antimodeMenu-button annotate" onPointerDown={this.audioDown} style={{ cursor: 'grab' }}> diff --git a/src/client/views/pdf/GPTPopup.scss b/src/client/views/pdf/GPTPopup.scss new file mode 100644 index 000000000..6f2e39b7e --- /dev/null +++ b/src/client/views/pdf/GPTPopup.scss @@ -0,0 +1,9 @@ +.summary-box { + background-color: #ffffff; + position: absolute; + top: 0; + width: 200px; + height: 200px; + padding: 20px; + overflow: auto; +} diff --git a/src/client/views/pdf/GPTPopup.tsx b/src/client/views/pdf/GPTPopup.tsx new file mode 100644 index 000000000..110351126 --- /dev/null +++ b/src/client/views/pdf/GPTPopup.tsx @@ -0,0 +1,19 @@ +import { observer } from 'mobx-react'; +import React = require('react'); +import './GPTPopup.scss'; + +interface GPTPopupProps { + visible: boolean; + text: string; +} + +@observer +export class GPTPopup extends React.Component<GPTPopupProps> { + render() { + return ( + <div className="summary-box" style={{ display: this.props.visible ? 'block' : 'none' }}> + {`Summary: ${this.props.text}`} + </div> + ); + } +} diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index b0b7816b8..324f31f23 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -24,6 +24,7 @@ import { AnchorMenu } from './AnchorMenu'; import { Annotation } from './Annotation'; import './PDFViewer.scss'; import React = require('react'); +import { gptSummarize } from '../../apis/gpt/Summarization'; const PDFJSViewer = require('pdfjs-dist/web/pdf_viewer'); const pdfjsLib = require('pdfjs-dist'); const _global = (window /* browser */ || global) /* node */ as any; @@ -42,7 +43,7 @@ interface IViewerProps extends FieldViewProps { url: string; loaded?: (nw: number, nh: number, np: number) => void; setPdfViewer: (view: PDFViewer) => void; - anchorMenuClick?: () => undefined | ((anchor: Doc) => void); + anchorMenuClick?: () => undefined | ((anchor: Doc, summarize?: boolean) => void); crop: (region: Doc | undefined, addCrop?: boolean) => Doc | undefined; } @@ -82,6 +83,19 @@ export class PDFViewer extends React.Component<IViewerProps> { return AnchorMenu.Instance?.GetAnchor; } + // Fields for using GPT to summarize selected text + private _summaryText: string = ''; + setSummaryText = async () => { + try { + const summary = await gptSummarize(this.selectionText()); + this._summaryText = `Summary: ${summary}`; + } catch (err) { + console.log(err); + this._summaryText = 'Failed to fetch summary.'; + } + }; + summaryText = () => this._summaryText; + selectionText = () => this._selectionText; selectionContent = () => this._selectionContent; @@ -413,6 +427,10 @@ export class PDFViewer extends React.Component<IViewerProps> { document.removeEventListener('pointerup', this.onSelectEnd); const sel = window.getSelection(); + if (sel) { + AnchorMenu.Instance.setSelectedText(sel.toString()); + } + if (sel?.type === 'Range') { this.createTextAnnotation(sel, sel.getRangeAt(0)); AnchorMenu.Instance.jumpTo(e.clientX, e.clientY); @@ -596,6 +614,8 @@ export class PDFViewer extends React.Component<IViewerProps> { finishMarquee={this.finishMarquee} savedAnnotations={this.savedAnnotations} selectionText={this.selectionText} + setSummaryText={this.setSummaryText} + summaryText={this.summaryText} annotationLayer={this._annotationLayer.current} mainCont={this._mainCont.current} anchorMenuCrop={this._textSelecting ? undefined : this.crop} |
