aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/apis/gpt/GPT.ts34
-rw-r--r--src/client/util/CurrentUserUtils.ts20
-rw-r--r--src/client/views/FilterPanel.scss18
-rw-r--r--src/client/views/FilterPanel.tsx3
-rw-r--r--src/client/views/InkingStroke.tsx14
-rw-r--r--src/client/views/collections/CollectionCardDeckView.tsx221
-rw-r--r--src/client/views/global/globalScripts.ts26
-rw-r--r--src/client/views/nodes/IconTagBox.tsx23
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.scss56
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.tsx319
10 files changed, 525 insertions, 209 deletions
diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts
index d95e564c7..f9183d3e2 100644
--- a/src/client/apis/gpt/GPT.ts
+++ b/src/client/apis/gpt/GPT.ts
@@ -12,7 +12,10 @@ enum GPTCallType {
DESCRIBE = 'describe',
MERMAID = 'mermaid',
DATA = 'data',
- RUBRIC = 'rubric'
+ RUBRIC = 'rubric',
+ TYPE = 'type',
+ SUBSET = 'subset',
+ INFO = 'info'
}
type GPTCallOpts = {
@@ -45,7 +48,7 @@ const callTypeMap: { [type: string]: GPTCallOpts } = {
model: 'gpt-4o',
maxTokens: 2048,
temp: 0.25,
- prompt: "The user is going to give you a list of descriptions. Each one is separated by `======` on either side. Descriptions will vary in length, so make sure to only separate when you see `======`. Sort them by shared content. Make sure each description is only in the list once. Each item should be separated by `======`. Immediately afterward, surrounded by `------` on BOTH SIDES, provide some insight into your reasoning for the way you sorted (and mention nothing about the formatting details given in this description). It is VERY important that you format it exactly as described, ensuring the proper number of `=` and `-` (6 of each) and no commas"
+ prompt: "The user is going to give you a list of descriptions. Each one is separated by `======` on either side. Descriptions will vary in length, so make sure to only separate when you see `======`. Sort them by the user's specifications. Make sure each description is only in the list once. Each item should be separated by `======`. Immediately afterward, surrounded by `------` on BOTH SIDES, provide some insight into your reasoning for the way you sorted (and mention nothing about the formatting details given in this description). It is VERY important that you format it exactly as described, ensuring the proper number of `=` and `-` (6 of each) and NO commas"
// prompt: "I'm going to give you a list of descriptions. Each one is separated by `======` on either side. Descriptions will vary in length, so make sure to only separate when you see `======`. Sort them into lists by shared content. Make sure each description is in only one list. Each list should be separated by `======` with the elements within it separated by `~~~~~~`. Immediately afterward, surrounded by `------` on BOTH SIDES, provide some insight into your reasoning for the way you sorted. It is VERY important that you format it exactly as described, ensuring the proper number of `=` `~` and `-` (6 of each) and no commas.Try to create around 4 groups, but a little more or less is ok. Also, I may provide some more insight after this colon:"
},
describe: { model: 'gpt-4-vision-preview', maxTokens: 2048, temp: 0, prompt: 'Describe these images in 3-5 words' },
@@ -54,15 +57,38 @@ const callTypeMap: { [type: string]: GPTCallOpts } = {
model: 'gpt-4-turbo',
maxTokens: 1024,
temp: 0,
- prompt: 'List unique differences between the content of the UserAnswer and Rubric. Before each difference, label it and provide any additional information the UserAnswer missed and explain it in second person without separating it into UserAnswer and Rubric content and additional information. If there are no differences, say correct',
+ prompt: "BRIEFLY (<50 words) describe any differences between the rubric and the user's answer answer in second person. If there are no differences, say correct",
},
rubric: {
model: 'gpt-4-turbo',
maxTokens: 1024,
temp: 0,
- prompt: "Provide a definition for the vollowing term. It will be used as a rubric to evaluate the user's understanding of the topic",
+ prompt: "BRIEFLY (<75 words) provide a definition for the following term. It will be used as a rubric to evaluate the user's understanding of the topic",
},
+
+ type: {
+ model: 'gpt-4-turbo',
+ maxTokens: 1024,
+ temp: 0,
+ prompt: "I'm going to provide you with a question. Based on the question, is the user asking you to 1. Assigns docs with tags(like star / heart etc)/labels, 2. Filter docs, 3. Provide information about a specific doc 4. Provide a specific doc based on a question/information 5. Provide general information 6. Put cards in a specific order. Answer with only the number for 2-6. For number one, provide the number (1) and the appropriate tag",
+ },
+
+ subset: {
+ model: 'gpt-4-turbo',
+ maxTokens: 1024,
+ temp: 0,
+ prompt: "I'm going to give you a list of descriptions. Each one is separated by `======` on either side. Descriptions will vary in length, so make sure to only separate when you see `======`. Based on the question the user asks, provide a subset of the given descriptions that best matches the user's specifications. Make sure each description is only in the list once. Each item should be separated by `======`. Immediately afterward, surrounded by `------` on BOTH SIDES, provide some insight into your reasoning in the 2nd person (and mention nothing about the formatting details given in this description). It is VERY important that you format it exactly as described, ensuring the proper number of `=` and `-` (6 of each) and no commas"
+ },
+
+ info: {
+ model: 'gpt-4-turbo',
+ maxTokens: 1024,
+ temp: 0,
+ prompt: "Answer the user's question with a short (<100 word) response. If a particular document is selected I will provide that information (which may help with your response)"
+ },
+
+
};
let lastCall = '';
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 1a7c0f6e1..6a81f9125 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -675,7 +675,8 @@ pie title Minerals in my tap water
{ title: "Time", icon:"hourglass-half", toolTip:"Sort by most recent document creation", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"time", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
{ title: "Type", icon:"eye", toolTip:"Sort by document type", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"docType",funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
{ title: "Color", icon:"palette", toolTip:"Sort by document color", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"color", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
- { title: "AI Sort", icon:"robot", toolTip:"Have Chat GPT sort your cards for you !", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"chat", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
+ { title: "Tags", icon:"bolt", toolTip:"Sort by document's tags", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"tag", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
+ // { title: "AI Sort", icon:"robot", toolTip:"Have Chat GPT sort your cards for you !", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"chat", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
{ title: "Pile", icon:"layer-group", toolTip:"View the cards as a pile in the free form view !", btnType: ButtonType.ClickButton, expertMode: false, toolType:"pile", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
{ title: "Chat Popup", icon:"lightbulb", toolTip:"Toggle the chat popup's visibility!", width: 45 ,btnType: ButtonType.ToggleButton, expertMode: false, toolType:"toggle-chat", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'} },
@@ -845,6 +846,9 @@ pie title Minerals in my tap water
{ title: "Back", icon: "chevron-left", toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)'}, width: 30, scripts: { onClick: 'prevKeyFrame(_readOnly_)'}},
{ title: "Num", icon:"", toolTip: "Frame # (click to toggle edit mode)",btnType: ButtonType.TextButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)', buttonText: 'selectedDocs()?.lastElement()?.currentFrame?.toString()'}, width: 20, scripts: { onClick: '{ return curKeyFrame(_readOnly_);}'}},
{ title: "Fwd", icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)'}, width: 30, scripts: { onClick: 'nextKeyFrame(_readOnly_)'}},
+
+
+
{ title: "Text", icon: "Text", toolTip: "Text functions", subMenu: CurrentUserUtils.textTools(), expertMode: false, toolType:DocumentType.RTF, funcs: { linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
{ title: "Ink", icon: "Ink", toolTip: "Ink functions", subMenu: CurrentUserUtils.inkTools(), expertMode: false, toolType:DocumentType.INK, funcs: {hidden: `IsExploreMode()`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available
{ title: "Doc", icon: "Doc", toolTip: "Freeform Doc tools", subMenu: CurrentUserUtils.freeTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode, true)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
@@ -863,6 +867,13 @@ pie title Minerals in my tap water
// { title: "Visibility", icon:"Visibility", toolTip:"Filter stars", width: 80, subMenu: this.cardGroupTools("star"), expertMode: false, toolType:CollectionViewType.Card, funcs: {hidden:`!showFreeform("star", true)`, width: 100, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} },
// // { title: "Custom", icon:"cloud", toolTip:"Add Idea labels", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"idea", funcs: {hidden:`showFreeform ("idea", true)`},scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
// { title: "Visibility", icon:"Visibility", toolTip:"Filter ideas", width: 80, subMenu: this.cardGroupTools("cloud"), expertMode: false, toolType:CollectionViewType.Card, funcs: {hidden:`!showFreeform("idea", true)`,width: 100, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} },
+
+ { title: "Card", icon: "Card", toolTip: "Card View Tools", subMenu: CurrentUserUtils.cardTools(), expertMode: false, toolType:CollectionViewType.Card, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
+ // { title: "Create", icon: "Create", toolTip: "Assign card labels", subMenu: CurrentUserUtils.labelTools(), expertMode: false, toolType:CollectionViewType.Card, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
+ { title: "Web", icon: "Web", toolTip: "Web functions", subMenu: CurrentUserUtils.webTools(), expertMode: false, toolType:DocumentType.WEB, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when Web is selected
+ { title: "Video", icon: "Video", toolTip: "Video functions", subMenu: CurrentUserUtils.videoTools(), expertMode: false, toolType:DocumentType.VID, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when video is selected
+ { title: "Image", icon: "Image", toolTip: "Image functions", subMenu: CurrentUserUtils.imageTools(), expertMode: false, toolType:DocumentType.IMG, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when image is selected
+ { title: "Schema", icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",subMenu: CurrentUserUtils.schemaTools(),expertMode: false,toolType:CollectionViewType.Schema,funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when Schema is selected
{ title: "Filter", icon:"=", toolTip:"Filter cards by tags", btnType: ButtonType.MultiToggleButton, width: 150, ignoreClick: true,toolType:DocumentType.COL,
subMenu: this.tagGroupTools(), funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)'},
// [
@@ -873,13 +884,8 @@ pie title Minerals in my tap water
// ]
},
- { title: "Card", icon: "Card", toolTip: "Card View Tools", subMenu: CurrentUserUtils.cardTools(), expertMode: false, toolType:CollectionViewType.Card, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
- // { title: "Create", icon: "Create", toolTip: "Assign card labels", subMenu: CurrentUserUtils.labelTools(), expertMode: false, toolType:CollectionViewType.Card, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available
- { title: "Web", icon: "Web", toolTip: "Web functions", subMenu: CurrentUserUtils.webTools(), expertMode: false, toolType:DocumentType.WEB, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when Web is selected
- { title: "Video", icon: "Video", toolTip: "Video functions", subMenu: CurrentUserUtils.videoTools(), expertMode: false, toolType:DocumentType.VID, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when video is selected
- { title: "Image", icon: "Image", toolTip: "Image functions", subMenu: CurrentUserUtils.imageTools(), expertMode: false, toolType:DocumentType.IMG, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when image is selected
- { title: "Schema", icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",subMenu: CurrentUserUtils.schemaTools(),expertMode: false,toolType:CollectionViewType.Schema,funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Only when Schema is selected
];
+
}
/// initializes a context menu button for the top bar context menu
diff --git a/src/client/views/FilterPanel.scss b/src/client/views/FilterPanel.scss
index 0b9076f3b..34c3d2fc1 100644
--- a/src/client/views/FilterPanel.scss
+++ b/src/client/views/FilterPanel.scss
@@ -283,6 +283,8 @@
.hotkey-title{
top: 6px;
position: relative;
+ cursor: text;
+
}
.hotkey-title-input{
@@ -290,6 +292,8 @@
border: none;
border-color: transparent;
outline: none;
+ cursor: text;
+
}
}
@@ -345,6 +349,20 @@
}
+
+.drawing-box{
+ position: absolute;
+ z-index: 10000;
+ border-color: black;
+ border-style: solid;
+ border-width: medium;
+ border-radius: 10%;
+ background-color: #323232;
+
+
+
+
+}
// .sliderBox-outerDiv {
// width: 30%;// width: calc(100% - 14px); // 14px accounts for handles that are at the max value of the slider that would extend outside the box
// height: 40; // height: 100%;
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx
index 17c5cb173..ca4e4df84 100644
--- a/src/client/views/FilterPanel.tsx
+++ b/src/client/views/FilterPanel.tsx
@@ -51,10 +51,13 @@ interface filterProps {
@observer
export class FilterPanel extends ObservableReactComponent<filterProps> {
@observable _selectedFacetHeaders = new Set<string>();
+ public static Instance: FilterPanel;
+
constructor(props: any) {
super(props);
makeObservable(this);
+ FilterPanel.Instance = this;
}
/**
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 62b79dd5a..a117ff3c3 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -447,13 +447,13 @@ export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>()
}),
icon: 'paint-brush',
});
- cm?.addItem({
- description: 'Create a hotkey',
- event: action(() => {
- InkStrokeProperties.Instance._controlButton = !InkStrokeProperties.Instance._controlButton;
- }),
- icon: 'satellite',
- });
+ // cm?.addItem({
+ // description: 'Create a hotkey',
+ // event: action(() => {
+ // InkStrokeProperties.Instance._controlButton = !InkStrokeProperties.Instance._controlButton;
+ // }),
+ // icon: 'satellite',
+ // });
},
};
return (
diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
index 52f01e239..5dafb1088 100644
--- a/src/client/views/collections/CollectionCardDeckView.tsx
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -28,6 +28,8 @@ import { SettingsManager } from '../../util/SettingsManager';
import { Tooltip } from '@mui/material';
import { dropActionType } from '../../util/DropActionTypes';
import { List } from '../../../fields/List';
+import { DocCast } from '../../../fields/Types';
+import { SelectionManager } from '../../util/SelectionManager';
enum cardSortings {
Time = 'time',
@@ -35,6 +37,7 @@ enum cardSortings {
Color = 'color',
Custom = 'custom',
Chat = 'chat',
+ Tag = 'tag',
None = '',
}
@observer
@@ -91,7 +94,9 @@ export class CollectionCardView extends CollectionSubView() {
childPairStringListAndUpdateSortDesc = async () => {
const sortDesc = await this.childPairStringList(); // Await the promise to get the string result
GPTPopup.Instance.setSortDesc(sortDesc.join());
- GPTPopup.Instance.onSortComplete = (sortResult: string) => this.processGptOutput(sortResult);
+ GPTPopup.Instance.onSortComplete = (sortResult: string, questionType: string, tag?: string) => this.processGptOutput(sortResult, questionType, tag);
+ GPTPopup.Instance.onQuizRandom = () => this.quizMode()
+
};
componentDidMount(): void {
@@ -103,9 +108,17 @@ export class CollectionCardView extends CollectionSubView() {
});
+ // Reaction to cardSort changes
this._disposers.sort = reaction(
- () => ({ cardSort: this.cardSort }),
- ({ cardSort}) => (cardSort === cardSortings.Chat ? this.openChatPopup() : GPTPopup.Instance.setVisible(false))
+ () => this.cardSort,
+ (cardSort) => {
+ if (cardSort === cardSortings.Chat) {
+ this.openChatPopup();
+ } else {
+ GPTPopup.Instance.setVisible(false);
+ }
+ // Force re-render to see if this resolves the sorting issue
+ }
);
@@ -121,6 +134,7 @@ export class CollectionCardView extends CollectionSubView() {
}
@computed get cardSort() {
+ // console.log(StrCast(this.Document.cardSort) as any as cardSortings)
return StrCast(this.Document.cardSort) as any as cardSortings;
}
@@ -151,6 +165,16 @@ export class CollectionCardView extends CollectionSubView() {
return regularDocs;
}
+ quizMode () {
+
+ const randomIndex = Math.floor(Math.random() * this.childDocs.length)
+ console.log('hiiiiiii')
+
+ SelectionManager.DeselectAll()
+ DocumentView.SelectView(DocumentView.getDocumentView(this.childDocs[randomIndex]), false)
+
+ }
+
/**
@@ -290,13 +314,48 @@ export class CollectionCardView extends CollectionSubView() {
};
- @computed get sortedDocs() {
+ get sortedDocs() {
// console.log("hi hi hi")
// console.log(this.layoutDoc.cardSort_isDesc + "layoutdoc desc")
- console.log(this.cardSort + "card sort")
+ // console.log(this.cardSort + "card sort")
- return this.sort(this.childDocsWithoutLinks, this.cardSort, BoolCast(this.layoutDoc.cardSort_isDesc), this._docDraggedIndex);
+ return this.sort(this.childDocsWithoutLinks, this.cardSort, BoolCast(this.Document.cardSort_isDesc), this._docDraggedIndex);
}
+
+ tagValue(doc: Doc) {
+ const keys = StrListCast(Doc.UserDoc().myFilterHotKeyTitles);
+
+ const isTagActive = (buttonID: number) => {
+ return BoolCast(doc[StrCast(Doc.UserDoc()[keys[buttonID]])]);
+ };
+
+ let base = '';
+ let fraction = '';
+
+ for (let i = 0; i < keys.length; i++) {
+ if (isTagActive(i)) {
+ if (base === '') {
+ base = i.toString(); // First active tag becomes the base
+ } else {
+ fraction += i.toString(); // Subsequent active tags become part of the fraction
+ }
+ }
+ }
+
+ // If no tag was active, return 0 by default
+ if (base === '') {
+ return 0;
+ }
+
+ // Construct the final number by appending the fraction if it exists
+ const numberString = fraction ? `${base}.${fraction}` : base;
+
+ // Convert the result to a number and return
+ return Number(numberString);
+ }
+
+
+
/**
* Called in the sortedDocsType method. Compares the cards' value in regards to the desired sort type-- earlier cards are move to the
* front, latter cards to the back
@@ -305,7 +364,8 @@ export class CollectionCardView extends CollectionSubView() {
* @param isDesc
* @returns
*/
- sort = (docs: Doc[], sortType: cardSortings, isDesc: boolean, dragIndex: number) => {
+ @action sort = (docs: Doc[], sortType: cardSortings, isDesc: boolean, dragIndex: number) => {
+ // console.log('hiiii')
// if (sortType === cardSortings.None) return docs;
// if(sortType !== cardSortings.None){
@@ -319,12 +379,13 @@ export class CollectionCardView extends CollectionSubView() {
case cardSortings.Color:
return [ClientUtils.hexToHsv(StrCast(docA.backgroundColor)),
ClientUtils.hexToHsv(StrCast(docB.backgroundColor))];
- case cardSortings.Custom:
- return [CollectionCardView.getButtonGroup(this.cardSort_customField, docA) ?? 9999,
- CollectionCardView.getButtonGroup(this.cardSort_customField, docB) ?? 9999];
+ case cardSortings.Tag:
+ return [this.tagValue(docA) ?? 9999,
+ this.tagValue(docB) ?? 9999];
case cardSortings.Chat:
- return [NumCast(docA.chat) ?? 9999,
- NumCast(docB.chat) ?? 9999]
+ return [NumCast(docA.chatIndex) ?? 9999,
+ NumCast(docB.chatIndex) ?? 9999]
+
default:
return [StrCast(docA.type), StrCast(docB.type)]
@@ -487,12 +548,19 @@ export class CollectionCardView extends CollectionSubView() {
* Converts the gpt output into a hashmap that can be used for sorting. lists are seperated by ==== while elements within the list are seperated by ~~~~~~
* @param gptOutput
*/
- @action processGptOutput = (gptOutput: string) => {
+ @action processGptOutput = (gptOutput: string, questionType: string, tag?: string) => {
console.log("HIIII")
console.log(StrCast(this.Document.cardSort) + "cardSort")
// Split the string into individual list items
const listItems = gptOutput.split('======').filter(item => item.trim() !== '');
+
+
+ if (questionType == '2' || questionType == '4'){
+ this.childDocs.forEach(d => {
+ d['chatFilter'] = false
+ })
+ }
// console.log(listItems + " LISTT");
// Debug: print the map contents
@@ -509,10 +577,47 @@ export class CollectionCardView extends CollectionSubView() {
// console.log("ITEM:", normalizedItem);
if (doc) {
- doc.chat = index;
+ switch (questionType){
+ case '6':
+ doc.chatIndex = index
+ console.log(index)
+ break
+ case '1':
+ const allHotKeys = StrListCast(Doc.UserDoc().myFilterHotKeyTitles)
+
+ let myTag = ''
+
+ if (tag){
+ for (let i=0; i< allHotKeys.length; i++){
+ if (tag.includes(allHotKeys[i])){
+ myTag = StrCast(Doc.UserDoc()[allHotKeys[i]])
+ break
+ }
+
+ else if (tag.includes(StrCast(Doc.UserDoc()[allHotKeys[i]]))){
+ myTag = StrCast(Doc.UserDoc()[allHotKeys[i]])
+ break
+ }
+ }
+
+ if (myTag != ''){
+ doc[myTag] = true
+ }
+ }
+ break
+ case '2':
+ case '4':
+ doc['chatFilter'] = true
+ Doc.setDocFilter(DocCast(this.Document.embedContainer), 'chatFilter', true, 'match');
+ break
+
+
+
+ }
} else {
console.warn(`No matching document found for item: ${normalizedItem}`);
}
+
});
}
@@ -528,100 +633,20 @@ export class CollectionCardView extends CollectionSubView() {
const sortDesc = await this.childPairStringList(); // Await the promise to get the string result
GPTPopup.Instance.setCardsDoneLoading(true); // Set dataDoneLoading to true after data is loaded
GPTPopup.Instance.setSortDesc(sortDesc.join());
- GPTPopup.Instance.onSortComplete = (sortResult: string) => this.processGptOutput(sortResult);
- };
-
- /**
- * Renders the buttons to customize sorting depending on which group the card belongs to and the amount of total groups
- * @param doc
- * @param cardSort
- * @returns
- */
- renderButtons = (doc: Doc, cardSort: cardSortings): JSX.Element | null => {
- // if (cardSort !== cardSortings.Custom) return null;
-
- const amButtons = 4
-
- // const amButtons = Math.max(
- // 4,
- // this.childDocs?.reduce((set, d) => {
- // if (this.cardSort_customField) {
- // set.add(NumCast(d[this.cardSort_customField]));
- // }
- // return set;
- // }, new Set<number>()).size ?? 0
- // );
-
- // const activeButtonIndex = CollectionCardView.getButtonGroup(this.cardSort_customField, doc);
-
- const totalWidth = amButtons * 72 + amButtons * 2 * 5 + 6;
-
- const iconMap: { [key: number]: any } = {
- 0: 'star',
- 1: 'heart',
- 2: 'cloud',
- 3: 'bolt'
- };
-
- return (
- <div className="card-button-container" style={{ width: `${totalWidth}px`, fontSize: '50px' }}>
- {numberRange(amButtons).map(i => (
- <Tooltip key={i} title={<div className="dash-tooltip">Click to add/remove this card from the {iconMap[i]} group</div>}>
- <button type="button" onClick={() => this.toggleButton(doc, iconMap[i] )}>
- {this.getButtonIcon(doc, iconMap[i])}
- </button>
- </Tooltip>
- ))}
- </div>
- );
- };
-
- /**
- * Toggles the buttons between on and off when creating custom sort groupings/changing those created by gpt
- * @param childPairIndex
- * @param buttonID
- * @param doc
- */
- toggleButton = undoable((doc: Doc, icon: string) => {
-
-
-
- // this.cardSort_customField && (doc[this.cardSort_customField] = buttonID);
-
- // doc.cardSort_activeIcons = new List<string>()
-
-
- // const list = StrListCast(doc.cardSort_activeIcons);
- // doc.cardSort_activeIcons = new List<string>(list.includes(icon) ? list.filter(d => d !== icon) : [...list, icon]);
-
- BoolCast(doc[icon]) ? doc[icon] = false : doc[icon] = true
-
-
-
- // StrListCast(doc.cardSort_activeIcons).push(iconMap[buttonID])
- }, 'toggle card tag');
-
-
- getButtonIcon = (doc: Doc, icon: any): JSX.Element => {
-
- // const isActive = StrListCast(doc.cardSort_activeIcons).includes(icon)
- const isActive = doc[icon]
-
- // console.log(StrListCast(doc.cardSort_activeIcons))
- const color = isActive ? '#4476f7' : '#323232';
-
- return <FontAwesomeIcon icon={icon} size="lg" style={{ color }} />;
+ GPTPopup.Instance.onSortComplete = (sortResult: string, questionType: string, tag?: string) => this.processGptOutput(sortResult, questionType, tag);
+ GPTPopup.Instance.onQuizRandom = () => this.quizMode()
};
/**
* Actually renders all the cards
*/
renderCards = () => {
+ // console.log('christ')
const anySelected = this.childDocs.some(doc => DocumentView.SelectedDocs().includes(doc));
const isEmpty = this.childDocsWithoutLinks.length === 0;
const isDesc = BoolCast(this.Document.cardSort_isDesc)
- console.log(this.childDocsWithoutLinks.length + "length")
+ // console.log(this.childDocsWithoutLinks.length + "length")
if (isEmpty) {
return (
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index a48e3f9d9..1efcd84e4 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -146,7 +146,7 @@ ScriptingGlobals.add(function showFreeform(attr: 'center' | 'grid' | 'snaplines'
}
// prettier-ignore
- const map: Map<'flashcards' | 'center' | 'grid' | 'snaplines' | 'clusters' | 'arrange' | 'viewAll' | 'fitOnce' | 'time' | 'docType' | 'color' | 'chat' | 'up' | 'down' | 'pile' | 'toggle-chat',
+ const map: Map<'flashcards' | 'center' | 'grid' | 'snaplines' | 'clusters' | 'arrange' | 'viewAll' | 'fitOnce' | 'time' | 'docType' | 'color' | 'chat' | 'up' | 'down' | 'pile' | 'toggle-chat' | 'tag',
{
waitForRender?: boolean;
checkResult: (doc: Doc) => any;
@@ -193,6 +193,10 @@ ScriptingGlobals.add(function showFreeform(attr: 'center' | 'grid' | 'snaplines'
checkResult: (doc: Doc) => StrCast(doc?.cardSort) === "color",
setDoc: (doc: Doc, dv: DocumentView) => doc.cardSort === "color" ? doc.cardSort = '' : doc.cardSort = 'color',
}],
+ ['tag', {
+ checkResult: (doc: Doc) => StrCast(doc?.cardSort) === "tag",
+ setDoc: (doc: Doc, dv: DocumentView) => doc.cardSort === "tag" ? doc.cardSort = '' : doc.cardSort = 'tag',
+ }],
// ['heart', {
// checkResult: (doc: Doc) => isAttrFiltered('heart'),
// setDoc: (doc: Doc, dv: DocumentView) => {
@@ -221,16 +225,16 @@ ScriptingGlobals.add(function showFreeform(attr: 'center' | 'grid' | 'snaplines'
// }
// }],
- ['chat', {
- checkResult: (doc: Doc) => {
+ // ['chat', {
+ // checkResult: (doc: Doc) => {
- if (StrCast(doc?.cardSort) === "chat"){
- return true
- }} ,
- setDoc: (doc: Doc, dv: DocumentView) => {
- doc.cardSort === "chat" ? doc.cardSort = '' : doc.cardSort = 'chat';
- },
- }],
+ // if (StrCast(doc?.cardSort) === "chat"){
+ // return true
+ // }} ,
+ // setDoc: (doc: Doc, dv: DocumentView) => {
+ // doc.cardSort === "chat" ? doc.cardSort = '' : doc.cardSort = 'chat';
+ // },
+ // }],
['up', {
checkResult: (doc: Doc) => BoolCast(!doc?.cardSort_isDesc),
setDoc: (doc: Doc, dv: DocumentView) => {
@@ -248,6 +252,8 @@ ScriptingGlobals.add(function showFreeform(attr: 'center' | 'grid' | 'snaplines'
setDoc: (doc: Doc, dv: DocumentView) => {
GPTPopup.Instance.setVisible(!GPTPopup.Instance.visible);
GPTPopup.Instance.setMode(GPTPopupMode.SORT);
+ doc.cardSort === "chat" ? doc.cardSort = '' : doc.cardSort = 'chat';
+
},
}],
diff --git a/src/client/views/nodes/IconTagBox.tsx b/src/client/views/nodes/IconTagBox.tsx
index c72d48ef5..8aa6bff2b 100644
--- a/src/client/views/nodes/IconTagBox.tsx
+++ b/src/client/views/nodes/IconTagBox.tsx
@@ -26,6 +26,9 @@ import { setupMoveUpEvents } from "../../../ClientUtils";
import { returnFalse } from "../../../ClientUtils";
import { emptyFunction } from "../../../Utils";
import { CollectionViewType } from "../../documents/DocumentTypes";
+import { SnappingManager } from "../../util/SnappingManager";
+import { MainView } from "../MainView";
+import { PropertiesView } from "../PropertiesView";
export interface IconTagProps {
@@ -129,7 +132,7 @@ export class IconTagBox extends ObservableReactComponent<IconTagProps> {
renderButtons = (doc: Doc): JSX.Element | null => {
// if (cardSort !== cardSortings.Custom) return null;
- const amButtons = StrListCast(Doc.UserDoc().myFilterHotKeyTitles).length
+ const amButtons = (StrListCast(Doc.UserDoc().myFilterHotKeyTitles).length) + 1
const keys = StrListCast(Doc.UserDoc().myFilterHotKeyTitles)
@@ -146,7 +149,7 @@ export class IconTagBox extends ObservableReactComponent<IconTagProps> {
// const activeButtonIndex = CollectionCardView.getButtonGroup(this.cardSort_customField, doc);
- const totalWidth = amButtons * 35 + amButtons * 2 * 5 + 6;
+ const totalWidth = (amButtons -1) * 35 + (amButtons -1) * 2 * 5 + 6;
const iconMap = (buttonID: number) => {
return StrCast(Doc.UserDoc()[keys[buttonID]])
@@ -169,17 +172,31 @@ export class IconTagBox extends ObservableReactComponent<IconTagProps> {
fontSize: '50px'
}}
>
- {numberRange(amButtons).map(i => (
+ {numberRange(amButtons-1).map(i => (
<Tooltip key={i} title={<div className="dash-tooltip">Click to add/remove this card from the {iconMap(i)} group</div>}>
<button key = {i} type="button" onClick={() => this.toggleButton(doc, iconMap(i) )}>
{this.getButtonIcon(doc, iconMap(i))}
</button>
</Tooltip>
))}
+
+ {/* <Tooltip title={<div className="dash-tooltip">Click to customize these icons</div>}>
+ <button type="button" onClick={() => this.openHotKeyMenu() }>
+ <FontAwesomeIcon icon='gear' style={{ color: '#17438a', height: '30px', width: '30px'}} />
+ </button>
+ </Tooltip> */}
</div>
);
};
+ openHotKeyMenu = () => {
+ SnappingManager.PropertiesWidth < 5 && SnappingManager.SetPropertiesWidth(0);
+ SnappingManager.SetPropertiesWidth(MainView.Instance.propertiesWidth() < 15 ? Math.min(MainView.Instance._dashUIWidth - 50, 250) : 0);
+
+ PropertiesView.Instance.CloseAll()
+ PropertiesView.Instance.openFilters = true
+ }
+
/**
* Toggles the buttons between on and off when creating custom sort groupings/changing those created by gpt
* @param childPairIndex
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.scss b/src/client/views/pdf/GPTPopup/GPTPopup.scss
index eaa3eaebf..1defd1a7f 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.scss
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.scss
@@ -78,15 +78,63 @@ $highlightedText: #82e0ff;
align-items: center;
flex-direction: column;
- transform: translateY(30px);
+ .inputWrapper{
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 60px;
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ background-color: white;
+
+ }
.searchBox-input{
- transform: translateY(-15px);
- height: 50px;
+ height: 40px;
border-radius: 10px;
+ position: absolute;
+ bottom: 10px;
border-color: #5b97ff;
+ width: 90%
+ }
+
+ .chat-wrapper {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ max-height: calc(100vh - 80px); /* Height minus the input box and some padding */
+ overflow-y: auto;
+ padding-bottom: 60px; /* Space for the input */
+ }
+
+ .chat-bubbles {
+ margin-top: 20px;
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ }
+
+ .chat-bubble {
+ padding: 10px;
+ margin-bottom: 10px;
+ border-radius: 10px;
+ max-width: 60%;
}
+
+ .user-message {
+ background-color: #283d53;
+ align-self: flex-end;
+ color: whitesmoke;
+ }
+
+ .chat-message {
+ background-color: #367ae7;
+ align-self: flex-start;
+ color:whitesmoke;
+ }
+
@@ -98,6 +146,8 @@ $highlightedText: #82e0ff;
+
+
}
// button {
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
index d216cc421..1b44508d7 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
@@ -34,6 +34,13 @@ export enum GPTPopupMode {
QUIZ
}
+export enum GPTQuizType {
+ CURRENT = 0,
+ CHOOSE = 1,
+ MULTIPLE = 2
+
+}
+
@@ -151,7 +158,8 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
this.sortDesc = t;
};
- @observable onSortComplete?: (sortResult: string) => void;
+ @observable onSortComplete?: (sortResult: string, questionType: string, tag?: string) => void;
+ @observable onQuizRandom?: () => void;
@observable cardsDoneLoading = false;
@action setCardsDoneLoading(done: boolean) {
@@ -165,6 +173,9 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
this.sortRespText = resp
}
+ //mode where gpt says to select a specific card
+ //
+
@observable chatSortPrompt: string = ""
@@ -179,39 +190,65 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
this.quizAnswer = e.target.value;
});
+
+ @observable correctAnswer: string = ''
+ @observable setCorrectAnswer = (s: string) => {
+ this.correctAnswer = s
+ }
+
generateQuiz = async () => {
this.setLoading(true);
this.setSortDone(false);
+ const quizType = this.quizMode;
const selected = DocumentView.SelectedDocs().lastElement();
- const questionText = 'Question: ' + StrCast(selected['gptInputText']);
- if (StrCast(selected['gptRubric']) === '') {
- const rubricText = 'Rubric: ' + await this.generateRubric(StrCast(selected['gptInputText']), selected)
- }
+ const questionText = 'Question: ' + StrCast(selected['gptInputText']);
- const rubricText = 'Rubric: ' + (StrCast(selected['gptRubric']))
- // const rubricText = 'Rubric: ' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_0']).text)?.Text);
- const queryText = questionText + ' UserAnswer: ' + this.quizAnswer + '. ' + 'Rubric' + rubricText;
+ if (StrCast(selected['gptRubric']) === '') {
+ const rubricText = 'Rubric: ' + await this.generateRubric(StrCast(selected['gptInputText']), selected)
+ }
- try {
- const res = await gptAPICall(queryText, GPTCallType.QUIZ);
- if (!res) {
- console.error('GPT call failed');
- return;
- }
- console.log(res)
- this.setQuizResp(res)
+ const rubricText = 'Rubric: ' + (StrCast(selected['gptRubric']))
+ // const rubricText = 'Rubric: ' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_0']).text)?.Text);
+ const queryText = questionText + ' UserAnswer: ' + this.quizAnswer + '. ' + 'Rubric' + rubricText;
- this.setLoading(false);
- this.setSortDone(true);
+ try {
+ const res = await gptAPICall(queryText, GPTCallType.QUIZ);
+ if (!res) {
+ console.error('GPT call failed');
+ return;
+ }
+ console.log(res)
+ this.setQuizResp(res)
+ this.conversationArray.push(res)
+
+ this.setLoading(false);
+ this.setSortDone(true);
+
+ // this._outputValue = res;
+ } catch (err) {
+ console.error('GPT call failed');
+ }
+
+
+ if (this.onQuizRandom){
+ this.onQuizRandom()
+ }
- // this._outputValue = res;
- } catch (err) {
- console.error('GPT call failed');
- }
+
+
+
+
+ // switch(quizType){
+ // default:
+
+ // }
+
+
+
}
@@ -254,11 +291,7 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
}
-
- /**
- * Sorts cards in the CollectionCardDeckView
- */
- generateSort = async () => {
+ generateCard = async () => {
console.log(this.chatSortPrompt + "USER PROMPT")
this.setLoading(true);
this.setSortDone(false);
@@ -268,17 +301,50 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
}
try {
- const res = await gptAPICall(this.sortDesc, GPTCallType.SORT, this.chatSortPrompt);
+ // const res = await gptAPICall(this.sortDesc, GPTCallType.SORT, this.chatSortPrompt);
+ const questionType = await gptAPICall(this.chatSortPrompt, GPTCallType.TYPE);
+ const questionNumber = questionType.split(' ')[0]
+ console.log(questionType)
+ let res = ''
+
+ switch (questionNumber) {
+ case '1':
+ case '2':
+ case '4':
+ res = await gptAPICall(this.sortDesc, GPTCallType.SUBSET, this.chatSortPrompt);
+ break
+ case '6':
+ res = await gptAPICall(this.sortDesc, GPTCallType.SORT, this.chatSortPrompt);
+ break
+ default:
+
+ const selected = DocumentView.SelectedDocs().lastElement();
+ const questionText = StrCast(selected!['gptInputText']);
+
+
+ res = await gptAPICall(questionText, GPTCallType.INFO, this.chatSortPrompt);
+ break
+ }
+
+
+ // const res = await gptAPICall(this.sortDesc, GPTCallType.SUBSET, this.chatSortPrompt);
// Trigger the callback with the result
if (this.onSortComplete) {
- this.onSortComplete(res || 'Something went wrong :(');
+ this.onSortComplete(res || 'Something went wrong :(', questionNumber, questionType.split(' ').slice(1).join(' '));
+
+ let explanation = res
+
+ if (questionType != '5' && questionType != '3'){
// 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';
+ explanation = explanationMatch[1] ? explanationMatch[1].trim() : 'No explanation found';
+ }
// Set the extracted explanation to sortRespText
this.setSortRespText(explanation);
+ this.conversationArray.push(this.sortRespText)
+ this.scrollToBottom()
console.log(res);
}
@@ -289,6 +355,43 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
this.setLoading(false);
this.setSortDone(true);
};
+
+
+ // /**
+ // * 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, 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);
+ // };
/**
@@ -422,19 +525,40 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
super(props);
makeObservable(this);
GPTPopup.Instance = this;
+ this.messagesEndRef = React.createRef();
+
}
+ private messagesEndRef: React.RefObject<HTMLDivElement>;
+
+
+ scrollToBottom = () => {
+ setTimeout(() => {
+ // Code to execute after 1 second (1000 ms)
+ if (this.messagesEndRef.current) {
+
+ this.messagesEndRef.current.scrollIntoView({ behavior: 'smooth', block: 'end' });
+ }
+
+ }, 50);
+ }
+
componentDidUpdate = () => {
if (this.loading) {
this.setDone(false);
}
};
+ @observable quizMode : GPTQuizType = GPTQuizType.CURRENT
+ @action setQuizMode (g: GPTQuizType) {
+ this.quizMode = g
+ }
+
cardMenu = () => (
<div className="btns-wrapper-gpt">
<Button
- tooltip="Have ChatGPT sort your cards for you!"
- text="Sort Cards!"
+ tooltip="Have ChatGPT sort, tag, define, or filter your cards for you!"
+ text="Modify/Sort Cards!"
onClick={() => this.setMode(GPTPopupMode.SORT)}
color={StrCast(Doc.UserDoc().userVariantColor)}
type={Type.TERT}
@@ -450,7 +574,16 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
<Button
tooltip="Test your knowledge with ChatGPT!"
text="Quiz Cards!"
- onClick={() => this.setMode(GPTPopupMode.QUIZ)}
+ onClick={() => {
+ this.conversationArray = ['Define the selected card!']
+ this.setMode(GPTPopupMode.QUIZ)
+ if (this.onQuizRandom){
+ this.onQuizRandom()
+ }
+
+
+
+ }}
color={StrCast(Doc.UserDoc().userVariantColor)}
type={Type.TERT}
style={{
@@ -464,62 +597,94 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
/>
</div>
)
+
+ @observable conversationArray: string[] = ["Hi! In this pop up, you can ask ChatGPT questions about your documents and filter / sort them. If you're not sure if something is possible-- just ask!"]
+
+
+ handleKeyPress = async (e: React.KeyboardEvent, isSort: boolean) => {
+ if (e.key === 'Enter') {
+ e.stopPropagation();
+
+ if (isSort) {
+ this.conversationArray.push(this.chatSortPrompt);
+ await this.generateCard();
+ this.chatSortPrompt = ''
+
+ } else {
+ this.conversationArray.push(this.quizAnswer);
+ await this.generateQuiz();
+ this.quizAnswer = ''
+
+ }
+
+ this.scrollToBottom();
+ }
+ }
cardActual = (opt: GPTPopupMode) => {
const isSort = opt === GPTPopupMode.SORT
// if (opt === GPTPopupMode.SORT) {
return (
- !this.sortDone ? (
- <>
- <div className="btns-wrapper-gpt">
+ // !this.sortDone ? (
+ // <>
+ <div className="btns-wrapper-gpt">
+ {/* Chat bubble container with scroll */}
+ <div className="chat-wrapper">
+ <div className="chat-bubbles">
+ {this.conversationArray.map((message, index) => (
+ <div
+ key={index}
+ className={`chat-bubble ${index % 2 === 1 ? 'user-message' : 'chat-message'}`}
+ >
+ {message}
+ </div>
+ ))}
+
+ {/* Conditional Loading message */}
+ {(!this.cardsDoneLoading || this.loading) && (
+ <div className={`chat-bubble chat-message`}>
+ ...
+ </div>
+ )}
+ </div>
+
+ <div ref={this.messagesEndRef} style= {{height: '100px'}} />
+
+ </div>
+
+ <div className="inputWrapper">
<input
className="searchBox-input"
defaultValue=""
autoComplete="off"
onChange={isSort ? this.sortPromptChanged : this.quizAnswerChanged}
- onKeyDown={e => {
- if (e.key === 'Enter') {
- isSort ? this.generateSort() : this.generateQuiz();
+ onKeyDown={(e) => {
+ this.handleKeyPress(e, isSort)
+
+
}
- e.stopPropagation();
- }}
+ }
type="text"
- placeholder={`${isSort ? 'How do you want to sort your cards?' : 'Define the selected card?'}`}
- id="search-input"
- style={{ width: '100%' }}
- />
- {/* </div>
- <div className="btns-wrapper-gpt"> */}
- <Button
- tooltip={`${isSort ? 'HaveChatGPT sort ypur cards for you!' : 'See how close you get to the right answer!'}`}
- text={`${isSort ? 'Sort!' : 'Check!'}`}
- onClick={isSort ? this.generateSort : this.generateQuiz}
- color={StrCast(Doc.UserDoc().userVariantColor)}
- type={Type.TERT}
- style={{
- width: '100%',
- textAlign: 'center',
- color: '#ffffff',
- fontSize: '16px',
- height: '40%',
-
- }}
- />
- </div>
- </>
- ) : (
- <div>
- <div className="content-wrapper">
- <p>{this.text === 'Something went wrong :(' ? 'Something went wrong :(' : `${isSort ? this.sortRespText : this.quizRespText}`}</p>
- <IconButton
- tooltip="Generate Again"
- onClick={() => this.setSortDone(false)}
- icon={<FontAwesomeIcon icon="redo-alt" size="lg" />}
- color={StrCast(Doc.UserDoc().userVariantColor)}
+ placeholder={`${isSort ? 'Have ChatGPT sort, tag, define, or filter your cards for you!' : 'Define the selected card!'}`}
/>
</div>
</div>
- )
+
+
+ // </>
+ // ) : (
+ // <div>
+ // <div className="content-wrapper">
+ // <p>{this.text === 'Something went wrong :(' ? 'Something went wrong :(' : `${isSort ? this.sortRespText : this.quizRespText}`}</p>
+ // <IconButton
+ // tooltip="Generate Again"
+ // onClick={() => this.setSortDone(false)}
+ // icon={<FontAwesomeIcon icon="redo-alt" size="lg" />}
+ // color={StrCast(Doc.UserDoc().userVariantColor)}
+ // />
+ // </div>
+ // </div>
+ // )
);
// } else if (opt === GPTPopupMode.QUIZ) {
// return (
@@ -563,10 +728,10 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
};
sortBox = () => (
- <div>
+ <div style = {{height: '80%'}}>
{this.heading(this.mode === GPTPopupMode.SORT ? 'SORTING' : 'QUIZ')}
<>
- {!this.cardsDoneLoading || this.loading ? (
+ {!this.cardsDoneLoading? (
<div className="content-wrapper">
<div className="loading-spinner">
<ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} />
@@ -737,7 +902,7 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
tooltip="back"
icon={<CgCornerUpLeft size="16px" />}
onClick={() => this.mode = GPTPopupMode.CARD}
- style = {{right: '-20%'}}
+ style = {{right: '50px', position: 'absolute'}}
/>
)}
<IconButton