aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/pdf/GPTPopup.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/pdf/GPTPopup.tsx')
-rw-r--r--src/client/views/pdf/GPTPopup.tsx115
1 files changed, 107 insertions, 8 deletions
diff --git a/src/client/views/pdf/GPTPopup.tsx b/src/client/views/pdf/GPTPopup.tsx
index 76f3c8187..ec4fa58dc 100644
--- a/src/client/views/pdf/GPTPopup.tsx
+++ b/src/client/views/pdf/GPTPopup.tsx
@@ -1,30 +1,129 @@
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, observable } from 'mobx';
import { observer } from 'mobx-react';
import React = require('react');
import ReactLoading from 'react-loading';
import Typist from 'react-typist';
+import { Doc } from '../../../fields/Doc';
+import { Docs } from '../../documents/Documents';
import './GPTPopup.scss';
interface GPTPopupProps {
visible: boolean;
text: string;
loadingSummary: boolean;
+ callApi: (e: React.PointerEvent) => Promise<void>;
}
@observer
export class GPTPopup extends React.Component<GPTPopupProps> {
+ static Instance: GPTPopup;
+
+ @observable
+ private summaryDone: boolean = false;
+ @observable
+ private sidebarId: string = '';
+ @action
+ public setSummaryDone = (done: boolean) => {
+ this.summaryDone = done;
+ };
+ @action
+ public setSidebarId = (id: string) => {
+ this.sidebarId = id;
+ };
+
+ public addDoc: (doc: Doc | Doc[], sidebarKey?: string | undefined) => boolean = () => false;
+
+ /**
+ * Transfers the summarization text to a sidebar annotation text document.
+ */
+ private transferToText = () => {
+ const newDoc = Docs.Create.TextDocument(this.props.text.trim(), {
+ _width: 200,
+ _height: 50,
+ _fitWidth: true,
+ _autoHeight: true,
+ });
+ this.addDoc(newDoc, this.sidebarId);
+ };
+
+ constructor(props: GPTPopupProps) {
+ super(props);
+ GPTPopup.Instance = this;
+ }
+
+ componentDidUpdate = () => {
+ if (this.props.loadingSummary) {
+ this.setSummaryDone(false);
+ }
+ };
+
render() {
return (
- <div className="summary-box" style={{ display: this.props.visible ? 'block' : 'none' }}>
+ <div className="summary-box" style={{ display: this.props.visible ? 'flex' : 'none' }}>
<div className="summary-heading">
<label className="summary-text">SUMMARY</label>
- {this.props.loadingSummary ? <ReactLoading type="spin" color="#bcbcbc" width={14} height={14} /> : <></>}
+ {this.props.loadingSummary && <ReactLoading type="spin" color="#bcbcbc" width={14} height={14} />}
</div>
- {!this.props.loadingSummary ? (
- <Typist key={this.props.text} avgTypingDelay={20} cursor={{ hideWhenDone: true }}>
- {this.props.text}
- </Typist>
- ) : (
- <></>
+ <div className="content-wrapper">
+ {!this.props.loadingSummary &&
+ (!this.summaryDone ? (
+ <Typist
+ key={this.props.text}
+ avgTypingDelay={15}
+ cursor={{ hideWhenDone: true }}
+ onTypingDone={action(() => {
+ setTimeout(
+ action(() => {
+ this.summaryDone = true;
+ }),
+ 500
+ );
+ })}>
+ {this.props.text}
+ </Typist>
+ ) : (
+ this.props.text
+ ))}
+ </div>
+ {!this.props.loadingSummary && (
+ <div className="btns-wrapper">
+ {this.summaryDone ? (
+ <>
+ <button className="icon-btn" onPointerDown={e => this.props.callApi(e)}>
+ <FontAwesomeIcon icon="redo-alt" size="lg" />
+ </button>
+ <button
+ className="text-btn"
+ onClick={e => {
+ this.transferToText();
+ }}>
+ Transfer to Text
+ </button>
+ </>
+ ) : (
+ <div className="summarizing">
+ <label>Summarizing</label>
+ <ReactLoading type="bubbles" color="#bcbcbc" width={20} height={20} />
+ <button
+ className="btn-secondary"
+ onClick={e => {
+ this.setSummaryDone(true);
+ }}>
+ Stop Animation
+ </button>
+ </div>
+ )}
+ </div>
+ )}
+ {this.summaryDone && (
+ <div className="ai-warning">
+ <FontAwesomeIcon icon="exclamation-circle" size="sm" style={{ paddingRight: '5px' }} />
+ AI generated responses can contain inaccurate or misleading content.{' '}
+ <a target="_blank" href="https://www.nytimes.com/2023/02/08/technology/ai-chatbots-disinformation.html">
+ Learn More
+ </a>
+ </div>
)}
</div>
);