diff options
-rw-r--r-- | src/client/views/collections/CollectionCardDeckView.tsx | 52 | ||||
-rw-r--r-- | src/client/views/pdf/GPTPopup/GPTPopup.scss | 33 | ||||
-rw-r--r-- | src/client/views/pdf/GPTPopup/GPTPopup.tsx | 138 |
3 files changed, 215 insertions, 8 deletions
diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx index e64c013f1..e96fbc161 100644 --- a/src/client/views/collections/CollectionCardDeckView.tsx +++ b/src/client/views/collections/CollectionCardDeckView.tsx @@ -21,7 +21,9 @@ import { List } from '../../../fields/List'; import { gptAPICall, gptImageLabel } from '../../apis/gpt/GPT'; import { GPTCallType } from '../../apis/gpt/GPT'; import { ImageField, PdfField, URLField } from '../../../fields/URLField'; - +import { GPTPopup } from '../pdf/GPTPopup/GPTPopup'; +import { GPTPopupMode } from '../pdf/GPTPopup/GPTPopup'; +import { reaction } from 'mobx'; @observer export class CollectionCardView extends CollectionSubView() { @@ -88,6 +90,15 @@ export class CollectionCardView extends CollectionSubView() { if (this._props.Document.customHashMap != undefined){ this.customGroupDictionary = this.getCustoms(StrListCast(this._props.Document.customHashMap)) } + + reaction( + () => this._props.Document.cardSort, + (cardSort) => { + if (cardSort === 'chat') { + this.openChatPopup(); + } + } + ); } @observable customGroupDictionary: Map<number, number>[] = [new Map<number, number>(), new Map<number, number>(), new Map<number, number>()]; @@ -230,10 +241,18 @@ export class CollectionCardView extends CollectionSubView() { @computed get sortedDocsType() { - if (this._props.Document.cardSort === 'chat' && this.sortedDocs.length === 0) { - this.smartSort(); // Trigger the sorting if it hasn't been done yet - return { docs: [] }; // Return an empty array or a loading state - } + // if (this._props.Document.cardSort === 'chat'){ + // this.openChatPopup() + // const textDesc = await this.childPairStringList(); + // GPTPopup.Instance.setSortDesc(textDesc) + // } + + // if (this._props.Document.cardSort === 'chat' && this.sortedDocs.length === 0) { + + // this.smartSort(); // Trigger the sorting if it hasn't been done yet + // return { docs: [] }; // Return an empty array or a loading state + // } + const desc = BoolCast(this.layoutDoc.sortDesc); let sorted = []; @@ -253,7 +272,7 @@ export class CollectionCardView extends CollectionSubView() { case 'custom': return this.sort(sorted, 'custom', desc); case 'chat': - return { docs: this.sortedDocs }; // Use the sorted docs from the observable + return { docs: this.sortedDocs || this.myChildLayoutPairs}; // Use the sorted docs from the observable default: docs = this.myChildLayoutPairs; return { docs }; @@ -656,6 +675,25 @@ export class CollectionCardView extends CollectionSubView() { }); } + @observable isChatPopupOpen = false; + + @action openChatPopup = async () => { + this.isChatPopupOpen = true; + GPTPopup.Instance.setVisible(true); + GPTPopup.Instance.setMode(GPTPopupMode.SORT); + + // Await the promise to get the string result + const sortDesc = await this.childPairStringList(); + GPTPopup.Instance.setSortDesc(sortDesc); + GPTPopup.Instance.onSortComplete = this.handleGptSortResult; +}; + @action handleGptSortResult = (sortResult: string) => { + this.processGptOutput(sortResult); + this.sortedDocs = this.sort(this.myChildLayoutPairs, 'gpt', BoolCast(this.layoutDoc.sortDesc)).docs; + }; + + + renderButtons(childPairIndex: number) { @@ -708,6 +746,8 @@ export class CollectionCardView extends CollectionSubView() { // } // } + + render() { return ( <div diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.scss b/src/client/views/pdf/GPTPopup/GPTPopup.scss index 5d966395c..4425cf158 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.scss +++ b/src/client/views/pdf/GPTPopup/GPTPopup.scss @@ -60,6 +60,17 @@ $highlightedText: #82e0ff; display: flex; justify-content: space-between; align-items: center; + transform: translateY(30px); + + + .searchBox-input{ + transform: translateY(-15px); + height: 50px; + border-radius: 10px; + border-color: #5b97ff; + } + + .summarizing { display: flex; @@ -111,6 +122,28 @@ $highlightedText: #82e0ff; } } +.loading-spinner { + display: flex; + justify-content: center; + align-items: center; + height: 100px; + font-size: 20px; + font-weight: bold; + color: #666; +} + + + + + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + + + .image-content-wrapper { display: flex; flex-direction: column; diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx index 29b1ca365..faf66af85 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx +++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx @@ -21,6 +21,7 @@ export enum GPTPopupMode { EDIT, IMAGE, DATA, + SORT } interface GPTPopupProps {} @@ -94,10 +95,21 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> { private done: boolean = false; @action public setDone = (done: boolean) => { + console.log("HIIIIIIIII") this.done = done; this.chatMode = false; }; + @observable + private sortDone: boolean = false // this is so redundant but the og done variable was causing weird unknown problems and im just a girl + + @action + public setSortDone = (done: boolean) => { + console.log("HIIIIIIIII") + this.sortDone = done; + }; + + // change what can be a ref into a ref @observable private sidebarId: string = ''; @@ -120,9 +132,61 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> { this.textAnchor = anchor; }; + @observable + public sortPrompt: string = ''; + @action + public setSortPrompt = ((e: React.ChangeEvent<HTMLInputElement>) => { + this.sortPrompt = e.target.value; + }); + + @observable + public sortText: string = '' + @action + public setSortText = (t: string) => { + this.sortText = t + } + + @observable + public sortDesc: string = '' + + @action public setSortDesc = (t:string) => { + this.sortDesc = t + } + + @observable onSortComplete?: (sortResult: string) => void; + + + + + + public addDoc: (doc: Doc | Doc[], sidebarKey?: string | undefined) => boolean = () => false; public addToCollection: ((doc: Doc | Doc[], annotationKey?: string | undefined) => boolean) | undefined; + + generateSort = async () => { + this.setLoading(true); + this.setSortDone(false); + + try { + const res = await gptAPICall(this.sortPrompt + this.sortDesc, GPTCallType.SORT); + this.setSortText(res || 'Something went wrong :('); + + // Trigger the callback with the result + if (this.onSortComplete) { + this.onSortComplete(res || 'Something went wrong :('); + } + } catch (err) { + console.error(err); + this.setSortText('Something went wrong :('); + } + + this.setLoading(false); + this.setSortDone(true); + } + + + /** * Generates a Dalle image and uploads it to the server. */ @@ -243,6 +307,74 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> { } }; + sortBox = () => ( + <> + <div> + {this.heading("SORTING")} + {this.loading ? ( + <div className="content-wrapper"> + <div className="loading-spinner"> + <ReactLoading type="spin" color="#000" height={30} width={30} /> + <span>Loading...</span> + </div> + </div> + ) : !this.sortDone && ( + <div className="btns-wrapper"> + <input + defaultValue="" + autoComplete="off" + onChange={this.setSortPrompt} + onKeyDown={e => { + if (e.key === 'Enter') { + this.generateSort(); + } + e.stopPropagation(); + }} + type="text" + placeholder="Enter sorting instructions..." + id="search-input" + className="searchBox-input" + style={{ width: "100%" }} + /> + </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> + )} + </div> + </> + ); + + + + +// <> +// <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>Sorting</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> +// )} + imageBox = () => { return ( <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}> @@ -396,8 +528,10 @@ 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() : <></>} - </div> + {this.mode === GPTPopupMode.SUMMARY ? this.summaryBox() : + this.mode === GPTPopupMode.DATA ? this.dataAnalysisBox() : + this.mode === GPTPopupMode.IMAGE ? this.imageBox() : + this.mode === GPTPopupMode.SORT ? this.sortBox() : <></>} </div> ); } } |