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.tsx2
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.scss20
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.tsx244
-rw-r--r--src/client/views/pdf/PDFViewer.tsx2
4 files changed, 216 insertions, 52 deletions
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 2f6824466..96f025ca0 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -133,7 +133,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
_layout_autoHeight: true,
});
- this.addToCollection?.(newCol);
+ this.addToCollection?.(newCol); //this._props.addDocument(newCol)
};
pointerDown = (e: React.PointerEvent) => {
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.scss b/src/client/views/pdf/GPTPopup/GPTPopup.scss
index 6d8793f82..291f272ce 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.scss
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.scss
@@ -7,10 +7,13 @@ $highlightedText: #82e0ff;
.summary-box {
position: fixed;
- bottom: 10px;
- right: 10px;
+ top: 115px;
+ left: 75px;
width: 250px;
+ height: 200px;
min-height: 200px;
+ min-width: 180px;
+
border-radius: 16px;
padding: 16px;
padding-bottom: 0;
@@ -21,6 +24,18 @@ $highlightedText: #82e0ff;
background-color: #ffffff;
box-shadow: 0 2px 5px #7474748d;
color: $textgrey;
+ resize: both; /* Allows resizing */
+ overflow: auto;
+
+ .resize-handle {
+ width: 10px;
+ height: 10px;
+ background: #ccc;
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ cursor: se-resize;
+ }
.summary-heading {
display: flex;
@@ -84,6 +99,7 @@ $highlightedText: #82e0ff;
font-size: 9px;
padding: 10px;
color: #ffffff;
+ width: 100%;
background-color: $button;
border-radius: 5px;
}
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
index cb5aad32d..71d437c3d 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
@@ -20,15 +20,19 @@ import './GPTPopup.scss';
import { SettingsManager } from '../../../util/SettingsManager';
import { SnappingManager } from '../../../util/SnappingManager';
+
export enum GPTPopupMode {
SUMMARY,
EDIT,
IMAGE,
FLASHCARD,
DATA,
+ CARD,
SORT,
+ QUIZ
}
+
interface GPTPopupProps {}
@observer
@@ -149,6 +153,28 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
this.cardsDoneLoading = done;
}
+ @observable sortRespText: string = ''
+
+ @action setSortRespText(resp: string) {
+ this.sortRespText = resp
+ }
+
+
+ @observable chatSortPrompt: string = ""
+
+ sortPromptChanged = action((e: React.ChangeEvent<HTMLInputElement>) => {
+ this.chatSortPrompt = e.target.value;
+ });
+
+ @observable private regenerateCallback: (() => Promise<void>) | null = null;
+
+ @action public setRegenerateCallback(callback: () => Promise<void>) {
+ this.regenerateCallback = callback;
+ }
+
+
+
+
public addDoc: (doc: Doc | Doc[], sidebarKey?: string | undefined) => boolean = () => false;
public createFilteredDoc: (axes?: any) => boolean = () => false;
public addToCollection: ((doc: Doc | Doc[], annotationKey?: string | undefined) => boolean) | undefined;
@@ -157,24 +183,38 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
* Sorts cards in the CollectionCardDeckView
*/
generateSort = async () => {
+ console.log(this.chatSortPrompt + "USER PROMPT")
this.setLoading(true);
this.setSortDone(false);
+ if (this.regenerateCallback) {
+ await this.regenerateCallback();
+ }
+
try {
- const res = await gptAPICall(this.sortDesc, GPTCallType.SORT);
+ const res = await gptAPICall(this.sortDesc, GPTCallType.SORT, this.chatSortPrompt);
// Trigger the callback with the result
if (this.onSortComplete) {
this.onSortComplete(res || 'Something went wrong :(');
+
+ // Extract explanation surrounded by ------ at the top or both at the top and bottom
+ const explanationMatch = res.match(/------\s*([\s\S]*?)\s*(?:------|$)/) || [];
+ const explanation = explanationMatch[1] ? explanationMatch[1].trim() : 'No explanation found';
+
+ // Set the extracted explanation to sortRespText
+ this.setSortRespText(explanation);
+
console.log(res);
}
} catch (err) {
console.error(err);
}
-
+
this.setLoading(false);
this.setSortDone(true);
};
-
+
+
/**
* Generates a Dalle image and uploads it to the server.
*/
@@ -314,59 +354,154 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
}
};
+ cardMenu = () => (
+ <div className="btns-wrapper-gpt">
+ <Button
+ tooltip="Have ChatGPT sort your cards for you!"
+ text="Sort Cards!"
+ onClick={this.generateSort}
+ color={StrCast(Doc.UserDoc().userVariantColor)}
+ type={Type.TERT}
+ style={{
+ width: '90%',
+ textAlign: 'center',
+ color: '#ffffff',
+ fontSize: '16px',
+ }}
+ />
+ <Button
+ tooltip="Test your knowledge with ChatGPT!"
+ text="Quiz Cards!"
+ onClick={this.generateSort}
+ color={StrCast(Doc.UserDoc().userVariantColor)}
+ type={Type.TERT}
+ style={{
+ width: '90%',
+ textAlign: 'center',
+ color: '#ffffff',
+ fontSize: '16px',
+ }}
+ />
+ </div>
+
+ )
+
+ cardActual = (opt: string) => {
+ const isSort = opt === 'sort'
+
+ if (opt === 'sort'){
+ return (
+ <>
+ <div className="btns-wrapper-gpt">
+ <input
+ className="searchBox-input"
+ defaultValue=""
+ autoComplete="off"
+ onChange={this.sortPromptChanged}
+ onKeyDown={e => {
+ if (e.key === 'Enter') {
+ this.generateSort();
+ }
+ e.stopPropagation();
+ }}
+ type="text"
+ placeholder= {`How do you want to sort your cards ?` }
+ id="search-input"
+ style={{ width: '100%' }}
+ />
+ </div>
+ <div className="btns-wrapper-gpt">
+ <Button
+ tooltip="Have ChatGPT sort your cards for you!"
+ text="Sort!"
+ onClick={this.generateSort}
+ color={StrCast(Doc.UserDoc().userVariantColor)}
+ type={Type.TERT}
+ style={{
+ width: '90%',
+ textAlign: 'center',
+ color: '#ffffff',
+ fontSize: '16px',
+ }}
+ />
+ </div>
+ </>
+ )
+
+ }
+
+}
+
sortBox = () => (
- <>
- <div>
- {this.heading('SORTING')}
- {this.loading ? (
+ <>
+ <div>
+ {this.heading('SORTING')}
+ <>
+ {!this.cardsDoneLoading || this.loading ? (
<div className="content-wrapper">
<div className="loading-spinner">
<ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} />
- <span>Loading...</span>
+ {this.loading ? <span>Loading...</span> : <span>Reading Cards...</span>}
</div>
</div>
) : (
- <>
- {!this.cardsDoneLoading ? (
- <div className="content-wrapper">
- <div className="loading-spinner">
- <ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} />
- <span>Reading Cards...</span>
- </div>
+ !this.sortDone && (
+ <>
+ <div className="btns-wrapper-gpt">
+ <input
+ className="searchBox-input"
+ defaultValue=""
+ autoComplete="off"
+ onChange={this.sortPromptChanged}
+ onKeyDown={e => {
+ if (e.key === 'Enter') {
+ this.generateSort();
+ }
+ e.stopPropagation();
+ }}
+ type="text"
+ placeholder="How do you want to sort your cards ?"
+ id="search-input"
+ style={{ width: '100%' }}
+ />
</div>
- ) : (
- !this.sortDone && (
- <div className="btns-wrapper-gpt">
- <Button
- tooltip="Have ChatGPT sort your cards for you!"
- text="Sort!"
- onClick={this.generateSort}
- color={StrCast(Doc.UserDoc().userVariantColor)}
- type={Type.TERT}
- style={{
- width: '90%', // Almost as wide as the container
- textAlign: 'center',
- color: '#ffffff', // White text
- fontSize: '16px', // Adjust font size as needed
- }}
- />
- </div>
- )
- )}
-
- {this.sortDone && (
- <div>
- <div className="content-wrapper">
- <p>{this.text === 'Something went wrong :(' ? 'Something went wrong :(' : 'Sorting done! Feel free to move things around / regenerate :) !'}</p>
- <IconButton tooltip="Generate Again" onClick={() => this.setSortDone(false)} icon={<FontAwesomeIcon icon="redo-alt" size="lg" />} color={StrCast(Doc.UserDoc().userVariantColor)} />
- </div>
+ <div className="btns-wrapper-gpt">
+ <Button
+ tooltip="Have ChatGPT sort your cards for you!"
+ text="Sort!"
+ onClick={this.generateSort}
+ color={StrCast(Doc.UserDoc().userVariantColor)}
+ type={Type.TERT}
+ style={{
+ width: '90%',
+ textAlign: 'center',
+ color: '#ffffff',
+ fontSize: '16px',
+ }}
+ />
</div>
- )}
- </>
+ </>
+ )
)}
- </div>
- </>
- );
+
+ {this.sortDone && (
+ <div>
+ <div className="content-wrapper">
+ <p>{this.text === 'Something went wrong :(' ? 'Something went wrong :(' : `${this.sortRespText}`}</p>
+ <IconButton
+ tooltip="Generate Again"
+ onClick={() => this.setSortDone(false)}
+ icon={<FontAwesomeIcon icon="redo-alt" size="lg" />}
+ color={StrCast(Doc.UserDoc().userVariantColor)}
+ />
+ </div>
+ </div>
+ )}
+ </>
+ </div>
+ </>
+);
+
imageBox = () => (
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
{this.heading('GENERATED IMAGE')}
@@ -518,9 +653,22 @@ 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.DATA ? this.dataAnalysisBox() : this.mode === GPTPopupMode.IMAGE ? this.imageBox() : this.mode === GPTPopupMode.SORT ? this.sortBox() : null}
+ <div
+ className="summary-box"
+ style={{ display: this.visible ? 'flex' : 'none' }}
+ >
+ {this.mode === GPTPopupMode.SUMMARY
+ ? this.summaryBox()
+ : this.mode === GPTPopupMode.DATA
+ ? this.dataAnalysisBox()
+ : this.mode === GPTPopupMode.IMAGE
+ ? this.imageBox()
+ : this.mode === GPTPopupMode.SORT
+ ? this.sortBox()
+ : null}
+ <div className="resize-handle" />
</div>
);
}
+
}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index c7d5e15b4..709e9a23c 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -33,7 +33,7 @@ import './PDFViewer.scss';
// pdfjsLib.GlobalWorkerOptions.workerSrc = `/assets/pdf.worker.js`;
// The workerSrc property shall be specified.
-Pdfjs.GlobalWorkerOptions.workerSrc = 'https://unpkg.com/pdfjs-dist@4.3.136/build/pdf.worker.mjs';
+Pdfjs.GlobalWorkerOptions.workerSrc = 'https://unpkg.com/pdfjs-dist@4.2.67/build/pdf.worker.mjs';
interface IViewerProps extends FieldViewProps {
pdfBox: PDFBox;