diff options
Diffstat (limited to 'src/client/views/pdf')
-rw-r--r-- | src/client/views/pdf/AnchorMenu.tsx | 15 | ||||
-rw-r--r-- | src/client/views/pdf/GPTPopup/GPTPopup.tsx | 152 | ||||
-rw-r--r-- | src/client/views/pdf/PDFViewer.tsx | 2 |
3 files changed, 123 insertions, 46 deletions
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index 59f191af0..0b3ba81d3 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -6,7 +6,6 @@ import * as React from 'react'; import { ColorResult } from 'react-color'; import { Utils, returnFalse, setupMoveUpEvents, unimplementedFunction } from '../../../Utils'; import { Doc, Opt } from '../../../fields/Doc'; -import { GPTCallType, gptAPICall } from '../../apis/gpt/GPT'; import { DocumentType } from '../../documents/DocumentTypes'; import { SelectionManager } from '../../util/SelectionManager'; import { SettingsManager } from '../../util/SettingsManager'; @@ -73,18 +72,8 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { * @param e pointer down event */ gptSummarize = async (e: React.PointerEvent) => { - // move this logic to gptpopup, need to implement generate again - GPTPopup.Instance.setVisible(true); - GPTPopup.Instance.setMode(GPTPopupMode.SUMMARY); - GPTPopup.Instance.setLoading(true); - - try { - const res = await gptAPICall(this.selectedText, GPTCallType.SUMMARY); - GPTPopup.Instance.setText(res || 'Something went wrong.'); - } catch (err) { - console.error(err); - } - GPTPopup.Instance.setLoading(false); + GPTPopup.Instance?.setSelectedText(this.selectedText); + GPTPopup.Instance.generateSummary(); }; pointerDown = (e: React.PointerEvent) => { diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx index da8a88803..29b1ca365 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx +++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Button, IconButton, Type } from 'browndash-components'; +import { Button, EditableText, IconButton, Size, Type } from 'browndash-components'; import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -10,7 +10,7 @@ import { Utils } from '../../../../Utils'; import { Doc } from '../../../../fields/Doc'; import { NumCast, StrCast } from '../../../../fields/Types'; import { Networking } from '../../../Network'; -import { gptImageCall } from '../../../apis/gpt/GPT'; +import { GPTCallType, gptAPICall, gptImageCall } from '../../../apis/gpt/GPT'; import { DocUtils, Docs } from '../../../documents/Documents'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { AnchorMenu } from '../AnchorMenu'; @@ -20,6 +20,7 @@ export enum GPTPopupMode { SUMMARY, EDIT, IMAGE, + DATA, } interface GPTPopupProps {} @@ -27,6 +28,7 @@ interface GPTPopupProps {} @observer export class GPTPopup extends ObservableReactComponent<GPTPopupProps> { static Instance: GPTPopup; + @observable private chatMode: boolean = false; @observable public visible: boolean = false; @@ -46,6 +48,20 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> { public setText = (text: string) => { this.text = text; }; + @observable + public selectedText: string = ''; + @action + public setSelectedText = (text: string) => { + this.selectedText = text; + }; + @observable + public dataJson: string = ''; + public dataChatPrompt: string | null = null; + @action + public setDataJson = (text: string) => { + if (text=="") this.dataChatPrompt = ""; + this.dataJson = text; + }; @observable public imgDesc: string = ''; @@ -79,6 +95,7 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> { @action public setDone = (done: boolean) => { this.done = done; + this.chatMode = false; }; // change what can be a ref into a ref @@ -118,18 +135,46 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> { try { let image_urls = await gptImageCall(this.imgDesc); + console.log('Image urls: ', image_urls); if (image_urls && image_urls[0]) { const [result] = await Networking.PostToServer('/uploadRemoteImage', { sources: [image_urls[0]] }); + console.log('Upload result: ', result); const source = Utils.prepend(result.accessPaths.agnostic.client); + console.log('Upload source: ', source); this.setImgUrls([[image_urls[0], source]]); } } catch (err) { - console.log(err); - return ''; + console.error(err); } this.setLoading(false); }; + generateSummary = async () => { + GPTPopup.Instance.setVisible(true); + GPTPopup.Instance.setMode(GPTPopupMode.SUMMARY); + GPTPopup.Instance.setLoading(true); + + try { + const res = await gptAPICall(this.selectedText, GPTCallType.SUMMARY); + GPTPopup.Instance.setText(res || 'Something went wrong.'); + } catch (err) { + console.error(err); + } + GPTPopup.Instance.setLoading(false); + } + + generateDataAnalysis = async () => { + GPTPopup.Instance.setVisible(true); + GPTPopup.Instance.setLoading(true); + try { + let res = await gptAPICall(this.dataJson, GPTCallType.DATA, this.dataChatPrompt); + GPTPopup.Instance.setText(res || 'Something went wrong.'); + } catch (err) { + console.error(err); + } + GPTPopup.Instance.setLoading(false); + } + /** * Transfers the summarization text to a sidebar annotation text document. */ @@ -174,6 +219,16 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> { DocUtils.MakeLink(textAnchor, newDoc, { link_relationship: 'Image Prompt' }); }; + /** + * Creates a chatbox for analyzing data so that users can ask specific questions. + */ + private chatWithAI = () => { + this.chatMode = true; + } + dataPromptChanged = action((e: React.ChangeEvent<HTMLInputElement>) => { + this.dataChatPrompt = e.target.value; + }); + private getPreviewUrl = (source: string) => source.split('.').join('_m.'); constructor(props: GPTPopupProps) { @@ -213,31 +268,6 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> { ); }; - data = () => { - return ( - <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}> - {this.heading('GENERATED IMAGE')} - <div className="image-content-wrapper"> - {this.imgUrls.map(rawSrc => ( - <div className="img-wrapper"> - <div className="img-container"> - <img key={rawSrc[0]} src={rawSrc[0]} width={150} height={150} alt="dalle generation" /> - </div> - <div className="btn-container"> - <Button text="Save Image" onClick={() => this.transferToImage(rawSrc[1])} color={StrCast(Doc.UserDoc().userColor)} type={Type.TERT} /> - </div> - </div> - ))} - </div> - {!this.loading && ( - <> - <IconButton tooltip="Generate Again" onClick={this.generateImage} icon={<FontAwesomeIcon icon="redo-alt" size="lg" />} color={StrCast(Doc.UserDoc().userVariantColor)} /> - </> - )} - </div> - ); - }; - summaryBox = () => ( <> <div> @@ -255,7 +285,6 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> { }, 500); }, ]} - //cursor={{ hideWhenDone: true }} /> ) : ( this.text @@ -266,7 +295,7 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> { <div className="btns-wrapper"> {this.done ? ( <> - <IconButton tooltip="Generate Again" onClick={this.callSummaryApi} icon={<FontAwesomeIcon icon="redo-alt" size="lg" />} color={StrCast(Doc.UserDoc().userVariantColor)} /> + <IconButton tooltip="Generate Again" onClick={this.generateSummary} icon={<FontAwesomeIcon icon="redo-alt" size="lg" />} color={StrCast(Doc.UserDoc().userVariantColor)} /> <Button tooltip="Transfer to text" text="Transfer To Text" onClick={this.transferToText} color={StrCast(Doc.UserDoc().userVariantColor)} type={Type.TERT} /> </> ) : ( @@ -288,6 +317,65 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> { </> ); + dataAnalysisBox = () => ( + <> + <div> + {this.heading("ANALYSIS")} + <div className="content-wrapper"> + {!this.loading && + (!this.done ? ( + <TypeAnimation + speed={50} + sequence={[ + this.text, + () => { + setTimeout(() => { + this.setDone(true); + }, 500); + }, + ]} + /> + ) : ( + this.text + ))} + </div> + </div> + {!this.loading && ( + <div className="btns-wrapper"> + {this.done? + this.chatMode?( + <input + defaultValue="" + autoComplete="off" + onChange={this.dataPromptChanged} + onKeyDown={e => { + e.key === 'Enter' ? this.generateDataAnalysis() : null; + e.stopPropagation(); + }} + type="text" + placeholder="Ask GPT a question about the data..." + id="search-input" + className="searchBox-input" + style={{width: "100%"}} + /> + ) + :( + <> + <Button tooltip="Transfer to text" text="Transfer To Text" onClick={this.transferToText} color={StrCast(Doc.UserDoc().userVariantColor)} type={Type.TERT} /> + <Button tooltip="Chat with AI" text="Chat with AI" onClick={this.chatWithAI} color={StrCast(Doc.UserDoc().userVariantColor)} type={Type.TERT} /> + </> + ) : ( + <div className="summarizing"> + <span>Summarizing</span> + <ReactLoading type="bubbles" color="#bcbcbc" width={20} height={20} /> + <Button text="Stop Animation" onClick={() => {this.setDone(true);}} color={StrCast(Doc.UserDoc().userVariantColor)} type={Type.TERT}/> + </div> + )} + </div> + )} + </> + ); + aiWarning = () => this.done ? ( <div className="ai-warning"> @@ -308,7 +396,7 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> { render() { return ( <div className="summary-box" style={{ display: this.visible ? 'flex' : 'none' }}> - {this.mode === GPTPopupMode.SUMMARY ? this.summaryBox() : this.mode === GPTPopupMode.IMAGE ? this.imageBox() : <></>} + {this.mode === GPTPopupMode.SUMMARY? this.summaryBox() : this.mode === GPTPopupMode.DATA? this.dataAnalysisBox() : this.mode === GPTPopupMode.IMAGE ? this.imageBox() : <></>} </div> ); } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index a582f8004..aaff2a342 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -30,7 +30,7 @@ const _global = (window /* browser */ || global) /* node */ as any; //pdfjsLib.GlobalWorkerOptions.workerSrc = `/assets/pdf.worker.js`; // The workerSrc property shall be specified. -Pdfjs.GlobalWorkerOptions.workerSrc = 'https://unpkg.com/pdfjs-dist@4.0.379/build/pdf.worker.mjs'; +Pdfjs.GlobalWorkerOptions.workerSrc = 'https://unpkg.com/pdfjs-dist@4.1.392/build/pdf.worker.mjs'; interface IViewerProps extends FieldViewProps { pdfBox: PDFBox; |