aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/pdf
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/pdf')
-rw-r--r--src/client/views/pdf/AnchorMenu.tsx15
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.tsx152
-rw-r--r--src/client/views/pdf/PDFViewer.tsx2
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;